Merging in update to knockout.js 3.2.0
authorJaroslav Tulach <jtulach@netbeans.org>
Tue, 19 Aug 2014 20:13:11 +0200
changeset 817838526467557
parent 813 394568d7b13b
parent 816 41979bf458e7
child 818 90553e4c4273
Merging in update to knockout.js 3.2.0
ko4j/src/main/resources/org/netbeans/html/ko4j/knockout-2.2.1.js
     1.1 --- a/boot-script/src/test/java/net/java/html/boot/script/ko4j/KOCase.java	Tue Aug 19 20:11:47 2014 +0200
     1.2 +++ b/boot-script/src/test/java/net/java/html/boot/script/ko4j/KOCase.java	Tue Aug 19 20:13:11 2014 +0200
     1.3 @@ -48,6 +48,8 @@
     1.4  import java.lang.reflect.Method;
     1.5  import java.util.concurrent.Executor;
     1.6  import java.util.concurrent.Executors;
     1.7 +import java.util.logging.Level;
     1.8 +import java.util.logging.Logger;
     1.9  import org.apidesign.html.boot.spi.Fn;
    1.10  import org.testng.ITest;
    1.11  import org.testng.SkipException;
    1.12 @@ -109,8 +111,13 @@
    1.13          } catch (InvocationTargetException ex) {
    1.14              Throwable r = ex.getTargetException();
    1.15              if (r instanceof InterruptedException) {
    1.16 -                if (count++ < 10000) {
    1.17 +                if (count++ < 1000) {
    1.18                      notify = false;
    1.19 +                    try {
    1.20 +                        Thread.sleep(30);
    1.21 +                    } catch (InterruptedException ignore) {
    1.22 +                        // just go on
    1.23 +                    }
    1.24                      JS.execute(this);
    1.25                      return;
    1.26                  }
     2.1 --- a/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java	Tue Aug 19 20:11:47 2014 +0200
     2.2 +++ b/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java	Tue Aug 19 20:13:11 2014 +0200
     2.3 @@ -57,7 +57,7 @@
     2.4   *
     2.5   * @author Jaroslav Tulach
     2.6   */
     2.7 -@JavaScriptResource("knockout-2.2.1.js")
     2.8 +@JavaScriptResource("knockout-3.2.0.debug.js")
     2.9  final class Knockout {
    2.10      @JavaScriptBody(args = { "model", "prop", "oldValue", "newValue" }, 
    2.11          wait4js = false,
    2.12 @@ -78,6 +78,7 @@
    2.13      );
    2.14  
    2.15      @JavaScriptBody(args = { "bindings" }, wait4js = false, body = 
    2.16 +        "ko.cleanNode(window.document.body);\n" +
    2.17          "ko.applyBindings(bindings);\n"
    2.18      )
    2.19      native static void applyBindings(Object bindings);
    2.20 @@ -96,6 +97,7 @@
    2.21          body = 
    2.22            "ret['ko-fx.model'] = model;\n"
    2.23          + "function koComputed(name, readOnly, value, prop) {\n"
    2.24 +        + "  var trigger = ko.observable().extend({notify:'always'});"
    2.25          + "  function realGetter() {\n"
    2.26          + "    try {\n"
    2.27          + "      var v = prop.@org.apidesign.html.json.spi.PropertyBinding::getValue()();\n"
    2.28 @@ -107,6 +109,7 @@
    2.29          + "  var activeGetter = function() { return value; };\n"
    2.30          + "  var bnd = {\n"
    2.31          + "    'read': function() {\n"
    2.32 +        + "      trigger();\n"
    2.33          + "      var r = activeGetter();\n"
    2.34          + "      activeGetter = realGetter;\n"
    2.35          + "      if (r) try { var br = r.valueOf(); } catch (err) {}\n"
    2.36 @@ -121,10 +124,9 @@
    2.37          + "    };\n"
    2.38          + "  };\n"
    2.39          + "  var cmpt = ko['computed'](bnd);\n"
    2.40 -        + "  var vhm = cmpt['valueHasMutated'];\n"
    2.41          + "  cmpt['valueHasMutated'] = function(val) {\n"
    2.42          + "    if (arguments.length === 1) activeGetter = function() { return val; };\n"
    2.43 -        + "    vhm();\n"
    2.44 +        + "    trigger.valueHasMutated();\n"
    2.45          + "  };\n"
    2.46          + "  ret[name] = cmpt;\n"
    2.47          + "}\n"
     3.1 --- a/ko4j/src/main/resources/org/netbeans/html/ko4j/knockout-2.2.1.js	Tue Aug 19 20:11:47 2014 +0200
     3.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.3 @@ -1,3595 +0,0 @@
     3.4 -// Knockout JavaScript library v2.2.1
     3.5 -// (c) Steven Sanderson - http://knockoutjs.com/
     3.6 -// License: MIT (http://www.opensource.org/licenses/mit-license.php)
     3.7 -
     3.8 -(function(){
     3.9 -var DEBUG=true;
    3.10 -(function(window,document,navigator,jQuery,undefined){
    3.11 -!function(factory) {
    3.12 -    // Support three module loading scenarios
    3.13 -    if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') {
    3.14 -        // [1] CommonJS/Node.js
    3.15 -        var target = module['exports'] || exports; // module.exports is for Node.js
    3.16 -        factory(target);
    3.17 -    } else if (typeof define === 'function' && define['amd']) {
    3.18 -        // [2] AMD anonymous module
    3.19 -        define(['exports'], factory);
    3.20 -    } else {
    3.21 -        // [3] No module loader (plain <script> tag) - put directly in global namespace
    3.22 -        factory(window['ko'] = {});
    3.23 -    }
    3.24 -}(function(koExports){
    3.25 -// Internally, all KO objects are attached to koExports (even the non-exported ones whose names will be minified by the closure compiler).
    3.26 -// In the future, the following "ko" variable may be made distinct from "koExports" so that private objects are not externally reachable.
    3.27 -var ko = typeof koExports !== 'undefined' ? koExports : {};
    3.28 -// Google Closure Compiler helpers (used only to make the minified file smaller)
    3.29 -ko.exportSymbol = function(koPath, object) {
    3.30 -	var tokens = koPath.split(".");
    3.31 -
    3.32 -	// In the future, "ko" may become distinct from "koExports" (so that non-exported objects are not reachable)
    3.33 -	// At that point, "target" would be set to: (typeof koExports !== "undefined" ? koExports : ko)
    3.34 -	var target = ko;
    3.35 -
    3.36 -	for (var i = 0; i < tokens.length - 1; i++)
    3.37 -		target = target[tokens[i]];
    3.38 -	target[tokens[tokens.length - 1]] = object;
    3.39 -};
    3.40 -ko.exportProperty = function(owner, publicName, object) {
    3.41 -  owner[publicName] = object;
    3.42 -};
    3.43 -ko.version = "2.2.1";
    3.44 -
    3.45 -ko.exportSymbol('version', ko.version);
    3.46 -ko.utils = new (function () {
    3.47 -    var stringTrimRegex = /^(\s|\u00A0)+|(\s|\u00A0)+$/g;
    3.48 -
    3.49 -    // Represent the known event types in a compact way, then at runtime transform it into a hash with event name as key (for fast lookup)
    3.50 -    var knownEvents = {}, knownEventTypesByEventName = {};
    3.51 -    var keyEventTypeName = /Firefox\/2/i.test(navigator.userAgent) ? 'KeyboardEvent' : 'UIEvents';
    3.52 -    knownEvents[keyEventTypeName] = ['keyup', 'keydown', 'keypress'];
    3.53 -    knownEvents['MouseEvents'] = ['click', 'dblclick', 'mousedown', 'mouseup', 'mousemove', 'mouseover', 'mouseout', 'mouseenter', 'mouseleave'];
    3.54 -    for (var eventType in knownEvents) {
    3.55 -        var knownEventsForType = knownEvents[eventType];
    3.56 -        if (knownEventsForType.length) {
    3.57 -            for (var i = 0, j = knownEventsForType.length; i < j; i++)
    3.58 -                knownEventTypesByEventName[knownEventsForType[i]] = eventType;
    3.59 -        }
    3.60 -    }
    3.61 -    var eventsThatMustBeRegisteredUsingAttachEvent = { 'propertychange': true }; // Workaround for an IE9 issue - https://github.com/SteveSanderson/knockout/issues/406
    3.62 -
    3.63 -    // Detect IE versions for bug workarounds (uses IE conditionals, not UA string, for robustness)
    3.64 -    // Note that, since IE 10 does not support conditional comments, the following logic only detects IE < 10.
    3.65 -    // Currently this is by design, since IE 10+ behaves correctly when treated as a standard browser.
    3.66 -    // If there is a future need to detect specific versions of IE10+, we will amend this.
    3.67 -    var ieVersion = (function() {
    3.68 -        var version = 3, div = document.createElement('div'), iElems = div.getElementsByTagName('i');
    3.69 -
    3.70 -        // Keep constructing conditional HTML blocks until we hit one that resolves to an empty fragment
    3.71 -        while (
    3.72 -            div.innerHTML = '<!--[if gt IE ' + (++version) + ']><i></i><![endif]-->',
    3.73 -            iElems[0]
    3.74 -        );
    3.75 -        return version > 4 ? version : undefined;
    3.76 -    }());
    3.77 -    var isIe6 = ieVersion === 6,
    3.78 -        isIe7 = ieVersion === 7;
    3.79 -
    3.80 -    function isClickOnCheckableElement(element, eventType) {
    3.81 -        if ((ko.utils.tagNameLower(element) !== "input") || !element.type) return false;
    3.82 -        if (eventType.toLowerCase() != "click") return false;
    3.83 -        var inputType = element.type;
    3.84 -        return (inputType == "checkbox") || (inputType == "radio");
    3.85 -    }
    3.86 -
    3.87 -    return {
    3.88 -        fieldsIncludedWithJsonPost: ['authenticity_token', /^__RequestVerificationToken(_.*)?$/],
    3.89 -
    3.90 -        arrayForEach: function (array, action) {
    3.91 -            for (var i = 0, j = array.length; i < j; i++)
    3.92 -                action(array[i]);
    3.93 -        },
    3.94 -
    3.95 -        arrayIndexOf: function (array, item) {
    3.96 -            if (typeof Array.prototype.indexOf == "function")
    3.97 -                return Array.prototype.indexOf.call(array, item);
    3.98 -            for (var i = 0, j = array.length; i < j; i++)
    3.99 -                if (array[i] === item)
   3.100 -                    return i;
   3.101 -            return -1;
   3.102 -        },
   3.103 -
   3.104 -        arrayFirst: function (array, predicate, predicateOwner) {
   3.105 -            for (var i = 0, j = array.length; i < j; i++)
   3.106 -                if (predicate.call(predicateOwner, array[i]))
   3.107 -                    return array[i];
   3.108 -            return null;
   3.109 -        },
   3.110 -
   3.111 -        arrayRemoveItem: function (array, itemToRemove) {
   3.112 -            var index = ko.utils.arrayIndexOf(array, itemToRemove);
   3.113 -            if (index >= 0)
   3.114 -                array.splice(index, 1);
   3.115 -        },
   3.116 -
   3.117 -        arrayGetDistinctValues: function (array) {
   3.118 -            array = array || [];
   3.119 -            var result = [];
   3.120 -            for (var i = 0, j = array.length; i < j; i++) {
   3.121 -                if (ko.utils.arrayIndexOf(result, array[i]) < 0)
   3.122 -                    result.push(array[i]);
   3.123 -            }
   3.124 -            return result;
   3.125 -        },
   3.126 -
   3.127 -        arrayMap: function (array, mapping) {
   3.128 -            array = array || [];
   3.129 -            var result = [];
   3.130 -            for (var i = 0, j = array.length; i < j; i++)
   3.131 -                result.push(mapping(array[i]));
   3.132 -            return result;
   3.133 -        },
   3.134 -
   3.135 -        arrayFilter: function (array, predicate) {
   3.136 -            array = array || [];
   3.137 -            var result = [];
   3.138 -            for (var i = 0, j = array.length; i < j; i++)
   3.139 -                if (predicate(array[i]))
   3.140 -                    result.push(array[i]);
   3.141 -            return result;
   3.142 -        },
   3.143 -
   3.144 -        arrayPushAll: function (array, valuesToPush) {
   3.145 -            if (valuesToPush instanceof Array)
   3.146 -                array.push.apply(array, valuesToPush);
   3.147 -            else
   3.148 -                for (var i = 0, j = valuesToPush.length; i < j; i++)
   3.149 -                    array.push(valuesToPush[i]);
   3.150 -            return array;
   3.151 -        },
   3.152 -
   3.153 -        extend: function (target, source) {
   3.154 -            if (source) {
   3.155 -                for(var prop in source) {
   3.156 -                    if(source.hasOwnProperty(prop)) {
   3.157 -                        target[prop] = source[prop];
   3.158 -                    }
   3.159 -                }
   3.160 -            }
   3.161 -            return target;
   3.162 -        },
   3.163 -
   3.164 -        emptyDomNode: function (domNode) {
   3.165 -            while (domNode.firstChild) {
   3.166 -                ko.removeNode(domNode.firstChild);
   3.167 -            }
   3.168 -        },
   3.169 -
   3.170 -        moveCleanedNodesToContainerElement: function(nodes) {
   3.171 -            // Ensure it's a real array, as we're about to reparent the nodes and
   3.172 -            // we don't want the underlying collection to change while we're doing that.
   3.173 -            var nodesArray = ko.utils.makeArray(nodes);
   3.174 -
   3.175 -            var container = document.createElement('div');
   3.176 -            for (var i = 0, j = nodesArray.length; i < j; i++) {
   3.177 -                container.appendChild(ko.cleanNode(nodesArray[i]));
   3.178 -            }
   3.179 -            return container;
   3.180 -        },
   3.181 -
   3.182 -        cloneNodes: function (nodesArray, shouldCleanNodes) {
   3.183 -            for (var i = 0, j = nodesArray.length, newNodesArray = []; i < j; i++) {
   3.184 -                var clonedNode = nodesArray[i].cloneNode(true);
   3.185 -                newNodesArray.push(shouldCleanNodes ? ko.cleanNode(clonedNode) : clonedNode);
   3.186 -            }
   3.187 -            return newNodesArray;
   3.188 -        },
   3.189 -
   3.190 -        setDomNodeChildren: function (domNode, childNodes) {
   3.191 -            ko.utils.emptyDomNode(domNode);
   3.192 -            if (childNodes) {
   3.193 -                for (var i = 0, j = childNodes.length; i < j; i++)
   3.194 -                    domNode.appendChild(childNodes[i]);
   3.195 -            }
   3.196 -        },
   3.197 -
   3.198 -        replaceDomNodes: function (nodeToReplaceOrNodeArray, newNodesArray) {
   3.199 -            var nodesToReplaceArray = nodeToReplaceOrNodeArray.nodeType ? [nodeToReplaceOrNodeArray] : nodeToReplaceOrNodeArray;
   3.200 -            if (nodesToReplaceArray.length > 0) {
   3.201 -                var insertionPoint = nodesToReplaceArray[0];
   3.202 -                var parent = insertionPoint.parentNode;
   3.203 -                for (var i = 0, j = newNodesArray.length; i < j; i++)
   3.204 -                    parent.insertBefore(newNodesArray[i], insertionPoint);
   3.205 -                for (var i = 0, j = nodesToReplaceArray.length; i < j; i++) {
   3.206 -                    ko.removeNode(nodesToReplaceArray[i]);
   3.207 -                }
   3.208 -            }
   3.209 -        },
   3.210 -
   3.211 -        setOptionNodeSelectionState: function (optionNode, isSelected) {
   3.212 -            // IE6 sometimes throws "unknown error" if you try to write to .selected directly, whereas Firefox struggles with setAttribute. Pick one based on browser.
   3.213 -            if (ieVersion < 7)
   3.214 -                optionNode.setAttribute("selected", isSelected);
   3.215 -            else
   3.216 -                optionNode.selected = isSelected;
   3.217 -        },
   3.218 -
   3.219 -        stringTrim: function (string) {
   3.220 -            return (string || "").replace(stringTrimRegex, "");
   3.221 -        },
   3.222 -
   3.223 -        stringTokenize: function (string, delimiter) {
   3.224 -            var result = [];
   3.225 -            var tokens = (string || "").split(delimiter);
   3.226 -            for (var i = 0, j = tokens.length; i < j; i++) {
   3.227 -                var trimmed = ko.utils.stringTrim(tokens[i]);
   3.228 -                if (trimmed !== "")
   3.229 -                    result.push(trimmed);
   3.230 -            }
   3.231 -            return result;
   3.232 -        },
   3.233 -
   3.234 -        stringStartsWith: function (string, startsWith) {
   3.235 -            string = string || "";
   3.236 -            if (startsWith.length > string.length)
   3.237 -                return false;
   3.238 -            return string.substring(0, startsWith.length) === startsWith;
   3.239 -        },
   3.240 -
   3.241 -        domNodeIsContainedBy: function (node, containedByNode) {
   3.242 -            if (containedByNode.compareDocumentPosition)
   3.243 -                return (containedByNode.compareDocumentPosition(node) & 16) == 16;
   3.244 -            while (node != null) {
   3.245 -                if (node == containedByNode)
   3.246 -                    return true;
   3.247 -                node = node.parentNode;
   3.248 -            }
   3.249 -            return false;
   3.250 -        },
   3.251 -
   3.252 -        domNodeIsAttachedToDocument: function (node) {
   3.253 -            return ko.utils.domNodeIsContainedBy(node, node.ownerDocument);
   3.254 -        },
   3.255 -
   3.256 -        tagNameLower: function(element) {
   3.257 -            // For HTML elements, tagName will always be upper case; for XHTML elements, it'll be lower case.
   3.258 -            // Possible future optimization: If we know it's an element from an XHTML document (not HTML),
   3.259 -            // we don't need to do the .toLowerCase() as it will always be lower case anyway.
   3.260 -            return element && element.tagName && element.tagName.toLowerCase();
   3.261 -        },
   3.262 -
   3.263 -        registerEventHandler: function (element, eventType, handler) {
   3.264 -            var mustUseAttachEvent = ieVersion && eventsThatMustBeRegisteredUsingAttachEvent[eventType];
   3.265 -            if (!mustUseAttachEvent && typeof jQuery != "undefined") {
   3.266 -                if (isClickOnCheckableElement(element, eventType)) {
   3.267 -                    // For click events on checkboxes, jQuery interferes with the event handling in an awkward way:
   3.268 -                    // it toggles the element checked state *after* the click event handlers run, whereas native
   3.269 -                    // click events toggle the checked state *before* the event handler.
   3.270 -                    // Fix this by intecepting the handler and applying the correct checkedness before it runs.
   3.271 -                    var originalHandler = handler;
   3.272 -                    handler = function(event, eventData) {
   3.273 -                        var jQuerySuppliedCheckedState = this.checked;
   3.274 -                        if (eventData)
   3.275 -                            this.checked = eventData.checkedStateBeforeEvent !== true;
   3.276 -                        originalHandler.call(this, event);
   3.277 -                        this.checked = jQuerySuppliedCheckedState; // Restore the state jQuery applied
   3.278 -                    };
   3.279 -                }
   3.280 -                jQuery(element)['bind'](eventType, handler);
   3.281 -            } else if (!mustUseAttachEvent && typeof element.addEventListener == "function")
   3.282 -                element.addEventListener(eventType, handler, false);
   3.283 -            else if (typeof element.attachEvent != "undefined")
   3.284 -                element.attachEvent("on" + eventType, function (event) {
   3.285 -                    handler.call(element, event);
   3.286 -                });
   3.287 -            else
   3.288 -                throw new Error("Browser doesn't support addEventListener or attachEvent");
   3.289 -        },
   3.290 -
   3.291 -        triggerEvent: function (element, eventType) {
   3.292 -            if (!(element && element.nodeType))
   3.293 -                throw new Error("element must be a DOM node when calling triggerEvent");
   3.294 -
   3.295 -            if (typeof jQuery != "undefined") {
   3.296 -                var eventData = [];
   3.297 -                if (isClickOnCheckableElement(element, eventType)) {
   3.298 -                    // Work around the jQuery "click events on checkboxes" issue described above by storing the original checked state before triggering the handler
   3.299 -                    eventData.push({ checkedStateBeforeEvent: element.checked });
   3.300 -                }
   3.301 -                jQuery(element)['trigger'](eventType, eventData);
   3.302 -            } else if (typeof document.createEvent == "function") {
   3.303 -                if (typeof element.dispatchEvent == "function") {
   3.304 -                    var eventCategory = knownEventTypesByEventName[eventType] || "HTMLEvents";
   3.305 -                    var event = document.createEvent(eventCategory);
   3.306 -                    event.initEvent(eventType, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, element);
   3.307 -                    element.dispatchEvent(event);
   3.308 -                }
   3.309 -                else
   3.310 -                    throw new Error("The supplied element doesn't support dispatchEvent");
   3.311 -            } else if (typeof element.fireEvent != "undefined") {
   3.312 -                // Unlike other browsers, IE doesn't change the checked state of checkboxes/radiobuttons when you trigger their "click" event
   3.313 -                // so to make it consistent, we'll do it manually here
   3.314 -                if (isClickOnCheckableElement(element, eventType))
   3.315 -                    element.checked = element.checked !== true;
   3.316 -                element.fireEvent("on" + eventType);
   3.317 -            }
   3.318 -            else
   3.319 -                throw new Error("Browser doesn't support triggering events");
   3.320 -        },
   3.321 -
   3.322 -        unwrapObservable: function (value) {
   3.323 -            return ko.isObservable(value) ? value() : value;
   3.324 -        },
   3.325 -
   3.326 -        peekObservable: function (value) {
   3.327 -            return ko.isObservable(value) ? value.peek() : value;
   3.328 -        },
   3.329 -
   3.330 -        toggleDomNodeCssClass: function (node, classNames, shouldHaveClass) {
   3.331 -            if (classNames) {
   3.332 -                var cssClassNameRegex = /[\w-]+/g,
   3.333 -                    currentClassNames = node.className.match(cssClassNameRegex) || [];
   3.334 -                ko.utils.arrayForEach(classNames.match(cssClassNameRegex), function(className) {
   3.335 -                    var indexOfClass = ko.utils.arrayIndexOf(currentClassNames, className);
   3.336 -                    if (indexOfClass >= 0) {
   3.337 -                        if (!shouldHaveClass)
   3.338 -                            currentClassNames.splice(indexOfClass, 1);
   3.339 -                    } else {
   3.340 -                        if (shouldHaveClass)
   3.341 -                            currentClassNames.push(className);
   3.342 -                    }
   3.343 -                });
   3.344 -                node.className = currentClassNames.join(" ");
   3.345 -            }
   3.346 -        },
   3.347 -
   3.348 -        setTextContent: function(element, textContent) {
   3.349 -            var value = ko.utils.unwrapObservable(textContent);
   3.350 -            if ((value === null) || (value === undefined))
   3.351 -                value = "";
   3.352 -
   3.353 -            if (element.nodeType === 3) {
   3.354 -                element.data = value;
   3.355 -            } else {
   3.356 -                // We need there to be exactly one child: a text node.
   3.357 -                // If there are no children, more than one, or if it's not a text node,
   3.358 -                // we'll clear everything and create a single text node.
   3.359 -                var innerTextNode = ko.virtualElements.firstChild(element);
   3.360 -                if (!innerTextNode || innerTextNode.nodeType != 3 || ko.virtualElements.nextSibling(innerTextNode)) {
   3.361 -                    ko.virtualElements.setDomNodeChildren(element, [document.createTextNode(value)]);
   3.362 -                } else {
   3.363 -                    innerTextNode.data = value;
   3.364 -                }
   3.365 -
   3.366 -                ko.utils.forceRefresh(element);
   3.367 -            }
   3.368 -        },
   3.369 -
   3.370 -        setElementName: function(element, name) {
   3.371 -            element.name = name;
   3.372 -
   3.373 -            // Workaround IE 6/7 issue
   3.374 -            // - https://github.com/SteveSanderson/knockout/issues/197
   3.375 -            // - http://www.matts411.com/post/setting_the_name_attribute_in_ie_dom/
   3.376 -            if (ieVersion <= 7) {
   3.377 -                try {
   3.378 -                    element.mergeAttributes(document.createElement("<input name='" + element.name + "'/>"), false);
   3.379 -                }
   3.380 -                catch(e) {} // For IE9 with doc mode "IE9 Standards" and browser mode "IE9 Compatibility View"
   3.381 -            }
   3.382 -        },
   3.383 -
   3.384 -        forceRefresh: function(node) {
   3.385 -            // Workaround for an IE9 rendering bug - https://github.com/SteveSanderson/knockout/issues/209
   3.386 -            if (ieVersion >= 9) {
   3.387 -                // For text nodes and comment nodes (most likely virtual elements), we will have to refresh the container
   3.388 -                var elem = node.nodeType == 1 ? node : node.parentNode;
   3.389 -                if (elem.style)
   3.390 -                    elem.style.zoom = elem.style.zoom;
   3.391 -            }
   3.392 -        },
   3.393 -
   3.394 -        ensureSelectElementIsRenderedCorrectly: function(selectElement) {
   3.395 -            // Workaround for IE9 rendering bug - it doesn't reliably display all the text in dynamically-added select boxes unless you force it to re-render by updating the width.
   3.396 -            // (See https://github.com/SteveSanderson/knockout/issues/312, http://stackoverflow.com/questions/5908494/select-only-shows-first-char-of-selected-option)
   3.397 -            if (ieVersion >= 9) {
   3.398 -                var originalWidth = selectElement.style.width;
   3.399 -                selectElement.style.width = 0;
   3.400 -                selectElement.style.width = originalWidth;
   3.401 -            }
   3.402 -        },
   3.403 -
   3.404 -        range: function (min, max) {
   3.405 -            min = ko.utils.unwrapObservable(min);
   3.406 -            max = ko.utils.unwrapObservable(max);
   3.407 -            var result = [];
   3.408 -            for (var i = min; i <= max; i++)
   3.409 -                result.push(i);
   3.410 -            return result;
   3.411 -        },
   3.412 -
   3.413 -        makeArray: function(arrayLikeObject) {
   3.414 -            var result = [];
   3.415 -            for (var i = 0, j = arrayLikeObject.length; i < j; i++) {
   3.416 -                result.push(arrayLikeObject[i]);
   3.417 -            };
   3.418 -            return result;
   3.419 -        },
   3.420 -
   3.421 -        isIe6 : isIe6,
   3.422 -        isIe7 : isIe7,
   3.423 -        ieVersion : ieVersion,
   3.424 -
   3.425 -        getFormFields: function(form, fieldName) {
   3.426 -            var fields = ko.utils.makeArray(form.getElementsByTagName("input")).concat(ko.utils.makeArray(form.getElementsByTagName("textarea")));
   3.427 -            var isMatchingField = (typeof fieldName == 'string')
   3.428 -                ? function(field) { return field.name === fieldName }
   3.429 -                : function(field) { return fieldName.test(field.name) }; // Treat fieldName as regex or object containing predicate
   3.430 -            var matches = [];
   3.431 -            for (var i = fields.length - 1; i >= 0; i--) {
   3.432 -                if (isMatchingField(fields[i]))
   3.433 -                    matches.push(fields[i]);
   3.434 -            };
   3.435 -            return matches;
   3.436 -        },
   3.437 -
   3.438 -        parseJson: function (jsonString) {
   3.439 -            if (typeof jsonString == "string") {
   3.440 -                jsonString = ko.utils.stringTrim(jsonString);
   3.441 -                if (jsonString) {
   3.442 -                    if (window.JSON && window.JSON.parse) // Use native parsing where available
   3.443 -                        return window.JSON.parse(jsonString);
   3.444 -                    return (new Function("return " + jsonString))(); // Fallback on less safe parsing for older browsers
   3.445 -                }
   3.446 -            }
   3.447 -            return null;
   3.448 -        },
   3.449 -
   3.450 -        stringifyJson: function (data, replacer, space) {   // replacer and space are optional
   3.451 -            if ((typeof JSON == "undefined") || (typeof JSON.stringify == "undefined"))
   3.452 -                throw new Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");
   3.453 -            return JSON.stringify(ko.utils.unwrapObservable(data), replacer, space);
   3.454 -        },
   3.455 -
   3.456 -        postJson: function (urlOrForm, data, options) {
   3.457 -            options = options || {};
   3.458 -            var params = options['params'] || {};
   3.459 -            var includeFields = options['includeFields'] || this.fieldsIncludedWithJsonPost;
   3.460 -            var url = urlOrForm;
   3.461 -
   3.462 -            // If we were given a form, use its 'action' URL and pick out any requested field values
   3.463 -            if((typeof urlOrForm == 'object') && (ko.utils.tagNameLower(urlOrForm) === "form")) {
   3.464 -                var originalForm = urlOrForm;
   3.465 -                url = originalForm.action;
   3.466 -                for (var i = includeFields.length - 1; i >= 0; i--) {
   3.467 -                    var fields = ko.utils.getFormFields(originalForm, includeFields[i]);
   3.468 -                    for (var j = fields.length - 1; j >= 0; j--)
   3.469 -                        params[fields[j].name] = fields[j].value;
   3.470 -                }
   3.471 -            }
   3.472 -
   3.473 -            data = ko.utils.unwrapObservable(data);
   3.474 -            var form = document.createElement("form");
   3.475 -            form.style.display = "none";
   3.476 -            form.action = url;
   3.477 -            form.method = "post";
   3.478 -            for (var key in data) {
   3.479 -                var input = document.createElement("input");
   3.480 -                input.name = key;
   3.481 -                input.value = ko.utils.stringifyJson(ko.utils.unwrapObservable(data[key]));
   3.482 -                form.appendChild(input);
   3.483 -            }
   3.484 -            for (var key in params) {
   3.485 -                var input = document.createElement("input");
   3.486 -                input.name = key;
   3.487 -                input.value = params[key];
   3.488 -                form.appendChild(input);
   3.489 -            }
   3.490 -            document.body.appendChild(form);
   3.491 -            options['submitter'] ? options['submitter'](form) : form.submit();
   3.492 -            setTimeout(function () { form.parentNode.removeChild(form); }, 0);
   3.493 -        }
   3.494 -    }
   3.495 -})();
   3.496 -
   3.497 -ko.exportSymbol('utils', ko.utils);
   3.498 -ko.exportSymbol('utils.arrayForEach', ko.utils.arrayForEach);
   3.499 -ko.exportSymbol('utils.arrayFirst', ko.utils.arrayFirst);
   3.500 -ko.exportSymbol('utils.arrayFilter', ko.utils.arrayFilter);
   3.501 -ko.exportSymbol('utils.arrayGetDistinctValues', ko.utils.arrayGetDistinctValues);
   3.502 -ko.exportSymbol('utils.arrayIndexOf', ko.utils.arrayIndexOf);
   3.503 -ko.exportSymbol('utils.arrayMap', ko.utils.arrayMap);
   3.504 -ko.exportSymbol('utils.arrayPushAll', ko.utils.arrayPushAll);
   3.505 -ko.exportSymbol('utils.arrayRemoveItem', ko.utils.arrayRemoveItem);
   3.506 -ko.exportSymbol('utils.extend', ko.utils.extend);
   3.507 -ko.exportSymbol('utils.fieldsIncludedWithJsonPost', ko.utils.fieldsIncludedWithJsonPost);
   3.508 -ko.exportSymbol('utils.getFormFields', ko.utils.getFormFields);
   3.509 -ko.exportSymbol('utils.peekObservable', ko.utils.peekObservable);
   3.510 -ko.exportSymbol('utils.postJson', ko.utils.postJson);
   3.511 -ko.exportSymbol('utils.parseJson', ko.utils.parseJson);
   3.512 -ko.exportSymbol('utils.registerEventHandler', ko.utils.registerEventHandler);
   3.513 -ko.exportSymbol('utils.stringifyJson', ko.utils.stringifyJson);
   3.514 -ko.exportSymbol('utils.range', ko.utils.range);
   3.515 -ko.exportSymbol('utils.toggleDomNodeCssClass', ko.utils.toggleDomNodeCssClass);
   3.516 -ko.exportSymbol('utils.triggerEvent', ko.utils.triggerEvent);
   3.517 -ko.exportSymbol('utils.unwrapObservable', ko.utils.unwrapObservable);
   3.518 -
   3.519 -if (!Function.prototype['bind']) {
   3.520 -    // Function.prototype.bind is a standard part of ECMAScript 5th Edition (December 2009, http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf)
   3.521 -    // In case the browser doesn't implement it natively, provide a JavaScript implementation. This implementation is based on the one in prototype.js
   3.522 -    Function.prototype['bind'] = function (object) {
   3.523 -        var originalFunction = this, args = Array.prototype.slice.call(arguments), object = args.shift();
   3.524 -        return function () {
   3.525 -            return originalFunction.apply(object, args.concat(Array.prototype.slice.call(arguments)));
   3.526 -        };
   3.527 -    };
   3.528 -}
   3.529 -
   3.530 -ko.utils.domData = new (function () {
   3.531 -    var uniqueId = 0;
   3.532 -    var dataStoreKeyExpandoPropertyName = "__ko__" + (new Date).getTime();
   3.533 -    var dataStore = {};
   3.534 -    return {
   3.535 -        get: function (node, key) {
   3.536 -            var allDataForNode = ko.utils.domData.getAll(node, false);
   3.537 -            return allDataForNode === undefined ? undefined : allDataForNode[key];
   3.538 -        },
   3.539 -        set: function (node, key, value) {
   3.540 -            if (value === undefined) {
   3.541 -                // Make sure we don't actually create a new domData key if we are actually deleting a value
   3.542 -                if (ko.utils.domData.getAll(node, false) === undefined)
   3.543 -                    return;
   3.544 -            }
   3.545 -            var allDataForNode = ko.utils.domData.getAll(node, true);
   3.546 -            allDataForNode[key] = value;
   3.547 -        },
   3.548 -        getAll: function (node, createIfNotFound) {
   3.549 -            var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
   3.550 -            var hasExistingDataStore = dataStoreKey && (dataStoreKey !== "null") && dataStore[dataStoreKey];
   3.551 -            if (!hasExistingDataStore) {
   3.552 -                if (!createIfNotFound)
   3.553 -                    return undefined;
   3.554 -                dataStoreKey = node[dataStoreKeyExpandoPropertyName] = "ko" + uniqueId++;
   3.555 -                dataStore[dataStoreKey] = {};
   3.556 -            }
   3.557 -            return dataStore[dataStoreKey];
   3.558 -        },
   3.559 -        clear: function (node) {
   3.560 -            var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
   3.561 -            if (dataStoreKey) {
   3.562 -                delete dataStore[dataStoreKey];
   3.563 -                node[dataStoreKeyExpandoPropertyName] = null;
   3.564 -                return true; // Exposing "did clean" flag purely so specs can infer whether things have been cleaned up as intended
   3.565 -            }
   3.566 -            return false;
   3.567 -        }
   3.568 -    }
   3.569 -})();
   3.570 -
   3.571 -ko.exportSymbol('utils.domData', ko.utils.domData);
   3.572 -ko.exportSymbol('utils.domData.clear', ko.utils.domData.clear); // Exporting only so specs can clear up after themselves fully
   3.573 -
   3.574 -ko.utils.domNodeDisposal = new (function () {
   3.575 -    var domDataKey = "__ko_domNodeDisposal__" + (new Date).getTime();
   3.576 -    var cleanableNodeTypes = { 1: true, 8: true, 9: true };       // Element, Comment, Document
   3.577 -    var cleanableNodeTypesWithDescendants = { 1: true, 9: true }; // Element, Document
   3.578 -
   3.579 -    function getDisposeCallbacksCollection(node, createIfNotFound) {
   3.580 -        var allDisposeCallbacks = ko.utils.domData.get(node, domDataKey);
   3.581 -        if ((allDisposeCallbacks === undefined) && createIfNotFound) {
   3.582 -            allDisposeCallbacks = [];
   3.583 -            ko.utils.domData.set(node, domDataKey, allDisposeCallbacks);
   3.584 -        }
   3.585 -        return allDisposeCallbacks;
   3.586 -    }
   3.587 -    function destroyCallbacksCollection(node) {
   3.588 -        ko.utils.domData.set(node, domDataKey, undefined);
   3.589 -    }
   3.590 -
   3.591 -    function cleanSingleNode(node) {
   3.592 -        // Run all the dispose callbacks
   3.593 -        var callbacks = getDisposeCallbacksCollection(node, false);
   3.594 -        if (callbacks) {
   3.595 -            callbacks = callbacks.slice(0); // Clone, as the array may be modified during iteration (typically, callbacks will remove themselves)
   3.596 -            for (var i = 0; i < callbacks.length; i++)
   3.597 -                callbacks[i](node);
   3.598 -        }
   3.599 -
   3.600 -        // Also erase the DOM data
   3.601 -        ko.utils.domData.clear(node);
   3.602 -
   3.603 -        // Special support for jQuery here because it's so commonly used.
   3.604 -        // Many jQuery plugins (including jquery.tmpl) store data using jQuery's equivalent of domData
   3.605 -        // so notify it to tear down any resources associated with the node & descendants here.
   3.606 -        if ((typeof jQuery == "function") && (typeof jQuery['cleanData'] == "function"))
   3.607 -            jQuery['cleanData']([node]);
   3.608 -
   3.609 -        // Also clear any immediate-child comment nodes, as these wouldn't have been found by
   3.610 -        // node.getElementsByTagName("*") in cleanNode() (comment nodes aren't elements)
   3.611 -        if (cleanableNodeTypesWithDescendants[node.nodeType])
   3.612 -            cleanImmediateCommentTypeChildren(node);
   3.613 -    }
   3.614 -
   3.615 -    function cleanImmediateCommentTypeChildren(nodeWithChildren) {
   3.616 -        var child, nextChild = nodeWithChildren.firstChild;
   3.617 -        while (child = nextChild) {
   3.618 -            nextChild = child.nextSibling;
   3.619 -            if (child.nodeType === 8)
   3.620 -                cleanSingleNode(child);
   3.621 -        }
   3.622 -    }
   3.623 -
   3.624 -    return {
   3.625 -        addDisposeCallback : function(node, callback) {
   3.626 -            if (typeof callback != "function")
   3.627 -                throw new Error("Callback must be a function");
   3.628 -            getDisposeCallbacksCollection(node, true).push(callback);
   3.629 -        },
   3.630 -
   3.631 -        removeDisposeCallback : function(node, callback) {
   3.632 -            var callbacksCollection = getDisposeCallbacksCollection(node, false);
   3.633 -            if (callbacksCollection) {
   3.634 -                ko.utils.arrayRemoveItem(callbacksCollection, callback);
   3.635 -                if (callbacksCollection.length == 0)
   3.636 -                    destroyCallbacksCollection(node);
   3.637 -            }
   3.638 -        },
   3.639 -
   3.640 -        cleanNode : function(node) {
   3.641 -            // First clean this node, where applicable
   3.642 -            if (cleanableNodeTypes[node.nodeType]) {
   3.643 -                cleanSingleNode(node);
   3.644 -
   3.645 -                // ... then its descendants, where applicable
   3.646 -                if (cleanableNodeTypesWithDescendants[node.nodeType]) {
   3.647 -                    // Clone the descendants list in case it changes during iteration
   3.648 -                    var descendants = [];
   3.649 -                    ko.utils.arrayPushAll(descendants, node.getElementsByTagName("*"));
   3.650 -                    for (var i = 0, j = descendants.length; i < j; i++)
   3.651 -                        cleanSingleNode(descendants[i]);
   3.652 -                }
   3.653 -            }
   3.654 -            return node;
   3.655 -        },
   3.656 -
   3.657 -        removeNode : function(node) {
   3.658 -            ko.cleanNode(node);
   3.659 -            if (node.parentNode)
   3.660 -                node.parentNode.removeChild(node);
   3.661 -        }
   3.662 -    }
   3.663 -})();
   3.664 -ko.cleanNode = ko.utils.domNodeDisposal.cleanNode; // Shorthand name for convenience
   3.665 -ko.removeNode = ko.utils.domNodeDisposal.removeNode; // Shorthand name for convenience
   3.666 -ko.exportSymbol('cleanNode', ko.cleanNode);
   3.667 -ko.exportSymbol('removeNode', ko.removeNode);
   3.668 -ko.exportSymbol('utils.domNodeDisposal', ko.utils.domNodeDisposal);
   3.669 -ko.exportSymbol('utils.domNodeDisposal.addDisposeCallback', ko.utils.domNodeDisposal.addDisposeCallback);
   3.670 -ko.exportSymbol('utils.domNodeDisposal.removeDisposeCallback', ko.utils.domNodeDisposal.removeDisposeCallback);
   3.671 -(function () {
   3.672 -    var leadingCommentRegex = /^(\s*)<!--(.*?)-->/;
   3.673 -
   3.674 -    function simpleHtmlParse(html) {
   3.675 -        // Based on jQuery's "clean" function, but only accounting for table-related elements.
   3.676 -        // If you have referenced jQuery, this won't be used anyway - KO will use jQuery's "clean" function directly
   3.677 -
   3.678 -        // Note that there's still an issue in IE < 9 whereby it will discard comment nodes that are the first child of
   3.679 -        // a descendant node. For example: "<div><!-- mycomment -->abc</div>" will get parsed as "<div>abc</div>"
   3.680 -        // This won't affect anyone who has referenced jQuery, and there's always the workaround of inserting a dummy node
   3.681 -        // (possibly a text node) in front of the comment. So, KO does not attempt to workaround this IE issue automatically at present.
   3.682 -
   3.683 -        // Trim whitespace, otherwise indexOf won't work as expected
   3.684 -        var tags = ko.utils.stringTrim(html).toLowerCase(), div = document.createElement("div");
   3.685 -
   3.686 -        // Finds the first match from the left column, and returns the corresponding "wrap" data from the right column
   3.687 -        var wrap = tags.match(/^<(thead|tbody|tfoot)/)              && [1, "<table>", "</table>"] ||
   3.688 -                   !tags.indexOf("<tr")                             && [2, "<table><tbody>", "</tbody></table>"] ||
   3.689 -                   (!tags.indexOf("<td") || !tags.indexOf("<th"))   && [3, "<table><tbody><tr>", "</tr></tbody></table>"] ||
   3.690 -                   /* anything else */                                 [0, "", ""];
   3.691 -
   3.692 -        // Go to html and back, then peel off extra wrappers
   3.693 -        // Note that we always prefix with some dummy text, because otherwise, IE<9 will strip out leading comment nodes in descendants. Total madness.
   3.694 -        var markup = "ignored<div>" + wrap[1] + html + wrap[2] + "</div>";
   3.695 -        if (typeof window['innerShiv'] == "function") {
   3.696 -            div.appendChild(window['innerShiv'](markup));
   3.697 -        } else {
   3.698 -            div.innerHTML = markup;
   3.699 -        }
   3.700 -
   3.701 -        // Move to the right depth
   3.702 -        while (wrap[0]--)
   3.703 -            div = div.lastChild;
   3.704 -
   3.705 -        return ko.utils.makeArray(div.lastChild.childNodes);
   3.706 -    }
   3.707 -
   3.708 -    function jQueryHtmlParse(html) {
   3.709 -        // jQuery's "parseHTML" function was introduced in jQuery 1.8.0 and is a documented public API.
   3.710 -        if (jQuery['parseHTML']) {
   3.711 -            return jQuery['parseHTML'](html);
   3.712 -        } else {
   3.713 -            // For jQuery < 1.8.0, we fall back on the undocumented internal "clean" function.
   3.714 -            var elems = jQuery['clean']([html]);
   3.715 -
   3.716 -            // As of jQuery 1.7.1, jQuery parses the HTML by appending it to some dummy parent nodes held in an in-memory document fragment.
   3.717 -            // Unfortunately, it never clears the dummy parent nodes from the document fragment, so it leaks memory over time.
   3.718 -            // Fix this by finding the top-most dummy parent element, and detaching it from its owner fragment.
   3.719 -            if (elems && elems[0]) {
   3.720 -                // Find the top-most parent element that's a direct child of a document fragment
   3.721 -                var elem = elems[0];
   3.722 -                while (elem.parentNode && elem.parentNode.nodeType !== 11 /* i.e., DocumentFragment */)
   3.723 -                    elem = elem.parentNode;
   3.724 -                // ... then detach it
   3.725 -                if (elem.parentNode)
   3.726 -                    elem.parentNode.removeChild(elem);
   3.727 -            }
   3.728 -
   3.729 -            return elems;
   3.730 -        }
   3.731 -    }
   3.732 -
   3.733 -    ko.utils.parseHtmlFragment = function(html) {
   3.734 -        return typeof jQuery != 'undefined' ? jQueryHtmlParse(html)   // As below, benefit from jQuery's optimisations where possible
   3.735 -                                            : simpleHtmlParse(html);  // ... otherwise, this simple logic will do in most common cases.
   3.736 -    };
   3.737 -
   3.738 -    ko.utils.setHtml = function(node, html) {
   3.739 -        ko.utils.emptyDomNode(node);
   3.740 -
   3.741 -        // There's no legitimate reason to display a stringified observable without unwrapping it, so we'll unwrap it
   3.742 -        html = ko.utils.unwrapObservable(html);
   3.743 -
   3.744 -        if ((html !== null) && (html !== undefined)) {
   3.745 -            if (typeof html != 'string')
   3.746 -                html = html.toString();
   3.747 -
   3.748 -            // jQuery contains a lot of sophisticated code to parse arbitrary HTML fragments,
   3.749 -            // for example <tr> elements which are not normally allowed to exist on their own.
   3.750 -            // If you've referenced jQuery we'll use that rather than duplicating its code.
   3.751 -            if (typeof jQuery != 'undefined') {
   3.752 -                jQuery(node)['html'](html);
   3.753 -            } else {
   3.754 -                // ... otherwise, use KO's own parsing logic.
   3.755 -                var parsedNodes = ko.utils.parseHtmlFragment(html);
   3.756 -                for (var i = 0; i < parsedNodes.length; i++)
   3.757 -                    node.appendChild(parsedNodes[i]);
   3.758 -            }
   3.759 -        }
   3.760 -    };
   3.761 -})();
   3.762 -
   3.763 -ko.exportSymbol('utils.parseHtmlFragment', ko.utils.parseHtmlFragment);
   3.764 -ko.exportSymbol('utils.setHtml', ko.utils.setHtml);
   3.765 -
   3.766 -ko.memoization = (function () {
   3.767 -    var memos = {};
   3.768 -
   3.769 -    function randomMax8HexChars() {
   3.770 -        return (((1 + Math.random()) * 0x100000000) | 0).toString(16).substring(1);
   3.771 -    }
   3.772 -    function generateRandomId() {
   3.773 -        return randomMax8HexChars() + randomMax8HexChars();
   3.774 -    }
   3.775 -    function findMemoNodes(rootNode, appendToArray) {
   3.776 -        if (!rootNode)
   3.777 -            return;
   3.778 -        if (rootNode.nodeType == 8) {
   3.779 -            var memoId = ko.memoization.parseMemoText(rootNode.nodeValue);
   3.780 -            if (memoId != null)
   3.781 -                appendToArray.push({ domNode: rootNode, memoId: memoId });
   3.782 -        } else if (rootNode.nodeType == 1) {
   3.783 -            for (var i = 0, childNodes = rootNode.childNodes, j = childNodes.length; i < j; i++)
   3.784 -                findMemoNodes(childNodes[i], appendToArray);
   3.785 -        }
   3.786 -    }
   3.787 -
   3.788 -    return {
   3.789 -        memoize: function (callback) {
   3.790 -            if (typeof callback != "function")
   3.791 -                throw new Error("You can only pass a function to ko.memoization.memoize()");
   3.792 -            var memoId = generateRandomId();
   3.793 -            memos[memoId] = callback;
   3.794 -            return "<!--[ko_memo:" + memoId + "]-->";
   3.795 -        },
   3.796 -
   3.797 -        unmemoize: function (memoId, callbackParams) {
   3.798 -            var callback = memos[memoId];
   3.799 -            if (callback === undefined)
   3.800 -                throw new Error("Couldn't find any memo with ID " + memoId + ". Perhaps it's already been unmemoized.");
   3.801 -            try {
   3.802 -                callback.apply(null, callbackParams || []);
   3.803 -                return true;
   3.804 -            }
   3.805 -            finally { delete memos[memoId]; }
   3.806 -        },
   3.807 -
   3.808 -        unmemoizeDomNodeAndDescendants: function (domNode, extraCallbackParamsArray) {
   3.809 -            var memos = [];
   3.810 -            findMemoNodes(domNode, memos);
   3.811 -            for (var i = 0, j = memos.length; i < j; i++) {
   3.812 -                var node = memos[i].domNode;
   3.813 -                var combinedParams = [node];
   3.814 -                if (extraCallbackParamsArray)
   3.815 -                    ko.utils.arrayPushAll(combinedParams, extraCallbackParamsArray);
   3.816 -                ko.memoization.unmemoize(memos[i].memoId, combinedParams);
   3.817 -                node.nodeValue = ""; // Neuter this node so we don't try to unmemoize it again
   3.818 -                if (node.parentNode)
   3.819 -                    node.parentNode.removeChild(node); // If possible, erase it totally (not always possible - someone else might just hold a reference to it then call unmemoizeDomNodeAndDescendants again)
   3.820 -            }
   3.821 -        },
   3.822 -
   3.823 -        parseMemoText: function (memoText) {
   3.824 -            var match = memoText.match(/^\[ko_memo\:(.*?)\]$/);
   3.825 -            return match ? match[1] : null;
   3.826 -        }
   3.827 -    };
   3.828 -})();
   3.829 -
   3.830 -ko.exportSymbol('memoization', ko.memoization);
   3.831 -ko.exportSymbol('memoization.memoize', ko.memoization.memoize);
   3.832 -ko.exportSymbol('memoization.unmemoize', ko.memoization.unmemoize);
   3.833 -ko.exportSymbol('memoization.parseMemoText', ko.memoization.parseMemoText);
   3.834 -ko.exportSymbol('memoization.unmemoizeDomNodeAndDescendants', ko.memoization.unmemoizeDomNodeAndDescendants);
   3.835 -ko.extenders = {
   3.836 -    'throttle': function(target, timeout) {
   3.837 -        // Throttling means two things:
   3.838 -
   3.839 -        // (1) For dependent observables, we throttle *evaluations* so that, no matter how fast its dependencies
   3.840 -        //     notify updates, the target doesn't re-evaluate (and hence doesn't notify) faster than a certain rate
   3.841 -        target['throttleEvaluation'] = timeout;
   3.842 -
   3.843 -        // (2) For writable targets (observables, or writable dependent observables), we throttle *writes*
   3.844 -        //     so the target cannot change value synchronously or faster than a certain rate
   3.845 -        var writeTimeoutInstance = null;
   3.846 -        return ko.dependentObservable({
   3.847 -            'read': target,
   3.848 -            'write': function(value) {
   3.849 -                clearTimeout(writeTimeoutInstance);
   3.850 -                writeTimeoutInstance = setTimeout(function() {
   3.851 -                    target(value);
   3.852 -                }, timeout);
   3.853 -            }
   3.854 -        });
   3.855 -    },
   3.856 -
   3.857 -    'notify': function(target, notifyWhen) {
   3.858 -        target["equalityComparer"] = notifyWhen == "always"
   3.859 -            ? function() { return false } // Treat all values as not equal
   3.860 -            : ko.observable["fn"]["equalityComparer"];
   3.861 -        return target;
   3.862 -    }
   3.863 -};
   3.864 -
   3.865 -function applyExtenders(requestedExtenders) {
   3.866 -    var target = this;
   3.867 -    if (requestedExtenders) {
   3.868 -        for (var key in requestedExtenders) {
   3.869 -            var extenderHandler = ko.extenders[key];
   3.870 -            if (typeof extenderHandler == 'function') {
   3.871 -                target = extenderHandler(target, requestedExtenders[key]);
   3.872 -            }
   3.873 -        }
   3.874 -    }
   3.875 -    return target;
   3.876 -}
   3.877 -
   3.878 -ko.exportSymbol('extenders', ko.extenders);
   3.879 -
   3.880 -ko.subscription = function (target, callback, disposeCallback) {
   3.881 -    this.target = target;
   3.882 -    this.callback = callback;
   3.883 -    this.disposeCallback = disposeCallback;
   3.884 -    ko.exportProperty(this, 'dispose', this.dispose);
   3.885 -};
   3.886 -ko.subscription.prototype.dispose = function () {
   3.887 -    this.isDisposed = true;
   3.888 -    this.disposeCallback();
   3.889 -};
   3.890 -
   3.891 -ko.subscribable = function () {
   3.892 -    this._subscriptions = {};
   3.893 -
   3.894 -    ko.utils.extend(this, ko.subscribable['fn']);
   3.895 -    ko.exportProperty(this, 'subscribe', this.subscribe);
   3.896 -    ko.exportProperty(this, 'extend', this.extend);
   3.897 -    ko.exportProperty(this, 'getSubscriptionsCount', this.getSubscriptionsCount);
   3.898 -}
   3.899 -
   3.900 -var defaultEvent = "change";
   3.901 -
   3.902 -ko.subscribable['fn'] = {
   3.903 -    subscribe: function (callback, callbackTarget, event) {
   3.904 -        event = event || defaultEvent;
   3.905 -        var boundCallback = callbackTarget ? callback.bind(callbackTarget) : callback;
   3.906 -
   3.907 -        var subscription = new ko.subscription(this, boundCallback, function () {
   3.908 -            ko.utils.arrayRemoveItem(this._subscriptions[event], subscription);
   3.909 -        }.bind(this));
   3.910 -
   3.911 -        if (!this._subscriptions[event])
   3.912 -            this._subscriptions[event] = [];
   3.913 -        this._subscriptions[event].push(subscription);
   3.914 -        return subscription;
   3.915 -    },
   3.916 -
   3.917 -    "notifySubscribers": function (valueToNotify, event) {
   3.918 -        event = event || defaultEvent;
   3.919 -        if (this._subscriptions[event]) {
   3.920 -            ko.dependencyDetection.ignore(function() {
   3.921 -                ko.utils.arrayForEach(this._subscriptions[event].slice(0), function (subscription) {
   3.922 -                    // In case a subscription was disposed during the arrayForEach cycle, check
   3.923 -                    // for isDisposed on each subscription before invoking its callback
   3.924 -                    if (subscription && (subscription.isDisposed !== true))
   3.925 -                        subscription.callback(valueToNotify);
   3.926 -                });
   3.927 -            }, this);
   3.928 -        }
   3.929 -    },
   3.930 -
   3.931 -    getSubscriptionsCount: function () {
   3.932 -        var total = 0;
   3.933 -        for (var eventName in this._subscriptions) {
   3.934 -            if (this._subscriptions.hasOwnProperty(eventName))
   3.935 -                total += this._subscriptions[eventName].length;
   3.936 -        }
   3.937 -        return total;
   3.938 -    },
   3.939 -
   3.940 -    extend: applyExtenders
   3.941 -};
   3.942 -
   3.943 -
   3.944 -ko.isSubscribable = function (instance) {
   3.945 -    return typeof instance.subscribe == "function" && typeof instance["notifySubscribers"] == "function";
   3.946 -};
   3.947 -
   3.948 -ko.exportSymbol('subscribable', ko.subscribable);
   3.949 -ko.exportSymbol('isSubscribable', ko.isSubscribable);
   3.950 -
   3.951 -ko.dependencyDetection = (function () {
   3.952 -    var _frames = [];
   3.953 -
   3.954 -    return {
   3.955 -        begin: function (callback) {
   3.956 -            _frames.push({ callback: callback, distinctDependencies:[] });
   3.957 -        },
   3.958 -
   3.959 -        end: function () {
   3.960 -            _frames.pop();
   3.961 -        },
   3.962 -
   3.963 -        registerDependency: function (subscribable) {
   3.964 -            if (!ko.isSubscribable(subscribable))
   3.965 -                throw new Error("Only subscribable things can act as dependencies");
   3.966 -            if (_frames.length > 0) {
   3.967 -                var topFrame = _frames[_frames.length - 1];
   3.968 -                if (!topFrame || ko.utils.arrayIndexOf(topFrame.distinctDependencies, subscribable) >= 0)
   3.969 -                    return;
   3.970 -                topFrame.distinctDependencies.push(subscribable);
   3.971 -                topFrame.callback(subscribable);
   3.972 -            }
   3.973 -        },
   3.974 -
   3.975 -        ignore: function(callback, callbackTarget, callbackArgs) {
   3.976 -            try {
   3.977 -                _frames.push(null);
   3.978 -                return callback.apply(callbackTarget, callbackArgs || []);
   3.979 -            } finally {
   3.980 -                _frames.pop();
   3.981 -            }
   3.982 -        }
   3.983 -    };
   3.984 -})();
   3.985 -var primitiveTypes = { 'undefined':true, 'boolean':true, 'number':true, 'string':true };
   3.986 -
   3.987 -ko.observable = function (initialValue) {
   3.988 -    var _latestValue = initialValue;
   3.989 -
   3.990 -    function observable() {
   3.991 -        if (arguments.length > 0) {
   3.992 -            // Write
   3.993 -
   3.994 -            // Ignore writes if the value hasn't changed
   3.995 -            if ((!observable['equalityComparer']) || !observable['equalityComparer'](_latestValue, arguments[0])) {
   3.996 -                observable.valueWillMutate();
   3.997 -                _latestValue = arguments[0];
   3.998 -                if (DEBUG) observable._latestValue = _latestValue;
   3.999 -                observable.valueHasMutated();
  3.1000 -            }
  3.1001 -            return this; // Permits chained assignments
  3.1002 -        }
  3.1003 -        else {
  3.1004 -            // Read
  3.1005 -            ko.dependencyDetection.registerDependency(observable); // The caller only needs to be notified of changes if they did a "read" operation
  3.1006 -            return _latestValue;
  3.1007 -        }
  3.1008 -    }
  3.1009 -    if (DEBUG) observable._latestValue = _latestValue;
  3.1010 -    ko.subscribable.call(observable);
  3.1011 -    observable.peek = function() { return _latestValue };
  3.1012 -    observable.valueHasMutated = function () { observable["notifySubscribers"](_latestValue); }
  3.1013 -    observable.valueWillMutate = function () { observable["notifySubscribers"](_latestValue, "beforeChange"); }
  3.1014 -    ko.utils.extend(observable, ko.observable['fn']);
  3.1015 -
  3.1016 -    ko.exportProperty(observable, 'peek', observable.peek);
  3.1017 -    ko.exportProperty(observable, "valueHasMutated", observable.valueHasMutated);
  3.1018 -    ko.exportProperty(observable, "valueWillMutate", observable.valueWillMutate);
  3.1019 -
  3.1020 -    return observable;
  3.1021 -}
  3.1022 -
  3.1023 -ko.observable['fn'] = {
  3.1024 -    "equalityComparer": function valuesArePrimitiveAndEqual(a, b) {
  3.1025 -        var oldValueIsPrimitive = (a === null) || (typeof(a) in primitiveTypes);
  3.1026 -        return oldValueIsPrimitive ? (a === b) : false;
  3.1027 -    }
  3.1028 -};
  3.1029 -
  3.1030 -var protoProperty = ko.observable.protoProperty = "__ko_proto__";
  3.1031 -ko.observable['fn'][protoProperty] = ko.observable;
  3.1032 -
  3.1033 -ko.hasPrototype = function(instance, prototype) {
  3.1034 -    if ((instance === null) || (instance === undefined) || (instance[protoProperty] === undefined)) return false;
  3.1035 -    if (instance[protoProperty] === prototype) return true;
  3.1036 -    return ko.hasPrototype(instance[protoProperty], prototype); // Walk the prototype chain
  3.1037 -};
  3.1038 -
  3.1039 -ko.isObservable = function (instance) {
  3.1040 -    return ko.hasPrototype(instance, ko.observable);
  3.1041 -}
  3.1042 -ko.isWriteableObservable = function (instance) {
  3.1043 -    // Observable
  3.1044 -    if ((typeof instance == "function") && instance[protoProperty] === ko.observable)
  3.1045 -        return true;
  3.1046 -    // Writeable dependent observable
  3.1047 -    if ((typeof instance == "function") && (instance[protoProperty] === ko.dependentObservable) && (instance.hasWriteFunction))
  3.1048 -        return true;
  3.1049 -    // Anything else
  3.1050 -    return false;
  3.1051 -}
  3.1052 -
  3.1053 -
  3.1054 -ko.exportSymbol('observable', ko.observable);
  3.1055 -ko.exportSymbol('isObservable', ko.isObservable);
  3.1056 -ko.exportSymbol('isWriteableObservable', ko.isWriteableObservable);
  3.1057 -ko.observableArray = function (initialValues) {
  3.1058 -    if (arguments.length == 0) {
  3.1059 -        // Zero-parameter constructor initializes to empty array
  3.1060 -        initialValues = [];
  3.1061 -    }
  3.1062 -    if ((initialValues !== null) && (initialValues !== undefined) && !('length' in initialValues))
  3.1063 -        throw new Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");
  3.1064 -
  3.1065 -    var result = ko.observable(initialValues);
  3.1066 -    ko.utils.extend(result, ko.observableArray['fn']);
  3.1067 -    return result;
  3.1068 -}
  3.1069 -
  3.1070 -ko.observableArray['fn'] = {
  3.1071 -    'remove': function (valueOrPredicate) {
  3.1072 -        var underlyingArray = this.peek();
  3.1073 -        var removedValues = [];
  3.1074 -        var predicate = typeof valueOrPredicate == "function" ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
  3.1075 -        for (var i = 0; i < underlyingArray.length; i++) {
  3.1076 -            var value = underlyingArray[i];
  3.1077 -            if (predicate(value)) {
  3.1078 -                if (removedValues.length === 0) {
  3.1079 -                    this.valueWillMutate();
  3.1080 -                }
  3.1081 -                removedValues.push(value);
  3.1082 -                underlyingArray.splice(i, 1);
  3.1083 -                i--;
  3.1084 -            }
  3.1085 -        }
  3.1086 -        if (removedValues.length) {
  3.1087 -            this.valueHasMutated();
  3.1088 -        }
  3.1089 -        return removedValues;
  3.1090 -    },
  3.1091 -
  3.1092 -    'removeAll': function (arrayOfValues) {
  3.1093 -        // If you passed zero args, we remove everything
  3.1094 -        if (arrayOfValues === undefined) {
  3.1095 -            var underlyingArray = this.peek();
  3.1096 -            var allValues = underlyingArray.slice(0);
  3.1097 -            this.valueWillMutate();
  3.1098 -            underlyingArray.splice(0, underlyingArray.length);
  3.1099 -            this.valueHasMutated();
  3.1100 -            return allValues;
  3.1101 -        }
  3.1102 -        // If you passed an arg, we interpret it as an array of entries to remove
  3.1103 -        if (!arrayOfValues)
  3.1104 -            return [];
  3.1105 -        return this['remove'](function (value) {
  3.1106 -            return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
  3.1107 -        });
  3.1108 -    },
  3.1109 -
  3.1110 -    'destroy': function (valueOrPredicate) {
  3.1111 -        var underlyingArray = this.peek();
  3.1112 -        var predicate = typeof valueOrPredicate == "function" ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
  3.1113 -        this.valueWillMutate();
  3.1114 -        for (var i = underlyingArray.length - 1; i >= 0; i--) {
  3.1115 -            var value = underlyingArray[i];
  3.1116 -            if (predicate(value))
  3.1117 -                underlyingArray[i]["_destroy"] = true;
  3.1118 -        }
  3.1119 -        this.valueHasMutated();
  3.1120 -    },
  3.1121 -
  3.1122 -    'destroyAll': function (arrayOfValues) {
  3.1123 -        // If you passed zero args, we destroy everything
  3.1124 -        if (arrayOfValues === undefined)
  3.1125 -            return this['destroy'](function() { return true });
  3.1126 -
  3.1127 -        // If you passed an arg, we interpret it as an array of entries to destroy
  3.1128 -        if (!arrayOfValues)
  3.1129 -            return [];
  3.1130 -        return this['destroy'](function (value) {
  3.1131 -            return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
  3.1132 -        });
  3.1133 -    },
  3.1134 -
  3.1135 -    'indexOf': function (item) {
  3.1136 -        var underlyingArray = this();
  3.1137 -        return ko.utils.arrayIndexOf(underlyingArray, item);
  3.1138 -    },
  3.1139 -
  3.1140 -    'replace': function(oldItem, newItem) {
  3.1141 -        var index = this['indexOf'](oldItem);
  3.1142 -        if (index >= 0) {
  3.1143 -            this.valueWillMutate();
  3.1144 -            this.peek()[index] = newItem;
  3.1145 -            this.valueHasMutated();
  3.1146 -        }
  3.1147 -    }
  3.1148 -}
  3.1149 -
  3.1150 -// Populate ko.observableArray.fn with read/write functions from native arrays
  3.1151 -// Important: Do not add any additional functions here that may reasonably be used to *read* data from the array
  3.1152 -// because we'll eval them without causing subscriptions, so ko.computed output could end up getting stale
  3.1153 -ko.utils.arrayForEach(["pop", "push", "reverse", "shift", "sort", "splice", "unshift"], function (methodName) {
  3.1154 -    ko.observableArray['fn'][methodName] = function () {
  3.1155 -        // Use "peek" to avoid creating a subscription in any computed that we're executing in the context of
  3.1156 -        // (for consistency with mutating regular observables)
  3.1157 -        var underlyingArray = this.peek();
  3.1158 -        this.valueWillMutate();
  3.1159 -        var methodCallResult = underlyingArray[methodName].apply(underlyingArray, arguments);
  3.1160 -        this.valueHasMutated();
  3.1161 -        return methodCallResult;
  3.1162 -    };
  3.1163 -});
  3.1164 -
  3.1165 -// Populate ko.observableArray.fn with read-only functions from native arrays
  3.1166 -ko.utils.arrayForEach(["slice"], function (methodName) {
  3.1167 -    ko.observableArray['fn'][methodName] = function () {
  3.1168 -        var underlyingArray = this();
  3.1169 -        return underlyingArray[methodName].apply(underlyingArray, arguments);
  3.1170 -    };
  3.1171 -});
  3.1172 -
  3.1173 -ko.exportSymbol('observableArray', ko.observableArray);
  3.1174 -ko.dependentObservable = function (evaluatorFunctionOrOptions, evaluatorFunctionTarget, options) {
  3.1175 -    var _latestValue,
  3.1176 -        _hasBeenEvaluated = false,
  3.1177 -        _isBeingEvaluated = false,
  3.1178 -        readFunction = evaluatorFunctionOrOptions;
  3.1179 -
  3.1180 -    if (readFunction && typeof readFunction == "object") {
  3.1181 -        // Single-parameter syntax - everything is on this "options" param
  3.1182 -        options = readFunction;
  3.1183 -        readFunction = options["read"];
  3.1184 -    } else {
  3.1185 -        // Multi-parameter syntax - construct the options according to the params passed
  3.1186 -        options = options || {};
  3.1187 -        if (!readFunction)
  3.1188 -            readFunction = options["read"];
  3.1189 -    }
  3.1190 -    if (typeof readFunction != "function")
  3.1191 -        throw new Error("Pass a function that returns the value of the ko.computed");
  3.1192 -
  3.1193 -    function addSubscriptionToDependency(subscribable) {
  3.1194 -        _subscriptionsToDependencies.push(subscribable.subscribe(evaluatePossiblyAsync));
  3.1195 -    }
  3.1196 -
  3.1197 -    function disposeAllSubscriptionsToDependencies() {
  3.1198 -        ko.utils.arrayForEach(_subscriptionsToDependencies, function (subscription) {
  3.1199 -            subscription.dispose();
  3.1200 -        });
  3.1201 -        _subscriptionsToDependencies = [];
  3.1202 -    }
  3.1203 -
  3.1204 -    function evaluatePossiblyAsync() {
  3.1205 -        var throttleEvaluationTimeout = dependentObservable['throttleEvaluation'];
  3.1206 -        if (throttleEvaluationTimeout && throttleEvaluationTimeout >= 0) {
  3.1207 -            clearTimeout(evaluationTimeoutInstance);
  3.1208 -            evaluationTimeoutInstance = setTimeout(evaluateImmediate, throttleEvaluationTimeout);
  3.1209 -        } else
  3.1210 -            evaluateImmediate();
  3.1211 -    }
  3.1212 -
  3.1213 -    function evaluateImmediate() {
  3.1214 -        if (_isBeingEvaluated) {
  3.1215 -            // If the evaluation of a ko.computed causes side effects, it's possible that it will trigger its own re-evaluation.
  3.1216 -            // This is not desirable (it's hard for a developer to realise a chain of dependencies might cause this, and they almost
  3.1217 -            // certainly didn't intend infinite re-evaluations). So, for predictability, we simply prevent ko.computeds from causing
  3.1218 -            // their own re-evaluation. Further discussion at https://github.com/SteveSanderson/knockout/pull/387
  3.1219 -            return;
  3.1220 -        }
  3.1221 -
  3.1222 -        // Don't dispose on first evaluation, because the "disposeWhen" callback might
  3.1223 -        // e.g., dispose when the associated DOM element isn't in the doc, and it's not
  3.1224 -        // going to be in the doc until *after* the first evaluation
  3.1225 -        if (_hasBeenEvaluated && disposeWhen()) {
  3.1226 -            dispose();
  3.1227 -            return;
  3.1228 -        }
  3.1229 -
  3.1230 -        _isBeingEvaluated = true;
  3.1231 -        try {
  3.1232 -            // Initially, we assume that none of the subscriptions are still being used (i.e., all are candidates for disposal).
  3.1233 -            // Then, during evaluation, we cross off any that are in fact still being used.
  3.1234 -            var disposalCandidates = ko.utils.arrayMap(_subscriptionsToDependencies, function(item) {return item.target;});
  3.1235 -
  3.1236 -            ko.dependencyDetection.begin(function(subscribable) {
  3.1237 -                var inOld;
  3.1238 -                if ((inOld = ko.utils.arrayIndexOf(disposalCandidates, subscribable)) >= 0)
  3.1239 -                    disposalCandidates[inOld] = undefined; // Don't want to dispose this subscription, as it's still being used
  3.1240 -                else
  3.1241 -                    addSubscriptionToDependency(subscribable); // Brand new subscription - add it
  3.1242 -            });
  3.1243 -
  3.1244 -            var newValue = readFunction.call(evaluatorFunctionTarget);
  3.1245 -
  3.1246 -            // For each subscription no longer being used, remove it from the active subscriptions list and dispose it
  3.1247 -            for (var i = disposalCandidates.length - 1; i >= 0; i--) {
  3.1248 -                if (disposalCandidates[i])
  3.1249 -                    _subscriptionsToDependencies.splice(i, 1)[0].dispose();
  3.1250 -            }
  3.1251 -            _hasBeenEvaluated = true;
  3.1252 -
  3.1253 -            dependentObservable["notifySubscribers"](_latestValue, "beforeChange");
  3.1254 -            _latestValue = newValue;
  3.1255 -            if (DEBUG) dependentObservable._latestValue = _latestValue;
  3.1256 -        } finally {
  3.1257 -            ko.dependencyDetection.end();
  3.1258 -        }
  3.1259 -
  3.1260 -        dependentObservable["notifySubscribers"](_latestValue);
  3.1261 -        _isBeingEvaluated = false;
  3.1262 -        if (!_subscriptionsToDependencies.length)
  3.1263 -            dispose();
  3.1264 -    }
  3.1265 -
  3.1266 -    function dependentObservable() {
  3.1267 -        if (arguments.length > 0) {
  3.1268 -            if (typeof writeFunction === "function") {
  3.1269 -                // Writing a value
  3.1270 -                writeFunction.apply(evaluatorFunctionTarget, arguments);
  3.1271 -            } else {
  3.1272 -                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.");
  3.1273 -            }
  3.1274 -            return this; // Permits chained assignments
  3.1275 -        } else {
  3.1276 -            // Reading the value
  3.1277 -            if (!_hasBeenEvaluated)
  3.1278 -                evaluateImmediate();
  3.1279 -            ko.dependencyDetection.registerDependency(dependentObservable);
  3.1280 -            return _latestValue;
  3.1281 -        }
  3.1282 -    }
  3.1283 -
  3.1284 -    function peek() {
  3.1285 -        if (!_hasBeenEvaluated)
  3.1286 -            evaluateImmediate();
  3.1287 -        return _latestValue;
  3.1288 -    }
  3.1289 -
  3.1290 -    function isActive() {
  3.1291 -        return !_hasBeenEvaluated || _subscriptionsToDependencies.length > 0;
  3.1292 -    }
  3.1293 -
  3.1294 -    // By here, "options" is always non-null
  3.1295 -    var writeFunction = options["write"],
  3.1296 -        disposeWhenNodeIsRemoved = options["disposeWhenNodeIsRemoved"] || options.disposeWhenNodeIsRemoved || null,
  3.1297 -        disposeWhen = options["disposeWhen"] || options.disposeWhen || function() { return false; },
  3.1298 -        dispose = disposeAllSubscriptionsToDependencies,
  3.1299 -        _subscriptionsToDependencies = [],
  3.1300 -        evaluationTimeoutInstance = null;
  3.1301 -
  3.1302 -    if (!evaluatorFunctionTarget)
  3.1303 -        evaluatorFunctionTarget = options["owner"];
  3.1304 -
  3.1305 -    dependentObservable.peek = peek;
  3.1306 -    dependentObservable.getDependenciesCount = function () { return _subscriptionsToDependencies.length; };
  3.1307 -    dependentObservable.hasWriteFunction = typeof options["write"] === "function";
  3.1308 -    dependentObservable.dispose = function () { dispose(); };
  3.1309 -    dependentObservable.isActive = isActive;
  3.1310 -    dependentObservable.valueHasMutated = function() {
  3.1311 -        _hasBeenEvaluated = false;
  3.1312 -        evaluateImmediate();
  3.1313 -    };
  3.1314 -
  3.1315 -    ko.subscribable.call(dependentObservable);
  3.1316 -    ko.utils.extend(dependentObservable, ko.dependentObservable['fn']);
  3.1317 -
  3.1318 -    ko.exportProperty(dependentObservable, 'valueHasMutated', dependentObservable.valueHasMutated);
  3.1319 -    ko.exportProperty(dependentObservable, 'peek', dependentObservable.peek);
  3.1320 -    ko.exportProperty(dependentObservable, 'dispose', dependentObservable.dispose);
  3.1321 -    ko.exportProperty(dependentObservable, 'isActive', dependentObservable.isActive);
  3.1322 -    ko.exportProperty(dependentObservable, 'getDependenciesCount', dependentObservable.getDependenciesCount);
  3.1323 -
  3.1324 -    // Evaluate, unless deferEvaluation is true
  3.1325 -    if (options['deferEvaluation'] !== true)
  3.1326 -        evaluateImmediate();
  3.1327 -
  3.1328 -    // Build "disposeWhenNodeIsRemoved" and "disposeWhenNodeIsRemovedCallback" option values.
  3.1329 -    // But skip if isActive is false (there will never be any dependencies to dispose).
  3.1330 -    // (Note: "disposeWhenNodeIsRemoved" option both proactively disposes as soon as the node is removed using ko.removeNode(),
  3.1331 -    // plus adds a "disposeWhen" callback that, on each evaluation, disposes if the node was removed by some other means.)
  3.1332 -    if (disposeWhenNodeIsRemoved && isActive()) {
  3.1333 -        dispose = function() {
  3.1334 -            ko.utils.domNodeDisposal.removeDisposeCallback(disposeWhenNodeIsRemoved, arguments.callee);
  3.1335 -            disposeAllSubscriptionsToDependencies();
  3.1336 -        };
  3.1337 -        ko.utils.domNodeDisposal.addDisposeCallback(disposeWhenNodeIsRemoved, dispose);
  3.1338 -        var existingDisposeWhenFunction = disposeWhen;
  3.1339 -        disposeWhen = function () {
  3.1340 -            return !ko.utils.domNodeIsAttachedToDocument(disposeWhenNodeIsRemoved) || existingDisposeWhenFunction();
  3.1341 -        }
  3.1342 -    }
  3.1343 -
  3.1344 -    return dependentObservable;
  3.1345 -};
  3.1346 -
  3.1347 -ko.isComputed = function(instance) {
  3.1348 -    return ko.hasPrototype(instance, ko.dependentObservable);
  3.1349 -};
  3.1350 -
  3.1351 -var protoProp = ko.observable.protoProperty; // == "__ko_proto__"
  3.1352 -ko.dependentObservable[protoProp] = ko.observable;
  3.1353 -
  3.1354 -ko.dependentObservable['fn'] = {};
  3.1355 -ko.dependentObservable['fn'][protoProp] = ko.dependentObservable;
  3.1356 -
  3.1357 -ko.exportSymbol('dependentObservable', ko.dependentObservable);
  3.1358 -ko.exportSymbol('computed', ko.dependentObservable); // Make "ko.computed" an alias for "ko.dependentObservable"
  3.1359 -ko.exportSymbol('isComputed', ko.isComputed);
  3.1360 -
  3.1361 -(function() {
  3.1362 -    var maxNestedObservableDepth = 10; // Escape the (unlikely) pathalogical case where an observable's current value is itself (or similar reference cycle)
  3.1363 -
  3.1364 -    ko.toJS = function(rootObject) {
  3.1365 -        if (arguments.length == 0)
  3.1366 -            throw new Error("When calling ko.toJS, pass the object you want to convert.");
  3.1367 -
  3.1368 -        // We just unwrap everything at every level in the object graph
  3.1369 -        return mapJsObjectGraph(rootObject, function(valueToMap) {
  3.1370 -            // Loop because an observable's value might in turn be another observable wrapper
  3.1371 -            for (var i = 0; ko.isObservable(valueToMap) && (i < maxNestedObservableDepth); i++)
  3.1372 -                valueToMap = valueToMap();
  3.1373 -            return valueToMap;
  3.1374 -        });
  3.1375 -    };
  3.1376 -
  3.1377 -    ko.toJSON = function(rootObject, replacer, space) {     // replacer and space are optional
  3.1378 -        var plainJavaScriptObject = ko.toJS(rootObject);
  3.1379 -        return ko.utils.stringifyJson(plainJavaScriptObject, replacer, space);
  3.1380 -    };
  3.1381 -
  3.1382 -    function mapJsObjectGraph(rootObject, mapInputCallback, visitedObjects) {
  3.1383 -        visitedObjects = visitedObjects || new objectLookup();
  3.1384 -
  3.1385 -        rootObject = mapInputCallback(rootObject);
  3.1386 -        var canHaveProperties = (typeof rootObject == "object") && (rootObject !== null) && (rootObject !== undefined) && (!(rootObject instanceof Date));
  3.1387 -        if (!canHaveProperties)
  3.1388 -            return rootObject;
  3.1389 -
  3.1390 -        var outputProperties = rootObject instanceof Array ? [] : {};
  3.1391 -        visitedObjects.save(rootObject, outputProperties);
  3.1392 -
  3.1393 -        visitPropertiesOrArrayEntries(rootObject, function(indexer) {
  3.1394 -            var propertyValue = mapInputCallback(rootObject[indexer]);
  3.1395 -
  3.1396 -            switch (typeof propertyValue) {
  3.1397 -                case "boolean":
  3.1398 -                case "number":
  3.1399 -                case "string":
  3.1400 -                case "function":
  3.1401 -                    outputProperties[indexer] = propertyValue;
  3.1402 -                    break;
  3.1403 -                case "object":
  3.1404 -                case "undefined":
  3.1405 -                    var previouslyMappedValue = visitedObjects.get(propertyValue);
  3.1406 -                    outputProperties[indexer] = (previouslyMappedValue !== undefined)
  3.1407 -                        ? previouslyMappedValue
  3.1408 -                        : mapJsObjectGraph(propertyValue, mapInputCallback, visitedObjects);
  3.1409 -                    break;
  3.1410 -            }
  3.1411 -        });
  3.1412 -
  3.1413 -        return outputProperties;
  3.1414 -    }
  3.1415 -
  3.1416 -    function visitPropertiesOrArrayEntries(rootObject, visitorCallback) {
  3.1417 -        if (rootObject instanceof Array) {
  3.1418 -            for (var i = 0; i < rootObject.length; i++)
  3.1419 -                visitorCallback(i);
  3.1420 -
  3.1421 -            // For arrays, also respect toJSON property for custom mappings (fixes #278)
  3.1422 -            if (typeof rootObject['toJSON'] == 'function')
  3.1423 -                visitorCallback('toJSON');
  3.1424 -        } else {
  3.1425 -            for (var propertyName in rootObject)
  3.1426 -                visitorCallback(propertyName);
  3.1427 -        }
  3.1428 -    };
  3.1429 -
  3.1430 -    function objectLookup() {
  3.1431 -        var keys = [];
  3.1432 -        var values = [];
  3.1433 -        this.save = function(key, value) {
  3.1434 -            var existingIndex = ko.utils.arrayIndexOf(keys, key);
  3.1435 -            if (existingIndex >= 0)
  3.1436 -                values[existingIndex] = value;
  3.1437 -            else {
  3.1438 -                keys.push(key);
  3.1439 -                values.push(value);
  3.1440 -            }
  3.1441 -        };
  3.1442 -        this.get = function(key) {
  3.1443 -            var existingIndex = ko.utils.arrayIndexOf(keys, key);
  3.1444 -            return (existingIndex >= 0) ? values[existingIndex] : undefined;
  3.1445 -        };
  3.1446 -    };
  3.1447 -})();
  3.1448 -
  3.1449 -ko.exportSymbol('toJS', ko.toJS);
  3.1450 -ko.exportSymbol('toJSON', ko.toJSON);
  3.1451 -(function () {
  3.1452 -    var hasDomDataExpandoProperty = '__ko__hasDomDataOptionValue__';
  3.1453 -
  3.1454 -    // Normally, SELECT elements and their OPTIONs can only take value of type 'string' (because the values
  3.1455 -    // are stored on DOM attributes). ko.selectExtensions provides a way for SELECTs/OPTIONs to have values
  3.1456 -    // that are arbitrary objects. This is very convenient when implementing things like cascading dropdowns.
  3.1457 -    ko.selectExtensions = {
  3.1458 -        readValue : function(element) {
  3.1459 -            switch (ko.utils.tagNameLower(element)) {
  3.1460 -                case 'option':
  3.1461 -                    if (element[hasDomDataExpandoProperty] === true)
  3.1462 -                        return ko.utils.domData.get(element, ko.bindingHandlers.options.optionValueDomDataKey);
  3.1463 -                    return ko.utils.ieVersion <= 7
  3.1464 -                        ? (element.getAttributeNode('value').specified ? element.value : element.text)
  3.1465 -                        : element.value;
  3.1466 -                case 'select':
  3.1467 -                    return element.selectedIndex >= 0 ? ko.selectExtensions.readValue(element.options[element.selectedIndex]) : undefined;
  3.1468 -                default:
  3.1469 -                    return element.value;
  3.1470 -            }
  3.1471 -        },
  3.1472 -
  3.1473 -        writeValue: function(element, value) {
  3.1474 -            switch (ko.utils.tagNameLower(element)) {
  3.1475 -                case 'option':
  3.1476 -                    switch(typeof value) {
  3.1477 -                        case "string":
  3.1478 -                            ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, undefined);
  3.1479 -                            if (hasDomDataExpandoProperty in element) { // IE <= 8 throws errors if you delete non-existent properties from a DOM node
  3.1480 -                                delete element[hasDomDataExpandoProperty];
  3.1481 -                            }
  3.1482 -                            element.value = value;
  3.1483 -                            break;
  3.1484 -                        default:
  3.1485 -                            // Store arbitrary object using DomData
  3.1486 -                            ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, value);
  3.1487 -                            element[hasDomDataExpandoProperty] = true;
  3.1488 -
  3.1489 -                            // Special treatment of numbers is just for backward compatibility. KO 1.2.1 wrote numerical values to element.value.
  3.1490 -                            element.value = typeof value === "number" ? value : "";
  3.1491 -                            break;
  3.1492 -                    }
  3.1493 -                    break;
  3.1494 -                case 'select':
  3.1495 -                    for (var i = element.options.length - 1; i >= 0; i--) {
  3.1496 -                        if (ko.selectExtensions.readValue(element.options[i]) == value) {
  3.1497 -                            element.selectedIndex = i;
  3.1498 -                            break;
  3.1499 -                        }
  3.1500 -                    }
  3.1501 -                    break;
  3.1502 -                default:
  3.1503 -                    if ((value === null) || (value === undefined))
  3.1504 -                        value = "";
  3.1505 -                    element.value = value;
  3.1506 -                    break;
  3.1507 -            }
  3.1508 -        }
  3.1509 -    };
  3.1510 -})();
  3.1511 -
  3.1512 -ko.exportSymbol('selectExtensions', ko.selectExtensions);
  3.1513 -ko.exportSymbol('selectExtensions.readValue', ko.selectExtensions.readValue);
  3.1514 -ko.exportSymbol('selectExtensions.writeValue', ko.selectExtensions.writeValue);
  3.1515 -ko.expressionRewriting = (function () {
  3.1516 -    var restoreCapturedTokensRegex = /\@ko_token_(\d+)\@/g;
  3.1517 -    var javaScriptReservedWords = ["true", "false"];
  3.1518 -
  3.1519 -    // Matches something that can be assigned to--either an isolated identifier or something ending with a property accessor
  3.1520 -    // This is designed to be simple and avoid false negatives, but could produce false positives (e.g., a+b.c).
  3.1521 -    var javaScriptAssignmentTarget = /^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i;
  3.1522 -
  3.1523 -    function restoreTokens(string, tokens) {
  3.1524 -        var prevValue = null;
  3.1525 -        while (string != prevValue) { // Keep restoring tokens until it no longer makes a difference (they may be nested)
  3.1526 -            prevValue = string;
  3.1527 -            string = string.replace(restoreCapturedTokensRegex, function (match, tokenIndex) {
  3.1528 -                return tokens[tokenIndex];
  3.1529 -            });
  3.1530 -        }
  3.1531 -        return string;
  3.1532 -    }
  3.1533 -
  3.1534 -    function getWriteableValue(expression) {
  3.1535 -        if (ko.utils.arrayIndexOf(javaScriptReservedWords, ko.utils.stringTrim(expression).toLowerCase()) >= 0)
  3.1536 -            return false;
  3.1537 -        var match = expression.match(javaScriptAssignmentTarget);
  3.1538 -        return match === null ? false : match[1] ? ('Object(' + match[1] + ')' + match[2]) : expression;
  3.1539 -    }
  3.1540 -
  3.1541 -    function ensureQuoted(key) {
  3.1542 -        var trimmedKey = ko.utils.stringTrim(key);
  3.1543 -        switch (trimmedKey.length && trimmedKey.charAt(0)) {
  3.1544 -            case "'":
  3.1545 -            case '"':
  3.1546 -                return key;
  3.1547 -            default:
  3.1548 -                return "'" + trimmedKey + "'";
  3.1549 -        }
  3.1550 -    }
  3.1551 -
  3.1552 -    return {
  3.1553 -        bindingRewriteValidators: [],
  3.1554 -
  3.1555 -        parseObjectLiteral: function(objectLiteralString) {
  3.1556 -            // A full tokeniser+lexer would add too much weight to this library, so here's a simple parser
  3.1557 -            // that is sufficient just to split an object literal string into a set of top-level key-value pairs
  3.1558 -
  3.1559 -            var str = ko.utils.stringTrim(objectLiteralString);
  3.1560 -            if (str.length < 3)
  3.1561 -                return [];
  3.1562 -            if (str.charAt(0) === "{")// Ignore any braces surrounding the whole object literal
  3.1563 -                str = str.substring(1, str.length - 1);
  3.1564 -
  3.1565 -            // Pull out any string literals and regex literals
  3.1566 -            var tokens = [];
  3.1567 -            var tokenStart = null, tokenEndChar;
  3.1568 -            for (var position = 0; position < str.length; position++) {
  3.1569 -                var c = str.charAt(position);
  3.1570 -                if (tokenStart === null) {
  3.1571 -                    switch (c) {
  3.1572 -                        case '"':
  3.1573 -                        case "'":
  3.1574 -                        case "/":
  3.1575 -                            tokenStart = position;
  3.1576 -                            tokenEndChar = c;
  3.1577 -                            break;
  3.1578 -                    }
  3.1579 -                } else if ((c == tokenEndChar) && (str.charAt(position - 1) !== "\\")) {
  3.1580 -                    var token = str.substring(tokenStart, position + 1);
  3.1581 -                    tokens.push(token);
  3.1582 -                    var replacement = "@ko_token_" + (tokens.length - 1) + "@";
  3.1583 -                    str = str.substring(0, tokenStart) + replacement + str.substring(position + 1);
  3.1584 -                    position -= (token.length - replacement.length);
  3.1585 -                    tokenStart = null;
  3.1586 -                }
  3.1587 -            }
  3.1588 -
  3.1589 -            // Next pull out balanced paren, brace, and bracket blocks
  3.1590 -            tokenStart = null;
  3.1591 -            tokenEndChar = null;
  3.1592 -            var tokenDepth = 0, tokenStartChar = null;
  3.1593 -            for (var position = 0; position < str.length; position++) {
  3.1594 -                var c = str.charAt(position);
  3.1595 -                if (tokenStart === null) {
  3.1596 -                    switch (c) {
  3.1597 -                        case "{": tokenStart = position; tokenStartChar = c;
  3.1598 -                                  tokenEndChar = "}";
  3.1599 -                                  break;
  3.1600 -                        case "(": tokenStart = position; tokenStartChar = c;
  3.1601 -                                  tokenEndChar = ")";
  3.1602 -                                  break;
  3.1603 -                        case "[": tokenStart = position; tokenStartChar = c;
  3.1604 -                                  tokenEndChar = "]";
  3.1605 -                                  break;
  3.1606 -                    }
  3.1607 -                }
  3.1608 -
  3.1609 -                if (c === tokenStartChar)
  3.1610 -                    tokenDepth++;
  3.1611 -                else if (c === tokenEndChar) {
  3.1612 -                    tokenDepth--;
  3.1613 -                    if (tokenDepth === 0) {
  3.1614 -                        var token = str.substring(tokenStart, position + 1);
  3.1615 -                        tokens.push(token);
  3.1616 -                        var replacement = "@ko_token_" + (tokens.length - 1) + "@";
  3.1617 -                        str = str.substring(0, tokenStart) + replacement + str.substring(position + 1);
  3.1618 -                        position -= (token.length - replacement.length);
  3.1619 -                        tokenStart = null;
  3.1620 -                    }
  3.1621 -                }
  3.1622 -            }
  3.1623 -
  3.1624 -            // Now we can safely split on commas to get the key/value pairs
  3.1625 -            var result = [];
  3.1626 -            var keyValuePairs = str.split(",");
  3.1627 -            for (var i = 0, j = keyValuePairs.length; i < j; i++) {
  3.1628 -                var pair = keyValuePairs[i];
  3.1629 -                var colonPos = pair.indexOf(":");
  3.1630 -                if ((colonPos > 0) && (colonPos < pair.length - 1)) {
  3.1631 -                    var key = pair.substring(0, colonPos);
  3.1632 -                    var value = pair.substring(colonPos + 1);
  3.1633 -                    result.push({ 'key': restoreTokens(key, tokens), 'value': restoreTokens(value, tokens) });
  3.1634 -                } else {
  3.1635 -                    result.push({ 'unknown': restoreTokens(pair, tokens) });
  3.1636 -                }
  3.1637 -            }
  3.1638 -            return result;
  3.1639 -        },
  3.1640 -
  3.1641 -        preProcessBindings: function (objectLiteralStringOrKeyValueArray) {
  3.1642 -            var keyValueArray = typeof objectLiteralStringOrKeyValueArray === "string"
  3.1643 -                ? ko.expressionRewriting.parseObjectLiteral(objectLiteralStringOrKeyValueArray)
  3.1644 -                : objectLiteralStringOrKeyValueArray;
  3.1645 -            var resultStrings = [], propertyAccessorResultStrings = [];
  3.1646 -
  3.1647 -            var keyValueEntry;
  3.1648 -            for (var i = 0; keyValueEntry = keyValueArray[i]; i++) {
  3.1649 -                if (resultStrings.length > 0)
  3.1650 -                    resultStrings.push(",");
  3.1651 -
  3.1652 -                if (keyValueEntry['key']) {
  3.1653 -                    var quotedKey = ensureQuoted(keyValueEntry['key']), val = keyValueEntry['value'];
  3.1654 -                    resultStrings.push(quotedKey);
  3.1655 -                    resultStrings.push(":");
  3.1656 -                    resultStrings.push(val);
  3.1657 -
  3.1658 -                    if (val = getWriteableValue(ko.utils.stringTrim(val))) {
  3.1659 -                        if (propertyAccessorResultStrings.length > 0)
  3.1660 -                            propertyAccessorResultStrings.push(", ");
  3.1661 -                        propertyAccessorResultStrings.push(quotedKey + " : function(__ko_value) { " + val + " = __ko_value; }");
  3.1662 -                    }
  3.1663 -                } else if (keyValueEntry['unknown']) {
  3.1664 -                    resultStrings.push(keyValueEntry['unknown']);
  3.1665 -                }
  3.1666 -            }
  3.1667 -
  3.1668 -            var combinedResult = resultStrings.join("");
  3.1669 -            if (propertyAccessorResultStrings.length > 0) {
  3.1670 -                var allPropertyAccessors = propertyAccessorResultStrings.join("");
  3.1671 -                combinedResult = combinedResult + ", '_ko_property_writers' : { " + allPropertyAccessors + " } ";
  3.1672 -            }
  3.1673 -
  3.1674 -            return combinedResult;
  3.1675 -        },
  3.1676 -
  3.1677 -        keyValueArrayContainsKey: function(keyValueArray, key) {
  3.1678 -            for (var i = 0; i < keyValueArray.length; i++)
  3.1679 -                if (ko.utils.stringTrim(keyValueArray[i]['key']) == key)
  3.1680 -                    return true;
  3.1681 -            return false;
  3.1682 -        },
  3.1683 -
  3.1684 -        // Internal, private KO utility for updating model properties from within bindings
  3.1685 -        // property:            If the property being updated is (or might be) an observable, pass it here
  3.1686 -        //                      If it turns out to be a writable observable, it will be written to directly
  3.1687 -        // allBindingsAccessor: All bindings in the current execution context.
  3.1688 -        //                      This will be searched for a '_ko_property_writers' property in case you're writing to a non-observable
  3.1689 -        // key:                 The key identifying the property to be written. Example: for { hasFocus: myValue }, write to 'myValue' by specifying the key 'hasFocus'
  3.1690 -        // value:               The value to be written
  3.1691 -        // checkIfDifferent:    If true, and if the property being written is a writable observable, the value will only be written if
  3.1692 -        //                      it is !== existing value on that writable observable
  3.1693 -        writeValueToProperty: function(property, allBindingsAccessor, key, value, checkIfDifferent) {
  3.1694 -            if (!property || !ko.isWriteableObservable(property)) {
  3.1695 -                var propWriters = allBindingsAccessor()['_ko_property_writers'];
  3.1696 -                if (propWriters && propWriters[key])
  3.1697 -                    propWriters[key](value);
  3.1698 -            } else if (!checkIfDifferent || property.peek() !== value) {
  3.1699 -                property(value);
  3.1700 -            }
  3.1701 -        }
  3.1702 -    };
  3.1703 -})();
  3.1704 -
  3.1705 -ko.exportSymbol('expressionRewriting', ko.expressionRewriting);
  3.1706 -ko.exportSymbol('expressionRewriting.bindingRewriteValidators', ko.expressionRewriting.bindingRewriteValidators);
  3.1707 -ko.exportSymbol('expressionRewriting.parseObjectLiteral', ko.expressionRewriting.parseObjectLiteral);
  3.1708 -ko.exportSymbol('expressionRewriting.preProcessBindings', ko.expressionRewriting.preProcessBindings);
  3.1709 -
  3.1710 -// For backward compatibility, define the following aliases. (Previously, these function names were misleading because
  3.1711 -// they referred to JSON specifically, even though they actually work with arbitrary JavaScript object literal expressions.)
  3.1712 -ko.exportSymbol('jsonExpressionRewriting', ko.expressionRewriting);
  3.1713 -ko.exportSymbol('jsonExpressionRewriting.insertPropertyAccessorsIntoJson', ko.expressionRewriting.preProcessBindings);(function() {
  3.1714 -    // "Virtual elements" is an abstraction on top of the usual DOM API which understands the notion that comment nodes
  3.1715 -    // may be used to represent hierarchy (in addition to the DOM's natural hierarchy).
  3.1716 -    // If you call the DOM-manipulating functions on ko.virtualElements, you will be able to read and write the state
  3.1717 -    // of that virtual hierarchy
  3.1718 -    //
  3.1719 -    // The point of all this is to support containerless templates (e.g., <!-- ko foreach:someCollection -->blah<!-- /ko -->)
  3.1720 -    // without having to scatter special cases all over the binding and templating code.
  3.1721 -
  3.1722 -    // IE 9 cannot reliably read the "nodeValue" property of a comment node (see https://github.com/SteveSanderson/knockout/issues/186)
  3.1723 -    // but it does give them a nonstandard alternative property called "text" that it can read reliably. Other browsers don't have that property.
  3.1724 -    // So, use node.text where available, and node.nodeValue elsewhere
  3.1725 -    var commentNodesHaveTextProperty = document.createComment("test").text === "<!--test-->";
  3.1726 -
  3.1727 -    var startCommentRegex = commentNodesHaveTextProperty ? /^<!--\s*ko(?:\s+(.+\s*\:[\s\S]*))?\s*-->$/ : /^\s*ko(?:\s+(.+\s*\:[\s\S]*))?\s*$/;
  3.1728 -    var endCommentRegex =   commentNodesHaveTextProperty ? /^<!--\s*\/ko\s*-->$/ : /^\s*\/ko\s*$/;
  3.1729 -    var htmlTagsWithOptionallyClosingChildren = { 'ul': true, 'ol': true };
  3.1730 -
  3.1731 -    function isStartComment(node) {
  3.1732 -        return (node.nodeType == 8) && (commentNodesHaveTextProperty ? node.text : node.nodeValue).match(startCommentRegex);
  3.1733 -    }
  3.1734 -
  3.1735 -    function isEndComment(node) {
  3.1736 -        return (node.nodeType == 8) && (commentNodesHaveTextProperty ? node.text : node.nodeValue).match(endCommentRegex);
  3.1737 -    }
  3.1738 -
  3.1739 -    function getVirtualChildren(startComment, allowUnbalanced) {
  3.1740 -        var currentNode = startComment;
  3.1741 -        var depth = 1;
  3.1742 -        var children = [];
  3.1743 -        while (currentNode = currentNode.nextSibling) {
  3.1744 -            if (isEndComment(currentNode)) {
  3.1745 -                depth--;
  3.1746 -                if (depth === 0)
  3.1747 -                    return children;
  3.1748 -            }
  3.1749 -
  3.1750 -            children.push(currentNode);
  3.1751 -
  3.1752 -            if (isStartComment(currentNode))
  3.1753 -                depth++;
  3.1754 -        }
  3.1755 -        if (!allowUnbalanced)
  3.1756 -            throw new Error("Cannot find closing comment tag to match: " + startComment.nodeValue);
  3.1757 -        return null;
  3.1758 -    }
  3.1759 -
  3.1760 -    function getMatchingEndComment(startComment, allowUnbalanced) {
  3.1761 -        var allVirtualChildren = getVirtualChildren(startComment, allowUnbalanced);
  3.1762 -        if (allVirtualChildren) {
  3.1763 -            if (allVirtualChildren.length > 0)
  3.1764 -                return allVirtualChildren[allVirtualChildren.length - 1].nextSibling;
  3.1765 -            return startComment.nextSibling;
  3.1766 -        } else
  3.1767 -            return null; // Must have no matching end comment, and allowUnbalanced is true
  3.1768 -    }
  3.1769 -
  3.1770 -    function getUnbalancedChildTags(node) {
  3.1771 -        // e.g., from <div>OK</div><!-- ko blah --><span>Another</span>, returns: <!-- ko blah --><span>Another</span>
  3.1772 -        //       from <div>OK</div><!-- /ko --><!-- /ko -->,             returns: <!-- /ko --><!-- /ko -->
  3.1773 -        var childNode = node.firstChild, captureRemaining = null;
  3.1774 -        if (childNode) {
  3.1775 -            do {
  3.1776 -                if (captureRemaining)                   // We already hit an unbalanced node and are now just scooping up all subsequent nodes
  3.1777 -                    captureRemaining.push(childNode);
  3.1778 -                else if (isStartComment(childNode)) {
  3.1779 -                    var matchingEndComment = getMatchingEndComment(childNode, /* allowUnbalanced: */ true);
  3.1780 -                    if (matchingEndComment)             // It's a balanced tag, so skip immediately to the end of this virtual set
  3.1781 -                        childNode = matchingEndComment;
  3.1782 -                    else
  3.1783 -                        captureRemaining = [childNode]; // It's unbalanced, so start capturing from this point
  3.1784 -                } else if (isEndComment(childNode)) {
  3.1785 -                    captureRemaining = [childNode];     // It's unbalanced (if it wasn't, we'd have skipped over it already), so start capturing
  3.1786 -                }
  3.1787 -            } while (childNode = childNode.nextSibling);
  3.1788 -        }
  3.1789 -        return captureRemaining;
  3.1790 -    }
  3.1791 -
  3.1792 -    ko.virtualElements = {
  3.1793 -        allowedBindings: {},
  3.1794 -
  3.1795 -        childNodes: function(node) {
  3.1796 -            return isStartComment(node) ? getVirtualChildren(node) : node.childNodes;
  3.1797 -        },
  3.1798 -
  3.1799 -        emptyNode: function(node) {
  3.1800 -            if (!isStartComment(node))
  3.1801 -                ko.utils.emptyDomNode(node);
  3.1802 -            else {
  3.1803 -                var virtualChildren = ko.virtualElements.childNodes(node);
  3.1804 -                for (var i = 0, j = virtualChildren.length; i < j; i++)
  3.1805 -                    ko.removeNode(virtualChildren[i]);
  3.1806 -            }
  3.1807 -        },
  3.1808 -
  3.1809 -        setDomNodeChildren: function(node, childNodes) {
  3.1810 -            if (!isStartComment(node))
  3.1811 -                ko.utils.setDomNodeChildren(node, childNodes);
  3.1812 -            else {
  3.1813 -                ko.virtualElements.emptyNode(node);
  3.1814 -                var endCommentNode = node.nextSibling; // Must be the next sibling, as we just emptied the children
  3.1815 -                for (var i = 0, j = childNodes.length; i < j; i++)
  3.1816 -                    endCommentNode.parentNode.insertBefore(childNodes[i], endCommentNode);
  3.1817 -            }
  3.1818 -        },
  3.1819 -
  3.1820 -        prepend: function(containerNode, nodeToPrepend) {
  3.1821 -            if (!isStartComment(containerNode)) {
  3.1822 -                if (containerNode.firstChild)
  3.1823 -                    containerNode.insertBefore(nodeToPrepend, containerNode.firstChild);
  3.1824 -                else
  3.1825 -                    containerNode.appendChild(nodeToPrepend);
  3.1826 -            } else {
  3.1827 -                // Start comments must always have a parent and at least one following sibling (the end comment)
  3.1828 -                containerNode.parentNode.insertBefore(nodeToPrepend, containerNode.nextSibling);
  3.1829 -            }
  3.1830 -        },
  3.1831 -
  3.1832 -        insertAfter: function(containerNode, nodeToInsert, insertAfterNode) {
  3.1833 -            if (!insertAfterNode) {
  3.1834 -                ko.virtualElements.prepend(containerNode, nodeToInsert);
  3.1835 -            } else if (!isStartComment(containerNode)) {
  3.1836 -                // Insert after insertion point
  3.1837 -                if (insertAfterNode.nextSibling)
  3.1838 -                    containerNode.insertBefore(nodeToInsert, insertAfterNode.nextSibling);
  3.1839 -                else
  3.1840 -                    containerNode.appendChild(nodeToInsert);
  3.1841 -            } else {
  3.1842 -                // Children of start comments must always have a parent and at least one following sibling (the end comment)
  3.1843 -                containerNode.parentNode.insertBefore(nodeToInsert, insertAfterNode.nextSibling);
  3.1844 -            }
  3.1845 -        },
  3.1846 -
  3.1847 -        firstChild: function(node) {
  3.1848 -            if (!isStartComment(node))
  3.1849 -                return node.firstChild;
  3.1850 -            if (!node.nextSibling || isEndComment(node.nextSibling))
  3.1851 -                return null;
  3.1852 -            return node.nextSibling;
  3.1853 -        },
  3.1854 -
  3.1855 -        nextSibling: function(node) {
  3.1856 -            if (isStartComment(node))
  3.1857 -                node = getMatchingEndComment(node);
  3.1858 -            if (node.nextSibling && isEndComment(node.nextSibling))
  3.1859 -                return null;
  3.1860 -            return node.nextSibling;
  3.1861 -        },
  3.1862 -
  3.1863 -        virtualNodeBindingValue: function(node) {
  3.1864 -            var regexMatch = isStartComment(node);
  3.1865 -            return regexMatch ? regexMatch[1] : null;
  3.1866 -        },
  3.1867 -
  3.1868 -        normaliseVirtualElementDomStructure: function(elementVerified) {
  3.1869 -            // Workaround for https://github.com/SteveSanderson/knockout/issues/155
  3.1870 -            // (IE <= 8 or IE 9 quirks mode parses your HTML weirdly, treating closing </li> tags as if they don't exist, thereby moving comment nodes
  3.1871 -            // that are direct descendants of <ul> into the preceding <li>)
  3.1872 -            if (!htmlTagsWithOptionallyClosingChildren[ko.utils.tagNameLower(elementVerified)])
  3.1873 -                return;
  3.1874 -
  3.1875 -            // Scan immediate children to see if they contain unbalanced comment tags. If they do, those comment tags
  3.1876 -            // must be intended to appear *after* that child, so move them there.
  3.1877 -            var childNode = elementVerified.firstChild;
  3.1878 -            if (childNode) {
  3.1879 -                do {
  3.1880 -                    if (childNode.nodeType === 1) {
  3.1881 -                        var unbalancedTags = getUnbalancedChildTags(childNode);
  3.1882 -                        if (unbalancedTags) {
  3.1883 -                            // Fix up the DOM by moving the unbalanced tags to where they most likely were intended to be placed - *after* the child
  3.1884 -                            var nodeToInsertBefore = childNode.nextSibling;
  3.1885 -                            for (var i = 0; i < unbalancedTags.length; i++) {
  3.1886 -                                if (nodeToInsertBefore)
  3.1887 -                                    elementVerified.insertBefore(unbalancedTags[i], nodeToInsertBefore);
  3.1888 -                                else
  3.1889 -                                    elementVerified.appendChild(unbalancedTags[i]);
  3.1890 -                            }
  3.1891 -                        }
  3.1892 -                    }
  3.1893 -                } while (childNode = childNode.nextSibling);
  3.1894 -            }
  3.1895 -        }
  3.1896 -    };
  3.1897 -})();
  3.1898 -ko.exportSymbol('virtualElements', ko.virtualElements);
  3.1899 -ko.exportSymbol('virtualElements.allowedBindings', ko.virtualElements.allowedBindings);
  3.1900 -ko.exportSymbol('virtualElements.emptyNode', ko.virtualElements.emptyNode);
  3.1901 -//ko.exportSymbol('virtualElements.firstChild', ko.virtualElements.firstChild);     // firstChild is not minified
  3.1902 -ko.exportSymbol('virtualElements.insertAfter', ko.virtualElements.insertAfter);
  3.1903 -//ko.exportSymbol('virtualElements.nextSibling', ko.virtualElements.nextSibling);   // nextSibling is not minified
  3.1904 -ko.exportSymbol('virtualElements.prepend', ko.virtualElements.prepend);
  3.1905 -ko.exportSymbol('virtualElements.setDomNodeChildren', ko.virtualElements.setDomNodeChildren);
  3.1906 -(function() {
  3.1907 -    var defaultBindingAttributeName = "data-bind";
  3.1908 -
  3.1909 -    ko.bindingProvider = function() {
  3.1910 -        this.bindingCache = {};
  3.1911 -    };
  3.1912 -
  3.1913 -    ko.utils.extend(ko.bindingProvider.prototype, {
  3.1914 -        'nodeHasBindings': function(node) {
  3.1915 -            switch (node.nodeType) {
  3.1916 -                case 1: return node.getAttribute(defaultBindingAttributeName) != null;   // Element
  3.1917 -                case 8: return ko.virtualElements.virtualNodeBindingValue(node) != null; // Comment node
  3.1918 -                default: return false;
  3.1919 -            }
  3.1920 -        },
  3.1921 -
  3.1922 -        'getBindings': function(node, bindingContext) {
  3.1923 -            var bindingsString = this['getBindingsString'](node, bindingContext);
  3.1924 -            return bindingsString ? this['parseBindingsString'](bindingsString, bindingContext, node) : null;
  3.1925 -        },
  3.1926 -
  3.1927 -        // The following function is only used internally by this default provider.
  3.1928 -        // It's not part of the interface definition for a general binding provider.
  3.1929 -        'getBindingsString': function(node, bindingContext) {
  3.1930 -            switch (node.nodeType) {
  3.1931 -                case 1: return node.getAttribute(defaultBindingAttributeName);   // Element
  3.1932 -                case 8: return ko.virtualElements.virtualNodeBindingValue(node); // Comment node
  3.1933 -                default: return null;
  3.1934 -            }
  3.1935 -        },
  3.1936 -
  3.1937 -        // The following function is only used internally by this default provider.
  3.1938 -        // It's not part of the interface definition for a general binding provider.
  3.1939 -        'parseBindingsString': function(bindingsString, bindingContext, node) {
  3.1940 -            try {
  3.1941 -                var bindingFunction = createBindingsStringEvaluatorViaCache(bindingsString, this.bindingCache);
  3.1942 -                return bindingFunction(bindingContext, node);
  3.1943 -            } catch (ex) {
  3.1944 -                throw new Error("Unable to parse bindings.\nMessage: " + ex + ";\nBindings value: " + bindingsString);
  3.1945 -            }
  3.1946 -        }
  3.1947 -    });
  3.1948 -
  3.1949 -    ko.bindingProvider['instance'] = new ko.bindingProvider();
  3.1950 -
  3.1951 -    function createBindingsStringEvaluatorViaCache(bindingsString, cache) {
  3.1952 -        var cacheKey = bindingsString;
  3.1953 -        return cache[cacheKey]
  3.1954 -            || (cache[cacheKey] = createBindingsStringEvaluator(bindingsString));
  3.1955 -    }
  3.1956 -
  3.1957 -    function createBindingsStringEvaluator(bindingsString) {
  3.1958 -        // Build the source for a function that evaluates "expression"
  3.1959 -        // For each scope variable, add an extra level of "with" nesting
  3.1960 -        // Example result: with(sc1) { with(sc0) { return (expression) } }
  3.1961 -        var rewrittenBindings = ko.expressionRewriting.preProcessBindings(bindingsString),
  3.1962 -            functionBody = "with($context){with($data||{}){return{" + rewrittenBindings + "}}}";
  3.1963 -        return new Function("$context", "$element", functionBody);
  3.1964 -    }
  3.1965 -})();
  3.1966 -
  3.1967 -ko.exportSymbol('bindingProvider', ko.bindingProvider);
  3.1968 -(function () {
  3.1969 -    ko.bindingHandlers = {};
  3.1970 -
  3.1971 -    ko.bindingContext = function(dataItem, parentBindingContext, dataItemAlias) {
  3.1972 -        if (parentBindingContext) {
  3.1973 -            ko.utils.extend(this, parentBindingContext); // Inherit $root and any custom properties
  3.1974 -            this['$parentContext'] = parentBindingContext;
  3.1975 -            this['$parent'] = parentBindingContext['$data'];
  3.1976 -            this['$parents'] = (parentBindingContext['$parents'] || []).slice(0);
  3.1977 -            this['$parents'].unshift(this['$parent']);
  3.1978 -        } else {
  3.1979 -            this['$parents'] = [];
  3.1980 -            this['$root'] = dataItem;
  3.1981 -            // Export 'ko' in the binding context so it will be available in bindings and templates
  3.1982 -            // even if 'ko' isn't exported as a global, such as when using an AMD loader.
  3.1983 -            // See https://github.com/SteveSanderson/knockout/issues/490
  3.1984 -            this['ko'] = ko;
  3.1985 -        }
  3.1986 -        this['$data'] = dataItem;
  3.1987 -        if (dataItemAlias)
  3.1988 -            this[dataItemAlias] = dataItem;
  3.1989 -    }
  3.1990 -    ko.bindingContext.prototype['createChildContext'] = function (dataItem, dataItemAlias) {
  3.1991 -        return new ko.bindingContext(dataItem, this, dataItemAlias);
  3.1992 -    };
  3.1993 -    ko.bindingContext.prototype['extend'] = function(properties) {
  3.1994 -        var clone = ko.utils.extend(new ko.bindingContext(), this);
  3.1995 -        return ko.utils.extend(clone, properties);
  3.1996 -    };
  3.1997 -
  3.1998 -    function validateThatBindingIsAllowedForVirtualElements(bindingName) {
  3.1999 -        var validator = ko.virtualElements.allowedBindings[bindingName];
  3.2000 -        if (!validator)
  3.2001 -            throw new Error("The binding '" + bindingName + "' cannot be used with virtual elements")
  3.2002 -    }
  3.2003 -
  3.2004 -    function applyBindingsToDescendantsInternal (viewModel, elementOrVirtualElement, bindingContextsMayDifferFromDomParentElement) {
  3.2005 -        var currentChild, nextInQueue = ko.virtualElements.firstChild(elementOrVirtualElement);
  3.2006 -        while (currentChild = nextInQueue) {
  3.2007 -            // Keep a record of the next child *before* applying bindings, in case the binding removes the current child from its position
  3.2008 -            nextInQueue = ko.virtualElements.nextSibling(currentChild);
  3.2009 -            applyBindingsToNodeAndDescendantsInternal(viewModel, currentChild, bindingContextsMayDifferFromDomParentElement);
  3.2010 -        }
  3.2011 -    }
  3.2012 -
  3.2013 -    function applyBindingsToNodeAndDescendantsInternal (viewModel, nodeVerified, bindingContextMayDifferFromDomParentElement) {
  3.2014 -        var shouldBindDescendants = true;
  3.2015 -
  3.2016 -        // Perf optimisation: Apply bindings only if...
  3.2017 -        // (1) We need to store the binding context on this node (because it may differ from the DOM parent node's binding context)
  3.2018 -        //     Note that we can't store binding contexts on non-elements (e.g., text nodes), as IE doesn't allow expando properties for those
  3.2019 -        // (2) It might have bindings (e.g., it has a data-bind attribute, or it's a marker for a containerless template)
  3.2020 -        var isElement = (nodeVerified.nodeType === 1);
  3.2021 -        if (isElement) // Workaround IE <= 8 HTML parsing weirdness
  3.2022 -            ko.virtualElements.normaliseVirtualElementDomStructure(nodeVerified);
  3.2023 -
  3.2024 -        var shouldApplyBindings = (isElement && bindingContextMayDifferFromDomParentElement)             // Case (1)
  3.2025 -                               || ko.bindingProvider['instance']['nodeHasBindings'](nodeVerified);       // Case (2)
  3.2026 -        if (shouldApplyBindings)
  3.2027 -            shouldBindDescendants = applyBindingsToNodeInternal(nodeVerified, null, viewModel, bindingContextMayDifferFromDomParentElement).shouldBindDescendants;
  3.2028 -
  3.2029 -        if (shouldBindDescendants) {
  3.2030 -            // We're recursing automatically into (real or virtual) child nodes without changing binding contexts. So,
  3.2031 -            //  * For children of a *real* element, the binding context is certainly the same as on their DOM .parentNode,
  3.2032 -            //    hence bindingContextsMayDifferFromDomParentElement is false
  3.2033 -            //  * For children of a *virtual* element, we can't be sure. Evaluating .parentNode on those children may
  3.2034 -            //    skip over any number of intermediate virtual elements, any of which might define a custom binding context,
  3.2035 -            //    hence bindingContextsMayDifferFromDomParentElement is true
  3.2036 -            applyBindingsToDescendantsInternal(viewModel, nodeVerified, /* bindingContextsMayDifferFromDomParentElement: */ !isElement);
  3.2037 -        }
  3.2038 -    }
  3.2039 -
  3.2040 -    function applyBindingsToNodeInternal (node, bindings, viewModelOrBindingContext, bindingContextMayDifferFromDomParentElement) {
  3.2041 -        // Need to be sure that inits are only run once, and updates never run until all the inits have been run
  3.2042 -        var initPhase = 0; // 0 = before all inits, 1 = during inits, 2 = after all inits
  3.2043 -
  3.2044 -        // Each time the dependentObservable is evaluated (after data changes),
  3.2045 -        // the binding attribute is reparsed so that it can pick out the correct
  3.2046 -        // model properties in the context of the changed data.
  3.2047 -        // DOM event callbacks need to be able to access this changed data,
  3.2048 -        // so we need a single parsedBindings variable (shared by all callbacks
  3.2049 -        // associated with this node's bindings) that all the closures can access.
  3.2050 -        var parsedBindings;
  3.2051 -        function makeValueAccessor(bindingKey) {
  3.2052 -            return function () { return parsedBindings[bindingKey] }
  3.2053 -        }
  3.2054 -        function parsedBindingsAccessor() {
  3.2055 -            return parsedBindings;
  3.2056 -        }
  3.2057 -
  3.2058 -        var bindingHandlerThatControlsDescendantBindings;
  3.2059 -        ko.dependentObservable(
  3.2060 -            function () {
  3.2061 -                // Ensure we have a nonnull binding context to work with
  3.2062 -                var bindingContextInstance = viewModelOrBindingContext && (viewModelOrBindingContext instanceof ko.bindingContext)
  3.2063 -                    ? viewModelOrBindingContext
  3.2064 -                    : new ko.bindingContext(ko.utils.unwrapObservable(viewModelOrBindingContext));
  3.2065 -                var viewModel = bindingContextInstance['$data'];
  3.2066 -
  3.2067 -                // Optimization: Don't store the binding context on this node if it's definitely the same as on node.parentNode, because
  3.2068 -                // we can easily recover it just by scanning up the node's ancestors in the DOM
  3.2069 -                // (note: here, parent node means "real DOM parent" not "virtual parent", as there's no O(1) way to find the virtual parent)
  3.2070 -                if (bindingContextMayDifferFromDomParentElement)
  3.2071 -                    ko.storedBindingContextForNode(node, bindingContextInstance);
  3.2072 -
  3.2073 -                // Use evaluatedBindings if given, otherwise fall back on asking the bindings provider to give us some bindings
  3.2074 -                var evaluatedBindings = (typeof bindings == "function") ? bindings(bindingContextInstance, node) : bindings;
  3.2075 -                parsedBindings = evaluatedBindings || ko.bindingProvider['instance']['getBindings'](node, bindingContextInstance);
  3.2076 -
  3.2077 -                if (parsedBindings) {
  3.2078 -                    // First run all the inits, so bindings can register for notification on changes
  3.2079 -                    if (initPhase === 0) {
  3.2080 -                        initPhase = 1;
  3.2081 -                        for (var bindingKey in parsedBindings) {
  3.2082 -                            var binding = ko.bindingHandlers[bindingKey];
  3.2083 -                            if (binding && node.nodeType === 8)
  3.2084 -                                validateThatBindingIsAllowedForVirtualElements(bindingKey);
  3.2085 -
  3.2086 -                            if (binding && typeof binding["init"] == "function") {
  3.2087 -                                var handlerInitFn = binding["init"];
  3.2088 -                                var initResult = handlerInitFn(node, makeValueAccessor(bindingKey), parsedBindingsAccessor, viewModel, bindingContextInstance);
  3.2089 -
  3.2090 -                                // If this binding handler claims to control descendant bindings, make a note of this
  3.2091 -                                if (initResult && initResult['controlsDescendantBindings']) {
  3.2092 -                                    if (bindingHandlerThatControlsDescendantBindings !== undefined)
  3.2093 -                                        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.");
  3.2094 -                                    bindingHandlerThatControlsDescendantBindings = bindingKey;
  3.2095 -                                }
  3.2096 -                            }
  3.2097 -                        }
  3.2098 -                        initPhase = 2;
  3.2099 -                    }
  3.2100 -
  3.2101 -                    // ... then run all the updates, which might trigger changes even on the first evaluation
  3.2102 -                    if (initPhase === 2) {
  3.2103 -                        for (var bindingKey in parsedBindings) {
  3.2104 -                            var binding = ko.bindingHandlers[bindingKey];
  3.2105 -                            if (binding && typeof binding["update"] == "function") {
  3.2106 -                                var handlerUpdateFn = binding["update"];
  3.2107 -                                handlerUpdateFn(node, makeValueAccessor(bindingKey), parsedBindingsAccessor, viewModel, bindingContextInstance);
  3.2108 -                            }
  3.2109 -                        }
  3.2110 -                    }
  3.2111 -                }
  3.2112 -            },
  3.2113 -            null,
  3.2114 -            { disposeWhenNodeIsRemoved : node }
  3.2115 -        );
  3.2116 -
  3.2117 -        return {
  3.2118 -            shouldBindDescendants: bindingHandlerThatControlsDescendantBindings === undefined
  3.2119 -        };
  3.2120 -    };
  3.2121 -
  3.2122 -    var storedBindingContextDomDataKey = "__ko_bindingContext__";
  3.2123 -    ko.storedBindingContextForNode = function (node, bindingContext) {
  3.2124 -        if (arguments.length == 2)
  3.2125 -            ko.utils.domData.set(node, storedBindingContextDomDataKey, bindingContext);
  3.2126 -        else
  3.2127 -            return ko.utils.domData.get(node, storedBindingContextDomDataKey);
  3.2128 -    }
  3.2129 -
  3.2130 -    ko.applyBindingsToNode = function (node, bindings, viewModel) {
  3.2131 -        if (node.nodeType === 1) // If it's an element, workaround IE <= 8 HTML parsing weirdness
  3.2132 -            ko.virtualElements.normaliseVirtualElementDomStructure(node);
  3.2133 -        return applyBindingsToNodeInternal(node, bindings, viewModel, true);
  3.2134 -    };
  3.2135 -
  3.2136 -    ko.applyBindingsToDescendants = function(viewModel, rootNode) {
  3.2137 -        if (rootNode.nodeType === 1 || rootNode.nodeType === 8)
  3.2138 -            applyBindingsToDescendantsInternal(viewModel, rootNode, true);
  3.2139 -    };
  3.2140 -
  3.2141 -    ko.applyBindings = function (viewModel, rootNode) {
  3.2142 -        if (rootNode && (rootNode.nodeType !== 1) && (rootNode.nodeType !== 8))
  3.2143 -            throw new Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");
  3.2144 -        rootNode = rootNode || window.document.body; // Make "rootNode" parameter optional
  3.2145 -
  3.2146 -        applyBindingsToNodeAndDescendantsInternal(viewModel, rootNode, true);
  3.2147 -    };
  3.2148 -
  3.2149 -    // Retrieving binding context from arbitrary nodes
  3.2150 -    ko.contextFor = function(node) {
  3.2151 -        // We can only do something meaningful for elements and comment nodes (in particular, not text nodes, as IE can't store domdata for them)
  3.2152 -        switch (node.nodeType) {
  3.2153 -            case 1:
  3.2154 -            case 8:
  3.2155 -                var context = ko.storedBindingContextForNode(node);
  3.2156 -                if (context) return context;
  3.2157 -                if (node.parentNode) return ko.contextFor(node.parentNode);
  3.2158 -                break;
  3.2159 -        }
  3.2160 -        return undefined;
  3.2161 -    };
  3.2162 -    ko.dataFor = function(node) {
  3.2163 -        var context = ko.contextFor(node);
  3.2164 -        return context ? context['$data'] : undefined;
  3.2165 -    };
  3.2166 -
  3.2167 -    ko.exportSymbol('bindingHandlers', ko.bindingHandlers);
  3.2168 -    ko.exportSymbol('applyBindings', ko.applyBindings);
  3.2169 -    ko.exportSymbol('applyBindingsToDescendants', ko.applyBindingsToDescendants);
  3.2170 -    ko.exportSymbol('applyBindingsToNode', ko.applyBindingsToNode);
  3.2171 -    ko.exportSymbol('contextFor', ko.contextFor);
  3.2172 -    ko.exportSymbol('dataFor', ko.dataFor);
  3.2173 -})();
  3.2174 -var attrHtmlToJavascriptMap = { 'class': 'className', 'for': 'htmlFor' };
  3.2175 -ko.bindingHandlers['attr'] = {
  3.2176 -    'update': function(element, valueAccessor, allBindingsAccessor) {
  3.2177 -        var value = ko.utils.unwrapObservable(valueAccessor()) || {};
  3.2178 -        for (var attrName in value) {
  3.2179 -            if (typeof attrName == "string") {
  3.2180 -                var attrValue = ko.utils.unwrapObservable(value[attrName]);
  3.2181 -
  3.2182 -                // To cover cases like "attr: { checked:someProp }", we want to remove the attribute entirely
  3.2183 -                // when someProp is a "no value"-like value (strictly null, false, or undefined)
  3.2184 -                // (because the absence of the "checked" attr is how to mark an element as not checked, etc.)
  3.2185 -                var toRemove = (attrValue === false) || (attrValue === null) || (attrValue === undefined);
  3.2186 -                if (toRemove)
  3.2187 -                    element.removeAttribute(attrName);
  3.2188 -
  3.2189 -                // In IE <= 7 and IE8 Quirks Mode, you have to use the Javascript property name instead of the
  3.2190 -                // HTML attribute name for certain attributes. IE8 Standards Mode supports the correct behavior,
  3.2191 -                // but instead of figuring out the mode, we'll just set the attribute through the Javascript
  3.2192 -                // property for IE <= 8.
  3.2193 -                if (ko.utils.ieVersion <= 8 && attrName in attrHtmlToJavascriptMap) {
  3.2194 -                    attrName = attrHtmlToJavascriptMap[attrName];
  3.2195 -                    if (toRemove)
  3.2196 -                        element.removeAttribute(attrName);
  3.2197 -                    else
  3.2198 -                        element[attrName] = attrValue;
  3.2199 -                } else if (!toRemove) {
  3.2200 -                    try {
  3.2201 -                        element.setAttribute(attrName, attrValue.toString());
  3.2202 -                    } catch (err) {
  3.2203 -                        // ignore for now
  3.2204 -                        if (console) {
  3.2205 -                            console.log("Can't set attribute " + attrName + " to " + attrValue + " error: " + err);
  3.2206 -                        }
  3.2207 -                    }
  3.2208 -                }
  3.2209 -
  3.2210 -                // Treat "name" specially - although you can think of it as an attribute, it also needs
  3.2211 -                // special handling on older versions of IE (https://github.com/SteveSanderson/knockout/pull/333)
  3.2212 -                // Deliberately being case-sensitive here because XHTML would regard "Name" as a different thing
  3.2213 -                // entirely, and there's no strong reason to allow for such casing in HTML.
  3.2214 -                if (attrName === "name") {
  3.2215 -                    ko.utils.setElementName(element, toRemove ? "" : attrValue.toString());
  3.2216 -                }
  3.2217 -            }
  3.2218 -        }
  3.2219 -    }
  3.2220 -};
  3.2221 -ko.bindingHandlers['checked'] = {
  3.2222 -    'init': function (element, valueAccessor, allBindingsAccessor) {
  3.2223 -        var updateHandler = function() {
  3.2224 -            var valueToWrite;
  3.2225 -            if (element.type == "checkbox") {
  3.2226 -                valueToWrite = element.checked;
  3.2227 -            } else if ((element.type == "radio") && (element.checked)) {
  3.2228 -                valueToWrite = element.value;
  3.2229 -            } else {
  3.2230 -                return; // "checked" binding only responds to checkboxes and selected radio buttons
  3.2231 -            }
  3.2232 -
  3.2233 -            var modelValue = valueAccessor(), unwrappedValue = ko.utils.unwrapObservable(modelValue);
  3.2234 -            if ((element.type == "checkbox") && (unwrappedValue instanceof Array)) {
  3.2235 -                // For checkboxes bound to an array, we add/remove the checkbox value to that array
  3.2236 -                // This works for both observable and non-observable arrays
  3.2237 -                var existingEntryIndex = ko.utils.arrayIndexOf(unwrappedValue, element.value);
  3.2238 -                if (element.checked && (existingEntryIndex < 0))
  3.2239 -                    modelValue.push(element.value);
  3.2240 -                else if ((!element.checked) && (existingEntryIndex >= 0))
  3.2241 -                    modelValue.splice(existingEntryIndex, 1);
  3.2242 -            } else {
  3.2243 -                ko.expressionRewriting.writeValueToProperty(modelValue, allBindingsAccessor, 'checked', valueToWrite, true);
  3.2244 -            }
  3.2245 -        };
  3.2246 -        ko.utils.registerEventHandler(element, "click", updateHandler);
  3.2247 -
  3.2248 -        // IE 6 won't allow radio buttons to be selected unless they have a name
  3.2249 -        if ((element.type == "radio") && !element.name)
  3.2250 -            ko.bindingHandlers['uniqueName']['init'](element, function() { return true });
  3.2251 -    },
  3.2252 -    'update': function (element, valueAccessor) {
  3.2253 -        var value = ko.utils.unwrapObservable(valueAccessor());
  3.2254 -
  3.2255 -        if (element.type == "checkbox") {
  3.2256 -            if (value instanceof Array) {
  3.2257 -                // When bound to an array, the checkbox being checked represents its value being present in that array
  3.2258 -                element.checked = ko.utils.arrayIndexOf(value, element.value) >= 0;
  3.2259 -            } else {
  3.2260 -                // When bound to anything other value (not an array), the checkbox being checked represents the value being trueish
  3.2261 -                element.checked = value;
  3.2262 -            }
  3.2263 -        } else if (element.type == "radio") {
  3.2264 -            element.checked = (element.value == value);
  3.2265 -        }
  3.2266 -    }
  3.2267 -};
  3.2268 -var classesWrittenByBindingKey = '__ko__cssValue';
  3.2269 -ko.bindingHandlers['css'] = {
  3.2270 -    'update': function (element, valueAccessor) {
  3.2271 -        var value = ko.utils.unwrapObservable(valueAccessor());
  3.2272 -        if (typeof value == "object") {
  3.2273 -            for (var className in value) {
  3.2274 -                var shouldHaveClass = ko.utils.unwrapObservable(value[className]);
  3.2275 -                ko.utils.toggleDomNodeCssClass(element, className, shouldHaveClass);
  3.2276 -            }
  3.2277 -        } else {
  3.2278 -            value = String(value || ''); // Make sure we don't try to store or set a non-string value
  3.2279 -            ko.utils.toggleDomNodeCssClass(element, element[classesWrittenByBindingKey], false);
  3.2280 -            element[classesWrittenByBindingKey] = value;
  3.2281 -            ko.utils.toggleDomNodeCssClass(element, value, true);
  3.2282 -        }
  3.2283 -    }
  3.2284 -};
  3.2285 -ko.bindingHandlers['enable'] = {
  3.2286 -    'update': function (element, valueAccessor) {
  3.2287 -        var value = ko.utils.unwrapObservable(valueAccessor());
  3.2288 -        if (value && element.disabled)
  3.2289 -            element.removeAttribute("disabled");
  3.2290 -        else if ((!value) && (!element.disabled))
  3.2291 -            element.disabled = true;
  3.2292 -    }
  3.2293 -};
  3.2294 -
  3.2295 -ko.bindingHandlers['disable'] = {
  3.2296 -    'update': function (element, valueAccessor) {
  3.2297 -        ko.bindingHandlers['enable']['update'](element, function() { return !ko.utils.unwrapObservable(valueAccessor()) });
  3.2298 -    }
  3.2299 -};
  3.2300 -// For certain common events (currently just 'click'), allow a simplified data-binding syntax
  3.2301 -// e.g. click:handler instead of the usual full-length event:{click:handler}
  3.2302 -function makeEventHandlerShortcut(eventName) {
  3.2303 -    ko.bindingHandlers[eventName] = {
  3.2304 -        'init': function(element, valueAccessor, allBindingsAccessor, viewModel) {
  3.2305 -            var newValueAccessor = function () {
  3.2306 -                var result = {};
  3.2307 -                result[eventName] = valueAccessor();
  3.2308 -                return result;
  3.2309 -            };
  3.2310 -            return ko.bindingHandlers['event']['init'].call(this, element, newValueAccessor, allBindingsAccessor, viewModel);
  3.2311 -        }
  3.2312 -    }
  3.2313 -}
  3.2314 -
  3.2315 -ko.bindingHandlers['event'] = {
  3.2316 -    'init' : function (element, valueAccessor, allBindingsAccessor, viewModel) {
  3.2317 -        var eventsToHandle = valueAccessor() || {};
  3.2318 -        for(var eventNameOutsideClosure in eventsToHandle) {
  3.2319 -            (function() {
  3.2320 -                var eventName = eventNameOutsideClosure; // Separate variable to be captured by event handler closure
  3.2321 -                if (typeof eventName == "string") {
  3.2322 -                    ko.utils.registerEventHandler(element, eventName, function (event) {
  3.2323 -                        var handlerReturnValue;
  3.2324 -                        var handlerFunction = valueAccessor()[eventName];
  3.2325 -                        if (!handlerFunction)
  3.2326 -                            return;
  3.2327 -                        var allBindings = allBindingsAccessor();
  3.2328 -
  3.2329 -                        try {
  3.2330 -                            // Take all the event args, and prefix with the viewmodel
  3.2331 -                            var argsForHandler = ko.utils.makeArray(arguments);
  3.2332 -                            argsForHandler.unshift(viewModel);
  3.2333 -                            handlerReturnValue = handlerFunction.apply(viewModel, argsForHandler);
  3.2334 -                        } finally {
  3.2335 -                            if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
  3.2336 -                                if (event.preventDefault)
  3.2337 -                                    event.preventDefault();
  3.2338 -                                else
  3.2339 -                                    event.returnValue = false;
  3.2340 -                            }
  3.2341 -                        }
  3.2342 -
  3.2343 -                        var bubble = allBindings[eventName + 'Bubble'] !== false;
  3.2344 -                        if (!bubble) {
  3.2345 -                            event.cancelBubble = true;
  3.2346 -                            if (event.stopPropagation)
  3.2347 -                                event.stopPropagation();
  3.2348 -                        }
  3.2349 -                    });
  3.2350 -                }
  3.2351 -            })();
  3.2352 -        }
  3.2353 -    }
  3.2354 -};
  3.2355 -// "foreach: someExpression" is equivalent to "template: { foreach: someExpression }"
  3.2356 -// "foreach: { data: someExpression, afterAdd: myfn }" is equivalent to "template: { foreach: someExpression, afterAdd: myfn }"
  3.2357 -ko.bindingHandlers['foreach'] = {
  3.2358 -    makeTemplateValueAccessor: function(valueAccessor) {
  3.2359 -        return function() {
  3.2360 -            var modelValue = valueAccessor(),
  3.2361 -                unwrappedValue = ko.utils.peekObservable(modelValue);    // Unwrap without setting a dependency here
  3.2362 -
  3.2363 -            // If unwrappedValue is the array, pass in the wrapped value on its own
  3.2364 -            // The value will be unwrapped and tracked within the template binding
  3.2365 -            // (See https://github.com/SteveSanderson/knockout/issues/523)
  3.2366 -            if ((!unwrappedValue) || typeof unwrappedValue.length == "number")
  3.2367 -                return { 'foreach': modelValue, 'templateEngine': ko.nativeTemplateEngine.instance };
  3.2368 -
  3.2369 -            // If unwrappedValue.data is the array, preserve all relevant options and unwrap again value so we get updates
  3.2370 -            ko.utils.unwrapObservable(modelValue);
  3.2371 -            return {
  3.2372 -                'foreach': unwrappedValue['data'],
  3.2373 -                'as': unwrappedValue['as'],
  3.2374 -                'includeDestroyed': unwrappedValue['includeDestroyed'],
  3.2375 -                'afterAdd': unwrappedValue['afterAdd'],
  3.2376 -                'beforeRemove': unwrappedValue['beforeRemove'],
  3.2377 -                'afterRender': unwrappedValue['afterRender'],
  3.2378 -                'beforeMove': unwrappedValue['beforeMove'],
  3.2379 -                'afterMove': unwrappedValue['afterMove'],
  3.2380 -                'templateEngine': ko.nativeTemplateEngine.instance
  3.2381 -            };
  3.2382 -        };
  3.2383 -    },
  3.2384 -    'init': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
  3.2385 -        return ko.bindingHandlers['template']['init'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor));
  3.2386 -    },
  3.2387 -    'update': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
  3.2388 -        return ko.bindingHandlers['template']['update'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor), allBindingsAccessor, viewModel, bindingContext);
  3.2389 -    }
  3.2390 -};
  3.2391 -ko.expressionRewriting.bindingRewriteValidators['foreach'] = false; // Can't rewrite control flow bindings
  3.2392 -ko.virtualElements.allowedBindings['foreach'] = true;
  3.2393 -var hasfocusUpdatingProperty = '__ko_hasfocusUpdating';
  3.2394 -ko.bindingHandlers['hasfocus'] = {
  3.2395 -    'init': function(element, valueAccessor, allBindingsAccessor) {
  3.2396 -        var handleElementFocusChange = function(isFocused) {
  3.2397 -            // Where possible, ignore which event was raised and determine focus state using activeElement,
  3.2398 -            // as this avoids phantom focus/blur events raised when changing tabs in modern browsers.
  3.2399 -            // However, not all KO-targeted browsers (Firefox 2) support activeElement. For those browsers,
  3.2400 -            // prevent a loss of focus when changing tabs/windows by setting a flag that prevents hasfocus
  3.2401 -            // from calling 'blur()' on the element when it loses focus.
  3.2402 -            // Discussion at https://github.com/SteveSanderson/knockout/pull/352
  3.2403 -            element[hasfocusUpdatingProperty] = true;
  3.2404 -            var ownerDoc = element.ownerDocument;
  3.2405 -            if ("activeElement" in ownerDoc) {
  3.2406 -                isFocused = (ownerDoc.activeElement === element);
  3.2407 -            }
  3.2408 -            var modelValue = valueAccessor();
  3.2409 -            ko.expressionRewriting.writeValueToProperty(modelValue, allBindingsAccessor, 'hasfocus', isFocused, true);
  3.2410 -            element[hasfocusUpdatingProperty] = false;
  3.2411 -        };
  3.2412 -        var handleElementFocusIn = handleElementFocusChange.bind(null, true);
  3.2413 -        var handleElementFocusOut = handleElementFocusChange.bind(null, false);
  3.2414 -
  3.2415 -        ko.utils.registerEventHandler(element, "focus", handleElementFocusIn);
  3.2416 -        ko.utils.registerEventHandler(element, "focusin", handleElementFocusIn); // For IE
  3.2417 -        ko.utils.registerEventHandler(element, "blur",  handleElementFocusOut);
  3.2418 -        ko.utils.registerEventHandler(element, "focusout",  handleElementFocusOut); // For IE
  3.2419 -    },
  3.2420 -    'update': function(element, valueAccessor) {
  3.2421 -        var value = ko.utils.unwrapObservable(valueAccessor());
  3.2422 -        if (!element[hasfocusUpdatingProperty]) {
  3.2423 -            value ? element.focus() : element.blur();
  3.2424 -            ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, value ? "focusin" : "focusout"]); // For IE, which doesn't reliably fire "focus" or "blur" events synchronously
  3.2425 -        }
  3.2426 -    }
  3.2427 -};
  3.2428 -ko.bindingHandlers['html'] = {
  3.2429 -    'init': function() {
  3.2430 -        // Prevent binding on the dynamically-injected HTML (as developers are unlikely to expect that, and it has security implications)
  3.2431 -        return { 'controlsDescendantBindings': true };
  3.2432 -    },
  3.2433 -    'update': function (element, valueAccessor) {
  3.2434 -        // setHtml will unwrap the value if needed
  3.2435 -        ko.utils.setHtml(element, valueAccessor());
  3.2436 -    }
  3.2437 -};
  3.2438 -var withIfDomDataKey = '__ko_withIfBindingData';
  3.2439 -// Makes a binding like with or if
  3.2440 -function makeWithIfBinding(bindingKey, isWith, isNot, makeContextCallback) {
  3.2441 -    ko.bindingHandlers[bindingKey] = {
  3.2442 -        'init': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
  3.2443 -            ko.utils.domData.set(element, withIfDomDataKey, {});
  3.2444 -            return { 'controlsDescendantBindings': true };
  3.2445 -        },
  3.2446 -        'update': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
  3.2447 -            var withIfData = ko.utils.domData.get(element, withIfDomDataKey),
  3.2448 -                dataValue = ko.utils.unwrapObservable(valueAccessor()),
  3.2449 -                shouldDisplay = !isNot !== !dataValue, // equivalent to isNot ? !dataValue : !!dataValue
  3.2450 -                isFirstRender = !withIfData.savedNodes,
  3.2451 -                needsRefresh = isFirstRender || isWith || (shouldDisplay !== withIfData.didDisplayOnLastUpdate);
  3.2452 -
  3.2453 -            if (needsRefresh) {
  3.2454 -                if (isFirstRender) {
  3.2455 -                    withIfData.savedNodes = ko.utils.cloneNodes(ko.virtualElements.childNodes(element), true /* shouldCleanNodes */);
  3.2456 -                }
  3.2457 -
  3.2458 -                if (shouldDisplay) {
  3.2459 -                    if (!isFirstRender) {
  3.2460 -                        ko.virtualElements.setDomNodeChildren(element, ko.utils.cloneNodes(withIfData.savedNodes));
  3.2461 -                    }
  3.2462 -                    ko.applyBindingsToDescendants(makeContextCallback ? makeContextCallback(bindingContext, dataValue) : bindingContext, element);
  3.2463 -                } else {
  3.2464 -                    ko.virtualElements.emptyNode(element);
  3.2465 -                }
  3.2466 -
  3.2467 -                withIfData.didDisplayOnLastUpdate = shouldDisplay;
  3.2468 -            }
  3.2469 -        }
  3.2470 -    };
  3.2471 -    ko.expressionRewriting.bindingRewriteValidators[bindingKey] = false; // Can't rewrite control flow bindings
  3.2472 -    ko.virtualElements.allowedBindings[bindingKey] = true;
  3.2473 -}
  3.2474 -
  3.2475 -// Construct the actual binding handlers
  3.2476 -makeWithIfBinding('if');
  3.2477 -makeWithIfBinding('ifnot', false /* isWith */, true /* isNot */);
  3.2478 -makeWithIfBinding('with', true /* isWith */, false /* isNot */,
  3.2479 -    function(bindingContext, dataValue) {
  3.2480 -        return bindingContext['createChildContext'](dataValue);
  3.2481 -    }
  3.2482 -);
  3.2483 -function ensureDropdownSelectionIsConsistentWithModelValue(element, modelValue, preferModelValue) {
  3.2484 -    if (preferModelValue) {
  3.2485 -        if (modelValue !== ko.selectExtensions.readValue(element))
  3.2486 -            ko.selectExtensions.writeValue(element, modelValue);
  3.2487 -    }
  3.2488 -
  3.2489 -    // No matter which direction we're syncing in, we want the end result to be equality between dropdown value and model value.
  3.2490 -    // If they aren't equal, either we prefer the dropdown value, or the model value couldn't be represented, so either way,
  3.2491 -    // change the model value to match the dropdown.
  3.2492 -    if (modelValue !== ko.selectExtensions.readValue(element))
  3.2493 -        ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, "change"]);
  3.2494 -};
  3.2495 -
  3.2496 -ko.bindingHandlers['options'] = {
  3.2497 -    'update': function (element, valueAccessor, allBindingsAccessor) {
  3.2498 -        if (ko.utils.tagNameLower(element) !== "select")
  3.2499 -            throw new Error("options binding applies only to SELECT elements");
  3.2500 -
  3.2501 -        var selectWasPreviouslyEmpty = element.length == 0;
  3.2502 -        var previousSelectedValues = ko.utils.arrayMap(ko.utils.arrayFilter(element.childNodes, function (node) {
  3.2503 -            return node.tagName && (ko.utils.tagNameLower(node) === "option") && node.selected;
  3.2504 -        }), function (node) {
  3.2505 -            return ko.selectExtensions.readValue(node) || node.innerText || node.textContent;
  3.2506 -        });
  3.2507 -        var previousScrollTop = element.scrollTop;
  3.2508 -
  3.2509 -        var value = ko.utils.unwrapObservable(valueAccessor());
  3.2510 -        var selectedValue = element.value;
  3.2511 -
  3.2512 -        // Remove all existing <option>s.
  3.2513 -        // Need to use .remove() rather than .removeChild() for <option>s otherwise IE behaves oddly (https://github.com/SteveSanderson/knockout/issues/134)
  3.2514 -        while (element.length > 0) {
  3.2515 -            ko.cleanNode(element.options[0]);
  3.2516 -            element.remove(0);
  3.2517 -        }
  3.2518 -
  3.2519 -        if (value) {
  3.2520 -            var allBindings = allBindingsAccessor(),
  3.2521 -                includeDestroyed = allBindings['optionsIncludeDestroyed'];
  3.2522 -
  3.2523 -            if (typeof value.length != "number")
  3.2524 -                value = [value];
  3.2525 -            if (allBindings['optionsCaption']) {
  3.2526 -                var option = document.createElement("option");
  3.2527 -                ko.utils.setHtml(option, allBindings['optionsCaption']);
  3.2528 -                ko.selectExtensions.writeValue(option, undefined);
  3.2529 -                element.appendChild(option);
  3.2530 -            }
  3.2531 -
  3.2532 -            for (var i = 0, j = value.length; i < j; i++) {
  3.2533 -                // Skip destroyed items
  3.2534 -                var arrayEntry = value[i];
  3.2535 -                if (arrayEntry && arrayEntry['_destroy'] && !includeDestroyed)
  3.2536 -                    continue;
  3.2537 -
  3.2538 -                var option = document.createElement("option");
  3.2539 -
  3.2540 -                function applyToObject(object, predicate, defaultValue) {
  3.2541 -                    var predicateType = typeof predicate;
  3.2542 -                    if (predicateType == "function")    // Given a function; run it against the data value
  3.2543 -                        return predicate(object);
  3.2544 -                    else if (predicateType == "string") // Given a string; treat it as a property name on the data value
  3.2545 -                        return object[predicate];
  3.2546 -                    else                                // Given no optionsText arg; use the data value itself
  3.2547 -                        return defaultValue;
  3.2548 -                }
  3.2549 -
  3.2550 -                // Apply a value to the option element
  3.2551 -                var optionValue = applyToObject(arrayEntry, allBindings['optionsValue'], arrayEntry);
  3.2552 -                ko.selectExtensions.writeValue(option, ko.utils.unwrapObservable(optionValue));
  3.2553 -
  3.2554 -                // Apply some text to the option element
  3.2555 -                var optionText = applyToObject(arrayEntry, allBindings['optionsText'], optionValue);
  3.2556 -                ko.utils.setTextContent(option, optionText);
  3.2557 -
  3.2558 -                element.appendChild(option);
  3.2559 -            }
  3.2560 -
  3.2561 -            // IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document.
  3.2562 -            // That's why we first added them without selection. Now it's time to set the selection.
  3.2563 -            var newOptions = element.getElementsByTagName("option");
  3.2564 -            var countSelectionsRetained = 0;
  3.2565 -            for (var i = 0, j = newOptions.length; i < j; i++) {
  3.2566 -                if (ko.utils.arrayIndexOf(previousSelectedValues, ko.selectExtensions.readValue(newOptions[i])) >= 0) {
  3.2567 -                    ko.utils.setOptionNodeSelectionState(newOptions[i], true);
  3.2568 -                    countSelectionsRetained++;
  3.2569 -                }
  3.2570 -            }
  3.2571 -
  3.2572 -            element.scrollTop = previousScrollTop;
  3.2573 -
  3.2574 -            if (selectWasPreviouslyEmpty && ('value' in allBindings)) {
  3.2575 -                // Ensure consistency between model value and selected option.
  3.2576 -                // If the dropdown is being populated for the first time here (or was otherwise previously empty),
  3.2577 -                // the dropdown selection state is meaningless, so we preserve the model value.
  3.2578 -                ensureDropdownSelectionIsConsistentWithModelValue(element, ko.utils.peekObservable(allBindings['value']), /* preferModelValue */ true);
  3.2579 -            }
  3.2580 -
  3.2581 -            // Workaround for IE9 bug
  3.2582 -            ko.utils.ensureSelectElementIsRenderedCorrectly(element);
  3.2583 -        }
  3.2584 -    }
  3.2585 -};
  3.2586 -ko.bindingHandlers['options'].optionValueDomDataKey = '__ko.optionValueDomData__';
  3.2587 -ko.bindingHandlers['selectedOptions'] = {
  3.2588 -    'init': function (element, valueAccessor, allBindingsAccessor) {
  3.2589 -        ko.utils.registerEventHandler(element, "change", function () {
  3.2590 -            var value = valueAccessor(), valueToWrite = [];
  3.2591 -            ko.utils.arrayForEach(element.getElementsByTagName("option"), function(node) {
  3.2592 -                if (node.selected)
  3.2593 -                    valueToWrite.push(ko.selectExtensions.readValue(node));
  3.2594 -            });
  3.2595 -            ko.expressionRewriting.writeValueToProperty(value, allBindingsAccessor, 'value', valueToWrite);
  3.2596 -        });
  3.2597 -    },
  3.2598 -    'update': function (element, valueAccessor) {
  3.2599 -        if (ko.utils.tagNameLower(element) != "select")
  3.2600 -            throw new Error("values binding applies only to SELECT elements");
  3.2601 -
  3.2602 -        var newValue = ko.utils.unwrapObservable(valueAccessor());
  3.2603 -        if (newValue && typeof newValue.length == "number") {
  3.2604 -            ko.utils.arrayForEach(element.getElementsByTagName("option"), function(node) {
  3.2605 -                var isSelected = ko.utils.arrayIndexOf(newValue, ko.selectExtensions.readValue(node)) >= 0;
  3.2606 -                ko.utils.setOptionNodeSelectionState(node, isSelected);
  3.2607 -            });
  3.2608 -        }
  3.2609 -    }
  3.2610 -};
  3.2611 -ko.bindingHandlers['style'] = {
  3.2612 -    'update': function (element, valueAccessor) {
  3.2613 -        var value = ko.utils.unwrapObservable(valueAccessor() || {});
  3.2614 -        for (var styleName in value) {
  3.2615 -            if (typeof styleName == "string") {
  3.2616 -                var styleValue = ko.utils.unwrapObservable(value[styleName]);
  3.2617 -                element.style[styleName] = styleValue || ""; // Empty string removes the value, whereas null/undefined have no effect
  3.2618 -            }
  3.2619 -        }
  3.2620 -    }
  3.2621 -};
  3.2622 -ko.bindingHandlers['submit'] = {
  3.2623 -    'init': function (element, valueAccessor, allBindingsAccessor, viewModel) {
  3.2624 -        if (typeof valueAccessor() != "function")
  3.2625 -            throw new Error("The value for a submit binding must be a function");
  3.2626 -        ko.utils.registerEventHandler(element, "submit", function (event) {
  3.2627 -            var handlerReturnValue;
  3.2628 -            var value = valueAccessor();
  3.2629 -            try { handlerReturnValue = value.call(viewModel, element); }
  3.2630 -            finally {
  3.2631 -                if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
  3.2632 -                    if (event.preventDefault)
  3.2633 -                        event.preventDefault();
  3.2634 -                    else
  3.2635 -                        event.returnValue = false;
  3.2636 -                }
  3.2637 -            }
  3.2638 -        });
  3.2639 -    }
  3.2640 -};
  3.2641 -ko.bindingHandlers['text'] = {
  3.2642 -    'update': function (element, valueAccessor) {
  3.2643 -        ko.utils.setTextContent(element, valueAccessor());
  3.2644 -    }
  3.2645 -};
  3.2646 -ko.virtualElements.allowedBindings['text'] = true;
  3.2647 -ko.bindingHandlers['uniqueName'] = {
  3.2648 -    'init': function (element, valueAccessor) {
  3.2649 -        if (valueAccessor()) {
  3.2650 -            var name = "ko_unique_" + (++ko.bindingHandlers['uniqueName'].currentIndex);
  3.2651 -            ko.utils.setElementName(element, name);
  3.2652 -        }
  3.2653 -    }
  3.2654 -};
  3.2655 -ko.bindingHandlers['uniqueName'].currentIndex = 0;
  3.2656 -ko.bindingHandlers['value'] = {
  3.2657 -    'init': function (element, valueAccessor, allBindingsAccessor) {
  3.2658 -        // Always catch "change" event; possibly other events too if asked
  3.2659 -        var eventsToCatch = ["change"];
  3.2660 -        var requestedEventsToCatch = allBindingsAccessor()["valueUpdate"];
  3.2661 -        var propertyChangedFired = false;
  3.2662 -        if (requestedEventsToCatch) {
  3.2663 -            if (typeof requestedEventsToCatch == "string") // Allow both individual event names, and arrays of event names
  3.2664 -                requestedEventsToCatch = [requestedEventsToCatch];
  3.2665 -            ko.utils.arrayPushAll(eventsToCatch, requestedEventsToCatch);
  3.2666 -            eventsToCatch = ko.utils.arrayGetDistinctValues(eventsToCatch);
  3.2667 -        }
  3.2668 -
  3.2669 -        var valueUpdateHandler = function() {
  3.2670 -            propertyChangedFired = false;
  3.2671 -            var modelValue = valueAccessor();
  3.2672 -            var elementValue = ko.selectExtensions.readValue(element);
  3.2673 -            ko.expressionRewriting.writeValueToProperty(modelValue, allBindingsAccessor, 'value', elementValue);
  3.2674 -        }
  3.2675 -
  3.2676 -        // Workaround for https://github.com/SteveSanderson/knockout/issues/122
  3.2677 -        // IE doesn't fire "change" events on textboxes if the user selects a value from its autocomplete list
  3.2678 -        var ieAutoCompleteHackNeeded = ko.utils.ieVersion && element.tagName.toLowerCase() == "input" && element.type == "text"
  3.2679 -                                       && element.autocomplete != "off" && (!element.form || element.form.autocomplete != "off");
  3.2680 -        if (ieAutoCompleteHackNeeded && ko.utils.arrayIndexOf(eventsToCatch, "propertychange") == -1) {
  3.2681 -            ko.utils.registerEventHandler(element, "propertychange", function () { propertyChangedFired = true });
  3.2682 -            ko.utils.registerEventHandler(element, "blur", function() {
  3.2683 -                if (propertyChangedFired) {
  3.2684 -                    valueUpdateHandler();
  3.2685 -                }
  3.2686 -            });
  3.2687 -        }
  3.2688 -
  3.2689 -        ko.utils.arrayForEach(eventsToCatch, function(eventName) {
  3.2690 -            // The syntax "after<eventname>" means "run the handler asynchronously after the event"
  3.2691 -            // This is useful, for example, to catch "keydown" events after the browser has updated the control
  3.2692 -            // (otherwise, ko.selectExtensions.readValue(this) will receive the control's value *before* the key event)
  3.2693 -            var handler = valueUpdateHandler;
  3.2694 -            if (ko.utils.stringStartsWith(eventName, "after")) {
  3.2695 -                handler = function() { setTimeout(valueUpdateHandler, 0) };
  3.2696 -                eventName = eventName.substring("after".length);
  3.2697 -            }
  3.2698 -            ko.utils.registerEventHandler(element, eventName, handler);
  3.2699 -        });
  3.2700 -    },
  3.2701 -    'update': function (element, valueAccessor) {
  3.2702 -        var valueIsSelectOption = ko.utils.tagNameLower(element) === "select";
  3.2703 -        var newValue = ko.utils.unwrapObservable(valueAccessor());
  3.2704 -        var elementValue = ko.selectExtensions.readValue(element);
  3.2705 -        var valueHasChanged = (newValue != elementValue);
  3.2706 -
  3.2707 -        // JavaScript's 0 == "" behavious is unfortunate here as it prevents writing 0 to an empty text box (loose equality suggests the values are the same).
  3.2708 -        // We don't want to do a strict equality comparison as that is more confusing for developers in certain cases, so we specifically special case 0 != "" here.
  3.2709 -        if ((newValue === 0) && (elementValue !== 0) && (elementValue !== "0"))
  3.2710 -            valueHasChanged = true;
  3.2711 -
  3.2712 -        if (valueHasChanged) {
  3.2713 -            var applyValueAction = function () { ko.selectExtensions.writeValue(element, newValue); };
  3.2714 -            applyValueAction();
  3.2715 -
  3.2716 -            // Workaround for IE6 bug: It won't reliably apply values to SELECT nodes during the same execution thread
  3.2717 -            // right after you've changed the set of OPTION nodes on it. So for that node type, we'll schedule a second thread
  3.2718 -            // to apply the value as well.
  3.2719 -            var alsoApplyAsynchronously = valueIsSelectOption;
  3.2720 -            if (alsoApplyAsynchronously)
  3.2721 -                setTimeout(applyValueAction, 0);
  3.2722 -        }
  3.2723 -
  3.2724 -        // If you try to set a model value that can't be represented in an already-populated dropdown, reject that change,
  3.2725 -        // because you're not allowed to have a model value that disagrees with a visible UI selection.
  3.2726 -        if (valueIsSelectOption && (element.length > 0))
  3.2727 -            ensureDropdownSelectionIsConsistentWithModelValue(element, newValue, /* preferModelValue */ false);
  3.2728 -    }
  3.2729 -};
  3.2730 -ko.bindingHandlers['visible'] = {
  3.2731 -    'update': function (element, valueAccessor) {
  3.2732 -        var value = ko.utils.unwrapObservable(valueAccessor());
  3.2733 -        var isCurrentlyVisible = !(element.style.display == "none");
  3.2734 -        if (value && !isCurrentlyVisible)
  3.2735 -            element.style.display = "";
  3.2736 -        else if ((!value) && isCurrentlyVisible)
  3.2737 -            element.style.display = "none";
  3.2738 -    }
  3.2739 -};
  3.2740 -// 'click' is just a shorthand for the usual full-length event:{click:handler}
  3.2741 -makeEventHandlerShortcut('click');
  3.2742 -// If you want to make a custom template engine,
  3.2743 -//
  3.2744 -// [1] Inherit from this class (like ko.nativeTemplateEngine does)
  3.2745 -// [2] Override 'renderTemplateSource', supplying a function with this signature:
  3.2746 -//
  3.2747 -//        function (templateSource, bindingContext, options) {
  3.2748 -//            // - templateSource.text() is the text of the template you should render
  3.2749 -//            // - bindingContext.$data is the data you should pass into the template
  3.2750 -//            //   - you might also want to make bindingContext.$parent, bindingContext.$parents,
  3.2751 -//            //     and bindingContext.$root available in the template too
  3.2752 -//            // - options gives you access to any other properties set on "data-bind: { template: options }"
  3.2753 -//            //
  3.2754 -//            // Return value: an array of DOM nodes
  3.2755 -//        }
  3.2756 -//
  3.2757 -// [3] Override 'createJavaScriptEvaluatorBlock', supplying a function with this signature:
  3.2758 -//
  3.2759 -//        function (script) {
  3.2760 -//            // Return value: Whatever syntax means "Evaluate the JavaScript statement 'script' and output the result"
  3.2761 -//            //               For example, the jquery.tmpl template engine converts 'someScript' to '${ someScript }'
  3.2762 -//        }
  3.2763 -//
  3.2764 -//     This is only necessary if you want to allow data-bind attributes to reference arbitrary template variables.
  3.2765 -//     If you don't want to allow that, you can set the property 'allowTemplateRewriting' to false (like ko.nativeTemplateEngine does)
  3.2766 -//     and then you don't need to override 'createJavaScriptEvaluatorBlock'.
  3.2767 -
  3.2768 -ko.templateEngine = function () { };
  3.2769 -
  3.2770 -ko.templateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options) {
  3.2771 -    throw new Error("Override renderTemplateSource");
  3.2772 -};
  3.2773 -
  3.2774 -ko.templateEngine.prototype['createJavaScriptEvaluatorBlock'] = function (script) {
  3.2775 -    throw new Error("Override createJavaScriptEvaluatorBlock");
  3.2776 -};
  3.2777 -
  3.2778 -ko.templateEngine.prototype['makeTemplateSource'] = function(template, templateDocument) {
  3.2779 -    // Named template
  3.2780 -    if (typeof template == "string") {
  3.2781 -        templateDocument = templateDocument || document;
  3.2782 -        var elem = templateDocument.getElementById(template);
  3.2783 -        if (!elem)
  3.2784 -            throw new Error("Cannot find template with ID " + template);
  3.2785 -        return new ko.templateSources.domElement(elem);
  3.2786 -    } else if ((template.nodeType == 1) || (template.nodeType == 8)) {
  3.2787 -        // Anonymous template
  3.2788 -        return new ko.templateSources.anonymousTemplate(template);
  3.2789 -    } else
  3.2790 -        throw new Error("Unknown template type: " + template);
  3.2791 -};
  3.2792 -
  3.2793 -ko.templateEngine.prototype['renderTemplate'] = function (template, bindingContext, options, templateDocument) {
  3.2794 -    var templateSource = this['makeTemplateSource'](template, templateDocument);
  3.2795 -    return this['renderTemplateSource'](templateSource, bindingContext, options);
  3.2796 -};
  3.2797 -
  3.2798 -ko.templateEngine.prototype['isTemplateRewritten'] = function (template, templateDocument) {
  3.2799 -    // Skip rewriting if requested
  3.2800 -    if (this['allowTemplateRewriting'] === false)
  3.2801 -        return true;
  3.2802 -    return this['makeTemplateSource'](template, templateDocument)['data']("isRewritten");
  3.2803 -};
  3.2804 -
  3.2805 -ko.templateEngine.prototype['rewriteTemplate'] = function (template, rewriterCallback, templateDocument) {
  3.2806 -    var templateSource = this['makeTemplateSource'](template, templateDocument);
  3.2807 -    var rewritten = rewriterCallback(templateSource['text']());
  3.2808 -    templateSource['text'](rewritten);
  3.2809 -    templateSource['data']("isRewritten", true);
  3.2810 -};
  3.2811 -
  3.2812 -ko.exportSymbol('templateEngine', ko.templateEngine);
  3.2813 -
  3.2814 -ko.templateRewriting = (function () {
  3.2815 -    var memoizeDataBindingAttributeSyntaxRegex = /(<[a-z]+\d*(\s+(?!data-bind=)[a-z0-9\-]+(=(\"[^\"]*\"|\'[^\']*\'))?)*\s+)data-bind=(["'])([\s\S]*?)\5/gi;
  3.2816 -    var memoizeVirtualContainerBindingSyntaxRegex = /<!--\s*ko\b\s*([\s\S]*?)\s*-->/g;
  3.2817 -
  3.2818 -    function validateDataBindValuesForRewriting(keyValueArray) {
  3.2819 -        var allValidators = ko.expressionRewriting.bindingRewriteValidators;
  3.2820 -        for (var i = 0; i < keyValueArray.length; i++) {
  3.2821 -            var key = keyValueArray[i]['key'];
  3.2822 -            if (allValidators.hasOwnProperty(key)) {
  3.2823 -                var validator = allValidators[key];
  3.2824 -
  3.2825 -                if (typeof validator === "function") {
  3.2826 -                    var possibleErrorMessage = validator(keyValueArray[i]['value']);
  3.2827 -                    if (possibleErrorMessage)
  3.2828 -                        throw new Error(possibleErrorMessage);
  3.2829 -                } else if (!validator) {
  3.2830 -                    throw new Error("This template engine does not support the '" + key + "' binding within its templates");
  3.2831 -                }
  3.2832 -            }
  3.2833 -        }
  3.2834 -    }
  3.2835 -
  3.2836 -    function constructMemoizedTagReplacement(dataBindAttributeValue, tagToRetain, templateEngine) {
  3.2837 -        var dataBindKeyValueArray = ko.expressionRewriting.parseObjectLiteral(dataBindAttributeValue);
  3.2838 -        validateDataBindValuesForRewriting(dataBindKeyValueArray);
  3.2839 -        var rewrittenDataBindAttributeValue = ko.expressionRewriting.preProcessBindings(dataBindKeyValueArray);
  3.2840 -
  3.2841 -        // For no obvious reason, Opera fails to evaluate rewrittenDataBindAttributeValue unless it's wrapped in an additional
  3.2842 -        // anonymous function, even though Opera's built-in debugger can evaluate it anyway. No other browser requires this
  3.2843 -        // extra indirection.
  3.2844 -        var applyBindingsToNextSiblingScript =
  3.2845 -            "ko.__tr_ambtns(function($context,$element){return(function(){return{ " + rewrittenDataBindAttributeValue + " } })()})";
  3.2846 -        return templateEngine['createJavaScriptEvaluatorBlock'](applyBindingsToNextSiblingScript) + tagToRetain;
  3.2847 -    }
  3.2848 -
  3.2849 -    return {
  3.2850 -        ensureTemplateIsRewritten: function (template, templateEngine, templateDocument) {
  3.2851 -            if (!templateEngine['isTemplateRewritten'](template, templateDocument))
  3.2852 -                templateEngine['rewriteTemplate'](template, function (htmlString) {
  3.2853 -                    return ko.templateRewriting.memoizeBindingAttributeSyntax(htmlString, templateEngine);
  3.2854 -                }, templateDocument);
  3.2855 -        },
  3.2856 -
  3.2857 -        memoizeBindingAttributeSyntax: function (htmlString, templateEngine) {
  3.2858 -            return htmlString.replace(memoizeDataBindingAttributeSyntaxRegex, function () {
  3.2859 -                return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[6], /* tagToRetain: */ arguments[1], templateEngine);
  3.2860 -            }).replace(memoizeVirtualContainerBindingSyntaxRegex, function() {
  3.2861 -                return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[1], /* tagToRetain: */ "<!-- ko -->", templateEngine);
  3.2862 -            });
  3.2863 -        },
  3.2864 -
  3.2865 -        applyMemoizedBindingsToNextSibling: function (bindings) {
  3.2866 -            return ko.memoization.memoize(function (domNode, bindingContext) {
  3.2867 -                if (domNode.nextSibling)
  3.2868 -                    ko.applyBindingsToNode(domNode.nextSibling, bindings, bindingContext);
  3.2869 -            });
  3.2870 -        }
  3.2871 -    }
  3.2872 -})();
  3.2873 -
  3.2874 -
  3.2875 -// Exported only because it has to be referenced by string lookup from within rewritten template
  3.2876 -ko.exportSymbol('__tr_ambtns', ko.templateRewriting.applyMemoizedBindingsToNextSibling);
  3.2877 -(function() {
  3.2878 -    // A template source represents a read/write way of accessing a template. This is to eliminate the need for template loading/saving
  3.2879 -    // logic to be duplicated in every template engine (and means they can all work with anonymous templates, etc.)
  3.2880 -    //
  3.2881 -    // Two are provided by default:
  3.2882 -    //  1. ko.templateSources.domElement       - reads/writes the text content of an arbitrary DOM element
  3.2883 -    //  2. ko.templateSources.anonymousElement - uses ko.utils.domData to read/write text *associated* with the DOM element, but
  3.2884 -    //                                           without reading/writing the actual element text content, since it will be overwritten
  3.2885 -    //                                           with the rendered template output.
  3.2886 -    // You can implement your own template source if you want to fetch/store templates somewhere other than in DOM elements.
  3.2887 -    // Template sources need to have the following functions:
  3.2888 -    //   text() 			- returns the template text from your storage location
  3.2889 -    //   text(value)		- writes the supplied template text to your storage location
  3.2890 -    //   data(key)			- reads values stored using data(key, value) - see below
  3.2891 -    //   data(key, value)	- associates "value" with this template and the key "key". Is used to store information like "isRewritten".
  3.2892 -    //
  3.2893 -    // Optionally, template sources can also have the following functions:
  3.2894 -    //   nodes()            - returns a DOM element containing the nodes of this template, where available
  3.2895 -    //   nodes(value)       - writes the given DOM element to your storage location
  3.2896 -    // If a DOM element is available for a given template source, template engines are encouraged to use it in preference over text()
  3.2897 -    // for improved speed. However, all templateSources must supply text() even if they don't supply nodes().
  3.2898 -    //
  3.2899 -    // Once you've implemented a templateSource, make your template engine use it by subclassing whatever template engine you were
  3.2900 -    // using and overriding "makeTemplateSource" to return an instance of your custom template source.
  3.2901 -
  3.2902 -    ko.templateSources = {};
  3.2903 -
  3.2904 -    // ---- ko.templateSources.domElement -----
  3.2905 -
  3.2906 -    ko.templateSources.domElement = function(element) {
  3.2907 -        this.domElement = element;
  3.2908 -    }
  3.2909 -
  3.2910 -    ko.templateSources.domElement.prototype['text'] = function(/* valueToWrite */) {
  3.2911 -        var tagNameLower = ko.utils.tagNameLower(this.domElement),
  3.2912 -            elemContentsProperty = tagNameLower === "script" ? "text"
  3.2913 -                                 : tagNameLower === "textarea" ? "value"
  3.2914 -                                 : "innerHTML";
  3.2915 -
  3.2916 -        if (arguments.length == 0) {
  3.2917 -            return this.domElement[elemContentsProperty];
  3.2918 -        } else {
  3.2919 -            var valueToWrite = arguments[0];
  3.2920 -            if (elemContentsProperty === "innerHTML")
  3.2921 -                ko.utils.setHtml(this.domElement, valueToWrite);
  3.2922 -            else
  3.2923 -                this.domElement[elemContentsProperty] = valueToWrite;
  3.2924 -        }
  3.2925 -    };
  3.2926 -
  3.2927 -    ko.templateSources.domElement.prototype['data'] = function(key /*, valueToWrite */) {
  3.2928 -        if (arguments.length === 1) {
  3.2929 -            return ko.utils.domData.get(this.domElement, "templateSourceData_" + key);
  3.2930 -        } else {
  3.2931 -            ko.utils.domData.set(this.domElement, "templateSourceData_" + key, arguments[1]);
  3.2932 -        }
  3.2933 -    };
  3.2934 -
  3.2935 -    // ---- ko.templateSources.anonymousTemplate -----
  3.2936 -    // Anonymous templates are normally saved/retrieved as DOM nodes through "nodes".
  3.2937 -    // For compatibility, you can also read "text"; it will be serialized from the nodes on demand.
  3.2938 -    // Writing to "text" is still supported, but then the template data will not be available as DOM nodes.
  3.2939 -
  3.2940 -    var anonymousTemplatesDomDataKey = "__ko_anon_template__";
  3.2941 -    ko.templateSources.anonymousTemplate = function(element) {
  3.2942 -        this.domElement = element;
  3.2943 -    }
  3.2944 -    ko.templateSources.anonymousTemplate.prototype = new ko.templateSources.domElement();
  3.2945 -    ko.templateSources.anonymousTemplate.prototype['text'] = function(/* valueToWrite */) {
  3.2946 -        if (arguments.length == 0) {
  3.2947 -            var templateData = ko.utils.domData.get(this.domElement, anonymousTemplatesDomDataKey) || {};
  3.2948 -            if (templateData.textData === undefined && templateData.containerData)
  3.2949 -                templateData.textData = templateData.containerData.innerHTML;
  3.2950 -            return templateData.textData;
  3.2951 -        } else {
  3.2952 -            var valueToWrite = arguments[0];
  3.2953 -            ko.utils.domData.set(this.domElement, anonymousTemplatesDomDataKey, {textData: valueToWrite});
  3.2954 -        }
  3.2955 -    };
  3.2956 -    ko.templateSources.domElement.prototype['nodes'] = function(/* valueToWrite */) {
  3.2957 -        if (arguments.length == 0) {
  3.2958 -            var templateData = ko.utils.domData.get(this.domElement, anonymousTemplatesDomDataKey) || {};
  3.2959 -            return templateData.containerData;
  3.2960 -        } else {
  3.2961 -            var valueToWrite = arguments[0];
  3.2962 -            ko.utils.domData.set(this.domElement, anonymousTemplatesDomDataKey, {containerData: valueToWrite});
  3.2963 -        }
  3.2964 -    };
  3.2965 -
  3.2966 -    ko.exportSymbol('templateSources', ko.templateSources);
  3.2967 -    ko.exportSymbol('templateSources.domElement', ko.templateSources.domElement);
  3.2968 -    ko.exportSymbol('templateSources.anonymousTemplate', ko.templateSources.anonymousTemplate);
  3.2969 -})();
  3.2970 -(function () {
  3.2971 -    var _templateEngine;
  3.2972 -    ko.setTemplateEngine = function (templateEngine) {
  3.2973 -        if ((templateEngine != undefined) && !(templateEngine instanceof ko.templateEngine))
  3.2974 -            throw new Error("templateEngine must inherit from ko.templateEngine");
  3.2975 -        _templateEngine = templateEngine;
  3.2976 -    }
  3.2977 -
  3.2978 -    function invokeForEachNodeOrCommentInContinuousRange(firstNode, lastNode, action) {
  3.2979 -        var node, nextInQueue = firstNode, firstOutOfRangeNode = ko.virtualElements.nextSibling(lastNode);
  3.2980 -        while (nextInQueue && ((node = nextInQueue) !== firstOutOfRangeNode)) {
  3.2981 -            nextInQueue = ko.virtualElements.nextSibling(node);
  3.2982 -            if (node.nodeType === 1 || node.nodeType === 8)
  3.2983 -                action(node);
  3.2984 -        }
  3.2985 -    }
  3.2986 -
  3.2987 -    function activateBindingsOnContinuousNodeArray(continuousNodeArray, bindingContext) {
  3.2988 -        // To be used on any nodes that have been rendered by a template and have been inserted into some parent element
  3.2989 -        // Walks through continuousNodeArray (which *must* be continuous, i.e., an uninterrupted sequence of sibling nodes, because
  3.2990 -        // the algorithm for walking them relies on this), and for each top-level item in the virtual-element sense,
  3.2991 -        // (1) Does a regular "applyBindings" to associate bindingContext with this node and to activate any non-memoized bindings
  3.2992 -        // (2) Unmemoizes any memos in the DOM subtree (e.g., to activate bindings that had been memoized during template rewriting)
  3.2993 -
  3.2994 -        if (continuousNodeArray.length) {
  3.2995 -            var firstNode = continuousNodeArray[0], lastNode = continuousNodeArray[continuousNodeArray.length - 1];
  3.2996 -
  3.2997 -            // Need to applyBindings *before* unmemoziation, because unmemoization might introduce extra nodes (that we don't want to re-bind)
  3.2998 -            // whereas a regular applyBindings won't introduce new memoized nodes
  3.2999 -            invokeForEachNodeOrCommentInContinuousRange(firstNode, lastNode, function(node) {
  3.3000 -                ko.applyBindings(bindingContext, node);
  3.3001 -            });
  3.3002 -            invokeForEachNodeOrCommentInContinuousRange(firstNode, lastNode, function(node) {
  3.3003 -                ko.memoization.unmemoizeDomNodeAndDescendants(node, [bindingContext]);
  3.3004 -            });
  3.3005 -        }
  3.3006 -    }
  3.3007 -
  3.3008 -    function getFirstNodeFromPossibleArray(nodeOrNodeArray) {
  3.3009 -        return nodeOrNodeArray.nodeType ? nodeOrNodeArray
  3.3010 -                                        : nodeOrNodeArray.length > 0 ? nodeOrNodeArray[0]
  3.3011 -                                        : null;
  3.3012 -    }
  3.3013 -
  3.3014 -    function executeTemplate(targetNodeOrNodeArray, renderMode, template, bindingContext, options) {
  3.3015 -        options = options || {};
  3.3016 -        var firstTargetNode = targetNodeOrNodeArray && getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
  3.3017 -        var templateDocument = firstTargetNode && firstTargetNode.ownerDocument;
  3.3018 -        var templateEngineToUse = (options['templateEngine'] || _templateEngine);
  3.3019 -        ko.templateRewriting.ensureTemplateIsRewritten(template, templateEngineToUse, templateDocument);
  3.3020 -        var renderedNodesArray = templateEngineToUse['renderTemplate'](template, bindingContext, options, templateDocument);
  3.3021 -
  3.3022 -        // Loosely check result is an array of DOM nodes
  3.3023 -        if ((typeof renderedNodesArray.length != "number") || (renderedNodesArray.length > 0 && typeof renderedNodesArray[0].nodeType != "number"))
  3.3024 -            throw new Error("Template engine must return an array of DOM nodes");
  3.3025 -
  3.3026 -        var haveAddedNodesToParent = false;
  3.3027 -        switch (renderMode) {
  3.3028 -            case "replaceChildren":
  3.3029 -                ko.virtualElements.setDomNodeChildren(targetNodeOrNodeArray, renderedNodesArray);
  3.3030 -                haveAddedNodesToParent = true;
  3.3031 -                break;
  3.3032 -            case "replaceNode":
  3.3033 -                ko.utils.replaceDomNodes(targetNodeOrNodeArray, renderedNodesArray);
  3.3034 -                haveAddedNodesToParent = true;
  3.3035 -                break;
  3.3036 -            case "ignoreTargetNode": break;
  3.3037 -            default:
  3.3038 -                throw new Error("Unknown renderMode: " + renderMode);
  3.3039 -        }
  3.3040 -
  3.3041 -        if (haveAddedNodesToParent) {
  3.3042 -            activateBindingsOnContinuousNodeArray(renderedNodesArray, bindingContext);
  3.3043 -            if (options['afterRender'])
  3.3044 -                ko.dependencyDetection.ignore(options['afterRender'], null, [renderedNodesArray, bindingContext['$data']]);
  3.3045 -        }
  3.3046 -
  3.3047 -        return renderedNodesArray;
  3.3048 -    }
  3.3049 -
  3.3050 -    ko.renderTemplate = function (template, dataOrBindingContext, options, targetNodeOrNodeArray, renderMode) {
  3.3051 -        options = options || {};
  3.3052 -        if ((options['templateEngine'] || _templateEngine) == undefined)
  3.3053 -            throw new Error("Set a template engine before calling renderTemplate");
  3.3054 -        renderMode = renderMode || "replaceChildren";
  3.3055 -
  3.3056 -        if (targetNodeOrNodeArray) {
  3.3057 -            var firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
  3.3058 -
  3.3059 -            var whenToDispose = function () { return (!firstTargetNode) || !ko.utils.domNodeIsAttachedToDocument(firstTargetNode); }; // Passive disposal (on next evaluation)
  3.3060 -            var activelyDisposeWhenNodeIsRemoved = (firstTargetNode && renderMode == "replaceNode") ? firstTargetNode.parentNode : firstTargetNode;
  3.3061 -
  3.3062 -            return ko.dependentObservable( // So the DOM is automatically updated when any dependency changes
  3.3063 -                function () {
  3.3064 -                    // Ensure we've got a proper binding context to work with
  3.3065 -                    var bindingContext = (dataOrBindingContext && (dataOrBindingContext instanceof ko.bindingContext))
  3.3066 -                        ? dataOrBindingContext
  3.3067 -                        : new ko.bindingContext(ko.utils.unwrapObservable(dataOrBindingContext));
  3.3068 -
  3.3069 -                    // Support selecting template as a function of the data being rendered
  3.3070 -                    var templateName = typeof(template) == 'function' ? template(bindingContext['$data'], bindingContext) : template;
  3.3071 -
  3.3072 -                    var renderedNodesArray = executeTemplate(targetNodeOrNodeArray, renderMode, templateName, bindingContext, options);
  3.3073 -                    if (renderMode == "replaceNode") {
  3.3074 -                        targetNodeOrNodeArray = renderedNodesArray;
  3.3075 -                        firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
  3.3076 -                    }
  3.3077 -                },
  3.3078 -                null,
  3.3079 -                { disposeWhen: whenToDispose, disposeWhenNodeIsRemoved: activelyDisposeWhenNodeIsRemoved }
  3.3080 -            );
  3.3081 -        } else {
  3.3082 -            // We don't yet have a DOM node to evaluate, so use a memo and render the template later when there is a DOM node
  3.3083 -            return ko.memoization.memoize(function (domNode) {
  3.3084 -                ko.renderTemplate(template, dataOrBindingContext, options, domNode, "replaceNode");
  3.3085 -            });
  3.3086 -        }
  3.3087 -    };
  3.3088 -
  3.3089 -    ko.renderTemplateForEach = function (template, arrayOrObservableArray, options, targetNode, parentBindingContext) {
  3.3090 -        // Since setDomNodeChildrenFromArrayMapping always calls executeTemplateForArrayItem and then
  3.3091 -        // activateBindingsCallback for added items, we can store the binding context in the former to use in the latter.
  3.3092 -        var arrayItemContext;
  3.3093 -
  3.3094 -        // This will be called by setDomNodeChildrenFromArrayMapping to get the nodes to add to targetNode
  3.3095 -        var executeTemplateForArrayItem = function (arrayValue, index) {
  3.3096 -            // Support selecting template as a function of the data being rendered
  3.3097 -            arrayItemContext = parentBindingContext['createChildContext'](ko.utils.unwrapObservable(arrayValue), options['as']);
  3.3098 -            arrayItemContext['$index'] = index;
  3.3099 -            var templateName = typeof(template) == 'function' ? template(arrayValue, arrayItemContext) : template;
  3.3100 -            return executeTemplate(null, "ignoreTargetNode", templateName, arrayItemContext, options);
  3.3101 -        }
  3.3102 -
  3.3103 -        // This will be called whenever setDomNodeChildrenFromArrayMapping has added nodes to targetNode
  3.3104 -        var activateBindingsCallback = function(arrayValue, addedNodesArray, index) {
  3.3105 -            activateBindingsOnContinuousNodeArray(addedNodesArray, arrayItemContext);
  3.3106 -            if (options['afterRender'])
  3.3107 -                options['afterRender'](addedNodesArray, arrayValue);
  3.3108 -        };
  3.3109 -
  3.3110 -        return ko.dependentObservable(function () {
  3.3111 -            var unwrappedArray = ko.utils.unwrapObservable(arrayOrObservableArray) || [];
  3.3112 -            if (typeof unwrappedArray.length == "undefined") // Coerce single value into array
  3.3113 -                unwrappedArray = [unwrappedArray];
  3.3114 -
  3.3115 -            // Filter out any entries marked as destroyed
  3.3116 -            var filteredArray = ko.utils.arrayFilter(unwrappedArray, function(item) {
  3.3117 -                return options['includeDestroyed'] || item === undefined || item === null || !ko.utils.unwrapObservable(item['_destroy']);
  3.3118 -            });
  3.3119 -
  3.3120 -            // Call setDomNodeChildrenFromArrayMapping, ignoring any observables unwrapped within (most likely from a callback function).
  3.3121 -            // If the array items are observables, though, they will be unwrapped in executeTemplateForArrayItem and managed within setDomNodeChildrenFromArrayMapping.
  3.3122 -            ko.dependencyDetection.ignore(ko.utils.setDomNodeChildrenFromArrayMapping, null, [targetNode, filteredArray, executeTemplateForArrayItem, options, activateBindingsCallback]);
  3.3123 -
  3.3124 -        }, null, { disposeWhenNodeIsRemoved: targetNode });
  3.3125 -    };
  3.3126 -
  3.3127 -    var templateComputedDomDataKey = '__ko__templateComputedDomDataKey__';
  3.3128 -    function disposeOldComputedAndStoreNewOne(element, newComputed) {
  3.3129 -        var oldComputed = ko.utils.domData.get(element, templateComputedDomDataKey);
  3.3130 -        if (oldComputed && (typeof(oldComputed.dispose) == 'function'))
  3.3131 -            oldComputed.dispose();
  3.3132 -        ko.utils.domData.set(element, templateComputedDomDataKey, (newComputed && newComputed.isActive()) ? newComputed : undefined);
  3.3133 -    }
  3.3134 -
  3.3135 -    ko.bindingHandlers['template'] = {
  3.3136 -        'init': function(element, valueAccessor) {
  3.3137 -            // Support anonymous templates
  3.3138 -            var bindingValue = ko.utils.unwrapObservable(valueAccessor());
  3.3139 -            if ((typeof bindingValue != "string") && (!bindingValue['name']) && (element.nodeType == 1 || element.nodeType == 8)) {
  3.3140 -                // It's an anonymous template - store the element contents, then clear the element
  3.3141 -                var templateNodes = element.nodeType == 1 ? element.childNodes : ko.virtualElements.childNodes(element),
  3.3142 -                    container = ko.utils.moveCleanedNodesToContainerElement(templateNodes); // This also removes the nodes from their current parent
  3.3143 -                new ko.templateSources.anonymousTemplate(element)['nodes'](container);
  3.3144 -            }
  3.3145 -            return { 'controlsDescendantBindings': true };
  3.3146 -        },
  3.3147 -        'update': function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
  3.3148 -            var templateName = ko.utils.unwrapObservable(valueAccessor()),
  3.3149 -                options = {},
  3.3150 -                shouldDisplay = true,
  3.3151 -                dataValue,
  3.3152 -                templateComputed = null;
  3.3153 -
  3.3154 -            if (typeof templateName != "string") {
  3.3155 -                options = templateName;
  3.3156 -                templateName = options['name'];
  3.3157 -
  3.3158 -                // Support "if"/"ifnot" conditions
  3.3159 -                if ('if' in options)
  3.3160 -                    shouldDisplay = ko.utils.unwrapObservable(options['if']);
  3.3161 -                if (shouldDisplay && 'ifnot' in options)
  3.3162 -                    shouldDisplay = !ko.utils.unwrapObservable(options['ifnot']);
  3.3163 -
  3.3164 -                dataValue = ko.utils.unwrapObservable(options['data']);
  3.3165 -            }
  3.3166 -
  3.3167 -            if ('foreach' in options) {
  3.3168 -                // Render once for each data point (treating data set as empty if shouldDisplay==false)
  3.3169 -                var dataArray = (shouldDisplay && options['foreach']) || [];
  3.3170 -                templateComputed = ko.renderTemplateForEach(templateName || element, dataArray, options, element, bindingContext);
  3.3171 -            } else if (!shouldDisplay) {
  3.3172 -                ko.virtualElements.emptyNode(element);
  3.3173 -            } else {
  3.3174 -                // Render once for this single data point (or use the viewModel if no data was provided)
  3.3175 -                var innerBindingContext = ('data' in options) ?
  3.3176 -                    bindingContext['createChildContext'](dataValue, options['as']) :  // Given an explitit 'data' value, we create a child binding context for it
  3.3177 -                    bindingContext;                                                        // Given no explicit 'data' value, we retain the same binding context
  3.3178 -                templateComputed = ko.renderTemplate(templateName || element, innerBindingContext, options, element);
  3.3179 -            }
  3.3180 -
  3.3181 -            // It only makes sense to have a single template computed per element (otherwise which one should have its output displayed?)
  3.3182 -            disposeOldComputedAndStoreNewOne(element, templateComputed);
  3.3183 -        }
  3.3184 -    };
  3.3185 -
  3.3186 -    // Anonymous templates can't be rewritten. Give a nice error message if you try to do it.
  3.3187 -    ko.expressionRewriting.bindingRewriteValidators['template'] = function(bindingValue) {
  3.3188 -        var parsedBindingValue = ko.expressionRewriting.parseObjectLiteral(bindingValue);
  3.3189 -
  3.3190 -        if ((parsedBindingValue.length == 1) && parsedBindingValue[0]['unknown'])
  3.3191 -            return null; // It looks like a string literal, not an object literal, so treat it as a named template (which is allowed for rewriting)
  3.3192 -
  3.3193 -        if (ko.expressionRewriting.keyValueArrayContainsKey(parsedBindingValue, "name"))
  3.3194 -            return null; // Named templates can be rewritten, so return "no error"
  3.3195 -        return "This template engine does not support anonymous templates nested within its templates";
  3.3196 -    };
  3.3197 -
  3.3198 -    ko.virtualElements.allowedBindings['template'] = true;
  3.3199 -})();
  3.3200 -
  3.3201 -ko.exportSymbol('setTemplateEngine', ko.setTemplateEngine);
  3.3202 -ko.exportSymbol('renderTemplate', ko.renderTemplate);
  3.3203 -
  3.3204 -ko.utils.compareArrays = (function () {
  3.3205 -    var statusNotInOld = 'added', statusNotInNew = 'deleted';
  3.3206 -
  3.3207 -    // Simple calculation based on Levenshtein distance.
  3.3208 -    function compareArrays(oldArray, newArray, dontLimitMoves) {
  3.3209 -        oldArray = oldArray || [];
  3.3210 -        newArray = newArray || [];
  3.3211 -
  3.3212 -        if (oldArray.length <= newArray.length)
  3.3213 -            return compareSmallArrayToBigArray(oldArray, newArray, statusNotInOld, statusNotInNew, dontLimitMoves);
  3.3214 -        else
  3.3215 -            return compareSmallArrayToBigArray(newArray, oldArray, statusNotInNew, statusNotInOld, dontLimitMoves);
  3.3216 -    }
  3.3217 -
  3.3218 -    function compareSmallArrayToBigArray(smlArray, bigArray, statusNotInSml, statusNotInBig, dontLimitMoves) {
  3.3219 -        var myMin = Math.min,
  3.3220 -            myMax = Math.max,
  3.3221 -            editDistanceMatrix = [],
  3.3222 -            smlIndex, smlIndexMax = smlArray.length,
  3.3223 -            bigIndex, bigIndexMax = bigArray.length,
  3.3224 -            compareRange = (bigIndexMax - smlIndexMax) || 1,
  3.3225 -            maxDistance = smlIndexMax + bigIndexMax + 1,
  3.3226 -            thisRow, lastRow,
  3.3227 -            bigIndexMaxForRow, bigIndexMinForRow;
  3.3228 -
  3.3229 -        for (smlIndex = 0; smlIndex <= smlIndexMax; smlIndex++) {
  3.3230 -            lastRow = thisRow;
  3.3231 -            editDistanceMatrix.push(thisRow = []);
  3.3232 -            bigIndexMaxForRow = myMin(bigIndexMax, smlIndex + compareRange);
  3.3233 -            bigIndexMinForRow = myMax(0, smlIndex - 1);
  3.3234 -            for (bigIndex = bigIndexMinForRow; bigIndex <= bigIndexMaxForRow; bigIndex++) {
  3.3235 -                if (!bigIndex)
  3.3236 -                    thisRow[bigIndex] = smlIndex + 1;
  3.3237 -                else if (!smlIndex)  // Top row - transform empty array into new array via additions
  3.3238 -                    thisRow[bigIndex] = bigIndex + 1;
  3.3239 -                else if (smlArray[smlIndex - 1] === bigArray[bigIndex - 1])
  3.3240 -                    thisRow[bigIndex] = lastRow[bigIndex - 1];                  // copy value (no edit)
  3.3241 -                else {
  3.3242 -                    var northDistance = lastRow[bigIndex] || maxDistance;       // not in big (deletion)
  3.3243 -                    var westDistance = thisRow[bigIndex - 1] || maxDistance;    // not in small (addition)
  3.3244 -                    thisRow[bigIndex] = myMin(northDistance, westDistance) + 1;
  3.3245 -                }
  3.3246 -            }
  3.3247 -        }
  3.3248 -
  3.3249 -        var editScript = [], meMinusOne, notInSml = [], notInBig = [];
  3.3250 -        for (smlIndex = smlIndexMax, bigIndex = bigIndexMax; smlIndex || bigIndex;) {
  3.3251 -            meMinusOne = editDistanceMatrix[smlIndex][bigIndex] - 1;
  3.3252 -            if (bigIndex && meMinusOne === editDistanceMatrix[smlIndex][bigIndex-1]) {
  3.3253 -                notInSml.push(editScript[editScript.length] = {     // added
  3.3254 -                    'status': statusNotInSml,
  3.3255 -                    'value': bigArray[--bigIndex],
  3.3256 -                    'index': bigIndex });
  3.3257 -            } else if (smlIndex && meMinusOne === editDistanceMatrix[smlIndex - 1][bigIndex]) {
  3.3258 -                notInBig.push(editScript[editScript.length] = {     // deleted
  3.3259 -                    'status': statusNotInBig,
  3.3260 -                    'value': smlArray[--smlIndex],
  3.3261 -                    'index': smlIndex });
  3.3262 -            } else {
  3.3263 -                editScript.push({
  3.3264 -                    'status': "retained",
  3.3265 -                    'value': bigArray[--bigIndex] });
  3.3266 -                --smlIndex;
  3.3267 -            }
  3.3268 -        }
  3.3269 -
  3.3270 -        if (notInSml.length && notInBig.length) {
  3.3271 -            // Set a limit on the number of consecutive non-matching comparisons; having it a multiple of
  3.3272 -            // smlIndexMax keeps the time complexity of this algorithm linear.
  3.3273 -            var limitFailedCompares = smlIndexMax * 10, failedCompares,
  3.3274 -                a, d, notInSmlItem, notInBigItem;
  3.3275 -            // Go through the items that have been added and deleted and try to find matches between them.
  3.3276 -            for (failedCompares = a = 0; (dontLimitMoves || failedCompares < limitFailedCompares) && (notInSmlItem = notInSml[a]); a++) {
  3.3277 -                for (d = 0; notInBigItem = notInBig[d]; d++) {
  3.3278 -                    if (notInSmlItem['value'] === notInBigItem['value']) {
  3.3279 -                        notInSmlItem['moved'] = notInBigItem['index'];
  3.3280 -                        notInBigItem['moved'] = notInSmlItem['index'];
  3.3281 -                        notInBig.splice(d,1);       // This item is marked as moved; so remove it from notInBig list
  3.3282 -                        failedCompares = d = 0;     // Reset failed compares count because we're checking for consecutive failures
  3.3283 -                        break;
  3.3284 -                    }
  3.3285 -                }
  3.3286 -                failedCompares += d;
  3.3287 -            }
  3.3288 -        }
  3.3289 -        return editScript.reverse();
  3.3290 -    }
  3.3291 -
  3.3292 -    return compareArrays;
  3.3293 -})();
  3.3294 -
  3.3295 -ko.exportSymbol('utils.compareArrays', ko.utils.compareArrays);
  3.3296 -
  3.3297 -(function () {
  3.3298 -    // Objective:
  3.3299 -    // * Given an input array, a container DOM node, and a function from array elements to arrays of DOM nodes,
  3.3300 -    //   map the array elements to arrays of DOM nodes, concatenate together all these arrays, and use them to populate the container DOM node
  3.3301 -    // * Next time we're given the same combination of things (with the array possibly having mutated), update the container DOM node
  3.3302 -    //   so that its children is again the concatenation of the mappings of the array elements, but don't re-map any array elements that we
  3.3303 -    //   previously mapped - retain those nodes, and just insert/delete other ones
  3.3304 -
  3.3305 -    // "callbackAfterAddingNodes" will be invoked after any "mapping"-generated nodes are inserted into the container node
  3.3306 -    // You can use this, for example, to activate bindings on those nodes.
  3.3307 -
  3.3308 -    function fixUpNodesToBeMovedOrRemoved(contiguousNodeArray) {
  3.3309 -        // Before moving, deleting, or replacing a set of nodes that were previously outputted by the "map" function, we have to reconcile
  3.3310 -        // them against what is in the DOM right now. It may be that some of the nodes have already been removed from the document,
  3.3311 -        // or that new nodes might have been inserted in the middle, for example by a binding. Also, there may previously have been
  3.3312 -        // leading comment nodes (created by rewritten string-based templates) that have since been removed during binding.
  3.3313 -        // So, this function translates the old "map" output array into its best guess of what set of current DOM nodes should be removed.
  3.3314 -        //
  3.3315 -        // Rules:
  3.3316 -        //   [A] Any leading nodes that aren't in the document any more should be ignored
  3.3317 -        //       These most likely correspond to memoization nodes that were already removed during binding
  3.3318 -        //       See https://github.com/SteveSanderson/knockout/pull/440
  3.3319 -        //   [B] We want to output a contiguous series of nodes that are still in the document. So, ignore any nodes that
  3.3320 -        //       have already been removed, and include any nodes that have been inserted among the previous collection
  3.3321 -
  3.3322 -        // Rule [A]
  3.3323 -        while (contiguousNodeArray.length && !ko.utils.domNodeIsAttachedToDocument(contiguousNodeArray[0]))
  3.3324 -            contiguousNodeArray.splice(0, 1);
  3.3325 -
  3.3326 -        // Rule [B]
  3.3327 -        if (contiguousNodeArray.length > 1) {
  3.3328 -            // Build up the actual new contiguous node set
  3.3329 -            var current = contiguousNodeArray[0], last = contiguousNodeArray[contiguousNodeArray.length - 1], newContiguousSet = [current];
  3.3330 -            while (current !== last) {
  3.3331 -                current = current.nextSibling;
  3.3332 -                if (!current) // Won't happen, except if the developer has manually removed some DOM elements (then we're in an undefined scenario)
  3.3333 -                    return;
  3.3334 -                newContiguousSet.push(current);
  3.3335 -            }
  3.3336 -
  3.3337 -            // ... then mutate the input array to match this.
  3.3338 -            // (The following line replaces the contents of contiguousNodeArray with newContiguousSet)
  3.3339 -            Array.prototype.splice.apply(contiguousNodeArray, [0, contiguousNodeArray.length].concat(newContiguousSet));
  3.3340 -        }
  3.3341 -        return contiguousNodeArray;
  3.3342 -    }
  3.3343 -
  3.3344 -    function mapNodeAndRefreshWhenChanged(containerNode, mapping, valueToMap, callbackAfterAddingNodes, index) {
  3.3345 -        // Map this array value inside a dependentObservable so we re-map when any dependency changes
  3.3346 -        var mappedNodes = [];
  3.3347 -        var dependentObservable = ko.dependentObservable(function() {
  3.3348 -            var newMappedNodes = mapping(valueToMap, index) || [];
  3.3349 -
  3.3350 -            // On subsequent evaluations, just replace the previously-inserted DOM nodes
  3.3351 -            if (mappedNodes.length > 0) {
  3.3352 -                ko.utils.replaceDomNodes(fixUpNodesToBeMovedOrRemoved(mappedNodes), newMappedNodes);
  3.3353 -                if (callbackAfterAddingNodes)
  3.3354 -                    ko.dependencyDetection.ignore(callbackAfterAddingNodes, null, [valueToMap, newMappedNodes, index]);
  3.3355 -            }
  3.3356 -
  3.3357 -            // Replace the contents of the mappedNodes array, thereby updating the record
  3.3358 -            // of which nodes would be deleted if valueToMap was itself later removed
  3.3359 -            mappedNodes.splice(0, mappedNodes.length);
  3.3360 -            ko.utils.arrayPushAll(mappedNodes, newMappedNodes);
  3.3361 -        }, null, { disposeWhenNodeIsRemoved: containerNode, disposeWhen: function() { return (mappedNodes.length == 0) || !ko.utils.domNodeIsAttachedToDocument(mappedNodes[0]) } });
  3.3362 -        return { mappedNodes : mappedNodes, dependentObservable : (dependentObservable.isActive() ? dependentObservable : undefined) };
  3.3363 -    }
  3.3364 -
  3.3365 -    var lastMappingResultDomDataKey = "setDomNodeChildrenFromArrayMapping_lastMappingResult";
  3.3366 -
  3.3367 -    ko.utils.setDomNodeChildrenFromArrayMapping = function (domNode, array, mapping, options, callbackAfterAddingNodes) {
  3.3368 -        // Compare the provided array against the previous one
  3.3369 -        array = array || [];
  3.3370 -        options = options || {};
  3.3371 -        var isFirstExecution = ko.utils.domData.get(domNode, lastMappingResultDomDataKey) === undefined;
  3.3372 -        var lastMappingResult = ko.utils.domData.get(domNode, lastMappingResultDomDataKey) || [];
  3.3373 -        var lastArray = ko.utils.arrayMap(lastMappingResult, function (x) { return x.arrayEntry; });
  3.3374 -        var editScript = ko.utils.compareArrays(lastArray, array);
  3.3375 -
  3.3376 -        // Build the new mapping result
  3.3377 -        var newMappingResult = [];
  3.3378 -        var lastMappingResultIndex = 0;
  3.3379 -        var newMappingResultIndex = 0;
  3.3380 -
  3.3381 -        var nodesToDelete = [];
  3.3382 -        var itemsToProcess = [];
  3.3383 -        var itemsForBeforeRemoveCallbacks = [];
  3.3384 -        var itemsForMoveCallbacks = [];
  3.3385 -        var itemsForAfterAddCallbacks = [];
  3.3386 -        var mapData;
  3.3387 -
  3.3388 -        function itemMovedOrRetained(editScriptIndex, oldPosition) {
  3.3389 -            mapData = lastMappingResult[oldPosition];
  3.3390 -            if (newMappingResultIndex !== oldPosition)
  3.3391 -                itemsForMoveCallbacks[editScriptIndex] = mapData;
  3.3392 -            // Since updating the index might change the nodes, do so before calling fixUpNodesToBeMovedOrRemoved
  3.3393 -            mapData.indexObservable(newMappingResultIndex++);
  3.3394 -            fixUpNodesToBeMovedOrRemoved(mapData.mappedNodes);
  3.3395 -            newMappingResult.push(mapData);
  3.3396 -            itemsToProcess.push(mapData);
  3.3397 -        }
  3.3398 -
  3.3399 -        function callCallback(callback, items) {
  3.3400 -            if (callback) {
  3.3401 -                for (var i = 0, n = items.length; i < n; i++) {
  3.3402 -                    if (items[i]) {
  3.3403 -                        ko.utils.arrayForEach(items[i].mappedNodes, function(node) {
  3.3404 -                            callback(node, i, items[i].arrayEntry);
  3.3405 -                        });
  3.3406 -                    }
  3.3407 -                }
  3.3408 -            }
  3.3409 -        }
  3.3410 -
  3.3411 -        for (var i = 0, editScriptItem, movedIndex; editScriptItem = editScript[i]; i++) {
  3.3412 -            movedIndex = editScriptItem['moved'];
  3.3413 -            switch (editScriptItem['status']) {
  3.3414 -                case "deleted":
  3.3415 -                    if (movedIndex === undefined) {
  3.3416 -                        mapData = lastMappingResult[lastMappingResultIndex];
  3.3417 -
  3.3418 -                        // Stop tracking changes to the mapping for these nodes
  3.3419 -                        if (mapData.dependentObservable)
  3.3420 -                            mapData.dependentObservable.dispose();
  3.3421 -
  3.3422 -                        // Queue these nodes for later removal
  3.3423 -                        nodesToDelete.push.apply(nodesToDelete, fixUpNodesToBeMovedOrRemoved(mapData.mappedNodes));
  3.3424 -                        if (options['beforeRemove']) {
  3.3425 -                            itemsForBeforeRemoveCallbacks[i] = mapData;
  3.3426 -                            itemsToProcess.push(mapData);
  3.3427 -                        }
  3.3428 -                    }
  3.3429 -                    lastMappingResultIndex++;
  3.3430 -                    break;
  3.3431 -
  3.3432 -                case "retained":
  3.3433 -                    itemMovedOrRetained(i, lastMappingResultIndex++);
  3.3434 -                    break;
  3.3435 -
  3.3436 -                case "added":
  3.3437 -                    if (movedIndex !== undefined) {
  3.3438 -                        itemMovedOrRetained(i, movedIndex);
  3.3439 -                    } else {
  3.3440 -                        mapData = { arrayEntry: editScriptItem['value'], indexObservable: ko.observable(newMappingResultIndex++) };
  3.3441 -                        newMappingResult.push(mapData);
  3.3442 -                        itemsToProcess.push(mapData);
  3.3443 -                        if (!isFirstExecution)
  3.3444 -                            itemsForAfterAddCallbacks[i] = mapData;
  3.3445 -                    }
  3.3446 -                    break;
  3.3447 -            }
  3.3448 -        }
  3.3449 -
  3.3450 -        // Call beforeMove first before any changes have been made to the DOM
  3.3451 -        callCallback(options['beforeMove'], itemsForMoveCallbacks);
  3.3452 -
  3.3453 -        // Next remove nodes for deleted items (or just clean if there's a beforeRemove callback)
  3.3454 -        ko.utils.arrayForEach(nodesToDelete, options['beforeRemove'] ? ko.cleanNode : ko.removeNode);
  3.3455 -
  3.3456 -        // Next add/reorder the remaining items (will include deleted items if there's a beforeRemove callback)
  3.3457 -        for (var i = 0, nextNode = ko.virtualElements.firstChild(domNode), lastNode, node; mapData = itemsToProcess[i]; i++) {
  3.3458 -            // Get nodes for newly added items
  3.3459 -            if (!mapData.mappedNodes)
  3.3460 -                ko.utils.extend(mapData, mapNodeAndRefreshWhenChanged(domNode, mapping, mapData.arrayEntry, callbackAfterAddingNodes, mapData.indexObservable));
  3.3461 -
  3.3462 -            // Put nodes in the right place if they aren't there already
  3.3463 -            for (var j = 0; node = mapData.mappedNodes[j]; nextNode = node.nextSibling, lastNode = node, j++) {
  3.3464 -                if (node !== nextNode)
  3.3465 -                    ko.virtualElements.insertAfter(domNode, node, lastNode);
  3.3466 -            }
  3.3467 -
  3.3468 -            // Run the callbacks for newly added nodes (for example, to apply bindings, etc.)
  3.3469 -            if (!mapData.initialized && callbackAfterAddingNodes) {
  3.3470 -                callbackAfterAddingNodes(mapData.arrayEntry, mapData.mappedNodes, mapData.indexObservable);
  3.3471 -                mapData.initialized = true;
  3.3472 -            }
  3.3473 -        }
  3.3474 -
  3.3475 -        // If there's a beforeRemove callback, call it after reordering.
  3.3476 -        // Note that we assume that the beforeRemove callback will usually be used to remove the nodes using
  3.3477 -        // some sort of animation, which is why we first reorder the nodes that will be removed. If the
  3.3478 -        // callback instead removes the nodes right away, it would be more efficient to skip reordering them.
  3.3479 -        // Perhaps we'll make that change in the future if this scenario becomes more common.
  3.3480 -        callCallback(options['beforeRemove'], itemsForBeforeRemoveCallbacks);
  3.3481 -
  3.3482 -        // Finally call afterMove and afterAdd callbacks
  3.3483 -        callCallback(options['afterMove'], itemsForMoveCallbacks);
  3.3484 -        callCallback(options['afterAdd'], itemsForAfterAddCallbacks);
  3.3485 -
  3.3486 -        // Store a copy of the array items we just considered so we can difference it next time
  3.3487 -        ko.utils.domData.set(domNode, lastMappingResultDomDataKey, newMappingResult);
  3.3488 -    }
  3.3489 -})();
  3.3490 -
  3.3491 -ko.exportSymbol('utils.setDomNodeChildrenFromArrayMapping', ko.utils.setDomNodeChildrenFromArrayMapping);
  3.3492 -ko.nativeTemplateEngine = function () {
  3.3493 -    this['allowTemplateRewriting'] = false;
  3.3494 -}
  3.3495 -
  3.3496 -ko.nativeTemplateEngine.prototype = new ko.templateEngine();
  3.3497 -ko.nativeTemplateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options) {
  3.3498 -    var useNodesIfAvailable = !(ko.utils.ieVersion < 9), // IE<9 cloneNode doesn't work properly
  3.3499 -        templateNodesFunc = useNodesIfAvailable ? templateSource['nodes'] : null,
  3.3500 -        templateNodes = templateNodesFunc ? templateSource['nodes']() : null;
  3.3501 -
  3.3502 -    if (templateNodes) {
  3.3503 -        return ko.utils.makeArray(templateNodes.cloneNode(true).childNodes);
  3.3504 -    } else {
  3.3505 -        var templateText = templateSource['text']();
  3.3506 -        return ko.utils.parseHtmlFragment(templateText);
  3.3507 -    }
  3.3508 -};
  3.3509 -
  3.3510 -ko.nativeTemplateEngine.instance = new ko.nativeTemplateEngine();
  3.3511 -ko.setTemplateEngine(ko.nativeTemplateEngine.instance);
  3.3512 -
  3.3513 -ko.exportSymbol('nativeTemplateEngine', ko.nativeTemplateEngine);
  3.3514 -(function() {
  3.3515 -    ko.jqueryTmplTemplateEngine = function () {
  3.3516 -        // Detect which version of jquery-tmpl you're using. Unfortunately jquery-tmpl
  3.3517 -        // doesn't expose a version number, so we have to infer it.
  3.3518 -        // Note that as of Knockout 1.3, we only support jQuery.tmpl 1.0.0pre and later,
  3.3519 -        // which KO internally refers to as version "2", so older versions are no longer detected.
  3.3520 -        var jQueryTmplVersion = this.jQueryTmplVersion = (function() {
  3.3521 -            if ((typeof(jQuery) == "undefined") || !(jQuery['tmpl']))
  3.3522 -                return 0;
  3.3523 -            // Since it exposes no official version number, we use our own numbering system. To be updated as jquery-tmpl evolves.
  3.3524 -            try {
  3.3525 -                if (jQuery['tmpl']['tag']['tmpl']['open'].toString().indexOf('__') >= 0) {
  3.3526 -                    // Since 1.0.0pre, custom tags should append markup to an array called "__"
  3.3527 -                    return 2; // Final version of jquery.tmpl
  3.3528 -                }
  3.3529 -            } catch(ex) { /* Apparently not the version we were looking for */ }
  3.3530 -
  3.3531 -            return 1; // Any older version that we don't support
  3.3532 -        })();
  3.3533 -
  3.3534 -        function ensureHasReferencedJQueryTemplates() {
  3.3535 -            if (jQueryTmplVersion < 2)
  3.3536 -                throw new Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");
  3.3537 -        }
  3.3538 -
  3.3539 -        function executeTemplate(compiledTemplate, data, jQueryTemplateOptions) {
  3.3540 -            return jQuery['tmpl'](compiledTemplate, data, jQueryTemplateOptions);
  3.3541 -        }
  3.3542 -
  3.3543 -        this['renderTemplateSource'] = function(templateSource, bindingContext, options) {
  3.3544 -            options = options || {};
  3.3545 -            ensureHasReferencedJQueryTemplates();
  3.3546 -
  3.3547 -            // Ensure we have stored a precompiled version of this template (don't want to reparse on every render)
  3.3548 -            var precompiled = templateSource['data']('precompiled');
  3.3549 -            if (!precompiled) {
  3.3550 -                var templateText = templateSource['text']() || "";
  3.3551 -                // Wrap in "with($whatever.koBindingContext) { ... }"
  3.3552 -                templateText = "{{ko_with $item.koBindingContext}}" + templateText + "{{/ko_with}}";
  3.3553 -
  3.3554 -                precompiled = jQuery['template'](null, templateText);
  3.3555 -                templateSource['data']('precompiled', precompiled);
  3.3556 -            }
  3.3557 -
  3.3558 -            var data = [bindingContext['$data']]; // Prewrap the data in an array to stop jquery.tmpl from trying to unwrap any arrays
  3.3559 -            var jQueryTemplateOptions = jQuery['extend']({ 'koBindingContext': bindingContext }, options['templateOptions']);
  3.3560 -
  3.3561 -            var resultNodes = executeTemplate(precompiled, data, jQueryTemplateOptions);
  3.3562 -            resultNodes['appendTo'](document.createElement("div")); // Using "appendTo" forces jQuery/jQuery.tmpl to perform necessary cleanup work
  3.3563 -
  3.3564 -            jQuery['fragments'] = {}; // Clear jQuery's fragment cache to avoid a memory leak after a large number of template renders
  3.3565 -            return resultNodes;
  3.3566 -        };
  3.3567 -
  3.3568 -        this['createJavaScriptEvaluatorBlock'] = function(script) {
  3.3569 -            return "{{ko_code ((function() { return " + script + " })()) }}";
  3.3570 -        };
  3.3571 -
  3.3572 -        this['addTemplate'] = function(templateName, templateMarkup) {
  3.3573 -            document.write("<script type='text/html' id='" + templateName + "'>" + templateMarkup + "</script>");
  3.3574 -        };
  3.3575 -
  3.3576 -        if (jQueryTmplVersion > 0) {
  3.3577 -            jQuery['tmpl']['tag']['ko_code'] = {
  3.3578 -                open: "__.push($1 || '');"
  3.3579 -            };
  3.3580 -            jQuery['tmpl']['tag']['ko_with'] = {
  3.3581 -                open: "with($1) {",
  3.3582 -                close: "} "
  3.3583 -            };
  3.3584 -        }
  3.3585 -    };
  3.3586 -
  3.3587 -    ko.jqueryTmplTemplateEngine.prototype = new ko.templateEngine();
  3.3588 -
  3.3589 -    // Use this one by default *only if jquery.tmpl is referenced*
  3.3590 -    var jqueryTmplTemplateEngineInstance = new ko.jqueryTmplTemplateEngine();
  3.3591 -    if (jqueryTmplTemplateEngineInstance.jQueryTmplVersion > 0)
  3.3592 -        ko.setTemplateEngine(jqueryTmplTemplateEngineInstance);
  3.3593 -
  3.3594 -    ko.exportSymbol('jqueryTmplTemplateEngine', ko.jqueryTmplTemplateEngine);
  3.3595 -})();
  3.3596 -});
  3.3597 -})(window,document,navigator,window["jQuery"]);
  3.3598 -})();
  3.3599 \ No newline at end of file
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/ko4j/src/main/resources/org/netbeans/html/ko4j/knockout-3.2.0.debug.js	Tue Aug 19 20:13:11 2014 +0200
     4.3 @@ -0,0 +1,5299 @@
     4.4 +/*!
     4.5 + * Knockout JavaScript library v3.2.0
     4.6 + * (c) Steven Sanderson - http://knockoutjs.com/
     4.7 + * License: MIT (http://www.opensource.org/licenses/mit-license.php)
     4.8 + */
     4.9 +
    4.10 +(function(){
    4.11 +var DEBUG=true;
    4.12 +(function(undefined){
    4.13 +    // (0, eval)('this') is a robust way of getting a reference to the global object
    4.14 +    // For details, see http://stackoverflow.com/questions/14119988/return-this-0-evalthis/14120023#14120023
    4.15 +    var window = this || (0, eval)('this'),
    4.16 +        document = window['document'],
    4.17 +        navigator = window['navigator'],
    4.18 +        jQueryInstance = window["jQuery"],
    4.19 +        JSON = window["JSON"];
    4.20 +(function(factory) {
    4.21 +    // Support three module loading scenarios
    4.22 +    if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') {
    4.23 +        // [1] CommonJS/Node.js
    4.24 +        var target = module['exports'] || exports; // module.exports is for Node.js
    4.25 +        factory(target, require);
    4.26 +    } else if (typeof define === 'function' && define['amd']) {
    4.27 +        // [2] AMD anonymous module
    4.28 +        define(['exports', 'require'], factory);
    4.29 +    } else {
    4.30 +        // [3] No module loader (plain <script> tag) - put directly in global namespace
    4.31 +        factory(window['ko'] = {});
    4.32 +    }
    4.33 +}(function(koExports, require){
    4.34 +// Internally, all KO objects are attached to koExports (even the non-exported ones whose names will be minified by the closure compiler).
    4.35 +// In the future, the following "ko" variable may be made distinct from "koExports" so that private objects are not externally reachable.
    4.36 +var ko = typeof koExports !== 'undefined' ? koExports : {};
    4.37 +// Google Closure Compiler helpers (used only to make the minified file smaller)
    4.38 +ko.exportSymbol = function(koPath, object) {
    4.39 +    var tokens = koPath.split(".");
    4.40 +
    4.41 +    // In the future, "ko" may become distinct from "koExports" (so that non-exported objects are not reachable)
    4.42 +    // At that point, "target" would be set to: (typeof koExports !== "undefined" ? koExports : ko)
    4.43 +    var target = ko;
    4.44 +
    4.45 +    for (var i = 0; i < tokens.length - 1; i++)
    4.46 +        target = target[tokens[i]];
    4.47 +    target[tokens[tokens.length - 1]] = object;
    4.48 +};
    4.49 +ko.exportProperty = function(owner, publicName, object) {
    4.50 +    owner[publicName] = object;
    4.51 +};
    4.52 +ko.version = "3.2.0";
    4.53 +
    4.54 +ko.exportSymbol('version', ko.version);
    4.55 +ko.utils = (function () {
    4.56 +    function objectForEach(obj, action) {
    4.57 +        for (var prop in obj) {
    4.58 +            if (obj.hasOwnProperty(prop)) {
    4.59 +                action(prop, obj[prop]);
    4.60 +            }
    4.61 +        }
    4.62 +    }
    4.63 +
    4.64 +    function extend(target, source) {
    4.65 +        if (source) {
    4.66 +            for(var prop in source) {
    4.67 +                if(source.hasOwnProperty(prop)) {
    4.68 +                    target[prop] = source[prop];
    4.69 +                }
    4.70 +            }
    4.71 +        }
    4.72 +        return target;
    4.73 +    }
    4.74 +
    4.75 +    function setPrototypeOf(obj, proto) {
    4.76 +        obj.__proto__ = proto;
    4.77 +        return obj;
    4.78 +    }
    4.79 +
    4.80 +    var canSetPrototype = ({ __proto__: [] } instanceof Array);
    4.81 +
    4.82 +    // Represent the known event types in a compact way, then at runtime transform it into a hash with event name as key (for fast lookup)
    4.83 +    var knownEvents = {}, knownEventTypesByEventName = {};
    4.84 +    var keyEventTypeName = (navigator && /Firefox\/2/i.test(navigator.userAgent)) ? 'KeyboardEvent' : 'UIEvents';
    4.85 +    knownEvents[keyEventTypeName] = ['keyup', 'keydown', 'keypress'];
    4.86 +    knownEvents['MouseEvents'] = ['click', 'dblclick', 'mousedown', 'mouseup', 'mousemove', 'mouseover', 'mouseout', 'mouseenter', 'mouseleave'];
    4.87 +    objectForEach(knownEvents, function(eventType, knownEventsForType) {
    4.88 +        if (knownEventsForType.length) {
    4.89 +            for (var i = 0, j = knownEventsForType.length; i < j; i++)
    4.90 +                knownEventTypesByEventName[knownEventsForType[i]] = eventType;
    4.91 +        }
    4.92 +    });
    4.93 +    var eventsThatMustBeRegisteredUsingAttachEvent = { 'propertychange': true }; // Workaround for an IE9 issue - https://github.com/SteveSanderson/knockout/issues/406
    4.94 +
    4.95 +    // Detect IE versions for bug workarounds (uses IE conditionals, not UA string, for robustness)
    4.96 +    // Note that, since IE 10 does not support conditional comments, the following logic only detects IE < 10.
    4.97 +    // Currently this is by design, since IE 10+ behaves correctly when treated as a standard browser.
    4.98 +    // If there is a future need to detect specific versions of IE10+, we will amend this.
    4.99 +    var ieVersion = document && (function() {
   4.100 +        var version = 3, div = document.createElement('div'), iElems = div.getElementsByTagName('i');
   4.101 +
   4.102 +        // Keep constructing conditional HTML blocks until we hit one that resolves to an empty fragment
   4.103 +        while (
   4.104 +            div.innerHTML = '<!--[if gt IE ' + (++version) + ']><i></i><![endif]-->',
   4.105 +            iElems[0]
   4.106 +        ) {}
   4.107 +        return version > 4 ? version : undefined;
   4.108 +    }());
   4.109 +    var isIe6 = ieVersion === 6,
   4.110 +        isIe7 = ieVersion === 7;
   4.111 +
   4.112 +    function isClickOnCheckableElement(element, eventType) {
   4.113 +        if ((ko.utils.tagNameLower(element) !== "input") || !element.type) return false;
   4.114 +        if (eventType.toLowerCase() != "click") return false;
   4.115 +        var inputType = element.type;
   4.116 +        return (inputType == "checkbox") || (inputType == "radio");
   4.117 +    }
   4.118 +
   4.119 +    return {
   4.120 +        fieldsIncludedWithJsonPost: ['authenticity_token', /^__RequestVerificationToken(_.*)?$/],
   4.121 +
   4.122 +        arrayForEach: function (array, action) {
   4.123 +            for (var i = 0, j = array.length; i < j; i++)
   4.124 +                action(array[i], i);
   4.125 +        },
   4.126 +
   4.127 +        arrayIndexOf: function (array, item) {
   4.128 +            if (typeof Array.prototype.indexOf == "function")
   4.129 +                return Array.prototype.indexOf.call(array, item);
   4.130 +            for (var i = 0, j = array.length; i < j; i++)
   4.131 +                if (array[i] === item)
   4.132 +                    return i;
   4.133 +            return -1;
   4.134 +        },
   4.135 +
   4.136 +        arrayFirst: function (array, predicate, predicateOwner) {
   4.137 +            for (var i = 0, j = array.length; i < j; i++)
   4.138 +                if (predicate.call(predicateOwner, array[i], i))
   4.139 +                    return array[i];
   4.140 +            return null;
   4.141 +        },
   4.142 +
   4.143 +        arrayRemoveItem: function (array, itemToRemove) {
   4.144 +            var index = ko.utils.arrayIndexOf(array, itemToRemove);
   4.145 +            if (index > 0) {
   4.146 +                array.splice(index, 1);
   4.147 +            }
   4.148 +            else if (index === 0) {
   4.149 +                array.shift();
   4.150 +            }
   4.151 +        },
   4.152 +
   4.153 +        arrayGetDistinctValues: function (array) {
   4.154 +            array = array || [];
   4.155 +            var result = [];
   4.156 +            for (var i = 0, j = array.length; i < j; i++) {
   4.157 +                if (ko.utils.arrayIndexOf(result, array[i]) < 0)
   4.158 +                    result.push(array[i]);
   4.159 +            }
   4.160 +            return result;
   4.161 +        },
   4.162 +
   4.163 +        arrayMap: function (array, mapping) {
   4.164 +            array = array || [];
   4.165 +            var result = [];
   4.166 +            for (var i = 0, j = array.length; i < j; i++)
   4.167 +                result.push(mapping(array[i], i));
   4.168 +            return result;
   4.169 +        },
   4.170 +
   4.171 +        arrayFilter: function (array, predicate) {
   4.172 +            array = array || [];
   4.173 +            var result = [];
   4.174 +            for (var i = 0, j = array.length; i < j; i++)
   4.175 +                if (predicate(array[i], i))
   4.176 +                    result.push(array[i]);
   4.177 +            return result;
   4.178 +        },
   4.179 +
   4.180 +        arrayPushAll: function (array, valuesToPush) {
   4.181 +            if (valuesToPush instanceof Array)
   4.182 +                array.push.apply(array, valuesToPush);
   4.183 +            else
   4.184 +                for (var i = 0, j = valuesToPush.length; i < j; i++)
   4.185 +                    array.push(valuesToPush[i]);
   4.186 +            return array;
   4.187 +        },
   4.188 +
   4.189 +        addOrRemoveItem: function(array, value, included) {
   4.190 +            var existingEntryIndex = ko.utils.arrayIndexOf(ko.utils.peekObservable(array), value);
   4.191 +            if (existingEntryIndex < 0) {
   4.192 +                if (included)
   4.193 +                    array.push(value);
   4.194 +            } else {
   4.195 +                if (!included)
   4.196 +                    array.splice(existingEntryIndex, 1);
   4.197 +            }
   4.198 +        },
   4.199 +
   4.200 +        canSetPrototype: canSetPrototype,
   4.201 +
   4.202 +        extend: extend,
   4.203 +
   4.204 +        setPrototypeOf: setPrototypeOf,
   4.205 +
   4.206 +        setPrototypeOfOrExtend: canSetPrototype ? setPrototypeOf : extend,
   4.207 +
   4.208 +        objectForEach: objectForEach,
   4.209 +
   4.210 +        objectMap: function(source, mapping) {
   4.211 +            if (!source)
   4.212 +                return source;
   4.213 +            var target = {};
   4.214 +            for (var prop in source) {
   4.215 +                if (source.hasOwnProperty(prop)) {
   4.216 +                    target[prop] = mapping(source[prop], prop, source);
   4.217 +                }
   4.218 +            }
   4.219 +            return target;
   4.220 +        },
   4.221 +
   4.222 +        emptyDomNode: function (domNode) {
   4.223 +            while (domNode.firstChild) {
   4.224 +                ko.removeNode(domNode.firstChild);
   4.225 +            }
   4.226 +        },
   4.227 +
   4.228 +        moveCleanedNodesToContainerElement: function(nodes) {
   4.229 +            // Ensure it's a real array, as we're about to reparent the nodes and
   4.230 +            // we don't want the underlying collection to change while we're doing that.
   4.231 +            var nodesArray = ko.utils.makeArray(nodes);
   4.232 +
   4.233 +            var container = document.createElement('div');
   4.234 +            for (var i = 0, j = nodesArray.length; i < j; i++) {
   4.235 +                container.appendChild(ko.cleanNode(nodesArray[i]));
   4.236 +            }
   4.237 +            return container;
   4.238 +        },
   4.239 +
   4.240 +        cloneNodes: function (nodesArray, shouldCleanNodes) {
   4.241 +            for (var i = 0, j = nodesArray.length, newNodesArray = []; i < j; i++) {
   4.242 +                var clonedNode = nodesArray[i].cloneNode(true);
   4.243 +                newNodesArray.push(shouldCleanNodes ? ko.cleanNode(clonedNode) : clonedNode);
   4.244 +            }
   4.245 +            return newNodesArray;
   4.246 +        },
   4.247 +
   4.248 +        setDomNodeChildren: function (domNode, childNodes) {
   4.249 +            ko.utils.emptyDomNode(domNode);
   4.250 +            if (childNodes) {
   4.251 +                for (var i = 0, j = childNodes.length; i < j; i++)
   4.252 +                    domNode.appendChild(childNodes[i]);
   4.253 +            }
   4.254 +        },
   4.255 +
   4.256 +        replaceDomNodes: function (nodeToReplaceOrNodeArray, newNodesArray) {
   4.257 +            var nodesToReplaceArray = nodeToReplaceOrNodeArray.nodeType ? [nodeToReplaceOrNodeArray] : nodeToReplaceOrNodeArray;
   4.258 +            if (nodesToReplaceArray.length > 0) {
   4.259 +                var insertionPoint = nodesToReplaceArray[0];
   4.260 +                var parent = insertionPoint.parentNode;
   4.261 +                for (var i = 0, j = newNodesArray.length; i < j; i++)
   4.262 +                    parent.insertBefore(newNodesArray[i], insertionPoint);
   4.263 +                for (var i = 0, j = nodesToReplaceArray.length; i < j; i++) {
   4.264 +                    ko.removeNode(nodesToReplaceArray[i]);
   4.265 +                }
   4.266 +            }
   4.267 +        },
   4.268 +
   4.269 +        fixUpContinuousNodeArray: function(continuousNodeArray, parentNode) {
   4.270 +            // Before acting on a set of nodes that were previously outputted by a template function, we have to reconcile
   4.271 +            // them against what is in the DOM right now. It may be that some of the nodes have already been removed, or that
   4.272 +            // new nodes might have been inserted in the middle, for example by a binding. Also, there may previously have been
   4.273 +            // leading comment nodes (created by rewritten string-based templates) that have since been removed during binding.
   4.274 +            // So, this function translates the old "map" output array into its best guess of the set of current DOM nodes.
   4.275 +            //
   4.276 +            // Rules:
   4.277 +            //   [A] Any leading nodes that have been removed should be ignored
   4.278 +            //       These most likely correspond to memoization nodes that were already removed during binding
   4.279 +            //       See https://github.com/SteveSanderson/knockout/pull/440
   4.280 +            //   [B] We want to output a continuous series of nodes. So, ignore any nodes that have already been removed,
   4.281 +            //       and include any nodes that have been inserted among the previous collection
   4.282 +
   4.283 +            if (continuousNodeArray.length) {
   4.284 +                // The parent node can be a virtual element; so get the real parent node
   4.285 +                parentNode = (parentNode.nodeType === 8 && parentNode.parentNode) || parentNode;
   4.286 +
   4.287 +                // Rule [A]
   4.288 +                while (continuousNodeArray.length && continuousNodeArray[0].parentNode !== parentNode)
   4.289 +                    continuousNodeArray.shift();
   4.290 +
   4.291 +                // Rule [B]
   4.292 +                if (continuousNodeArray.length > 1) {
   4.293 +                    var current = continuousNodeArray[0], last = continuousNodeArray[continuousNodeArray.length - 1];
   4.294 +                    // Replace with the actual new continuous node set
   4.295 +                    continuousNodeArray.length = 0;
   4.296 +                    while (current !== last) {
   4.297 +                        continuousNodeArray.push(current);
   4.298 +                        current = current.nextSibling;
   4.299 +                        if (!current) // Won't happen, except if the developer has manually removed some DOM elements (then we're in an undefined scenario)
   4.300 +                            return;
   4.301 +                    }
   4.302 +                    continuousNodeArray.push(last);
   4.303 +                }
   4.304 +            }
   4.305 +            return continuousNodeArray;
   4.306 +        },
   4.307 +
   4.308 +        setOptionNodeSelectionState: function (optionNode, isSelected) {
   4.309 +            // IE6 sometimes throws "unknown error" if you try to write to .selected directly, whereas Firefox struggles with setAttribute. Pick one based on browser.
   4.310 +            if (ieVersion < 7)
   4.311 +                optionNode.setAttribute("selected", isSelected);
   4.312 +            else
   4.313 +                optionNode.selected = isSelected;
   4.314 +        },
   4.315 +
   4.316 +        stringTrim: function (string) {
   4.317 +            return string === null || string === undefined ? '' :
   4.318 +                string.trim ?
   4.319 +                    string.trim() :
   4.320 +                    string.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g, '');
   4.321 +        },
   4.322 +
   4.323 +        stringStartsWith: function (string, startsWith) {
   4.324 +            string = string || "";
   4.325 +            if (startsWith.length > string.length)
   4.326 +                return false;
   4.327 +            return string.substring(0, startsWith.length) === startsWith;
   4.328 +        },
   4.329 +
   4.330 +        domNodeIsContainedBy: function (node, containedByNode) {
   4.331 +            if (node === containedByNode)
   4.332 +                return true;
   4.333 +            if (node.nodeType === 11)
   4.334 +                return false; // Fixes issue #1162 - can't use node.contains for document fragments on IE8
   4.335 +            if (containedByNode.contains)
   4.336 +                return containedByNode.contains(node.nodeType === 3 ? node.parentNode : node);
   4.337 +            if (containedByNode.compareDocumentPosition)
   4.338 +                return (containedByNode.compareDocumentPosition(node) & 16) == 16;
   4.339 +            while (node && node != containedByNode) {
   4.340 +                node = node.parentNode;
   4.341 +            }
   4.342 +            return !!node;
   4.343 +        },
   4.344 +
   4.345 +        domNodeIsAttachedToDocument: function (node) {
   4.346 +            return ko.utils.domNodeIsContainedBy(node, node.ownerDocument.documentElement);
   4.347 +        },
   4.348 +
   4.349 +        anyDomNodeIsAttachedToDocument: function(nodes) {
   4.350 +            return !!ko.utils.arrayFirst(nodes, ko.utils.domNodeIsAttachedToDocument);
   4.351 +        },
   4.352 +
   4.353 +        tagNameLower: function(element) {
   4.354 +            // For HTML elements, tagName will always be upper case; for XHTML elements, it'll be lower case.
   4.355 +            // Possible future optimization: If we know it's an element from an XHTML document (not HTML),
   4.356 +            // we don't need to do the .toLowerCase() as it will always be lower case anyway.
   4.357 +            return element && element.tagName && element.tagName.toLowerCase();
   4.358 +        },
   4.359 +
   4.360 +        registerEventHandler: function (element, eventType, handler) {
   4.361 +            var mustUseAttachEvent = ieVersion && eventsThatMustBeRegisteredUsingAttachEvent[eventType];
   4.362 +            if (!mustUseAttachEvent && jQueryInstance) {
   4.363 +                jQueryInstance(element)['bind'](eventType, handler);
   4.364 +            } else if (!mustUseAttachEvent && typeof element.addEventListener == "function")
   4.365 +                element.addEventListener(eventType, handler, false);
   4.366 +            else if (typeof element.attachEvent != "undefined") {
   4.367 +                var attachEventHandler = function (event) { handler.call(element, event); },
   4.368 +                    attachEventName = "on" + eventType;
   4.369 +                element.attachEvent(attachEventName, attachEventHandler);
   4.370 +
   4.371 +                // IE does not dispose attachEvent handlers automatically (unlike with addEventListener)
   4.372 +                // so to avoid leaks, we have to remove them manually. See bug #856
   4.373 +                ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
   4.374 +                    element.detachEvent(attachEventName, attachEventHandler);
   4.375 +                });
   4.376 +            } else
   4.377 +                throw new Error("Browser doesn't support addEventListener or attachEvent");
   4.378 +        },
   4.379 +
   4.380 +        triggerEvent: function (element, eventType) {
   4.381 +            if (!(element && element.nodeType))
   4.382 +                throw new Error("element must be a DOM node when calling triggerEvent");
   4.383 +
   4.384 +            // For click events on checkboxes and radio buttons, jQuery toggles the element checked state *after* the
   4.385 +            // event handler runs instead of *before*. (This was fixed in 1.9 for checkboxes but not for radio buttons.)
   4.386 +            // IE doesn't change the checked state when you trigger the click event using "fireEvent".
   4.387 +            // In both cases, we'll use the click method instead.
   4.388 +            var useClickWorkaround = isClickOnCheckableElement(element, eventType);
   4.389 +
   4.390 +            if (jQueryInstance && !useClickWorkaround) {
   4.391 +                jQueryInstance(element)['trigger'](eventType);
   4.392 +            } else if (typeof document.createEvent == "function") {
   4.393 +                if (typeof element.dispatchEvent == "function") {
   4.394 +                    var eventCategory = knownEventTypesByEventName[eventType] || "HTMLEvents";
   4.395 +                    var event = document.createEvent(eventCategory);
   4.396 +                    event.initEvent(eventType, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, element);
   4.397 +                    element.dispatchEvent(event);
   4.398 +                }
   4.399 +                else
   4.400 +                    throw new Error("The supplied element doesn't support dispatchEvent");
   4.401 +            } else if (useClickWorkaround && element.click) {
   4.402 +                element.click();
   4.403 +            } else if (typeof element.fireEvent != "undefined") {
   4.404 +                element.fireEvent("on" + eventType);
   4.405 +            } else {
   4.406 +                throw new Error("Browser doesn't support triggering events");
   4.407 +            }
   4.408 +        },
   4.409 +
   4.410 +        unwrapObservable: function (value) {
   4.411 +            return ko.isObservable(value) ? value() : value;
   4.412 +        },
   4.413 +
   4.414 +        peekObservable: function (value) {
   4.415 +            return ko.isObservable(value) ? value.peek() : value;
   4.416 +        },
   4.417 +
   4.418 +        toggleDomNodeCssClass: function (node, classNames, shouldHaveClass) {
   4.419 +            if (classNames) {
   4.420 +                var cssClassNameRegex = /\S+/g,
   4.421 +                    currentClassNames = node.className.match(cssClassNameRegex) || [];
   4.422 +                ko.utils.arrayForEach(classNames.match(cssClassNameRegex), function(className) {
   4.423 +                    ko.utils.addOrRemoveItem(currentClassNames, className, shouldHaveClass);
   4.424 +                });
   4.425 +                node.className = currentClassNames.join(" ");
   4.426 +            }
   4.427 +        },
   4.428 +
   4.429 +        setTextContent: function(element, textContent) {
   4.430 +            var value = ko.utils.unwrapObservable(textContent);
   4.431 +            if ((value === null) || (value === undefined))
   4.432 +                value = "";
   4.433 +
   4.434 +            // We need there to be exactly one child: a text node.
   4.435 +            // If there are no children, more than one, or if it's not a text node,
   4.436 +            // we'll clear everything and create a single text node.
   4.437 +            var innerTextNode = ko.virtualElements.firstChild(element);
   4.438 +            if (!innerTextNode || innerTextNode.nodeType != 3 || ko.virtualElements.nextSibling(innerTextNode)) {
   4.439 +                ko.virtualElements.setDomNodeChildren(element, [element.ownerDocument.createTextNode(value)]);
   4.440 +            } else {
   4.441 +                innerTextNode.data = value;
   4.442 +            }
   4.443 +
   4.444 +            ko.utils.forceRefresh(element);
   4.445 +        },
   4.446 +
   4.447 +        setElementName: function(element, name) {
   4.448 +            element.name = name;
   4.449 +
   4.450 +            // Workaround IE 6/7 issue
   4.451 +            // - https://github.com/SteveSanderson/knockout/issues/197
   4.452 +            // - http://www.matts411.com/post/setting_the_name_attribute_in_ie_dom/
   4.453 +            if (ieVersion <= 7) {
   4.454 +                try {
   4.455 +                    element.mergeAttributes(document.createElement("<input name='" + element.name + "'/>"), false);
   4.456 +                }
   4.457 +                catch(e) {} // For IE9 with doc mode "IE9 Standards" and browser mode "IE9 Compatibility View"
   4.458 +            }
   4.459 +        },
   4.460 +
   4.461 +        forceRefresh: function(node) {
   4.462 +            // Workaround for an IE9 rendering bug - https://github.com/SteveSanderson/knockout/issues/209
   4.463 +            if (ieVersion >= 9) {
   4.464 +                // For text nodes and comment nodes (most likely virtual elements), we will have to refresh the container
   4.465 +                var elem = node.nodeType == 1 ? node : node.parentNode;
   4.466 +                if (elem.style)
   4.467 +                    elem.style.zoom = elem.style.zoom;
   4.468 +            }
   4.469 +        },
   4.470 +
   4.471 +        ensureSelectElementIsRenderedCorrectly: function(selectElement) {
   4.472 +            // Workaround for IE9 rendering bug - it doesn't reliably display all the text in dynamically-added select boxes unless you force it to re-render by updating the width.
   4.473 +            // (See https://github.com/SteveSanderson/knockout/issues/312, http://stackoverflow.com/questions/5908494/select-only-shows-first-char-of-selected-option)
   4.474 +            // Also fixes IE7 and IE8 bug that causes selects to be zero width if enclosed by 'if' or 'with'. (See issue #839)
   4.475 +            if (ieVersion) {
   4.476 +                var originalWidth = selectElement.style.width;
   4.477 +                selectElement.style.width = 0;
   4.478 +                selectElement.style.width = originalWidth;
   4.479 +            }
   4.480 +        },
   4.481 +
   4.482 +        range: function (min, max) {
   4.483 +            min = ko.utils.unwrapObservable(min);
   4.484 +            max = ko.utils.unwrapObservable(max);
   4.485 +            var result = [];
   4.486 +            for (var i = min; i <= max; i++)
   4.487 +                result.push(i);
   4.488 +            return result;
   4.489 +        },
   4.490 +
   4.491 +        makeArray: function(arrayLikeObject) {
   4.492 +            var result = [];
   4.493 +            for (var i = 0, j = arrayLikeObject.length; i < j; i++) {
   4.494 +                result.push(arrayLikeObject[i]);
   4.495 +            };
   4.496 +            return result;
   4.497 +        },
   4.498 +
   4.499 +        isIe6 : isIe6,
   4.500 +        isIe7 : isIe7,
   4.501 +        ieVersion : ieVersion,
   4.502 +
   4.503 +        getFormFields: function(form, fieldName) {
   4.504 +            var fields = ko.utils.makeArray(form.getElementsByTagName("input")).concat(ko.utils.makeArray(form.getElementsByTagName("textarea")));
   4.505 +            var isMatchingField = (typeof fieldName == 'string')
   4.506 +                ? function(field) { return field.name === fieldName }
   4.507 +                : function(field) { return fieldName.test(field.name) }; // Treat fieldName as regex or object containing predicate
   4.508 +            var matches = [];
   4.509 +            for (var i = fields.length - 1; i >= 0; i--) {
   4.510 +                if (isMatchingField(fields[i]))
   4.511 +                    matches.push(fields[i]);
   4.512 +            };
   4.513 +            return matches;
   4.514 +        },
   4.515 +
   4.516 +        parseJson: function (jsonString) {
   4.517 +            if (typeof jsonString == "string") {
   4.518 +                jsonString = ko.utils.stringTrim(jsonString);
   4.519 +                if (jsonString) {
   4.520 +                    if (JSON && JSON.parse) // Use native parsing where available
   4.521 +                        return JSON.parse(jsonString);
   4.522 +                    return (new Function("return " + jsonString))(); // Fallback on less safe parsing for older browsers
   4.523 +                }
   4.524 +            }
   4.525 +            return null;
   4.526 +        },
   4.527 +
   4.528 +        stringifyJson: function (data, replacer, space) {   // replacer and space are optional
   4.529 +            if (!JSON || !JSON.stringify)
   4.530 +                throw new Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");
   4.531 +            return JSON.stringify(ko.utils.unwrapObservable(data), replacer, space);
   4.532 +        },
   4.533 +
   4.534 +        postJson: function (urlOrForm, data, options) {
   4.535 +            options = options || {};
   4.536 +            var params = options['params'] || {};
   4.537 +            var includeFields = options['includeFields'] || this.fieldsIncludedWithJsonPost;
   4.538 +            var url = urlOrForm;
   4.539 +
   4.540 +            // If we were given a form, use its 'action' URL and pick out any requested field values
   4.541 +            if((typeof urlOrForm == 'object') && (ko.utils.tagNameLower(urlOrForm) === "form")) {
   4.542 +                var originalForm = urlOrForm;
   4.543 +                url = originalForm.action;
   4.544 +                for (var i = includeFields.length - 1; i >= 0; i--) {
   4.545 +                    var fields = ko.utils.getFormFields(originalForm, includeFields[i]);
   4.546 +                    for (var j = fields.length - 1; j >= 0; j--)
   4.547 +                        params[fields[j].name] = fields[j].value;
   4.548 +                }
   4.549 +            }
   4.550 +
   4.551 +            data = ko.utils.unwrapObservable(data);
   4.552 +            var form = document.createElement("form");
   4.553 +            form.style.display = "none";
   4.554 +            form.action = url;
   4.555 +            form.method = "post";
   4.556 +            for (var key in data) {
   4.557 +                // Since 'data' this is a model object, we include all properties including those inherited from its prototype
   4.558 +                var input = document.createElement("input");
   4.559 +                input.type = "hidden";
   4.560 +                input.name = key;
   4.561 +                input.value = ko.utils.stringifyJson(ko.utils.unwrapObservable(data[key]));
   4.562 +                form.appendChild(input);
   4.563 +            }
   4.564 +            objectForEach(params, function(key, value) {
   4.565 +                var input = document.createElement("input");
   4.566 +                input.type = "hidden";
   4.567 +                input.name = key;
   4.568 +                input.value = value;
   4.569 +                form.appendChild(input);
   4.570 +            });
   4.571 +            document.body.appendChild(form);
   4.572 +            options['submitter'] ? options['submitter'](form) : form.submit();
   4.573 +            setTimeout(function () { form.parentNode.removeChild(form); }, 0);
   4.574 +        }
   4.575 +    }
   4.576 +}());
   4.577 +
   4.578 +ko.exportSymbol('utils', ko.utils);
   4.579 +ko.exportSymbol('utils.arrayForEach', ko.utils.arrayForEach);
   4.580 +ko.exportSymbol('utils.arrayFirst', ko.utils.arrayFirst);
   4.581 +ko.exportSymbol('utils.arrayFilter', ko.utils.arrayFilter);
   4.582 +ko.exportSymbol('utils.arrayGetDistinctValues', ko.utils.arrayGetDistinctValues);
   4.583 +ko.exportSymbol('utils.arrayIndexOf', ko.utils.arrayIndexOf);
   4.584 +ko.exportSymbol('utils.arrayMap', ko.utils.arrayMap);
   4.585 +ko.exportSymbol('utils.arrayPushAll', ko.utils.arrayPushAll);
   4.586 +ko.exportSymbol('utils.arrayRemoveItem', ko.utils.arrayRemoveItem);
   4.587 +ko.exportSymbol('utils.extend', ko.utils.extend);
   4.588 +ko.exportSymbol('utils.fieldsIncludedWithJsonPost', ko.utils.fieldsIncludedWithJsonPost);
   4.589 +ko.exportSymbol('utils.getFormFields', ko.utils.getFormFields);
   4.590 +ko.exportSymbol('utils.peekObservable', ko.utils.peekObservable);
   4.591 +ko.exportSymbol('utils.postJson', ko.utils.postJson);
   4.592 +ko.exportSymbol('utils.parseJson', ko.utils.parseJson);
   4.593 +ko.exportSymbol('utils.registerEventHandler', ko.utils.registerEventHandler);
   4.594 +ko.exportSymbol('utils.stringifyJson', ko.utils.stringifyJson);
   4.595 +ko.exportSymbol('utils.range', ko.utils.range);
   4.596 +ko.exportSymbol('utils.toggleDomNodeCssClass', ko.utils.toggleDomNodeCssClass);
   4.597 +ko.exportSymbol('utils.triggerEvent', ko.utils.triggerEvent);
   4.598 +ko.exportSymbol('utils.unwrapObservable', ko.utils.unwrapObservable);
   4.599 +ko.exportSymbol('utils.objectForEach', ko.utils.objectForEach);
   4.600 +ko.exportSymbol('utils.addOrRemoveItem', ko.utils.addOrRemoveItem);
   4.601 +ko.exportSymbol('unwrap', ko.utils.unwrapObservable); // Convenient shorthand, because this is used so commonly
   4.602 +
   4.603 +if (!Function.prototype['bind']) {
   4.604 +    // Function.prototype.bind is a standard part of ECMAScript 5th Edition (December 2009, http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf)
   4.605 +    // In case the browser doesn't implement it natively, provide a JavaScript implementation. This implementation is based on the one in prototype.js
   4.606 +    Function.prototype['bind'] = function (object) {
   4.607 +        var originalFunction = this, args = Array.prototype.slice.call(arguments), object = args.shift();
   4.608 +        return function () {
   4.609 +            return originalFunction.apply(object, args.concat(Array.prototype.slice.call(arguments)));
   4.610 +        };
   4.611 +    };
   4.612 +}
   4.613 +
   4.614 +ko.utils.domData = new (function () {
   4.615 +    var uniqueId = 0;
   4.616 +    var dataStoreKeyExpandoPropertyName = "__ko__" + (new Date).getTime();
   4.617 +    var dataStore = {};
   4.618 +
   4.619 +    function getAll(node, createIfNotFound) {
   4.620 +        var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
   4.621 +        var hasExistingDataStore = dataStoreKey && (dataStoreKey !== "null") && dataStore[dataStoreKey];
   4.622 +        if (!hasExistingDataStore) {
   4.623 +            if (!createIfNotFound)
   4.624 +                return undefined;
   4.625 +            dataStoreKey = node[dataStoreKeyExpandoPropertyName] = "ko" + uniqueId++;
   4.626 +            dataStore[dataStoreKey] = {};
   4.627 +        }
   4.628 +        return dataStore[dataStoreKey];
   4.629 +    }
   4.630 +
   4.631 +    return {
   4.632 +        get: function (node, key) {
   4.633 +            var allDataForNode = getAll(node, false);
   4.634 +            return allDataForNode === undefined ? undefined : allDataForNode[key];
   4.635 +        },
   4.636 +        set: function (node, key, value) {
   4.637 +            if (value === undefined) {
   4.638 +                // Make sure we don't actually create a new domData key if we are actually deleting a value
   4.639 +                if (getAll(node, false) === undefined)
   4.640 +                    return;
   4.641 +            }
   4.642 +            var allDataForNode = getAll(node, true);
   4.643 +            allDataForNode[key] = value;
   4.644 +        },
   4.645 +        clear: function (node) {
   4.646 +            var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
   4.647 +            if (dataStoreKey) {
   4.648 +                delete dataStore[dataStoreKey];
   4.649 +                node[dataStoreKeyExpandoPropertyName] = null;
   4.650 +                return true; // Exposing "did clean" flag purely so specs can infer whether things have been cleaned up as intended
   4.651 +            }
   4.652 +            return false;
   4.653 +        },
   4.654 +
   4.655 +        nextKey: function () {
   4.656 +            return (uniqueId++) + dataStoreKeyExpandoPropertyName;
   4.657 +        }
   4.658 +    };
   4.659 +})();
   4.660 +
   4.661 +ko.exportSymbol('utils.domData', ko.utils.domData);
   4.662 +ko.exportSymbol('utils.domData.clear', ko.utils.domData.clear); // Exporting only so specs can clear up after themselves fully
   4.663 +
   4.664 +ko.utils.domNodeDisposal = new (function () {
   4.665 +    var domDataKey = ko.utils.domData.nextKey();
   4.666 +    var cleanableNodeTypes = { 1: true, 8: true, 9: true };       // Element, Comment, Document
   4.667 +    var cleanableNodeTypesWithDescendants = { 1: true, 9: true }; // Element, Document
   4.668 +
   4.669 +    function getDisposeCallbacksCollection(node, createIfNotFound) {
   4.670 +        var allDisposeCallbacks = ko.utils.domData.get(node, domDataKey);
   4.671 +        if ((allDisposeCallbacks === undefined) && createIfNotFound) {
   4.672 +            allDisposeCallbacks = [];
   4.673 +            ko.utils.domData.set(node, domDataKey, allDisposeCallbacks);
   4.674 +        }
   4.675 +        return allDisposeCallbacks;
   4.676 +    }
   4.677 +    function destroyCallbacksCollection(node) {
   4.678 +        ko.utils.domData.set(node, domDataKey, undefined);
   4.679 +    }
   4.680 +
   4.681 +    function cleanSingleNode(node) {
   4.682 +        // Run all the dispose callbacks
   4.683 +        var callbacks = getDisposeCallbacksCollection(node, false);
   4.684 +        if (callbacks) {
   4.685 +            callbacks = callbacks.slice(0); // Clone, as the array may be modified during iteration (typically, callbacks will remove themselves)
   4.686 +            for (var i = 0; i < callbacks.length; i++)
   4.687 +                callbacks[i](node);
   4.688 +        }
   4.689 +
   4.690 +        // Erase the DOM data
   4.691 +        ko.utils.domData.clear(node);
   4.692 +
   4.693 +        // Perform cleanup needed by external libraries (currently only jQuery, but can be extended)
   4.694 +        ko.utils.domNodeDisposal["cleanExternalData"](node);
   4.695 +
   4.696 +        // Clear any immediate-child comment nodes, as these wouldn't have been found by
   4.697 +        // node.getElementsByTagName("*") in cleanNode() (comment nodes aren't elements)
   4.698 +        if (cleanableNodeTypesWithDescendants[node.nodeType])
   4.699 +            cleanImmediateCommentTypeChildren(node);
   4.700 +    }
   4.701 +
   4.702 +    function cleanImmediateCommentTypeChildren(nodeWithChildren) {
   4.703 +        var child, nextChild = nodeWithChildren.firstChild;
   4.704 +        while (child = nextChild) {
   4.705 +            nextChild = child.nextSibling;
   4.706 +            if (child.nodeType === 8)
   4.707 +                cleanSingleNode(child);
   4.708 +        }
   4.709 +    }
   4.710 +
   4.711 +    return {
   4.712 +        addDisposeCallback : function(node, callback) {
   4.713 +            if (typeof callback != "function")
   4.714 +                throw new Error("Callback must be a function");
   4.715 +            getDisposeCallbacksCollection(node, true).push(callback);
   4.716 +        },
   4.717 +
   4.718 +        removeDisposeCallback : function(node, callback) {
   4.719 +            var callbacksCollection = getDisposeCallbacksCollection(node, false);
   4.720 +            if (callbacksCollection) {
   4.721 +                ko.utils.arrayRemoveItem(callbacksCollection, callback);
   4.722 +                if (callbacksCollection.length == 0)
   4.723 +                    destroyCallbacksCollection(node);
   4.724 +            }
   4.725 +        },
   4.726 +
   4.727 +        cleanNode : function(node) {
   4.728 +            // First clean this node, where applicable
   4.729 +            if (cleanableNodeTypes[node.nodeType]) {
   4.730 +                cleanSingleNode(node);
   4.731 +
   4.732 +                // ... then its descendants, where applicable
   4.733 +                if (cleanableNodeTypesWithDescendants[node.nodeType]) {
   4.734 +                    // Clone the descendants list in case it changes during iteration
   4.735 +                    var descendants = [];
   4.736 +                    ko.utils.arrayPushAll(descendants, node.getElementsByTagName("*"));
   4.737 +                    for (var i = 0, j = descendants.length; i < j; i++)
   4.738 +                        cleanSingleNode(descendants[i]);
   4.739 +                }
   4.740 +            }
   4.741 +            return node;
   4.742 +        },
   4.743 +
   4.744 +        removeNode : function(node) {
   4.745 +            ko.cleanNode(node);
   4.746 +            if (node.parentNode)
   4.747 +                node.parentNode.removeChild(node);
   4.748 +        },
   4.749 +
   4.750 +        "cleanExternalData" : function (node) {
   4.751 +            // Special support for jQuery here because it's so commonly used.
   4.752 +            // Many jQuery plugins (including jquery.tmpl) store data using jQuery's equivalent of domData
   4.753 +            // so notify it to tear down any resources associated with the node & descendants here.
   4.754 +            if (jQueryInstance && (typeof jQueryInstance['cleanData'] == "function"))
   4.755 +                jQueryInstance['cleanData']([node]);
   4.756 +        }
   4.757 +    }
   4.758 +})();
   4.759 +ko.cleanNode = ko.utils.domNodeDisposal.cleanNode; // Shorthand name for convenience
   4.760 +ko.removeNode = ko.utils.domNodeDisposal.removeNode; // Shorthand name for convenience
   4.761 +ko.exportSymbol('cleanNode', ko.cleanNode);
   4.762 +ko.exportSymbol('removeNode', ko.removeNode);
   4.763 +ko.exportSymbol('utils.domNodeDisposal', ko.utils.domNodeDisposal);
   4.764 +ko.exportSymbol('utils.domNodeDisposal.addDisposeCallback', ko.utils.domNodeDisposal.addDisposeCallback);
   4.765 +ko.exportSymbol('utils.domNodeDisposal.removeDisposeCallback', ko.utils.domNodeDisposal.removeDisposeCallback);
   4.766 +(function () {
   4.767 +    var leadingCommentRegex = /^(\s*)<!--(.*?)-->/;
   4.768 +
   4.769 +    function simpleHtmlParse(html) {
   4.770 +        // Based on jQuery's "clean" function, but only accounting for table-related elements.
   4.771 +        // If you have referenced jQuery, this won't be used anyway - KO will use jQuery's "clean" function directly
   4.772 +
   4.773 +        // Note that there's still an issue in IE < 9 whereby it will discard comment nodes that are the first child of
   4.774 +        // a descendant node. For example: "<div><!-- mycomment -->abc</div>" will get parsed as "<div>abc</div>"
   4.775 +        // This won't affect anyone who has referenced jQuery, and there's always the workaround of inserting a dummy node
   4.776 +        // (possibly a text node) in front of the comment. So, KO does not attempt to workaround this IE issue automatically at present.
   4.777 +
   4.778 +        // Trim whitespace, otherwise indexOf won't work as expected
   4.779 +        var tags = ko.utils.stringTrim(html).toLowerCase(), div = document.createElement("div");
   4.780 +
   4.781 +        // Finds the first match from the left column, and returns the corresponding "wrap" data from the right column
   4.782 +        var wrap = tags.match(/^<(thead|tbody|tfoot)/)              && [1, "<table>", "</table>"] ||
   4.783 +                   !tags.indexOf("<tr")                             && [2, "<table><tbody>", "</tbody></table>"] ||
   4.784 +                   (!tags.indexOf("<td") || !tags.indexOf("<th"))   && [3, "<table><tbody><tr>", "</tr></tbody></table>"] ||
   4.785 +                   /* anything else */                                 [0, "", ""];
   4.786 +
   4.787 +        // Go to html and back, then peel off extra wrappers
   4.788 +        // Note that we always prefix with some dummy text, because otherwise, IE<9 will strip out leading comment nodes in descendants. Total madness.
   4.789 +        var markup = "ignored<div>" + wrap[1] + html + wrap[2] + "</div>";
   4.790 +        if (typeof window['innerShiv'] == "function") {
   4.791 +            div.appendChild(window['innerShiv'](markup));
   4.792 +        } else {
   4.793 +            div.innerHTML = markup;
   4.794 +        }
   4.795 +
   4.796 +        // Move to the right depth
   4.797 +        while (wrap[0]--)
   4.798 +            div = div.lastChild;
   4.799 +
   4.800 +        return ko.utils.makeArray(div.lastChild.childNodes);
   4.801 +    }
   4.802 +
   4.803 +    function jQueryHtmlParse(html) {
   4.804 +        // jQuery's "parseHTML" function was introduced in jQuery 1.8.0 and is a documented public API.
   4.805 +        if (jQueryInstance['parseHTML']) {
   4.806 +            return jQueryInstance['parseHTML'](html) || []; // Ensure we always return an array and never null
   4.807 +        } else {
   4.808 +            // For jQuery < 1.8.0, we fall back on the undocumented internal "clean" function.
   4.809 +            var elems = jQueryInstance['clean']([html]);
   4.810 +
   4.811 +            // As of jQuery 1.7.1, jQuery parses the HTML by appending it to some dummy parent nodes held in an in-memory document fragment.
   4.812 +            // Unfortunately, it never clears the dummy parent nodes from the document fragment, so it leaks memory over time.
   4.813 +            // Fix this by finding the top-most dummy parent element, and detaching it from its owner fragment.
   4.814 +            if (elems && elems[0]) {
   4.815 +                // Find the top-most parent element that's a direct child of a document fragment
   4.816 +                var elem = elems[0];
   4.817 +                while (elem.parentNode && elem.parentNode.nodeType !== 11 /* i.e., DocumentFragment */)
   4.818 +                    elem = elem.parentNode;
   4.819 +                // ... then detach it
   4.820 +                if (elem.parentNode)
   4.821 +                    elem.parentNode.removeChild(elem);
   4.822 +            }
   4.823 +
   4.824 +            return elems;
   4.825 +        }
   4.826 +    }
   4.827 +
   4.828 +    ko.utils.parseHtmlFragment = function(html) {
   4.829 +        return jQueryInstance ? jQueryHtmlParse(html)   // As below, benefit from jQuery's optimisations where possible
   4.830 +                              : simpleHtmlParse(html);  // ... otherwise, this simple logic will do in most common cases.
   4.831 +    };
   4.832 +
   4.833 +    ko.utils.setHtml = function(node, html) {
   4.834 +        ko.utils.emptyDomNode(node);
   4.835 +
   4.836 +        // There's no legitimate reason to display a stringified observable without unwrapping it, so we'll unwrap it
   4.837 +        html = ko.utils.unwrapObservable(html);
   4.838 +
   4.839 +        if ((html !== null) && (html !== undefined)) {
   4.840 +            if (typeof html != 'string')
   4.841 +                html = html.toString();
   4.842 +
   4.843 +            // jQuery contains a lot of sophisticated code to parse arbitrary HTML fragments,
   4.844 +            // for example <tr> elements which are not normally allowed to exist on their own.
   4.845 +            // If you've referenced jQuery we'll use that rather than duplicating its code.
   4.846 +            if (jQueryInstance) {
   4.847 +                jQueryInstance(node)['html'](html);
   4.848 +            } else {
   4.849 +                // ... otherwise, use KO's own parsing logic.
   4.850 +                var parsedNodes = ko.utils.parseHtmlFragment(html);
   4.851 +                for (var i = 0; i < parsedNodes.length; i++)
   4.852 +                    node.appendChild(parsedNodes[i]);
   4.853 +            }
   4.854 +        }
   4.855 +    };
   4.856 +})();
   4.857 +
   4.858 +ko.exportSymbol('utils.parseHtmlFragment', ko.utils.parseHtmlFragment);
   4.859 +ko.exportSymbol('utils.setHtml', ko.utils.setHtml);
   4.860 +
   4.861 +ko.memoization = (function () {
   4.862 +    var memos = {};
   4.863 +
   4.864 +    function randomMax8HexChars() {
   4.865 +        return (((1 + Math.random()) * 0x100000000) | 0).toString(16).substring(1);
   4.866 +    }
   4.867 +    function generateRandomId() {
   4.868 +        return randomMax8HexChars() + randomMax8HexChars();
   4.869 +    }
   4.870 +    function findMemoNodes(rootNode, appendToArray) {
   4.871 +        if (!rootNode)
   4.872 +            return;
   4.873 +        if (rootNode.nodeType == 8) {
   4.874 +            var memoId = ko.memoization.parseMemoText(rootNode.nodeValue);
   4.875 +            if (memoId != null)
   4.876 +                appendToArray.push({ domNode: rootNode, memoId: memoId });
   4.877 +        } else if (rootNode.nodeType == 1) {
   4.878 +            for (var i = 0, childNodes = rootNode.childNodes, j = childNodes.length; i < j; i++)
   4.879 +                findMemoNodes(childNodes[i], appendToArray);
   4.880 +        }
   4.881 +    }
   4.882 +
   4.883 +    return {
   4.884 +        memoize: function (callback) {
   4.885 +            if (typeof callback != "function")
   4.886 +                throw new Error("You can only pass a function to ko.memoization.memoize()");
   4.887 +            var memoId = generateRandomId();
   4.888 +            memos[memoId] = callback;
   4.889 +            return "<!--[ko_memo:" + memoId + "]-->";
   4.890 +        },
   4.891 +
   4.892 +        unmemoize: function (memoId, callbackParams) {
   4.893 +            var callback = memos[memoId];
   4.894 +            if (callback === undefined)
   4.895 +                throw new Error("Couldn't find any memo with ID " + memoId + ". Perhaps it's already been unmemoized.");
   4.896 +            try {
   4.897 +                callback.apply(null, callbackParams || []);
   4.898 +                return true;
   4.899 +            }
   4.900 +            finally { delete memos[memoId]; }
   4.901 +        },
   4.902 +
   4.903 +        unmemoizeDomNodeAndDescendants: function (domNode, extraCallbackParamsArray) {
   4.904 +            var memos = [];
   4.905 +            findMemoNodes(domNode, memos);
   4.906 +            for (var i = 0, j = memos.length; i < j; i++) {
   4.907 +                var node = memos[i].domNode;
   4.908 +                var combinedParams = [node];
   4.909 +                if (extraCallbackParamsArray)
   4.910 +                    ko.utils.arrayPushAll(combinedParams, extraCallbackParamsArray);
   4.911 +                ko.memoization.unmemoize(memos[i].memoId, combinedParams);
   4.912 +                node.nodeValue = ""; // Neuter this node so we don't try to unmemoize it again
   4.913 +                if (node.parentNode)
   4.914 +                    node.parentNode.removeChild(node); // If possible, erase it totally (not always possible - someone else might just hold a reference to it then call unmemoizeDomNodeAndDescendants again)
   4.915 +            }
   4.916 +        },
   4.917 +
   4.918 +        parseMemoText: function (memoText) {
   4.919 +            var match = memoText.match(/^\[ko_memo\:(.*?)\]$/);
   4.920 +            return match ? match[1] : null;
   4.921 +        }
   4.922 +    };
   4.923 +})();
   4.924 +
   4.925 +ko.exportSymbol('memoization', ko.memoization);
   4.926 +ko.exportSymbol('memoization.memoize', ko.memoization.memoize);
   4.927 +ko.exportSymbol('memoization.unmemoize', ko.memoization.unmemoize);
   4.928 +ko.exportSymbol('memoization.parseMemoText', ko.memoization.parseMemoText);
   4.929 +ko.exportSymbol('memoization.unmemoizeDomNodeAndDescendants', ko.memoization.unmemoizeDomNodeAndDescendants);
   4.930 +ko.extenders = {
   4.931 +    'throttle': function(target, timeout) {
   4.932 +        // Throttling means two things:
   4.933 +
   4.934 +        // (1) For dependent observables, we throttle *evaluations* so that, no matter how fast its dependencies
   4.935 +        //     notify updates, the target doesn't re-evaluate (and hence doesn't notify) faster than a certain rate
   4.936 +        target['throttleEvaluation'] = timeout;
   4.937 +
   4.938 +        // (2) For writable targets (observables, or writable dependent observables), we throttle *writes*
   4.939 +        //     so the target cannot change value synchronously or faster than a certain rate
   4.940 +        var writeTimeoutInstance = null;
   4.941 +        return ko.dependentObservable({
   4.942 +            'read': target,
   4.943 +            'write': function(value) {
   4.944 +                clearTimeout(writeTimeoutInstance);
   4.945 +                writeTimeoutInstance = setTimeout(function() {
   4.946 +                    target(value);
   4.947 +                }, timeout);
   4.948 +            }
   4.949 +        });
   4.950 +    },
   4.951 +
   4.952 +    'rateLimit': function(target, options) {
   4.953 +        var timeout, method, limitFunction;
   4.954 +
   4.955 +        if (typeof options == 'number') {
   4.956 +            timeout = options;
   4.957 +        } else {
   4.958 +            timeout = options['timeout'];
   4.959 +            method = options['method'];
   4.960 +        }
   4.961 +
   4.962 +        limitFunction = method == 'notifyWhenChangesStop' ?  debounce : throttle;
   4.963 +        target.limit(function(callback) {
   4.964 +            return limitFunction(callback, timeout);
   4.965 +        });
   4.966 +    },
   4.967 +
   4.968 +    'notify': function(target, notifyWhen) {
   4.969 +        target["equalityComparer"] = notifyWhen == "always" ?
   4.970 +            null :  // null equalityComparer means to always notify
   4.971 +            valuesArePrimitiveAndEqual;
   4.972 +    }
   4.973 +};
   4.974 +
   4.975 +var primitiveTypes = { 'undefined':1, 'boolean':1, 'number':1, 'string':1 };
   4.976 +function valuesArePrimitiveAndEqual(a, b) {
   4.977 +    var oldValueIsPrimitive = (a === null) || (typeof(a) in primitiveTypes);
   4.978 +    return oldValueIsPrimitive ? (a === b) : false;
   4.979 +}
   4.980 +
   4.981 +function throttle(callback, timeout) {
   4.982 +    var timeoutInstance;
   4.983 +    return function () {
   4.984 +        if (!timeoutInstance) {
   4.985 +            timeoutInstance = setTimeout(function() {
   4.986 +                timeoutInstance = undefined;
   4.987 +                callback();
   4.988 +            }, timeout);
   4.989 +        }
   4.990 +    };
   4.991 +}
   4.992 +
   4.993 +function debounce(callback, timeout) {
   4.994 +    var timeoutInstance;
   4.995 +    return function () {
   4.996 +        clearTimeout(timeoutInstance);
   4.997 +        timeoutInstance = setTimeout(callback, timeout);
   4.998 +    };
   4.999 +}
  4.1000 +
  4.1001 +function applyExtenders(requestedExtenders) {
  4.1002 +    var target = this;
  4.1003 +    if (requestedExtenders) {
  4.1004 +        ko.utils.objectForEach(requestedExtenders, function(key, value) {
  4.1005 +            var extenderHandler = ko.extenders[key];
  4.1006 +            if (typeof extenderHandler == 'function') {
  4.1007 +                target = extenderHandler(target, value) || target;
  4.1008 +            }
  4.1009 +        });
  4.1010 +    }
  4.1011 +    return target;
  4.1012 +}
  4.1013 +
  4.1014 +ko.exportSymbol('extenders', ko.extenders);
  4.1015 +
  4.1016 +ko.subscription = function (target, callback, disposeCallback) {
  4.1017 +    this.target = target;
  4.1018 +    this.callback = callback;
  4.1019 +    this.disposeCallback = disposeCallback;
  4.1020 +    this.isDisposed = false;
  4.1021 +    ko.exportProperty(this, 'dispose', this.dispose);
  4.1022 +};
  4.1023 +ko.subscription.prototype.dispose = function () {
  4.1024 +    this.isDisposed = true;
  4.1025 +    this.disposeCallback();
  4.1026 +};
  4.1027 +
  4.1028 +ko.subscribable = function () {
  4.1029 +    ko.utils.setPrototypeOfOrExtend(this, ko.subscribable['fn']);
  4.1030 +    this._subscriptions = {};
  4.1031 +}
  4.1032 +
  4.1033 +var defaultEvent = "change";
  4.1034 +
  4.1035 +var ko_subscribable_fn = {
  4.1036 +    subscribe: function (callback, callbackTarget, event) {
  4.1037 +        var self = this;
  4.1038 +
  4.1039 +        event = event || defaultEvent;
  4.1040 +        var boundCallback = callbackTarget ? callback.bind(callbackTarget) : callback;
  4.1041 +
  4.1042 +        var subscription = new ko.subscription(self, boundCallback, function () {
  4.1043 +            ko.utils.arrayRemoveItem(self._subscriptions[event], subscription);
  4.1044 +            if (self.afterSubscriptionRemove)
  4.1045 +                self.afterSubscriptionRemove(event);
  4.1046 +        });
  4.1047 +
  4.1048 +        if (self.beforeSubscriptionAdd)
  4.1049 +            self.beforeSubscriptionAdd(event);
  4.1050 +
  4.1051 +        if (!self._subscriptions[event])
  4.1052 +            self._subscriptions[event] = [];
  4.1053 +        self._subscriptions[event].push(subscription);
  4.1054 +
  4.1055 +        return subscription;
  4.1056 +    },
  4.1057 +
  4.1058 +    "notifySubscribers": function (valueToNotify, event) {
  4.1059 +        event = event || defaultEvent;
  4.1060 +        if (this.hasSubscriptionsForEvent(event)) {
  4.1061 +            try {
  4.1062 +                ko.dependencyDetection.begin(); // Begin suppressing dependency detection (by setting the top frame to undefined)
  4.1063 +                for (var a = this._subscriptions[event].slice(0), i = 0, subscription; subscription = a[i]; ++i) {
  4.1064 +                    // In case a subscription was disposed during the arrayForEach cycle, check
  4.1065 +                    // for isDisposed on each subscription before invoking its callback
  4.1066 +                    if (!subscription.isDisposed)
  4.1067 +                        subscription.callback(valueToNotify);
  4.1068 +                }
  4.1069 +            } finally {
  4.1070 +                ko.dependencyDetection.end(); // End suppressing dependency detection
  4.1071 +            }
  4.1072 +        }
  4.1073 +    },
  4.1074 +
  4.1075 +    limit: function(limitFunction) {
  4.1076 +        var self = this, selfIsObservable = ko.isObservable(self),
  4.1077 +            isPending, previousValue, pendingValue, beforeChange = 'beforeChange';
  4.1078 +
  4.1079 +        if (!self._origNotifySubscribers) {
  4.1080 +            self._origNotifySubscribers = self["notifySubscribers"];
  4.1081 +            self["notifySubscribers"] = function(value, event) {
  4.1082 +                if (!event || event === defaultEvent) {
  4.1083 +                    self._rateLimitedChange(value);
  4.1084 +                } else if (event === beforeChange) {
  4.1085 +                    self._rateLimitedBeforeChange(value);
  4.1086 +                } else {
  4.1087 +                    self._origNotifySubscribers(value, event);
  4.1088 +                }
  4.1089 +            };
  4.1090 +        }
  4.1091 +
  4.1092 +        var finish = limitFunction(function() {
  4.1093 +            // If an observable provided a reference to itself, access it to get the latest value.
  4.1094 +            // This allows computed observables to delay calculating their value until needed.
  4.1095 +            if (selfIsObservable && pendingValue === self) {
  4.1096 +                pendingValue = self();
  4.1097 +            }
  4.1098 +            isPending = false;
  4.1099 +            if (self.isDifferent(previousValue, pendingValue)) {
  4.1100 +                self._origNotifySubscribers(previousValue = pendingValue);
  4.1101 +            }
  4.1102 +        });
  4.1103 +
  4.1104 +        self._rateLimitedChange = function(value) {
  4.1105 +            isPending = true;
  4.1106 +            pendingValue = value;
  4.1107 +            finish();
  4.1108 +        };
  4.1109 +        self._rateLimitedBeforeChange = function(value) {
  4.1110 +            if (!isPending) {
  4.1111 +                previousValue = value;
  4.1112 +                self._origNotifySubscribers(value, beforeChange);
  4.1113 +            }
  4.1114 +        };
  4.1115 +    },
  4.1116 +
  4.1117 +    hasSubscriptionsForEvent: function(event) {
  4.1118 +        return this._subscriptions[event] && this._subscriptions[event].length;
  4.1119 +    },
  4.1120 +
  4.1121 +    getSubscriptionsCount: function () {
  4.1122 +        var total = 0;
  4.1123 +        ko.utils.objectForEach(this._subscriptions, function(eventName, subscriptions) {
  4.1124 +            total += subscriptions.length;
  4.1125 +        });
  4.1126 +        return total;
  4.1127 +    },
  4.1128 +
  4.1129 +    isDifferent: function(oldValue, newValue) {
  4.1130 +        return !this['equalityComparer'] || !this['equalityComparer'](oldValue, newValue);
  4.1131 +    },
  4.1132 +
  4.1133 +    extend: applyExtenders
  4.1134 +};
  4.1135 +
  4.1136 +ko.exportProperty(ko_subscribable_fn, 'subscribe', ko_subscribable_fn.subscribe);
  4.1137 +ko.exportProperty(ko_subscribable_fn, 'extend', ko_subscribable_fn.extend);
  4.1138 +ko.exportProperty(ko_subscribable_fn, 'getSubscriptionsCount', ko_subscribable_fn.getSubscriptionsCount);
  4.1139 +
  4.1140 +// For browsers that support proto assignment, we overwrite the prototype of each
  4.1141 +// observable instance. Since observables are functions, we need Function.prototype
  4.1142 +// to still be in the prototype chain.
  4.1143 +if (ko.utils.canSetPrototype) {
  4.1144 +    ko.utils.setPrototypeOf(ko_subscribable_fn, Function.prototype);
  4.1145 +}
  4.1146 +
  4.1147 +ko.subscribable['fn'] = ko_subscribable_fn;
  4.1148 +
  4.1149 +
  4.1150 +ko.isSubscribable = function (instance) {
  4.1151 +    return instance != null && typeof instance.subscribe == "function" && typeof instance["notifySubscribers"] == "function";
  4.1152 +};
  4.1153 +
  4.1154 +ko.exportSymbol('subscribable', ko.subscribable);
  4.1155 +ko.exportSymbol('isSubscribable', ko.isSubscribable);
  4.1156 +
  4.1157 +ko.computedContext = ko.dependencyDetection = (function () {
  4.1158 +    var outerFrames = [],
  4.1159 +        currentFrame,
  4.1160 +        lastId = 0;
  4.1161 +
  4.1162 +    // Return a unique ID that can be assigned to an observable for dependency tracking.
  4.1163 +    // Theoretically, you could eventually overflow the number storage size, resulting
  4.1164 +    // in duplicate IDs. But in JavaScript, the largest exact integral value is 2^53
  4.1165 +    // or 9,007,199,254,740,992. If you created 1,000,000 IDs per second, it would
  4.1166 +    // take over 285 years to reach that number.
  4.1167 +    // Reference http://blog.vjeux.com/2010/javascript/javascript-max_int-number-limits.html
  4.1168 +    function getId() {
  4.1169 +        return ++lastId;
  4.1170 +    }
  4.1171 +
  4.1172 +    function begin(options) {
  4.1173 +        outerFrames.push(currentFrame);
  4.1174 +        currentFrame = options;
  4.1175 +    }
  4.1176 +
  4.1177 +    function end() {
  4.1178 +        currentFrame = outerFrames.pop();
  4.1179 +    }
  4.1180 +
  4.1181 +    return {
  4.1182 +        begin: begin,
  4.1183 +
  4.1184 +        end: end,
  4.1185 +
  4.1186 +        registerDependency: function (subscribable) {
  4.1187 +            if (currentFrame) {
  4.1188 +                if (!ko.isSubscribable(subscribable))
  4.1189 +                    throw new Error("Only subscribable things can act as dependencies");
  4.1190 +                currentFrame.callback(subscribable, subscribable._id || (subscribable._id = getId()));
  4.1191 +            }
  4.1192 +        },
  4.1193 +
  4.1194 +        ignore: function (callback, callbackTarget, callbackArgs) {
  4.1195 +            try {
  4.1196 +                begin();
  4.1197 +                return callback.apply(callbackTarget, callbackArgs || []);
  4.1198 +            } finally {
  4.1199 +                end();
  4.1200 +            }
  4.1201 +        },
  4.1202 +
  4.1203 +        getDependenciesCount: function () {
  4.1204 +            if (currentFrame)
  4.1205 +                return currentFrame.computed.getDependenciesCount();
  4.1206 +        },
  4.1207 +
  4.1208 +        isInitial: function() {
  4.1209 +            if (currentFrame)
  4.1210 +                return currentFrame.isInitial;
  4.1211 +        }
  4.1212 +    };
  4.1213 +})();
  4.1214 +
  4.1215 +ko.exportSymbol('computedContext', ko.computedContext);
  4.1216 +ko.exportSymbol('computedContext.getDependenciesCount', ko.computedContext.getDependenciesCount);
  4.1217 +ko.exportSymbol('computedContext.isInitial', ko.computedContext.isInitial);
  4.1218 +ko.exportSymbol('computedContext.isSleeping', ko.computedContext.isSleeping);
  4.1219 +ko.observable = function (initialValue) {
  4.1220 +    var _latestValue = initialValue;
  4.1221 +
  4.1222 +    function observable() {
  4.1223 +        if (arguments.length > 0) {
  4.1224 +            // Write
  4.1225 +
  4.1226 +            // Ignore writes if the value hasn't changed
  4.1227 +            if (observable.isDifferent(_latestValue, arguments[0])) {
  4.1228 +                observable.valueWillMutate();
  4.1229 +                _latestValue = arguments[0];
  4.1230 +                if (DEBUG) observable._latestValue = _latestValue;
  4.1231 +                observable.valueHasMutated();
  4.1232 +            }
  4.1233 +            return this; // Permits chained assignments
  4.1234 +        }
  4.1235 +        else {
  4.1236 +            // Read
  4.1237 +            ko.dependencyDetection.registerDependency(observable); // The caller only needs to be notified of changes if they did a "read" operation
  4.1238 +            return _latestValue;
  4.1239 +        }
  4.1240 +    }
  4.1241 +    ko.subscribable.call(observable);
  4.1242 +    ko.utils.setPrototypeOfOrExtend(observable, ko.observable['fn']);
  4.1243 +
  4.1244 +    if (DEBUG) observable._latestValue = _latestValue;
  4.1245 +    observable.peek = function() { return _latestValue };
  4.1246 +    observable.valueHasMutated = function () { observable["notifySubscribers"](_latestValue); }
  4.1247 +    observable.valueWillMutate = function () { observable["notifySubscribers"](_latestValue, "beforeChange"); }
  4.1248 +
  4.1249 +    ko.exportProperty(observable, 'peek', observable.peek);
  4.1250 +    ko.exportProperty(observable, "valueHasMutated", observable.valueHasMutated);
  4.1251 +    ko.exportProperty(observable, "valueWillMutate", observable.valueWillMutate);
  4.1252 +
  4.1253 +    return observable;
  4.1254 +}
  4.1255 +
  4.1256 +ko.observable['fn'] = {
  4.1257 +    "equalityComparer": valuesArePrimitiveAndEqual
  4.1258 +};
  4.1259 +
  4.1260 +var protoProperty = ko.observable.protoProperty = "__ko_proto__";
  4.1261 +ko.observable['fn'][protoProperty] = ko.observable;
  4.1262 +
  4.1263 +// Note that for browsers that don't support proto assignment, the
  4.1264 +// inheritance chain is created manually in the ko.observable constructor
  4.1265 +if (ko.utils.canSetPrototype) {
  4.1266 +    ko.utils.setPrototypeOf(ko.observable['fn'], ko.subscribable['fn']);
  4.1267 +}
  4.1268 +
  4.1269 +ko.hasPrototype = function(instance, prototype) {
  4.1270 +    if ((instance === null) || (instance === undefined) || (instance[protoProperty] === undefined)) return false;
  4.1271 +    if (instance[protoProperty] === prototype) return true;
  4.1272 +    return ko.hasPrototype(instance[protoProperty], prototype); // Walk the prototype chain
  4.1273 +};
  4.1274 +
  4.1275 +ko.isObservable = function (instance) {
  4.1276 +    return ko.hasPrototype(instance, ko.observable);
  4.1277 +}
  4.1278 +ko.isWriteableObservable = function (instance) {
  4.1279 +    // Observable
  4.1280 +    if ((typeof instance == "function") && instance[protoProperty] === ko.observable)
  4.1281 +        return true;
  4.1282 +    // Writeable dependent observable
  4.1283 +    if ((typeof instance == "function") && (instance[protoProperty] === ko.dependentObservable) && (instance.hasWriteFunction))
  4.1284 +        return true;
  4.1285 +    // Anything else
  4.1286 +    return false;
  4.1287 +}
  4.1288 +
  4.1289 +
  4.1290 +ko.exportSymbol('observable', ko.observable);
  4.1291 +ko.exportSymbol('isObservable', ko.isObservable);
  4.1292 +ko.exportSymbol('isWriteableObservable', ko.isWriteableObservable);
  4.1293 +ko.exportSymbol('isWritableObservable', ko.isWriteableObservable);
  4.1294 +ko.observableArray = function (initialValues) {
  4.1295 +    initialValues = initialValues || [];
  4.1296 +
  4.1297 +    if (typeof initialValues != 'object' || !('length' in initialValues))
  4.1298 +        throw new Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");
  4.1299 +
  4.1300 +    var result = ko.observable(initialValues);
  4.1301 +    ko.utils.setPrototypeOfOrExtend(result, ko.observableArray['fn']);
  4.1302 +    return result.extend({'trackArrayChanges':true});
  4.1303 +};
  4.1304 +
  4.1305 +ko.observableArray['fn'] = {
  4.1306 +    'remove': function (valueOrPredicate) {
  4.1307 +        var underlyingArray = this.peek();
  4.1308 +        var removedValues = [];
  4.1309 +        var predicate = typeof valueOrPredicate == "function" && !ko.isObservable(valueOrPredicate) ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
  4.1310 +        for (var i = 0; i < underlyingArray.length; i++) {
  4.1311 +            var value = underlyingArray[i];
  4.1312 +            if (predicate(value)) {
  4.1313 +                if (removedValues.length === 0) {
  4.1314 +                    this.valueWillMutate();
  4.1315 +                }
  4.1316 +                removedValues.push(value);
  4.1317 +                underlyingArray.splice(i, 1);
  4.1318 +                i--;
  4.1319 +            }
  4.1320 +        }
  4.1321 +        if (removedValues.length) {
  4.1322 +            this.valueHasMutated();
  4.1323 +        }
  4.1324 +        return removedValues;
  4.1325 +    },
  4.1326 +
  4.1327 +    'removeAll': function (arrayOfValues) {
  4.1328 +        // If you passed zero args, we remove everything
  4.1329 +        if (arrayOfValues === undefined) {
  4.1330 +            var underlyingArray = this.peek();
  4.1331 +            var allValues = underlyingArray.slice(0);
  4.1332 +            this.valueWillMutate();
  4.1333 +            underlyingArray.splice(0, underlyingArray.length);
  4.1334 +            this.valueHasMutated();
  4.1335 +            return allValues;
  4.1336 +        }
  4.1337 +        // If you passed an arg, we interpret it as an array of entries to remove
  4.1338 +        if (!arrayOfValues)
  4.1339 +            return [];
  4.1340 +        return this['remove'](function (value) {
  4.1341 +            return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
  4.1342 +        });
  4.1343 +    },
  4.1344 +
  4.1345 +    'destroy': function (valueOrPredicate) {
  4.1346 +        var underlyingArray = this.peek();
  4.1347 +        var predicate = typeof valueOrPredicate == "function" && !ko.isObservable(valueOrPredicate) ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
  4.1348 +        this.valueWillMutate();
  4.1349 +        for (var i = underlyingArray.length - 1; i >= 0; i--) {
  4.1350 +            var value = underlyingArray[i];
  4.1351 +            if (predicate(value))
  4.1352 +                underlyingArray[i]["_destroy"] = true;
  4.1353 +        }
  4.1354 +        this.valueHasMutated();
  4.1355 +    },
  4.1356 +
  4.1357 +    'destroyAll': function (arrayOfValues) {
  4.1358 +        // If you passed zero args, we destroy everything
  4.1359 +        if (arrayOfValues === undefined)
  4.1360 +            return this['destroy'](function() { return true });
  4.1361 +
  4.1362 +        // If you passed an arg, we interpret it as an array of entries to destroy
  4.1363 +        if (!arrayOfValues)
  4.1364 +            return [];
  4.1365 +        return this['destroy'](function (value) {
  4.1366 +            return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
  4.1367 +        });
  4.1368 +    },
  4.1369 +
  4.1370 +    'indexOf': function (item) {
  4.1371 +        var underlyingArray = this();
  4.1372 +        return ko.utils.arrayIndexOf(underlyingArray, item);
  4.1373 +    },
  4.1374 +
  4.1375 +    'replace': function(oldItem, newItem) {
  4.1376 +        var index = this['indexOf'](oldItem);
  4.1377 +        if (index >= 0) {
  4.1378 +            this.valueWillMutate();
  4.1379 +            this.peek()[index] = newItem;
  4.1380 +            this.valueHasMutated();
  4.1381 +        }
  4.1382 +    }
  4.1383 +};
  4.1384 +
  4.1385 +// Populate ko.observableArray.fn with read/write functions from native arrays
  4.1386 +// Important: Do not add any additional functions here that may reasonably be used to *read* data from the array
  4.1387 +// because we'll eval them without causing subscriptions, so ko.computed output could end up getting stale
  4.1388 +ko.utils.arrayForEach(["pop", "push", "reverse", "shift", "sort", "splice", "unshift"], function (methodName) {
  4.1389 +    ko.observableArray['fn'][methodName] = function () {
  4.1390 +        // Use "peek" to avoid creating a subscription in any computed that we're executing in the context of
  4.1391 +        // (for consistency with mutating regular observables)
  4.1392 +        var underlyingArray = this.peek();
  4.1393 +        this.valueWillMutate();
  4.1394 +        this.cacheDiffForKnownOperation(underlyingArray, methodName, arguments);
  4.1395 +        var methodCallResult = underlyingArray[methodName].apply(underlyingArray, arguments);
  4.1396 +        this.valueHasMutated();
  4.1397 +        return methodCallResult;
  4.1398 +    };
  4.1399 +});
  4.1400 +
  4.1401 +// Populate ko.observableArray.fn with read-only functions from native arrays
  4.1402 +ko.utils.arrayForEach(["slice"], function (methodName) {
  4.1403 +    ko.observableArray['fn'][methodName] = function () {
  4.1404 +        var underlyingArray = this();
  4.1405 +        return underlyingArray[methodName].apply(underlyingArray, arguments);
  4.1406 +    };
  4.1407 +});
  4.1408 +
  4.1409 +// Note that for browsers that don't support proto assignment, the
  4.1410 +// inheritance chain is created manually in the ko.observableArray constructor
  4.1411 +if (ko.utils.canSetPrototype) {
  4.1412 +    ko.utils.setPrototypeOf(ko.observableArray['fn'], ko.observable['fn']);
  4.1413 +}
  4.1414 +
  4.1415 +ko.exportSymbol('observableArray', ko.observableArray);
  4.1416 +var arrayChangeEventName = 'arrayChange';
  4.1417 +ko.extenders['trackArrayChanges'] = function(target) {
  4.1418 +    // Only modify the target observable once
  4.1419 +    if (target.cacheDiffForKnownOperation) {
  4.1420 +        return;
  4.1421 +    }
  4.1422 +    var trackingChanges = false,
  4.1423 +        cachedDiff = null,
  4.1424 +        pendingNotifications = 0,
  4.1425 +        underlyingSubscribeFunction = target.subscribe;
  4.1426 +
  4.1427 +    // Intercept "subscribe" calls, and for array change events, ensure change tracking is enabled
  4.1428 +    target.subscribe = target['subscribe'] = function(callback, callbackTarget, event) {
  4.1429 +        if (event === arrayChangeEventName) {
  4.1430 +            trackChanges();
  4.1431 +        }
  4.1432 +        return underlyingSubscribeFunction.apply(this, arguments);
  4.1433 +    };
  4.1434 +
  4.1435 +    function trackChanges() {
  4.1436 +        // Calling 'trackChanges' multiple times is the same as calling it once
  4.1437 +        if (trackingChanges) {
  4.1438 +            return;
  4.1439 +        }
  4.1440 +
  4.1441 +        trackingChanges = true;
  4.1442 +
  4.1443 +        // Intercept "notifySubscribers" to track how many times it was called.
  4.1444 +        var underlyingNotifySubscribersFunction = target['notifySubscribers'];
  4.1445 +        target['notifySubscribers'] = function(valueToNotify, event) {
  4.1446 +            if (!event || event === defaultEvent) {
  4.1447 +                ++pendingNotifications;
  4.1448 +            }
  4.1449 +            return underlyingNotifySubscribersFunction.apply(this, arguments);
  4.1450 +        };
  4.1451 +
  4.1452 +        // Each time the array changes value, capture a clone so that on the next
  4.1453 +        // change it's possible to produce a diff
  4.1454 +        var previousContents = [].concat(target.peek() || []);
  4.1455 +        cachedDiff = null;
  4.1456 +        target.subscribe(function(currentContents) {
  4.1457 +            // Make a copy of the current contents and ensure it's an array
  4.1458 +            currentContents = [].concat(currentContents || []);
  4.1459 +
  4.1460 +            // Compute the diff and issue notifications, but only if someone is listening
  4.1461 +            if (target.hasSubscriptionsForEvent(arrayChangeEventName)) {
  4.1462 +                var changes = getChanges(previousContents, currentContents);
  4.1463 +                if (changes.length) {
  4.1464 +                    target['notifySubscribers'](changes, arrayChangeEventName);
  4.1465 +                }
  4.1466 +            }
  4.1467 +
  4.1468 +            // Eliminate references to the old, removed items, so they can be GCed
  4.1469 +            previousContents = currentContents;
  4.1470 +            cachedDiff = null;
  4.1471 +            pendingNotifications = 0;
  4.1472 +        });
  4.1473 +    }
  4.1474 +
  4.1475 +    function getChanges(previousContents, currentContents) {
  4.1476 +        // We try to re-use cached diffs.
  4.1477 +        // The scenarios where pendingNotifications > 1 are when using rate-limiting or the Deferred Updates
  4.1478 +        // plugin, which without this check would not be compatible with arrayChange notifications. Normally,
  4.1479 +        // notifications are issued immediately so we wouldn't be queueing up more than one.
  4.1480 +        if (!cachedDiff || pendingNotifications > 1) {
  4.1481 +            cachedDiff = ko.utils.compareArrays(previousContents, currentContents, { 'sparse': true });
  4.1482 +        }
  4.1483 +
  4.1484 +        return cachedDiff;
  4.1485 +    }
  4.1486 +
  4.1487 +    target.cacheDiffForKnownOperation = function(rawArray, operationName, args) {
  4.1488 +        // Only run if we're currently tracking changes for this observable array
  4.1489 +        // and there aren't any pending deferred notifications.
  4.1490 +        if (!trackingChanges || pendingNotifications) {
  4.1491 +            return;
  4.1492 +        }
  4.1493 +        var diff = [],
  4.1494 +            arrayLength = rawArray.length,
  4.1495 +            argsLength = args.length,
  4.1496 +            offset = 0;
  4.1497 +
  4.1498 +        function pushDiff(status, value, index) {
  4.1499 +            return diff[diff.length] = { 'status': status, 'value': value, 'index': index };
  4.1500 +        }
  4.1501 +        switch (operationName) {
  4.1502 +            case 'push':
  4.1503 +                offset = arrayLength;
  4.1504 +            case 'unshift':
  4.1505 +                for (var index = 0; index < argsLength; index++) {
  4.1506 +                    pushDiff('added', args[index], offset + index);
  4.1507 +                }
  4.1508 +                break;
  4.1509 +
  4.1510 +            case 'pop':
  4.1511 +                offset = arrayLength - 1;
  4.1512 +            case 'shift':
  4.1513 +                if (arrayLength) {
  4.1514 +                    pushDiff('deleted', rawArray[offset], offset);
  4.1515 +                }
  4.1516 +                break;
  4.1517 +
  4.1518 +            case 'splice':
  4.1519 +                // Negative start index means 'from end of array'. After that we clamp to [0...arrayLength].
  4.1520 +                // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
  4.1521 +                var startIndex = Math.min(Math.max(0, args[0] < 0 ? arrayLength + args[0] : args[0]), arrayLength),
  4.1522 +                    endDeleteIndex = argsLength === 1 ? arrayLength : Math.min(startIndex + (args[1] || 0), arrayLength),
  4.1523 +                    endAddIndex = startIndex + argsLength - 2,
  4.1524 +                    endIndex = Math.max(endDeleteIndex, endAddIndex),
  4.1525 +                    additions = [], deletions = [];
  4.1526 +                for (var index = startIndex, argsIndex = 2; index < endIndex; ++index, ++argsIndex) {
  4.1527 +                    if (index < endDeleteIndex)
  4.1528 +                        deletions.push(pushDiff('deleted', rawArray[index], index));
  4.1529 +                    if (index < endAddIndex)
  4.1530 +                        additions.push(pushDiff('added', args[argsIndex], index));
  4.1531 +                }
  4.1532 +                ko.utils.findMovesInArrayComparison(deletions, additions);
  4.1533 +                break;
  4.1534 +
  4.1535 +            default:
  4.1536 +                return;
  4.1537 +        }
  4.1538 +        cachedDiff = diff;
  4.1539 +    };
  4.1540 +};
  4.1541 +ko.computed = ko.dependentObservable = function (evaluatorFunctionOrOptions, evaluatorFunctionTarget, options) {
  4.1542 +    var _latestValue,
  4.1543 +        _needsEvaluation = true,
  4.1544 +        _isBeingEvaluated = false,
  4.1545 +        _suppressDisposalUntilDisposeWhenReturnsFalse = false,
  4.1546 +        _isDisposed = false,
  4.1547 +        readFunction = evaluatorFunctionOrOptions,
  4.1548 +        pure = false,
  4.1549 +        isSleeping = false;
  4.1550 +
  4.1551 +    if (readFunction && typeof readFunction == "object") {
  4.1552 +        // Single-parameter syntax - everything is on this "options" param
  4.1553 +        options = readFunction;
  4.1554 +        readFunction = options["read"];
  4.1555 +    } else {
  4.1556 +        // Multi-parameter syntax - construct the options according to the params passed
  4.1557 +        options = options || {};
  4.1558 +        if (!readFunction)
  4.1559 +            readFunction = options["read"];
  4.1560 +    }
  4.1561 +    if (typeof readFunction != "function")
  4.1562 +        throw new Error("Pass a function that returns the value of the ko.computed");
  4.1563 +
  4.1564 +    function addSubscriptionToDependency(subscribable, id) {
  4.1565 +        if (!_subscriptionsToDependencies[id]) {
  4.1566 +            _subscriptionsToDependencies[id] = subscribable.subscribe(evaluatePossiblyAsync);
  4.1567 +            ++_dependenciesCount;
  4.1568 +        }
  4.1569 +    }
  4.1570 +
  4.1571 +    function disposeAllSubscriptionsToDependencies() {
  4.1572 +        ko.utils.objectForEach(_subscriptionsToDependencies, function (id, subscription) {
  4.1573 +            subscription.dispose();
  4.1574 +        });
  4.1575 +        _subscriptionsToDependencies = {};
  4.1576 +    }
  4.1577 +
  4.1578 +    function disposeComputed() {
  4.1579 +        disposeAllSubscriptionsToDependencies();
  4.1580 +        _dependenciesCount = 0;
  4.1581 +        _isDisposed = true;
  4.1582 +        _needsEvaluation = false;
  4.1583 +    }
  4.1584 +
  4.1585 +    function evaluatePossiblyAsync() {
  4.1586 +        var throttleEvaluationTimeout = dependentObservable['throttleEvaluation'];
  4.1587 +        if (throttleEvaluationTimeout && throttleEvaluationTimeout >= 0) {
  4.1588 +            clearTimeout(evaluationTimeoutInstance);
  4.1589 +            evaluationTimeoutInstance = setTimeout(evaluateImmediate, throttleEvaluationTimeout);
  4.1590 +        } else if (dependentObservable._evalRateLimited) {
  4.1591 +            dependentObservable._evalRateLimited();
  4.1592 +        } else {
  4.1593 +            evaluateImmediate();
  4.1594 +        }
  4.1595 +    }
  4.1596 +
  4.1597 +    function evaluateImmediate(suppressChangeNotification) {
  4.1598 +        if (_isBeingEvaluated) {
  4.1599 +            if (pure) {
  4.1600 +                throw Error("A 'pure' computed must not be called recursively");
  4.1601 +            }
  4.1602 +            // If the evaluation of a ko.computed causes side effects, it's possible that it will trigger its own re-evaluation.
  4.1603 +            // This is not desirable (it's hard for a developer to realise a chain of dependencies might cause this, and they almost
  4.1604 +            // certainly didn't intend infinite re-evaluations). So, for predictability, we simply prevent ko.computeds from causing
  4.1605 +            // their own re-evaluation. Further discussion at https://github.com/SteveSanderson/knockout/pull/387
  4.1606 +            return;
  4.1607 +        }
  4.1608 +
  4.1609 +        // Do not evaluate (and possibly capture new dependencies) if disposed
  4.1610 +        if (_isDisposed) {
  4.1611 +            return;
  4.1612 +        }
  4.1613 +
  4.1614 +        if (disposeWhen && disposeWhen()) {
  4.1615 +            // See comment below about _suppressDisposalUntilDisposeWhenReturnsFalse
  4.1616 +            if (!_suppressDisposalUntilDisposeWhenReturnsFalse) {
  4.1617 +                dispose();
  4.1618 +                return;
  4.1619 +            }
  4.1620 +        } else {
  4.1621 +            // It just did return false, so we can stop suppressing now
  4.1622 +            _suppressDisposalUntilDisposeWhenReturnsFalse = false;
  4.1623 +        }
  4.1624 +
  4.1625 +        _isBeingEvaluated = true;
  4.1626 +
  4.1627 +        // When sleeping, recalculate the value and return.
  4.1628 +        if (isSleeping) {
  4.1629 +            try {
  4.1630 +                var dependencyTracking = {};
  4.1631 +                ko.dependencyDetection.begin({
  4.1632 +                    callback: function (subscribable, id) {
  4.1633 +                        if (!dependencyTracking[id]) {
  4.1634 +                            dependencyTracking[id] = 1;
  4.1635 +                            ++_dependenciesCount;
  4.1636 +                        }
  4.1637 +                    },
  4.1638 +                    computed: dependentObservable,
  4.1639 +                    isInitial: undefined
  4.1640 +                });
  4.1641 +                _dependenciesCount = 0;
  4.1642 +                _latestValue = readFunction.call(evaluatorFunctionTarget);
  4.1643 +            } finally {
  4.1644 +                ko.dependencyDetection.end();
  4.1645 +                _isBeingEvaluated = false;
  4.1646 +            }
  4.1647 +        } else {
  4.1648 +            try {
  4.1649 +                // Initially, we assume that none of the subscriptions are still being used (i.e., all are candidates for disposal).
  4.1650 +                // Then, during evaluation, we cross off any that are in fact still being used.
  4.1651 +                var disposalCandidates = _subscriptionsToDependencies, disposalCount = _dependenciesCount;
  4.1652 +                ko.dependencyDetection.begin({
  4.1653 +                    callback: function(subscribable, id) {
  4.1654 +                        if (!_isDisposed) {
  4.1655 +                            if (disposalCount && disposalCandidates[id]) {
  4.1656 +                                // Don't want to dispose this subscription, as it's still being used
  4.1657 +                                _subscriptionsToDependencies[id] = disposalCandidates[id];
  4.1658 +                                ++_dependenciesCount;
  4.1659 +                                delete disposalCandidates[id];
  4.1660 +                                --disposalCount;
  4.1661 +                            } else {
  4.1662 +                                // Brand new subscription - add it
  4.1663 +                                addSubscriptionToDependency(subscribable, id);
  4.1664 +                            }
  4.1665 +                        }
  4.1666 +                    },
  4.1667 +                    computed: dependentObservable,
  4.1668 +                    isInitial: pure ? undefined : !_dependenciesCount        // If we're evaluating when there are no previous dependencies, it must be the first time
  4.1669 +                });
  4.1670 +
  4.1671 +                _subscriptionsToDependencies = {};
  4.1672 +                _dependenciesCount = 0;
  4.1673 +
  4.1674 +                try {
  4.1675 +                    var newValue = evaluatorFunctionTarget ? readFunction.call(evaluatorFunctionTarget) : readFunction();
  4.1676 +
  4.1677 +                } finally {
  4.1678 +                    ko.dependencyDetection.end();
  4.1679 +
  4.1680 +                    // For each subscription no longer being used, remove it from the active subscriptions list and dispose it
  4.1681 +                    if (disposalCount) {
  4.1682 +                        ko.utils.objectForEach(disposalCandidates, function(id, toDispose) {
  4.1683 +                            toDispose.dispose();
  4.1684 +                        });
  4.1685 +                    }
  4.1686 +
  4.1687 +                    _needsEvaluation = false;
  4.1688 +                }
  4.1689 +
  4.1690 +                if (dependentObservable.isDifferent(_latestValue, newValue)) {
  4.1691 +                    dependentObservable["notifySubscribers"](_latestValue, "beforeChange");
  4.1692 +
  4.1693 +                    _latestValue = newValue;
  4.1694 +                    if (DEBUG) dependentObservable._latestValue = _latestValue;
  4.1695 +
  4.1696 +                    if (suppressChangeNotification !== true) {  // Check for strict true value since setTimeout in Firefox passes a numeric value to the function
  4.1697 +                        dependentObservable["notifySubscribers"](_latestValue);
  4.1698 +                    }
  4.1699 +                }
  4.1700 +            } finally {
  4.1701 +                _isBeingEvaluated = false;
  4.1702 +            }
  4.1703 +        }
  4.1704 +
  4.1705 +        if (!_dependenciesCount)
  4.1706 +            dispose();
  4.1707 +    }
  4.1708 +
  4.1709 +    function dependentObservable() {
  4.1710 +        if (arguments.length > 0) {
  4.1711 +            if (typeof writeFunction === "function") {
  4.1712 +                // Writing a value
  4.1713 +                writeFunction.apply(evaluatorFunctionTarget, arguments);
  4.1714 +            } else {
  4.1715 +                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.");
  4.1716 +            }
  4.1717 +            return this; // Permits chained assignments
  4.1718 +        } else {
  4.1719 +            // Reading the value
  4.1720 +            ko.dependencyDetection.registerDependency(dependentObservable);
  4.1721 +            if (_needsEvaluation)
  4.1722 +                evaluateImmediate(true /* suppressChangeNotification */);
  4.1723 +            return _latestValue;
  4.1724 +        }
  4.1725 +    }
  4.1726 +
  4.1727 +    function peek() {
  4.1728 +        // Peek won't re-evaluate, except to get the initial value when "deferEvaluation" is set, or while the computed is sleeping.
  4.1729 +        // Those are the only times that both of these conditions will be satisfied.
  4.1730 +        if (_needsEvaluation && !_dependenciesCount)
  4.1731 +            evaluateImmediate(true /* suppressChangeNotification */);
  4.1732 +        return _latestValue;
  4.1733 +    }
  4.1734 +
  4.1735 +    function isActive() {
  4.1736 +        return _needsEvaluation || _dependenciesCount > 0;
  4.1737 +    }
  4.1738 +
  4.1739 +    // By here, "options" is always non-null
  4.1740 +    var writeFunction = options["write"],
  4.1741 +        disposeWhenNodeIsRemoved = options["disposeWhenNodeIsRemoved"] || options.disposeWhenNodeIsRemoved || null,
  4.1742 +        disposeWhenOption = options["disposeWhen"] || options.disposeWhen,
  4.1743 +        disposeWhen = disposeWhenOption,
  4.1744 +        dispose = disposeComputed,
  4.1745 +        _subscriptionsToDependencies = {},
  4.1746 +        _dependenciesCount = 0,
  4.1747 +        evaluationTimeoutInstance = null;
  4.1748 +
  4.1749 +    if (!evaluatorFunctionTarget)
  4.1750 +        evaluatorFunctionTarget = options["owner"];
  4.1751 +
  4.1752 +    ko.subscribable.call(dependentObservable);
  4.1753 +    ko.utils.setPrototypeOfOrExtend(dependentObservable, ko.dependentObservable['fn']);
  4.1754 +
  4.1755 +    dependentObservable.peek = peek;
  4.1756 +    dependentObservable.getDependenciesCount = function () { return _dependenciesCount; };
  4.1757 +    dependentObservable.hasWriteFunction = typeof options["write"] === "function";
  4.1758 +    dependentObservable.dispose = function () { dispose(); };
  4.1759 +    dependentObservable.isActive = isActive;
  4.1760 +
  4.1761 +    // Replace the limit function with one that delays evaluation as well.
  4.1762 +    var originalLimit = dependentObservable.limit;
  4.1763 +    dependentObservable.limit = function(limitFunction) {
  4.1764 +        originalLimit.call(dependentObservable, limitFunction);
  4.1765 +        dependentObservable._evalRateLimited = function() {
  4.1766 +            dependentObservable._rateLimitedBeforeChange(_latestValue);
  4.1767 +
  4.1768 +            _needsEvaluation = true;    // Mark as dirty
  4.1769 +
  4.1770 +            // Pass the observable to the rate-limit code, which will access it when
  4.1771 +            // it's time to do the notification.
  4.1772 +            dependentObservable._rateLimitedChange(dependentObservable);
  4.1773 +        }
  4.1774 +    };
  4.1775 +
  4.1776 +    if (options['pure']) {
  4.1777 +        pure = true;
  4.1778 +        isSleeping = true;     // Starts off sleeping; will awake on the first subscription
  4.1779 +        dependentObservable.beforeSubscriptionAdd = function () {
  4.1780 +            // If asleep, wake up the computed and evaluate to register any dependencies.
  4.1781 +            if (isSleeping) {
  4.1782 +                isSleeping = false;
  4.1783 +                evaluateImmediate(true /* suppressChangeNotification */);
  4.1784 +            }
  4.1785 +        }
  4.1786 +        dependentObservable.afterSubscriptionRemove = function () {
  4.1787 +            if (!dependentObservable.getSubscriptionsCount()) {
  4.1788 +                disposeAllSubscriptionsToDependencies();
  4.1789 +                isSleeping = _needsEvaluation = true;
  4.1790 +            }
  4.1791 +        }
  4.1792 +    } else if (options['deferEvaluation']) {
  4.1793 +        // This will force a computed with deferEvaluation to evaluate when the first subscriptions is registered.
  4.1794 +        dependentObservable.beforeSubscriptionAdd = function () {
  4.1795 +            peek();
  4.1796 +            delete dependentObservable.beforeSubscriptionAdd;
  4.1797 +        }
  4.1798 +    }
  4.1799 +
  4.1800 +    ko.exportProperty(dependentObservable, 'peek', dependentObservable.peek);
  4.1801 +    ko.exportProperty(dependentObservable, 'dispose', dependentObservable.dispose);
  4.1802 +    ko.exportProperty(dependentObservable, 'isActive', dependentObservable.isActive);
  4.1803 +    ko.exportProperty(dependentObservable, 'getDependenciesCount', dependentObservable.getDependenciesCount);
  4.1804 +
  4.1805 +    // Add a "disposeWhen" callback that, on each evaluation, disposes if the node was removed without using ko.removeNode.
  4.1806 +    if (disposeWhenNodeIsRemoved) {
  4.1807 +        // Since this computed is associated with a DOM node, and we don't want to dispose the computed
  4.1808 +        // until the DOM node is *removed* from the document (as opposed to never having been in the document),
  4.1809 +        // we'll prevent disposal until "disposeWhen" first returns false.
  4.1810 +        _suppressDisposalUntilDisposeWhenReturnsFalse = true;
  4.1811 +
  4.1812 +        // Only watch for the node's disposal if the value really is a node. It might not be,
  4.1813 +        // e.g., { disposeWhenNodeIsRemoved: true } can be used to opt into the "only dispose
  4.1814 +        // after first false result" behaviour even if there's no specific node to watch. This
  4.1815 +        // technique is intended for KO's internal use only and shouldn't be documented or used
  4.1816 +        // by application code, as it's likely to change in a future version of KO.
  4.1817 +        if (disposeWhenNodeIsRemoved.nodeType) {
  4.1818 +            disposeWhen = function () {
  4.1819 +                return !ko.utils.domNodeIsAttachedToDocument(disposeWhenNodeIsRemoved) || (disposeWhenOption && disposeWhenOption());
  4.1820 +            };
  4.1821 +        }
  4.1822 +    }
  4.1823 +
  4.1824 +    // Evaluate, unless sleeping or deferEvaluation is true
  4.1825 +    if (!isSleeping && !options['deferEvaluation'])
  4.1826 +        evaluateImmediate();
  4.1827 +
  4.1828 +    // Attach a DOM node disposal callback so that the computed will be proactively disposed as soon as the node is
  4.1829 +    // removed using ko.removeNode. But skip if isActive is false (there will never be any dependencies to dispose).
  4.1830 +    if (disposeWhenNodeIsRemoved && isActive() && disposeWhenNodeIsRemoved.nodeType) {
  4.1831 +        dispose = function() {
  4.1832 +            ko.utils.domNodeDisposal.removeDisposeCallback(disposeWhenNodeIsRemoved, dispose);
  4.1833 +            disposeComputed();
  4.1834 +        };
  4.1835 +        ko.utils.domNodeDisposal.addDisposeCallback(disposeWhenNodeIsRemoved, dispose);
  4.1836 +    }
  4.1837 +
  4.1838 +    return dependentObservable;
  4.1839 +};
  4.1840 +
  4.1841 +ko.isComputed = function(instance) {
  4.1842 +    return ko.hasPrototype(instance, ko.dependentObservable);
  4.1843 +};
  4.1844 +
  4.1845 +var protoProp = ko.observable.protoProperty; // == "__ko_proto__"
  4.1846 +ko.dependentObservable[protoProp] = ko.observable;
  4.1847 +
  4.1848 +ko.dependentObservable['fn'] = {
  4.1849 +    "equalityComparer": valuesArePrimitiveAndEqual
  4.1850 +};
  4.1851 +ko.dependentObservable['fn'][protoProp] = ko.dependentObservable;
  4.1852 +
  4.1853 +// Note that for browsers that don't support proto assignment, the
  4.1854 +// inheritance chain is created manually in the ko.dependentObservable constructor
  4.1855 +if (ko.utils.canSetPrototype) {
  4.1856 +    ko.utils.setPrototypeOf(ko.dependentObservable['fn'], ko.subscribable['fn']);
  4.1857 +}
  4.1858 +
  4.1859 +ko.exportSymbol('dependentObservable', ko.dependentObservable);
  4.1860 +ko.exportSymbol('computed', ko.dependentObservable); // Make "ko.computed" an alias for "ko.dependentObservable"
  4.1861 +ko.exportSymbol('isComputed', ko.isComputed);
  4.1862 +
  4.1863 +ko.pureComputed = function (evaluatorFunctionOrOptions, evaluatorFunctionTarget) {
  4.1864 +    if (typeof evaluatorFunctionOrOptions === 'function') {
  4.1865 +        return ko.computed(evaluatorFunctionOrOptions, evaluatorFunctionTarget, {'pure':true});
  4.1866 +    } else {
  4.1867 +        evaluatorFunctionOrOptions = ko.utils.extend({}, evaluatorFunctionOrOptions);   // make a copy of the parameter object
  4.1868 +        evaluatorFunctionOrOptions['pure'] = true;
  4.1869 +        return ko.computed(evaluatorFunctionOrOptions, evaluatorFunctionTarget);
  4.1870 +    }
  4.1871 +}
  4.1872 +ko.exportSymbol('pureComputed', ko.pureComputed);
  4.1873 +
  4.1874 +(function() {
  4.1875 +    var maxNestedObservableDepth = 10; // Escape the (unlikely) pathalogical case where an observable's current value is itself (or similar reference cycle)
  4.1876 +
  4.1877 +    ko.toJS = function(rootObject) {
  4.1878 +        if (arguments.length == 0)
  4.1879 +            throw new Error("When calling ko.toJS, pass the object you want to convert.");
  4.1880 +
  4.1881 +        // We just unwrap everything at every level in the object graph
  4.1882 +        return mapJsObjectGraph(rootObject, function(valueToMap) {
  4.1883 +            // Loop because an observable's value might in turn be another observable wrapper
  4.1884 +            for (var i = 0; ko.isObservable(valueToMap) && (i < maxNestedObservableDepth); i++)
  4.1885 +                valueToMap = valueToMap();
  4.1886 +            return valueToMap;
  4.1887 +        });
  4.1888 +    };
  4.1889 +
  4.1890 +    ko.toJSON = function(rootObject, replacer, space) {     // replacer and space are optional
  4.1891 +        var plainJavaScriptObject = ko.toJS(rootObject);
  4.1892 +        return ko.utils.stringifyJson(plainJavaScriptObject, replacer, space);
  4.1893 +    };
  4.1894 +
  4.1895 +    function mapJsObjectGraph(rootObject, mapInputCallback, visitedObjects) {
  4.1896 +        visitedObjects = visitedObjects || new objectLookup();
  4.1897 +
  4.1898 +        rootObject = mapInputCallback(rootObject);
  4.1899 +        var canHaveProperties = (typeof rootObject == "object") && (rootObject !== null) && (rootObject !== undefined) && (!(rootObject instanceof Date)) && (!(rootObject instanceof String)) && (!(rootObject instanceof Number)) && (!(rootObject instanceof Boolean));
  4.1900 +        if (!canHaveProperties)
  4.1901 +            return rootObject;
  4.1902 +
  4.1903 +        var outputProperties = rootObject instanceof Array ? [] : {};
  4.1904 +        visitedObjects.save(rootObject, outputProperties);
  4.1905 +
  4.1906 +        visitPropertiesOrArrayEntries(rootObject, function(indexer) {
  4.1907 +            var propertyValue = mapInputCallback(rootObject[indexer]);
  4.1908 +
  4.1909 +            switch (typeof propertyValue) {
  4.1910 +                case "boolean":
  4.1911 +                case "number":
  4.1912 +                case "string":
  4.1913 +                case "function":
  4.1914 +                    outputProperties[indexer] = propertyValue;
  4.1915 +                    break;
  4.1916 +                case "object":
  4.1917 +                case "undefined":
  4.1918 +                    var previouslyMappedValue = visitedObjects.get(propertyValue);
  4.1919 +                    outputProperties[indexer] = (previouslyMappedValue !== undefined)
  4.1920 +                        ? previouslyMappedValue
  4.1921 +                        : mapJsObjectGraph(propertyValue, mapInputCallback, visitedObjects);
  4.1922 +                    break;
  4.1923 +            }
  4.1924 +        });
  4.1925 +
  4.1926 +        return outputProperties;
  4.1927 +    }
  4.1928 +
  4.1929 +    function visitPropertiesOrArrayEntries(rootObject, visitorCallback) {
  4.1930 +        if (rootObject instanceof Array) {
  4.1931 +            for (var i = 0; i < rootObject.length; i++)
  4.1932 +                visitorCallback(i);
  4.1933 +
  4.1934 +            // For arrays, also respect toJSON property for custom mappings (fixes #278)
  4.1935 +            if (typeof rootObject['toJSON'] == 'function')
  4.1936 +                visitorCallback('toJSON');
  4.1937 +        } else {
  4.1938 +            for (var propertyName in rootObject) {
  4.1939 +                visitorCallback(propertyName);
  4.1940 +            }
  4.1941 +        }
  4.1942 +    };
  4.1943 +
  4.1944 +    function objectLookup() {
  4.1945 +        this.keys = [];
  4.1946 +        this.values = [];
  4.1947 +    };
  4.1948 +
  4.1949 +    objectLookup.prototype = {
  4.1950 +        constructor: objectLookup,
  4.1951 +        save: function(key, value) {
  4.1952 +            var existingIndex = ko.utils.arrayIndexOf(this.keys, key);
  4.1953 +            if (existingIndex >= 0)
  4.1954 +                this.values[existingIndex] = value;
  4.1955 +            else {
  4.1956 +                this.keys.push(key);
  4.1957 +                this.values.push(value);
  4.1958 +            }
  4.1959 +        },
  4.1960 +        get: function(key) {
  4.1961 +            var existingIndex = ko.utils.arrayIndexOf(this.keys, key);
  4.1962 +            return (existingIndex >= 0) ? this.values[existingIndex] : undefined;
  4.1963 +        }
  4.1964 +    };
  4.1965 +})();
  4.1966 +
  4.1967 +ko.exportSymbol('toJS', ko.toJS);
  4.1968 +ko.exportSymbol('toJSON', ko.toJSON);
  4.1969 +(function () {
  4.1970 +    var hasDomDataExpandoProperty = '__ko__hasDomDataOptionValue__';
  4.1971 +
  4.1972 +    // Normally, SELECT elements and their OPTIONs can only take value of type 'string' (because the values
  4.1973 +    // are stored on DOM attributes). ko.selectExtensions provides a way for SELECTs/OPTIONs to have values
  4.1974 +    // that are arbitrary objects. This is very convenient when implementing things like cascading dropdowns.
  4.1975 +    ko.selectExtensions = {
  4.1976 +        readValue : function(element) {
  4.1977 +            switch (ko.utils.tagNameLower(element)) {
  4.1978 +                case 'option':
  4.1979 +                    if (element[hasDomDataExpandoProperty] === true)
  4.1980 +                        return ko.utils.domData.get(element, ko.bindingHandlers.options.optionValueDomDataKey);
  4.1981 +                    return ko.utils.ieVersion <= 7
  4.1982 +                        ? (element.getAttributeNode('value') && element.getAttributeNode('value').specified ? element.value : element.text)
  4.1983 +                        : element.value;
  4.1984 +                case 'select':
  4.1985 +                    return element.selectedIndex >= 0 ? ko.selectExtensions.readValue(element.options[element.selectedIndex]) : undefined;
  4.1986 +                default:
  4.1987 +                    return element.value;
  4.1988 +            }
  4.1989 +        },
  4.1990 +
  4.1991 +        writeValue: function(element, value, allowUnset) {
  4.1992 +            switch (ko.utils.tagNameLower(element)) {
  4.1993 +                case 'option':
  4.1994 +                    switch(typeof value) {
  4.1995 +                        case "string":
  4.1996 +                            ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, undefined);
  4.1997 +                            if (hasDomDataExpandoProperty in element) { // IE <= 8 throws errors if you delete non-existent properties from a DOM node
  4.1998 +                                delete element[hasDomDataExpandoProperty];
  4.1999 +                            }
  4.2000 +                            element.value = value;
  4.2001 +                            break;
  4.2002 +                        default:
  4.2003 +                            // Store arbitrary object using DomData
  4.2004 +                            ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, value);
  4.2005 +                            element[hasDomDataExpandoProperty] = true;
  4.2006 +
  4.2007 +                            // Special treatment of numbers is just for backward compatibility. KO 1.2.1 wrote numerical values to element.value.
  4.2008 +                            element.value = typeof value === "number" ? value : "";
  4.2009 +                            break;
  4.2010 +                    }
  4.2011 +                    break;
  4.2012 +                case 'select':
  4.2013 +                    if (value === "" || value === null)       // A blank string or null value will select the caption
  4.2014 +                        value = undefined;
  4.2015 +                    var selection = -1;
  4.2016 +                    for (var i = 0, n = element.options.length, optionValue; i < n; ++i) {
  4.2017 +                        optionValue = ko.selectExtensions.readValue(element.options[i]);
  4.2018 +                        // Include special check to handle selecting a caption with a blank string value
  4.2019 +                        if (optionValue == value || (optionValue == "" && value === undefined)) {
  4.2020 +                            selection = i;
  4.2021 +                            break;
  4.2022 +                        }
  4.2023 +                    }
  4.2024 +                    if (allowUnset || selection >= 0 || (value === undefined && element.size > 1)) {
  4.2025 +                        element.selectedIndex = selection;
  4.2026 +                    }
  4.2027 +                    break;
  4.2028 +                default:
  4.2029 +                    if ((value === null) || (value === undefined))
  4.2030 +                        value = "";
  4.2031 +                    element.value = value;
  4.2032 +                    break;
  4.2033 +            }
  4.2034 +        }
  4.2035 +    };
  4.2036 +})();
  4.2037 +
  4.2038 +ko.exportSymbol('selectExtensions', ko.selectExtensions);
  4.2039 +ko.exportSymbol('selectExtensions.readValue', ko.selectExtensions.readValue);
  4.2040 +ko.exportSymbol('selectExtensions.writeValue', ko.selectExtensions.writeValue);
  4.2041 +ko.expressionRewriting = (function () {
  4.2042 +    var javaScriptReservedWords = ["true", "false", "null", "undefined"];
  4.2043 +
  4.2044 +    // Matches something that can be assigned to--either an isolated identifier or something ending with a property accessor
  4.2045 +    // This is designed to be simple and avoid false negatives, but could produce false positives (e.g., a+b.c).
  4.2046 +    // This also will not properly handle nested brackets (e.g., obj1[obj2['prop']]; see #911).
  4.2047 +    var javaScriptAssignmentTarget = /^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i;
  4.2048 +
  4.2049 +    function getWriteableValue(expression) {
  4.2050 +        if (ko.utils.arrayIndexOf(javaScriptReservedWords, expression) >= 0)
  4.2051 +            return false;
  4.2052 +        var match = expression.match(javaScriptAssignmentTarget);
  4.2053 +        return match === null ? false : match[1] ? ('Object(' + match[1] + ')' + match[2]) : expression;
  4.2054 +    }
  4.2055 +
  4.2056 +    // The following regular expressions will be used to split an object-literal string into tokens
  4.2057 +
  4.2058 +        // These two match strings, either with double quotes or single quotes
  4.2059 +    var stringDouble = '"(?:[^"\\\\]|\\\\.)*"',
  4.2060 +        stringSingle = "'(?:[^'\\\\]|\\\\.)*'",
  4.2061 +        // Matches a regular expression (text enclosed by slashes), but will also match sets of divisions
  4.2062 +        // as a regular expression (this is handled by the parsing loop below).
  4.2063 +        stringRegexp = '/(?:[^/\\\\]|\\\\.)*/\w*',
  4.2064 +        // These characters have special meaning to the parser and must not appear in the middle of a
  4.2065 +        // token, except as part of a string.
  4.2066 +        specials = ',"\'{}()/:[\\]',
  4.2067 +        // Match text (at least two characters) that does not contain any of the above special characters,
  4.2068 +        // although some of the special characters are allowed to start it (all but the colon and comma).
  4.2069 +        // The text can contain spaces, but leading or trailing spaces are skipped.
  4.2070 +        everyThingElse = '[^\\s:,/][^' + specials + ']*[^\\s' + specials + ']',
  4.2071 +        // Match any non-space character not matched already. This will match colons and commas, since they're
  4.2072 +        // not matched by "everyThingElse", but will also match any other single character that wasn't already
  4.2073 +        // matched (for example: in "a: 1, b: 2", each of the non-space characters will be matched by oneNotSpace).
  4.2074 +        oneNotSpace = '[^\\s]',
  4.2075 +
  4.2076 +        // Create the actual regular expression by or-ing the above strings. The order is important.
  4.2077 +        bindingToken = RegExp(stringDouble + '|' + stringSingle + '|' + stringRegexp + '|' + everyThingElse + '|' + oneNotSpace, 'g'),
  4.2078 +
  4.2079 +        // Match end of previous token to determine whether a slash is a division or regex.
  4.2080 +        divisionLookBehind = /[\])"'A-Za-z0-9_$]+$/,
  4.2081 +        keywordRegexLookBehind = {'in':1,'return':1,'typeof':1};
  4.2082 +
  4.2083 +    function parseObjectLiteral(objectLiteralString) {
  4.2084 +        // Trim leading and trailing spaces from the string
  4.2085 +        var str = ko.utils.stringTrim(objectLiteralString);
  4.2086 +
  4.2087 +        // Trim braces '{' surrounding the whole object literal
  4.2088 +        if (str.charCodeAt(0) === 123) str = str.slice(1, -1);
  4.2089 +
  4.2090 +        // Split into tokens
  4.2091 +        var result = [], toks = str.match(bindingToken), key, values, depth = 0;
  4.2092 +
  4.2093 +        if (toks) {
  4.2094 +            // Append a comma so that we don't need a separate code block to deal with the last item
  4.2095 +            toks.push(',');
  4.2096 +
  4.2097 +            for (var i = 0, tok; tok = toks[i]; ++i) {
  4.2098 +                var c = tok.charCodeAt(0);
  4.2099 +                // A comma signals the end of a key/value pair if depth is zero
  4.2100 +                if (c === 44) { // ","
  4.2101 +                    if (depth <= 0) {
  4.2102 +                        if (key)
  4.2103 +                            result.push(values ? {key: key, value: values.join('')} : {'unknown': key});
  4.2104 +                        key = values = depth = 0;
  4.2105 +                        continue;
  4.2106 +                    }
  4.2107 +                // Simply skip the colon that separates the name and value
  4.2108 +                } else if (c === 58) { // ":"
  4.2109 +                    if (!values)
  4.2110 +                        continue;
  4.2111 +                // A set of slashes is initially matched as a regular expression, but could be division
  4.2112 +                } else if (c === 47 && i && tok.length > 1) {  // "/"
  4.2113 +                    // Look at the end of the previous token to determine if the slash is actually division
  4.2114 +                    var match = toks[i-1].match(divisionLookBehind);
  4.2115 +                    if (match && !keywordRegexLookBehind[match[0]]) {
  4.2116 +                        // The slash is actually a division punctuator; re-parse the remainder of the string (not including the slash)
  4.2117 +                        str = str.substr(str.indexOf(tok) + 1);
  4.2118 +                        toks = str.match(bindingToken);
  4.2119 +                        toks.push(',');
  4.2120 +                        i = -1;
  4.2121 +                        // Continue with just the slash
  4.2122 +                        tok = '/';
  4.2123 +                    }
  4.2124 +                // Increment depth for parentheses, braces, and brackets so that interior commas are ignored
  4.2125 +                } else if (c === 40 || c === 123 || c === 91) { // '(', '{', '['
  4.2126 +                    ++depth;
  4.2127 +                } else if (c === 41 || c === 125 || c === 93) { // ')', '}', ']'
  4.2128 +                    --depth;
  4.2129 +                // The key must be a single token; if it's a string, trim the quotes
  4.2130 +                } else if (!key && !values) {
  4.2131 +                    key = (c === 34 || c === 39) /* '"', "'" */ ? tok.slice(1, -1) : tok;
  4.2132 +                    continue;
  4.2133 +                }
  4.2134 +                if (values)
  4.2135 +                    values.push(tok);
  4.2136 +                else
  4.2137 +                    values = [tok];
  4.2138 +            }
  4.2139 +        }
  4.2140 +        return result;
  4.2141 +    }
  4.2142 +
  4.2143 +    // Two-way bindings include a write function that allow the handler to update the value even if it's not an observable.
  4.2144 +    var twoWayBindings = {};
  4.2145 +
  4.2146 +    function preProcessBindings(bindingsStringOrKeyValueArray, bindingOptions) {
  4.2147 +        bindingOptions = bindingOptions || {};
  4.2148 +
  4.2149 +        function processKeyValue(key, val) {
  4.2150 +            var writableVal;
  4.2151 +            function callPreprocessHook(obj) {
  4.2152 +                return (obj && obj['preprocess']) ? (val = obj['preprocess'](val, key, processKeyValue)) : true;
  4.2153 +            }
  4.2154 +            if (!bindingParams) {
  4.2155 +                if (!callPreprocessHook(ko['getBindingHandler'](key)))
  4.2156 +                    return;
  4.2157 +
  4.2158 +                if (twoWayBindings[key] && (writableVal = getWriteableValue(val))) {
  4.2159 +                    // For two-way bindings, provide a write method in case the value
  4.2160 +                    // isn't a writable observable.
  4.2161 +                    propertyAccessorResultStrings.push("'" + key + "':function(_z){" + writableVal + "=_z}");
  4.2162 +                }
  4.2163 +            }
  4.2164 +            // Values are wrapped in a function so that each value can be accessed independently
  4.2165 +            if (makeValueAccessors) {
  4.2166 +                val = 'function(){return ' + val + ' }';
  4.2167 +            }
  4.2168 +            resultStrings.push("'" + key + "':" + val);
  4.2169 +        }
  4.2170 +
  4.2171 +        var resultStrings = [],
  4.2172 +            propertyAccessorResultStrings = [],
  4.2173 +            makeValueAccessors = bindingOptions['valueAccessors'],
  4.2174 +            bindingParams = bindingOptions['bindingParams'],
  4.2175 +            keyValueArray = typeof bindingsStringOrKeyValueArray === "string" ?
  4.2176 +                parseObjectLiteral(bindingsStringOrKeyValueArray) : bindingsStringOrKeyValueArray;
  4.2177 +
  4.2178 +        ko.utils.arrayForEach(keyValueArray, function(keyValue) {
  4.2179 +            processKeyValue(keyValue.key || keyValue['unknown'], keyValue.value);
  4.2180 +        });
  4.2181 +
  4.2182 +        if (propertyAccessorResultStrings.length)
  4.2183 +            processKeyValue('_ko_property_writers', "{" + propertyAccessorResultStrings.join(",") + " }");
  4.2184 +
  4.2185 +        return resultStrings.join(",");
  4.2186 +    }
  4.2187 +
  4.2188 +    return {
  4.2189 +        bindingRewriteValidators: [],
  4.2190 +
  4.2191 +        twoWayBindings: twoWayBindings,
  4.2192 +
  4.2193 +        parseObjectLiteral: parseObjectLiteral,
  4.2194 +
  4.2195 +        preProcessBindings: preProcessBindings,
  4.2196 +
  4.2197 +        keyValueArrayContainsKey: function(keyValueArray, key) {
  4.2198 +            for (var i = 0; i < keyValueArray.length; i++)
  4.2199 +                if (keyValueArray[i]['key'] == key)
  4.2200 +                    return true;
  4.2201 +            return false;
  4.2202 +        },
  4.2203 +
  4.2204 +        // Internal, private KO utility for updating model properties from within bindings
  4.2205 +        // property:            If the property being updated is (or might be) an observable, pass it here
  4.2206 +        //                      If it turns out to be a writable observable, it will be written to directly
  4.2207 +        // allBindings:         An object with a get method to retrieve bindings in the current execution context.
  4.2208 +        //                      This will be searched for a '_ko_property_writers' property in case you're writing to a non-observable
  4.2209 +        // key:                 The key identifying the property to be written. Example: for { hasFocus: myValue }, write to 'myValue' by specifying the key 'hasFocus'
  4.2210 +        // value:               The value to be written
  4.2211 +        // checkIfDifferent:    If true, and if the property being written is a writable observable, the value will only be written if
  4.2212 +        //                      it is !== existing value on that writable observable
  4.2213 +        writeValueToProperty: function(property, allBindings, key, value, checkIfDifferent) {
  4.2214 +            if (!property || !ko.isObservable(property)) {
  4.2215 +                var propWriters = allBindings.get('_ko_property_writers');
  4.2216 +                if (propWriters && propWriters[key])
  4.2217 +                    propWriters[key](value);
  4.2218 +            } else if (ko.isWriteableObservable(property) && (!checkIfDifferent || property.peek() !== value)) {
  4.2219 +                property(value);
  4.2220 +            }
  4.2221 +        }
  4.2222 +    };
  4.2223 +})();
  4.2224 +
  4.2225 +ko.exportSymbol('expressionRewriting', ko.expressionRewriting);
  4.2226 +ko.exportSymbol('expressionRewriting.bindingRewriteValidators', ko.expressionRewriting.bindingRewriteValidators);
  4.2227 +ko.exportSymbol('expressionRewriting.parseObjectLiteral', ko.expressionRewriting.parseObjectLiteral);
  4.2228 +ko.exportSymbol('expressionRewriting.preProcessBindings', ko.expressionRewriting.preProcessBindings);
  4.2229 +
  4.2230 +// Making bindings explicitly declare themselves as "two way" isn't ideal in the long term (it would be better if
  4.2231 +// all bindings could use an official 'property writer' API without needing to declare that they might). However,
  4.2232 +// since this is not, and has never been, a public API (_ko_property_writers was never documented), it's acceptable
  4.2233 +// as an internal implementation detail in the short term.
  4.2234 +// For those developers who rely on _ko_property_writers in their custom bindings, we expose _twoWayBindings as an
  4.2235 +// undocumented feature that makes it relatively easy to upgrade to KO 3.0. However, this is still not an official
  4.2236 +// public API, and we reserve the right to remove it at any time if we create a real public property writers API.
  4.2237 +ko.exportSymbol('expressionRewriting._twoWayBindings', ko.expressionRewriting.twoWayBindings);
  4.2238 +
  4.2239 +// For backward compatibility, define the following aliases. (Previously, these function names were misleading because
  4.2240 +// they referred to JSON specifically, even though they actually work with arbitrary JavaScript object literal expressions.)
  4.2241 +ko.exportSymbol('jsonExpressionRewriting', ko.expressionRewriting);
  4.2242 +ko.exportSymbol('jsonExpressionRewriting.insertPropertyAccessorsIntoJson', ko.expressionRewriting.preProcessBindings);
  4.2243 +(function() {
  4.2244 +    // "Virtual elements" is an abstraction on top of the usual DOM API which understands the notion that comment nodes
  4.2245 +    // may be used to represent hierarchy (in addition to the DOM's natural hierarchy).
  4.2246 +    // If you call the DOM-manipulating functions on ko.virtualElements, you will be able to read and write the state
  4.2247 +    // of that virtual hierarchy
  4.2248 +    //
  4.2249 +    // The point of all this is to support containerless templates (e.g., <!-- ko foreach:someCollection -->blah<!-- /ko -->)
  4.2250 +    // without having to scatter special cases all over the binding and templating code.
  4.2251 +
  4.2252 +    // IE 9 cannot reliably read the "nodeValue" property of a comment node (see https://github.com/SteveSanderson/knockout/issues/186)
  4.2253 +    // but it does give them a nonstandard alternative property called "text" that it can read reliably. Other browsers don't have that property.
  4.2254 +    // So, use node.text where available, and node.nodeValue elsewhere
  4.2255 +    var commentNodesHaveTextProperty = document && document.createComment("test").text === "<!--test-->";
  4.2256 +
  4.2257 +    var startCommentRegex = commentNodesHaveTextProperty ? /^<!--\s*ko(?:\s+([\s\S]+))?\s*-->$/ : /^\s*ko(?:\s+([\s\S]+))?\s*$/;
  4.2258 +    var endCommentRegex =   commentNodesHaveTextProperty ? /^<!--\s*\/ko\s*-->$/ : /^\s*\/ko\s*$/;
  4.2259 +    var htmlTagsWithOptionallyClosingChildren = { 'ul': true, 'ol': true };
  4.2260 +
  4.2261 +    function isStartComment(node) {
  4.2262 +        return (node.nodeType == 8) && startCommentRegex.test(commentNodesHaveTextProperty ? node.text : node.nodeValue);
  4.2263 +    }
  4.2264 +
  4.2265 +    function isEndComment(node) {
  4.2266 +        return (node.nodeType == 8) && endCommentRegex.test(commentNodesHaveTextProperty ? node.text : node.nodeValue);
  4.2267 +    }
  4.2268 +
  4.2269 +    function getVirtualChildren(startComment, allowUnbalanced) {
  4.2270 +        var currentNode = startComment;
  4.2271 +        var depth = 1;
  4.2272 +        var children = [];
  4.2273 +        while (currentNode = currentNode.nextSibling) {
  4.2274 +            if (isEndComment(currentNode)) {
  4.2275 +                depth--;
  4.2276 +                if (depth === 0)
  4.2277 +                    return children;
  4.2278 +            }
  4.2279 +
  4.2280 +            children.push(currentNode);
  4.2281 +
  4.2282 +            if (isStartComment(currentNode))
  4.2283 +                depth++;
  4.2284 +        }
  4.2285 +        if (!allowUnbalanced)
  4.2286 +            throw new Error("Cannot find closing comment tag to match: " + startComment.nodeValue);
  4.2287 +        return null;
  4.2288 +    }
  4.2289 +
  4.2290 +    function getMatchingEndComment(startComment, allowUnbalanced) {
  4.2291 +        var allVirtualChildren = getVirtualChildren(startComment, allowUnbalanced);
  4.2292 +        if (allVirtualChildren) {
  4.2293 +            if (allVirtualChildren.length > 0)
  4.2294 +                return allVirtualChildren[allVirtualChildren.length - 1].nextSibling;
  4.2295 +            return startComment.nextSibling;
  4.2296 +        } else
  4.2297 +            return null; // Must have no matching end comment, and allowUnbalanced is true
  4.2298 +    }
  4.2299 +
  4.2300 +    function getUnbalancedChildTags(node) {
  4.2301 +        // e.g., from <div>OK</div><!-- ko blah --><span>Another</span>, returns: <!-- ko blah --><span>Another</span>
  4.2302 +        //       from <div>OK</div><!-- /ko --><!-- /ko -->,             returns: <!-- /ko --><!-- /ko -->
  4.2303 +        var childNode = node.firstChild, captureRemaining = null;
  4.2304 +        if (childNode) {
  4.2305 +            do {
  4.2306 +                if (captureRemaining)                   // We already hit an unbalanced node and are now just scooping up all subsequent nodes
  4.2307 +                    captureRemaining.push(childNode);
  4.2308 +                else if (isStartComment(childNode)) {
  4.2309 +                    var matchingEndComment = getMatchingEndComment(childNode, /* allowUnbalanced: */ true);
  4.2310 +                    if (matchingEndComment)             // It's a balanced tag, so skip immediately to the end of this virtual set
  4.2311 +                        childNode = matchingEndComment;
  4.2312 +                    else
  4.2313 +                        captureRemaining = [childNode]; // It's unbalanced, so start capturing from this point
  4.2314 +                } else if (isEndComment(childNode)) {
  4.2315 +                    captureRemaining = [childNode];     // It's unbalanced (if it wasn't, we'd have skipped over it already), so start capturing
  4.2316 +                }
  4.2317 +            } while (childNode = childNode.nextSibling);
  4.2318 +        }
  4.2319 +        return captureRemaining;
  4.2320 +    }
  4.2321 +
  4.2322 +    ko.virtualElements = {
  4.2323 +        allowedBindings: {},
  4.2324 +
  4.2325 +        childNodes: function(node) {
  4.2326 +            return isStartComment(node) ? getVirtualChildren(node) : node.childNodes;
  4.2327 +        },
  4.2328 +
  4.2329 +        emptyNode: function(node) {
  4.2330 +            if (!isStartComment(node))
  4.2331 +                ko.utils.emptyDomNode(node);
  4.2332 +            else {
  4.2333 +                var virtualChildren = ko.virtualElements.childNodes(node);
  4.2334 +                for (var i = 0, j = virtualChildren.length; i < j; i++)
  4.2335 +                    ko.removeNode(virtualChildren[i]);
  4.2336 +            }
  4.2337 +        },
  4.2338 +
  4.2339 +        setDomNodeChildren: function(node, childNodes) {
  4.2340 +            if (!isStartComment(node))
  4.2341 +                ko.utils.setDomNodeChildren(node, childNodes);
  4.2342 +            else {
  4.2343 +                ko.virtualElements.emptyNode(node);
  4.2344 +                var endCommentNode = node.nextSibling; // Must be the next sibling, as we just emptied the children
  4.2345 +                for (var i = 0, j = childNodes.length; i < j; i++)
  4.2346 +                    endCommentNode.parentNode.insertBefore(childNodes[i], endCommentNode);
  4.2347 +            }
  4.2348 +        },
  4.2349 +
  4.2350 +        prepend: function(containerNode, nodeToPrepend) {
  4.2351 +            if (!isStartComment(containerNode)) {
  4.2352 +                if (containerNode.firstChild)
  4.2353 +                    containerNode.insertBefore(nodeToPrepend, containerNode.firstChild);
  4.2354 +                else
  4.2355 +                    containerNode.appendChild(nodeToPrepend);
  4.2356 +            } else {
  4.2357 +                // Start comments must always have a parent and at least one following sibling (the end comment)
  4.2358 +                containerNode.parentNode.insertBefore(nodeToPrepend, containerNode.nextSibling);
  4.2359 +            }
  4.2360 +        },
  4.2361 +
  4.2362 +        insertAfter: function(containerNode, nodeToInsert, insertAfterNode) {
  4.2363 +            if (!insertAfterNode) {
  4.2364 +                ko.virtualElements.prepend(containerNode, nodeToInsert);
  4.2365 +            } else if (!isStartComment(containerNode)) {
  4.2366 +                // Insert after insertion point
  4.2367 +                if (insertAfterNode.nextSibling)
  4.2368 +                    containerNode.insertBefore(nodeToInsert, insertAfterNode.nextSibling);
  4.2369 +                else
  4.2370 +                    containerNode.appendChild(nodeToInsert);
  4.2371 +            } else {
  4.2372 +                // Children of start comments must always have a parent and at least one following sibling (the end comment)
  4.2373 +                containerNode.parentNode.insertBefore(nodeToInsert, insertAfterNode.nextSibling);
  4.2374 +            }
  4.2375 +        },
  4.2376 +
  4.2377 +        firstChild: function(node) {
  4.2378 +            if (!isStartComment(node))
  4.2379 +                return node.firstChild;
  4.2380 +            if (!node.nextSibling || isEndComment(node.nextSibling))
  4.2381 +                return null;
  4.2382 +            return node.nextSibling;
  4.2383 +        },
  4.2384 +
  4.2385 +        nextSibling: function(node) {
  4.2386 +            if (isStartComment(node))
  4.2387 +                node = getMatchingEndComment(node);
  4.2388 +            if (node.nextSibling && isEndComment(node.nextSibling))
  4.2389 +                return null;
  4.2390 +            return node.nextSibling;
  4.2391 +        },
  4.2392 +
  4.2393 +        hasBindingValue: isStartComment,
  4.2394 +
  4.2395 +        virtualNodeBindingValue: function(node) {
  4.2396 +            var regexMatch = (commentNodesHaveTextProperty ? node.text : node.nodeValue).match(startCommentRegex);
  4.2397 +            return regexMatch ? regexMatch[1] : null;
  4.2398 +        },
  4.2399 +
  4.2400 +        normaliseVirtualElementDomStructure: function(elementVerified) {
  4.2401 +            // Workaround for https://github.com/SteveSanderson/knockout/issues/155
  4.2402 +            // (IE <= 8 or IE 9 quirks mode parses your HTML weirdly, treating closing </li> tags as if they don't exist, thereby moving comment nodes
  4.2403 +            // that are direct descendants of <ul> into the preceding <li>)
  4.2404 +            if (!htmlTagsWithOptionallyClosingChildren[ko.utils.tagNameLower(elementVerified)])
  4.2405 +                return;
  4.2406 +
  4.2407 +            // Scan immediate children to see if they contain unbalanced comment tags. If they do, those comment tags
  4.2408 +            // must be intended to appear *after* that child, so move them there.
  4.2409 +            var childNode = elementVerified.firstChild;
  4.2410 +            if (childNode) {
  4.2411 +                do {
  4.2412 +                    if (childNode.nodeType === 1) {
  4.2413 +                        var unbalancedTags = getUnbalancedChildTags(childNode);
  4.2414 +                        if (unbalancedTags) {
  4.2415 +                            // Fix up the DOM by moving the unbalanced tags to where they most likely were intended to be placed - *after* the child
  4.2416 +                            var nodeToInsertBefore = childNode.nextSibling;
  4.2417 +                            for (var i = 0; i < unbalancedTags.length; i++) {
  4.2418 +                                if (nodeToInsertBefore)
  4.2419 +                                    elementVerified.insertBefore(unbalancedTags[i], nodeToInsertBefore);
  4.2420 +                                else
  4.2421 +                                    elementVerified.appendChild(unbalancedTags[i]);
  4.2422 +                            }
  4.2423 +                        }
  4.2424 +                    }
  4.2425 +                } while (childNode = childNode.nextSibling);
  4.2426 +            }
  4.2427 +        }
  4.2428 +    };
  4.2429 +})();
  4.2430 +ko.exportSymbol('virtualElements', ko.virtualElements);
  4.2431 +ko.exportSymbol('virtualElements.allowedBindings', ko.virtualElements.allowedBindings);
  4.2432 +ko.exportSymbol('virtualElements.emptyNode', ko.virtualElements.emptyNode);
  4.2433 +//ko.exportSymbol('virtualElements.firstChild', ko.virtualElements.firstChild);     // firstChild is not minified
  4.2434 +ko.exportSymbol('virtualElements.insertAfter', ko.virtualElements.insertAfter);
  4.2435 +//ko.exportSymbol('virtualElements.nextSibling', ko.virtualElements.nextSibling);   // nextSibling is not minified
  4.2436 +ko.exportSymbol('virtualElements.prepend', ko.virtualElements.prepend);
  4.2437 +ko.exportSymbol('virtualElements.setDomNodeChildren', ko.virtualElements.setDomNodeChildren);
  4.2438 +(function() {
  4.2439 +    var defaultBindingAttributeName = "data-bind";
  4.2440 +
  4.2441 +    ko.bindingProvider = function() {
  4.2442 +        this.bindingCache = {};
  4.2443 +    };
  4.2444 +
  4.2445 +    ko.utils.extend(ko.bindingProvider.prototype, {
  4.2446 +        'nodeHasBindings': function(node) {
  4.2447 +            switch (node.nodeType) {
  4.2448 +                case 1: // Element
  4.2449 +                    return node.getAttribute(defaultBindingAttributeName) != null
  4.2450 +                        || ko.components['getComponentNameForNode'](node);
  4.2451 +                case 8: // Comment node
  4.2452 +                    return ko.virtualElements.hasBindingValue(node);
  4.2453 +                default: return false;
  4.2454 +            }
  4.2455 +        },
  4.2456 +
  4.2457 +        'getBindings': function(node, bindingContext) {
  4.2458 +            var bindingsString = this['getBindingsString'](node, bindingContext),
  4.2459 +                parsedBindings = bindingsString ? this['parseBindingsString'](bindingsString, bindingContext, node) : null;
  4.2460 +            return ko.components.addBindingsForCustomElement(parsedBindings, node, bindingContext, /* valueAccessors */ false);
  4.2461 +        },
  4.2462 +
  4.2463 +        'getBindingAccessors': function(node, bindingContext) {
  4.2464 +            var bindingsString = this['getBindingsString'](node, bindingContext),
  4.2465 +                parsedBindings = bindingsString ? this['parseBindingsString'](bindingsString, bindingContext, node, { 'valueAccessors': true }) : null;
  4.2466 +            return ko.components.addBindingsForCustomElement(parsedBindings, node, bindingContext, /* valueAccessors */ true);
  4.2467 +        },
  4.2468 +
  4.2469 +        // The following function is only used internally by this default provider.
  4.2470 +        // It's not part of the interface definition for a general binding provider.
  4.2471 +        'getBindingsString': function(node, bindingContext) {
  4.2472 +            switch (node.nodeType) {
  4.2473 +                case 1: return node.getAttribute(defaultBindingAttributeName);   // Element
  4.2474 +                case 8: return ko.virtualElements.virtualNodeBindingValue(node); // Comment node
  4.2475 +                default: return null;
  4.2476 +            }
  4.2477 +        },
  4.2478 +
  4.2479 +        // The following function is only used internally by this default provider.
  4.2480 +        // It's not part of the interface definition for a general binding provider.
  4.2481 +        'parseBindingsString': function(bindingsString, bindingContext, node, options) {
  4.2482 +            try {
  4.2483 +                var bindingFunction = createBindingsStringEvaluatorViaCache(bindingsString, this.bindingCache, options);
  4.2484 +                return bindingFunction(bindingContext, node);
  4.2485 +            } catch (ex) {
  4.2486 +                ex.message = "Unable to parse bindings.\nBindings value: " + bindingsString + "\nMessage: " + ex.message;
  4.2487 +                throw ex;
  4.2488 +            }
  4.2489 +        }
  4.2490 +    });
  4.2491 +
  4.2492 +    ko.bindingProvider['instance'] = new ko.bindingProvider();
  4.2493 +
  4.2494 +    function createBindingsStringEvaluatorViaCache(bindingsString, cache, options) {
  4.2495 +        var cacheKey = bindingsString + (options && options['valueAccessors'] || '');
  4.2496 +        return cache[cacheKey]
  4.2497 +            || (cache[cacheKey] = createBindingsStringEvaluator(bindingsString, options));
  4.2498 +    }
  4.2499 +
  4.2500 +    function createBindingsStringEvaluator(bindingsString, options) {
  4.2501 +        // Build the source for a function that evaluates "expression"
  4.2502 +        // For each scope variable, add an extra level of "with" nesting
  4.2503 +        // Example result: with(sc1) { with(sc0) { return (expression) } }
  4.2504 +        var rewrittenBindings = ko.expressionRewriting.preProcessBindings(bindingsString, options),
  4.2505 +            functionBody = "with($context){with($data||{}){return{" + rewrittenBindings + "}}}";
  4.2506 +        return new Function("$context", "$element", functionBody);
  4.2507 +    }
  4.2508 +})();
  4.2509 +
  4.2510 +ko.exportSymbol('bindingProvider', ko.bindingProvider);
  4.2511 +(function () {
  4.2512 +    ko.bindingHandlers = {};
  4.2513 +
  4.2514 +    // The following element types will not be recursed into during binding. In the future, we
  4.2515 +    // may consider adding <template> to this list, because such elements' contents are always
  4.2516 +    // intended to be bound in a different context from where they appear in the document.
  4.2517 +    var bindingDoesNotRecurseIntoElementTypes = {
  4.2518 +        // Don't want bindings that operate on text nodes to mutate <script> contents,
  4.2519 +        // because it's unexpected and a potential XSS issue
  4.2520 +        'script': true
  4.2521 +    };
  4.2522 +
  4.2523 +    // Use an overridable method for retrieving binding handlers so that a plugins may support dynamically created handlers
  4.2524 +    ko['getBindingHandler'] = function(bindingKey) {
  4.2525 +        return ko.bindingHandlers[bindingKey];
  4.2526 +    };
  4.2527 +
  4.2528 +    // The ko.bindingContext constructor is only called directly to create the root context. For child
  4.2529 +    // contexts, use bindingContext.createChildContext or bindingContext.extend.
  4.2530 +    ko.bindingContext = function(dataItemOrAccessor, parentContext, dataItemAlias, extendCallback) {
  4.2531 +
  4.2532 +        // The binding context object includes static properties for the current, parent, and root view models.
  4.2533 +        // If a view model is actually stored in an observable, the corresponding binding context object, and
  4.2534 +        // any child contexts, must be updated when the view model is changed.
  4.2535 +        function updateContext() {
  4.2536 +            // Most of the time, the context will directly get a view model object, but if a function is given,
  4.2537 +            // we call the function to retrieve the view model. If the function accesses any obsevables or returns
  4.2538 +            // an observable, the dependency is tracked, and those observables can later cause the binding
  4.2539 +            // context to be updated.
  4.2540 +            var dataItemOrObservable = isFunc ? dataItemOrAccessor() : dataItemOrAccessor,
  4.2541 +                dataItem = ko.utils.unwrapObservable(dataItemOrObservable);
  4.2542 +
  4.2543 +            if (parentContext) {
  4.2544 +                // When a "parent" context is given, register a dependency on the parent context. Thus whenever the
  4.2545 +                // parent context is updated, this context will also be updated.
  4.2546 +                if (parentContext._subscribable)
  4.2547 +                    parentContext._subscribable();
  4.2548 +
  4.2549 +                // Copy $root and any custom properties from the parent context
  4.2550 +                ko.utils.extend(self, parentContext);
  4.2551 +
  4.2552 +                // Because the above copy overwrites our own properties, we need to reset them.
  4.2553 +                // During the first execution, "subscribable" isn't set, so don't bother doing the update then.
  4.2554 +                if (subscribable) {
  4.2555 +                    self._subscribable = subscribable;
  4.2556 +                }
  4.2557 +            } else {
  4.2558 +                self['$parents'] = [];
  4.2559 +                self['$root'] = dataItem;
  4.2560 +
  4.2561 +                // Export 'ko' in the binding context so it will be available in bindings and templates
  4.2562 +                // even if 'ko' isn't exported as a global, such as when using an AMD loader.
  4.2563 +                // See https://github.com/SteveSanderson/knockout/issues/490
  4.2564 +                self['ko'] = ko;
  4.2565 +            }
  4.2566 +            self['$rawData'] = dataItemOrObservable;
  4.2567 +            self['$data'] = dataItem;
  4.2568 +            if (dataItemAlias)
  4.2569 +                self[dataItemAlias] = dataItem;
  4.2570 +
  4.2571 +            // The extendCallback function is provided when creating a child context or extending a context.
  4.2572 +            // It handles the specific actions needed to finish setting up the binding context. Actions in this
  4.2573 +            // function could also add dependencies to this binding context.
  4.2574 +            if (extendCallback)
  4.2575 +                extendCallback(self, parentContext, dataItem);
  4.2576 +
  4.2577 +            return self['$data'];
  4.2578 +        }
  4.2579 +        function disposeWhen() {
  4.2580 +            return nodes && !ko.utils.anyDomNodeIsAttachedToDocument(nodes);
  4.2581 +        }
  4.2582 +
  4.2583 +        var self = this,
  4.2584 +            isFunc = typeof(dataItemOrAccessor) == "function" && !ko.isObservable(dataItemOrAccessor),
  4.2585 +            nodes,
  4.2586 +            subscribable = ko.dependentObservable(updateContext, null, { disposeWhen: disposeWhen, disposeWhenNodeIsRemoved: true });
  4.2587 +
  4.2588 +        // At this point, the binding context has been initialized, and the "subscribable" computed observable is
  4.2589 +        // subscribed to any observables that were accessed in the process. If there is nothing to track, the
  4.2590 +        // computed will be inactive, and we can safely throw it away. If it's active, the computed is stored in
  4.2591 +        // the context object.
  4.2592 +        if (subscribable.isActive()) {
  4.2593 +            self._subscribable = subscribable;
  4.2594 +
  4.2595 +            // Always notify because even if the model ($data) hasn't changed, other context properties might have changed
  4.2596 +            subscribable['equalityComparer'] = null;
  4.2597 +
  4.2598 +            // We need to be able to dispose of this computed observable when it's no longer needed. This would be
  4.2599 +            // easy if we had a single node to watch, but binding contexts can be used by many different nodes, and
  4.2600 +            // we cannot assume that those nodes have any relation to each other. So instead we track any node that
  4.2601 +            // the context is attached to, and dispose the computed when all of those nodes have been cleaned.
  4.2602 +
  4.2603 +            // Add properties to *subscribable* instead of *self* because any properties added to *self* may be overwritten on updates
  4.2604 +            nodes = [];
  4.2605 +            subscribable._addNode = function(node) {
  4.2606 +                nodes.push(node);
  4.2607 +                ko.utils.domNodeDisposal.addDisposeCallback(node, function(node) {
  4.2608 +                    ko.utils.arrayRemoveItem(nodes, node);
  4.2609 +                    if (!nodes.length) {
  4.2610 +                        subscribable.dispose();
  4.2611 +                        self._subscribable = subscribable = undefined;
  4.2612 +                    }
  4.2613 +                });
  4.2614 +            };
  4.2615 +        }
  4.2616 +    }
  4.2617 +
  4.2618 +    // Extend the binding context hierarchy with a new view model object. If the parent context is watching
  4.2619 +    // any obsevables, the new child context will automatically get a dependency on the parent context.
  4.2620 +    // But this does not mean that the $data value of the child context will also get updated. If the child
  4.2621 +    // view model also depends on the parent view model, you must provide a function that returns the correct
  4.2622 +    // view model on each update.
  4.2623 +    ko.bindingContext.prototype['createChildContext'] = function (dataItemOrAccessor, dataItemAlias, extendCallback) {
  4.2624 +        return new ko.bindingContext(dataItemOrAccessor, this, dataItemAlias, function(self, parentContext) {
  4.2625 +            // Extend the context hierarchy by setting the appropriate pointers
  4.2626 +            self['$parentContext'] = parentContext;
  4.2627 +            self['$parent'] = parentContext['$data'];
  4.2628 +            self['$parents'] = (parentContext['$parents'] || []).slice(0);
  4.2629 +            self['$parents'].unshift(self['$parent']);
  4.2630 +            if (extendCallback)
  4.2631 +                extendCallback(self);
  4.2632 +        });
  4.2633 +    };
  4.2634 +
  4.2635 +    // Extend the binding context with new custom properties. This doesn't change the context hierarchy.
  4.2636 +    // Similarly to "child" contexts, provide a function here to make sure that the correct values are set
  4.2637 +    // when an observable view model is updated.
  4.2638 +    ko.bindingContext.prototype['extend'] = function(properties) {
  4.2639 +        // If the parent context references an observable view model, "_subscribable" will always be the
  4.2640 +        // latest view model object. If not, "_subscribable" isn't set, and we can use the static "$data" value.
  4.2641 +        return new ko.bindingContext(this._subscribable || this['$data'], this, null, function(self, parentContext) {
  4.2642 +            // This "child" context doesn't directly track a parent observable view model,
  4.2643 +            // so we need to manually set the $rawData value to match the parent.
  4.2644 +            self['$rawData'] = parentContext['$rawData'];
  4.2645 +            ko.utils.extend(self, typeof(properties) == "function" ? properties() : properties);
  4.2646 +        });
  4.2647 +    };
  4.2648 +
  4.2649 +    // Returns the valueAccesor function for a binding value
  4.2650 +    function makeValueAccessor(value) {
  4.2651 +        return function() {
  4.2652 +            return value;
  4.2653 +        };
  4.2654 +    }
  4.2655 +
  4.2656 +    // Returns the value of a valueAccessor function
  4.2657 +    function evaluateValueAccessor(valueAccessor) {
  4.2658 +        return valueAccessor();
  4.2659 +    }
  4.2660 +
  4.2661 +    // Given a function that returns bindings, create and return a new object that contains
  4.2662 +    // binding value-accessors functions. Each accessor function calls the original function
  4.2663 +    // so that it always gets the latest value and all dependencies are captured. This is used
  4.2664 +    // by ko.applyBindingsToNode and getBindingsAndMakeAccessors.
  4.2665 +    function makeAccessorsFromFunction(callback) {
  4.2666 +        return ko.utils.objectMap(ko.dependencyDetection.ignore(callback), function(value, key) {
  4.2667 +            return function() {
  4.2668 +                return callback()[key];
  4.2669 +            };
  4.2670 +        });
  4.2671 +    }
  4.2672 +
  4.2673 +    // Given a bindings function or object, create and return a new object that contains
  4.2674 +    // binding value-accessors functions. This is used by ko.applyBindingsToNode.
  4.2675 +    function makeBindingAccessors(bindings, context, node) {
  4.2676 +        if (typeof bindings === 'function') {
  4.2677 +            return makeAccessorsFromFunction(bindings.bind(null, context, node));
  4.2678 +        } else {
  4.2679 +            return ko.utils.objectMap(bindings, makeValueAccessor);
  4.2680 +        }
  4.2681 +    }
  4.2682 +
  4.2683 +    // This function is used if the binding provider doesn't include a getBindingAccessors function.
  4.2684 +    // It must be called with 'this' set to the provider instance.
  4.2685 +    function getBindingsAndMakeAccessors(node, context) {
  4.2686 +        return makeAccessorsFromFunction(this['getBindings'].bind(this, node, context));
  4.2687 +    }
  4.2688 +
  4.2689 +    function validateThatBindingIsAllowedForVirtualElements(bindingName) {
  4.2690 +        var validator = ko.virtualElements.allowedBindings[bindingName];
  4.2691 +        if (!validator)
  4.2692 +            throw new Error("The binding '" + bindingName + "' cannot be used with virtual elements")
  4.2693 +    }
  4.2694 +
  4.2695 +    function applyBindingsToDescendantsInternal (bindingContext, elementOrVirtualElement, bindingContextsMayDifferFromDomParentElement) {
  4.2696 +        var currentChild,
  4.2697 +            nextInQueue = ko.virtualElements.firstChild(elementOrVirtualElement),
  4.2698 +            provider = ko.bindingProvider['instance'],
  4.2699 +            preprocessNode = provider['preprocessNode'];
  4.2700 +
  4.2701 +        // Preprocessing allows a binding provider to mutate a node before bindings are applied to it. For example it's
  4.2702 +        // possible to insert new siblings after it, and/or replace the node with a different one. This can be used to
  4.2703 +        // implement custom binding syntaxes, such as {{ value }} for string interpolation, or custom element types that
  4.2704 +        // trigger insertion of <template> contents at that point in the document.
  4.2705 +        if (preprocessNode) {
  4.2706 +            while (currentChild = nextInQueue) {
  4.2707 +                nextInQueue = ko.virtualElements.nextSibling(currentChild);
  4.2708 +                preprocessNode.call(provider, currentChild);
  4.2709 +            }
  4.2710 +            // Reset nextInQueue for the next loop
  4.2711 +            nextInQueue = ko.virtualElements.firstChild(elementOrVirtualElement);
  4.2712 +        }
  4.2713 +
  4.2714 +        while (currentChild = nextInQueue) {
  4.2715 +            // Keep a record of the next child *before* applying bindings, in case the binding removes the current child from its position
  4.2716 +            nextInQueue = ko.virtualElements.nextSibling(currentChild);
  4.2717 +            applyBindingsToNodeAndDescendantsInternal(bindingContext, currentChild, bindingContextsMayDifferFromDomParentElement);
  4.2718 +        }
  4.2719 +    }
  4.2720 +
  4.2721 +    function applyBindingsToNodeAndDescendantsInternal (bindingContext, nodeVerified, bindingContextMayDifferFromDomParentElement) {
  4.2722 +        var shouldBindDescendants = true;
  4.2723 +
  4.2724 +        // Perf optimisation: Apply bindings only if...
  4.2725 +        // (1) We need to store the binding context on this node (because it may differ from the DOM parent node's binding context)
  4.2726 +        //     Note that we can't store binding contexts on non-elements (e.g., text nodes), as IE doesn't allow expando properties for those
  4.2727 +        // (2) It might have bindings (e.g., it has a data-bind attribute, or it's a marker for a containerless template)
  4.2728 +        var isElement = (nodeVerified.nodeType === 1);
  4.2729 +        if (isElement) // Workaround IE <= 8 HTML parsing weirdness
  4.2730 +            ko.virtualElements.normaliseVirtualElementDomStructure(nodeVerified);
  4.2731 +
  4.2732 +        var shouldApplyBindings = (isElement && bindingContextMayDifferFromDomParentElement)             // Case (1)
  4.2733 +                               || ko.bindingProvider['instance']['nodeHasBindings'](nodeVerified);       // Case (2)
  4.2734 +        if (shouldApplyBindings)
  4.2735 +            shouldBindDescendants = applyBindingsToNodeInternal(nodeVerified, null, bindingContext, bindingContextMayDifferFromDomParentElement)['shouldBindDescendants'];
  4.2736 +
  4.2737 +        if (shouldBindDescendants && !bindingDoesNotRecurseIntoElementTypes[ko.utils.tagNameLower(nodeVerified)]) {
  4.2738 +            // We're recursing automatically into (real or virtual) child nodes without changing binding contexts. So,
  4.2739 +            //  * For children of a *real* element, the binding context is certainly the same as on their DOM .parentNode,
  4.2740 +            //    hence bindingContextsMayDifferFromDomParentElement is false
  4.2741 +            //  * For children of a *virtual* element, we can't be sure. Evaluating .parentNode on those children may
  4.2742 +            //    skip over any number of intermediate virtual elements, any of which might define a custom binding context,
  4.2743 +            //    hence bindingContextsMayDifferFromDomParentElement is true
  4.2744 +            applyBindingsToDescendantsInternal(bindingContext, nodeVerified, /* bindingContextsMayDifferFromDomParentElement: */ !isElement);
  4.2745 +        }
  4.2746 +    }
  4.2747 +
  4.2748 +    var boundElementDomDataKey = ko.utils.domData.nextKey();
  4.2749 +
  4.2750 +
  4.2751 +    function topologicalSortBindings(bindings) {
  4.2752 +        // Depth-first sort
  4.2753 +        var result = [],                // The list of key/handler pairs that we will return
  4.2754 +            bindingsConsidered = {},    // A temporary record of which bindings are already in 'result'
  4.2755 +            cyclicDependencyStack = []; // Keeps track of a depth-search so that, if there's a cycle, we know which bindings caused it
  4.2756 +        ko.utils.objectForEach(bindings, function pushBinding(bindingKey) {
  4.2757 +            if (!bindingsConsidered[bindingKey]) {
  4.2758 +                var binding = ko['getBindingHandler'](bindingKey);
  4.2759 +                if (binding) {
  4.2760 +                    // First add dependencies (if any) of the current binding
  4.2761 +                    if (binding['after']) {
  4.2762 +                        cyclicDependencyStack.push(bindingKey);
  4.2763 +                        ko.utils.arrayForEach(binding['after'], function(bindingDependencyKey) {
  4.2764 +                            if (bindings[bindingDependencyKey]) {
  4.2765 +                                if (ko.utils.arrayIndexOf(cyclicDependencyStack, bindingDependencyKey) !== -1) {
  4.2766 +                                    throw Error("Cannot combine the following bindings, because they have a cyclic dependency: " + cyclicDependencyStack.join(", "));
  4.2767 +                                } else {
  4.2768 +                                    pushBinding(bindingDependencyKey);
  4.2769 +                                }
  4.2770 +                            }
  4.2771 +                        });
  4.2772 +                        cyclicDependencyStack.length--;
  4.2773 +                    }
  4.2774 +                    // Next add the current binding
  4.2775 +                    result.push({ key: bindingKey, handler: binding });
  4.2776 +                }
  4.2777 +                bindingsConsidered[bindingKey] = true;
  4.2778 +            }
  4.2779 +        });
  4.2780 +
  4.2781 +        return result;
  4.2782 +    }
  4.2783 +
  4.2784 +    function applyBindingsToNodeInternal(node, sourceBindings, bindingContext, bindingContextMayDifferFromDomParentElement) {
  4.2785 +        // Prevent multiple applyBindings calls for the same node, except when a binding value is specified
  4.2786 +        var alreadyBound = ko.utils.domData.get(node, boundElementDomDataKey);
  4.2787 +        if (!sourceBindings) {
  4.2788 +            if (alreadyBound) {
  4.2789 +                throw Error("You cannot apply bindings multiple times to the same element.");
  4.2790 +            }
  4.2791 +            ko.utils.domData.set(node, boundElementDomDataKey, true);
  4.2792 +        }
  4.2793 +
  4.2794 +        // Optimization: Don't store the binding context on this node if it's definitely the same as on node.parentNode, because
  4.2795 +        // we can easily recover it just by scanning up the node's ancestors in the DOM
  4.2796 +        // (note: here, parent node means "real DOM parent" not "virtual parent", as there's no O(1) way to find the virtual parent)
  4.2797 +        if (!alreadyBound && bindingContextMayDifferFromDomParentElement)
  4.2798 +            ko.storedBindingContextForNode(node, bindingContext);
  4.2799 +
  4.2800 +        // Use bindings if given, otherwise fall back on asking the bindings provider to give us some bindings
  4.2801 +        var bindings;
  4.2802 +        if (sourceBindings && typeof sourceBindings !== 'function') {
  4.2803 +            bindings = sourceBindings;
  4.2804 +        } else {
  4.2805 +            var provider = ko.bindingProvider['instance'],
  4.2806 +                getBindings = provider['getBindingAccessors'] || getBindingsAndMakeAccessors;
  4.2807 +
  4.2808 +            // Get the binding from the provider within a computed observable so that we can update the bindings whenever
  4.2809 +            // the binding context is updated or if the binding provider accesses observables.
  4.2810 +            var bindingsUpdater = ko.dependentObservable(
  4.2811 +                function() {
  4.2812 +                    bindings = sourceBindings ? sourceBindings(bindingContext, node) : getBindings.call(provider, node, bindingContext);
  4.2813 +                    // Register a dependency on the binding context to support obsevable view models.
  4.2814 +                    if (bindings && bindingContext._subscribable)
  4.2815 +                        bindingContext._subscribable();
  4.2816 +                    return bindings;
  4.2817 +                },
  4.2818 +                null, { disposeWhenNodeIsRemoved: node }
  4.2819 +            );
  4.2820 +
  4.2821 +            if (!bindings || !bindingsUpdater.isActive())
  4.2822 +                bindingsUpdater = null;
  4.2823 +        }
  4.2824 +
  4.2825 +        var bindingHandlerThatControlsDescendantBindings;
  4.2826 +        if (bindings) {
  4.2827 +            // Return the value accessor for a given binding. When bindings are static (won't be updated because of a binding
  4.2828 +            // context update), just return the value accessor from the binding. Otherwise, return a function that always gets
  4.2829 +            // the latest binding value and registers a dependency on the binding updater.
  4.2830 +            var getValueAccessor = bindingsUpdater
  4.2831 +                ? function(bindingKey) {
  4.2832 +                    return function() {
  4.2833 +                        return evaluateValueAccessor(bindingsUpdater()[bindingKey]);
  4.2834 +                    };
  4.2835 +                } : function(bindingKey) {
  4.2836 +                    return bindings[bindingKey];
  4.2837 +                };
  4.2838 +
  4.2839 +            // Use of allBindings as a function is maintained for backwards compatibility, but its use is deprecated
  4.2840 +            function allBindings() {
  4.2841 +                return ko.utils.objectMap(bindingsUpdater ? bindingsUpdater() : bindings, evaluateValueAccessor);
  4.2842 +            }
  4.2843 +            // The following is the 3.x allBindings API
  4.2844 +            allBindings['get'] = function(key) {
  4.2845 +                return bindings[key] && evaluateValueAccessor(getValueAccessor(key));
  4.2846 +            };
  4.2847 +            allBindings['has'] = function(key) {
  4.2848 +                return key in bindings;
  4.2849 +            };
  4.2850 +
  4.2851 +            // First put the bindings into the right order
  4.2852 +            var orderedBindings = topologicalSortBindings(bindings);
  4.2853 +
  4.2854 +            // Go through the sorted bindings, calling init and update for each
  4.2855 +            ko.utils.arrayForEach(orderedBindings, function(bindingKeyAndHandler) {
  4.2856 +                // Note that topologicalSortBindings has already filtered out any nonexistent binding handlers,
  4.2857 +                // so bindingKeyAndHandler.handler will always be nonnull.
  4.2858 +                var handlerInitFn = bindingKeyAndHandler.handler["init"],
  4.2859 +                    handlerUpdateFn = bindingKeyAndHandler.handler["update"],
  4.2860 +                    bindingKey = bindingKeyAndHandler.key;
  4.2861 +
  4.2862 +                if (node.nodeType === 8) {
  4.2863 +                    validateThatBindingIsAllowedForVirtualElements(bindingKey);
  4.2864 +                }
  4.2865 +
  4.2866 +                try {
  4.2867 +                    // Run init, ignoring any dependencies
  4.2868 +                    if (typeof handlerInitFn == "function") {
  4.2869 +                        ko.dependencyDetection.ignore(function() {
  4.2870 +                            var initResult = handlerInitFn(node, getValueAccessor(bindingKey), allBindings, bindingContext['$data'], bindingContext);
  4.2871 +
  4.2872 +                            // If this binding handler claims to control descendant bindings, make a note of this
  4.2873 +                            if (initResult && initResult['controlsDescendantBindings']) {
  4.2874 +                                if (bindingHandlerThatControlsDescendantBindings !== undefined)
  4.2875 +                                    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.");
  4.2876 +                                bindingHandlerThatControlsDescendantBindings = bindingKey;
  4.2877 +                            }
  4.2878 +                        });
  4.2879 +                    }
  4.2880 +
  4.2881 +                    // Run update in its own computed wrapper
  4.2882 +                    if (typeof handlerUpdateFn == "function") {
  4.2883 +                        ko.dependentObservable(
  4.2884 +                            function() {
  4.2885 +                                handlerUpdateFn(node, getValueAccessor(bindingKey), allBindings, bindingContext['$data'], bindingContext);
  4.2886 +                            },
  4.2887 +                            null,
  4.2888 +                            { disposeWhenNodeIsRemoved: node }
  4.2889 +                        );
  4.2890 +                    }
  4.2891 +                } catch (ex) {
  4.2892 +                    ex.message = "Unable to process binding \"" + bindingKey + ": " + bindings[bindingKey] + "\"\nMessage: " + ex.message;
  4.2893 +                    throw ex;
  4.2894 +                }
  4.2895 +            });
  4.2896 +        }
  4.2897 +
  4.2898 +        return {
  4.2899 +            'shouldBindDescendants': bindingHandlerThatControlsDescendantBindings === undefined
  4.2900 +        };
  4.2901 +    };
  4.2902 +
  4.2903 +    var storedBindingContextDomDataKey = ko.utils.domData.nextKey();
  4.2904 +    ko.storedBindingContextForNode = function (node, bindingContext) {
  4.2905 +        if (arguments.length == 2) {
  4.2906 +            ko.utils.domData.set(node, storedBindingContextDomDataKey, bindingContext);
  4.2907 +            if (bindingContext._subscribable)
  4.2908 +                bindingContext._subscribable._addNode(node);
  4.2909 +        } else {
  4.2910 +            return ko.utils.domData.get(node, storedBindingContextDomDataKey);
  4.2911 +        }
  4.2912 +    }
  4.2913 +
  4.2914 +    function getBindingContext(viewModelOrBindingContext) {
  4.2915 +        return viewModelOrBindingContext && (viewModelOrBindingContext instanceof ko.bindingContext)
  4.2916 +            ? viewModelOrBindingContext
  4.2917 +            : new ko.bindingContext(viewModelOrBindingContext);
  4.2918 +    }
  4.2919 +
  4.2920 +    ko.applyBindingAccessorsToNode = function (node, bindings, viewModelOrBindingContext) {
  4.2921 +        if (node.nodeType === 1) // If it's an element, workaround IE <= 8 HTML parsing weirdness
  4.2922 +            ko.virtualElements.normaliseVirtualElementDomStructure(node);
  4.2923 +        return applyBindingsToNodeInternal(node, bindings, getBindingContext(viewModelOrBindingContext), true);
  4.2924 +    };
  4.2925 +
  4.2926 +    ko.applyBindingsToNode = function (node, bindings, viewModelOrBindingContext) {
  4.2927 +        var context = getBindingContext(viewModelOrBindingContext);
  4.2928 +        return ko.applyBindingAccessorsToNode(node, makeBindingAccessors(bindings, context, node), context);
  4.2929 +    };
  4.2930 +
  4.2931 +    ko.applyBindingsToDescendants = function(viewModelOrBindingContext, rootNode) {
  4.2932 +        if (rootNode.nodeType === 1 || rootNode.nodeType === 8)
  4.2933 +            applyBindingsToDescendantsInternal(getBindingContext(viewModelOrBindingContext), rootNode, true);
  4.2934 +    };
  4.2935 +
  4.2936 +    ko.applyBindings = function (viewModelOrBindingContext, rootNode) {
  4.2937 +        // If jQuery is loaded after Knockout, we won't initially have access to it. So save it here.
  4.2938 +        if (!jQueryInstance && window['jQuery']) {
  4.2939 +            jQueryInstance = window['jQuery'];
  4.2940 +        }
  4.2941 +
  4.2942 +        if (rootNode && (rootNode.nodeType !== 1) && (rootNode.nodeType !== 8))
  4.2943 +            throw new Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");
  4.2944 +        rootNode = rootNode || window.document.body; // Make "rootNode" parameter optional
  4.2945 +
  4.2946 +        applyBindingsToNodeAndDescendantsInternal(getBindingContext(viewModelOrBindingContext), rootNode, true);
  4.2947 +    };
  4.2948 +
  4.2949 +    // Retrieving binding context from arbitrary nodes
  4.2950 +    ko.contextFor = function(node) {
  4.2951 +        // We can only do something meaningful for elements and comment nodes (in particular, not text nodes, as IE can't store domdata for them)
  4.2952 +        switch (node.nodeType) {
  4.2953 +            case 1:
  4.2954 +            case 8:
  4.2955 +                var context = ko.storedBindingContextForNode(node);
  4.2956 +                if (context) return context;
  4.2957 +                if (node.parentNode) return ko.contextFor(node.parentNode);
  4.2958 +                break;
  4.2959 +        }
  4.2960 +        return undefined;
  4.2961 +    };
  4.2962 +    ko.dataFor = function(node) {
  4.2963 +        var context = ko.contextFor(node);
  4.2964 +        return context ? context['$data'] : undefined;
  4.2965 +    };
  4.2966 +
  4.2967 +    ko.exportSymbol('bindingHandlers', ko.bindingHandlers);
  4.2968 +    ko.exportSymbol('applyBindings', ko.applyBindings);
  4.2969 +    ko.exportSymbol('applyBindingsToDescendants', ko.applyBindingsToDescendants);
  4.2970 +    ko.exportSymbol('applyBindingAccessorsToNode', ko.applyBindingAccessorsToNode);
  4.2971 +    ko.exportSymbol('applyBindingsToNode', ko.applyBindingsToNode);
  4.2972 +    ko.exportSymbol('contextFor', ko.contextFor);
  4.2973 +    ko.exportSymbol('dataFor', ko.dataFor);
  4.2974 +})();
  4.2975 +(function(undefined) {
  4.2976 +    var loadingSubscribablesCache = {}, // Tracks component loads that are currently in flight
  4.2977 +        loadedDefinitionsCache = {};    // Tracks component loads that have already completed
  4.2978 +
  4.2979 +    ko.components = {
  4.2980 +        get: function(componentName, callback) {
  4.2981 +            var cachedDefinition = getObjectOwnProperty(loadedDefinitionsCache, componentName);
  4.2982 +            if (cachedDefinition) {
  4.2983 +                // It's already loaded and cached. Reuse the same definition object.
  4.2984 +                // Note that for API consistency, even cache hits complete asynchronously.
  4.2985 +                setTimeout(function() { callback(cachedDefinition) }, 0);
  4.2986 +            } else {
  4.2987 +                // Join the loading process that is already underway, or start a new one.
  4.2988 +                loadComponentAndNotify(componentName, callback);
  4.2989 +            }
  4.2990 +        },
  4.2991 +
  4.2992 +        clearCachedDefinition: function(componentName) {
  4.2993 +            delete loadedDefinitionsCache[componentName];
  4.2994 +        },
  4.2995 +
  4.2996 +        _getFirstResultFromLoaders: getFirstResultFromLoaders
  4.2997 +    };
  4.2998 +
  4.2999 +    function getObjectOwnProperty(obj, propName) {
  4.3000 +        return obj.hasOwnProperty(propName) ? obj[propName] : undefined;
  4.3001 +    }
  4.3002 +
  4.3003 +    function loadComponentAndNotify(componentName, callback) {
  4.3004 +        var subscribable = getObjectOwnProperty(loadingSubscribablesCache, componentName),
  4.3005 +            completedAsync;
  4.3006 +        if (!subscribable) {
  4.3007 +            // It's not started loading yet. Start loading, and when it's done, move it to loadedDefinitionsCache.
  4.3008 +            subscribable = loadingSubscribablesCache[componentName] = new ko.subscribable();
  4.3009 +            beginLoadingComponent(componentName, function(definition) {
  4.3010 +                loadedDefinitionsCache[componentName] = definition;
  4.3011 +                delete loadingSubscribablesCache[componentName];
  4.3012 +
  4.3013 +                // For API consistency, all loads complete asynchronously. However we want to avoid
  4.3014 +                // adding an extra setTimeout if it's unnecessary (i.e., the completion is already
  4.3015 +                // async) since setTimeout(..., 0) still takes about 16ms or more on most browsers.
  4.3016 +                if (completedAsync) {
  4.3017 +                    subscribable['notifySubscribers'](definition);
  4.3018 +                } else {
  4.3019 +                    setTimeout(function() {
  4.3020 +                        subscribable['notifySubscribers'](definition);
  4.3021 +                    }, 0);
  4.3022 +                }
  4.3023 +            });
  4.3024 +            completedAsync = true;
  4.3025 +        }
  4.3026 +        subscribable.subscribe(callback);
  4.3027 +    }
  4.3028 +
  4.3029 +    function beginLoadingComponent(componentName, callback) {
  4.3030 +        getFirstResultFromLoaders('getConfig', [componentName], function(config) {
  4.3031 +            if (config) {
  4.3032 +                // We have a config, so now load its definition
  4.3033 +                getFirstResultFromLoaders('loadComponent', [componentName, config], function(definition) {
  4.3034 +                    callback(definition);
  4.3035 +                });
  4.3036 +            } else {
  4.3037 +                // The component has no config - it's unknown to all the loaders.
  4.3038 +                // Note that this is not an error (e.g., a module loading error) - that would abort the
  4.3039 +                // process and this callback would not run. For this callback to run, all loaders must
  4.3040 +                // have confirmed they don't know about this component.
  4.3041 +                callback(null);
  4.3042 +            }
  4.3043 +        });
  4.3044 +    }
  4.3045 +
  4.3046 +    function getFirstResultFromLoaders(methodName, argsExceptCallback, callback, candidateLoaders) {
  4.3047 +        // On the first call in the stack, start with the full set of loaders
  4.3048 +        if (!candidateLoaders) {
  4.3049 +            candidateLoaders = ko.components['loaders'].slice(0); // Use a copy, because we'll be mutating this array
  4.3050 +        }
  4.3051 +
  4.3052 +        // Try the next candidate
  4.3053 +        var currentCandidateLoader = candidateLoaders.shift();
  4.3054 +        if (currentCandidateLoader) {
  4.3055 +            var methodInstance = currentCandidateLoader[methodName];
  4.3056 +            if (methodInstance) {
  4.3057 +                var wasAborted = false,
  4.3058 +                    synchronousReturnValue = methodInstance.apply(currentCandidateLoader, argsExceptCallback.concat(function(result) {
  4.3059 +                        if (wasAborted) {
  4.3060 +                            callback(null);
  4.3061 +                        } else if (result !== null) {
  4.3062 +                            // This candidate returned a value. Use it.
  4.3063 +                            callback(result);
  4.3064 +                        } else {
  4.3065 +                            // Try the next candidate
  4.3066 +                            getFirstResultFromLoaders(methodName, argsExceptCallback, callback, candidateLoaders);
  4.3067 +                        }
  4.3068 +                    }));
  4.3069 +
  4.3070 +                // Currently, loaders may not return anything synchronously. This leaves open the possibility
  4.3071 +                // that we'll extend the API to support synchronous return values in the future. It won't be
  4.3072 +                // a breaking change, because currently no loader is allowed to return anything except undefined.
  4.3073 +                if (synchronousReturnValue !== undefined) {
  4.3074 +                    wasAborted = true;
  4.3075 +
  4.3076 +                    // Method to suppress exceptions will remain undocumented. This is only to keep
  4.3077 +                    // KO's specs running tidily, since we can observe the loading got aborted without
  4.3078 +                    // having exceptions cluttering up the console too.
  4.3079 +                    if (!currentCandidateLoader['suppressLoaderExceptions']) {
  4.3080 +                        throw new Error('Component loaders must supply values by invoking the callback, not by returning values synchronously.');
  4.3081 +                    }
  4.3082 +                }
  4.3083 +            } else {
  4.3084 +                // This candidate doesn't have the relevant handler. Synchronously move on to the next one.
  4.3085 +                getFirstResultFromLoaders(methodName, argsExceptCallback, callback, candidateLoaders);
  4.3086 +            }
  4.3087 +        } else {
  4.3088 +            // No candidates returned a value
  4.3089 +            callback(null);
  4.3090 +        }
  4.3091 +    }
  4.3092 +
  4.3093 +    // Reference the loaders via string name so it's possible for developers
  4.3094 +    // to replace the whole array by assigning to ko.components.loaders
  4.3095 +    ko.components['loaders'] = [];
  4.3096 +
  4.3097 +    ko.exportSymbol('components', ko.components);
  4.3098 +    ko.exportSymbol('components.get', ko.components.get);
  4.3099 +    ko.exportSymbol('components.clearCachedDefinition', ko.components.clearCachedDefinition);
  4.3100 +})();
  4.3101 +(function(undefined) {
  4.3102 +
  4.3103 +    // The default loader is responsible for two things:
  4.3104 +    // 1. Maintaining the default in-memory registry of component configuration objects
  4.3105 +    //    (i.e., the thing you're writing to when you call ko.components.register(someName, ...))
  4.3106 +    // 2. Answering requests for components by fetching configuration objects
  4.3107 +    //    from that default in-memory registry and resolving them into standard
  4.3108 +    //    component definition objects (of the form { createViewModel: ..., template: ... })
  4.3109 +    // Custom loaders may override either of these facilities, i.e.,
  4.3110 +    // 1. To supply configuration objects from some other source (e.g., conventions)
  4.3111 +    // 2. Or, to resolve configuration objects by loading viewmodels/templates via arbitrary logic.
  4.3112 +
  4.3113 +    var defaultConfigRegistry = {};
  4.3114 +
  4.3115 +    ko.components.register = function(componentName, config) {
  4.3116 +        if (!config) {
  4.3117 +            throw new Error('Invalid configuration for ' + componentName);
  4.3118 +        }
  4.3119 +
  4.3120 +        if (ko.components.isRegistered(componentName)) {
  4.3121 +            throw new Error('Component ' + componentName + ' is already registered');
  4.3122 +        }
  4.3123 +
  4.3124 +        defaultConfigRegistry[componentName] = config;
  4.3125 +    }
  4.3126 +
  4.3127 +    ko.components.isRegistered = function(componentName) {
  4.3128 +        return componentName in defaultConfigRegistry;
  4.3129 +    }
  4.3130 +
  4.3131 +    ko.components.unregister = function(componentName) {
  4.3132 +        delete defaultConfigRegistry[componentName];
  4.3133 +        ko.components.clearCachedDefinition(componentName);
  4.3134 +    }
  4.3135 +
  4.3136 +    ko.components.defaultLoader = {
  4.3137 +        'getConfig': function(componentName, callback) {
  4.3138 +            var result = defaultConfigRegistry.hasOwnProperty(componentName)
  4.3139 +                ? defaultConfigRegistry[componentName]
  4.3140 +                : null;
  4.3141 +            callback(result);
  4.3142 +        },
  4.3143 +
  4.3144 +        'loadComponent': function(componentName, config, callback) {
  4.3145 +            var errorCallback = makeErrorCallback(componentName);
  4.3146 +            possiblyGetConfigFromAmd(errorCallback, config, function(loadedConfig) {
  4.3147 +                resolveConfig(componentName, errorCallback, loadedConfig, callback);
  4.3148 +            });
  4.3149 +        },
  4.3150 +
  4.3151 +        'loadTemplate': function(componentName, templateConfig, callback) {
  4.3152 +            resolveTemplate(makeErrorCallback(componentName), templateConfig, callback);
  4.3153 +        },
  4.3154 +
  4.3155 +        'loadViewModel': function(componentName, viewModelConfig, callback) {
  4.3156 +            resolveViewModel(makeErrorCallback(componentName), viewModelConfig, callback);
  4.3157 +        }
  4.3158 +    };
  4.3159 +
  4.3160 +    var createViewModelKey = 'createViewModel';
  4.3161 +
  4.3162 +    // Takes a config object of the form { template: ..., viewModel: ... }, and asynchronously convert it
  4.3163 +    // into the standard component definition format:
  4.3164 +    //    { template: <ArrayOfDomNodes>, createViewModel: function(params, componentInfo) { ... } }.
  4.3165 +    // Since both template and viewModel may need to be resolved asynchronously, both tasks are performed
  4.3166 +    // in parallel, and the results joined when both are ready. We don't depend on any promises infrastructure,
  4.3167 +    // so this is implemented manually below.
  4.3168 +    function resolveConfig(componentName, errorCallback, config, callback) {
  4.3169 +        var result = {},
  4.3170 +            makeCallBackWhenZero = 2,
  4.3171 +            tryIssueCallback = function() {
  4.3172 +                if (--makeCallBackWhenZero === 0) {
  4.3173 +                    callback(result);
  4.3174 +                }
  4.3175 +            },
  4.3176 +            templateConfig = config['template'],
  4.3177 +            viewModelConfig = config['viewModel'];
  4.3178 +
  4.3179 +        if (templateConfig) {
  4.3180 +            possiblyGetConfigFromAmd(errorCallback, templateConfig, function(loadedConfig) {
  4.3181 +                ko.components._getFirstResultFromLoaders('loadTemplate', [componentName, loadedConfig], function(resolvedTemplate) {
  4.3182 +                    result['template'] = resolvedTemplate;
  4.3183 +                    tryIssueCallback();
  4.3184 +                });
  4.3185 +            });
  4.3186 +        } else {
  4.3187 +            tryIssueCallback();
  4.3188 +        }
  4.3189 +
  4.3190 +        if (viewModelConfig) {
  4.3191 +            possiblyGetConfigFromAmd(errorCallback, viewModelConfig, function(loadedConfig) {
  4.3192 +                ko.components._getFirstResultFromLoaders('loadViewModel', [componentName, loadedConfig], function(resolvedViewModel) {
  4.3193 +                    result[createViewModelKey] = resolvedViewModel;
  4.3194 +                    tryIssueCallback();
  4.3195 +                });
  4.3196 +            });
  4.3197 +        } else {
  4.3198 +            tryIssueCallback();
  4.3199 +        }
  4.3200 +    }
  4.3201 +
  4.3202 +    function resolveTemplate(errorCallback, templateConfig, callback) {
  4.3203 +        if (typeof templateConfig === 'string') {
  4.3204 +            // Markup - parse it
  4.3205 +            callback(ko.utils.parseHtmlFragment(templateConfig));
  4.3206 +        } else if (templateConfig instanceof Array) {
  4.3207 +            // Assume already an array of DOM nodes - pass through unchanged
  4.3208 +            callback(templateConfig);
  4.3209 +        } else if (isDocumentFragment(templateConfig)) {
  4.3210 +            // Document fragment - use its child nodes
  4.3211 +            callback(ko.utils.makeArray(templateConfig.childNodes));
  4.3212 +        } else if (templateConfig['element']) {
  4.3213 +            var element = templateConfig['element'];
  4.3214 +            if (isDomElement(element)) {
  4.3215 +                // Element instance - copy its child nodes
  4.3216 +                callback(cloneNodesFromTemplateSourceElement(element));
  4.3217 +            } else if (typeof element === 'string') {
  4.3218 +                // Element ID - find it, then copy its child nodes
  4.3219 +                var elemInstance = document.getElementById(element);
  4.3220 +                if (elemInstance) {
  4.3221 +                    callback(cloneNodesFromTemplateSourceElement(elemInstance));
  4.3222 +                } else {
  4.3223 +                    errorCallback('Cannot find element with ID ' + element);
  4.3224 +                }
  4.3225 +            } else {
  4.3226 +                errorCallback('Unknown element type: ' + element);
  4.3227 +            }
  4.3228 +        } else {
  4.3229 +            errorCallback('Unknown template value: ' + templateConfig);
  4.3230 +        }
  4.3231 +    }
  4.3232 +
  4.3233 +    function resolveViewModel(errorCallback, viewModelConfig, callback) {
  4.3234 +        if (typeof viewModelConfig === 'function') {
  4.3235 +            // Constructor - convert to standard factory function format
  4.3236 +            // By design, this does *not* supply componentInfo to the constructor, as the intent is that
  4.3237 +            // componentInfo contains non-viewmodel data (e.g., the component's element) that should only
  4.3238 +            // be used in factory functions, not viewmodel constructors.
  4.3239 +            callback(function (params /*, componentInfo */) {
  4.3240 +                return new viewModelConfig(params);
  4.3241 +            });
  4.3242 +        } else if (typeof viewModelConfig[createViewModelKey] === 'function') {
  4.3243 +            // Already a factory function - use it as-is
  4.3244 +            callback(viewModelConfig[createViewModelKey]);
  4.3245 +        } else if ('instance' in viewModelConfig) {
  4.3246 +            // Fixed object instance - promote to createViewModel format for API consistency
  4.3247 +            var fixedInstance = viewModelConfig['instance'];
  4.3248 +            callback(function (params, componentInfo) {
  4.3249 +                return fixedInstance;
  4.3250 +            });
  4.3251 +        } else if ('viewModel' in viewModelConfig) {
  4.3252 +            // Resolved AMD module whose value is of the form { viewModel: ... }
  4.3253 +            resolveViewModel(errorCallback, viewModelConfig['viewModel'], callback);
  4.3254 +        } else {
  4.3255 +            errorCallback('Unknown viewModel value: ' + viewModelConfig);
  4.3256 +        }
  4.3257 +    }
  4.3258 +
  4.3259 +    function cloneNodesFromTemplateSourceElement(elemInstance) {
  4.3260 +        switch (ko.utils.tagNameLower(elemInstance)) {
  4.3261 +            case 'script':
  4.3262 +                return ko.utils.parseHtmlFragment(elemInstance.text);
  4.3263 +            case 'textarea':
  4.3264 +                return ko.utils.parseHtmlFragment(elemInstance.value);
  4.3265 +            case 'template':
  4.3266 +                // For browsers with proper <template> element support (i.e., where the .content property
  4.3267 +                // gives a document fragment), use that document fragment.
  4.3268 +                if (isDocumentFragment(elemInstance.content)) {
  4.3269 +                    return ko.utils.cloneNodes(elemInstance.content.childNodes);
  4.3270 +                }
  4.3271 +        }
  4.3272 +
  4.3273 +        // Regular elements such as <div>, and <template> elements on old browsers that don't really
  4.3274 +        // understand <template> and just treat it as a regular container
  4.3275 +        return ko.utils.cloneNodes(elemInstance.childNodes);
  4.3276 +    }
  4.3277 +
  4.3278 +    function isDomElement(obj) {
  4.3279 +        if (window['HTMLElement']) {
  4.3280 +            return obj instanceof HTMLElement;
  4.3281 +        } else {
  4.3282 +            return obj && obj.tagName && obj.nodeType === 1;
  4.3283 +        }
  4.3284 +    }
  4.3285 +
  4.3286 +    function isDocumentFragment(obj) {
  4.3287 +        if (window['DocumentFragment']) {
  4.3288 +            return obj instanceof DocumentFragment;
  4.3289 +        } else {
  4.3290 +            return obj && obj.nodeType === 11;
  4.3291 +        }
  4.3292 +    }
  4.3293 +
  4.3294 +    function possiblyGetConfigFromAmd(errorCallback, config, callback) {
  4.3295 +        if (typeof config['require'] === 'string') {
  4.3296 +            // The config is the value of an AMD module
  4.3297 +            if (require || window['require']) {
  4.3298 +                (require || window['require'])([config['require']], callback);
  4.3299 +            } else {
  4.3300 +                errorCallback('Uses require, but no AMD loader is present');
  4.3301 +            }
  4.3302 +        } else {
  4.3303 +            callback(config);
  4.3304 +        }
  4.3305 +    }
  4.3306 +
  4.3307 +    function makeErrorCallback(componentName) {
  4.3308 +        return function (message) {
  4.3309 +            throw new Error('Component \'' + componentName + '\': ' + message);
  4.3310 +        };
  4.3311 +    }
  4.3312 +
  4.3313 +    ko.exportSymbol('components.register', ko.components.register);
  4.3314 +    ko.exportSymbol('components.isRegistered', ko.components.isRegistered);
  4.3315 +    ko.exportSymbol('components.unregister', ko.components.unregister);
  4.3316 +
  4.3317 +    // Expose the default loader so that developers can directly ask it for configuration
  4.3318 +    // or to resolve configuration
  4.3319 +    ko.exportSymbol('components.defaultLoader', ko.components.defaultLoader);
  4.3320 +
  4.3321 +    // By default, the default loader is the only registered component loader
  4.3322 +    ko.components['loaders'].push(ko.components.defaultLoader);
  4.3323 +
  4.3324 +    // Privately expose the underlying config registry for use in old-IE shim
  4.3325 +    ko.components._allRegisteredComponents = defaultConfigRegistry;
  4.3326 +})();
  4.3327 +(function (undefined) {
  4.3328 +    // Overridable API for determining which component name applies to a given node. By overriding this,
  4.3329 +    // you can for example map specific tagNames to components that are not preregistered.
  4.3330 +    ko.components['getComponentNameForNode'] = function(node) {
  4.3331 +        var tagNameLower = ko.utils.tagNameLower(node);
  4.3332 +        return ko.components.isRegistered(tagNameLower) && tagNameLower;
  4.3333 +    };
  4.3334 +
  4.3335 +    ko.components.addBindingsForCustomElement = function(allBindings, node, bindingContext, valueAccessors) {
  4.3336 +        // Determine if it's really a custom element matching a component
  4.3337 +        if (node.nodeType === 1) {
  4.3338 +            var componentName = ko.components['getComponentNameForNode'](node);
  4.3339 +            if (componentName) {
  4.3340 +                // It does represent a component, so add a component binding for it
  4.3341 +                allBindings = allBindings || {};
  4.3342 +
  4.3343 +                if (allBindings['component']) {
  4.3344 +                    // Avoid silently overwriting some other 'component' binding that may already be on the element
  4.3345 +                    throw new Error('Cannot use the "component" binding on a custom element matching a component');
  4.3346 +                }
  4.3347 +
  4.3348 +                var componentBindingValue = { 'name': componentName, 'params': getComponentParamsFromCustomElement(node, bindingContext) };
  4.3349 +
  4.3350 +                allBindings['component'] = valueAccessors
  4.3351 +                    ? function() { return componentBindingValue; }
  4.3352 +                    : componentBindingValue;
  4.3353 +            }
  4.3354 +        }
  4.3355 +
  4.3356 +        return allBindings;
  4.3357 +    }
  4.3358 +
  4.3359 +    var nativeBindingProviderInstance = new ko.bindingProvider();
  4.3360 +
  4.3361 +    function getComponentParamsFromCustomElement(elem, bindingContext) {
  4.3362 +        var paramsAttribute = elem.getAttribute('params');
  4.3363 +
  4.3364 +        if (paramsAttribute) {
  4.3365 +            var params = nativeBindingProviderInstance['parseBindingsString'](paramsAttribute, bindingContext, elem, { 'valueAccessors': true, 'bindingParams': true }),
  4.3366 +                rawParamComputedValues = ko.utils.objectMap(params, function(paramValue, paramName) {
  4.3367 +                    return ko.computed(paramValue, null, { disposeWhenNodeIsRemoved: elem });
  4.3368 +                }),
  4.3369 +                result = ko.utils.objectMap(rawParamComputedValues, function(paramValueComputed, paramName) {
  4.3370 +                    // Does the evaluation of the parameter value unwrap any observables?
  4.3371 +                    if (!paramValueComputed.isActive()) {
  4.3372 +                        // No it doesn't, so there's no need for any computed wrapper. Just pass through the supplied value directly.
  4.3373 +                        // Example: "someVal: firstName, age: 123" (whether or not firstName is an observable/computed)
  4.3374 +                        return paramValueComputed.peek();
  4.3375 +                    } else {
  4.3376 +                        // Yes it does. Supply a computed property that unwraps both the outer (binding expression)
  4.3377 +                        // level of observability, and any inner (resulting model value) level of observability.
  4.3378 +                        // This means the component doesn't have to worry about multiple unwrapping.
  4.3379 +                        return ko.computed(function() {
  4.3380 +                            return ko.utils.unwrapObservable(paramValueComputed());
  4.3381 +                        }, null, { disposeWhenNodeIsRemoved: elem });
  4.3382 +                    }
  4.3383 +                });
  4.3384 +
  4.3385 +            // Give access to the raw computeds, as long as that wouldn't overwrite any custom param also called '$raw'
  4.3386 +            // This is in case the developer wants to react to outer (binding) observability separately from inner
  4.3387 +            // (model value) observability, or in case the model value observable has subobservables.
  4.3388 +            if (!result.hasOwnProperty('$raw')) {
  4.3389 +                result['$raw'] = rawParamComputedValues;
  4.3390 +            }
  4.3391 +
  4.3392 +            return result;
  4.3393 +        } else {
  4.3394 +            // For consistency, absence of a "params" attribute is treated the same as the presence of
  4.3395 +            // any empty one. Otherwise component viewmodels need special code to check whether or not
  4.3396 +            // 'params' or 'params.$raw' is null/undefined before reading subproperties, which is annoying.
  4.3397 +            return { '$raw': {} };
  4.3398 +        }
  4.3399 +    }
  4.3400 +
  4.3401 +    // --------------------------------------------------------------------------------
  4.3402 +    // Compatibility code for older (pre-HTML5) IE browsers
  4.3403 +
  4.3404 +    if (ko.utils.ieVersion < 9) {
  4.3405 +        // Whenever you preregister a component, enable it as a custom element in the current document
  4.3406 +        ko.components['register'] = (function(originalFunction) {
  4.3407 +            return function(componentName) {
  4.3408 +                document.createElement(componentName); // Allows IE<9 to parse markup containing the custom element
  4.3409 +                return originalFunction.apply(this, arguments);
  4.3410 +            }
  4.3411 +        })(ko.components['register']);
  4.3412 +
  4.3413 +        // Whenever you create a document fragment, enable all preregistered component names as custom elements
  4.3414 +        // This is needed to make innerShiv/jQuery HTML parsing correctly handle the custom elements
  4.3415 +        document.createDocumentFragment = (function(originalFunction) {
  4.3416 +            return function() {
  4.3417 +                var newDocFrag = originalFunction(),
  4.3418 +                    allComponents = ko.components._allRegisteredComponents;
  4.3419 +                for (var componentName in allComponents) {
  4.3420 +                    if (allComponents.hasOwnProperty(componentName)) {
  4.3421 +                        newDocFrag.createElement(componentName);
  4.3422 +                    }
  4.3423 +                }
  4.3424 +                return newDocFrag;
  4.3425 +            };
  4.3426 +        })(document.createDocumentFragment);
  4.3427 +    }
  4.3428 +})();(function(undefined) {
  4.3429 +
  4.3430 +    var componentLoadingOperationUniqueId = 0;
  4.3431 +
  4.3432 +    ko.bindingHandlers['component'] = {
  4.3433 +        'init': function(element, valueAccessor, ignored1, ignored2, bindingContext) {
  4.3434 +            var currentViewModel,
  4.3435 +                currentLoadingOperationId,
  4.3436 +                disposeAssociatedComponentViewModel = function () {
  4.3437 +                    var currentViewModelDispose = currentViewModel && currentViewModel['dispose'];
  4.3438 +                    if (typeof currentViewModelDispose === 'function') {
  4.3439 +                        currentViewModelDispose.call(currentViewModel);
  4.3440 +                    }
  4.3441 +
  4.3442 +                    // Any in-flight loading operation is no longer relevant, so make sure we ignore its completion
  4.3443 +                    currentLoadingOperationId = null;
  4.3444 +                };
  4.3445 +
  4.3446 +            ko.utils.domNodeDisposal.addDisposeCallback(element, disposeAssociatedComponentViewModel);
  4.3447 +
  4.3448 +            ko.computed(function () {
  4.3449 +                var value = ko.utils.unwrapObservable(valueAccessor()),
  4.3450 +                    componentName, componentParams;
  4.3451 +
  4.3452 +                if (typeof value === 'string') {
  4.3453 +                    componentName = value;
  4.3454 +                } else {
  4.3455 +                    componentName = ko.utils.unwrapObservable(value['name']);
  4.3456 +                    componentParams = ko.utils.unwrapObservable(value['params']);
  4.3457 +                }
  4.3458 +
  4.3459 +                if (!componentName) {
  4.3460 +                    throw new Error('No component name specified');
  4.3461 +                }
  4.3462 +
  4.3463 +                var loadingOperationId = currentLoadingOperationId = ++componentLoadingOperationUniqueId;
  4.3464 +                ko.components.get(componentName, function(componentDefinition) {
  4.3465 +                    // If this is not the current load operation for this element, ignore it.
  4.3466 +                    if (currentLoadingOperationId !== loadingOperationId) {
  4.3467 +                        return;
  4.3468 +                    }
  4.3469 +
  4.3470 +                    // Clean up previous state
  4.3471 +                    disposeAssociatedComponentViewModel();
  4.3472 +
  4.3473 +                    // Instantiate and bind new component. Implicitly this cleans any old DOM nodes.
  4.3474 +                    if (!componentDefinition) {
  4.3475 +                        throw new Error('Unknown component \'' + componentName + '\'');
  4.3476 +                    }
  4.3477 +                    cloneTemplateIntoElement(componentName, componentDefinition, element);
  4.3478 +                    var componentViewModel = createViewModel(componentDefinition, element, componentParams),
  4.3479 +                        childBindingContext = bindingContext['createChildContext'](componentViewModel);
  4.3480 +                    currentViewModel = componentViewModel;
  4.3481 +                    ko.applyBindingsToDescendants(childBindingContext, element);
  4.3482 +                });
  4.3483 +            }, null, { disposeWhenNodeIsRemoved: element });
  4.3484 +
  4.3485 +            return { 'controlsDescendantBindings': true };
  4.3486 +        }
  4.3487 +    };
  4.3488 +
  4.3489 +    ko.virtualElements.allowedBindings['component'] = true;
  4.3490 +
  4.3491 +    function cloneTemplateIntoElement(componentName, componentDefinition, element) {
  4.3492 +        var template = componentDefinition['template'];
  4.3493 +        if (!template) {
  4.3494 +            throw new Error('Component \'' + componentName + '\' has no template');
  4.3495 +        }
  4.3496 +
  4.3497 +        var clonedNodesArray = ko.utils.cloneNodes(template);
  4.3498 +        ko.virtualElements.setDomNodeChildren(element, clonedNodesArray);
  4.3499 +    }
  4.3500 +
  4.3501 +    function createViewModel(componentDefinition, element, componentParams) {
  4.3502 +        var componentViewModelFactory = componentDefinition['createViewModel'];
  4.3503 +        return componentViewModelFactory
  4.3504 +            ? componentViewModelFactory.call(componentDefinition, componentParams, { element: element })
  4.3505 +            : componentParams; // Template-only component
  4.3506 +    }
  4.3507 +
  4.3508 +})();
  4.3509 +var attrHtmlToJavascriptMap = { 'class': 'className', 'for': 'htmlFor' };
  4.3510 +ko.bindingHandlers['attr'] = {
  4.3511 +    'update': function(element, valueAccessor, allBindings) {
  4.3512 +        var value = ko.utils.unwrapObservable(valueAccessor()) || {};
  4.3513 +        ko.utils.objectForEach(value, function(attrName, attrValue) {
  4.3514 +            attrValue = ko.utils.unwrapObservable(attrValue);
  4.3515 +
  4.3516 +            // To cover cases like "attr: { checked:someProp }", we want to remove the attribute entirely
  4.3517 +            // when someProp is a "no value"-like value (strictly null, false, or undefined)
  4.3518 +            // (because the absence of the "checked" attr is how to mark an element as not checked, etc.)
  4.3519 +            var toRemove = (attrValue === false) || (attrValue === null) || (attrValue === undefined);
  4.3520 +            if (toRemove)
  4.3521 +                element.removeAttribute(attrName);
  4.3522 +
  4.3523 +            // In IE <= 7 and IE8 Quirks Mode, you have to use the Javascript property name instead of the
  4.3524 +            // HTML attribute name for certain attributes. IE8 Standards Mode supports the correct behavior,
  4.3525 +            // but instead of figuring out the mode, we'll just set the attribute through the Javascript
  4.3526 +            // property for IE <= 8.
  4.3527 +            if (ko.utils.ieVersion <= 8 && attrName in attrHtmlToJavascriptMap) {
  4.3528 +                attrName = attrHtmlToJavascriptMap[attrName];
  4.3529 +                if (toRemove)
  4.3530 +                    element.removeAttribute(attrName);
  4.3531 +                else
  4.3532 +                    element[attrName] = attrValue;
  4.3533 +            } else if (!toRemove) {
  4.3534 +                element.setAttribute(attrName, attrValue.toString());
  4.3535 +            }
  4.3536 +
  4.3537 +            // Treat "name" specially - although you can think of it as an attribute, it also needs
  4.3538 +            // special handling on older versions of IE (https://github.com/SteveSanderson/knockout/pull/333)
  4.3539 +            // Deliberately being case-sensitive here because XHTML would regard "Name" as a different thing
  4.3540 +            // entirely, and there's no strong reason to allow for such casing in HTML.
  4.3541 +            if (attrName === "name") {
  4.3542 +                ko.utils.setElementName(element, toRemove ? "" : attrValue.toString());
  4.3543 +            }
  4.3544 +        });
  4.3545 +    }
  4.3546 +};
  4.3547 +(function() {
  4.3548 +
  4.3549 +ko.bindingHandlers['checked'] = {
  4.3550 +    'after': ['value', 'attr'],
  4.3551 +    'init': function (element, valueAccessor, allBindings) {
  4.3552 +        var checkedValue = ko.pureComputed(function() {
  4.3553 +            // Treat "value" like "checkedValue" when it is included with "checked" binding
  4.3554 +            if (allBindings['has']('checkedValue')) {
  4.3555 +                return ko.utils.unwrapObservable(allBindings.get('checkedValue'));
  4.3556 +            } else if (allBindings['has']('value')) {
  4.3557 +                return ko.utils.unwrapObservable(allBindings.get('value'));
  4.3558 +            }
  4.3559 +
  4.3560 +            return element.value;
  4.3561 +        });
  4.3562 +
  4.3563 +        function updateModel() {
  4.3564 +            // This updates the model value from the view value.
  4.3565 +            // It runs in response to DOM events (click) and changes in checkedValue.
  4.3566 +            var isChecked = element.checked,
  4.3567 +                elemValue = useCheckedValue ? checkedValue() : isChecked;
  4.3568 +
  4.3569 +            // When we're first setting up this computed, don't change any model state.
  4.3570 +            if (ko.computedContext.isInitial()) {
  4.3571 +                return;
  4.3572 +            }
  4.3573 +
  4.3574 +            // We can ignore unchecked radio buttons, because some other radio
  4.3575 +            // button will be getting checked, and that one can take care of updating state.
  4.3576 +            if (isRadio && !isChecked) {
  4.3577 +                return;
  4.3578 +            }
  4.3579 +
  4.3580 +            var modelValue = ko.dependencyDetection.ignore(valueAccessor);
  4.3581 +            if (isValueArray) {
  4.3582 +                if (oldElemValue !== elemValue) {
  4.3583 +                    // When we're responding to the checkedValue changing, and the element is
  4.3584 +                    // currently checked, replace the old elem value with the new elem value
  4.3585 +                    // in the model array.
  4.3586 +                    if (isChecked) {
  4.3587 +                        ko.utils.addOrRemoveItem(modelValue, elemValue, true);
  4.3588 +                        ko.utils.addOrRemoveItem(modelValue, oldElemValue, false);
  4.3589 +                    }
  4.3590 +
  4.3591 +                    oldElemValue = elemValue;
  4.3592 +                } else {
  4.3593 +                    // When we're responding to the user having checked/unchecked a checkbox,
  4.3594 +                    // add/remove the element value to the model array.
  4.3595 +                    ko.utils.addOrRemoveItem(modelValue, elemValue, isChecked);
  4.3596 +                }
  4.3597 +            } else {
  4.3598 +                ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'checked', elemValue, true);
  4.3599 +            }
  4.3600 +        };
  4.3601 +
  4.3602 +        function updateView() {
  4.3603 +            // This updates the view value from the model value.
  4.3604 +            // It runs in response to changes in the bound (checked) value.
  4.3605 +            var modelValue = ko.utils.unwrapObservable(valueAccessor());
  4.3606 +
  4.3607 +            if (isValueArray) {
  4.3608 +                // When a checkbox is bound to an array, being checked represents its value being present in that array
  4.3609 +                element.checked = ko.utils.arrayIndexOf(modelValue, checkedValue()) >= 0;
  4.3610 +            } else if (isCheckbox) {
  4.3611 +                // When a checkbox is bound to any other value (not an array), being checked represents the value being trueish
  4.3612 +                element.checked = modelValue;
  4.3613 +            } else {
  4.3614 +                // For radio buttons, being checked means that the radio button's value corresponds to the model value
  4.3615 +                element.checked = (checkedValue() === modelValue);
  4.3616 +            }
  4.3617 +        };
  4.3618 +
  4.3619 +        var isCheckbox = element.type == "checkbox",
  4.3620 +            isRadio = element.type == "radio";
  4.3621 +
  4.3622 +        // Only bind to check boxes and radio buttons
  4.3623 +        if (!isCheckbox && !isRadio) {
  4.3624 +            return;
  4.3625 +        }
  4.3626 +
  4.3627 +        var isValueArray = isCheckbox && (ko.utils.unwrapObservable(valueAccessor()) instanceof Array),
  4.3628 +            oldElemValue = isValueArray ? checkedValue() : undefined,
  4.3629 +            useCheckedValue = isRadio || isValueArray;
  4.3630 +
  4.3631 +        // IE 6 won't allow radio buttons to be selected unless they have a name
  4.3632 +        if (isRadio && !element.name)
  4.3633 +            ko.bindingHandlers['uniqueName']['init'](element, function() { return true });
  4.3634 +
  4.3635 +        // Set up two computeds to update the binding:
  4.3636 +
  4.3637 +        // The first responds to changes in the checkedValue value and to element clicks
  4.3638 +        ko.computed(updateModel, null, { disposeWhenNodeIsRemoved: element });
  4.3639 +        ko.utils.registerEventHandler(element, "click", updateModel);
  4.3640 +
  4.3641 +        // The second responds to changes in the model value (the one associated with the checked binding)
  4.3642 +        ko.computed(updateView, null, { disposeWhenNodeIsRemoved: element });
  4.3643 +    }
  4.3644 +};
  4.3645 +ko.expressionRewriting.twoWayBindings['checked'] = true;
  4.3646 +
  4.3647 +ko.bindingHandlers['checkedValue'] = {
  4.3648 +    'update': function (element, valueAccessor) {
  4.3649 +        element.value = ko.utils.unwrapObservable(valueAccessor());
  4.3650 +    }
  4.3651 +};
  4.3652 +
  4.3653 +})();var classesWrittenByBindingKey = '__ko__cssValue';
  4.3654 +ko.bindingHandlers['css'] = {
  4.3655 +    'update': function (element, valueAccessor) {
  4.3656 +        var value = ko.utils.unwrapObservable(valueAccessor());
  4.3657 +        if (typeof value == "object") {
  4.3658 +            ko.utils.objectForEach(value, function(className, shouldHaveClass) {
  4.3659 +                shouldHaveClass = ko.utils.unwrapObservable(shouldHaveClass);
  4.3660 +                ko.utils.toggleDomNodeCssClass(element, className, shouldHaveClass);
  4.3661 +            });
  4.3662 +        } else {
  4.3663 +            value = String(value || ''); // Make sure we don't try to store or set a non-string value
  4.3664 +            ko.utils.toggleDomNodeCssClass(element, element[classesWrittenByBindingKey], false);
  4.3665 +            element[classesWrittenByBindingKey] = value;
  4.3666 +            ko.utils.toggleDomNodeCssClass(element, value, true);
  4.3667 +        }
  4.3668 +    }
  4.3669 +};
  4.3670 +ko.bindingHandlers['enable'] = {
  4.3671 +    'update': function (element, valueAccessor) {
  4.3672 +        var value = ko.utils.unwrapObservable(valueAccessor());
  4.3673 +        if (value && element.disabled)
  4.3674 +            element.removeAttribute("disabled");
  4.3675 +        else if ((!value) && (!element.disabled))
  4.3676 +            element.disabled = true;
  4.3677 +    }
  4.3678 +};
  4.3679 +
  4.3680 +ko.bindingHandlers['disable'] = {
  4.3681 +    'update': function (element, valueAccessor) {
  4.3682 +        ko.bindingHandlers['enable']['update'](element, function() { return !ko.utils.unwrapObservable(valueAccessor()) });
  4.3683 +    }
  4.3684 +};
  4.3685 +// For certain common events (currently just 'click'), allow a simplified data-binding syntax
  4.3686 +// e.g. click:handler instead of the usual full-length event:{click:handler}
  4.3687 +function makeEventHandlerShortcut(eventName) {
  4.3688 +    ko.bindingHandlers[eventName] = {
  4.3689 +        'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
  4.3690 +            var newValueAccessor = function () {
  4.3691 +                var result = {};
  4.3692 +                result[eventName] = valueAccessor();
  4.3693 +                return result;
  4.3694 +            };
  4.3695 +            return ko.bindingHandlers['event']['init'].call(this, element, newValueAccessor, allBindings, viewModel, bindingContext);
  4.3696 +        }
  4.3697 +    }
  4.3698 +}
  4.3699 +
  4.3700 +ko.bindingHandlers['event'] = {
  4.3701 +    'init' : function (element, valueAccessor, allBindings, viewModel, bindingContext) {
  4.3702 +        var eventsToHandle = valueAccessor() || {};
  4.3703 +        ko.utils.objectForEach(eventsToHandle, function(eventName) {
  4.3704 +            if (typeof eventName == "string") {
  4.3705 +                ko.utils.registerEventHandler(element, eventName, function (event) {
  4.3706 +                    var handlerReturnValue;
  4.3707 +                    var handlerFunction = valueAccessor()[eventName];
  4.3708 +                    if (!handlerFunction)
  4.3709 +                        return;
  4.3710 +
  4.3711 +                    try {
  4.3712 +                        // Take all the event args, and prefix with the viewmodel
  4.3713 +                        var argsForHandler = ko.utils.makeArray(arguments);
  4.3714 +                        viewModel = bindingContext['$data'];
  4.3715 +                        argsForHandler.unshift(viewModel);
  4.3716 +                        handlerReturnValue = handlerFunction.apply(viewModel, argsForHandler);
  4.3717 +                    } finally {
  4.3718 +                        if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
  4.3719 +                            if (event.preventDefault)
  4.3720 +                                event.preventDefault();
  4.3721 +                            else
  4.3722 +                                event.returnValue = false;
  4.3723 +                        }
  4.3724 +                    }
  4.3725 +
  4.3726 +                    var bubble = allBindings.get(eventName + 'Bubble') !== false;
  4.3727 +                    if (!bubble) {
  4.3728 +                        event.cancelBubble = true;
  4.3729 +                        if (event.stopPropagation)
  4.3730 +                            event.stopPropagation();
  4.3731 +                    }
  4.3732 +                });
  4.3733 +            }
  4.3734 +        });
  4.3735 +    }
  4.3736 +};
  4.3737 +// "foreach: someExpression" is equivalent to "template: { foreach: someExpression }"
  4.3738 +// "foreach: { data: someExpression, afterAdd: myfn }" is equivalent to "template: { foreach: someExpression, afterAdd: myfn }"
  4.3739 +ko.bindingHandlers['foreach'] = {
  4.3740 +    makeTemplateValueAccessor: function(valueAccessor) {
  4.3741 +        return function() {
  4.3742 +            var modelValue = valueAccessor(),
  4.3743 +                unwrappedValue = ko.utils.peekObservable(modelValue);    // Unwrap without setting a dependency here
  4.3744 +
  4.3745 +            // If unwrappedValue is the array, pass in the wrapped value on its own
  4.3746 +            // The value will be unwrapped and tracked within the template binding
  4.3747 +            // (See https://github.com/SteveSanderson/knockout/issues/523)
  4.3748 +            if ((!unwrappedValue) || typeof unwrappedValue.length == "number")
  4.3749 +                return { 'foreach': modelValue, 'templateEngine': ko.nativeTemplateEngine.instance };
  4.3750 +
  4.3751 +            // If unwrappedValue.data is the array, preserve all relevant options and unwrap again value so we get updates
  4.3752 +            ko.utils.unwrapObservable(modelValue);
  4.3753 +            return {
  4.3754 +                'foreach': unwrappedValue['data'],
  4.3755 +                'as': unwrappedValue['as'],
  4.3756 +                'includeDestroyed': unwrappedValue['includeDestroyed'],
  4.3757 +                'afterAdd': unwrappedValue['afterAdd'],
  4.3758 +                'beforeRemove': unwrappedValue['beforeRemove'],
  4.3759 +                'afterRender': unwrappedValue['afterRender'],
  4.3760 +                'beforeMove': unwrappedValue['beforeMove'],
  4.3761 +                'afterMove': unwrappedValue['afterMove'],
  4.3762 +                'templateEngine': ko.nativeTemplateEngine.instance
  4.3763 +            };
  4.3764 +        };
  4.3765 +    },
  4.3766 +    'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
  4.3767 +        return ko.bindingHandlers['template']['init'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor));
  4.3768 +    },
  4.3769 +    'update': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
  4.3770 +        return ko.bindingHandlers['template']['update'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor), allBindings, viewModel, bindingContext);
  4.3771 +    }
  4.3772 +};
  4.3773 +ko.expressionRewriting.bindingRewriteValidators['foreach'] = false; // Can't rewrite control flow bindings
  4.3774 +ko.virtualElements.allowedBindings['foreach'] = true;
  4.3775 +var hasfocusUpdatingProperty = '__ko_hasfocusUpdating';
  4.3776 +var hasfocusLastValue = '__ko_hasfocusLastValue';
  4.3777 +ko.bindingHandlers['hasfocus'] = {
  4.3778 +    'init': function(element, valueAccessor, allBindings) {
  4.3779 +        var handleElementFocusChange = function(isFocused) {
  4.3780 +            // Where possible, ignore which event was raised and determine focus state using activeElement,
  4.3781 +            // as this avoids phantom focus/blur events raised when changing tabs in modern browsers.
  4.3782 +            // However, not all KO-targeted browsers (Firefox 2) support activeElement. For those browsers,
  4.3783 +            // prevent a loss of focus when changing tabs/windows by setting a flag that prevents hasfocus
  4.3784 +            // from calling 'blur()' on the element when it loses focus.
  4.3785 +            // Discussion at https://github.com/SteveSanderson/knockout/pull/352
  4.3786 +            element[hasfocusUpdatingProperty] = true;
  4.3787 +            var ownerDoc = element.ownerDocument;
  4.3788 +            if ("activeElement" in ownerDoc) {
  4.3789 +                var active;
  4.3790 +                try {
  4.3791 +                    active = ownerDoc.activeElement;
  4.3792 +                } catch(e) {
  4.3793 +                    // IE9 throws if you access activeElement during page load (see issue #703)
  4.3794 +                    active = ownerDoc.body;
  4.3795 +                }
  4.3796 +                isFocused = (active === element);
  4.3797 +            }
  4.3798 +            var modelValue = valueAccessor();
  4.3799 +            ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'hasfocus', isFocused, true);
  4.3800 +
  4.3801 +            //cache the latest value, so we can avoid unnecessarily calling focus/blur in the update function
  4.3802 +            element[hasfocusLastValue] = isFocused;
  4.3803 +            element[hasfocusUpdatingProperty] = false;
  4.3804 +        };
  4.3805 +        var handleElementFocusIn = handleElementFocusChange.bind(null, true);
  4.3806 +        var handleElementFocusOut = handleElementFocusChange.bind(null, false);
  4.3807 +
  4.3808 +        ko.utils.registerEventHandler(element, "focus", handleElementFocusIn);
  4.3809 +        ko.utils.registerEventHandler(element, "focusin", handleElementFocusIn); // For IE
  4.3810 +        ko.utils.registerEventHandler(element, "blur",  handleElementFocusOut);
  4.3811 +        ko.utils.registerEventHandler(element, "focusout",  handleElementFocusOut); // For IE
  4.3812 +    },
  4.3813 +    'update': function(element, valueAccessor) {
  4.3814 +        var value = !!ko.utils.unwrapObservable(valueAccessor()); //force boolean to compare with last value
  4.3815 +        if (!element[hasfocusUpdatingProperty] && element[hasfocusLastValue] !== value) {
  4.3816 +            value ? element.focus() : element.blur();
  4.3817 +            ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, value ? "focusin" : "focusout"]); // For IE, which doesn't reliably fire "focus" or "blur" events synchronously
  4.3818 +        }
  4.3819 +    }
  4.3820 +};
  4.3821 +ko.expressionRewriting.twoWayBindings['hasfocus'] = true;
  4.3822 +
  4.3823 +ko.bindingHandlers['hasFocus'] = ko.bindingHandlers['hasfocus']; // Make "hasFocus" an alias
  4.3824 +ko.expressionRewriting.twoWayBindings['hasFocus'] = true;
  4.3825 +ko.bindingHandlers['html'] = {
  4.3826 +    'init': function() {
  4.3827 +        // Prevent binding on the dynamically-injected HTML (as developers are unlikely to expect that, and it has security implications)
  4.3828 +        return { 'controlsDescendantBindings': true };
  4.3829 +    },
  4.3830 +    'update': function (element, valueAccessor) {
  4.3831 +        // setHtml will unwrap the value if needed
  4.3832 +        ko.utils.setHtml(element, valueAccessor());
  4.3833 +    }
  4.3834 +};
  4.3835 +// Makes a binding like with or if
  4.3836 +function makeWithIfBinding(bindingKey, isWith, isNot, makeContextCallback) {
  4.3837 +    ko.bindingHandlers[bindingKey] = {
  4.3838 +        'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
  4.3839 +            var didDisplayOnLastUpdate,
  4.3840 +                savedNodes;
  4.3841 +            ko.computed(function() {
  4.3842 +                var dataValue = ko.utils.unwrapObservable(valueAccessor()),
  4.3843 +                    shouldDisplay = !isNot !== !dataValue, // equivalent to isNot ? !dataValue : !!dataValue
  4.3844 +                    isFirstRender = !savedNodes,
  4.3845 +                    needsRefresh = isFirstRender || isWith || (shouldDisplay !== didDisplayOnLastUpdate);
  4.3846 +
  4.3847 +                if (needsRefresh) {
  4.3848 +                    // Save a copy of the inner nodes on the initial update, but only if we have dependencies.
  4.3849 +                    if (isFirstRender && ko.computedContext.getDependenciesCount()) {
  4.3850 +                        savedNodes = ko.utils.cloneNodes(ko.virtualElements.childNodes(element), true /* shouldCleanNodes */);
  4.3851 +                    }
  4.3852 +
  4.3853 +                    if (shouldDisplay) {
  4.3854 +                        if (!isFirstRender) {
  4.3855 +                            ko.virtualElements.setDomNodeChildren(element, ko.utils.cloneNodes(savedNodes));
  4.3856 +                        }
  4.3857 +                        ko.applyBindingsToDescendants(makeContextCallback ? makeContextCallback(bindingContext, dataValue) : bindingContext, element);
  4.3858 +                    } else {
  4.3859 +                        ko.virtualElements.emptyNode(element);
  4.3860 +                    }
  4.3861 +
  4.3862 +                    didDisplayOnLastUpdate = shouldDisplay;
  4.3863 +                }
  4.3864 +            }, null, { disposeWhenNodeIsRemoved: element });
  4.3865 +            return { 'controlsDescendantBindings': true };
  4.3866 +        }
  4.3867 +    };
  4.3868 +    ko.expressionRewriting.bindingRewriteValidators[bindingKey] = false; // Can't rewrite control flow bindings
  4.3869 +    ko.virtualElements.allowedBindings[bindingKey] = true;
  4.3870 +}
  4.3871 +
  4.3872 +// Construct the actual binding handlers
  4.3873 +makeWithIfBinding('if');
  4.3874 +makeWithIfBinding('ifnot', false /* isWith */, true /* isNot */);
  4.3875 +makeWithIfBinding('with', true /* isWith */, false /* isNot */,
  4.3876 +    function(bindingContext, dataValue) {
  4.3877 +        return bindingContext['createChildContext'](dataValue);
  4.3878 +    }
  4.3879 +);
  4.3880 +var captionPlaceholder = {};
  4.3881 +ko.bindingHandlers['options'] = {
  4.3882 +    'init': function(element) {
  4.3883 +        if (ko.utils.tagNameLower(element) !== "select")
  4.3884 +            throw new Error("options binding applies only to SELECT elements");
  4.3885 +
  4.3886 +        // Remove all existing <option>s.
  4.3887 +        while (element.length > 0) {
  4.3888 +            element.remove(0);
  4.3889 +        }
  4.3890 +
  4.3891 +        // Ensures that the binding processor doesn't try to bind the options
  4.3892 +        return { 'controlsDescendantBindings': true };
  4.3893 +    },
  4.3894 +    'update': function (element, valueAccessor, allBindings) {
  4.3895 +        function selectedOptions() {
  4.3896 +            return ko.utils.arrayFilter(element.options, function (node) { return node.selected; });
  4.3897 +        }
  4.3898 +
  4.3899 +        var selectWasPreviouslyEmpty = element.length == 0;
  4.3900 +        var previousScrollTop = (!selectWasPreviouslyEmpty && element.multiple) ? element.scrollTop : null;
  4.3901 +        var unwrappedArray = ko.utils.unwrapObservable(valueAccessor());
  4.3902 +        var includeDestroyed = allBindings.get('optionsIncludeDestroyed');
  4.3903 +        var arrayToDomNodeChildrenOptions = {};
  4.3904 +        var captionValue;
  4.3905 +        var filteredArray;
  4.3906 +        var previousSelectedValues;
  4.3907 +
  4.3908 +        if (element.multiple) {
  4.3909 +            previousSelectedValues = ko.utils.arrayMap(selectedOptions(), ko.selectExtensions.readValue);
  4.3910 +        } else {
  4.3911 +            previousSelectedValues = element.selectedIndex >= 0 ? [ ko.selectExtensions.readValue(element.options[element.selectedIndex]) ] : [];
  4.3912 +        }
  4.3913 +
  4.3914 +        if (unwrappedArray) {
  4.3915 +            if (typeof unwrappedArray.length == "undefined") // Coerce single value into array
  4.3916 +                unwrappedArray = [unwrappedArray];
  4.3917 +
  4.3918 +            // Filter out any entries marked as destroyed
  4.3919 +            filteredArray = ko.utils.arrayFilter(unwrappedArray, function(item) {
  4.3920 +                return includeDestroyed || item === undefined || item === null || !ko.utils.unwrapObservable(item['_destroy']);
  4.3921 +            });
  4.3922 +
  4.3923 +            // If caption is included, add it to the array
  4.3924 +            if (allBindings['has']('optionsCaption')) {
  4.3925 +                captionValue = ko.utils.unwrapObservable(allBindings.get('optionsCaption'));
  4.3926 +                // If caption value is null or undefined, don't show a caption
  4.3927 +                if (captionValue !== null && captionValue !== undefined) {
  4.3928 +                    filteredArray.unshift(captionPlaceholder);
  4.3929 +                }
  4.3930 +            }
  4.3931 +        } else {
  4.3932 +            // If a falsy value is provided (e.g. null), we'll simply empty the select element
  4.3933 +        }
  4.3934 +
  4.3935 +        function applyToObject(object, predicate, defaultValue) {
  4.3936 +            var predicateType = typeof predicate;
  4.3937 +            if (predicateType == "function")    // Given a function; run it against the data value
  4.3938 +                return predicate(object);
  4.3939 +            else if (predicateType == "string") // Given a string; treat it as a property name on the data value
  4.3940 +                return object[predicate];
  4.3941 +            else                                // Given no optionsText arg; use the data value itself
  4.3942 +                return defaultValue;
  4.3943 +        }
  4.3944 +
  4.3945 +        // The following functions can run at two different times:
  4.3946 +        // The first is when the whole array is being updated directly from this binding handler.
  4.3947 +        // The second is when an observable value for a specific array entry is updated.
  4.3948 +        // oldOptions will be empty in the first case, but will be filled with the previously generated option in the second.
  4.3949 +        var itemUpdate = false;
  4.3950 +        function optionForArrayItem(arrayEntry, index, oldOptions) {
  4.3951 +            if (oldOptions.length) {
  4.3952 +                previousSelectedValues = oldOptions[0].selected ? [ ko.selectExtensions.readValue(oldOptions[0]) ] : [];
  4.3953 +                itemUpdate = true;
  4.3954 +            }
  4.3955 +            var option = element.ownerDocument.createElement("option");
  4.3956 +            if (arrayEntry === captionPlaceholder) {
  4.3957 +                ko.utils.setTextContent(option, allBindings.get('optionsCaption'));
  4.3958 +                ko.selectExtensions.writeValue(option, undefined);
  4.3959 +            } else {
  4.3960 +                // Apply a value to the option element
  4.3961 +                var optionValue = applyToObject(arrayEntry, allBindings.get('optionsValue'), arrayEntry);
  4.3962 +                ko.selectExtensions.writeValue(option, ko.utils.unwrapObservable(optionValue));
  4.3963 +
  4.3964 +                // Apply some text to the option element
  4.3965 +                var optionText = applyToObject(arrayEntry, allBindings.get('optionsText'), optionValue);
  4.3966 +                ko.utils.setTextContent(option, optionText);
  4.3967 +            }
  4.3968 +            return [option];
  4.3969 +        }
  4.3970 +
  4.3971 +        // By using a beforeRemove callback, we delay the removal until after new items are added. This fixes a selection
  4.3972 +        // problem in IE<=8 and Firefox. See https://github.com/knockout/knockout/issues/1208
  4.3973 +        arrayToDomNodeChildrenOptions['beforeRemove'] =
  4.3974 +            function (option) {
  4.3975 +                element.removeChild(option);
  4.3976 +            };
  4.3977 +
  4.3978 +        function setSelectionCallback(arrayEntry, newOptions) {
  4.3979 +            // IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document.
  4.3980 +            // That's why we first added them without selection. Now it's time to set the selection.
  4.3981 +            if (previousSelectedValues.length) {
  4.3982 +                var isSelected = ko.utils.arrayIndexOf(previousSelectedValues, ko.selectExtensions.readValue(newOptions[0])) >= 0;
  4.3983 +                ko.utils.setOptionNodeSelectionState(newOptions[0], isSelected);
  4.3984 +
  4.3985 +                // If this option was changed from being selected during a single-item update, notify the change
  4.3986 +                if (itemUpdate && !isSelected)
  4.3987 +                    ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, "change"]);
  4.3988 +            }
  4.3989 +        }
  4.3990 +
  4.3991 +        var callback = setSelectionCallback;
  4.3992 +        if (allBindings['has']('optionsAfterRender')) {
  4.3993 +            callback = function(arrayEntry, newOptions) {
  4.3994 +                setSelectionCallback(arrayEntry, newOptions);
  4.3995 +                ko.dependencyDetection.ignore(allBindings.get('optionsAfterRender'), null, [newOptions[0], arrayEntry !== captionPlaceholder ? arrayEntry : undefined]);
  4.3996 +            }
  4.3997 +        }
  4.3998 +
  4.3999 +        ko.utils.setDomNodeChildrenFromArrayMapping(element, filteredArray, optionForArrayItem, arrayToDomNodeChildrenOptions, callback);
  4.4000 +
  4.4001 +        ko.dependencyDetection.ignore(function () {
  4.4002 +            if (allBindings.get('valueAllowUnset') && allBindings['has']('value')) {
  4.4003 +                // The model value is authoritative, so make sure its value is the one selected
  4.4004 +                ko.selectExtensions.writeValue(element, ko.utils.unwrapObservable(allBindings.get('value')), true /* allowUnset */);
  4.4005 +            } else {
  4.4006 +                // Determine if the selection has changed as a result of updating the options list
  4.4007 +                var selectionChanged;
  4.4008 +                if (element.multiple) {
  4.4009 +                    // For a multiple-select box, compare the new selection count to the previous one
  4.4010 +                    // But if nothing was selected before, the selection can't have changed
  4.4011 +                    selectionChanged = previousSelectedValues.length && selectedOptions().length < previousSelectedValues.length;
  4.4012 +                } else {
  4.4013 +                    // For a single-select box, compare the current value to the previous value
  4.4014 +                    // But if nothing was selected before or nothing is selected now, just look for a change in selection
  4.4015 +                    selectionChanged = (previousSelectedValues.length && element.selectedIndex >= 0)
  4.4016 +                        ? (ko.selectExtensions.readValue(element.options[element.selectedIndex]) !== previousSelectedValues[0])
  4.4017 +                        : (previousSelectedValues.length || element.selectedIndex >= 0);
  4.4018 +                }
  4.4019 +
  4.4020 +                // Ensure consistency between model value and selected option.
  4.4021 +                // If the dropdown was changed so that selection is no longer the same,
  4.4022 +                // notify the value or selectedOptions binding.
  4.4023 +                if (selectionChanged) {
  4.4024 +                    ko.utils.triggerEvent(element, "change");
  4.4025 +                }
  4.4026 +            }
  4.4027 +        });
  4.4028 +
  4.4029 +        // Workaround for IE bug
  4.4030 +        ko.utils.ensureSelectElementIsRenderedCorrectly(element);
  4.4031 +
  4.4032 +        if (previousScrollTop && Math.abs(previousScrollTop - element.scrollTop) > 20)
  4.4033 +            element.scrollTop = previousScrollTop;
  4.4034 +    }
  4.4035 +};
  4.4036 +ko.bindingHandlers['options'].optionValueDomDataKey = ko.utils.domData.nextKey();
  4.4037 +ko.bindingHandlers['selectedOptions'] = {
  4.4038 +    'after': ['options', 'foreach'],
  4.4039 +    'init': function (element, valueAccessor, allBindings) {
  4.4040 +        ko.utils.registerEventHandler(element, "change", function () {
  4.4041 +            var value = valueAccessor(), valueToWrite = [];
  4.4042 +            ko.utils.arrayForEach(element.getElementsByTagName("option"), function(node) {
  4.4043 +                if (node.selected)
  4.4044 +                    valueToWrite.push(ko.selectExtensions.readValue(node));
  4.4045 +            });
  4.4046 +            ko.expressionRewriting.writeValueToProperty(value, allBindings, 'selectedOptions', valueToWrite);
  4.4047 +        });
  4.4048 +    },
  4.4049 +    'update': function (element, valueAccessor) {
  4.4050 +        if (ko.utils.tagNameLower(element) != "select")
  4.4051 +            throw new Error("values binding applies only to SELECT elements");
  4.4052 +
  4.4053 +        var newValue = ko.utils.unwrapObservable(valueAccessor());
  4.4054 +        if (newValue && typeof newValue.length == "number") {
  4.4055 +            ko.utils.arrayForEach(element.getElementsByTagName("option"), function(node) {
  4.4056 +                var isSelected = ko.utils.arrayIndexOf(newValue, ko.selectExtensions.readValue(node)) >= 0;
  4.4057 +                ko.utils.setOptionNodeSelectionState(node, isSelected);
  4.4058 +            });
  4.4059 +        }
  4.4060 +    }
  4.4061 +};
  4.4062 +ko.expressionRewriting.twoWayBindings['selectedOptions'] = true;
  4.4063 +ko.bindingHandlers['style'] = {
  4.4064 +    'update': function (element, valueAccessor) {
  4.4065 +        var value = ko.utils.unwrapObservable(valueAccessor() || {});
  4.4066 +        ko.utils.objectForEach(value, function(styleName, styleValue) {
  4.4067 +            styleValue = ko.utils.unwrapObservable(styleValue);
  4.4068 +
  4.4069 +            if (styleValue === null || styleValue === undefined || styleValue === false) {
  4.4070 +                // Empty string removes the value, whereas null/undefined have no effect
  4.4071 +                styleValue = "";
  4.4072 +            }
  4.4073 +
  4.4074 +            element.style[styleName] = styleValue;
  4.4075 +        });
  4.4076 +    }
  4.4077 +};
  4.4078 +ko.bindingHandlers['submit'] = {
  4.4079 +    'init': function (element, valueAccessor, allBindings, viewModel, bindingContext) {
  4.4080 +        if (typeof valueAccessor() != "function")
  4.4081 +            throw new Error("The value for a submit binding must be a function");
  4.4082 +        ko.utils.registerEventHandler(element, "submit", function (event) {
  4.4083 +            var handlerReturnValue;
  4.4084 +            var value = valueAccessor();
  4.4085 +            try { handlerReturnValue = value.call(bindingContext['$data'], element); }
  4.4086 +            finally {
  4.4087 +                if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
  4.4088 +                    if (event.preventDefault)
  4.4089 +                        event.preventDefault();
  4.4090 +                    else
  4.4091 +                        event.returnValue = false;
  4.4092 +                }
  4.4093 +            }
  4.4094 +        });
  4.4095 +    }
  4.4096 +};
  4.4097 +ko.bindingHandlers['text'] = {
  4.4098 +    'init': function() {
  4.4099 +        // Prevent binding on the dynamically-injected text node (as developers are unlikely to expect that, and it has security implications).
  4.4100 +        // It should also make things faster, as we no longer have to consider whether the text node might be bindable.
  4.4101 +        return { 'controlsDescendantBindings': true };
  4.4102 +    },
  4.4103 +    'update': function (element, valueAccessor) {
  4.4104 +        ko.utils.setTextContent(element, valueAccessor());
  4.4105 +    }
  4.4106 +};
  4.4107 +ko.virtualElements.allowedBindings['text'] = true;
  4.4108 +(function () {
  4.4109 +
  4.4110 +if (window && window.navigator) {
  4.4111 +    var parseVersion = function (matches) {
  4.4112 +        if (matches) {
  4.4113 +            return parseFloat(matches[1]);
  4.4114 +        }
  4.4115 +    };
  4.4116 +
  4.4117 +    // Detect various browser versions because some old versions don't fully support the 'input' event
  4.4118 +    var operaVersion = window.opera && window.opera.version && parseInt(window.opera.version()),
  4.4119 +        userAgent = window.navigator.userAgent,
  4.4120 +        safariVersion = parseVersion(userAgent.match(/^(?:(?!chrome).)*version\/([^ ]*) safari/i)),
  4.4121 +        firefoxVersion = parseVersion(userAgent.match(/Firefox\/([^ ]*)/));
  4.4122 +}
  4.4123 +
  4.4124 +// IE 8 and 9 have bugs that prevent the normal events from firing when the value changes.
  4.4125 +// But it does fire the 'selectionchange' event on many of those, presumably because the
  4.4126 +// cursor is moving and that counts as the selection changing. The 'selectionchange' event is
  4.4127 +// fired at the document level only and doesn't directly indicate which element changed. We
  4.4128 +// set up just one event handler for the document and use 'activeElement' to determine which
  4.4129 +// element was changed.
  4.4130 +if (ko.utils.ieVersion < 10) {
  4.4131 +    var selectionChangeRegisteredName = ko.utils.domData.nextKey(),
  4.4132 +        selectionChangeHandlerName = ko.utils.domData.nextKey();
  4.4133 +    var selectionChangeHandler = function(event) {
  4.4134 +        var target = this.activeElement,
  4.4135 +            handler = target && ko.utils.domData.get(target, selectionChangeHandlerName);
  4.4136 +        if (handler) {
  4.4137 +            handler(event);
  4.4138 +        }
  4.4139 +    };
  4.4140 +    var registerForSelectionChangeEvent = function (element, handler) {
  4.4141 +        var ownerDoc = element.ownerDocument;
  4.4142 +        if (!ko.utils.domData.get(ownerDoc, selectionChangeRegisteredName)) {
  4.4143 +            ko.utils.domData.set(ownerDoc, selectionChangeRegisteredName, true);
  4.4144 +            ko.utils.registerEventHandler(ownerDoc, 'selectionchange', selectionChangeHandler);
  4.4145 +        }
  4.4146 +        ko.utils.domData.set(element, selectionChangeHandlerName, handler);
  4.4147 +    };
  4.4148 +}
  4.4149 +
  4.4150 +ko.bindingHandlers['textInput'] = {
  4.4151 +    'init': function (element, valueAccessor, allBindings) {
  4.4152 +
  4.4153 +        var previousElementValue = element.value,
  4.4154 +            timeoutHandle,
  4.4155 +            elementValueBeforeEvent;
  4.4156 +
  4.4157 +        var updateModel = function (event) {
  4.4158 +            clearTimeout(timeoutHandle);
  4.4159 +            elementValueBeforeEvent = timeoutHandle = undefined;
  4.4160 +
  4.4161 +            var elementValue = element.value;
  4.4162 +            if (previousElementValue !== elementValue) {
  4.4163 +                // Provide a way for tests to know exactly which event was processed
  4.4164 +                if (DEBUG && event) element['_ko_textInputProcessedEvent'] = event.type;
  4.4165 +                previousElementValue = elementValue;
  4.4166 +                ko.expressionRewriting.writeValueToProperty(valueAccessor(), allBindings, 'textInput', elementValue);
  4.4167 +            }
  4.4168 +        };
  4.4169 +
  4.4170 +        var deferUpdateModel = function (event) {
  4.4171 +            if (!timeoutHandle) {
  4.4172 +                // The elementValueBeforeEvent variable is set *only* during the brief gap between an
  4.4173 +                // event firing and the updateModel function running. This allows us to ignore model
  4.4174 +                // updates that are from the previous state of the element, usually due to techniques
  4.4175 +                // such as rateLimit. Such updates, if not ignored, can cause keystrokes to be lost.
  4.4176 +                elementValueBeforeEvent = element.value;
  4.4177 +                var handler = DEBUG ? updateModel.bind(element, {type: event.type}) : updateModel;
  4.4178 +                timeoutHandle = setTimeout(handler, 4);
  4.4179 +            }
  4.4180 +        };
  4.4181 +
  4.4182 +        var updateView = function () {
  4.4183 +            var modelValue = ko.utils.unwrapObservable(valueAccessor());
  4.4184 +
  4.4185 +            if (modelValue === null || modelValue === undefined) {
  4.4186 +                modelValue = '';
  4.4187 +            }
  4.4188 +
  4.4189 +            if (elementValueBeforeEvent !== undefined && modelValue === elementValueBeforeEvent) {
  4.4190 +                setTimeout(updateView, 4);
  4.4191 +                return;
  4.4192 +            }
  4.4193 +
  4.4194 +            // Update the element only if the element and model are different. On some browsers, updating the value
  4.4195 +            // will move the cursor to the end of the input, which would be bad while the user is typing.
  4.4196 +            if (element.value !== modelValue) {
  4.4197 +                previousElementValue = modelValue;  // Make sure we ignore events (propertychange) that result from updating the value
  4.4198 +                element.value = modelValue;
  4.4199 +            }
  4.4200 +        };
  4.4201 +
  4.4202 +        var onEvent = function (event, handler) {
  4.4203 +            ko.utils.registerEventHandler(element, event, handler);
  4.4204 +        };
  4.4205 +
  4.4206 +        if (DEBUG && ko.bindingHandlers['textInput']['_forceUpdateOn']) {
  4.4207 +            // Provide a way for tests to specify exactly which events are bound
  4.4208 +            ko.utils.arrayForEach(ko.bindingHandlers['textInput']['_forceUpdateOn'], function(eventName) {
  4.4209 +                if (eventName.slice(0,5) == 'after') {
  4.4210 +                    onEvent(eventName.slice(5), deferUpdateModel);
  4.4211 +                } else {
  4.4212 +                    onEvent(eventName, updateModel);
  4.4213 +                }
  4.4214 +            });
  4.4215 +        } else {
  4.4216 +            if (ko.utils.ieVersion < 10) {
  4.4217 +                // Internet Explorer <= 8 doesn't support the 'input' event, but does include 'propertychange' that fires whenever
  4.4218 +                // any property of an element changes. Unlike 'input', it also fires if a property is changed from JavaScript code,
  4.4219 +                // but that's an acceptable compromise for this binding. IE 9 does support 'input', but since it doesn't fire it
  4.4220 +                // when using autocomplete, we'll use 'propertychange' for it also.
  4.4221 +                onEvent('propertychange', function(event) {
  4.4222 +                    if (event.propertyName === 'value') {
  4.4223 +                        updateModel(event);
  4.4224 +                    }
  4.4225 +                });
  4.4226 +
  4.4227 +                if (ko.utils.ieVersion == 8) {
  4.4228 +                    // IE 8 has a bug where it fails to fire 'propertychange' on the first update following a value change from
  4.4229 +                    // JavaScript code. It also doesn't fire if you clear the entire value. To fix this, we bind to the following
  4.4230 +                    // events too.
  4.4231 +                    onEvent('keyup', updateModel);      // A single keystoke
  4.4232 +                    onEvent('keydown', updateModel);    // The first character when a key is held down
  4.4233 +                }
  4.4234 +                if (ko.utils.ieVersion >= 8) {
  4.4235 +                    // Internet Explorer 9 doesn't fire the 'input' event when deleting text, including using
  4.4236 +                    // the backspace, delete, or ctrl-x keys, clicking the 'x' to clear the input, dragging text
  4.4237 +                    // out of the field, and cutting or deleting text using the context menu. 'selectionchange'
  4.4238 +                    // can detect all of those except dragging text out of the field, for which we use 'dragend'.
  4.4239 +                    // These are also needed in IE8 because of the bug described above.
  4.4240 +                    registerForSelectionChangeEvent(element, updateModel);  // 'selectionchange' covers cut, paste, drop, delete, etc.
  4.4241 +                    onEvent('dragend', deferUpdateModel);
  4.4242 +                }
  4.4243 +            } else {
  4.4244 +                // All other supported browsers support the 'input' event, which fires whenever the content of the element is changed
  4.4245 +                // through the user interface.
  4.4246 +                onEvent('input', updateModel);
  4.4247 +
  4.4248 +                if (safariVersion < 5 && ko.utils.tagNameLower(element) === "textarea") {
  4.4249 +                    // Safari <5 doesn't fire the 'input' event for <textarea> elements (it does fire 'textInput'
  4.4250 +                    // but only when typing). So we'll just catch as much as we can with keydown, cut, and paste.
  4.4251 +                    onEvent('keydown', deferUpdateModel);
  4.4252 +                    onEvent('paste', deferUpdateModel);
  4.4253 +                    onEvent('cut', deferUpdateModel);
  4.4254 +                } else if (operaVersion < 11) {
  4.4255 +                    // Opera 10 doesn't always fire the 'input' event for cut, paste, undo & drop operations.
  4.4256 +                    // We can try to catch some of those using 'keydown'.
  4.4257 +                    onEvent('keydown', deferUpdateModel);
  4.4258 +                } else if (firefoxVersion < 4.0) {
  4.4259 +                    // Firefox <= 3.6 doesn't fire the 'input' event when text is filled in through autocomplete
  4.4260 +                    onEvent('DOMAutoComplete', updateModel);
  4.4261 +
  4.4262 +                    // Firefox <=3.5 doesn't fire the 'input' event when text is dropped into the input.
  4.4263 +                    onEvent('dragdrop', updateModel);       // <3.5
  4.4264 +                    onEvent('drop', updateModel);           // 3.5
  4.4265 +                }
  4.4266 +            }
  4.4267 +        }
  4.4268 +
  4.4269 +        // Bind to the change event so that we can catch programmatic updates of the value that fire this event.
  4.4270 +        onEvent('change', updateModel);
  4.4271 +
  4.4272 +        ko.computed(updateView, null, { disposeWhenNodeIsRemoved: element });
  4.4273 +    }
  4.4274 +};
  4.4275 +ko.expressionRewriting.twoWayBindings['textInput'] = true;
  4.4276 +
  4.4277 +// textinput is an alias for textInput
  4.4278 +ko.bindingHandlers['textinput'] = {
  4.4279 +    // preprocess is the only way to set up a full alias
  4.4280 +    'preprocess': function (value, name, addBinding) {
  4.4281 +        addBinding('textInput', value);
  4.4282 +    }
  4.4283 +};
  4.4284 +
  4.4285 +})();ko.bindingHandlers['uniqueName'] = {
  4.4286 +    'init': function (element, valueAccessor) {
  4.4287 +        if (valueAccessor()) {
  4.4288 +            var name = "ko_unique_" + (++ko.bindingHandlers['uniqueName'].currentIndex);
  4.4289 +            ko.utils.setElementName(element, name);
  4.4290 +        }
  4.4291 +    }
  4.4292 +};
  4.4293 +ko.bindingHandlers['uniqueName'].currentIndex = 0;
  4.4294 +ko.bindingHandlers['value'] = {
  4.4295 +    'after': ['options', 'foreach'],
  4.4296 +    'init': function (element, valueAccessor, allBindings) {
  4.4297 +        // If the value binding is placed on a radio/checkbox, then just pass through to checkedValue and quit
  4.4298 +        if (element.tagName.toLowerCase() == "input" && (element.type == "checkbox" || element.type == "radio")) {
  4.4299 +            ko.applyBindingAccessorsToNode(element, { 'checkedValue': valueAccessor });
  4.4300 +            return;
  4.4301 +        }
  4.4302 +
  4.4303 +        // Always catch "change" event; possibly other events too if asked
  4.4304 +        var eventsToCatch = ["change"];
  4.4305 +        var requestedEventsToCatch = allBindings.get("valueUpdate");
  4.4306 +        var propertyChangedFired = false;
  4.4307 +        var elementValueBeforeEvent = null;
  4.4308 +
  4.4309 +        if (requestedEventsToCatch) {
  4.4310 +            if (typeof requestedEventsToCatch == "string") // Allow both individual event names, and arrays of event names
  4.4311 +                requestedEventsToCatch = [requestedEventsToCatch];
  4.4312 +            ko.utils.arrayPushAll(eventsToCatch, requestedEventsToCatch);
  4.4313 +            eventsToCatch = ko.utils.arrayGetDistinctValues(eventsToCatch);
  4.4314 +        }
  4.4315 +
  4.4316 +        var valueUpdateHandler = function() {
  4.4317 +            elementValueBeforeEvent = null;
  4.4318 +            propertyChangedFired = false;
  4.4319 +            var modelValue = valueAccessor();
  4.4320 +            var elementValue = ko.selectExtensions.readValue(element);
  4.4321 +            ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'value', elementValue);
  4.4322 +        }
  4.4323 +
  4.4324 +        // Workaround for https://github.com/SteveSanderson/knockout/issues/122
  4.4325 +        // IE doesn't fire "change" events on textboxes if the user selects a value from its autocomplete list
  4.4326 +        var ieAutoCompleteHackNeeded = ko.utils.ieVersion && element.tagName.toLowerCase() == "input" && element.type == "text"
  4.4327 +                                       && element.autocomplete != "off" && (!element.form || element.form.autocomplete != "off");
  4.4328 +        if (ieAutoCompleteHackNeeded && ko.utils.arrayIndexOf(eventsToCatch, "propertychange") == -1) {
  4.4329 +            ko.utils.registerEventHandler(element, "propertychange", function () { propertyChangedFired = true });
  4.4330 +            ko.utils.registerEventHandler(element, "focus", function () { propertyChangedFired = false });
  4.4331 +            ko.utils.registerEventHandler(element, "blur", function() {
  4.4332 +                if (propertyChangedFired) {
  4.4333 +                    valueUpdateHandler();
  4.4334 +                }
  4.4335 +            });
  4.4336 +        }
  4.4337 +
  4.4338 +        ko.utils.arrayForEach(eventsToCatch, function(eventName) {
  4.4339 +            // The syntax "after<eventname>" means "run the handler asynchronously after the event"
  4.4340 +            // This is useful, for example, to catch "keydown" events after the browser has updated the control
  4.4341 +            // (otherwise, ko.selectExtensions.readValue(this) will receive the control's value *before* the key event)
  4.4342 +            var handler = valueUpdateHandler;
  4.4343 +            if (ko.utils.stringStartsWith(eventName, "after")) {
  4.4344 +                handler = function() {
  4.4345 +                    // The elementValueBeforeEvent variable is non-null *only* during the brief gap between
  4.4346 +                    // a keyX event firing and the valueUpdateHandler running, which is scheduled to happen
  4.4347 +                    // at the earliest asynchronous opportunity. We store this temporary information so that
  4.4348 +                    // if, between keyX and valueUpdateHandler, the underlying model value changes separately,
  4.4349 +                    // we can overwrite that model value change with the value the user just typed. Otherwise,
  4.4350 +                    // techniques like rateLimit can trigger model changes at critical moments that will
  4.4351 +                    // override the user's inputs, causing keystrokes to be lost.
  4.4352 +                    elementValueBeforeEvent = ko.selectExtensions.readValue(element);
  4.4353 +                    setTimeout(valueUpdateHandler, 0);
  4.4354 +                };
  4.4355 +                eventName = eventName.substring("after".length);
  4.4356 +            }
  4.4357 +            ko.utils.registerEventHandler(element, eventName, handler);
  4.4358 +        });
  4.4359 +
  4.4360 +        var updateFromModel = function () {
  4.4361 +            var newValue = ko.utils.unwrapObservable(valueAccessor());
  4.4362 +            var elementValue = ko.selectExtensions.readValue(element);
  4.4363 +
  4.4364 +            if (elementValueBeforeEvent !== null && newValue === elementValueBeforeEvent) {
  4.4365 +                setTimeout(updateFromModel, 0);
  4.4366 +                return;
  4.4367 +            }
  4.4368 +
  4.4369 +            var valueHasChanged = (newValue !== elementValue);
  4.4370 +
  4.4371 +            if (valueHasChanged) {
  4.4372 +                if (ko.utils.tagNameLower(element) === "select") {
  4.4373 +                    var allowUnset = allBindings.get('valueAllowUnset');
  4.4374 +                    var applyValueAction = function () {
  4.4375 +                        ko.selectExtensions.writeValue(element, newValue, allowUnset);
  4.4376 +                    };
  4.4377 +                    applyValueAction();
  4.4378 +
  4.4379 +                    if (!allowUnset && newValue !== ko.selectExtensions.readValue(element)) {
  4.4380 +                        // If you try to set a model value that can't be represented in an already-populated dropdown, reject that change,
  4.4381 +                        // because you're not allowed to have a model value that disagrees with a visible UI selection.
  4.4382 +                        ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, "change"]);
  4.4383 +                    } else {
  4.4384 +                        // Workaround for IE6 bug: It won't reliably apply values to SELECT nodes during the same execution thread
  4.4385 +                        // right after you've changed the set of OPTION nodes on it. So for that node type, we'll schedule a second thread
  4.4386 +                        // to apply the value as well.
  4.4387 +                        setTimeout(applyValueAction, 0);
  4.4388 +                    }
  4.4389 +                } else {
  4.4390 +                    ko.selectExtensions.writeValue(element, newValue);
  4.4391 +                }
  4.4392 +            }
  4.4393 +        };
  4.4394 +
  4.4395 +        ko.computed(updateFromModel, null, { disposeWhenNodeIsRemoved: element });
  4.4396 +    },
  4.4397 +    'update': function() {} // Keep for backwards compatibility with code that may have wrapped value binding
  4.4398 +};
  4.4399 +ko.expressionRewriting.twoWayBindings['value'] = true;
  4.4400 +ko.bindingHandlers['visible'] = {
  4.4401 +    'update': function (element, valueAccessor) {
  4.4402 +        var value = ko.utils.unwrapObservable(valueAccessor());
  4.4403 +        var isCurrentlyVisible = !(element.style.display == "none");
  4.4404 +        if (value && !isCurrentlyVisible)
  4.4405 +            element.style.display = "";
  4.4406 +        else if ((!value) && isCurrentlyVisible)
  4.4407 +            element.style.display = "none";
  4.4408 +    }
  4.4409 +};
  4.4410 +// 'click' is just a shorthand for the usual full-length event:{click:handler}
  4.4411 +makeEventHandlerShortcut('click');
  4.4412 +// If you want to make a custom template engine,
  4.4413 +//
  4.4414 +// [1] Inherit from this class (like ko.nativeTemplateEngine does)
  4.4415 +// [2] Override 'renderTemplateSource', supplying a function with this signature:
  4.4416 +//
  4.4417 +//        function (templateSource, bindingContext, options) {
  4.4418 +//            // - templateSource.text() is the text of the template you should render
  4.4419 +//            // - bindingContext.$data is the data you should pass into the template
  4.4420 +//            //   - you might also want to make bindingContext.$parent, bindingContext.$parents,
  4.4421 +//            //     and bindingContext.$root available in the template too
  4.4422 +//            // - options gives you access to any other properties set on "data-bind: { template: options }"
  4.4423 +//            //
  4.4424 +//            // Return value: an array of DOM nodes
  4.4425 +//        }
  4.4426 +//
  4.4427 +// [3] Override 'createJavaScriptEvaluatorBlock', supplying a function with this signature:
  4.4428 +//
  4.4429 +//        function (script) {
  4.4430 +//            // Return value: Whatever syntax means "Evaluate the JavaScript statement 'script' and output the result"
  4.4431 +//            //               For example, the jquery.tmpl template engine converts 'someScript' to '${ someScript }'
  4.4432 +//        }
  4.4433 +//
  4.4434 +//     This is only necessary if you want to allow data-bind attributes to reference arbitrary template variables.
  4.4435 +//     If you don't want to allow that, you can set the property 'allowTemplateRewriting' to false (like ko.nativeTemplateEngine does)
  4.4436 +//     and then you don't need to override 'createJavaScriptEvaluatorBlock'.
  4.4437 +
  4.4438 +ko.templateEngine = function () { };
  4.4439 +
  4.4440 +ko.templateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options) {
  4.4441 +    throw new Error("Override renderTemplateSource");
  4.4442 +};
  4.4443 +
  4.4444 +ko.templateEngine.prototype['createJavaScriptEvaluatorBlock'] = function (script) {
  4.4445 +    throw new Error("Override createJavaScriptEvaluatorBlock");
  4.4446 +};
  4.4447 +
  4.4448 +ko.templateEngine.prototype['makeTemplateSource'] = function(template, templateDocument) {
  4.4449 +    // Named template
  4.4450 +    if (typeof template == "string") {
  4.4451 +        templateDocument = templateDocument || document;
  4.4452 +        var elem = templateDocument.getElementById(template);
  4.4453 +        if (!elem)
  4.4454 +            throw new Error("Cannot find template with ID " + template);
  4.4455 +        return new ko.templateSources.domElement(elem);
  4.4456 +    } else if ((template.nodeType == 1) || (template.nodeType == 8)) {
  4.4457 +        // Anonymous template
  4.4458 +        return new ko.templateSources.anonymousTemplate(template);
  4.4459 +    } else
  4.4460 +        throw new Error("Unknown template type: " + template);
  4.4461 +};
  4.4462 +
  4.4463 +ko.templateEngine.prototype['renderTemplate'] = function (template, bindingContext, options, templateDocument) {
  4.4464 +    var templateSource = this['makeTemplateSource'](template, templateDocument);
  4.4465 +    return this['renderTemplateSource'](templateSource, bindingContext, options);
  4.4466 +};
  4.4467 +
  4.4468 +ko.templateEngine.prototype['isTemplateRewritten'] = function (template, templateDocument) {
  4.4469 +    // Skip rewriting if requested
  4.4470 +    if (this['allowTemplateRewriting'] === false)
  4.4471 +        return true;
  4.4472 +    return this['makeTemplateSource'](template, templateDocument)['data']("isRewritten");
  4.4473 +};
  4.4474 +
  4.4475 +ko.templateEngine.prototype['rewriteTemplate'] = function (template, rewriterCallback, templateDocument) {
  4.4476 +    var templateSource = this['makeTemplateSource'](template, templateDocument);
  4.4477 +    var rewritten = rewriterCallback(templateSource['text']());
  4.4478 +    templateSource['text'](rewritten);
  4.4479 +    templateSource['data']("isRewritten", true);
  4.4480 +};
  4.4481 +
  4.4482 +ko.exportSymbol('templateEngine', ko.templateEngine);
  4.4483 +
  4.4484 +ko.templateRewriting = (function () {
  4.4485 +    var memoizeDataBindingAttributeSyntaxRegex = /(<([a-z]+\d*)(?:\s+(?!data-bind\s*=\s*)[a-z0-9\-]+(?:=(?:\"[^\"]*\"|\'[^\']*\'))?)*\s+)data-bind\s*=\s*(["'])([\s\S]*?)\3/gi;
  4.4486 +    var memoizeVirtualContainerBindingSyntaxRegex = /<!--\s*ko\b\s*([\s\S]*?)\s*-->/g;
  4.4487 +
  4.4488 +    function validateDataBindValuesForRewriting(keyValueArray) {
  4.4489 +        var allValidators = ko.expressionRewriting.bindingRewriteValidators;
  4.4490 +        for (var i = 0; i < keyValueArray.length; i++) {
  4.4491 +            var key = keyValueArray[i]['key'];
  4.4492 +            if (allValidators.hasOwnProperty(key)) {
  4.4493 +                var validator = allValidators[key];
  4.4494 +
  4.4495 +                if (typeof validator === "function") {
  4.4496 +                    var possibleErrorMessage = validator(keyValueArray[i]['value']);
  4.4497 +                    if (possibleErrorMessage)
  4.4498 +                        throw new Error(possibleErrorMessage);
  4.4499 +                } else if (!validator) {
  4.4500 +                    throw new Error("This template engine does not support the '" + key + "' binding within its templates");
  4.4501 +                }
  4.4502 +            }
  4.4503 +        }
  4.4504 +    }
  4.4505 +
  4.4506 +    function constructMemoizedTagReplacement(dataBindAttributeValue, tagToRetain, nodeName, templateEngine) {
  4.4507 +        var dataBindKeyValueArray = ko.expressionRewriting.parseObjectLiteral(dataBindAttributeValue);
  4.4508 +        validateDataBindValuesForRewriting(dataBindKeyValueArray);
  4.4509 +        var rewrittenDataBindAttributeValue = ko.expressionRewriting.preProcessBindings(dataBindKeyValueArray, {'valueAccessors':true});
  4.4510 +
  4.4511 +        // For no obvious reason, Opera fails to evaluate rewrittenDataBindAttributeValue unless it's wrapped in an additional
  4.4512 +        // anonymous function, even though Opera's built-in debugger can evaluate it anyway. No other browser requires this
  4.4513 +        // extra indirection.
  4.4514 +        var applyBindingsToNextSiblingScript =
  4.4515 +            "ko.__tr_ambtns(function($context,$element){return(function(){return{ " + rewrittenDataBindAttributeValue + " } })()},'" + nodeName.toLowerCase() + "')";
  4.4516 +        return templateEngine['createJavaScriptEvaluatorBlock'](applyBindingsToNextSiblingScript) + tagToRetain;
  4.4517 +    }
  4.4518 +
  4.4519 +    return {
  4.4520 +        ensureTemplateIsRewritten: function (template, templateEngine, templateDocument) {
  4.4521 +            if (!templateEngine['isTemplateRewritten'](template, templateDocument))
  4.4522 +                templateEngine['rewriteTemplate'](template, function (htmlString) {
  4.4523 +                    return ko.templateRewriting.memoizeBindingAttributeSyntax(htmlString, templateEngine);
  4.4524 +                }, templateDocument);
  4.4525 +        },
  4.4526 +
  4.4527 +        memoizeBindingAttributeSyntax: function (htmlString, templateEngine) {
  4.4528 +            return htmlString.replace(memoizeDataBindingAttributeSyntaxRegex, function () {
  4.4529 +                return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[4], /* tagToRetain: */ arguments[1], /* nodeName: */ arguments[2], templateEngine);
  4.4530 +            }).replace(memoizeVirtualContainerBindingSyntaxRegex, function() {
  4.4531 +                return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[1], /* tagToRetain: */ "<!-- ko -->", /* nodeName: */ "#comment", templateEngine);
  4.4532 +            });
  4.4533 +        },
  4.4534 +
  4.4535 +        applyMemoizedBindingsToNextSibling: function (bindings, nodeName) {
  4.4536 +            return ko.memoization.memoize(function (domNode, bindingContext) {
  4.4537 +                var nodeToBind = domNode.nextSibling;
  4.4538 +                if (nodeToBind && nodeToBind.nodeName.toLowerCase() === nodeName) {
  4.4539 +                    ko.applyBindingAccessorsToNode(nodeToBind, bindings, bindingContext);
  4.4540 +                }
  4.4541 +            });
  4.4542 +        }
  4.4543 +    }
  4.4544 +})();
  4.4545 +
  4.4546 +
  4.4547 +// Exported only because it has to be referenced by string lookup from within rewritten template
  4.4548 +ko.exportSymbol('__tr_ambtns', ko.templateRewriting.applyMemoizedBindingsToNextSibling);
  4.4549 +(function() {
  4.4550 +    // A template source represents a read/write way of accessing a template. This is to eliminate the need for template loading/saving
  4.4551 +    // logic to be duplicated in every template engine (and means they can all work with anonymous templates, etc.)
  4.4552 +    //
  4.4553 +    // Two are provided by default:
  4.4554 +    //  1. ko.templateSources.domElement       - reads/writes the text content of an arbitrary DOM element
  4.4555 +    //  2. ko.templateSources.anonymousElement - uses ko.utils.domData to read/write text *associated* with the DOM element, but
  4.4556 +    //                                           without reading/writing the actual element text content, since it will be overwritten
  4.4557 +    //                                           with the rendered template output.
  4.4558 +    // You can implement your own template source if you want to fetch/store templates somewhere other than in DOM elements.
  4.4559 +    // Template sources need to have the following functions:
  4.4560 +    //   text() 			- returns the template text from your storage location
  4.4561 +    //   text(value)		- writes the supplied template text to your storage location
  4.4562 +    //   data(key)			- reads values stored using data(key, value) - see below
  4.4563 +    //   data(key, value)	- associates "value" with this template and the key "key". Is used to store information like "isRewritten".
  4.4564 +    //
  4.4565 +    // Optionally, template sources can also have the following functions:
  4.4566 +    //   nodes()            - returns a DOM element containing the nodes of this template, where available
  4.4567 +    //   nodes(value)       - writes the given DOM element to your storage location
  4.4568 +    // If a DOM element is available for a given template source, template engines are encouraged to use it in preference over text()
  4.4569 +    // for improved speed. However, all templateSources must supply text() even if they don't supply nodes().
  4.4570 +    //
  4.4571 +    // Once you've implemented a templateSource, make your template engine use it by subclassing whatever template engine you were
  4.4572 +    // using and overriding "makeTemplateSource" to return an instance of your custom template source.
  4.4573 +
  4.4574 +    ko.templateSources = {};
  4.4575 +
  4.4576 +    // ---- ko.templateSources.domElement -----
  4.4577 +
  4.4578 +    ko.templateSources.domElement = function(element) {
  4.4579 +        this.domElement = element;
  4.4580 +    }
  4.4581 +
  4.4582 +    ko.templateSources.domElement.prototype['text'] = function(/* valueToWrite */) {
  4.4583 +        var tagNameLower = ko.utils.tagNameLower(this.domElement),
  4.4584 +            elemContentsProperty = tagNameLower === "script" ? "text"
  4.4585 +                                 : tagNameLower === "textarea" ? "value"
  4.4586 +                                 : "innerHTML";
  4.4587 +
  4.4588 +        if (arguments.length == 0) {
  4.4589 +            return this.domElement[elemContentsProperty];
  4.4590 +        } else {
  4.4591 +            var valueToWrite = arguments[0];
  4.4592 +            if (elemContentsProperty === "innerHTML")
  4.4593 +                ko.utils.setHtml(this.domElement, valueToWrite);
  4.4594 +            else
  4.4595 +                this.domElement[elemContentsProperty] = valueToWrite;
  4.4596 +        }
  4.4597 +    };
  4.4598 +
  4.4599 +    var dataDomDataPrefix = ko.utils.domData.nextKey() + "_";
  4.4600 +    ko.templateSources.domElement.prototype['data'] = function(key /*, valueToWrite */) {
  4.4601 +        if (arguments.length === 1) {
  4.4602 +            return ko.utils.domData.get(this.domElement, dataDomDataPrefix + key);
  4.4603 +        } else {
  4.4604 +            ko.utils.domData.set(this.domElement, dataDomDataPrefix + key, arguments[1]);
  4.4605 +        }
  4.4606 +    };
  4.4607 +
  4.4608 +    // ---- ko.templateSources.anonymousTemplate -----
  4.4609 +    // Anonymous templates are normally saved/retrieved as DOM nodes through "nodes".
  4.4610 +    // For compatibility, you can also read "text"; it will be serialized from the nodes on demand.
  4.4611 +    // Writing to "text" is still supported, but then the template data will not be available as DOM nodes.
  4.4612 +
  4.4613 +    var anonymousTemplatesDomDataKey = ko.utils.domData.nextKey();
  4.4614 +    ko.templateSources.anonymousTemplate = function(element) {
  4.4615 +        this.domElement = element;
  4.4616 +    }
  4.4617 +    ko.templateSources.anonymousTemplate.prototype = new ko.templateSources.domElement();
  4.4618 +    ko.templateSources.anonymousTemplate.prototype.constructor = ko.templateSources.anonymousTemplate;
  4.4619 +    ko.templateSources.anonymousTemplate.prototype['text'] = function(/* valueToWrite */) {
  4.4620 +        if (arguments.length == 0) {
  4.4621 +            var templateData = ko.utils.domData.get(this.domElement, anonymousTemplatesDomDataKey) || {};
  4.4622 +            if (templateData.textData === undefined && templateData.containerData)
  4.4623 +                templateData.textData = templateData.containerData.innerHTML;
  4.4624 +            return templateData.textData;
  4.4625 +        } else {
  4.4626 +            var valueToWrite = arguments[0];
  4.4627 +            ko.utils.domData.set(this.domElement, anonymousTemplatesDomDataKey, {textData: valueToWrite});
  4.4628 +        }
  4.4629 +    };
  4.4630 +    ko.templateSources.domElement.prototype['nodes'] = function(/* valueToWrite */) {
  4.4631 +        if (arguments.length == 0) {
  4.4632 +            var templateData = ko.utils.domData.get(this.domElement, anonymousTemplatesDomDataKey) || {};
  4.4633 +            return templateData.containerData;
  4.4634 +        } else {
  4.4635 +            var valueToWrite = arguments[0];
  4.4636 +            ko.utils.domData.set(this.domElement, anonymousTemplatesDomDataKey, {containerData: valueToWrite});
  4.4637 +        }
  4.4638 +    };
  4.4639 +
  4.4640 +    ko.exportSymbol('templateSources', ko.templateSources);
  4.4641 +    ko.exportSymbol('templateSources.domElement', ko.templateSources.domElement);
  4.4642 +    ko.exportSymbol('templateSources.anonymousTemplate', ko.templateSources.anonymousTemplate);
  4.4643 +})();
  4.4644 +(function () {
  4.4645 +    var _templateEngine;
  4.4646 +    ko.setTemplateEngine = function (templateEngine) {
  4.4647 +        if ((templateEngine != undefined) && !(templateEngine instanceof ko.templateEngine))
  4.4648 +            throw new Error("templateEngine must inherit from ko.templateEngine");
  4.4649 +        _templateEngine = templateEngine;
  4.4650 +    }
  4.4651 +
  4.4652 +    function invokeForEachNodeInContinuousRange(firstNode, lastNode, action) {
  4.4653 +        var node, nextInQueue = firstNode, firstOutOfRangeNode = ko.virtualElements.nextSibling(lastNode);
  4.4654 +        while (nextInQueue && ((node = nextInQueue) !== firstOutOfRangeNode)) {
  4.4655 +            nextInQueue = ko.virtualElements.nextSibling(node);
  4.4656 +            action(node, nextInQueue);
  4.4657 +        }
  4.4658 +    }
  4.4659 +
  4.4660 +    function activateBindingsOnContinuousNodeArray(continuousNodeArray, bindingContext) {
  4.4661 +        // To be used on any nodes that have been rendered by a template and have been inserted into some parent element
  4.4662 +        // Walks through continuousNodeArray (which *must* be continuous, i.e., an uninterrupted sequence of sibling nodes, because
  4.4663 +        // the algorithm for walking them relies on this), and for each top-level item in the virtual-element sense,
  4.4664 +        // (1) Does a regular "applyBindings" to associate bindingContext with this node and to activate any non-memoized bindings
  4.4665 +        // (2) Unmemoizes any memos in the DOM subtree (e.g., to activate bindings that had been memoized during template rewriting)
  4.4666 +
  4.4667 +        if (continuousNodeArray.length) {
  4.4668 +            var firstNode = continuousNodeArray[0],
  4.4669 +                lastNode = continuousNodeArray[continuousNodeArray.length - 1],
  4.4670 +                parentNode = firstNode.parentNode,
  4.4671 +                provider = ko.bindingProvider['instance'],
  4.4672 +                preprocessNode = provider['preprocessNode'];
  4.4673 +
  4.4674 +            if (preprocessNode) {
  4.4675 +                invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node, nextNodeInRange) {
  4.4676 +                    var nodePreviousSibling = node.previousSibling;
  4.4677 +                    var newNodes = preprocessNode.call(provider, node);
  4.4678 +                    if (newNodes) {
  4.4679 +                        if (node === firstNode)
  4.4680 +                            firstNode = newNodes[0] || nextNodeInRange;
  4.4681 +                        if (node === lastNode)
  4.4682 +                            lastNode = newNodes[newNodes.length - 1] || nodePreviousSibling;
  4.4683 +                    }
  4.4684 +                });
  4.4685 +
  4.4686 +                // Because preprocessNode can change the nodes, including the first and last nodes, update continuousNodeArray to match.
  4.4687 +                // We need the full set, including inner nodes, because the unmemoize step might remove the first node (and so the real
  4.4688 +                // first node needs to be in the array).
  4.4689 +                continuousNodeArray.length = 0;
  4.4690 +                if (!firstNode) { // preprocessNode might have removed all the nodes, in which case there's nothing left to do
  4.4691 +                    return;
  4.4692 +                }
  4.4693 +                if (firstNode === lastNode) {
  4.4694 +                    continuousNodeArray.push(firstNode);
  4.4695 +                } else {
  4.4696 +                    continuousNodeArray.push(firstNode, lastNode);
  4.4697 +                    ko.utils.fixUpContinuousNodeArray(continuousNodeArray, parentNode);
  4.4698 +                }
  4.4699 +            }
  4.4700 +
  4.4701 +            // Need to applyBindings *before* unmemoziation, because unmemoization might introduce extra nodes (that we don't want to re-bind)
  4.4702 +            // whereas a regular applyBindings won't introduce new memoized nodes
  4.4703 +            invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node) {
  4.4704 +                if (node.nodeType === 1 || node.nodeType === 8)
  4.4705 +                    ko.applyBindings(bindingContext, node);
  4.4706 +            });
  4.4707 +            invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node) {
  4.4708 +                if (node.nodeType === 1 || node.nodeType === 8)
  4.4709 +                    ko.memoization.unmemoizeDomNodeAndDescendants(node, [bindingContext]);
  4.4710 +            });
  4.4711 +
  4.4712 +            // Make sure any changes done by applyBindings or unmemoize are reflected in the array
  4.4713 +            ko.utils.fixUpContinuousNodeArray(continuousNodeArray, parentNode);
  4.4714 +        }
  4.4715 +    }
  4.4716 +
  4.4717 +    function getFirstNodeFromPossibleArray(nodeOrNodeArray) {
  4.4718 +        return nodeOrNodeArray.nodeType ? nodeOrNodeArray
  4.4719 +                                        : nodeOrNodeArray.length > 0 ? nodeOrNodeArray[0]
  4.4720 +                                        : null;
  4.4721 +    }
  4.4722 +
  4.4723 +    function executeTemplate(targetNodeOrNodeArray, renderMode, template, bindingContext, options) {
  4.4724 +        options = options || {};
  4.4725 +        var firstTargetNode = targetNodeOrNodeArray && getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
  4.4726 +        var templateDocument = firstTargetNode && firstTargetNode.ownerDocument;
  4.4727 +        var templateEngineToUse = (options['templateEngine'] || _templateEngine);
  4.4728 +        ko.templateRewriting.ensureTemplateIsRewritten(template, templateEngineToUse, templateDocument);
  4.4729 +        var renderedNodesArray = templateEngineToUse['renderTemplate'](template, bindingContext, options, templateDocument);
  4.4730 +
  4.4731 +        // Loosely check result is an array of DOM nodes
  4.4732 +        if ((typeof renderedNodesArray.length != "number") || (renderedNodesArray.length > 0 && typeof renderedNodesArray[0].nodeType != "number"))
  4.4733 +            throw new Error("Template engine must return an array of DOM nodes");
  4.4734 +
  4.4735 +        var haveAddedNodesToParent = false;
  4.4736 +        switch (renderMode) {
  4.4737 +            case "replaceChildren":
  4.4738 +                ko.virtualElements.setDomNodeChildren(targetNodeOrNodeArray, renderedNodesArray);
  4.4739 +                haveAddedNodesToParent = true;
  4.4740 +                break;
  4.4741 +            case "replaceNode":
  4.4742 +                ko.utils.replaceDomNodes(targetNodeOrNodeArray, renderedNodesArray);
  4.4743 +                haveAddedNodesToParent = true;
  4.4744 +                break;
  4.4745 +            case "ignoreTargetNode": break;
  4.4746 +            default:
  4.4747 +                throw new Error("Unknown renderMode: " + renderMode);
  4.4748 +        }
  4.4749 +
  4.4750 +        if (haveAddedNodesToParent) {
  4.4751 +            activateBindingsOnContinuousNodeArray(renderedNodesArray, bindingContext);
  4.4752 +            if (options['afterRender'])
  4.4753 +                ko.dependencyDetection.ignore(options['afterRender'], null, [renderedNodesArray, bindingContext['$data']]);
  4.4754 +        }
  4.4755 +
  4.4756 +        return renderedNodesArray;
  4.4757 +    }
  4.4758 +
  4.4759 +    function resolveTemplateName(template, data, context) {
  4.4760 +        // The template can be specified as:
  4.4761 +        if (ko.isObservable(template)) {
  4.4762 +            // 1. An observable, with string value
  4.4763 +            return template();
  4.4764 +        } else if (typeof template === 'function') {
  4.4765 +            // 2. A function of (data, context) returning a string
  4.4766 +            return template(data, context);
  4.4767 +        } else {
  4.4768 +            // 3. A string
  4.4769 +            return template;
  4.4770 +        }
  4.4771 +    }
  4.4772 +
  4.4773 +    ko.renderTemplate = function (template, dataOrBindingContext, options, targetNodeOrNodeArray, renderMode) {
  4.4774 +        options = options || {};
  4.4775 +        if ((options['templateEngine'] || _templateEngine) == undefined)
  4.4776 +            throw new Error("Set a template engine before calling renderTemplate");
  4.4777 +        renderMode = renderMode || "replaceChildren";
  4.4778 +
  4.4779 +        if (targetNodeOrNodeArray) {
  4.4780 +            var firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
  4.4781 +
  4.4782 +            var whenToDispose = function () { return (!firstTargetNode) || !ko.utils.domNodeIsAttachedToDocument(firstTargetNode); }; // Passive disposal (on next evaluation)
  4.4783 +            var activelyDisposeWhenNodeIsRemoved = (firstTargetNode && renderMode == "replaceNode") ? firstTargetNode.parentNode : firstTargetNode;
  4.4784 +
  4.4785 +            return ko.dependentObservable( // So the DOM is automatically updated when any dependency changes
  4.4786 +                function () {
  4.4787 +                    // Ensure we've got a proper binding context to work with
  4.4788 +                    var bindingContext = (dataOrBindingContext && (dataOrBindingContext instanceof ko.bindingContext))
  4.4789 +                        ? dataOrBindingContext
  4.4790 +                        : new ko.bindingContext(ko.utils.unwrapObservable(dataOrBindingContext));
  4.4791 +
  4.4792 +                    var templateName = resolveTemplateName(template, bindingContext['$data'], bindingContext),
  4.4793 +                        renderedNodesArray = executeTemplate(targetNodeOrNodeArray, renderMode, templateName, bindingContext, options);
  4.4794 +
  4.4795 +                    if (renderMode == "replaceNode") {
  4.4796 +                        targetNodeOrNodeArray = renderedNodesArray;
  4.4797 +                        firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
  4.4798 +                    }
  4.4799 +                },
  4.4800 +                null,
  4.4801 +                { disposeWhen: whenToDispose, disposeWhenNodeIsRemoved: activelyDisposeWhenNodeIsRemoved }
  4.4802 +            );
  4.4803 +        } else {
  4.4804 +            // We don't yet have a DOM node to evaluate, so use a memo and render the template later when there is a DOM node
  4.4805 +            return ko.memoization.memoize(function (domNode) {
  4.4806 +                ko.renderTemplate(template, dataOrBindingContext, options, domNode, "replaceNode");
  4.4807 +            });
  4.4808 +        }
  4.4809 +    };
  4.4810 +
  4.4811 +    ko.renderTemplateForEach = function (template, arrayOrObservableArray, options, targetNode, parentBindingContext) {
  4.4812 +        // Since setDomNodeChildrenFromArrayMapping always calls executeTemplateForArrayItem and then
  4.4813 +        // activateBindingsCallback for added items, we can store the binding context in the former to use in the latter.
  4.4814 +        var arrayItemContext;
  4.4815 +
  4.4816 +        // This will be called by setDomNodeChildrenFromArrayMapping to get the nodes to add to targetNode
  4.4817 +        var executeTemplateForArrayItem = function (arrayValue, index) {
  4.4818 +            // Support selecting template as a function of the data being rendered
  4.4819 +            arrayItemContext = parentBindingContext['createChildContext'](arrayValue, options['as'], function(context) {
  4.4820 +                context['$index'] = index;
  4.4821 +            });
  4.4822 +
  4.4823 +            var templateName = resolveTemplateName(template, arrayValue, arrayItemContext);
  4.4824 +            return executeTemplate(null, "ignoreTargetNode", templateName, arrayItemContext, options);
  4.4825 +        }
  4.4826 +
  4.4827 +        // This will be called whenever setDomNodeChildrenFromArrayMapping has added nodes to targetNode
  4.4828 +        var activateBindingsCallback = function(arrayValue, addedNodesArray, index) {
  4.4829 +            activateBindingsOnContinuousNodeArray(addedNodesArray, arrayItemContext);
  4.4830 +            if (options['afterRender'])
  4.4831 +                options['afterRender'](addedNodesArray, arrayValue);
  4.4832 +        };
  4.4833 +
  4.4834 +        return ko.dependentObservable(function () {
  4.4835 +            var unwrappedArray = ko.utils.unwrapObservable(arrayOrObservableArray) || [];
  4.4836 +            if (typeof unwrappedArray.length == "undefined") // Coerce single value into array
  4.4837 +                unwrappedArray = [unwrappedArray];
  4.4838 +
  4.4839 +            // Filter out any entries marked as destroyed
  4.4840 +            var filteredArray = ko.utils.arrayFilter(unwrappedArray, function(item) {
  4.4841 +                return options['includeDestroyed'] || item === undefined || item === null || !ko.utils.unwrapObservable(item['_destroy']);
  4.4842 +            });
  4.4843 +
  4.4844 +            // Call setDomNodeChildrenFromArrayMapping, ignoring any observables unwrapped within (most likely from a callback function).
  4.4845 +            // If the array items are observables, though, they will be unwrapped in executeTemplateForArrayItem and managed within setDomNodeChildrenFromArrayMapping.
  4.4846 +            ko.dependencyDetection.ignore(ko.utils.setDomNodeChildrenFromArrayMapping, null, [targetNode, filteredArray, executeTemplateForArrayItem, options, activateBindingsCallback]);
  4.4847 +
  4.4848 +        }, null, { disposeWhenNodeIsRemoved: targetNode });
  4.4849 +    };
  4.4850 +
  4.4851 +    var templateComputedDomDataKey = ko.utils.domData.nextKey();
  4.4852 +    function disposeOldComputedAndStoreNewOne(element, newComputed) {
  4.4853 +        var oldComputed = ko.utils.domData.get(element, templateComputedDomDataKey);
  4.4854 +        if (oldComputed && (typeof(oldComputed.dispose) == 'function'))
  4.4855 +            oldComputed.dispose();
  4.4856 +        ko.utils.domData.set(element, templateComputedDomDataKey, (newComputed && newComputed.isActive()) ? newComputed : undefined);
  4.4857 +    }
  4.4858 +
  4.4859 +    ko.bindingHandlers['template'] = {
  4.4860 +        'init': function(element, valueAccessor) {
  4.4861 +            // Support anonymous templates
  4.4862 +            var bindingValue = ko.utils.unwrapObservable(valueAccessor());
  4.4863 +            if (typeof bindingValue == "string" || bindingValue['name']) {
  4.4864 +                // It's a named template - clear the element
  4.4865 +                ko.virtualElements.emptyNode(element);
  4.4866 +            } else {
  4.4867 +                // It's an anonymous template - store the element contents, then clear the element
  4.4868 +                var templateNodes = ko.virtualElements.childNodes(element),
  4.4869 +                    container = ko.utils.moveCleanedNodesToContainerElement(templateNodes); // This also removes the nodes from their current parent
  4.4870 +                new ko.templateSources.anonymousTemplate(element)['nodes'](container);
  4.4871 +            }
  4.4872 +            return { 'controlsDescendantBindings': true };
  4.4873 +        },
  4.4874 +        'update': function (element, valueAccessor, allBindings, viewModel, bindingContext) {
  4.4875 +            var value = valueAccessor(),
  4.4876 +                dataValue,
  4.4877 +                options = ko.utils.unwrapObservable(value),
  4.4878 +                shouldDisplay = true,
  4.4879 +                templateComputed = null,
  4.4880 +                templateName;
  4.4881 +
  4.4882 +            if (typeof options == "string") {
  4.4883 +                templateName = value;
  4.4884 +                options = {};
  4.4885 +            } else {
  4.4886 +                templateName = options['name'];
  4.4887 +
  4.4888 +                // Support "if"/"ifnot" conditions
  4.4889 +                if ('if' in options)
  4.4890 +                    shouldDisplay = ko.utils.unwrapObservable(options['if']);
  4.4891 +                if (shouldDisplay && 'ifnot' in options)
  4.4892 +                    shouldDisplay = !ko.utils.unwrapObservable(options['ifnot']);
  4.4893 +
  4.4894 +                dataValue = ko.utils.unwrapObservable(options['data']);
  4.4895 +            }
  4.4896 +
  4.4897 +            if ('foreach' in options) {
  4.4898 +                // Render once for each data point (treating data set as empty if shouldDisplay==false)
  4.4899 +                var dataArray = (shouldDisplay && options['foreach']) || [];
  4.4900 +                templateComputed = ko.renderTemplateForEach(templateName || element, dataArray, options, element, bindingContext);
  4.4901 +            } else if (!shouldDisplay) {
  4.4902 +                ko.virtualElements.emptyNode(element);
  4.4903 +            } else {
  4.4904 +                // Render once for this single data point (or use the viewModel if no data was provided)
  4.4905 +                var innerBindingContext = ('data' in options) ?
  4.4906 +                    bindingContext['createChildContext'](dataValue, options['as']) :  // Given an explitit 'data' value, we create a child binding context for it
  4.4907 +                    bindingContext;                                                        // Given no explicit 'data' value, we retain the same binding context
  4.4908 +                templateComputed = ko.renderTemplate(templateName || element, innerBindingContext, options, element);
  4.4909 +            }
  4.4910 +
  4.4911 +            // It only makes sense to have a single template computed per element (otherwise which one should have its output displayed?)
  4.4912 +            disposeOldComputedAndStoreNewOne(element, templateComputed);
  4.4913 +        }
  4.4914 +    };
  4.4915 +
  4.4916 +    // Anonymous templates can't be rewritten. Give a nice error message if you try to do it.
  4.4917 +    ko.expressionRewriting.bindingRewriteValidators['template'] = function(bindingValue) {
  4.4918 +        var parsedBindingValue = ko.expressionRewriting.parseObjectLiteral(bindingValue);
  4.4919 +
  4.4920 +        if ((parsedBindingValue.length == 1) && parsedBindingValue[0]['unknown'])
  4.4921 +            return null; // It looks like a string literal, not an object literal, so treat it as a named template (which is allowed for rewriting)
  4.4922 +
  4.4923 +        if (ko.expressionRewriting.keyValueArrayContainsKey(parsedBindingValue, "name"))
  4.4924 +            return null; // Named templates can be rewritten, so return "no error"
  4.4925 +        return "This template engine does not support anonymous templates nested within its templates";
  4.4926 +    };
  4.4927 +
  4.4928 +    ko.virtualElements.allowedBindings['template'] = true;
  4.4929 +})();
  4.4930 +
  4.4931 +ko.exportSymbol('setTemplateEngine', ko.setTemplateEngine);
  4.4932 +ko.exportSymbol('renderTemplate', ko.renderTemplate);
  4.4933 +// Go through the items that have been added and deleted and try to find matches between them.
  4.4934 +ko.utils.findMovesInArrayComparison = function (left, right, limitFailedCompares) {
  4.4935 +    if (left.length && right.length) {
  4.4936 +        var failedCompares, l, r, leftItem, rightItem;
  4.4937 +        for (failedCompares = l = 0; (!limitFailedCompares || failedCompares < limitFailedCompares) && (leftItem = left[l]); ++l) {
  4.4938 +            for (r = 0; rightItem = right[r]; ++r) {
  4.4939 +                if (leftItem['value'] === rightItem['value']) {
  4.4940 +                    leftItem['moved'] = rightItem['index'];
  4.4941 +                    rightItem['moved'] = leftItem['index'];
  4.4942 +                    right.splice(r, 1);         // This item is marked as moved; so remove it from right list
  4.4943 +                    failedCompares = r = 0;     // Reset failed compares count because we're checking for consecutive failures
  4.4944 +                    break;
  4.4945 +                }
  4.4946 +            }
  4.4947 +            failedCompares += r;
  4.4948 +        }
  4.4949 +    }
  4.4950 +};
  4.4951 +
  4.4952 +ko.utils.compareArrays = (function () {
  4.4953 +    var statusNotInOld = 'added', statusNotInNew = 'deleted';
  4.4954 +
  4.4955 +    // Simple calculation based on Levenshtein distance.
  4.4956 +    function compareArrays(oldArray, newArray, options) {
  4.4957 +        // For backward compatibility, if the third arg is actually a bool, interpret
  4.4958 +        // it as the old parameter 'dontLimitMoves'. Newer code should use { dontLimitMoves: true }.
  4.4959 +        options = (typeof options === 'boolean') ? { 'dontLimitMoves': options } : (options || {});
  4.4960 +        oldArray = oldArray || [];
  4.4961 +        newArray = newArray || [];
  4.4962 +
  4.4963 +        if (oldArray.length <= newArray.length)
  4.4964 +            return compareSmallArrayToBigArray(oldArray, newArray, statusNotInOld, statusNotInNew, options);
  4.4965 +        else
  4.4966 +            return compareSmallArrayToBigArray(newArray, oldArray, statusNotInNew, statusNotInOld, options);
  4.4967 +    }
  4.4968 +
  4.4969 +    function compareSmallArrayToBigArray(smlArray, bigArray, statusNotInSml, statusNotInBig, options) {
  4.4970 +        var myMin = Math.min,
  4.4971 +            myMax = Math.max,
  4.4972 +            editDistanceMatrix = [],
  4.4973 +            smlIndex, smlIndexMax = smlArray.length,
  4.4974 +            bigIndex, bigIndexMax = bigArray.length,
  4.4975 +            compareRange = (bigIndexMax - smlIndexMax) || 1,
  4.4976 +            maxDistance = smlIndexMax + bigIndexMax + 1,
  4.4977 +            thisRow, lastRow,
  4.4978 +            bigIndexMaxForRow, bigIndexMinForRow;
  4.4979 +
  4.4980 +        for (smlIndex = 0; smlIndex <= smlIndexMax; smlIndex++) {
  4.4981 +            lastRow = thisRow;
  4.4982 +            editDistanceMatrix.push(thisRow = []);
  4.4983 +            bigIndexMaxForRow = myMin(bigIndexMax, smlIndex + compareRange);
  4.4984 +            bigIndexMinForRow = myMax(0, smlIndex - 1);
  4.4985 +            for (bigIndex = bigIndexMinForRow; bigIndex <= bigIndexMaxForRow; bigIndex++) {
  4.4986 +                if (!bigIndex)
  4.4987 +                    thisRow[bigIndex] = smlIndex + 1;
  4.4988 +                else if (!smlIndex)  // Top row - transform empty array into new array via additions
  4.4989 +                    thisRow[bigIndex] = bigIndex + 1;
  4.4990 +                else if (smlArray[smlIndex - 1] === bigArray[bigIndex - 1])
  4.4991 +                    thisRow[bigIndex] = lastRow[bigIndex - 1];                  // copy value (no edit)
  4.4992 +                else {
  4.4993 +                    var northDistance = lastRow[bigIndex] || maxDistance;       // not in big (deletion)
  4.4994 +                    var westDistance = thisRow[bigIndex - 1] || maxDistance;    // not in small (addition)
  4.4995 +                    thisRow[bigIndex] = myMin(northDistance, westDistance) + 1;
  4.4996 +                }
  4.4997 +            }
  4.4998 +        }
  4.4999 +
  4.5000 +        var editScript = [], meMinusOne, notInSml = [], notInBig = [];
  4.5001 +        for (smlIndex = smlIndexMax, bigIndex = bigIndexMax; smlIndex || bigIndex;) {
  4.5002 +            meMinusOne = editDistanceMatrix[smlIndex][bigIndex] - 1;
  4.5003 +            if (bigIndex && meMinusOne === editDistanceMatrix[smlIndex][bigIndex-1]) {
  4.5004 +                notInSml.push(editScript[editScript.length] = {     // added
  4.5005 +                    'status': statusNotInSml,
  4.5006 +                    'value': bigArray[--bigIndex],
  4.5007 +                    'index': bigIndex });
  4.5008 +            } else if (smlIndex && meMinusOne === editDistanceMatrix[smlIndex - 1][bigIndex]) {
  4.5009 +                notInBig.push(editScript[editScript.length] = {     // deleted
  4.5010 +                    'status': statusNotInBig,
  4.5011 +                    'value': smlArray[--smlIndex],
  4.5012 +                    'index': smlIndex });
  4.5013 +            } else {
  4.5014 +                --bigIndex;
  4.5015 +                --smlIndex;
  4.5016 +                if (!options['sparse']) {
  4.5017 +                    editScript.push({
  4.5018 +                        'status': "retained",
  4.5019 +                        'value': bigArray[bigIndex] });
  4.5020 +                }
  4.5021 +            }
  4.5022 +        }
  4.5023 +
  4.5024 +        // Set a limit on the number of consecutive non-matching comparisons; having it a multiple of
  4.5025 +        // smlIndexMax keeps the time complexity of this algorithm linear.
  4.5026 +        ko.utils.findMovesInArrayComparison(notInSml, notInBig, smlIndexMax * 10);
  4.5027 +
  4.5028 +        return editScript.reverse();
  4.5029 +    }
  4.5030 +
  4.5031 +    return compareArrays;
  4.5032 +})();
  4.5033 +
  4.5034 +ko.exportSymbol('utils.compareArrays', ko.utils.compareArrays);
  4.5035 +(function () {
  4.5036 +    // Objective:
  4.5037 +    // * Given an input array, a container DOM node, and a function from array elements to arrays of DOM nodes,
  4.5038 +    //   map the array elements to arrays of DOM nodes, concatenate together all these arrays, and use them to populate the container DOM node
  4.5039 +    // * Next time we're given the same combination of things (with the array possibly having mutated), update the container DOM node
  4.5040 +    //   so that its children is again the concatenation of the mappings of the array elements, but don't re-map any array elements that we
  4.5041 +    //   previously mapped - retain those nodes, and just insert/delete other ones
  4.5042 +
  4.5043 +    // "callbackAfterAddingNodes" will be invoked after any "mapping"-generated nodes are inserted into the container node
  4.5044 +    // You can use this, for example, to activate bindings on those nodes.
  4.5045 +
  4.5046 +    function mapNodeAndRefreshWhenChanged(containerNode, mapping, valueToMap, callbackAfterAddingNodes, index) {
  4.5047 +        // Map this array value inside a dependentObservable so we re-map when any dependency changes
  4.5048 +        var mappedNodes = [];
  4.5049 +        var dependentObservable = ko.dependentObservable(function() {
  4.5050 +            var newMappedNodes = mapping(valueToMap, index, ko.utils.fixUpContinuousNodeArray(mappedNodes, containerNode)) || [];
  4.5051 +
  4.5052 +            // On subsequent evaluations, just replace the previously-inserted DOM nodes
  4.5053 +            if (mappedNodes.length > 0) {
  4.5054 +                ko.utils.replaceDomNodes(mappedNodes, newMappedNodes);
  4.5055 +                if (callbackAfterAddingNodes)
  4.5056 +                    ko.dependencyDetection.ignore(callbackAfterAddingNodes, null, [valueToMap, newMappedNodes, index]);
  4.5057 +            }
  4.5058 +
  4.5059 +            // Replace the contents of the mappedNodes array, thereby updating the record
  4.5060 +            // of which nodes would be deleted if valueToMap was itself later removed
  4.5061 +            mappedNodes.length = 0;
  4.5062 +            ko.utils.arrayPushAll(mappedNodes, newMappedNodes);
  4.5063 +        }, null, { disposeWhenNodeIsRemoved: containerNode, disposeWhen: function() { return !ko.utils.anyDomNodeIsAttachedToDocument(mappedNodes); } });
  4.5064 +        return { mappedNodes : mappedNodes, dependentObservable : (dependentObservable.isActive() ? dependentObservable : undefined) };
  4.5065 +    }
  4.5066 +
  4.5067 +    var lastMappingResultDomDataKey = ko.utils.domData.nextKey();
  4.5068 +
  4.5069 +    ko.utils.setDomNodeChildrenFromArrayMapping = function (domNode, array, mapping, options, callbackAfterAddingNodes) {
  4.5070 +        // Compare the provided array against the previous one
  4.5071 +        array = array || [];
  4.5072 +        options = options || {};
  4.5073 +        var isFirstExecution = ko.utils.domData.get(domNode, lastMappingResultDomDataKey) === undefined;
  4.5074 +        var lastMappingResult = ko.utils.domData.get(domNode, lastMappingResultDomDataKey) || [];
  4.5075 +        var lastArray = ko.utils.arrayMap(lastMappingResult, function (x) { return x.arrayEntry; });
  4.5076 +        var editScript = ko.utils.compareArrays(lastArray, array, options['dontLimitMoves']);
  4.5077 +
  4.5078 +        // Build the new mapping result
  4.5079 +        var newMappingResult = [];
  4.5080 +        var lastMappingResultIndex = 0;
  4.5081 +        var newMappingResultIndex = 0;
  4.5082 +
  4.5083 +        var nodesToDelete = [];
  4.5084 +        var itemsToProcess = [];
  4.5085 +        var itemsForBeforeRemoveCallbacks = [];
  4.5086 +        var itemsForMoveCallbacks = [];
  4.5087 +        var itemsForAfterAddCallbacks = [];
  4.5088 +        var mapData;
  4.5089 +
  4.5090 +        function itemMovedOrRetained(editScriptIndex, oldPosition) {
  4.5091 +            mapData = lastMappingResult[oldPosition];
  4.5092 +            if (newMappingResultIndex !== oldPosition)
  4.5093 +                itemsForMoveCallbacks[editScriptIndex] = mapData;
  4.5094 +            // Since updating the index might change the nodes, do so before calling fixUpContinuousNodeArray
  4.5095 +            mapData.indexObservable(newMappingResultIndex++);
  4.5096 +            ko.utils.fixUpContinuousNodeArray(mapData.mappedNodes, domNode);
  4.5097 +            newMappingResult.push(mapData);
  4.5098 +            itemsToProcess.push(mapData);
  4.5099 +        }
  4.5100 +
  4.5101 +        function callCallback(callback, items) {
  4.5102 +            if (callback) {
  4.5103 +                for (var i = 0, n = items.length; i < n; i++) {
  4.5104 +                    if (items[i]) {
  4.5105 +                        ko.utils.arrayForEach(items[i].mappedNodes, function(node) {
  4.5106 +                            callback(node, i, items[i].arrayEntry);
  4.5107 +                        });
  4.5108 +                    }
  4.5109 +                }
  4.5110 +            }
  4.5111 +        }
  4.5112 +
  4.5113 +        for (var i = 0, editScriptItem, movedIndex; editScriptItem = editScript[i]; i++) {
  4.5114 +            movedIndex = editScriptItem['moved'];
  4.5115 +            switch (editScriptItem['status']) {
  4.5116 +                case "deleted":
  4.5117 +                    if (movedIndex === undefined) {
  4.5118 +                        mapData = lastMappingResult[lastMappingResultIndex];
  4.5119 +
  4.5120 +                        // Stop tracking changes to the mapping for these nodes
  4.5121 +                        if (mapData.dependentObservable)
  4.5122 +                            mapData.dependentObservable.dispose();
  4.5123 +
  4.5124 +                        // Queue these nodes for later removal
  4.5125 +                        nodesToDelete.push.apply(nodesToDelete, ko.utils.fixUpContinuousNodeArray(mapData.mappedNodes, domNode));
  4.5126 +                        if (options['beforeRemove']) {
  4.5127 +                            itemsForBeforeRemoveCallbacks[i] = mapData;
  4.5128 +                            itemsToProcess.push(mapData);
  4.5129 +                        }
  4.5130 +                    }
  4.5131 +                    lastMappingResultIndex++;
  4.5132 +                    break;
  4.5133 +
  4.5134 +                case "retained":
  4.5135 +                    itemMovedOrRetained(i, lastMappingResultIndex++);
  4.5136 +                    break;
  4.5137 +
  4.5138 +                case "added":
  4.5139 +                    if (movedIndex !== undefined) {
  4.5140 +                        itemMovedOrRetained(i, movedIndex);
  4.5141 +                    } else {
  4.5142 +                        mapData = { arrayEntry: editScriptItem['value'], indexObservable: ko.observable(newMappingResultIndex++) };
  4.5143 +                        newMappingResult.push(mapData);
  4.5144 +                        itemsToProcess.push(mapData);
  4.5145 +                        if (!isFirstExecution)
  4.5146 +                            itemsForAfterAddCallbacks[i] = mapData;
  4.5147 +                    }
  4.5148 +                    break;
  4.5149 +            }
  4.5150 +        }
  4.5151 +
  4.5152 +        // Call beforeMove first before any changes have been made to the DOM
  4.5153 +        callCallback(options['beforeMove'], itemsForMoveCallbacks);
  4.5154 +
  4.5155 +        // Next remove nodes for deleted items (or just clean if there's a beforeRemove callback)
  4.5156 +        ko.utils.arrayForEach(nodesToDelete, options['beforeRemove'] ? ko.cleanNode : ko.removeNode);
  4.5157 +
  4.5158 +        // Next add/reorder the remaining items (will include deleted items if there's a beforeRemove callback)
  4.5159 +        for (var i = 0, nextNode = ko.virtualElements.firstChild(domNode), lastNode, node; mapData = itemsToProcess[i]; i++) {
  4.5160 +            // Get nodes for newly added items
  4.5161 +            if (!mapData.mappedNodes)
  4.5162 +                ko.utils.extend(mapData, mapNodeAndRefreshWhenChanged(domNode, mapping, mapData.arrayEntry, callbackAfterAddingNodes, mapData.indexObservable));
  4.5163 +
  4.5164 +            // Put nodes in the right place if they aren't there already
  4.5165 +            for (var j = 0; node = mapData.mappedNodes[j]; nextNode = node.nextSibling, lastNode = node, j++) {
  4.5166 +                if (node !== nextNode)
  4.5167 +                    ko.virtualElements.insertAfter(domNode, node, lastNode);
  4.5168 +            }
  4.5169 +
  4.5170 +            // Run the callbacks for newly added nodes (for example, to apply bindings, etc.)
  4.5171 +            if (!mapData.initialized && callbackAfterAddingNodes) {
  4.5172 +                callbackAfterAddingNodes(mapData.arrayEntry, mapData.mappedNodes, mapData.indexObservable);
  4.5173 +                mapData.initialized = true;
  4.5174 +            }
  4.5175 +        }
  4.5176 +
  4.5177 +        // If there's a beforeRemove callback, call it after reordering.
  4.5178 +        // Note that we assume that the beforeRemove callback will usually be used to remove the nodes using
  4.5179 +        // some sort of animation, which is why we first reorder the nodes that will be removed. If the
  4.5180 +        // callback instead removes the nodes right away, it would be more efficient to skip reordering them.
  4.5181 +        // Perhaps we'll make that change in the future if this scenario becomes more common.
  4.5182 +        callCallback(options['beforeRemove'], itemsForBeforeRemoveCallbacks);
  4.5183 +
  4.5184 +        // Finally call afterMove and afterAdd callbacks
  4.5185 +        callCallback(options['afterMove'], itemsForMoveCallbacks);
  4.5186 +        callCallback(options['afterAdd'], itemsForAfterAddCallbacks);
  4.5187 +
  4.5188 +        // Store a copy of the array items we just considered so we can difference it next time
  4.5189 +        ko.utils.domData.set(domNode, lastMappingResultDomDataKey, newMappingResult);
  4.5190 +    }
  4.5191 +})();
  4.5192 +
  4.5193 +ko.exportSymbol('utils.setDomNodeChildrenFromArrayMapping', ko.utils.setDomNodeChildrenFromArrayMapping);
  4.5194 +ko.nativeTemplateEngine = function () {
  4.5195 +    this['allowTemplateRewriting'] = false;
  4.5196 +}
  4.5197 +
  4.5198 +ko.nativeTemplateEngine.prototype = new ko.templateEngine();
  4.5199 +ko.nativeTemplateEngine.prototype.constructor = ko.nativeTemplateEngine;
  4.5200 +ko.nativeTemplateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options) {
  4.5201 +    var useNodesIfAvailable = !(ko.utils.ieVersion < 9), // IE<9 cloneNode doesn't work properly
  4.5202 +        templateNodesFunc = useNodesIfAvailable ? templateSource['nodes'] : null,
  4.5203 +        templateNodes = templateNodesFunc ? templateSource['nodes']() : null;
  4.5204 +
  4.5205 +    if (templateNodes) {
  4.5206 +        return ko.utils.makeArray(templateNodes.cloneNode(true).childNodes);
  4.5207 +    } else {
  4.5208 +        var templateText = templateSource['text']();
  4.5209 +        return ko.utils.parseHtmlFragment(templateText);
  4.5210 +    }
  4.5211 +};
  4.5212 +
  4.5213 +ko.nativeTemplateEngine.instance = new ko.nativeTemplateEngine();
  4.5214 +ko.setTemplateEngine(ko.nativeTemplateEngine.instance);
  4.5215 +
  4.5216 +ko.exportSymbol('nativeTemplateEngine', ko.nativeTemplateEngine);
  4.5217 +(function() {
  4.5218 +    ko.jqueryTmplTemplateEngine = function () {
  4.5219 +        // Detect which version of jquery-tmpl you're using. Unfortunately jquery-tmpl
  4.5220 +        // doesn't expose a version number, so we have to infer it.
  4.5221 +        // Note that as of Knockout 1.3, we only support jQuery.tmpl 1.0.0pre and later,
  4.5222 +        // which KO internally refers to as version "2", so older versions are no longer detected.
  4.5223 +        var jQueryTmplVersion = this.jQueryTmplVersion = (function() {
  4.5224 +            if (!jQueryInstance || !(jQueryInstance['tmpl']))
  4.5225 +                return 0;
  4.5226 +            // Since it exposes no official version number, we use our own numbering system. To be updated as jquery-tmpl evolves.
  4.5227 +            try {
  4.5228 +                if (jQueryInstance['tmpl']['tag']['tmpl']['open'].toString().indexOf('__') >= 0) {
  4.5229 +                    // Since 1.0.0pre, custom tags should append markup to an array called "__"
  4.5230 +                    return 2; // Final version of jquery.tmpl
  4.5231 +                }
  4.5232 +            } catch(ex) { /* Apparently not the version we were looking for */ }
  4.5233 +
  4.5234 +            return 1; // Any older version that we don't support
  4.5235 +        })();
  4.5236 +
  4.5237 +        function ensureHasReferencedJQueryTemplates() {
  4.5238 +            if (jQueryTmplVersion < 2)
  4.5239 +                throw new Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");
  4.5240 +        }
  4.5241 +
  4.5242 +        function executeTemplate(compiledTemplate, data, jQueryTemplateOptions) {
  4.5243 +            return jQueryInstance['tmpl'](compiledTemplate, data, jQueryTemplateOptions);
  4.5244 +        }
  4.5245 +
  4.5246 +        this['renderTemplateSource'] = function(templateSource, bindingContext, options) {
  4.5247 +            options = options || {};
  4.5248 +            ensureHasReferencedJQueryTemplates();
  4.5249 +
  4.5250 +            // Ensure we have stored a precompiled version of this template (don't want to reparse on every render)
  4.5251 +            var precompiled = templateSource['data']('precompiled');
  4.5252 +            if (!precompiled) {
  4.5253 +                var templateText = templateSource['text']() || "";
  4.5254 +                // Wrap in "with($whatever.koBindingContext) { ... }"
  4.5255 +                templateText = "{{ko_with $item.koBindingContext}}" + templateText + "{{/ko_with}}";
  4.5256 +
  4.5257 +                precompiled = jQueryInstance['template'](null, templateText);
  4.5258 +                templateSource['data']('precompiled', precompiled);
  4.5259 +            }
  4.5260 +
  4.5261 +            var data = [bindingContext['$data']]; // Prewrap the data in an array to stop jquery.tmpl from trying to unwrap any arrays
  4.5262 +            var jQueryTemplateOptions = jQueryInstance['extend']({ 'koBindingContext': bindingContext }, options['templateOptions']);
  4.5263 +
  4.5264 +            var resultNodes = executeTemplate(precompiled, data, jQueryTemplateOptions);
  4.5265 +            resultNodes['appendTo'](document.createElement("div")); // Using "appendTo" forces jQuery/jQuery.tmpl to perform necessary cleanup work
  4.5266 +
  4.5267 +            jQueryInstance['fragments'] = {}; // Clear jQuery's fragment cache to avoid a memory leak after a large number of template renders
  4.5268 +            return resultNodes;
  4.5269 +        };
  4.5270 +
  4.5271 +        this['createJavaScriptEvaluatorBlock'] = function(script) {
  4.5272 +            return "{{ko_code ((function() { return " + script + " })()) }}";
  4.5273 +        };
  4.5274 +
  4.5275 +        this['addTemplate'] = function(templateName, templateMarkup) {
  4.5276 +            document.write("<script type='text/html' id='" + templateName + "'>" + templateMarkup + "<" + "/script>");
  4.5277 +        };
  4.5278 +
  4.5279 +        if (jQueryTmplVersion > 0) {
  4.5280 +            jQueryInstance['tmpl']['tag']['ko_code'] = {
  4.5281 +                open: "__.push($1 || '');"
  4.5282 +            };
  4.5283 +            jQueryInstance['tmpl']['tag']['ko_with'] = {
  4.5284 +                open: "with($1) {",
  4.5285 +                close: "} "
  4.5286 +            };
  4.5287 +        }
  4.5288 +    };
  4.5289 +
  4.5290 +    ko.jqueryTmplTemplateEngine.prototype = new ko.templateEngine();
  4.5291 +    ko.jqueryTmplTemplateEngine.prototype.constructor = ko.jqueryTmplTemplateEngine;
  4.5292 +
  4.5293 +    // Use this one by default *only if jquery.tmpl is referenced*
  4.5294 +    var jqueryTmplTemplateEngineInstance = new ko.jqueryTmplTemplateEngine();
  4.5295 +    if (jqueryTmplTemplateEngineInstance.jQueryTmplVersion > 0)
  4.5296 +        ko.setTemplateEngine(jqueryTmplTemplateEngineInstance);
  4.5297 +
  4.5298 +    ko.exportSymbol('jqueryTmplTemplateEngine', ko.jqueryTmplTemplateEngine);
  4.5299 +})();
  4.5300 +}));
  4.5301 +}());
  4.5302 +})();