PageSourceSearch

https://www.reviewofoptometry.com/Scripts/knockout-3.3.0.debug.js

js reviewofoptometry.com collected 2026-10-02 03:37:19 UTC 269,933 bytes, 5,475 lines download raw bytes

vendor: 47,868 bytes, lines 1-1050
1/*!
2 * Knockout JavaScript library v3.3.0
3 * (c) Steven Sanderson - http://knockoutjs.com/
4 * License: MIT (http://www.opensource.org/licenses/mit-license.php)
5 */
6
7(function(){
8var DEBUG=true;
9(function(undefined){
10    // (0, eval)('this') is a robust way of getting a reference to the global object
11    // For details, see http://stackoverflow.com/questions/14119988/return-this-0-evalthis/14120023#14120023
12    var window = this || (0, eval)('this'),
13        document = window['document'],
14        navigator = window['navigator'],
15        jQueryInstance = window["jQuery"],
16        JSON = window["JSON"];
17(function(factory) {
18    // Support three module loading scenarios
19    if (typeof define === 'function' && define['amd']) {
20        // [1] AMD anonymous module
21        define(['exports', 'require'], factory);
22    } else if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') {
23        // [2] CommonJS/Node.js
24        factory(module['exports'] || exports);  // module.exports is for Node.js
25    } else {
26        // [3] No module loader (plain <script> tag) - put directly in global namespace
27        factory(window['ko'] = {});
28    }
29}(function(koExports, amdRequire){
30// Internally, all KO objects are attached to koExports (even the non-exported ones whose names will be minified by the closure compiler).
31// In the future, the following "ko" variable may be made distinct from "koExports" so that private objects are not externally reachable.
32var ko = typeof koExports !== 'undefined' ? koExports : {};
33// Google Closure Compiler helpers (used only to make the minified file smaller)
34ko.exportSymbol = function(koPath, object) {
35    var tokens = koPath.split(".");
36
37    // In the future, "ko" may become distinct from "koExports" (so that non-exported objects are not reachable)
38    // At that point, "target" would be set to: (typeof koExports !== "undefined" ? koExports : ko)
39    var target = ko;
40
41    for (var i = 0; i < tokens.length - 1; i++)
42        target = target[tokens[i]];
43    target[tokens[tokens.length - 1]] = object;
44};
45ko.exportProperty = function(owner, publicName, object) {
46    owner[publicName] = object;
47};
48ko.version = "3.3.0";
49
50ko.exportSymbol('version', ko.version);
51ko.utils = (function () {
52    function objectForEach(obj, action) {
53        for (var prop in obj) {
54            if (obj.hasOwnProperty(prop)) {
55                action(prop, obj[prop]);
56            }
57        }
58    }
59
60    function extend(target, source) {
61        if (source) {
62            for(var prop in source) {
63                if(source.hasOwnProperty(prop)) {
64                    target[prop] = source[prop];
65                }
66            }
67        }
68        return target;
69    }
70
71    function setPrototypeOf(obj, proto) {
72        obj.__proto__ = proto;
73        return obj;
74    }
75
76    var canSetPrototype = ({ __proto__: [] } instanceof Array);
77
78    // 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)
79    var knownEvents = {}, knownEventTypesByEventName = {};
80    var keyEventTypeName = (navigator && /Firefox\/2/i.test(navigator.userAgent)) ? 'KeyboardEvent' : 'UIEvents';
81    knownEvents[keyEventTypeName] = ['keyup', 'keydown', 'keypress'];
82    knownEvents['MouseEvents'] = ['click', 'dblclick', 'mousedown', 'mouseup', 'mousemove', 'mouseover', 'mouseout', 'mouseenter', 'mouseleave'];
83    objectForEach(knownEvents, function(eventType, knownEventsForType) {
84        if (knownEventsForType.length) {
85            for (var i = 0, j = knownEventsForType.length; i < j; i++)
86                knownEventTypesByEventName[knownEventsForType[i]] = eventType;
87        }
88    });
89    var eventsThatMustBeRegisteredUsingAttachEvent = { 'propertychange': true }; // Workaround for an IE9 issue - https://github.com/SteveSanderson/knockout/issues/406
90
91    // Detect IE versions for bug workarounds (uses IE conditionals, not UA string, for robustness)
92    // Note that, since IE 10 does not support conditional comments, the following logic only detects IE < 10.
93    // Currently this is by design, since IE 10+ behaves correctly when treated as a standard browser.
94    // If there is a future need to detect specific versions of IE10+, we will amend this.
95    var ieVersion = document && (function() {
96        var version = 3, div = document.createElement('div'), iElems = div.getElementsByTagName('i');
97
98        // Keep constructing conditional HTML blocks until we hit one that resolves to an empty fragment
99        while (
100            div.innerHTML = '<!--[if gt IE ' + (++version) + ']><i></i><![endif]-->',
101            iElems[0]
102        ) {}
103        return version > 4 ? version : undefined;
104    }());
105    var isIe6 = ieVersion === 6,
106        isIe7 = ieVersion === 7;
107
108    function isClickOnCheckableElement(element, eventType) {
109        if ((ko.utils.tagNameLower(element) !== "input") || !element.type) return false;
110        if (eventType.toLowerCase() != "click") return false;
111        var inputType = element.type;
112        return (inputType == "checkbox") || (inputType == "radio");
113    }
114
115    // For details on the pattern for changing node classes
116    // see: https://github.com/knockout/knockout/issues/1597
117    var cssClassNameRegex = /\S+/g;
118
119    function toggleDomNodeCssClass(node, classNames, shouldHaveClass) {
120        var addOrRemoveFn;
121        if (classNames) {
122            if (typeof node.classList === 'object') {
123                addOrRemoveFn = node.classList[shouldHaveClass ? 'add' : 'remove'];
124                ko.utils.arrayForEach(classNames.match(cssClassNameRegex), function(className) {
125                    addOrRemoveFn.call(node.classList, className);
126                });
127            } else if (typeof node.className['baseVal'] === 'string') {
128                // SVG tag .classNames is an SVGAnimatedString instance
129                toggleObjectClassPropertyString(node.className, 'baseVal', classNames, shouldHaveClass);
130            } else {
131                // node.className ought to be a string.
132                toggleObjectClassPropertyString(node, 'className', classNames, shouldHaveClass);
133            }
134        }
135    }
136
137    function toggleObjectClassPropertyString(obj, prop, classNames, shouldHaveClass) {
138        // obj/prop is either a node/'className' or a SVGAnimatedString/'baseVal'.
139        var currentClassNames = obj[prop].match(cssClassNameRegex) || [];
140        ko.utils.arrayForEach(classNames.match(cssClassNameRegex), function(className) {
141            ko.utils.addOrRemoveItem(currentClassNames, className, shouldHaveClass);
142        });
143        obj[prop] = currentClassNames.join(" ");
144    }
145
146    return {
147        fieldsIncludedWithJsonPost: ['authenticity_token', /^__RequestVerificationToken(_.*)?$/],
148
149        arrayForEach: function (array, action) {
150            for (var i = 0, j = array.length; i < j; i++)
151                action(array[i], i);
152        },
153
154        arrayIndexOf: function (array, item) {
155            if (typeof Array.prototype.indexOf == "function")
156                return Array.prototype.indexOf.call(array, item);
157            for (var i = 0, j = array.length; i < j; i++)
158                if (array[i] === item)
159                    return i;
160            return -1;
161        },
162
163        arrayFirst: function (array, predicate, predicateOwner) {
164            for (var i = 0, j = array.length; i < j; i++)
165                if (predicate.call(predicateOwner, array[i], i))
166                    return array[i];
167            return null;
168        },
169
170        arrayRemoveItem: function (array, itemToRemove) {
171            var index = ko.utils.arrayIndexOf(array, itemToRemove);
172            if (index > 0) {
173                array.splice(index, 1);
174            }
175            else if (index === 0) {
176                array.shift();
177            }
178        },
179
180        arrayGetDistinctValues: function (array) {
181            array = array || [];
182            var result = [];
183            for (var i = 0, j = array.length; i < j; i++) {
184                if (ko.utils.arrayIndexOf(result, array[i]) < 0)
185                    result.push(array[i]);
186            }
187            return result;
188        },
189
190        arrayMap: function (array, mapping) {
191            array = array || [];
192            var result = [];
193            for (var i = 0, j = array.length; i < j; i++)
194                result.push(mapping(array[i], i));
195            return result;
196        },
197
198        arrayFilter: function (array, predicate) {
199            array = array || [];
200            var result = [];
201            for (var i = 0, j = array.length; i < j; i++)
202                if (predicate(array[i], i))
203                    result.push(array[i]);
204            return result;
205        },
206
207        arrayPushAll: function (array, valuesToPush) {
208            if (valuesToPush instanceof Array)
209                array.push.apply(array, valuesToPush);
210            else
211                for (var i = 0, j = valuesToPush.length; i < j; i++)
212                    array.push(valuesToPush[i]);
213            return array;
214        },
215
216        addOrRemoveItem: function(array, value, included) {
217            var existingEntryIndex = ko.utils.arrayIndexOf(ko.utils.peekObservable(array), value);
218            if (existingEntryIndex < 0) {
219                if (included)
220                    array.push(value);
221            } else {
222                if (!included)
223                    array.splice(existingEntryIndex, 1);
224            }
225        },
226
227        canSetPrototype: canSetPrototype,
228
229        extend: extend,
230
231        setPrototypeOf: setPrototypeOf,
232
233        setPrototypeOfOrExtend: canSetPrototype ? setPrototypeOf : extend,
234
235        objectForEach: objectForEach,
236
237        objectMap: function(source, mapping) {
238            if (!source)
239                return source;
240            var target = {};
241            for (var prop in source) {
242                if (source.hasOwnProperty(prop)) {
243                    target[prop] = mapping(source[prop], prop, source);
244                }
245            }
246            return target;
247        },
248
249        emptyDomNode: function (domNode) {
250            while (domNode.firstChild) {
251                ko.removeNode(domNode.firstChild);
252            }
253        },
254
255        moveCleanedNodesToContainerElement: function(nodes) {
256            // Ensure it's a real array, as we're about to reparent the nodes and
257            // we don't want the underlying collection to change while we're doing that.
258            var nodesArray = ko.utils.makeArray(nodes);
259            var templateDocument = (nodesArray[0] && nodesArray[0].ownerDocument) || document;
260
261            var container = templateDocument.createElement('div');
262            for (var i = 0, j = nodesArray.length; i < j; i++) {
263                container.appendChild(ko.cleanNode(nodesArray[i]));
264            }
265            return container;
266        },
267
268        cloneNodes: function (nodesArray, shouldCleanNodes) {
269            for (var i = 0, j = nodesArray.length, newNodesArray = []; i < j; i++) {
270                var clonedNode = nodesArray[i].cloneNode(true);
271                newNodesArray.push(shouldCleanNodes ? ko.cleanNode(clonedNode) : clonedNode);
272            }
273            return newNodesArray;
274        },
275
276        setDomNodeChildren: function (domNode, childNodes) {
277            ko.utils.emptyDomNode(domNode);
278            if (childNodes) {
279                for (var i = 0, j = childNodes.length; i < j; i++)
280                    domNode.appendChild(childNodes[i]);
281            }
282        },
283
284        replaceDomNodes: function (nodeToReplaceOrNodeArray, newNodesArray) {
285            var nodesToReplaceArray = nodeToReplaceOrNodeArray.nodeType ? [nodeToReplaceOrNodeArray] : nodeToReplaceOrNodeArray;
286            if (nodesToReplaceArray.length > 0) {
287                var insertionPoint = nodesToReplaceArray[0];
288                var parent = insertionPoint.parentNode;
289                for (var i = 0, j = newNodesArray.length; i < j; i++)
290                    parent.insertBefore(newNodesArray[i], insertionPoint);
291                for (var i = 0, j = nodesToReplaceArray.length; i < j; i++) {
292                    ko.removeNode(nodesToReplaceArray[i]);
293                }
294            }
295        },
296
297        fixUpContinuousNodeArray: function(continuousNodeArray, parentNode) {
298            // Before acting on a set of nodes that were previously outputted by a template function, we have to reconcile
299            // them against what is in the DOM right now. It may be that some of the nodes have already been removed, or that
300            // new nodes might have been inserted in the middle, for example by a binding. Also, there may previously have been
301            // leading comment nodes (created by rewritten string-based templates) that have since been removed during binding.
302            // So, this function translates the old "map" output array into its best guess of the set of current DOM nodes.
303            //
304            // Rules:
305            //   [A] Any leading nodes that have been removed should be ignored
306            //       These most likely correspond to memoization nodes that were already removed during binding
307            //       See https://github.com/SteveSanderson/knockout/pull/440
308            //   [B] We want to output a continuous series of nodes. So, ignore any nodes that have already been removed,
309            //       and include any nodes that have been inserted among the previous collection
310
311            if (continuousNodeArray.length) {
312                // The parent node can be a virtual element; so get the real parent node
313                parentNode = (parentNode.nodeType === 8 && parentNode.parentNode) || parentNode;
314
315                // Rule [A]
316                while (continuousNodeArray.length && continuousNodeArray[0].parentNode !== parentNode)
317                    continuousNodeArray.splice(0, 1);
318
319                // Rule [B]
320                if (continuousNodeArray.length > 1) {
321                    var current = continuousNodeArray[0], last = continuousNodeArray[continuousNodeArray.length - 1];
322                    // Replace with the actual new continuous node set
323                    continuousNodeArray.length = 0;
324                    while (current !== last) {
325                        continuousNodeArray.push(current);
326                        current = current.nextSibling;
327                        if (!current) // Won't happen, except if the developer has manually removed some DOM elements (then we're in an undefined scenario)
328                            return;
329                    }
330                    continuousNodeArray.push(last);
331                }
332            }
333            return continuousNodeArray;
334        },
335
336        setOptionNodeSelectionState: function (optionNode, isSelected) {
337            // IE6 sometimes throws "unknown error" if you try to write to .selected directly, whereas Firefox struggles with setAttribute. Pick one based on browser.
338            if (ieVersion < 7)
339                optionNode.setAttribute("selected", isSelected);
340            else
341                optionNode.selected = isSelected;
342        },
343
344        stringTrim: function (string) {
345            return string === null || string === undefined ? '' :
346                string.trim ?
347                    string.trim() :
348                    string.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g, '');
349        },
350
351        stringStartsWith: function (string, startsWith) {
352            string = string || "";
353            if (startsWith.length > string.length)
354                return false;
355            return string.substring(0, startsWith.length) === startsWith;
356        },
357
358        domNodeIsContainedBy: function (node, containedByNode) {
359            if (node === containedByNode)
360                return true;
361            if (node.nodeType === 11)
362                return false; // Fixes issue #1162 - can't use node.contains for document fragments on IE8
363            if (containedByNode.contains)
364                return containedByNode.contains(node.nodeType === 3 ? node.parentNode : node);
365            if (containedByNode.compareDocumentPosition)
366                return (containedByNode.compareDocumentPosition(node) & 16) == 16;
367            while (node && node != containedByNode) {
368                node = node.parentNode;
369            }
370            return !!node;
371        },
372
373        domNodeIsAttachedToDocument: function (node) {
374            return ko.utils.domNodeIsContainedBy(node, node.ownerDocument.documentElement);
375        },
376
377        anyDomNodeIsAttachedToDocument: function(nodes) {
378            return !!ko.utils.arrayFirst(nodes, ko.utils.domNodeIsAttachedToDocument);
379        },
380
381        tagNameLower: function(element) {
382            // For HTML elements, tagName will always be upper case; for XHTML elements, it'll be lower case.
383            // Possible future optimization: If we know it's an element from an XHTML document (not HTML),
384            // we don't need to do the .toLowerCase() as it will always be lower case anyway.
385            return element && element.tagName && element.tagName.toLowerCase();
386        },
387
388        registerEventHandler: function (element, eventType, handler) {
389            var mustUseAttachEvent = ieVersion && eventsThatMustBeRegisteredUsingAttachEvent[eventType];
390            if (!mustUseAttachEvent && jQueryInstance) {
391                jQueryInstance(element)['bind'](eventType, handler);
392            } else if (!mustUseAttachEvent && typeof element.addEventListener == "function")
393                element.addEventListener(eventType, handler, false);
394            else if (typeof element.attachEvent != "undefined") {
395                var attachEventHandler = function (event) { handler.call(element, event); },
396                    attachEventName = "on" + eventType;
397                element.attachEvent(attachEventName, attachEventHandler);
398
399                // IE does not dispose attachEvent handlers automatically (unlike with addEventListener)
400                // so to avoid leaks, we have to remove them manually. See bug #856
401                ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
402                    element.detachEvent(attachEventName, attachEventHandler);
403                });
404            } else
405                throw new Error("Browser doesn't support addEventListener or attachEvent");
406        },
407
408        triggerEvent: function (element, eventType) {
409            if (!(element && element.nodeType))
410                throw new Error("element must be a DOM node when calling triggerEvent");
411
412            // For click events on checkboxes and radio buttons, jQuery toggles the element checked state *after* the
413            // event handler runs instead of *before*. (This was fixed in 1.9 for checkboxes but not for radio buttons.)
414            // IE doesn't change the checked state when you trigger the click event using "fireEvent".
415            // In both cases, we'll use the click method instead.
416            var useClickWorkaround = isClickOnCheckableElement(element, eventType);
417
418            if (jQueryInstance && !useClickWorkaround) {
419                jQueryInstance(element)['trigger'](eventType);
420            } else if (typeof document.createEvent == "function") {
421                if (typeof element.dispatchEvent == "function") {
422                    var eventCategory = knownEventTypesByEventName[eventType] || "HTMLEvents";
423                    var event = document.createEvent(eventCategory);
424                    event.initEvent(eventType, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, element);
425                    element.dispatchEvent(event);
426                }
427                else
428                    throw new Error("The supplied element doesn't support dispatchEvent");
429            } else if (useClickWorkaround && element.click) {
430                element.click();
431            } else if (typeof element.fireEvent != "undefined") {
432                element.fireEvent("on" + eventType);
433            } else {
434                throw new Error("Browser doesn't support triggering events");
435            }
436        },
437
438        unwrapObservable: function (value) {
439            return ko.isObservable(value) ? value() : value;
440        },
441
442        peekObservable: function (value) {
443            return ko.isObservable(value) ? value.peek() : value;
444        },
445
446        toggleDomNodeCssClass: toggleDomNodeCssClass,
447
448        setTextContent: function(element, textContent) {
449            var value = ko.utils.unwrapObservable(textContent);
450            if ((value === null) || (value === undefined))
451                value = "";
452
453            // We need there to be exactly one child: a text node.
454            // If there are no children, more than one, or if it's not a text node,
455            // we'll clear everything and create a single text node.
456            var innerTextNode = ko.virtualElements.firstChild(element);
457            if (!innerTextNode || innerTextNode.nodeType != 3 || ko.virtualElements.nextSibling(innerTextNode)) {
458                ko.virtualElements.setDomNodeChildren(element, [element.ownerDocument.createTextNode(value)]);
459            } else {
460                innerTextNode.data = value;
461            }
462
463            ko.utils.forceRefresh(element);
464        },
465
466        setElementName: function(element, name) {
467            element.name = name;
468
469            // Workaround IE 6/7 issue
470            // - https://github.com/SteveSanderson/knockout/issues/197
471            // - http://www.matts411.com/post/setting_the_name_attribute_in_ie_dom/
472            if (ieVersion <= 7) {
473                try {
474                    element.mergeAttributes(document.createElement("<input name='" + element.name + "'/>"), false);
475                }
476                catch(e) {} // For IE9 with doc mode "IE9 Standards" and browser mode "IE9 Compatibility View"
477            }
478        },
479
480        forceRefresh: function(node) {
481            // Workaround for an IE9 rendering bug - https://github.com/SteveSanderson/knockout/issues/209
482            if (ieVersion >= 9) {
483                // For text nodes and comment nodes (most likely virtual elements), we will have to refresh the container
484                var elem = node.nodeType == 1 ? node : node.parentNode;
485                if (elem.style)
486                    elem.style.zoom = elem.style.zoom;
487            }
488        },
489
490        ensureSelectElementIsRenderedCorrectly: function(selectElement) {
491            // 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.
492            // (See https://github.com/SteveSanderson/knockout/issues/312, http://stackoverflow.com/questions/5908494/select-only-shows-first-char-of-selected-option)
493            // Also fixes IE7 and IE8 bug that causes selects to be zero width if enclosed by 'if' or 'with'. (See issue #839)
494            if (ieVersion) {
495                var originalWidth = selectElement.style.width;
496                selectElement.style.width = 0;
497                selectElement.style.width = originalWidth;
498            }
499        },
500
501        range: function (min, max) {
502            min = ko.utils.unwrapObservable(min);
503            max = ko.utils.unwrapObservable(max);
504            var result = [];
505            for (var i = min; i <= max; i++)
506                result.push(i);
507            return result;
508        },
509
510        makeArray: function(arrayLikeObject) {
511            var result = [];
512            for (var i = 0, j = arrayLikeObject.length; i < j; i++) {
513                result.push(arrayLikeObject[i]);
514            };
515            return result;
516        },
517
518        isIe6 : isIe6,
519        isIe7 : isIe7,
520        ieVersion : ieVersion,
521
522        getFormFields: function(form, fieldName) {
523            var fields = ko.utils.makeArray(form.getElementsByTagName("input")).concat(ko.utils.makeArray(form.getElementsByTagName("textarea")));
524            var isMatchingField = (typeof fieldName == 'string')
525                ? function(field) { return field.name === fieldName }
526                : function(field) { return fieldName.test(field.name) }; // Treat fieldName as regex or object containing predicate
527            var matches = [];
528            for (var i = fields.length - 1; i >= 0; i--) {
529                if (isMatchingField(fields[i]))
530                    matches.push(fields[i]);
531            };
532            return matches;
533        },
534
535        parseJson: function (jsonString) {
536            if (typeof jsonString == "string") {
537                jsonString = ko.utils.stringTrim(jsonString);
538                if (jsonString) {
539                    if (JSON && JSON.parse) // Use native parsing where available
540                        return JSON.parse(jsonString);
541                    return (new Function("return " + jsonString))(); // Fallback on less safe parsing for older browsers
542                }
543            }
544            return null;
545        },
546
547        stringifyJson: function (data, replacer, space) {   // replacer and space are optional
548            if (!JSON || !JSON.stringify)
549                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");
550            return JSON.stringify(ko.utils.unwrapObservable(data), replacer, space);
551        },
552
553        postJson: function (urlOrForm, data, options) {
554            options = options || {};
555            var params = options['params'] || {};
556            var includeFields = options['includeFields'] || this.fieldsIncludedWithJsonPost;
557            var url = urlOrForm;
558
559            // If we were given a form, use its 'action' URL and pick out any requested field values
560            if((typeof urlOrForm == 'object') && (ko.utils.tagNameLower(urlOrForm) === "form")) {
561                var originalForm = urlOrForm;
562                url = originalForm.action;
563                for (var i = includeFields.length - 1; i >= 0; i--) {
564                    var fields = ko.utils.getFormFields(originalForm, includeFields[i]);
565                    for (var j = fields.length - 1; j >= 0; j--)
566                        params[fields[j].name] = fields[j].value;
567                }
568            }
569
570            data = ko.utils.unwrapObservable(data);
571            var form = document.createElement("form");
572            form.style.display = "none";
573            form.action = url;
574            form.method = "post";
575            for (var key in data) {
576                // Since 'data' this is a model object, we include all properties including those inherited from its prototype
577                var input = document.createElement("input");
578                input.type = "hidden";
579                input.name = key;
580                input.value = ko.utils.stringifyJson(ko.utils.unwrapObservable(data[key]));
581                form.appendChild(input);
582            }
583            objectForEach(params, function(key, value) {
584                var input = document.createElement("input");
585                input.type = "hidden";
586                input.name = key;
587                input.value = value;
588                form.appendChild(input);
589            });
590            document.body.appendChild(form);
591            options['submitter'] ? options['submitter'](form) : form.submit();
592            setTimeout(function () { form.parentNode.removeChild(form); }, 0);
593        }
594    }
595}());
596
597ko.exportSymbol('utils', ko.utils);
598ko.exportSymbol('utils.arrayForEach', ko.utils.arrayForEach);
599ko.exportSymbol('utils.arrayFirst', ko.utils.arrayFirst);
600ko.exportSymbol('utils.arrayFilter', ko.utils.arrayFilter);
601ko.exportSymbol('utils.arrayGetDistinctValues', ko.utils.arrayGetDistinctValues);
602ko.exportSymbol('utils.arrayIndexOf', ko.utils.arrayIndexOf);
603ko.exportSymbol('utils.arrayMap', ko.utils.arrayMap);
604ko.exportSymbol('utils.arrayPushAll', ko.utils.arrayPushAll);
605ko.exportSymbol('utils.arrayRemoveItem', ko.utils.arrayRemoveItem);
606ko.exportSymbol('utils.extend', ko.utils.extend);
607ko.exportSymbol('utils.fieldsIncludedWithJsonPost', ko.utils.fieldsIncludedWithJsonPost);
608ko.exportSymbol('utils.getFormFields', ko.utils.getFormFields);
609ko.exportSymbol('utils.peekObservable', ko.utils.peekObservable);
610ko.exportSymbol('utils.postJson', ko.utils.postJson);
611ko.exportSymbol('utils.parseJson', ko.utils.parseJson);
612ko.exportSymbol('utils.registerEventHandler', ko.utils.registerEventHandler);
613ko.exportSymbol('utils.stringifyJson', ko.utils.stringifyJson);
614ko.exportSymbol('utils.range', ko.utils.range);
615ko.exportSymbol('utils.toggleDomNodeCssClass', ko.utils.toggleDomNodeCssClass);
616ko.exportSymbol('utils.triggerEvent', ko.utils.triggerEvent);
617ko.exportSymbol('utils.unwrapObservable', ko.utils.unwrapObservable);
618ko.exportSymbol('utils.objectForEach', ko.utils.objectForEach);
619ko.exportSymbol('utils.addOrRemoveItem', ko.utils.addOrRemoveItem);
620ko.exportSymbol('utils.setTextContent', ko.utils.setTextContent);
621ko.exportSymbol('unwrap', ko.utils.unwrapObservable); // Convenient shorthand, because this is used so commonly
622
623if (!Function.prototype['bind']) {
624    // 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)
625    // In case the browser doesn't implement it natively, provide a JavaScript implementation. This implementation is based on the one in prototype.js
626    Function.prototype['bind'] = function (object) {
627        var originalFunction = this;
628        if (arguments.length === 1) {
629            return function () {
630                return originalFunction.apply(object, arguments);
631            };
632        } else {
633            var partialArgs = Array.prototype.slice.call(arguments, 1);
634            return function () {
635                var args = partialArgs.slice(0);
636                args.push.apply(args, arguments);
637                return originalFunction.apply(object, args);
638            };
639        }
640    };
641}
642
643ko.utils.domData = new (function () {
644    var uniqueId = 0;
645    var dataStoreKeyExpandoPropertyName = "__ko__" + (new Date).getTime();
646    var dataStore = {};
647
648    function getAll(node, createIfNotFound) {
649        var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
650        var hasExistingDataStore = dataStoreKey && (dataStoreKey !== "null") && dataStore[dataStoreKey];
651        if (!hasExistingDataStore) {
652            if (!createIfNotFound)
653                return undefined;
654            dataStoreKey = node[dataStoreKeyExpandoPropertyName] = "ko" + uniqueId++;
655            dataStore[dataStoreKey] = {};
656        }
657        return dataStore[dataStoreKey];
658    }
659
660    return {
661        get: function (node, key) {
662            var allDataForNode = getAll(node, false);
663            return allDataForNode === undefined ? undefined : allDataForNode[key];
664        },
665        set: function (node, key, value) {
666            if (value === undefined) {
667                // Make sure we don't actually create a new domData key if we are actually deleting a value
668                if (getAll(node, false) === undefined)
669                    return;
670            }
671            var allDataForNode = getAll(node, true);
672            allDataForNode[key] = value;
673        },
674        clear: function (node) {
675            var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
676            if (dataStoreKey) {
677                delete dataStore[dataStoreKey];
678                node[dataStoreKeyExpandoPropertyName] = null;
679                return true; // Exposing "did clean" flag purely so specs can infer whether things have been cleaned up as intended
680            }
681            return false;
682        },
683
684        nextKey: function () {
685            return (uniqueId++) + dataStoreKeyExpandoPropertyName;
686        }
687    };
688})();
689
690ko.exportSymbol('utils.domData', ko.utils.domData);
691ko.exportSymbol('utils.domData.clear', ko.utils.domData.clear); // Exporting only so specs can clear up after themselves fully
692
693ko.utils.domNodeDisposal = new (function () {
694    var domDataKey = ko.utils.domData.nextKey();
695    var cleanableNodeTypes = { 1: true, 8: true, 9: true };       // Element, Comment, Document
696    var cleanableNodeTypesWithDescendants = { 1: true, 9: true }; // Element, Document
697
698    function getDisposeCallbacksCollection(node, createIfNotFound) {
699        var allDisposeCallbacks = ko.utils.domData.get(node, domDataKey);
700        if ((allDisposeCallbacks === undefined) && createIfNotFound) {
701            allDisposeCallbacks = [];
702            ko.utils.domData.set(node, domDataKey, allDisposeCallbacks);
703        }
704        return allDisposeCallbacks;
705    }
706    function destroyCallbacksCollection(node) {
707        ko.utils.domData.set(node, domDataKey, undefined);
708    }
709
710    function cleanSingleNode(node) {
711        // Run all the dispose callbacks
712        var callbacks = getDisposeCallbacksCollection(node, false);
713        if (callbacks) {
714            callbacks = callbacks.slice(0); // Clone, as the array may be modified during iteration (typically, callbacks will remove themselves)
715            for (var i = 0; i < callbacks.length; i++)
716                callbacks[i](node);
717        }
718
719        // Erase the DOM data
720        ko.utils.domData.clear(node);
721
722        // Perform cleanup needed by external libraries (currently only jQuery, but can be extended)
723        ko.utils.domNodeDisposal["cleanExternalData"](node);
724
725        // Clear any immediate-child comment nodes, as these wouldn't have been found by
726        // node.getElementsByTagName("*") in cleanNode() (comment nodes aren't elements)
727        if (cleanableNodeTypesWithDescendants[node.nodeType])
728            cleanImmediateCommentTypeChildren(node);
729    }
730
731    function cleanImmediateCommentTypeChildren(nodeWithChildren) {
732        var child, nextChild = nodeWithChildren.firstChild;
733        while (child = nextChild) {
734            nextChild = child.nextSibling;
735            if (child.nodeType === 8)
736                cleanSingleNode(child);
737        }
738    }
739
740    return {
741        addDisposeCallback : function(node, callback) {
742            if (typeof callback != "function")
743                throw new Error("Callback must be a function");
744            getDisposeCallbacksCollection(node, true).push(callback);
745        },
746
747        removeDisposeCallback : function(node, callback) {
748            var callbacksCollection = getDisposeCallbacksCollection(node, false);
749            if (callbacksCollection) {
750                ko.utils.arrayRemoveItem(callbacksCollection, callback);
751                if (callbacksCollection.length == 0)
752                    destroyCallbacksCollection(node);
753            }
754        },
755
756        cleanNode : function(node) {
757            // First clean this node, where applicable
758            if (cleanableNodeTypes[node.nodeType]) {
759                cleanSingleNode(node);
760
761                // ... then its descendants, where applicable
762                if (cleanableNodeTypesWithDescendants[node.nodeType]) {
763                    // Clone the descendants list in case it changes during iteration
764                    var descendants = [];
765                    ko.utils.arrayPushAll(descendants, node.getElementsByTagName("*"));
766                    for (var i = 0, j = descendants.length; i < j; i++)
767                        cleanSingleNode(descendants[i]);
768                }
769            }
770            return node;
771        },
772
773        removeNode : function(node) {
774            ko.cleanNode(node);
775            if (node.parentNode)
776                node.parentNode.removeChild(node);
777        },
778
779        "cleanExternalData" : function (node) {
780            // Special support for jQuery here because it's so commonly used.
781            // Many jQuery plugins (including jquery.tmpl) store data using jQuery's equivalent of domData
782            // so notify it to tear down any resources associated with the node & descendants here.
783            if (jQueryInstance && (typeof jQueryInstance['cleanData'] == "function"))
784                jQueryInstance['cleanData']([node]);
785        }
786    };
787})();
788ko.cleanNode = ko.utils.domNodeDisposal.cleanNode; // Shorthand name for convenience
789ko.removeNode = ko.utils.domNodeDisposal.removeNode; // Shorthand name for convenience
790ko.exportSymbol('cleanNode', ko.cleanNode);
791ko.exportSymbol('removeNode', ko.removeNode);
792ko.exportSymbol('utils.domNodeDisposal', ko.utils.domNodeDisposal);
793ko.exportSymbol('utils.domNodeDisposal.addDisposeCallback', ko.utils.domNodeDisposal.addDisposeCallback);
794ko.exportSymbol('utils.domNodeDisposal.removeDisposeCallback', ko.utils.domNodeDisposal.removeDisposeCallback);
795(function () {
796    var leadingCommentRegex = /^(\s*)<!--(.*?)-->/;
797
798    function simpleHtmlParse(html, documentContext) {
799        documentContext || (documentContext = document);
800        var windowContext = documentContext['parentWindow'] || documentContext['defaultView'] || window;
801
802        // Based on jQuery's "clean" function, but only accounting for table-related elements.
803        // If you have referenced jQuery, this won't be used anyway - KO will use jQuery's "clean" function directly
804
805        // Note that there's still an issue in IE < 9 whereby it will discard comment nodes that are the first child of
806        // a descendant node. For example: "<div><!-- mycomment -->abc</div>" will get parsed as "<div>abc</div>"
807        // This won't affect anyone who has referenced jQuery, and there's always the workaround of inserting a dummy node
808        // (possibly a text node) in front of the comment. So, KO does not attempt to workaround this IE issue automatically at present.
809
810        // Trim whitespace, otherwise indexOf won't work as expected
811        var tags = ko.utils.stringTrim(html).toLowerCase(), div = documentContext.createElement("div");
812
813        // Finds the first match from the left column, and returns the corresponding "wrap" data from the right column
814        var wrap = tags.match(/^<(thead|tbody|tfoot)/)              && [1, "<table>", "</table>"] ||
815                   !tags.indexOf("<tr")                             && [2, "<table><tbody>", "</tbody></table>"] ||
816                   (!tags.indexOf("<td") || !tags.indexOf("<th"))   && [3, "<table><tbody><tr>", "</tr></tbody></table>"] ||
817                   /* anything else */                                 [0, "", ""];
818
819        // Go to html and back, then peel off extra wrappers
820        // Note that we always prefix with some dummy text, because otherwise, IE<9 will strip out leading comment nodes in descendants. Total madness.
821        var markup = "ignored<div>" + wrap[1] + html + wrap[2] + "</div>";
822        if (typeof windowContext['innerShiv'] == "function") {
823            div.appendChild(windowContext['innerShiv'](markup));
824        } else {
825            div.innerHTML = markup;
826        }
827
828        // Move to the right depth
829        while (wrap[0]--)
830            div = div.lastChild;
831
832        return ko.utils.makeArray(div.lastChild.childNodes);
833    }
834
835    function jQueryHtmlParse(html, documentContext) {
836        // jQuery's "parseHTML" function was introduced in jQuery 1.8.0 and is a documented public API.
837        if (jQueryInstance['parseHTML']) {
838            return jQueryInstance['parseHTML'](html, documentContext) || []; // Ensure we always return an array and never null
839        } else {
840            // For jQuery < 1.8.0, we fall back on the undocumented internal "clean" function.
841            var elems = jQueryInstance['clean']([html], documentContext);
842
843            // 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.
844            // Unfortunately, it never clears the dummy parent nodes from the document fragment, so it leaks memory over time.
845            // Fix this by finding the top-most dummy parent element, and detaching it from its owner fragment.
846            if (elems && elems[0]) {
847                // Find the top-most parent element that's a direct child of a document fragment
848                var elem = elems[0];
849                while (elem.parentNode && elem.parentNode.nodeType !== 11 /* i.e., DocumentFragment */)
850                    elem = elem.parentNode;
851                // ... then detach it
852                if (elem.parentNode)
853                    elem.parentNode.removeChild(elem);
854            }
855
856            return elems;
857        }
858    }
859
860    ko.utils.parseHtmlFragment = function(html, documentContext) {
861        return jQueryInstance ? jQueryHtmlParse(html, documentContext)   // As below, benefit from jQuery's optimisations where possible
862                              : simpleHtmlParse(html, documentContext);  // ... otherwise, this simple logic will do in most common cases.
863    };
864
865    ko.utils.setHtml = function(node, html) {
866        ko.utils.emptyDomNode(node);
867
868        // There's no legitimate reason to display a stringified observable without unwrapping it, so we'll unwrap it
869        html = ko.utils.unwrapObservable(html);
870
871        if ((html !== null) && (html !== undefined)) {
872            if (typeof html != 'string')
873                html = html.toString();
874
875            // jQuery contains a lot of sophisticated code to parse arbitrary HTML fragments,
876            // for example <tr> elements which are not normally allowed to exist on their own.
877            // If you've referenced jQuery we'll use that rather than duplicating its code.
878            if (jQueryInstance) {
879                jQueryInstance(node)['html'](html);
880            } else {
881                // ... otherwise, use KO's own parsing logic.
882                var parsedNodes = ko.utils.parseHtmlFragment(html, node.ownerDocument);
883                for (var i = 0; i < parsedNodes.length; i++)
884                    node.appendChild(parsedNodes[i]);
885            }
886        }
887    };
888})();
889
890ko.exportSymbol('utils.parseHtmlFragment', ko.utils.parseHtmlFragment);
891ko.exportSymbol('utils.setHtml', ko.utils.setHtml);
892
893ko.memoization = (function () {
894    var memos = {};
895
896    function randomMax8HexChars() {
897        return (((1 + Math.random()) * 0x100000000) | 0).toString(16).substring(1);
898    }
899    function generateRandomId() {
900        return randomMax8HexChars() + randomMax8HexChars();
901    }
902    function findMemoNodes(rootNode, appendToArray) {
903        if (!rootNode)
904            return;
905        if (rootNode.nodeType == 8) {
906            var memoId = ko.memoization.parseMemoText(rootNode.nodeValue);
907            if (memoId != null)
908                appendToArray.push({ domNode: rootNode, memoId: memoId });
909        } else if (rootNode.nodeType == 1) {
910            for (var i = 0, childNodes = rootNode.childNodes, j = childNodes.length; i < j; i++)
911                findMemoNodes(childNodes[i], appendToArray);
912        }
913    }
914
915    return {
916        memoize: function (callback) {
917            if (typeof callback != "function")
918                throw new Error("You can only pass a function to ko.memoization.memoize()");
919            var memoId = generateRandomId();
920            memos[memoId] = callback;
921            return "<!--[ko_memo:" + memoId + "]-->";
922        },
923
924        unmemoize: function (memoId, callbackParams) {
925            var callback = memos[memoId];
926            if (callback === undefined)
927                throw new Error("Couldn't find any memo with ID " + memoId + ". Perhaps it's already been unmemoized.");
928            try {
929                callback.apply(null, callbackParams || []);
930                return true;
931            }
932            finally { delete memos[memoId]; }
933        },
934
935        unmemoizeDomNodeAndDescendants: function (domNode, extraCallbackParamsArray) {
936            var memos = [];
937            findMemoNodes(domNode, memos);
938            for (var i = 0, j = memos.length; i < j; i++) {
939                var node = memos[i].domNode;
940                var combinedParams = [node];
941                if (extraCallbackParamsArray)
942                    ko.utils.arrayPushAll(combinedParams, extraCallbackParamsArray);
943                ko.memoization.unmemoize(memos[i].memoId, combinedParams);
944                node.nodeValue = ""; // Neuter this node so we don't try to unmemoize it again
945                if (node.parentNode)
946                    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)
947            }
948        },
949
950        parseMemoText: function (memoText) {
951            var match = memoText.match(/^\[ko_memo\:(.*?)\]$/);
952            return match ? match[1] : null;
953        }
954    };
955})();
956
957ko.exportSymbol('memoization', ko.memoization);
958ko.exportSymbol('memoization.memoize', ko.memoization.memoize);
959ko.exportSymbol('memoization.unmemoize', ko.memoization.unmemoize);
960ko.exportSymbol('memoization.parseMemoText', ko.memoization.parseMemoText);
961ko.exportSymbol('memoization.unmemoizeDomNodeAndDescendants', ko.memoization.unmemoizeDomNodeAndDescendants);
962ko.extenders = {
963    'throttle': function(target, timeout) {
964        // Throttling means two things:
965
966        // (1) For dependent observables, we throttle *evaluations* so that, no matter how fast its dependencies
967        //     notify updates, the target doesn't re-evaluate (and hence doesn't notify) faster than a certain rate
968        target['throttleEvaluation'] = timeout;
969
970        // (2) For writable targets (observables, or writable dependent observables), we throttle *writes*
971        //     so the target cannot change value synchronously or faster than a certain rate
972        var writeTimeoutInstance = null;
973        return ko.dependentObservable({
974            'read': target,
975            'write': function(value) {
976                clearTimeout(writeTimeoutInstance);
977                writeTimeoutInstance = setTimeout(function() {
978                    target(value);
979                }, timeout);
980            }
981        });
982    },
983
984    'rateLimit': function(target, options) {
985        var timeout, method, limitFunction;
986
987        if (typeof options == 'number') {
988            timeout = options;
989        } else {
990            timeout = options['timeout'];
991            method = options['method'];
992        }
993
994        limitFunction = method == 'notifyWhenChangesStop' ?  debounce : throttle;
995        target.limit(function(callback) {
996            return limitFunction(callback, timeout);
997        });
998    },
999
1000    'notify': function(target, notifyWhen) {
1001        target["equalityComparer"] = notifyWhen == "always" ?
1002            null :  // null equalityComparer means to always notify
1003            valuesArePrimitiveAndEqual;
1004    }
1005};
1006
1007var primitiveTypes = { 'undefined':1, 'boolean':1, 'number':1, 'string':1 };
1008function valuesArePrimitiveAndEqual(a, b) {
1009    var oldValueIsPrimitive = (a === null) || (typeof(a) in primitiveTypes);
1010    return oldValueIsPrimitive ? (a === b) : false;
1011}
1012
1013function throttle(callback, timeout) {
1014    var timeoutInstance;
1015    return function () {
1016        if (!timeoutInstance) {
1017            timeoutInstance = setTimeout(function() {
1018                timeoutInstance = undefined;
1019                callback();
1020            }, timeout);
1021        }
1022    };
1023}
1024
1025function debounce(callback, timeout) {
1026    var timeoutInstance;
1027    return function () {
1028        clearTimeout(timeoutInstance);
1029        timeoutInstance = setTimeout(callback, timeout);
1030    };
1031}
1032
1033function applyExtenders(requestedExtenders) {
1034    var target = this;
1035    if (requestedExtenders) {
1036        ko.utils.objectForEach(requestedExtenders, function(key, value) {
1037            var extenderHandler = ko.extenders[key];
1038            if (typeof extenderHandler == 'function') {
1039                target = extenderHandler(target, value) || target;
1040            }
1041        });
1042    }
1043    return target;
1044}
1045
1046ko.exportSymbol('extenders', ko.extenders);
1047
1048ko.subscription = function (target, callback, disposeCallback) {
1049    this._target = target;
1050    this.callback = callback;
1051    this.disposeCallback = disposeCallback;
1052    this.isDisposed = false;
1053    ko.exportProperty(this, 'dispose', this.dispose);
1054};
1055ko.subscription.prototype.dispose = function () {
1056    this.isDisposed = true;
1057    this.disposeCallback();
1058};
1059
1060ko.subscribable = function () {
1061    ko.utils.setPrototypeOfOrExtend(this, ko.subscribable['fn']);
1062    this._subscriptions = {};
1063    this._versionNumber = 1;
1064}
1065
1066var defaultEvent = "change";
1067
1068var ko_subscribable_fn = {
1069    subscribe: function (callback, callbackTarget, event) {
1070        var self = this;
1071
1072        event = event || defaultEvent;
1073        var boundCallback = callbackTarget ? callback.bind(callbackTarget) : callback;
1074
1075        var subscription = new ko.subscription(self, boundCallback, function () {
1076            ko.utils.arrayRemoveItem(self._subscriptions[event], subscription);
1077            if (self.afterSubscriptionRemove)
1078                self.afterSubscriptionRemove(event);
1079        });
1080
1081        if (self.beforeSubscriptionAdd)
1082            self.beforeSubscriptionAdd(event);
1083
1084        if (!self._subscriptions[event])
1085            self._subscriptions[event] = [];
1086        self._subscriptions[event].push(subscription);
1087
1088        return subscription;
1089    },
1090
1091    "notifySubscribers": function (valueToNotify, event) {
1092        event = event || defaultEvent;
1093        if (event === defaultEvent) {
1094            this.updateVersion();
1095        }
1096        if (this.hasSubscriptionsForEvent(event)) {
1097            try {
1098                ko.dependencyDetection.begin(); // Begin suppressing dependency detection (by setting the top frame to undefined)
1099                for (var a = this._subscriptions[event].slice(0), i = 0, subscription; subscription = a[i]; ++i) {
1100                    // In case a subscription was disposed during the arrayForEach cycle, check
1101                    // for isDisposed on each subscription before invoking its callback
1102                    if (!subscription.isDisposed)
1103                        subscription.callback(valueToNotify);
1104                }
1105            } finally {
1106                ko.dependencyDetection.end(); // End suppressing dependency detection
1107            }
1108        }
1109    },
1110
1111    getVersion: function () {
1112        return this._versionNumber;
1113    },
1114
1115    hasChanged: function (versionToCheck) {
1116        return this.getVersion() !== versionToCheck;
1117    },
1118
1119    updateVersion: function () {
1120        ++this._versionNumber;
1121    },
1122
1123    limit: function(limitFunction) {
1124        var self = this, selfIsObservable = ko.isObservable(self),
1125            isPending, previousValue, pendingValue, beforeChange = 'beforeChange';
1126
1127        if (!self._origNotifySubscribers) {
1128            self._origNotifySubscribers = self["notifySubscribers"];
1129            self["notifySubscribers"] = function(value, event) {
1130                if (!event || event === defaultEvent) {
1131                    self._rateLimitedChange(value);
1132                } else if (event === beforeChange) {
1133                    self._rateLimitedBeforeChange(value);
1134                } else {
1135                    self._origNotifySubscribers(value, event);
1136                }
1137            };
1138        }
1139
1140        var finish = limitFunction(function() {
1141            // If an observable provided a reference to itself, access it to get the latest value.
1142            // This allows computed observables to delay calculating their value until needed.
1143            if (selfIsObservable && pendingValue === self) {
1144                pendingValue = self();
1145            }
1146            isPending = false;
1147            if (self.isDifferent(previousValue, pendingValue)) {
1148                self._origNotifySubscribers(previousValue = pendingValue);
1149            }
1150        });
1151
1152        self._rateLimitedChange = function(value) {
1153            isPending = true;
1154            pendingValue = value;
1155            finish();
1156        };
1157        self._rateLimitedBeforeChange = function(value) {
1158            if (!isPending) {
1159                previousValue = value;
1160                self._origNotifySubscribers(value, beforeChange);
1161            }
1162        };
1163    },
1164
1165    hasSubscriptionsForEvent: function(event) {
1166        return this._subscriptions[event] && this._subscriptions[event].length;
1167    },
1168
1169    getSubscriptionsCount: function (event) {
1170        if (event) {
1171            return this._subscriptions[event] && this._subscriptions[event].length || 0;
1172        } else {
1173            var total = 0;
1174            ko.utils.objectForEach(this._subscriptions, function(eventName, subscriptions) {
1175                total += subscriptions.length;
1176            });
1177            return total;
1178        }
1179    },
1180
1181    isDifferent: function(oldValue, newValue) {
1182        return !this['equalityComparer'] || !this['equalityComparer'](oldValue, newValue);
1183    },
1184
1185    extend: applyExtenders
1186};
1187
1188ko.exportProperty(ko_subscribable_fn, 'subscribe', ko_subscribable_fn.subscribe);
1189ko.exportProperty(ko_subscribable_fn, 'extend', ko_subscribable_fn.extend);
1190ko.exportProperty(ko_subscribable_fn, 'getSubscriptionsCount', ko_subscribable_fn.getSubscriptionsCount);
1191
1192// For browsers that support proto assignment, we overwrite the prototype of each
1193// observable instance. Since observables are functions, we need Function.prototype
1194// to still be in the prototype chain.
1195if (ko.utils.canSetPrototype) {
1196    ko.utils.setPrototypeOf(ko_subscribable_fn, Function.prototype);
1197}
1198
1199ko.subscribable['fn'] = ko_subscribable_fn;
1200
1201
1202ko.isSubscribable = function (instance) {
1203    return instance != null && typeof instance.subscribe == "function" && typeof instance["notifySubscribers"] == "function";
1204};
1205
1206ko.exportSymbol('subscribable', ko.subscribable);
1207ko.exportSymbol('isSubscribable', ko.isSubscribable);
1208
1209ko.computedContext = ko.dependencyDetection = (function () {
1210    var outerFrames = [],
1211        currentFrame,
1212        lastId = 0;
1213
1214    // Return a unique ID that can be assigned to an observable for dependency tracking.
1215    // Theoretically, you could eventually overflow the number storage size, resulting
1216    // in duplicate IDs. But in JavaScript, the largest exact integral value is 2^53
1217    // or 9,007,199,254,740,992. If you created 1,000,000 IDs per second, it would
1218    // take over 285 years to reach that number.
1219    // Reference http://blog.vjeux.com/2010/javascript/javascript-max_int-number-limits.html
1220    function getId() {
1221        return ++lastId;
1222    }
1223
1224    function begin(options) {
1225        outerFrames.push(currentFrame);
1226        currentFrame = options;
1227    }
1228
1229    function end() {
1230        currentFrame = outerFrames.pop();
1231    }
1232
1233    return {
1234        begin: begin,
1235
1236        end: end,
1237
1238        registerDependency: function (subscribable) {
1239            if (currentFrame) {
1240                if (!ko.isSubscribable(subscribable))
1241                    throw new Error("Only subscribable things can act as dependencies");
1242                currentFrame.callback(subscribable, subscribable._id || (subscribable._id = getId()));
1243            }
1244        },
1245
1246        ignore: function (callback, callbackTarget, callbackArgs) {
1247            try {
1248                begin();
1249                return callback.apply(callbackTarget, callbackArgs || []);
1250            } finally {
1251                end();
1252            }
1253        },
1254
1255        getDependenciesCount: function () {
1256            if (currentFrame)
1257                return currentFrame.computed.getDependenciesCount();
1258        },
1259
1260        isInitial: function() {
1261            if (currentFrame)
1262                return currentFrame.isInitial;
1263        }
1264    };
1265})();
1266
1267ko.exportSymbol('computedContext', ko.computedContext);
1268ko.exportSymbol('computedContext.getDependenciesCount', ko.computedContext.getDependenciesCount);
1269ko.exportSymbol('computedContext.isInitial', ko.computedContext.isInitial);
1270ko.exportSymbol('computedContext.isSleeping', ko.computedContext.isSleeping);
1271
1272ko.exportSymbol('ignoreDependencies', ko.ignoreDependencies = ko.dependencyDetection.ignore);
1273ko.observable = function (initialValue) {
1274    var _latestValue = initialValue;
1275
1276    function observable() {
1277        if (arguments.length > 0) {
1278            // Write
1279
1280            // Ignore writes if the value hasn't changed
1281            if (observable.isDifferent(_latestValue, arguments[0])) {
1282                observable.valueWillMutate();
1283                _latestValue = arguments[0];
1284                if (DEBUG) observable._latestValue = _latestValue;
1285                observable.valueHasMutated();
1286            }
1287            return this; // Permits chained assignments
1288        }
1289        else {
1290            // Read
1291            ko.dependencyDetection.registerDependency(observable); // The caller only needs to be notified of changes if they did a "read" operation
1292            return _latestValue;
1293        }
1294    }
1295    ko.subscribable.call(observable);
1296    ko.utils.setPrototypeOfOrExtend(observable, ko.observable['fn']);
1297
1298    if (DEBUG) observable._latestValue = _latestValue;
1299    observable.peek = function() { return _latestValue };
1300    observable.valueHasMutated = function () { observable["notifySubscribers"](_latestValue); }
1301    observable.valueWillMutate = function () { observable["notifySubscribers"](_latestValue, "beforeChange"); }
1302
1303    ko.exportProperty(observable, 'peek', observable.peek);
1304    ko.exportProperty(observable, "valueHasMutated", observable.valueHasMutated);
1305    ko.exportProperty(observable, "valueWillMutate", observable.valueWillMutate);
1306
1307    return observable;
1308}
1309
1310ko.observable['fn'] = {
1311    "equalityComparer": valuesArePrimitiveAndEqual
1312};
1313
1314var protoProperty = ko.observable.protoProperty = "__ko_proto__";
1315ko.observable['fn'][protoProperty] = ko.observable;
1316
1317// Note that for browsers that don't support proto assignment, the
1318// inheritance chain is created manually in the ko.observable constructor
1319if (ko.utils.canSetPrototype) {
1320    ko.utils.setPrototypeOf(ko.observable['fn'], ko.subscribable['fn']);
1321}
1322
1323ko.hasPrototype = function(instance, prototype) {
1324    if ((instance === null) || (instance === undefined) || (instance[protoProperty] === undefined)) return false;
1325    if (instance[protoProperty] === prototype) return true;
1326    return ko.hasPrototype(instance[protoProperty], prototype); // Walk the prototype chain
1327};
1328
1329ko.isObservable = function (instance) {
1330    return ko.hasPrototype(instance, ko.observable);
1331}
1332ko.isWriteableObservable = function (instance) {
1333    // Observable
1334    if ((typeof instance == "function") && instance[protoProperty] === ko.observable)
1335        return true;
1336    // Writeable dependent observable
1337    if ((typeof instance == "function") && (instance[protoProperty] === ko.dependentObservable) && (instance.hasWriteFunction))
1338        return true;
1339    // Anything else
1340    return false;
1341}
1342
1343
1344ko.exportSymbol('observable', ko.observable);
1345ko.exportSymbol('isObservable', ko.isObservable);
1346ko.exportSymbol('isWriteableObservable', ko.isWriteableObservable);
1347ko.exportSymbol('isWritableObservable', ko.isWriteableObservable);
1348ko.observableArray = function (initialValues) {
1349    initialValues = initialValues || [];
1350
1351    if (typeof initialValues != 'object' || !('length' in initialValues))
1352        throw new Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");
1353
1354    var result = ko.observable(initialValues);
vendor: 5,631 bytes, lines 1355-1491
1355    ko.utils.setPrototypeOfOrExtend(result, ko.observableArray['fn']);
1356    return result.extend({'trackArrayChanges':true});
1357};
1358
1359ko.observableArray['fn'] = {
1360    'remove': function (valueOrPredicate) {
1361        var underlyingArray = this.peek();
1362        var removedValues = [];
1363        var predicate = typeof valueOrPredicate == "function" && !ko.isObservable(valueOrPredicate) ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
1364        for (var i = 0; i < underlyingArray.length; i++) {
1365            var value = underlyingArray[i];
1366            if (predicate(value)) {
1367                if (removedValues.length === 0) {
1368                    this.valueWillMutate();
1369                }
1370                removedValues.push(value);
1371                underlyingArray.splice(i, 1);
1372                i--;
1373            }
1374        }
1375        if (removedValues.length) {
1376            this.valueHasMutated();
1377        }
1378        return removedValues;
1379    },
1380
1381    'removeAll': function (arrayOfValues) {
1382        // If you passed zero args, we remove everything
1383        if (arrayOfValues === undefined) {
1384            var underlyingArray = this.peek();
1385            var allValues = underlyingArray.slice(0);
1386            this.valueWillMutate();
1387            underlyingArray.splice(0, underlyingArray.length);
1388            this.valueHasMutated();
1389            return allValues;
1390        }
1391        // If you passed an arg, we interpret it as an array of entries to remove
1392        if (!arrayOfValues)
1393            return [];
1394        return this['remove'](function (value) {
1395            return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
1396        });
1397    },
1398
1399    'destroy': function (valueOrPredicate) {
1400        var underlyingArray = this.peek();
1401        var predicate = typeof valueOrPredicate == "function" && !ko.isObservable(valueOrPredicate) ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
1402        this.valueWillMutate();
1403        for (var i = underlyingArray.length - 1; i >= 0; i--) {
1404            var value = underlyingArray[i];
1405            if (predicate(value))
1406                underlyingArray[i]["_destroy"] = true;
1407        }
1408        this.valueHasMutated();
1409    },
1410
1411    'destroyAll': function (arrayOfValues) {
1412        // If you passed zero args, we destroy everything
1413        if (arrayOfValues === undefined)
1414            return this['destroy'](function() { return true });
1415
1416        // If you passed an arg, we interpret it as an array of entries to destroy
1417        if (!arrayOfValues)
1418            return [];
1419        return this['destroy'](function (value) {
1420            return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
1421        });
1422    },
1423
1424    'indexOf': function (item) {
1425        var underlyingArray = this();
1426        return ko.utils.arrayIndexOf(underlyingArray, item);
1427    },
1428
1429    'replace': function(oldItem, newItem) {
1430        var index = this['indexOf'](oldItem);
1431        if (index >= 0) {
1432            this.valueWillMutate();
1433            this.peek()[index] = newItem;
1434            this.valueHasMutated();
1435        }
1436    }
1437};
1438
1439// Populate ko.observableArray.fn with read/write functions from native arrays
1440// Important: Do not add any additional functions here that may reasonably be used to *read* data from the array
1441// because we'll eval them without causing subscriptions, so ko.computed output could end up getting stale
1442ko.utils.arrayForEach(["pop", "push", "reverse", "shift", "sort", "splice", "unshift"], function (methodName) {
1443    ko.observableArray['fn'][methodName] = function () {
1444        // Use "peek" to avoid creating a subscription in any computed that we're executing in the context of
1445        // (for consistency with mutating regular observables)
1446        var underlyingArray = this.peek();
1447        this.valueWillMutate();
1448        this.cacheDiffForKnownOperation(underlyingArray, methodName, arguments);
1449        var methodCallResult = underlyingArray[methodName].apply(underlyingArray, arguments);
1450        this.valueHasMutated();
1451        return methodCallResult;
1452    };
1453});
1454
1455// Populate ko.observableArray.fn with read-only functions from native arrays
1456ko.utils.arrayForEach(["slice"], function (methodName) {
1457    ko.observableArray['fn'][methodName] = function () {
1458        var underlyingArray = this();
1459        return underlyingArray[methodName].apply(underlyingArray, arguments);
1460    };
1461});
1462
1463// Note that for browsers that don't support proto assignment, the
1464// inheritance chain is created manually in the ko.observableArray constructor
1465if (ko.utils.canSetPrototype) {
1466    ko.utils.setPrototypeOf(ko.observableArray['fn'], ko.observable['fn']);
1467}
1468
1469ko.exportSymbol('observableArray', ko.observableArray);
1470var arrayChangeEventName = 'arrayChange';
1471ko.extenders['trackArrayChanges'] = function(target) {
1472    // Only modify the target observable once
1473    if (target.cacheDiffForKnownOperation) {
1474        return;
1475    }
1476    var trackingChanges = false,
1477        cachedDiff = null,
1478        arrayChangeSubscription,
1479        pendingNotifications = 0,
1480        underlyingBeforeSubscriptionAddFunction = target.beforeSubscriptionAdd,
1481        underlyingAfterSubscriptionRemoveFunction = target.afterSubscriptionRemove;
1482
1483    // Watch "subscribe" calls, and for array change events, ensure change tracking is enabled
1484    target.beforeSubscriptionAdd = function (event) {
1485        if (underlyingBeforeSubscriptionAddFunction)
1486            underlyingBeforeSubscriptionAddFunction.call(target, event);
1487        if (event === arrayChangeEventName) {
1488            trackChanges();
1489        }
1490    };
1491    // Watch "dispose" calls, and for array change events, ensure change tracking is disabled 
1491when all are disposed
1492    target.afterSubscriptionRemove = function (event) {
1493        if (underlyingAfterSubscriptionRemoveFunction)
1494            underlyingAfterSubscriptionRemoveFunction.call(target, event);
1495        if (event === arrayChangeEventName && !target.hasSubscriptionsForEvent(arrayChangeEventName)) {
1496            arrayChangeSubscription.dispose();
1497            trackingChanges = false;
1498        }
1499    };
1500
1501    function trackChanges() {
1502        // Calling 'trackChanges' multiple times is the same as calling it once
1503        if (trackingChanges) {
1504            return;
1505        }
1506
1507        trackingChanges = true;
1508
1509        // Intercept "notifySubscribers" to track how many times it was called.
1510        var underlyingNotifySubscribersFunction = target['notifySubscribers'];
1511        target['notifySubscribers'] = function(valueToNotify, event) {
1512            if (!event || event === defaultEvent) {
1513                ++pendingNotifications;
1514            }
1515            return underlyingNotifySubscribersFunction.apply(this, arguments);
1516        };
1517
1518        // Each time the array changes value, capture a clone so that on the next
1519        // change it's possible to produce a diff
1520        var previousContents = [].concat(target.peek() || []);
1521        cachedDiff = null;
1522        arrayChangeSubscription = target.subscribe(function(currentContents) {
1523            // Make a copy of the current contents and ensure it's an array
1524            currentContents = [].concat(currentContents || []);
1525
1526            // Compute the diff and issue notifications, but only if someone is listening
1527            if (target.hasSubscriptionsForEvent(arrayChangeEventName)) {
1528                var changes = getChanges(previousContents, currentContents);
1529            }
1530
1531            // Eliminate references to the old, removed items, so they can be GCed
1532            previousContents = currentContents;
1533            cachedDiff = null;
1534            pendingNotifications = 0;
1535
1536            if (changes && changes.length) {
1537                target['notifySubscribers'](changes, arrayChangeEventName);
1538            }
1539        });
1540    }
1541
1542    function getChanges(previousContents, currentContents) {
1543        // We try to re-use cached diffs.
1544        // The scenarios where pendingNotifications > 1 are when using rate-limiting or the Deferred Updates
1545        // plugin, which without this check would not be compatible with arrayChange notifications. Normally,
1546        // notifications are issued immediately so we wouldn't be queueing up more than one.
1547        if (!cachedDiff || pendingNotifications > 1) {
1548            cachedDiff = ko.utils.compareArrays(previousContents, currentContents, { 'sparse': true });
1549        }
1550
1551        return cachedDiff;
1552    }
1553
1554    target.cacheDiffForKnownOperation = function(rawArray, operationName, args) {
1555        // Only run if we're currently tracking changes for this observable array
1556        // and there aren't any pending deferred notifications.
1557        if (!trackingChanges || pendingNotifications) {
1558            return;
1559        }
1560        var diff = [],
1561            arrayLength = rawArray.length,
1562            argsLength = args.length,
1563            offset = 0;
1564
1565        function pushDiff(status, value, index) {
1566            return diff[diff.length] = { 'status': status, 'value': value, 'index': index };
1567        }
1568        switch (operationName) {
1569            case 'push':
1570                offset = arrayLength;
1571            case 'unshift':
1572                for (var index = 0; index < argsLength; index++) {
1573                    pushDiff('added', args[index], offset + index);
1574                }
1575                break;
1576
1577            case 'pop':
1578                offset = arrayLength - 1;
1579            case 'shift':
1580                if (arrayLength) {
1581                    pushDiff('deleted', rawArray[offset], offset);
1582                }
1583                break;
1584
1585            case 'splice':
1586                // Negative start index means 'from end of array'. After that we clamp to [0...arrayLength].
1587                // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
1588                var startIndex = Math.min(Math.max(0, args[0] < 0 ? arrayLength + args[0] : args[0]), arrayLength),
1589                    endDeleteIndex = argsLength === 1 ? arrayLength : Math.min(startIndex + (args[1] || 0), arrayLength),
1590                    endAddIndex = startIndex + argsLength - 2,
1591                    endIndex = Math.max(endDeleteIndex, endAddIndex),
1592                    additions = [], deletions = [];
1593                for (var index = startIndex, argsIndex = 2; index < endIndex; ++index, ++argsIndex) {
1594                    if (index < endDeleteIndex)
1595                        deletions.push(pushDiff('deleted', rawArray[index], index));
1596                    if (index < endAddIndex)
1597                        additions.push(pushDiff('added', args[argsIndex], index));
1598                }
1599                ko.utils.findMovesInArrayComparison(deletions, additions);
1600                break;
1601
1602            default:
1603                return;
1604        }
1605        cachedDiff = diff;
1606    };
1607};
1608ko.computed = ko.dependentObservable = function (evaluatorFunctionOrOptions, evaluatorFunctionTarget, options) {
1609    var _latestValue,
1610        _needsEvaluation = true,
1611        _isBeingEvaluated = false,
1612        _suppressDisposalUntilDisposeWhenReturnsFalse = false,
1613        _isDisposed = false,
1614        readFunction = evaluatorFunctionOrOptions,
1615        pure = false,
1616        isSleeping = false;
1617
1618    if (readFunction && typeof readFunction == "object") {
1619        // Single-parameter syntax - everything is on this "options" param
1620        options = readFunction;
1621        readFunction = options["read"];
1622    } else {
1623        // Multi-parameter syntax - construct the options according to the params passed
1624        options = options || {};
1625        if (!readFunction)
1626            readFunction = options["read"];
1627    }
1628    if (typeof readFunction != "function")
1629        throw new Error("Pass a function that returns the value of the ko.computed");
1630
1631    function addDependencyTracking(id, target, trackingObj) {
1632        if (pure && target === dependentObservable) {
1633            throw Error("A 'pure' computed must not be called recursively");
1634        }
1635
1636        dependencyTracking[id] = trackingObj;
1637        trackingObj._order = _dependenciesCount++;
1638        trackingObj._version = target.getVersion();
1639    }
1640
1641    function haveDependenciesChanged() {
1642        var id, dependency;
1643        for (id in dependencyTracking) {
1644            if (dependencyTracking.hasOwnProperty(id)) {
1645                dependency = dependencyTracking[id];
1646                if (dependency._target.hasChanged(dependency._version)) {
1647                    return true;
1648                }
1649            }
1650        }
1651    }
1652
1653    function disposeComputed() {
1654        if (!isSleeping && dependencyTracking) {
1655            ko.utils.objectForEach(dependencyTracking, function (id, dependency) {
1656                if (dependency.dispose)
1657                    dependency.dispose();
1658            });
1659        }
1660        dependencyTracking = null;
1661        _dependenciesCount = 0;
1662        _isDisposed = true;
1663        _needsEvaluation = false;
1664        isSleeping = false;
1665    }
1666
1667    function evaluatePossiblyAsync() {
1668        var throttleEvaluationTimeout = dependentObservable['throttleEvaluation'];
1669        if (throttleEvaluationTimeout && throttleEvaluationTimeout >= 0) {
1670            clearTimeout(evaluationTimeoutInstance);
1671            evaluationTimeoutInstance = setTimeout(function () {
1672                evaluateImmediate(true /*notifyChange*/);
1673            }, throttleEvaluationTimeout);
1674        } else if (dependentObservable._evalRateLimited) {
1675            dependentObservable._evalRateLimited();
1676        } else {
1677            evaluateImmediate(true /*notifyChange*/);
1678        }
1679    }
1680
1681    function evaluateImmediate(notifyChange) {
1682        if (_isBeingEvaluated) {
1683            // If the evaluation of a ko.computed causes side effects, it's possible that it will trigger its own re-evaluation.
1684            // This is not desirable (it's hard for a developer to realise a chain of dependencies might cause this, and they almost
1685            // certainly didn't intend infinite re-evaluations). So, for predictability, we simply prevent ko.computeds from causing
1686            // their own re-evaluation. Further discussion at https://github.com/SteveSanderson/knockout/pull/387
1687            return;
1688        }
1689
1690        // Do not evaluate (and possibly capture new dependencies) if disposed
1691        if (_isDisposed) {
1692            return;
1693        }
1694
1695        if (disposeWhen && disposeWhen()) {
1696            // See comment below about _suppressDisposalUntilDisposeWhenReturns
1696False
1697            if (!_suppressDisposalUntilDisposeWhenReturnsFalse) {
1698                dispose();
1699                return;
1700            }
1701        } else {
1702            // It just did return false, so we can stop suppressing now
1703            _suppressDisposalUntilDisposeWhenReturnsFalse = false;
1704        }
1705
1706        _isBeingEvaluated = true;
1707
1708        try {
1709            // Initially, we assume that none of the subscriptions are still being used (i.e., all are candidates for disposal).
1710            // Then, during evaluation, we cross off any that are in fact still being used.
1711            var disposalCandidates = dependencyTracking,
1712                disposalCount = _dependenciesCount,
1713                isInitial = pure ? undefined : !_dependenciesCount;   // If we're evaluating when there are no previous dependencies, it must be the first time
1714
1715            ko.dependencyDetection.begin({
1716                callback: function(subscribable, id) {
1717                    if (!_isDisposed) {
1718                        if (disposalCount && disposalCandidates[id]) {
1719                            // Don't want to dispose this subscription, as it's still being used
1720                            addDependencyTracking(id, subscribable, disposalCandidates[id]);
1721                            delete disposalCandidates[id];
1722                            --disposalCount;
1723                        } else if (!dependencyTracking[id]) {
1724                            // Brand new subscription - add it
1725                            addDependencyTracking(id, subscribable, isSleeping ? { _target: subscribable } : subscribable.subscribe(evaluatePossiblyAsync));
1726                        }
1727                    }
1728                },
1729                computed: dependentObservable,
1730                isInitial: isInitial
1731            });
1732
1733            dependencyTracking = {};
1734            _dependenciesCount = 0;
1735
1736            try {
1737                var newValue = evaluatorFunctionTarget ? readFunction.call(evaluatorFunctionTarget) : readFunction();
1738
1739            } finally {
1740                ko.dependencyDetection.end();
1741
1742                // For each subscription no longer being used, remove it from the active subscriptions list and dispose it
1743                if (disposalCount && !isSleeping) {
1744                    ko.utils.objectForEach(disposalCandidates, function(id, toDispose) {
1745                        if (toDispose.dispose)
1746                            toDispose.dispose();
1747                    });
1748                }
1749
1750                _needsEvaluation = false;
1751            }
1752
1753            if (dependentObservable.isDifferent(_latestValue, newValue)) {
1754                if (!isSleeping) {
1755                    notify(_latestValue, "beforeChange");
1756                }
1757
1758                _latestValue = newValue;
1759                if (DEBUG) dependentObservable._latestValue = _latestValue;
1760
1761                if (isSleeping) {
1762                    dependentObservable.updateVersion();
1763                } else if (notifyChange) {
1764                    notify(_latestValue);
1765                }
1766            }
1767
1768            if (isInitial) {
1769                notify(_latestValue, "awake");
1770            }
1771        } finally {
1772            _isBeingEvaluated = false;
1773        }
1774
1775        if (!_dependenciesCount)
1776            dispose();
1777    }
1778
1779    function dependentObservable() {
1780        if (arguments.length > 0) {
1781            if (typeof writeFunction === "function") {
1782                // Writing a value
1783                writeFunction.apply(evaluatorFunctionTarget, arguments);
1784            } else {
1785                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.");
1786            }
1787            return this; // Permits chained assignments
1788        } else {
1789            // Reading the value
1790            ko.dependencyDetection.registerDependency(dependentObservable);
1791            if (_needsEvaluation || (isSleeping && haveDependenciesChanged())) {
1792                evaluateImmediate();
1793            }
1794            return _latestValue;
1795        }
1796    }
1797
1798    function peek() {
1799        // Peek won't re-evaluate, except while the computed is sleeping or to get the initial value when "deferEvaluation" is set.
1800        if ((_needsEvaluation && !_dependenciesCount) || (isSleeping && haveDependenciesChanged())) {
1801            evaluateImmediate();
1802        }
1803        return _latestValue;
1804    }
1805
1806    function isActive() {
1807        return _needsEvaluation || _dependenciesCount > 0;
1808    }
1809
1810    function notify(value, event) {
1811        dependentObservable["notifySubscribers"](value, event);
1812    }
1813
1814    // By here, "options" is always non-null
1815    var writeFunction = options["write"],
1816        disposeWhenNodeIsRemoved = options["disposeWhenNodeIsRemoved"] || options.disposeWhenNodeIsRemoved || null,
1817        disposeWhenOption = options["disposeWhen"] || options.disposeWhen,
1818        disposeWhen = disposeWhenOption,
1819        dispose = disposeComputed,
1820        dependencyTracking = {},
1821        _dependenciesCount = 0,
1822        evaluationTimeoutInstance = null;
1823
1824    if (!evaluatorFunctionTarget)
1825        evaluatorFunctionTarget = options["owner"];
1826
1827    ko.subscribable.call(dependentObservable);
1828    ko.utils.setPrototypeOfOrExtend(dependentObservable, ko.dependentObservable['fn']);
1829
1830    dependentObservable.peek = peek;
1831    dependentObservable.getDependenciesCount = function () { return _dependenciesCount; };
1832    dependentObservable.hasWriteFunction = typeof writeFunction === "function";
1833    dependentObservable.dispose = function () { dispose(); };
1834    dependentObservable.isActive = isActive;
1835
1836    // Replace the limit function with one that delays evaluation as well.
1837    var originalLimit = dependentObservable.limit;
1838    dependentObservable.limit = function(limitFunction) {
1839        originalLimit.call(dependentObservable, limitFunction);
1840        dependentObservable._evalRateLimited = function() {
1841            dependentObservable._rateLimitedBeforeChange(_latestValue);
1842
1843            _needsEvaluation = true;    // Mark as dirty
1844
1845            // Pass the observable to the rate-limit code, which will access it when
1846            // it's time to do the notification.
1847            dependentObservable._rateLimitedChange(dependentObservable);
1848        }
1849    };
1850
1851    if (options['pure']) {
1852        pure = true;
1853        isSleeping = true;     // Starts off sleeping; will awake on the first subscription
1854        dependentObservable.beforeSubscriptionAdd = function (event) {
1855            // If asleep, wake up the computed by subscribing to any dependencies.
1856            if (!_isDisposed && isSleeping && event == 'change') {
1857                isSleeping = false;
1858                if (_needsEvaluation || haveDependenciesChanged()) {
1859                    dependencyTracking = null;
1860                    _dependenciesCount = 0;
1861                    _needsEvaluation = true;
1862                    evaluateImmediate();
1863                } else {
1864                    // First put the dependencies in order
1865                    var dependeciesOrder = [];
1866                    ko.utils.objectForEach(dependencyTracking, function (id, dependency) {
1867                        dependeciesOrder[dependency._order] = id;
1868                    });
1869                    // Next, subscribe to each one
1870                    ko.utils.arrayForEach(dependeciesOrder, function(id, order) {
1871                        var dependency = dependencyTracking[id],
1872                            subscription = dependency._target.subscribe(evaluatePossiblyAsync);
1873                        subscription._order = order;
1874                        subscription._version = dependency._version;
1875                        dependencyTracking[id] = subscription;
1876                    });
1877                }
1878                if (!_isDisposed) {     // test since evaluating could trigger disposal
1879                    notify(_latestValue, "awake");
1880                }
1881            }
1882        };
1883
1884        dependentObservable.afterSubscriptionRemove = function (event) {
1885            if (!_isDisposed && event == 'change' && !dependentObservable.hasSubscriptionsForEvent('change')) {
1886                ko.utils.objectForEach(dependencyTracking, function (id, dependency) {
1887                    if (dependency.dispose) {
1888                        dependencyTracking[id] = {
vendor: 39,796 bytes, lines 1889-2662
1889                            _target: dependency._target,
1890                            _order: dependency._order,
1891                            _version: dependency._version
1892                        };
1893                        dependency.dispose();
1894                    }
1895                });
1896                isSleeping = true;
1897                notify(undefined, "asleep");
1898            }
1899        };
1900
1901        // Because a pure computed is not automatically updated while it is sleeping, we can't
1902        // simply return the version number. Instead, we check if any of the dependencies have
1903        // changed and conditionally re-evaluate the computed observable.
1904        dependentObservable._originalGetVersion = dependentObservable.getVersion;
1905        dependentObservable.getVersion = function () {
1906            if (isSleeping && (_needsEvaluation || haveDependenciesChanged())) {
1907                evaluateImmediate();
1908            }
1909            return dependentObservable._originalGetVersion();
1910        };
1911    } else if (options['deferEvaluation']) {
1912        // This will force a computed with deferEvaluation to evaluate when the first subscriptions is registered.
1913        dependentObservable.beforeSubscriptionAdd = function (event) {
1914            if (event == 'change' || event == 'beforeChange') {
1915                peek();
1916            }
1917        }
1918    }
1919
1920    ko.exportProperty(dependentObservable, 'peek', dependentObservable.peek);
1921    ko.exportProperty(dependentObservable, 'dispose', dependentObservable.dispose);
1922    ko.exportProperty(dependentObservable, 'isActive', dependentObservable.isActive);
1923    ko.exportProperty(dependentObservable, 'getDependenciesCount', dependentObservable.getDependenciesCount);
1924
1925    // Add a "disposeWhen" callback that, on each evaluation, disposes if the node was removed without using ko.removeNode.
1926    if (disposeWhenNodeIsRemoved) {
1927        // Since this computed is associated with a DOM node, and we don't want to dispose the computed
1928        // until the DOM node is *removed* from the document (as opposed to never having been in the document),
1929        // we'll prevent disposal until "disposeWhen" first returns false.
1930        _suppressDisposalUntilDisposeWhenReturnsFalse = true;
1931
1932        // Only watch for the node's disposal if the value really is a node. It might not be,
1933        // e.g., { disposeWhenNodeIsRemoved: true } can be used to opt into the "only dispose
1934        // after first false result" behaviour even if there's no specific node to watch. This
1935        // technique is intended for KO's internal use only and shouldn't be documented or used
1936        // by application code, as it's likely to change in a future version of KO.
1937        if (disposeWhenNodeIsRemoved.nodeType) {
1938            disposeWhen = function () {
1939                return !ko.utils.domNodeIsAttachedToDocument(disposeWhenNodeIsRemoved) || (disposeWhenOption && disposeWhenOption());
1940            };
1941        }
1942    }
1943
1944    // Evaluate, unless sleeping or deferEvaluation is true
1945    if (!isSleeping && !options['deferEvaluation'])
1946        evaluateImmediate();
1947
1948    // Attach a DOM node disposal callback so that the computed will be proactively disposed as soon as the node is
1949    // removed using ko.removeNode. But skip if isActive is false (there will never be any dependencies to dispose).
1950    if (disposeWhenNodeIsRemoved && isActive() && disposeWhenNodeIsRemoved.nodeType) {
1951        dispose = function() {
1952            ko.utils.domNodeDisposal.removeDisposeCallback(disposeWhenNodeIsRemoved, dispose);
1953            disposeComputed();
1954        };
1955        ko.utils.domNodeDisposal.addDisposeCallback(disposeWhenNodeIsRemoved, dispose);
1956    }
1957
1958    return dependentObservable;
1959};
1960
1961ko.isComputed = function(instance) {
1962    return ko.hasPrototype(instance, ko.dependentObservable);
1963};
1964
1965var protoProp = ko.observable.protoProperty; // == "__ko_proto__"
1966ko.dependentObservable[protoProp] = ko.observable;
1967
1968ko.dependentObservable['fn'] = {
1969    "equalityComparer": valuesArePrimitiveAndEqual
1970};
1971ko.dependentObservable['fn'][protoProp] = ko.dependentObservable;
1972
1973// Note that for browsers that don't support proto assignment, the
1974// inheritance chain is created manually in the ko.dependentObservable constructor
1975if (ko.utils.canSetPrototype) {
1976    ko.utils.setPrototypeOf(ko.dependentObservable['fn'], ko.subscribable['fn']);
1977}
1978
1979ko.exportSymbol('dependentObservable', ko.dependentObservable);
1980ko.exportSymbol('computed', ko.dependentObservable); // Make "ko.computed" an alias for "ko.dependentObservable"
1981ko.exportSymbol('isComputed', ko.isComputed);
1982
1983ko.pureComputed = function (evaluatorFunctionOrOptions, evaluatorFunctionTarget) {
1984    if (typeof evaluatorFunctionOrOptions === 'function') {
1985        return ko.computed(evaluatorFunctionOrOptions, evaluatorFunctionTarget, {'pure':true});
1986    } else {
1987        evaluatorFunctionOrOptions = ko.utils.extend({}, evaluatorFunctionOrOptions);   // make a copy of the parameter object
1988        evaluatorFunctionOrOptions['pure'] = true;
1989        return ko.computed(evaluatorFunctionOrOptions, evaluatorFunctionTarget);
1990    }
1991}
1992ko.exportSymbol('pureComputed', ko.pureComputed);
1993
1994(function() {
1995    var maxNestedObservableDepth = 10; // Escape the (unlikely) pathalogical case where an observable's current value is itself (or similar reference cycle)
1996
1997    ko.toJS = function(rootObject) {
1998        if (arguments.length == 0)
1999            throw new Error("When calling ko.toJS, pass the object you want to convert.");
2000
2001        // We just unwrap everything at every level in the object graph
2002        return mapJsObjectGraph(rootObject, function(valueToMap) {
2003            // Loop because an observable's value might in turn be another observable wrapper
2004            for (var i = 0; ko.isObservable(valueToMap) && (i < maxNestedObservableDepth); i++)
2005                valueToMap = valueToMap();
2006            return valueToMap;
2007        });
2008    };
2009
2010    ko.toJSON = function(rootObject, replacer, space) {     // replacer and space are optional
2011        var plainJavaScriptObject = ko.toJS(rootObject);
2012        return ko.utils.stringifyJson(plainJavaScriptObject, replacer, space);
2013    };
2014
2015    function mapJsObjectGraph(rootObject, mapInputCallback, visitedObjects) {
2016        visitedObjects = visitedObjects || new objectLookup();
2017
2018        rootObject = mapInputCallback(rootObject);
2019        var canHaveProperties = (typeof rootObject == "object") && (rootObject !== null) && (rootObject !== undefined) && (!(rootObject instanceof Date)) && (!(rootObject instanceof String)) && (!(rootObject instanceof Number)) && (!(rootObject instanceof Boolean));
2020        if (!canHaveProperties)
2021            return rootObject;
2022
2023        var outputProperties = rootObject instanceof Array ? [] : {};
2024        visitedObjects.save(rootObject, outputProperties);
2025
2026        visitPropertiesOrArrayEntries(rootObject, function(indexer) {
2027            var propertyValue = mapInputCallback(rootObject[indexer]);
2028
2029            switch (typeof propertyValue) {
2030                case "boolean":
2031                case "number":
2032                case "string":
2033                case "function":
2034                    outputProperties[indexer] = propertyValue;
2035                    break;
2036                case "object":
2037                case "undefined":
2038                    var previouslyMappedValue = visitedObjects.get(propertyValue);
2039                    outputProperties[indexer] = (previouslyMappedValue !== undefined)
2040                        ? previouslyMappedValue
2041                        : mapJsObjectGraph(propertyValue, mapInputCallback, visitedObjects);
2042                    break;
2043            }
2044        });
2045
2046        return outputProperties;
2047    }
2048
2049    function visitPropertiesOrArrayEntries(rootObject, visitorCallback) {
2050        if (rootObject instanceof Array) {
2051            for (var i = 0; i < rootObject.length; i++)
2052                visitorCallback(i);
2053
2054            // For arrays, also respect toJSON property for custom mappings (fixes #278)
2055            if (typeof rootObject['toJSON'] == 'function')
2056                visitorCallback('toJSON');
2057        } else {
2058            for (var propertyName in rootObject) {
2059                visitorCallback(propertyName);
2060            }
2061        }
2062    };
2063
2064    function objectLookup() {
2065        this.keys = [];
2066        this.values = [];
2067    };
2068
2069    objectLookup.prototype = {
2070        constructor: objectLookup,
2071        save: function(key, value) {
2072            var existingIndex = ko.utils.arrayIndexOf(this.keys, key);
2073            if (existingIndex >= 0)
2074                this.values[existingIndex] = value;
2075            else {
2076                this.keys.push(key);
2077                this.values.push(value);
2078            }
2079        },
2080        get: function(key) {
2081            var existingIndex = ko.utils.arrayIndexOf(this.keys, key);
2082            return (existingIndex >= 0) ? this.values[existingIndex] : undefined;
2083        }
2084    };
2085})();
2086
2087ko.exportSymbol('toJS', ko.toJS);
2088ko.exportSymbol('toJSON', ko.toJSON);
2089(function () {
2090    var hasDomDataExpandoProperty = '__ko__hasDomDataOptionValue__';
2091
2092    // Normally, SELECT elements and their OPTIONs can only take value of type 'string' (because the values
2093    // are stored on DOM attributes). ko.selectExtensions provides a way for SELECTs/OPTIONs to have values
2094    // that are arbitrary objects. This is very convenient when implementing things like cascading dropdowns.
2095    ko.selectExtensions = {
2096        readValue : function(element) {
2097            switch (ko.utils.tagNameLower(element)) {
2098                case 'option':
2099                    if (element[hasDomDataExpandoProperty] === true)
2100                        return ko.utils.domData.get(element, ko.bindingHandlers.options.optionValueDomDataKey);
2101                    return ko.utils.ieVersion <= 7
2102                        ? (element.getAttributeNode('value') && element.getAttributeNode('value').specified ? element.value : element.text)
2103                        : element.value;
2104                case 'select':
2105                    return element.selectedIndex >= 0 ? ko.selectExtensions.readValue(element.options[element.selectedIndex]) : undefined;
2106                default:
2107                    return element.value;
2108            }
2109        },
2110
2111        writeValue: function(element, value, allowUnset) {
2112            switch (ko.utils.tagNameLower(element)) {
2113                case 'option':
2114                    switch(typeof value) {
2115                        case "string":
2116                            ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, undefined);
2117                            if (hasDomDataExpandoProperty in element) { // IE <= 8 throws errors if you delete non-existent properties from a DOM node
2118                                delete element[hasDomDataExpandoProperty];
2119                            }
2120                            element.value = value;
2121                            break;
2122                        default:
2123                            // Store arbitrary object using DomData
2124                            ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, value);
2125                            element[hasDomDataExpandoProperty] = true;
2126
2127                            // Special treatment of numbers is just for backward compatibility. KO 1.2.1 wrote numerical values to element.value.
2128                            element.value = typeof value === "number" ? value : "";
2129                            break;
2130                    }
2131                    break;
2132                case 'select':
2133                    if (value === "" || value === null)       // A blank string or null value will select the caption
2134                        value = undefined;
2135                    var selection = -1;
2136                    for (var i = 0, n = element.options.length, optionValue; i < n; ++i) {
2137                        optionValue = ko.selectExtensions.readValue(element.options[i]);
2138                        // Include special check to handle selecting a caption with a blank string value
2139                        if (optionValue == value || (optionValue == "" && value === undefined)) {
2140                            selection = i;
2141                            break;
2142                        }
2143                    }
2144                    if (allowUnset || selection >= 0 || (value === undefined && element.size > 1)) {
2145                        element.selectedIndex = selection;
2146                    }
2147                    break;
2148                default:
2149                    if ((value === null) || (value === undefined))
2150                        value = "";
2151                    element.value = value;
2152                    break;
2153            }
2154        }
2155    };
2156})();
2157
2158ko.exportSymbol('selectExtensions', ko.selectExtensions);
2159ko.exportSymbol('selectExtensions.readValue', ko.selectExtensions.readValue);
2160ko.exportSymbol('selectExtensions.writeValue', ko.selectExtensions.writeValue);
2161ko.expressionRewriting = (function () {
2162    var javaScriptReservedWords = ["true", "false", "null", "undefined"];
2163
2164    // Matches something that can be assigned to--either an isolated identifier or something ending with a property accessor
2165    // This is designed to be simple and avoid false negatives, but could produce false positives (e.g., a+b.c).
2166    // This also will not properly handle nested brackets (e.g., obj1[obj2['prop']]; see #911).
2167    var javaScriptAssignmentTarget = /^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i;
2168
2169    function getWriteableValue(expression) {
2170        if (ko.utils.arrayIndexOf(javaScriptReservedWords, expression) >= 0)
2171            return false;
2172        var match = expression.match(javaScriptAssignmentTarget);
2173        return match === null ? false : match[1] ? ('Object(' + match[1] + ')' + match[2]) : expression;
2174    }
2175
2176    // The following regular expressions will be used to split an object-literal string into tokens
2177
2178        // These two match strings, either with double quotes or single quotes
2179    var stringDouble = '"(?:[^"\\\\]|\\\\.)*"',
2180        stringSingle = "'(?:[^'\\\\]|\\\\.)*'",
2181        // Matches a regular expression (text enclosed by slashes), but will also match sets of divisions
2182        // as a regular expression (this is handled by the parsing loop below).
2183        stringRegexp = '/(?:[^/\\\\]|\\\\.)*/\w*',
2184        // These characters have special meaning to the parser and must not appear in the middle of a
2185        // token, except as part of a string.
2186        specials = ',"\'{}()/:[\\]',
2187        // Match text (at least two characters) that does not contain any of the above special characters,
2188        // although some of the special characters are allowed to start it (all but the colon and comma).
2189        // The text can contain spaces, but leading or trailing spaces are skipped.
2190        everyThingElse = '[^\\s:,/][^' + specials + ']*[^\\s' + specials + ']',
2191        // Match any non-space character not matched already. This will match colons and commas, since they're
2192        // not matched by "everyThingElse", but will also match any other single character that wasn't already
2193        // matched (for example: in "a: 1, b: 2", each of the non-space characters will be matched by oneNotSpace).
2194        oneNotSpace = '[^\\s]',
2195
2196        // Create the actual regular expression by or-ing the above strings. The order is important.
2197        bindingToken = RegExp(stringDouble + '|' + stringSingle + '|' + stringRegexp + '|' + everyThingElse + '|' + oneNotSpace, 'g'),
2198
2199        // Match end of previous token to determine whether a slash is a division or regex.
2200        divisionLookBehind = /[\])"'A-Za-z0-9_$]+$/,
2201        keywordRegexLookBehind = {'in':1,'return':1,'typeof':1};
2202
2203    function parseObjectLiteral(objectLiteralString) {
2204        // Trim leading and trailing spaces from the string
2205        var str = ko.utils.stringTrim(objectLiteralString);
2206
2207        // Trim braces '{' surrounding the whole object literal
2208        if (str.charCodeAt(0) === 123) str = str.slice(1, -1);
2209
2210        // Split into tokens
2211        var result = [], toks = str.match(bindingToken), key, values = [], depth = 0;
2212
2213        if (toks) {
2214            // Append a comma so that we don't need a separate code block to deal with the last item
2215            toks.push(',');
2216
2217            for (var i = 0, tok; tok = toks[i]; ++i) {
2218                var c = tok.charCodeAt(0);
2219                // A comma signals the end of a key/value pair if depth is zero
2220                if (c === 44) { // ","
2221                    if (depth <= 0) {
2222                        result.push((key && values.length) ? {key: key, value: values.join('')} : {'unknown': key || values.join('')});
2223                        key = depth = 0;
2224                        values = [];
2225                        continue;
2226                    }
2227                // Simply skip the colon that separates the name and value
2228                } else if (c === 58) { // ":"
2229                    if (!depth && !key && values.length === 1) {
2230                        key = values.pop();
2231                        continue;
2232                    }
2233                // A set of slashes is initially matched as a regular expression, but could be division
2234                } else if (c === 47 && i && tok.length > 1) {  // "/"
2235                    // Look at the end of the previous token to determine if the slash is actually division
2236                    var match = toks[i-1].match(divisionLookBehind);
2237                    if (match && !keywordRegexLookBehind[match[0]]) {
2238                        // The slash is actually a division punctuator; re-parse the remainder of the string (not including the slash)
2239                        str = str.substr(str.indexOf(tok) + 1);
2240                        toks = str.match(bindingToken);
2241                        toks.push(',');
2242                        i = -1;
2243                        // Continue with just the slash
2244                        tok = '/';
2245                    }
2246                // Increment depth for parentheses, braces, and brackets so that interior commas are ignored
2247                } else if (c === 40 || c === 123 || c === 91) { // '(', '{', '['
2248                    ++depth;
2249                } else if (c === 41 || c === 125 || c === 93) { // ')', '}', ']'
2250                    --depth;
2251                // The key will be the first token; if it's a string, trim the quotes
2252                } else if (!key && !values.length && (c === 34 || c === 39)) { // '"', "'"
2253                    tok = tok.slice(1, -1);
2254                }
2255                values.push(tok);
2256            }
2257        }
2258        return result;
2259    }
2260
2261    // Two-way bindings include a write function that allow the handler to update the value even if it's not an observable.
2262    var twoWayBindings = {};
2263
2264    function preProcessBindings(bindingsStringOrKeyValueArray, bindingOptions) {
2265        bindingOptions = bindingOptions || {};
2266
2267        function processKeyValue(key, val) {
2268            var writableVal;
2269            function callPreprocessHook(obj) {
2270                return (obj && obj['preprocess']) ? (val = obj['preprocess'](val, key, processKeyValue)) : true;
2271            }
2272            if (!bindingParams) {
2273                if (!callPreprocessHook(ko['getBindingHandler'](key)))
2274                    return;
2275
2276                if (twoWayBindings[key] && (writableVal = getWriteableValue(val))) {
2277                    // For two-way bindings, provide a write method in case the value
2278                    // isn't a writable observable.
2279                    propertyAccessorResultStrings.push("'" + key + "':function(_z){" + writableVal + "=_z}");
2280                }
2281            }
2282            // Values are wrapped in a function so that each value can be accessed independently
2283            if (makeValueAccessors) {
2284                val = 'function(){return ' + val + ' }';
2285            }
2286            resultStrings.push("'" + key + "':" + val);
2287        }
2288
2289        var resultStrings = [],
2290            propertyAccessorResultStrings = [],
2291            makeValueAccessors = bindingOptions['valueAccessors'],
2292            bindingParams = bindingOptions['bindingParams'],
2293            keyValueArray = typeof bindingsStringOrKeyValueArray === "string" ?
2294                parseObjectLiteral(bindingsStringOrKeyValueArray) : bindingsStringOrKeyValueArray;
2295
2296        ko.utils.arrayForEach(keyValueArray, function(keyValue) {
2297            processKeyValue(keyValue.key || keyValue['unknown'], keyValue.value);
2298        });
2299
2300        if (propertyAccessorResultStrings.length)
2301            processKeyValue('_ko_property_writers', "{" + propertyAccessorResultStrings.join(",") + " }");
2302
2303        return resultStrings.join(",");
2304    }
2305
2306    return {
2307        bindingRewriteValidators: [],
2308
2309        twoWayBindings: twoWayBindings,
2310
2311        parseObjectLiteral: parseObjectLiteral,
2312
2313        preProcessBindings: preProcessBindings,
2314
2315        keyValueArrayContainsKey: function(keyValueArray, key) {
2316            for (var i = 0; i < keyValueArray.length; i++)
2317                if (keyValueArray[i]['key'] == key)
2318                    return true;
2319            return false;
2320        },
2321
2322        // Internal, private KO utility for updating model properties from within bindings
2323        // property:            If the property being updated is (or might be) an observable, pass it here
2324        //                      If it turns out to be a writable observable, it will be written to directly
2325        // allBindings:         An object with a get method to retrieve bindings in the current execution context.
2326        //                      This will be searched for a '_ko_property_writers' property in case you're writing to a non-observable
2327        // key:                 The key identifying the property to be written. Example: for { hasFocus: myValue }, write to 'myValue' by specifying the key 'hasFocus'
2328        // value:               The value to be written
2329        // checkIfDifferent:    If true, and if the property being written is a writable observable, the value will only be written if
2330        //                      it is !== existing value on that writable observable
2331        writeValueToProperty: function(property, allBindings, key, value, checkIfDifferent) {
2332            if (!property || !ko.isObservable(property)) {
2333                var propWriters = allBindings.get('_ko_property_writers');
2334                if (propWriters && propWriters[key])
2335                    propWriters[key](value);
2336            } else if (ko.isWriteableObservable(property) && (!checkIfDifferent || property.peek() !== value)) {
2337                property(value);
2338            }
2339        }
2340    };
2341})();
2342
2343ko.exportSymbol('expressionRewriting', ko.expressionRewriting);
2344ko.exportSymbol('expressionRewriting.bindingRewriteValidators', ko.expressionRewriting.bindingRewriteValidators);
2345ko.exportSymbol('expressionRewriting.parseObjectLiteral', ko.expressionRewriting.parseObjectLiteral);
2346ko.exportSymbol('expressionRewriting.preProcessBindings', ko.expressionRewriting.preProcessBindings);
2347
2348// Making bindings explicitly declare themselves as "two way" isn't ideal in the long term (it would be better if
2349// all bindings could use an official 'property writer' API without needing to declare that they might). However,
2350// since this is not, and has never been, a public API (_ko_property_writers was never documented), it's acceptable
2351// as an internal implementation detail in the short term.
2352// For those developers who rely on _ko_property_writers in their custom bindings, we expose _twoWayBindings as an
2353// undocumented feature that makes it relatively easy to upgrade to KO 3.0. However, this is still not an official
2354// public API, and we reserve the right to remove it at any time if we create a real public property writers API.
2355ko.exportSymbol('expressionRewriting._twoWayBindings', ko.expressionRewriting.twoWayBindings);
2356
2357// For backward compatibility, define the following aliases. (Previously, these function names were misleading because
2358// they referred to JSON specifically, even though they actually work with arbitrary JavaScript object literal expressions.)
2359ko.exportSymbol('jsonExpressionRewriting', ko.expressionRewriting);
2360ko.exportSymbol('jsonExpressionRewriting.insertPropertyAccessorsIntoJson', ko.expressionRewriting.preProcessBindings);
2361(function() {
2362    // "Virtual elements" is an abstraction on top of the usual DOM API which understands the notion that comment nodes
2363    // may be used to represent hierarchy (in addition to the DOM's natural hierarchy).
2364    // If you call the DOM-manipulating functions on ko.virtualElements, you will be able to read and write the state
2365    // of that virtual hierarchy
2366    //
2367    // The point of all this is to support containerless templates (e.g., <!-- ko foreach:someCollection -->blah<!-- /ko -->)
2368    // without having to scatter special cases all over the binding and templating code.
2369
2370    // IE 9 cannot reliably read the "nodeValue" property of a comment node (see https://github.com/SteveSanderson/knockout/issues/186)
2371    // but it does give them a nonstandard alternative property called "text" that it can read reliably. Other browsers don't have that property.
2372    // So, use node.text where available, and node.nodeValue elsewhere
2373    var commentNodesHaveTextProperty = document && document.createComment("test").text === "<!--test-->";
2374
2375    var startCommentRegex = commentNodesHaveTextProperty ? /^<!--\s*ko(?:\s+([\s\S]+))?\s*-->$/ : /^\s*ko(?:\s+([\s\S]+))?\s*$/;
2376    var endCommentRegex =   commentNodesHaveTextProperty ? /^<!--\s*\/ko\s*-->$/ : /^\s*\/ko\s*$/;
2377    var htmlTagsWithOptionallyClosingChildren = { 'ul': true, 'ol': true };
2378
2379    function isStartComment(node) {
2380        return (node.nodeType == 8) && startCommentRegex.test(commentNodesHaveTextProperty ? node.text : node.nodeValue);
2381    }
2382
2383    function isEndComment(node) {
2384        return (node.nodeType == 8) && endCommentRegex.test(commentNodesHaveTextProperty ? node.text : node.nodeValue);
2385    }
2386
2387    function getVirtualChildren(startComment, allowUnbalanced) {
2388        var currentNode = startComment;
2389        var depth = 1;
2390        var children = [];
2391        while (currentNode = currentNode.nextSibling) {
2392            if (isEndComment(currentNode)) {
2393                depth--;
2394                if (depth === 0)
2395                    return children;
2396            }
2397
2398            children.push(currentNode);
2399
2400            if (isStartComment(currentNode))
2401                depth++;
2402        }
2403        if (!allowUnbalanced)
2404            throw new Error("Cannot find closing comment tag to match: " + startComment.nodeValue);
2405        return null;
2406    }
2407
2408    function getMatchingEndComment(startComment, allowUnbalanced) {
2409        var allVirtualChildren = getVirtualChildren(startComment, allowUnbalanced);
2410        if (allVirtualChildren) {
2411            if (allVirtualChildren.length > 0)
2412                return allVirtualChildren[allVirtualChildren.length - 1].nextSibling;
2413            return startComment.nextSibling;
2414        } else
2415            return null; // Must have no matching end comment, and allowUnbalanced is true
2416    }
2417
2418    function getUnbalancedChildTags(node) {
2419        // e.g., from <div>OK</div><!-- ko blah --><span>Another</span>, returns: <!-- ko blah --><span>Another</span>
2420        //       from <div>OK</div><!-- /ko --><!-- /ko -->,             returns: <!-- /ko --><!-- /ko -->
2421        var childNode = node.firstChild, captureRemaining = null;
2422        if (childNode) {
2423            do {
2424                if (captureRemaining)                   // We already hit an unbalanced node and are now just scooping up all subsequent nodes
2425                    captureRemaining.push(childNode);
2426                else if (isStartComment(childNode)) {
2427                    var matchingEndComment = getMatchingEndComment(childNode, /* allowUnbalanced: */ true);
2428                    if (matchingEndComment)             // It's a balanced tag, so skip immediately to the end of this virtual set
2429                        childNode = matchingEndComment;
2430                    else
2431                        captureRemaining = [childNode]; // It's unbalanced, so start capturing from this point
2432                } else if (isEndComment(childNode)) {
2433                    captureRemaining = [childNode];     // It's unbalanced (if it wasn't, we'd have skipped over it already), so start capturing
2434                }
2435            } while (childNode = childNode.nextSibling);
2436        }
2437        return captureRemaining;
2438    }
2439
2440    ko.virtualElements = {
2441        allowedBindings: {},
2442
2443        childNodes: function(node) {
2444            return isStartComment(node) ? getVirtualChildren(node) : node.childNodes;
2445        },
2446
2447        emptyNode: function(node) {
2448            if (!isStartComment(node))
2449                ko.utils.emptyDomNode(node);
2450            else {
2451                var virtualChildren = ko.virtualElements.childNodes(node);
2452                for (var i = 0, j = virtualChildren.length; i < j; i++)
2453                    ko.removeNode(virtualChildren[i]);
2454            }
2455        },
2456
2457        setDomNodeChildren: function(node, childNodes) {
2458            if (!isStartComment(node))
2459                ko.utils.setDomNodeChildren(node, childNodes);
2460            else {
2461                ko.virtualElements.emptyNode(node);
2462                var endCommentNode = node.nextSibling; // Must be the next sibling, as we just emptied the children
2463                for (var i = 0, j = childNodes.length; i < j; i++)
2464                    endCommentNode.parentNode.insertBefore(childNodes[i], endCommentNode);
2465            }
2466        },
2467
2468        prepend: function(containerNode, nodeToPrepend) {
2469            if (!isStartComment(containerNode)) {
2470                if (containerNode.firstChild)
2471                    containerNode.insertBefore(nodeToPrepend, containerNode.firstChild);
2472                else
2473                    containerNode.appendChild(nodeToPrepend);
2474            } else {
2475                // Start comments must always have a parent and at least one following sibling (the end comment)
2476                containerNode.parentNode.insertBefore(nodeToPrepend, containerNode.nextSibling);
2477            }
2478        },
2479
2480        insertAfter: function(containerNode, nodeToInsert, insertAfterNode) {
2481            if (!insertAfterNode) {
2482                ko.virtualElements.prepend(containerNode, nodeToInsert);
2483            } else if (!isStartComment(containerNode)) {
2484                // Insert after insertion point
2485                if (insertAfterNode.nextSibling)
2486                    containerNode.insertBefore(nodeToInsert, insertAfterNode.nextSibling);
2487                else
2488                    containerNode.appendChild(nodeToInsert);
2489            } else {
2490                // Children of start comments must always have a parent and at least one following sibling (the end comment)
2491                containerNode.parentNode.insertBefore(nodeToInsert, insertAfterNode.nextSibling);
2492            }
2493        },
2494
2495        firstChild: function(node) {
2496            if (!isStartComment(node))
2497                return node.firstChild;
2498            if (!node.nextSibling || isEndComment(node.nextSibling))
2499                return null;
2500            return node.nextSibling;
2501        },
2502
2503        nextSibling: function(node) {
2504            if (isStartComment(node))
2505                node = getMatchingEndComment(node);
2506            if (node.nextSibling && isEndComment(node.nextSibling))
2507                return null;
2508            return node.nextSibling;
2509        },
2510
2511        hasBindingValue: isStartComment,
2512
2513        virtualNodeBindingValue: function(node) {
2514            var regexMatch = (commentNodesHaveTextProperty ? node.text : node.nodeValue).match(startCommentRegex);
2515            return regexMatch ? regexMatch[1] : null;
2516        },
2517
2518        normaliseVirtualElementDomStructure: function(elementVerified) {
2519            // Workaround for https://github.com/SteveSanderson/knockout/issues/155
2520            // (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
2521            // that are direct descendants of <ul> into the preceding <li>)
2522            if (!htmlTagsWithOptionallyClosingChildren[ko.utils.tagNameLower(elementVerified)])
2523                return;
2524
2525            // Scan immediate children to see if they contain unbalanced comment tags. If they do, those comment tags
2526            // must be intended to appear *after* that child, so move them there.
2527            var childNode = elementVerified.firstChild;
2528            if (childNode) {
2529                do {
2530                    if (childNode.nodeType === 1) {
2531                        var unbalancedTags = getUnbalancedChildTags(childNode);
2532                        if (unbalancedTags) {
2533                            // Fix up the DOM by moving the unbalanced tags to where they most likely were intended to be placed - *after* the child
2534                            var nodeToInsertBefore = childNode.nextSibling;
2535                            for (var i = 0; i < unbalancedTags.length; i++) {
2536                                if (nodeToInsertBefore)
2537                                    elementVerified.insertBefore(unbalancedTags[i], nodeToInsertBefore);
2538                                else
2539                                    elementVerified.appendChild(unbalancedTags[i]);
2540                            }
2541                        }
2542                    }
2543                } while (childNode = childNode.nextSibling);
2544            }
2545        }
2546    };
2547})();
2548ko.exportSymbol('virtualElements', ko.virtualElements);
2549ko.exportSymbol('virtualElements.allowedBindings', ko.virtualElements.allowedBindings);
2550ko.exportSymbol('virtualElements.emptyNode', ko.virtualElements.emptyNode);
2551//ko.exportSymbol('virtualElements.firstChild', ko.virtualElements.firstChild);     // firstChild is not minified
2552ko.exportSymbol('virtualElements.insertAfter', ko.virtualElements.insertAfter);
2553//ko.exportSymbol('virtualElements.nextSibling', ko.virtualElements.nextSibling);   // nextSibling is not minified
2554ko.exportSymbol('virtualElements.prepend', ko.virtualElements.prepend);
2555ko.exportSymbol('virtualElements.setDomNodeChildren', ko.virtualElements.setDomNodeChildren);
2556(function() {
2557    var defaultBindingAttributeName = "data-bind";
2558
2559    ko.bindingProvider = function() {
2560        this.bindingCache = {};
2561    };
2562
2563    ko.utils.extend(ko.bindingProvider.prototype, {
2564        'nodeHasBindings': function(node) {
2565            switch (node.nodeType) {
2566                case 1: // Element
2567                    return node.getAttribute(defaultBindingAttributeName) != null
2568                        || ko.components['getComponentNameForNode'](node);
2569                case 8: // Comment node
2570                    return ko.virtualElements.hasBindingValue(node);
2571                default: return false;
2572            }
2573        },
2574
2575        'getBindings': function(node, bindingContext) {
2576            var bindingsString = this['getBindingsString'](node, bindingContext),
2577                parsedBindings = bindingsString ? this['parseBindingsString'](bindingsString, bindingContext, node) : null;
2578            return ko.components.addBindingsForCustomElement(parsedBindings, node, bindingContext, /* valueAccessors */ false);
2579        },
2580
2581        'getBindingAccessors': function(node, bindingContext) {
2582            var bindingsString = this['getBindingsString'](node, bindingContext),
2583                parsedBindings = bindingsString ? this['parseBindingsString'](bindingsString, bindingContext, node, { 'valueAccessors': true }) : null;
2584            return ko.components.addBindingsForCustomElement(parsedBindings, node, bindingContext, /* valueAccessors */ true);
2585        },
2586
2587        // The following function is only used internally by this default provider.
2588        // It's not part of the interface definition for a general binding provider.
2589        'getBindingsString': function(node, bindingContext) {
2590            switch (node.nodeType) {
2591                case 1: return node.getAttribute(defaultBindingAttributeName);   // Element
2592                case 8: return ko.virtualElements.virtualNodeBindingValue(node); // Comment node
2593                default: return null;
2594            }
2595        },
2596
2597        // The following function is only used internally by this default provider.
2598        // It's not part of the interface definition for a general binding provider.
2599        'parseBindingsString': function(bindingsString, bindingContext, node, options) {
2600            try {
2601                var bindingFunction = createBindingsStringEvaluatorViaCache(bindingsString, this.bindingCache, options);
2602                return bindingFunction(bindingContext, node);
2603            } catch (ex) {
2604                ex.message = "Unable to parse bindings.\nBindings value: " + bindingsString + "\nMessage: " + ex.message;
2605                throw ex;
2606            }
2607        }
2608    });
2609
2610    ko.bindingProvider['instance'] = new ko.bindingProvider();
2611
2612    function createBindingsStringEvaluatorViaCache(bindingsString, cache, options) {
2613        var cacheKey = bindingsString + (options && options['valueAccessors'] || '');
2614        return cache[cacheKey]
2615            || (cache[cacheKey] = createBindingsStringEvaluator(bindingsString, options));
2616    }
2617
2618    function createBindingsStringEvaluator(bindingsString, options) {
2619        // Build the source for a function that evaluates "expression"
2620        // For each scope variable, add an extra level of "with" nesting
2621        // Example result: with(sc1) { with(sc0) { return (expression) } }
2622        var rewrittenBindings = ko.expressionRewriting.preProcessBindings(bindingsString, options),
2623            functionBody = "with($context){with($data||{}){return{" + rewrittenBindings + "}}}";
2624        return new Function("$context", "$element", functionBody);
2625    }
2626})();
2627
2628ko.exportSymbol('bindingProvider', ko.bindingProvider);
2629(function () {
2630    ko.bindingHandlers = {};
2631
2632    // The following element types will not be recursed into during binding. In the future, we
2633    // may consider adding <template> to this list, because such elements' contents are always
2634    // intended to be bound in a different context from where they appear in the document.
2635    var bindingDoesNotRecurseIntoElementTypes = {
2636        // Don't want bindings that operate on text nodes to mutate <script> and <textarea> contents,
2637        // because it's unexpected and a potential XSS issue
2638        'script': true,
2639        'textarea': true
2640    };
2641
2642    // Use an overridable method for retrieving binding handlers so that a plugins may support dynamically created handlers
2643    ko['getBindingHandler'] = function(bindingKey) {
2644        return ko.bindingHandlers[bindingKey];
2645    };
2646
2647    // The ko.bindingContext constructor is only called directly to create the root context. For child
2648    // contexts, use bindingContext.createChildContext or bindingContext.extend.
2649    ko.bindingContext = function(dataItemOrAccessor, parentContext, dataItemAlias, extendCallback) {
2650
2651        // The binding context object includes static properties for the current, parent, and root view models.
2652        // If a view model is actually stored in an observable, the corresponding binding context object, and
2653        // any child contexts, must be updated when the view model is changed.
2654        function updateContext() {
2655            // Most of the time, the context will directly get a view model object, but if a function is given,
2656            // we call the function to retrieve the view model. If the function accesses any obsevables or returns
2657            // an observable, the dependency is tracked, and those observables can later cause the binding
2658            // context to be updated.
2659            var dataItemOrObservable = isFunc ? dataItemOrAccessor() : dataItemOrAccessor,
2660                dataItem = ko.utils.unwrapObservable(dataItemOrObservable);
2661
2662            if (parentContext) {
2663                // When a "parent" context is given, register a dependency on the parent context. Thus whenever the
2664                // parent context is updated, this context will also be updated.
2665                if (parentContext._subscribable)
2666                    parentContext._subscribable();
2667
2668                // Copy $root and any custom properties from the parent context
2669                ko.utils.extend(self, parentContext);
2670
2671                // Because the above copy overwrites our own properties, we need to reset them.
2672                // During the first execution, "subscribable" isn't set, so don't bother doing the update then.
2673                if (subscribable) {
2674                    self._subscribable = subscribable;
2675                }
2676            } else {
2677                self['$parents'] = [];
2678                self['$root'] = dataItem;
2679
2680                // Export 'ko' in the binding context so it will be available in bindings and templates
2681                // even if 'ko' isn't exported as a global, such as when using an AMD loader.
2682                // See https://github.com/SteveSanderson/knockout/issues/490
2683                self['ko'] = ko;
2684            }
2685            self['$rawData'] = dataItemOrObservable;
2686            self['$data'] = dataItem;
2687            if (dataItemAlias)
2688                self[dataItemAlias] = dataItem;
2689
2690            // The extendCallback function is provided when creating a child context or extending a context.
2691            // It handles the specific actions needed to finish setting up the binding context. Actions in this
2692            // function could also add dependencies to this binding context.
2693            if (extendCallback)
2694                extendCallback(self, parentContext, dataItem);
2695
2696            return self['$data'];
2697        }
2698        function disposeWhen() {
2699            return nodes && !ko.utils.anyDomNodeIsAttachedToDocument(nodes);
2700        }
2701
2702        var self = this,
2703            isFunc = typeof(dataItemOrAccessor) == "function" && !ko.isObservable(dataItemOrAccessor),
2704            nodes,
2705            subscribable = ko.dependentObservable(updateContext, null, { disposeWhen: disposeWhen, disposeWhenNodeIsRemoved: true });
2706
2707        // At this point, the binding context has been initialized, and the "subscribable" computed observable is
2708        // subscribed to any observables that were accessed in the process. If there is nothing to track, the
2709        // computed will be inactive, and we can safely throw it away. If it's active, the computed is stored in
2710        // the context object.
2711        if (subscribable.isActive()) {
2712            self._subscribable = subscribable;
2713
2714            // Always notify because even if the model ($data) hasn't changed, other context properties might have changed
2715            subscribable['equalityComparer'] = null;
2716
2717            // We need to be able to dispose of this computed observable when it's no longer needed. This would be
2718            // easy if we had a single node to watch, but binding contexts can be used by many different nodes, and
2719            // we cannot assume that those nodes have any relation to each other. So instead we track any node that
2720            // the context is attached to, and dispose the computed when all of those nodes have been cleaned.
2721
2722            // Add properties to *subscribable* instead of *self* because any properties added to *self* may be overwritten on updates
2723            nodes = [];
2724            subscribable._addNode = function(node) {
2725                nodes.push(node);
2726                ko.utils.domNodeDisposal.addDisposeCallback(node, function(node) {
2727                    ko.utils.arrayRemoveItem(nodes, node);
2728                    if (!nodes.length) {
2729                        subscribable.dispose();
2730                        self._subscribable = subscribable = undefined;
2731                    }
2732                });
2733            };
2734        }
2735    }
2736
2737    // Extend the binding context hierarchy with a new view model object. If the parent context is watching
2738    // any obsevables, the new child context will automatically get a dependency on the parent context.
2739    // But this does not mean that the $data value of the child context will also get updated. If the child
2740    // view model also depends on the parent view model, you must provide a function that returns the correct
2741    // view model on each update.
2742    ko.bindingContext.prototype['createChildContext'] = function (dataItemOrAccessor, dataItemAlias, extendCallback) {
2743        return new ko.bindingContext(dataItemOrAccessor, this, dataItemAlias, function(self, parentContext) {
2744            // Extend the context hierarchy by setting the appropriate pointers
2745            self['$parentContext'] = parentContext;
2746            self['$parent'] = parentContext['$data'];
2747            self['$parents'] = (parentContext['$parents'] || []).slice(0);
2748            self['$parents'].unshift(self['$parent']);
2749            if (extendCallback)
2750                extendCallback(self);
2751        });
2752    };
2753
2754    // Extend the binding context with new custom properties. This doesn't change the context hierarchy.
2755    // Similarly to "child" contexts, provide a function here to make sure that the correct values are set
2756    // when an observable view model is updated.
2757    ko.bindingContext.prototype['extend'] = function(properties) {
2758        // If the parent context references an observable view model, "_subscribable" will always be the
2759        // latest view model object. If not, "_subscribable" isn't set, and we can use the static "$data" value.
2760        return new ko.bindingContext(this._subscribable || this['$data'], this, null, function(self, parentContext) {
2761            // This "child" context doesn't directly track a parent observable view model,
2762            // so we need to manually set the $rawData value to match the parent.
2763            self['$rawData'] = parentContext['$rawData'];
2764            ko.utils.extend(self, typeof(properties) == "function" ? properties() : properties);
2765        });
2766    };
2767
2768    // Returns the valueAccesor function for a binding value
2769    function makeValueAccessor(value) {
2770        return function() {
2771            return value;
2772        };
2773    }
2774
2775    // Returns the value of a valueAccessor function
2776    function evaluateValueAccessor(valueAccessor) {
2777        return valueAccessor();
2778    }
2779
2780    // Given a function that returns bindings, create and return a new object that contains
2781    // binding value-accessors functions. Each accessor function calls the original function
2782    // so that it always gets the latest value and all dependencies are captured. This is used
2783    // by ko.applyBindingsToNode and getBindingsAndMakeAccessors.
2784    function makeAccessorsFromFunction(callback) {
2785        return ko.utils.objectMap(ko.dependencyDetection.ignore(callback), function(value, key) {
2786            return function() {
2787                return callback()[key];
2788            };
2789        });
2790    }
2791
2792    // Given a bindings function or object, create and return a new object that contains
2793    // binding value-accessors functions. This is used by ko.applyBindingsToNode.
2794    function makeBindingAccessors(bindings, context, node) {
2795        if (typeof bindings === 'function') {
2796            return makeAccessorsFromFunction(bindings.bind(null, context, node));
2797        } else {
2798            return ko.utils.objectMap(bindings, makeValueAccessor);
2799        }
2800    }
2801
2802    // This function is used if the binding provider doesn't include a getBindingAccessors function.
2803    // It must be called with 'this' set to the provider instance.
2804    function getBindingsAndMakeAccessors(node, context) {
2805        return makeAccessorsFromFunction(this['getBindings'].bind(this, node, context));
2806    }
2807
2808    function validateThatBindingIsAllowedForVirtualElements(bindingName) {
2809        var validator = ko.virtualElements.allowedBindings[bindingName];
2810        if (!validator)
2811            throw new Error("The binding '" + bindingName + "' cannot be used with virtual elements")
2812    }
2813
2814    function applyBindingsToDescendantsInternal (bindingContext, elementOrVirtualElement, bindingContextsMayDifferFromDomParentElement) {
2815        var currentChild,
2816            nextInQueue = ko.virtualElements.firstChild(elementOrVirtualElement),
2817            provider = ko.bindingProvider['instance'],
2818            preprocessNode = provider['preprocessNode'];
2819
2820        // Preprocessing allows a binding provider to mutate a node before bindings are applied to it. For example it's
2821        // possible to insert new siblings after it, and/or replace the node with a different one. This can be used to
2822        // implement custom binding syntaxes, such as {{ value }} for string interpolation, or custom element types that
2823        // trigger insertion of <template> contents at that point in the document.
2824        if (preprocessNode) {
2825            while (currentChild = nextInQueue) {
2826                nextInQueue = ko.virtualElements.nextSibling(currentChild);
2827                preprocessNode.call(provider, currentChild);
2828            }
2829            // Reset nextInQueue for the next loop
2830            nextInQueue = ko.virtualElements.firstChild(elementOrVirtualElement);
2831        }
2832
2833        while (currentChild = nextInQueue) {
2834            // Keep a record of the next child *before* applying bindings, in case the binding removes the current child from its position
2835            nextInQueue = ko.virtualElements.nextSibling(currentChild);
2836            applyBindingsToNodeAndDescendantsInternal(bindingContext, currentChild, bindingContextsMayDifferFromDomParentElement);
2837        }
2838    }
2839
2840    function applyBindingsToNodeAndDescendantsInternal (bindingContext, nodeVerified, bindingContextMayDifferFromDomParentElement) {
2841        var shouldBindDescendants = true;
2842
2843        // Perf optimisation: Apply bindings only if...
2844        // (1) We need to store the binding context on this node (because it may differ from the DOM parent node's binding context)
2845        //     Note that we can't store binding contexts on non-elements (e.g., text nodes), as IE doesn't allow expando properties for those
2846        // (2) It might have bindings (e.g., it has a data-bind attribute, or it's a marker for a containerless template)
2847        var isElement = (nodeVerified.nodeType === 1);
2848        if (isElement) // Workaround IE <= 8 HTML parsing weirdness
2849            ko.virtualElements.normaliseVirtualElementDomStructure(nodeVerified);
2850
2851        var shouldApplyBindings = (isElement && bindingContextMayDifferFromDomParentElement)             // Case (1)
2852                               || ko.bindingProvider['instance']['nodeHasBindings'](nodeVerified);       // Case (2)
2853        if (shouldApplyBindings)
2854            shouldBindDescendants = applyBindingsToNodeInternal(nodeVerified, null, bindingContext, bindingContextMayDifferFromDomParentElement)['shouldBindDescendants'];
2855
2856        if (shouldBindDescendants && !bindingDoesNotRecurseIntoElementTypes[ko.utils.tagNameLower(nodeVerified)]) {
2857            // We're recursing automatically into (real or virtual) child nodes without changing binding contexts. So,
2858            //  * For children of a *real* element, the binding context is certainly the same as on their DOM .parentNode,
2859            //    hence bindingContextsMayDifferFromDomParentElement is false
2860            //  * For children of a *virtual* element, we can't be sure. Evaluating .parentNode on those children may
2861            //    skip over any number of intermediate virtual elements, any of which might define a custom binding context,
2862            //    hence bindingContextsMayDifferFromDomParentElement is true
2863            applyBindingsToDescendantsInternal(bindingContext, nodeVerified, /* bindingContextsMayDifferFromDomParentElement: */ !isElement);
2864        }
2865    }
2866
2867    var boundElementDomDataKey = ko.utils.domData.nextKey();
2868
2869
2870    function topologicalSortBindings(bindings) {
2871        // Depth-first sort
2872        var result = [],                // The list of key/handler pairs that we will return
2873            bindingsConsidered = {},    // A temporary record of which bindings are already in 'result'
2874            cyclicDependencyStack = []; // Keeps track of a depth-search so that, if there's a cycle, we know which bindings caused it
2875        ko.utils.objectForEach(bindings, function pushBinding(bindingKey) {
2876            if (!bindingsConsidered[bindingKey]) {
2877                var binding = ko['getBindingHandler'](bindingKey);
2878                if (binding) {
2879                    // First add dependencies (if any) of the current binding
2880                    if (binding['after']) {
2881                        cyclicDependencyStack.push(bindingKey);
2882                        ko.utils.arrayForEach(binding['after'], function(bindingDependencyKey) {
2883                            if (bindings[bindingDependencyKey]) {
2884                                if (ko.utils.arrayIndexOf(cyclicDependencyStack, bindingDependencyKey) !== -1) {
2885                                    throw Error("Cannot combine the following bindings, because they have a cyclic dependency: " + cyclicDependencyStack.join(", "));
2886                                } else {
2887                                    pushBinding(bindingDependencyKey);
2888                                }
2889                            }
2890                        });
2891                        cyclicDependencyStack.length--;
2892                    }
2893                    // Next add the current binding
2894                    result.push({ key: bindingKey, handler: binding });
2895                }
2896                bindingsConsidered[bindingKey] = true;
2897            }
2898        });
2899
2900        return result;
2901    }
2902
2903    function applyBindingsToNodeInternal(node, sourceBindings, bindingContext, bindingContextMayDifferFromDomParentElement) {
2904        // Prevent multiple applyBindings calls for the same node, except when a binding value is specified
2905        var alreadyBound = ko.utils.domData.get(node, boundElementDomDataKey);
2906        if (!sourceBindings) {
2907            if (alreadyBound) {
2908                throw Error("You cannot apply bindings multiple times to the same element.");
2909            }
2910            ko.utils.domData.set(node, boundElementDomDataKey, true);
2911        }
2912
2913        // Optimization: Don't store the binding context on this node if it's definitely the same as on node.parentNode, be
vendor: 5,416 bytes, lines 2913-3006
2913cause
2914        // we can easily recover it just by scanning up the node's ancestors in the DOM
2915        // (note: here, parent node means "real DOM parent" not "virtual parent", as there's no O(1) way to find the virtual parent)
2916        if (!alreadyBound && bindingContextMayDifferFromDomParentElement)
2917            ko.storedBindingContextForNode(node, bindingContext);
2918
2919        // Use bindings if given, otherwise fall back on asking the bindings provider to give us some bindings
2920        var bindings;
2921        if (sourceBindings && typeof sourceBindings !== 'function') {
2922            bindings = sourceBindings;
2923        } else {
2924            var provider = ko.bindingProvider['instance'],
2925                getBindings = provider['getBindingAccessors'] || getBindingsAndMakeAccessors;
2926
2927            // Get the binding from the provider within a computed observable so that we can update the bindings whenever
2928            // the binding context is updated or if the binding provider accesses observables.
2929            var bindingsUpdater = ko.dependentObservable(
2930                function() {
2931                    bindings = sourceBindings ? sourceBindings(bindingContext, node) : getBindings.call(provider, node, bindingContext);
2932                    // Register a dependency on the binding context to support obsevable view models.
2933                    if (bindings && bindingContext._subscribable)
2934                        bindingContext._subscribable();
2935                    return bindings;
2936                },
2937                null, { disposeWhenNodeIsRemoved: node }
2938            );
2939
2940            if (!bindings || !bindingsUpdater.isActive())
2941                bindingsUpdater = null;
2942        }
2943
2944        var bindingHandlerThatControlsDescendantBindings;
2945        if (bindings) {
2946            // Return the value accessor for a given binding. When bindings are static (won't be updated because of a binding
2947            // context update), just return the value accessor from the binding. Otherwise, return a function that always gets
2948            // the latest binding value and registers a dependency on the binding updater.
2949            var getValueAccessor = bindingsUpdater
2950                ? function(bindingKey) {
2951                    return function() {
2952                        return evaluateValueAccessor(bindingsUpdater()[bindingKey]);
2953                    };
2954                } : function(bindingKey) {
2955                    return bindings[bindingKey];
2956                };
2957
2958            // Use of allBindings as a function is maintained for backwards compatibility, but its use is deprecated
2959            function allBindings() {
2960                return ko.utils.objectMap(bindingsUpdater ? bindingsUpdater() : bindings, evaluateValueAccessor);
2961            }
2962            // The following is the 3.x allBindings API
2963            allBindings['get'] = function(key) {
2964                return bindings[key] && evaluateValueAccessor(getValueAccessor(key));
2965            };
2966            allBindings['has'] = function(key) {
2967                return key in bindings;
2968            };
2969
2970            // First put the bindings into the right order
2971            var orderedBindings = topologicalSortBindings(bindings);
2972
2973            // Go through the sorted bindings, calling init and update for each
2974            ko.utils.arrayForEach(orderedBindings, function(bindingKeyAndHandler) {
2975                // Note that topologicalSortBindings has already filtered out any nonexistent binding handlers,
2976                // so bindingKeyAndHandler.handler will always be nonnull.
2977                var handlerInitFn = bindingKeyAndHandler.handler["init"],
2978                    handlerUpdateFn = bindingKeyAndHandler.handler["update"],
2979                    bindingKey = bindingKeyAndHandler.key;
2980
2981                if (node.nodeType === 8) {
2982                    validateThatBindingIsAllowedForVirtualElements(bindingKey);
2983                }
2984
2985                try {
2986                    // Run init, ignoring any dependencies
2987                    if (typeof handlerInitFn == "function") {
2988                        ko.dependencyDetection.ignore(function() {
2989                            var initResult = handlerInitFn(node, getValueAccessor(bindingKey), allBindings, bindingContext['$data'], bindingContext);
2990
2991                            // If this binding handler claims to control descendant bindings, make a note of this
2992                            if (initResult && initResult['controlsDescendantBindings']) {
2993                                if (bindingHandlerThatControlsDescendantBindings !== undefined)
2994                                    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.");
2995                                bindingHandlerThatControlsDescendantBindings = bindingKey;
2996                            }
2997                        });
2998                    }
2999
3000                    // Run update in its own computed wrapper
3001                    if (typeof handlerUpdateFn == "function") {
3002                        ko.dependentObservable(
3003                            function() {
3004                                handlerUpdateFn(node, getValueAccessor(bindingKey), allBindings, bindingContext['$data'], bindingContext);
3005                            },
3006                            null,
3007                            { disposeWhenNodeIsRemoved: node }
3008                        );
3009                    }
3010                } catch (ex) {
3011                    ex.message = "Unable to process binding \"" + bindingKey + ": " + bindings[bindingKey] + "\"\nMessage: " + ex.message;
3012                    throw ex;
3013                }
3014            });
3015        }
3016
3017        return {
3018            'shouldBindDescendants': bindingHandlerThatControlsDescendantBindings === undefined
3019        };
3020    };
3021
3022    var storedBindingContextDomDataKey = ko.utils.domData.nextKey();
3023    ko.storedBindingContextForNode = function (node, bindingContext) {
3024        if (arguments.length == 2) {
3025            ko.utils.domData.set(node, storedBindingContextDomDataKey, bindingContext);
3026            if (bindingContext._subscribable)
3027                bindingContext._subscribable._addNode(node);
3028        } else {
3029            return ko.utils.domData.get(node, storedBindingContextDomDataKey);
3030        }
3031    }
3032
3033    function getBindingContext(viewModelOrBindingContext) {
3034        return viewModelOrBindingContext && (viewModelOrBindingContext instanceof ko.bindingContext)
3035            ? viewModelOrBindingContext
3036            : new ko.bindingContext(viewModelOrBindingContext);
3037    }
3038
3039    ko.applyBindingAccessorsToNode = function (node, bindings, viewModelOrBindingContext) {
3040        if (node.nodeType === 1) // If it's an element, workaround IE <= 8 HTML parsing weirdness
3041            ko.virtualElements.normaliseVirtualElementDomStructure(node);
3042        return applyBindingsToNodeInternal(node, bindings, getBindingContext(viewModelOrBindingContext), true);
3043    };
3044
3045    ko.applyBindingsToNode = function (node, bindings, viewModelOrBindingContext) {
3046        var context = getBindingContext(viewModelOrBindingContext);
3047        return ko.applyBindingAccessorsToNode(node, makeBindingAccessors(bindings, context, node), context);
3048    };
3049
3050    ko.applyBindingsToDescendants = function(viewModelOrBindingContext, rootNode) {
3051        if (rootNode.nodeType === 1 || rootNode.nodeType === 8)
3052            applyBindingsToDescendantsInternal(getBindingContext(viewModelOrBindingContext), rootNode, true);
3053    };
3054
3055    ko.applyBindings = function (viewModelOrBindingContext, rootNode) {
3056        // If jQuery is loaded after Knockout, we won't initially have access to it. So save it here.
3057        if (!jQueryInstance && window['jQuery']) {
3058            jQueryInstance = window['jQuery'];
3059        }
3060
3061        if (rootNode && (rootNode.nodeType !== 1) && (rootNode.nodeType !== 8))
3062            throw new Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");
3063        rootNode = rootNode || window.document.body; // Make "rootNode" parameter optional
3064
3065        applyBindingsToNodeAndDescendantsInternal(getBindingContext(viewModelOrBindingContext), rootNode, true);
3066    };
3067
3068    // Retrieving binding context from arbitrary nodes
3069    ko.contextFor = function(node) {
3070        // We can only do something meaningful for elements and comment nodes (in particular, not text nodes, as IE can't store domdata for them)
3071        switch (node.nodeType) {
3072            case 1:
3073            case 8:
3074                var context = ko.storedBindingContextForNode(node);
3075                if (context) return context;
3076                if (node.parentNode) return ko.contextFor(node.parentNode);
3077                break;
3078        }
3079        return undefined;
3080    };
3081    ko.dataFor = function(node) {
3082        var context = ko.contextFor(node);
3083        return context ? context['$data'] : undefined;
3084    };
3085
3086    ko.exportSymbol('bindingHandlers', ko.bindingHandlers);
3087    ko.exportSymbol('applyBindings', ko.applyBindings);
3088    ko.exportSymbol('applyBindingsToDescendants', ko.applyBindingsToDescendants);
3089    ko.exportSymbol('applyBindingAccessorsToNode', ko.applyBindingAccessorsToNode);
3090    ko.exportSymbol('applyBindingsToNode', ko.applyBindingsToNode);
3091    ko.exportSymbol('contextFor', ko.contextFor);
3092    ko.exportSymbol('dataFor', ko.dataFor);
3093})();
3094(function(undefined) {
3095    var loadingSubscribablesCache = {}, // Tracks component loads that are currently in flight
3096        loadedDefinitionsCache = {};    // Tracks component loads that have already completed
3097
3098    ko.components = {
3099        get: function(componentName, callback) {
3100            var cachedDefinition = getObjectOwnProperty(loadedDefinitionsCache, componentName);
3101            if (cachedDefinition) {
3102                // It's already loaded and cached. Reuse the same definition object.
3103                // Note that for API consistency, even cache hits complete asynchronously by default.
3104                // You can bypass this by putting synchronous:true on your component config.
3105                if (cachedDefinition.isSynchronousComponent) {
3106                    ko.dependencyDetection.ignore(function() { // See comment in loaderRegistryBehaviors.js for reasoning
3107                        callback(cachedDefinition.definition);
3108                    });
3109                } else {
3110                    setTimeout(function() { callback(cachedDefinition.definition); }, 0);
3111                }
3112            } else {
3113                // Join the loading process that is already underway, or start a new one.
3114                loadComponentAndNotify(componentName, callback);
3115            }
3116        },
3117
3118        clearCachedDefinition: function(componentName) {
3119            delete loadedDefinitionsCache[componentName];
3120        },
3121
3122        _getFirstResultFromLoaders: getFirstResultFromLoaders
3123    };
3124
3125    function getObjectOwnProperty(obj, propName) {
3126        return obj.hasOwnProperty(propName) ? obj[propName] : undefined;
3127    }
3128
3129    function loadComponentAndNotify(componentName, callback) {
3130        var subscribable = getObjectOwnProperty(loadingSubscribablesCache, componentName),
3131            completedAsync;
3132        if (!subscribable) {
3133            // It's not started loading yet. Start loading, and when it's done, move it to loadedDefinitionsCache.
3134            subscribable = loadingSubscribablesCache[componentName] = new ko.subscribable();
3135            subscribable.subscribe(callback);
3136
3137            beginLoadingComponent(componentName, function(definition, config) {
3138                var isSynchronousComponent = !!(config && config['synchronous']);
3139                loadedDefinitionsCache[componentName] = { definition: definition, isSynchronousComponent: isSynchronousComponent };
3140                delete loadingSubscribablesCache[componentName];
3141
3142                // For API consistency, all loads complete asynchronously. However we want to avoid
3143                // adding an extra setTimeout if it's unnecessary (i.e., the completion is already
3144                // async) since setTimeout(..., 0) still takes about 16ms or more on most browsers.
3145                //
3146                // You can bypass the 'always synchronous' feature by putting the synchronous:true
3147                // flag on your component configuration when you register it.
3148                if (completedAsync || isSynchronousComponent) {
3149                    // Note that notifySubscribers ignores any dependencies read within the callback.
3150                    // See comment in loaderRegistryBehaviors.js for reasoning
vendor: 5,884 bytes, lines 3151-3273
3151                    subscribable['notifySubscribers'](definition);
3152                } else {
3153                    setTimeout(function() {
3154                        subscribable['notifySubscribers'](definition);
3155                    }, 0);
3156                }
3157            });
3158            completedAsync = true;
3159        } else {
3160            subscribable.subscribe(callback);
3161        }
3162    }
3163
3164    function beginLoadingComponent(componentName, callback) {
3165        getFirstResultFromLoaders('getConfig', [componentName], function(config) {
3166            if (config) {
3167                // We have a config, so now load its definition
3168                getFirstResultFromLoaders('loadComponent', [componentName, config], function(definition) {
3169                    callback(definition, config);
3170                });
3171            } else {
3172                // The component has no config - it's unknown to all the loaders.
3173                // Note that this is not an error (e.g., a module loading error) - that would abort the
3174                // process and this callback would not run. For this callback to run, all loaders must
3175                // have confirmed they don't know about this component.
3176                callback(null, null);
3177            }
3178        });
3179    }
3180
3181    function getFirstResultFromLoaders(methodName, argsExceptCallback, callback, candidateLoaders) {
3182        // On the first call in the stack, start with the full set of loaders
3183        if (!candidateLoaders) {
3184            candidateLoaders = ko.components['loaders'].slice(0); // Use a copy, because we'll be mutating this array
3185        }
3186
3187        // Try the next candidate
3188        var currentCandidateLoader = candidateLoaders.shift();
3189        if (currentCandidateLoader) {
3190            var methodInstance = currentCandidateLoader[methodName];
3191            if (methodInstance) {
3192                var wasAborted = false,
3193                    synchronousReturnValue = methodInstance.apply(currentCandidateLoader, argsExceptCallback.concat(function(result) {
3194                        if (wasAborted) {
3195                            callback(null);
3196                        } else if (result !== null) {
3197                            // This candidate returned a value. Use it.
3198                            callback(result);
3199                        } else {
3200                            // Try the next candidate
3201                            getFirstResultFromLoaders(methodName, argsExceptCallback, callback, candidateLoaders);
3202                        }
3203                    }));
3204
3205                // Currently, loaders may not return anything synchronously. This leaves open the possibility
3206                // that we'll extend the API to support synchronous return values in the future. It won't be
3207                // a breaking change, because currently no loader is allowed to return anything except undefined.
3208                if (synchronousReturnValue !== undefined) {
3209                    wasAborted = true;
3210
3211                    // Method to suppress exceptions will remain undocumented. This is only to keep
3212                    // KO's specs running tidily, since we can observe the loading got aborted without
3213                    // having exceptions cluttering up the console too.
3214                    if (!currentCandidateLoader['suppressLoaderExceptions']) {
3215                        throw new Error('Component loaders must supply values by invoking the callback, not by returning values synchronously.');
3216                    }
3217                }
3218            } else {
3219                // This candidate doesn't have the relevant handler. Synchronously move on to the next one.
3220                getFirstResultFromLoaders(methodName, argsExceptCallback, callback, candidateLoaders);
3221            }
3222        } else {
3223            // No candidates returned a value
3224            callback(null);
3225        }
3226    }
3227
3228    // Reference the loaders via string name so it's possible for developers
3229    // to replace the whole array by assigning to ko.components.loaders
3230    ko.components['loaders'] = [];
3231
3232    ko.exportSymbol('components', ko.components);
3233    ko.exportSymbol('components.get', ko.components.get);
3234    ko.exportSymbol('components.clearCachedDefinition', ko.components.clearCachedDefinition);
3235})();
3236(function(undefined) {
3237
3238    // The default loader is responsible for two things:
3239    // 1. Maintaining the default in-memory registry of component configuration objects
3240    //    (i.e., the thing you're writing to when you call ko.components.register(someName, ...))
3241    // 2. Answering requests for components by fetching configuration objects
3242    //    from that default in-memory registry and resolving them into standard
3243    //    component definition objects (of the form { createViewModel: ..., template: ... })
3244    // Custom loaders may override either of these facilities, i.e.,
3245    // 1. To supply configuration objects from some other source (e.g., conventions)
3246    // 2. Or, to resolve configuration objects by loading viewmodels/templates via arbitrary logic.
3247
3248    var defaultConfigRegistry = {};
3249
3250    ko.components.register = function(componentName, config) {
3251        if (!config) {
3252            throw new Error('Invalid configuration for ' + componentName);
3253        }
3254
3255        if (ko.components.isRegistered(componentName)) {
3256            throw new Error('Component ' + componentName + ' is already registered');
3257        }
3258
3259        defaultConfigRegistry[componentName] = config;
3260    }
3261
3262    ko.components.isRegistered = function(componentName) {
3263        return componentName in defaultConfigRegistry;
3264    }
3265
3266    ko.components.unregister = function(componentName) {
3267        delete defaultConfigRegistry[componentName];
3268        ko.components.clearCachedDefinition(componentName);
3269    }
3270
3271    ko.components.defaultLoader = {
3272        'getConfig': function(componentName, callback) {
3273            var result = defaultConfigRegistry.hasOwnProperty
vendor: 7,343 bytes, lines 3273-3433
3273(componentName)
3274                ? defaultConfigRegistry[componentName]
3275                : null;
3276            callback(result);
3277        },
3278
3279        'loadComponent': function(componentName, config, callback) {
3280            var errorCallback = makeErrorCallback(componentName);
3281            possiblyGetConfigFromAmd(errorCallback, config, function(loadedConfig) {
3282                resolveConfig(componentName, errorCallback, loadedConfig, callback);
3283            });
3284        },
3285
3286        'loadTemplate': function(componentName, templateConfig, callback) {
3287            resolveTemplate(makeErrorCallback(componentName), templateConfig, callback);
3288        },
3289
3290        'loadViewModel': function(componentName, viewModelConfig, callback) {
3291            resolveViewModel(makeErrorCallback(componentName), viewModelConfig, callback);
3292        }
3293    };
3294
3295    var createViewModelKey = 'createViewModel';
3296
3297    // Takes a config object of the form { template: ..., viewModel: ... }, and asynchronously convert it
3298    // into the standard component definition format:
3299    //    { template: <ArrayOfDomNodes>, createViewModel: function(params, componentInfo) { ... } }.
3300    // Since both template and viewModel may need to be resolved asynchronously, both tasks are performed
3301    // in parallel, and the results joined when both are ready. We don't depend on any promises infrastructure,
3302    // so this is implemented manually below.
3303    function resolveConfig(componentName, errorCallback, config, callback) {
3304        var result = {},
3305            makeCallBackWhenZero = 2,
3306            tryIssueCallback = function() {
3307                if (--makeCallBackWhenZero === 0) {
3308                    callback(result);
3309                }
3310            },
3311            templateConfig = config['template'],
3312            viewModelConfig = config['viewModel'];
3313
3314        if (templateConfig) {
3315            possiblyGetConfigFromAmd(errorCallback, templateConfig, function(loadedConfig) {
3316                ko.components._getFirstResultFromLoaders('loadTemplate', [componentName, loadedConfig], function(resolvedTemplate) {
3317                    result['template'] = resolvedTemplate;
3318                    tryIssueCallback();
3319                });
3320            });
3321        } else {
3322            tryIssueCallback();
3323        }
3324
3325        if (viewModelConfig) {
3326            possiblyGetConfigFromAmd(errorCallback, viewModelConfig, function(loadedConfig) {
3327                ko.components._getFirstResultFromLoaders('loadViewModel', [componentName, loadedConfig], function(resolvedViewModel) {
3328                    result[createViewModelKey] = resolvedViewModel;
3329                    tryIssueCallback();
3330                });
3331            });
3332        } else {
3333            tryIssueCallback();
3334        }
3335    }
3336
3337    function resolveTemplate(errorCallback, templateConfig, callback) {
3338        if (typeof templateConfig === 'string') {
3339            // Markup - parse it
3340            callback(ko.utils.parseHtmlFragment(templateConfig));
3341        } else if (templateConfig instanceof Array) {
3342            // Assume already an array of DOM nodes - pass through unchanged
3343            callback(templateConfig);
3344        } else if (isDocumentFragment(templateConfig)) {
3345            // Document fragment - use its child nodes
3346            callback(ko.utils.makeArray(templateConfig.childNodes));
3347        } else if (templateConfig['element']) {
3348            var element = templateConfig['element'];
3349            if (isDomElement(element)) {
3350                // Element instance - copy its child nodes
3351                callback(cloneNodesFromTemplateSourceElement(element));
3352            } else if (typeof element === 'string') {
3353                // Element ID - find it, then copy its child nodes
3354                var elemInstance = document.getElementById(element);
3355                if (elemInstance) {
3356                    callback(cloneNodesFromTemplateSourceElement(elemInstance));
3357                } else {
3358                    errorCallback('Cannot find element with ID ' + element);
3359                }
3360            } else {
3361                errorCallback('Unknown element type: ' + element);
3362            }
3363        } else {
3364            errorCallback('Unknown template value: ' + templateConfig);
3365        }
3366    }
3367
3368    function resolveViewModel(errorCallback, viewModelConfig, callback) {
3369        if (typeof viewModelConfig === 'function') {
3370            // Constructor - convert to standard factory function format
3371            // By design, this does *not* supply componentInfo to the constructor, as the intent is that
3372            // componentInfo contains non-viewmodel data (e.g., the component's element) that should only
3373            // be used in factory functions, not viewmodel constructors.
3374            callback(function (params /*, componentInfo */) {
3375                return new viewModelConfig(params);
3376            });
3377        } else if (typeof viewModelConfig[createViewModelKey] === 'function') {
3378            // Already a factory function - use it as-is
3379            callback(viewModelConfig[createViewModelKey]);
3380        } else if ('instance' in viewModelConfig) {
3381            // Fixed object instance - promote to createViewModel format for API consistency
3382            var fixedInstance = viewModelConfig['instance'];
3383            callback(function (params, componentInfo) {
3384                return fixedInstance;
3385            });
3386        } else if ('viewModel' in viewModelConfig) {
3387            // Resolved AMD module whose value is of the form { viewModel: ... }
3388            resolveViewModel(errorCallback, viewModelConfig['viewModel'], callback);
3389        } else {
3390            errorCallback('Unknown viewModel value: ' + viewModelConfig);
3391        }
3392    }
3393
3394    function cloneNodesFromTemplateSourceElement(elemInstance) {
3395        switch (ko.utils.tagNameLower(elemInstance)) {
3396            case 'script':
3397                return ko.utils.parseHtmlFragment(elemInstance.text);
3398            case 'textarea':
3399                return ko.utils.parseHtmlFragment(elemInstance.value);
3400            case 'template':
3401                // For browsers with proper <template> element support (i.e., where the .content property
3402                // gives a document fragment), use that document fragment.
3403                if (isDocumentFragment(elemInstance.content)) {
3404                    return ko.utils.cloneNodes(elemInstance.content.childNodes);
3405                }
3406        }
3407
3408        // Regular elements such as <div>, and <template> elements on old browsers that don't really
3409        // understand <template> and just treat it as a regular container
3410        return ko.utils.cloneNodes(elemInstance.childNodes);
3411    }
3412
3413    function isDomElement(obj) {
3414        if (window['HTMLElement']) {
3415            return obj instanceof HTMLElement;
3416        } else {
3417            return obj && obj.tagName && obj.nodeType === 1;
3418        }
3419    }
3420
3421    function isDocumentFragment(obj) {
3422        if (window['DocumentFragment']) {
3423            return obj instanceof DocumentFragment;
3424        } else {
3425            return obj && obj.nodeType === 11;
3426        }
3427    }
3428
3429    function possiblyGetConfigFromAmd(errorCallback, config, callback) {
3430        if (typeof config['require'] === 'string') {
3431            // The config is the value of an AMD module
3432            if (amdRequire || window['require']) {
3433                (amdRequire || window['require'])([config['require']], 
vendor: 52,868 bytes, lines 3433-4462
3433callback);
3434            } else {
3435                errorCallback('Uses require, but no AMD loader is present');
3436            }
3437        } else {
3438            callback(config);
3439        }
3440    }
3441
3442    function makeErrorCallback(componentName) {
3443        return function (message) {
3444            throw new Error('Component \'' + componentName + '\': ' + message);
3445        };
3446    }
3447
3448    ko.exportSymbol('components.register', ko.components.register);
3449    ko.exportSymbol('components.isRegistered', ko.components.isRegistered);
3450    ko.exportSymbol('components.unregister', ko.components.unregister);
3451
3452    // Expose the default loader so that developers can directly ask it for configuration
3453    // or to resolve configuration
3454    ko.exportSymbol('components.defaultLoader', ko.components.defaultLoader);
3455
3456    // By default, the default loader is the only registered component loader
3457    ko.components['loaders'].push(ko.components.defaultLoader);
3458
3459    // Privately expose the underlying config registry for use in old-IE shim
3460    ko.components._allRegisteredComponents = defaultConfigRegistry;
3461})();
3462(function (undefined) {
3463    // Overridable API for determining which component name applies to a given node. By overriding this,
3464    // you can for example map specific tagNames to components that are not preregistered.
3465    ko.components['getComponentNameForNode'] = function(node) {
3466        var tagNameLower = ko.utils.tagNameLower(node);
3467        return ko.components.isRegistered(tagNameLower) && tagNameLower;
3468    };
3469
3470    ko.components.addBindingsForCustomElement = function(allBindings, node, bindingContext, valueAccessors) {
3471        // Determine if it's really a custom element matching a component
3472        if (node.nodeType === 1) {
3473            var componentName = ko.components['getComponentNameForNode'](node);
3474            if (componentName) {
3475                // It does represent a component, so add a component binding for it
3476                allBindings = allBindings || {};
3477
3478                if (allBindings['component']) {
3479                    // Avoid silently overwriting some other 'component' binding that may already be on the element
3480                    throw new Error('Cannot use the "component" binding on a custom element matching a component');
3481                }
3482
3483                var componentBindingValue = { 'name': componentName, 'params': getComponentParamsFromCustomElement(node, bindingContext) };
3484
3485                allBindings['component'] = valueAccessors
3486                    ? function() { return componentBindingValue; }
3487                    : componentBindingValue;
3488            }
3489        }
3490
3491        return allBindings;
3492    }
3493
3494    var nativeBindingProviderInstance = new ko.bindingProvider();
3495
3496    function getComponentParamsFromCustomElement(elem, bindingContext) {
3497        var paramsAttribute = elem.getAttribute('params');
3498
3499        if (paramsAttribute) {
3500            var params = nativeBindingProviderInstance['parseBindingsString'](paramsAttribute, bindingContext, elem, { 'valueAccessors': true, 'bindingParams': true }),
3501                rawParamComputedValues = ko.utils.objectMap(params, function(paramValue, paramName) {
3502                    return ko.computed(paramValue, null, { disposeWhenNodeIsRemoved: elem });
3503                }),
3504                result = ko.utils.objectMap(rawParamComputedValues, function(paramValueComputed, paramName) {
3505                    var paramValue = paramValueComputed.peek();
3506                    // Does the evaluation of the parameter value unwrap any observables?
3507                    if (!paramValueComputed.isActive()) {
3508                        // No it doesn't, so there's no need for any computed wrapper. Just pass through the supplied value directly.
3509                        // Example: "someVal: firstName, age: 123" (whether or not firstName is an observable/computed)
3510                        return paramValue;
3511                    } else {
3512                        // Yes it does. Supply a computed property that unwraps both the outer (binding expression)
3513                        // level of observability, and any inner (resulting model value) level of observability.
3514                        // This means the component doesn't have to worry about multiple unwrapping. If the value is a
3515                        // writable observable, the computed will also be writable and pass the value on to the observable.
3516                        return ko.computed({
3517                            'read': function() {
3518                                return ko.utils.unwrapObservable(paramValueComputed());
3519                            },
3520                            'write': ko.isWriteableObservable(paramValue) && function(value) {
3521                                paramValueComputed()(value);
3522                            },
3523                            disposeWhenNodeIsRemoved: elem
3524                        });
3525                    }
3526                });
3527
3528            // Give access to the raw computeds, as long as that wouldn't overwrite any custom param also called '$raw'
3529            // This is in case the developer wants to react to outer (binding) observability separately from inner
3530            // (model value) observability, or in case the model value observable has subobservables.
3531            if (!result.hasOwnProperty('$raw')) {
3532                result['$raw'] = rawParamComputedValues;
3533            }
3534
3535            return result;
3536        } else {
3537            // For consistency, absence of a "params" attribute is treated the same as the presence of
3538            // any empty one. Otherwise component viewmodels need special code to check whether or not
3539            // 'params' or 'params.$raw' is null/undefined before reading subproperties, which is annoying.
3540            return { '$raw': {} };
3541        }
3542    }
3543
3544    // --------------------------------------------------------------------------------
3545    // Compatibility code for older (pre-HTML5) IE browsers
3546
3547    if (ko.utils.ieVersion < 9) {
3548        // Whenever you preregister a component, enable it as a custom element in the current document
3549        ko.components['register'] = (function(originalFunction) {
3550            return function(componentName) {
3551                document.createElement(componentName); // Allows IE<9 to parse markup containing the custom element
3552                return originalFunction.apply(this, arguments);
3553            }
3554        })(ko.components['register']);
3555
3556        // Whenever you create a document fragment, enable all preregistered component names as custom elements
3557        // This is needed to make innerShiv/jQuery HTML parsing correctly handle the custom elements
3558        document.createDocumentFragment = (function(originalFunction) {
3559            return function() {
3560                var newDocFrag = originalFunction(),
3561                    allComponents = ko.components._allRegisteredComponents;
3562                for (var componentName in allComponents) {
3563                    if (allComponents.hasOwnProperty(componentName)) {
3564                        newDocFrag.createElement(componentName);
3565                    }
3566                }
3567                return newDocFrag;
3568            };
3569        })(document.createDocumentFragment);
3570    }
3571})();(function(undefined) {
3572
3573    var componentLoadingOperationUniqueId = 0;
3574
3575    ko.bindingHandlers['component'] = {
3576        'init': function(element, valueAccessor, ignored1, ignored2, bindingContext) {
3577            var currentViewModel,
3578                currentLoadingOperationId,
3579                disposeAssociatedComponentViewModel = function () {
3580                    var currentViewModelDispose = currentViewModel && currentViewModel['dispose'];
3581                    if (typeof currentViewModelDispose === 'function') {
3582                        currentViewModelDispose.call(currentViewModel);
3583                    }
3584
3585                    // Any in-flight loading operation is no longer relevant, so make sure we ignore its completion
3586                    currentLoadingOperationId = null;
3587                },
3588                originalChildNodes = ko.utils.makeArray(ko.virtualElements.childNodes(element));
3589
3590            ko.utils.domNodeDisposal.addDisposeCallback(element, disposeAssociatedComponentViewModel);
3591
3592            ko.computed(function () {
3593                var value = ko.utils.unwrapObservable(valueAccessor()),
3594                    componentName, componentParams;
3595
3596                if (typeof value === 'string') {
3597                    componentName = value;
3598                } else {
3599                    componentName = ko.utils.unwrapObservable(value['name']);
3600                    componentParams = ko.utils.unwrapObservable(value['params']);
3601                }
3602
3603                if (!componentName) {
3604                    throw new Error('No component name specified');
3605                }
3606
3607                var loadingOperationId = currentLoadingOperationId = ++componentLoadingOperationUniqueId;
3608                ko.components.get(componentName, function(componentDefinition) {
3609                    // If this is not the current load operation for this element, ignore it.
3610                    if (currentLoadingOperationId !== loadingOperationId) {
3611                        return;
3612                    }
3613
3614                    // Clean up previous state
3615                    disposeAssociatedComponentViewModel();
3616
3617                    // Instantiate and bind new component. Implicitly this cleans any old DOM nodes.
3618                    if (!componentDefinition) {
3619                        throw new Error('Unknown component \'' + componentName + '\'');
3620                    }
3621                    cloneTemplateIntoElement(componentName, componentDefinition, element);
3622                    var componentViewModel = createViewModel(componentDefinition, element, originalChildNodes, componentParams),
3623                        childBindingContext = bindingContext['createChildContext'](componentViewModel, /* dataItemAlias */ undefined, function(ctx) {
3624                            ctx['$component'] = componentViewModel;
3625                            ctx['$componentTemplateNodes'] = originalChildNodes;
3626                        });
3627                    currentViewModel = componentViewModel;
3628                    ko.applyBindingsToDescendants(childBindingContext, element);
3629                });
3630            }, null, { disposeWhenNodeIsRemoved: element });
3631
3632            return { 'controlsDescendantBindings': true };
3633        }
3634    };
3635
3636    ko.virtualElements.allowedBindings['component'] = true;
3637
3638    function cloneTemplateIntoElement(componentName, componentDefinition, element) {
3639        var template = componentDefinition['template'];
3640        if (!template) {
3641            throw new Error('Component \'' + componentName + '\' has no template');
3642        }
3643
3644        var clonedNodesArray = ko.utils.cloneNodes(template);
3645        ko.virtualElements.setDomNodeChildren(element, clonedNodesArray);
3646    }
3647
3648    function createViewModel(componentDefinition, element, originalChildNodes, componentParams) {
3649        var componentViewModelFactory = componentDefinition['createViewModel'];
3650        return componentViewModelFactory
3651            ? componentViewModelFactory.call(componentDefinition, componentParams, { 'element': element, 'templateNodes': originalChildNodes })
3652            : componentParams; // Template-only component
3653    }
3654
3655})();
3656var attrHtmlToJavascriptMap = { 'class': 'className', 'for': 'htmlFor' };
3657ko.bindingHandlers['attr'] = {
3658    'update': function(element, valueAccessor, allBindings) {
3659        var value = ko.utils.unwrapObservable(valueAccessor()) || {};
3660        ko.utils.objectForEach(value, function(attrName, attrValue) {
3661            attrValue = ko.utils.unwrapObservable(attrValue);
3662
3663            // To cover cases like "attr: { checked:someProp }", we want to remove the attribute entirely
3664            // when someProp is a "no value"-like value (strictly null, false, or undefined)
3665            // (because the absence of the "checked" attr is how to mark an element as not checked, etc.)
3666            var toRemove = (attrValue === false) || (attrValue === null) || (attrValue === undefined);
3667            if (toRemove)
3668                element.removeAttribute(attrName);
3669
3670            // In IE <= 7 and IE8 Quirks Mode, you have to use the Javascript property name instead of the
3671            // HTML attribute name for certain attributes. IE8 Standards Mode supports the correct behavior,
3672            // but instead of figuring out the mode, we'll just set the attribute through the Javascript
3673            // property for IE <= 8.
3674            if (ko.utils.ieVersion <= 8 && attrName in attrHtmlToJavascriptMap) {
3675                attrName = attrHtmlToJavascriptMap[attrName];
3676                if (toRemove)
3677                    element.removeAttribute(attrName);
3678                else
3679                    element[attrName] = attrValue;
3680            } else if (!toRemove) {
3681                element.setAttribute(attrName, attrValue.toString());
3682            }
3683
3684            // Treat "name" specially - although you can think of it as an attribute, it also needs
3685            // special handling on older versions of IE (https://github.com/SteveSanderson/knockout/pull/333)
3686            // Deliberately being case-sensitive here because XHTML would regard "Name" as a different thing
3687            // entirely, and there's no strong reason to allow for such casing in HTML.
3688            if (attrName === "name") {
3689                ko.utils.setElementName(element, toRemove ? "" : attrValue.toString());
3690            }
3691        });
3692    }
3693};
3694(function() {
3695
3696ko.bindingHandlers['checked'] = {
3697    'after': ['value', 'attr'],
3698    'init': function (element, valueAccessor, allBindings) {
3699        var checkedValue = ko.pureComputed(function() {
3700            // Treat "value" like "checkedValue" when it is included with "checked" binding
3701            if (allBindings['has']('checkedValue')) {
3702                return ko.utils.unwrapObservable(allBindings.get('checkedValue'));
3703            } else if (allBindings['has']('value')) {
3704                return ko.utils.unwrapObservable(allBindings.get('value'));
3705            }
3706
3707            return element.value;
3708        });
3709
3710        function updateModel() {
3711            // This updates the model value from the view value.
3712            // It runs in response to DOM events (click) and changes in checkedValue.
3713            var isChecked = element.checked,
3714                elemValue = useCheckedValue ? checkedValue() : isChecked;
3715
3716            // When we're first setting up this computed, don't change any model state.
3717            if (ko.computedContext.isInitial()) {
3718                return;
3719            }
3720
3721            // We can ignore unchecked radio buttons, because some other radio
3722            // button will be getting checked, and that one can take care of updating state.
3723            if (isRadio && !isChecked) {
3724                return;
3725            }
3726
3727            var modelValue = ko.dependencyDetection.ignore(valueAccessor);
3728            if (isValueArray) {
3729                if (oldElemValue !== elemValue) {
3730                    // When we're responding to the checkedValue changing, and the element is
3731                    // currently checked, replace the old elem value with the new elem value
3732                    // in the model array.
3733                    if (isChecked) {
3734                        ko.utils.addOrRemoveItem(modelValue, elemValue, true);
3735                        ko.utils.addOrRemoveItem(modelValue, oldElemValue, false);
3736                    }
3737
3738                    oldElemValue = elemValue;
3739                } else {
3740                    // When we're responding to the user having checked/unchecked a checkbox,
3741                    // add/remove the element value to the model array.
3742                    ko.utils.addOrRemoveItem(modelValue, elemValue, isChecked);
3743                }
3744            } else {
3745                ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'checked', elemValue, true);
3746            }
3747        };
3748
3749        function updateView() {
3750            // This updates the view value from the model value.
3751            // It runs in response to changes in the bound (checked) value.
3752            var modelValue = ko.utils.unwrapObservable(valueAccessor());
3753
3754            if (isValueArray) {
3755                // When a checkbox is bound to an array, being checked represents its value being present in that array
3756                element.checked = ko.utils.arrayIndexOf(modelValue, checkedValue()) >= 0;
3757            } else if (isCheckbox) {
3758                // When a checkbox is bound to any other value (not an array), being checked represents the value being trueish
3759                element.checked = modelValue;
3760            } else {
3761                // For radio buttons, being checked means that the radio button's value corresponds to the model value
3762                element.checked = (checkedValue() === modelValue);
3763            }
3764        };
3765
3766        var isCheckbox = element.type == "checkbox",
3767            isRadio = element.type == "radio";
3768
3769        // Only bind to check boxes and radio buttons
3770        if (!isCheckbox && !isRadio) {
3771            return;
3772        }
3773
3774        var isValueArray = isCheckbox && (ko.utils.unwrapObservable(valueAccessor()) instanceof Array),
3775            oldElemValue = isValueArray ? checkedValue() : undefined,
3776            useCheckedValue = isRadio || isValueArray;
3777
3778        // IE 6 won't allow radio buttons to be selected unless they have a name
3779        if (isRadio && !element.name)
3780            ko.bindingHandlers['uniqueName']['init'](element, function() { return true });
3781
3782        // Set up two computeds to update the binding:
3783
3784        // The first responds to changes in the checkedValue value and to element clicks
3785        ko.computed(updateModel, null, { disposeWhenNodeIsRemoved: element });
3786        ko.utils.registerEventHandler(element, "click", updateModel);
3787
3788        // The second responds to changes in the model value (the one associated with the checked binding)
3789        ko.computed(updateView, null, { disposeWhenNodeIsRemoved: element });
3790    }
3791};
3792ko.expressionRewriting.twoWayBindings['checked'] = true;
3793
3794ko.bindingHandlers['checkedValue'] = {
3795    'update': function (element, valueAccessor) {
3796        element.value = ko.utils.unwrapObservable(valueAccessor());
3797    }
3798};
3799
3800})();var classesWrittenByBindingKey = '__ko__cssValue';
3801ko.bindingHandlers['css'] = {
3802    'update': function (element, valueAccessor) {
3803        var value = ko.utils.unwrapObservable(valueAccessor());
3804        if (value !== null && typeof value == "object") {
3805            ko.utils.objectForEach(value, function(className, shouldHaveClass) {
3806                shouldHaveClass = ko.utils.unwrapObservable(shouldHaveClass);
3807                ko.utils.toggleDomNodeCssClass(element, className, shouldHaveClass);
3808            });
3809        } else {
3810            value = String(value || ''); // Make sure we don't try to store or set a non-string value
3811            ko.utils.toggleDomNodeCssClass(element, element[classesWrittenByBindingKey], false);
3812            element[classesWrittenByBindingKey] = value;
3813            ko.utils.toggleDomNodeCssClass(element, value, true);
3814        }
3815    }
3816};
3817ko.bindingHandlers['enable'] = {
3818    'update': function (element, valueAccessor) {
3819        var value = ko.utils.unwrapObservable(valueAccessor());
3820        if (value && element.disabled)
3821            element.removeAttribute("disabled");
3822        else if ((!value) && (!element.disabled))
3823            element.disabled = true;
3824    }
3825};
3826
3827ko.bindingHandlers['disable'] = {
3828    'update': function (element, valueAccessor) {
3829        ko.bindingHandlers['enable']['update'](element, function() { return !ko.utils.unwrapObservable(valueAccessor()) });
3830    }
3831};
3832// For certain common events (currently just 'click'), allow a simplified data-binding syntax
3833// e.g. click:handler instead of the usual full-length event:{click:handler}
3834function makeEventHandlerShortcut(eventName) {
3835    ko.bindingHandlers[eventName] = {
3836        'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
3837            var newValueAccessor = function () {
3838                var result = {};
3839                result[eventName] = valueAccessor();
3840                return result;
3841            };
3842            return ko.bindingHandlers['event']['init'].call(this, element, newValueAccessor, allBindings, viewModel, bindingContext);
3843        }
3844    }
3845}
3846
3847ko.bindingHandlers['event'] = {
3848    'init' : function (element, valueAccessor, allBindings, viewModel, bindingContext) {
3849        var eventsToHandle = valueAccessor() || {};
3850        ko.utils.objectForEach(eventsToHandle, function(eventName) {
3851            if (typeof eventName == "string") {
3852                ko.utils.registerEventHandler(element, eventName, function (event) {
3853                    var handlerReturnValue;
3854                    var handlerFunction = valueAccessor()[eventName];
3855                    if (!handlerFunction)
3856                        return;
3857
3858                    try {
3859                        // Take all the event args, and prefix with the viewmodel
3860                        var argsForHandler = ko.utils.makeArray(arguments);
3861                        viewModel = bindingContext['$data'];
3862                        argsForHandler.unshift(viewModel);
3863                        handlerReturnValue = handlerFunction.apply(viewModel, argsForHandler);
3864                    } finally {
3865                        if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
3866                            if (event.preventDefault)
3867                                event.preventDefault();
3868                            else
3869                                event.returnValue = false;
3870                        }
3871                    }
3872
3873                    var bubble = allBindings.get(eventName + 'Bubble') !== false;
3874                    if (!bubble) {
3875                        event.cancelBubble = true;
3876                        if (event.stopPropagation)
3877                            event.stopPropagation();
3878                    }
3879                });
3880            }
3881        });
3882    }
3883};
3884// "foreach: someExpression" is equivalent to "template: { foreach: someExpression }"
3885// "foreach: { data: someExpression, afterAdd: myfn }" is equivalent to "template: { foreach: someExpression, afterAdd: myfn }"
3886ko.bindingHandlers['foreach'] = {
3887    makeTemplateValueAccessor: function(valueAccessor) {
3888        return function() {
3889            var modelValue = valueAccessor(),
3890                unwrappedValue = ko.utils.peekObservable(modelValue);    // Unwrap without setting a dependency here
3891
3892            // If unwrappedValue is the array, pass in the wrapped value on its own
3893            // The value will be unwrapped and tracked within the template binding
3894            // (See https://github.com/SteveSanderson/knockout/issues/523)
3895            if ((!unwrappedValue) || typeof unwrappedValue.length == "number")
3896                return { 'foreach': modelValue, 'templateEngine': ko.nativeTemplateEngine.instance };
3897
3898            // If unwrappedValue.data is the array, preserve all relevant options and unwrap again value so we get updates
3899            ko.utils.unwrapObservable(modelValue);
3900            return {
3901                'foreach': unwrappedValue['data'],
3902                'as': unwrappedValue['as'],
3903                'includeDestroyed': unwrappedValue['includeDestroyed'],
3904                'afterAdd': unwrappedValue['afterAdd'],
3905                'beforeRemove': unwrappedValue['beforeRemove'],
3906                'afterRender': unwrappedValue['afterRender'],
3907                'beforeMove': unwrappedValue['beforeMove'],
3908                'afterMove': unwrappedValue['afterMove'],
3909                'templateEngine': ko.nativeTemplateEngine.instance
3910            };
3911        };
3912    },
3913    'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
3914        return ko.bindingHandlers['template']['init'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor));
3915    },
3916    'update': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
3917        return ko.bindingHandlers['template']['update'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor), allBindings, viewModel, bindingContext);
3918    }
3919};
3920ko.expressionRewriting.bindingRewriteValidators['foreach'] = false; // Can't rewrite control flow bindings
3921ko.virtualElements.allowedBindings['foreach'] = true;
3922var hasfocusUpdatingProperty = '__ko_hasfocusUpdating';
3923var hasfocusLastValue = '__ko_hasfocusLastValue';
3924ko.bindingHandlers['hasfocus'] = {
3925    'init': function(element, valueAccessor, allBindings) {
3926        var handleElementFocusChange = function(isFocused) {
3927            // Where possible, ignore which event was raised and determine focus state using activeElement,
3928            // as this avoids phantom focus/blur events raised when changing tabs in modern browsers.
3929            // However, not all KO-targeted browsers (Firefox 2) support activeElement. For those browsers,
3930            // prevent a loss of focus when changing tabs/windows by setting a flag that prevents hasfocus
3931            // from calling 'blur()' on the element when it loses focus.
3932            // Discussion at https://github.com/SteveSanderson/knockout/pull/352
3933            element[hasfocusUpdatingProperty] = true;
3934            var ownerDoc = element.ownerDocument;
3935            if ("activeElement" in ownerDoc) {
3936                var active;
3937                try {
3938                    active = ownerDoc.activeElement;
3939                } catch(e) {
3940                    // IE9 throws if you access activeElement during page load (see issue #703)
3941                    active = ownerDoc.body;
3942                }
3943                isFocused = (active === element);
3944            }
3945            var modelValue = valueAccessor();
3946            ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'hasfocus', isFocused, true);
3947
3948            //cache the latest value, so we can avoid unnecessarily calling focus/blur in the update function
3949            element[hasfocusLastValue] = isFocused;
3950            element[hasfocusUpdatingProperty] = false;
3951        };
3952        var handleElementFocusIn = handleElementFocusChange.bind(null, true);
3953        var handleElementFocusOut = handleElementFocusChange.bind(null, false);
3954
3955        ko.utils.registerEventHandler(element, "focus", handleElementFocusIn);
3956        ko.utils.registerEventHandler(element, "focusin", handleElementFocusIn); // For IE
3957        ko.utils.registerEventHandler(element, "blur",  handleElementFocusOut);
3958        ko.utils.registerEventHandler(element, "focusout",  handleElementFocusOut); // For IE
3959    },
3960    'update': function(element, valueAccessor) {
3961        var value = !!ko.utils.unwrapObservable(valueAccessor()); //force boolean to compare with last value
3962        if (!element[hasfocusUpdatingProperty] && element[hasfocusLastValue] !== value) {
3963            value ? element.focus() : element.blur();
3964            ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, value ? "focusin" : "focusout"]); // For IE, which doesn't reliably fire "focus" or "blur" events synchronously
3965        }
3966    }
3967};
3968ko.expressionRewriting.twoWayBindings['hasfocus'] = true;
3969
3970ko.bindingHandlers['hasFocus'] = ko.bindingHandlers['hasfocus']; // Make "hasFocus" an alias
3971ko.expressionRewriting.twoWayBindings['hasFocus'] = true;
3972ko.bindingHandlers['html'] = {
3973    'init': function() {
3974        // Prevent binding on the dynamically-injected HTML (as developers are unlikely to expect that, and it has security implications)
3975        return { 'controlsDescendantBindings': true };
3976    },
3977    'update': function (element, valueAccessor) {
3978        // setHtml will unwrap the value if needed
3979        ko.utils.setHtml(element, valueAccessor());
3980    }
3981};
3982// Makes a binding like with or if
3983function makeWithIfBinding(bindingKey, isWith, isNot, makeContextCallback) {
3984    ko.bindingHandlers[bindingKey] = {
3985        'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
3986            var didDisplayOnLastUpdate,
3987                savedNodes;
3988            ko.computed(function() {
3989                var dataValue = ko.utils.unwrapObservable(valueAccessor()),
3990                    shouldDisplay = !isNot !== !dataValue, // equivalent to isNot ? !dataValue : !!dataValue
3991                    isFirstRender = !savedNodes,
3992                    needsRefresh = isFirstRender || isWith || (shouldDisplay !== didDisplayOnLastUpdate);
3993
3994                if (needsRefresh) {
3995                    // Save a copy of the inner nodes on the initial update, but only if we have dependencies.
3996                    if (isFirstRender && ko.computedContext.getDependenciesCount()) {
3997                        savedNodes = ko.utils.cloneNodes(ko.virtualElements.childNodes(element), true /* shouldCleanNodes */);
3998                    }
3999
4000                    if (shouldDisplay) {
4001                        if (!isFirstRender) {
4002                            ko.virtualElements.setDomNodeChildren(element, ko.utils.cloneNodes(savedNodes));
4003                        }
4004                        ko.applyBindingsToDescendants(makeContextCallback ? makeContextCallback(bindingContext, dataValue) : bindingContext, element);
4005                    } else {
4006                        ko.virtualElements.emptyNode(element);
4007                    }
4008
4009                    didDisplayOnLastUpdate = shouldDisplay;
4010                }
4011            }, null, { disposeWhenNodeIsRemoved: element });
4012            return { 'controlsDescendantBindings': true };
4013        }
4014    };
4015    ko.expressionRewriting.bindingRewriteValidators[bindingKey] = false; // Can't rewrite control flow bindings
4016    ko.virtualElements.allowedBindings[bindingKey] = true;
4017}
4018
4019// Construct the actual binding handlers
4020makeWithIfBinding('if');
4021makeWithIfBinding('ifnot', false /* isWith */, true /* isNot */);
4022makeWithIfBinding('with', true /* isWith */, false /* isNot */,
4023    function(bindingContext, dataValue) {
4024        return bindingContext['createChildContext'](dataValue);
4025    }
4026);
4027var captionPlaceholder = {};
4028ko.bindingHandlers['options'] = {
4029    'init': function(element) {
4030        if (ko.utils.tagNameLower(element) !== "select")
4031            throw new Error("options binding applies only to SELECT elements");
4032
4033        // Remove all existing <option>s.
4034        while (element.length > 0) {
4035            element.remove(0);
4036        }
4037
4038        // Ensures that the binding processor doesn't try to bind the options
4039        return { 'controlsDescendantBindings': true };
4040    },
4041    'update': function (element, valueAccessor, allBindings) {
4042        function selectedOptions() {
4043            return ko.utils.arrayFilter(element.options, function (node) { return node.selected; });
4044        }
4045
4046        var selectWasPreviouslyEmpty = element.length == 0,
4047            multiple = element.multiple,
4048            previousScrollTop = (!selectWasPreviouslyEmpty && multiple) ? element.scrollTop : null,
4049            unwrappedArray = ko.utils.unwrapObservable(valueAccessor()),
4050            valueAllowUnset = allBindings.get('valueAllowUnset') && allBindings['has']('value'),
4051            includeDestroyed = allBindings.get('optionsIncludeDestroyed'),
4052            arrayToDomNodeChildrenOptions = {},
4053            captionValue,
4054            filteredArray,
4055            previousSelectedValues = [];
4056
4057        if (!valueAllowUnset) {
4058            if (multiple) {
4059                previousSelectedValues = ko.utils.arrayMap(selectedOptions(), ko.selectExtensions.readValue);
4060            } else if (element.selectedIndex >= 0) {
4061                previousSelectedValues.push(ko.selectExtensions.readValue(element.options[element.selectedIndex]));
4062            }
4063        }
4064
4065        if (unwrappedArray) {
4066            if (typeof unwrappedArray.length == "undefined") // Coerce single value into array
4067                unwrappedArray = [unwrappedArray];
4068
4069            // Filter out any entries marked as destroyed
4070            filteredArray = ko.utils.arrayFilter(unwrappedArray, function(item) {
4071                return includeDestroyed || item === undefined || item === null || !ko.utils.unwrapObservable(item['_destroy']);
4072            });
4073
4074            // If caption is included, add it to the array
4075            if (allBindings['has']('optionsCaption')) {
4076                captionValue = ko.utils.unwrapObservable(allBindings.get('optionsCaption'));
4077                // If caption value is null or undefined, don't show a caption
4078                if (captionValue !== null && captionValue !== undefined) {
4079                    filteredArray.unshift(captionPlaceholder);
4080                }
4081            }
4082        } else {
4083            // If a falsy value is provided (e.g. null), we'll simply empty the select element
4084        }
4085
4086        function applyToObject(object, predicate, defaultValue) {
4087            var predicateType = typeof predicate;
4088            if (predicateType == "function")    // Given a function; run it against the data value
4089                return predicate(object);
4090            else if (predicateType == "string") // Given a string; treat it as a property name on the data value
4091                return object[predicate];
4092            else                                // Given no optionsText arg; use the data value itself
4093                return defaultValue;
4094        }
4095
4096        // The following functions can run at two different times:
4097        // The first is when the whole array is being updated directly from this binding handler.
4098        // The second is when an observable value for a specific array entry is updated.
4099        // oldOptions will be empty in the first case, but will be filled with the previously generated option in the second.
4100        var itemUpdate = false;
4101        function optionForArrayItem(arrayEntry, index, oldOptions) {
4102            if (oldOptions.length) {
4103                previousSelectedValues = !valueAllowUnset && oldOptions[0].selected ? [ ko.selectExtensions.readValue(oldOptions[0]) ] : [];
4104                itemUpdate = true;
4105            }
4106            var option = element.ownerDocument.createElement("option");
4107            if (arrayEntry === captionPlaceholder) {
4108                ko.utils.setTextContent(option, allBindings.get('optionsCaption'));
4109                ko.selectExtensions.writeValue(option, undefined);
4110            } else {
4111                // Apply a value to the option element
4112                var optionValue = applyToObject(arrayEntry, allBindings.get('optionsValue'), arrayEntry);
4113                ko.selectExtensions.writeValue(option, ko.utils.unwrapObservable(optionValue));
4114
4115                // Apply some text to the option element
4116                var optionText = applyToObject(arrayEntry, allBindings.get('optionsText'), optionValue);
4117                ko.utils.setTextContent(option, optionText);
4118            }
4119            return [option];
4120        }
4121
4122        // By using a beforeRemove callback, we delay the removal until after new items are added. This fixes a selection
4123        // problem in IE<=8 and Firefox. See https://github.com/knockout/knockout/issues/1208
4124        arrayToDomNodeChildrenOptions['beforeRemove'] =
4125            function (option) {
4126                element.removeChild(option);
4127            };
4128
4129        function setSelectionCallback(arrayEntry, newOptions) {
4130            if (itemUpdate && valueAllowUnset) {
4131                // The model value is authoritative, so make sure its value is the one selected
4132                // There is no need to use dependencyDetection.ignore since setDomNodeChildrenFromArrayMapping does so already.
4133                ko.selectExtensions.writeValue(element, ko.utils.unwrapObservable(allBindings.get('value')), true /* allowUnset */);
4134            } else if (previousSelectedValues.length) {
4135                // IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document.
4136                // That's why we first added them without selection. Now it's time to set the selection.
4137                var isSelected = ko.utils.arrayIndexOf(previousSelectedValues, ko.selectExtensions.readValue(newOptions[0])) >= 0;
4138                ko.utils.setOptionNodeSelectionState(newOptions[0], isSelected);
4139
4140                // If this option was changed from being selected during a single-item update, notify the change
4141                if (itemUpdate && !isSelected) {
4142                    ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, "change"]);
4143                }
4144            }
4145        }
4146
4147        var callback = setSelectionCallback;
4148        if (allBindings['has']('optionsAfterRender') && typeof allBindings.get('optionsAfterRender') == "function") {
4149            callback = function(arrayEntry, newOptions) {
4150                setSelectionCallback(arrayEntry, newOptions);
4151                ko.dependencyDetection.ignore(allBindings.get('optionsAfterRender'), null, [newOptions[0], arrayEntry !== captionPlaceholder ? arrayEntry : undefined]);
4152            }
4153        }
4154
4155        ko.utils.setDomNodeChildrenFromArrayMapping(element, filteredArray, optionForArrayItem, arrayToDomNodeChildrenOptions, callback);
4156
4157        ko.dependencyDetection.ignore(function () {
4158            if (valueAllowUnset) {
4159                // The model value is authoritative, so make sure its value is the one selected
4160                ko.selectExtensions.writeValue(element, ko.utils.unwrapObservable(allBindings.get('value')), true /* allowUnset */);
4161            } else {
4162                // Determine if the selection has changed as a result of updating the options list
4163                var selectionChanged;
4164                if (multiple) {
4165                    // For a multiple-select box, compare the new selection count to the previous one
4166                    // But if nothing was selected before, the selection can't have changed
4167                    selectionChanged = previousSelectedValues.length && selectedOptions().length < previousSelectedValues.length;
4168                } else {
4169                    // For a single-select box, compare the current value to the previous value
4170                    // But if nothing was selected before or nothing is selected now, just look for a change in selection
4171                    selectionChanged = (previousSelectedValues.length && element.selectedIndex >= 0)
4172                        ? (ko.selectExtensions.readValue(element.options[element.selectedIndex]) !== previousSelectedValues[0])
4173                        : (previousSelectedValues.length || element.selectedIndex >= 0);
4174                }
4175
4176                // Ensure consistency between model value and selected option.
4177                // If the dropdown was changed so that selection is no longer the same,
4178                // notify the value or selectedOptions binding.
4179                if (selectionChanged) {
4180                    ko.utils.triggerEvent(element, "change");
4181                }
4182            }
4183        });
4184
4185        // Workaround for IE bug
4186        ko.utils.ensureSelectElementIsRenderedCorrectly(element);
4187
4188        if (previousScrollTop && Math.abs(previousScrollTop - element.scrollTop) > 20)
4189            element.scrollTop = previousScrollTop;
4190    }
4191};
4192ko.bindingHandlers['options'].optionValueDomDataKey = ko.utils.domData.nextKey();
4193ko.bindingHandlers['selectedOptions'] = {
4194    'after': ['options', 'foreach'],
4195    'init': function (element, valueAccessor, allBindings) {
4196        ko.utils.registerEventHandler(element, "change", function () {
4197            var value = valueAccessor(), valueToWrite = [];
4198            ko.utils.arrayForEach(element.getElementsByTagName("option"), function(node) {
4199                if (node.selected)
4200                    valueToWrite.push(ko.selectExtensions.readValue(node));
4201            });
4202            ko.expressionRewriting.writeValueToProperty(value, allBindings, 'selectedOptions', valueToWrite);
4203        });
4204    },
4205    'update': function (element, valueAccessor) {
4206        if (ko.utils.tagNameLower(element) != "select")
4207            throw new Error("values binding applies only to SELECT elements");
4208
4209        var newValue = ko.utils.unwrapObservable(valueAccessor());
4210        if (newValue && typeof newValue.length == "number") {
4211            ko.utils.arrayForEach(element.getElementsByTagName("option"), function(node) {
4212                var isSelected = ko.utils.arrayIndexOf(newValue, ko.selectExtensions.readValue(node)) >= 0;
4213                ko.utils.setOptionNodeSelectionState(node, isSelected);
4214            });
4215        }
4216    }
4217};
4218ko.expressionRewriting.twoWayBindings['selectedOptions'] = true;
4219ko.bindingHandlers['style'] = {
4220    'update': function (element, valueAccessor) {
4221        var value = ko.utils.unwrapObservable(valueAccessor() || {});
4222        ko.utils.objectForEach(value, function(styleName, styleValue) {
4223            styleValue = ko.utils.unwrapObservable(styleValue);
4224
4225            if (styleValue === null || styleValue === undefined || styleValue === false) {
4226                // Empty string removes the value, whereas null/undefined have no effect
4227                styleValue = "";
4228            }
4229
4230            element.style[styleName] = styleValue;
4231        });
4232    }
4233};
4234ko.bindingHandlers['submit'] = {
4235    'init': function (element, valueAccessor, allBindings, viewModel, bindingContext) {
4236        if (typeof valueAccessor() != "function")
4237            throw new Error("The value for a submit binding must be a function");
4238        ko.utils.registerEventHandler(element, "submit", function (event) {
4239            var handlerReturnValue;
4240            var value = valueAccessor();
4241            try { handlerReturnValue = value.call(bindingContext['$data'], element); }
4242            finally {
4243                if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
4244                    if (event.preventDefault)
4245                        event.preventDefault();
4246                    else
4247                        event.returnValue = false;
4248                }
4249            }
4250        });
4251    }
4252};
4253ko.bindingHandlers['text'] = {
4254    'init': function() {
4255        // Prevent binding on the dynamically-injected text node (as developers are unlikely to expect that, and it has security implications).
4256        // It should also make things faster, as we no longer have to consider whether the text node might be bindable.
4257        return { 'controlsDescendantBindings': true };
4258    },
4259    'update': function (element, valueAccessor) {
4260        ko.utils.setTextContent(element, valueAccessor());
4261    }
4262};
4263ko.virtualElements.allowedBindings['text'] = true;
4264(function () {
4265
4266if (window && window.navigator) {
4267    var parseVersion = function (matches) {
4268        if (matches) {
4269            return parseFloat(matches[1]);
4270        }
4271    };
4272
4273    // Detect various browser versions because some old versions don't fully support the 'input' event
4274    var operaVersion = window.opera && window.opera.version && parseInt(window.opera.version()),
4275        userAgent = window.navigator.userAgent,
4276        safariVersion = parseVersion(userAgent.match(/^(?:(?!chrome).)*version\/([^ ]*) safari/i)),
4277        firefoxVersion = parseVersion(userAgent.match(/Firefox\/([^ ]*)/));
4278}
4279
4280// IE 8 and 9 have bugs that prevent the normal events from firing when the value changes.
4281// But it does fire the 'selectionchange' event on many of those, presumably because the
4282// cursor is moving and that counts as the selection changing. The 'selectionchange' event is
4283// fired at the document level only and doesn't directly indicate which element changed. We
4284// set up just one event handler for the document and use 'activeElement' to determine which
4285// element was changed.
4286if (ko.utils.ieVersion < 10) {
4287    var selectionChangeRegisteredName = ko.utils.domData.nextKey(),
4288        selectionChangeHandlerName = ko.utils.domData.nextKey();
4289    var selectionChangeHandler = function(event) {
4290        var target = this.activeElement,
4291            handler = target && ko.utils.domData.get(target, selectionChangeHandlerName);
4292        if (handler) {
4293            handler(event);
4294        }
4295    };
4296    var registerForSelectionChangeEvent = function (element, handler) {
4297        var ownerDoc = element.ownerDocument;
4298        if (!ko.utils.domData.get(ownerDoc, selectionChangeRegisteredName)) {
4299            ko.utils.domData.set(ownerDoc, selectionChangeRegisteredName, true);
4300            ko.utils.registerEventHandler(ownerDoc, 'selectionchange', selectionChangeHandler);
4301        }
4302        ko.utils.domData.set(element, selectionChangeHandlerName, handler);
4303    };
4304}
4305
4306ko.bindingHandlers['textInput'] = {
4307    'init': function (element, valueAccessor, allBindings) {
4308
4309        var previousElementValue = element.value,
4310            timeoutHandle,
4311            elementValueBeforeEvent;
4312
4313        var updateModel = function (event) {
4314            clearTimeout(timeoutHandle);
4315            elementValueBeforeEvent = timeoutHandle = undefined;
4316
4317            var elementValue = element.value;
4318            if (previousElementValue !== elementValue) {
4319                // Provide a way for tests to know exactly which event was processed
4320                if (DEBUG && event) element['_ko_textInputProcessedEvent'] = event.type;
4321                previousElementValue = elementValue;
4322                ko.expressionRewriting.writeValueToProperty(valueAccessor(), allBindings, 'textInput', elementValue);
4323            }
4324        };
4325
4326        var deferUpdateModel = function (event) {
4327            if (!timeoutHandle) {
4328                // The elementValueBeforeEvent variable is set *only* during the brief gap between an
4329                // event firing and the updateModel function running. This allows us to ignore model
4330                // updates that are from the previous state of the element, usually due to techniques
4331                // such as rateLimit. Such updates, if not ignored, can cause keystrokes to be lost.
4332                elementValueBeforeEvent = element.value;
4333                var handler = DEBUG ? updateModel.bind(element, {type: event.type}) : updateModel;
4334                timeoutHandle = setTimeout(handler, 4);
4335            }
4336        };
4337
4338        var updateView = function () {
4339            var modelValue = ko.utils.unwrapObservable(valueAccessor());
4340
4341            if (modelValue === null || modelValue === undefined) {
4342                modelValue = '';
4343            }
4344
4345            if (elementValueBeforeEvent !== undefined && modelValue === elementValueBeforeEvent) {
4346                setTimeout(updateView, 4);
4347                return;
4348            }
4349
4350            // Update the element only if the element and model are different. On some browsers, updating the value
4351            // will move the cursor to the end of the input, which would be bad while the user is typing.
4352            if (element.value !== modelValue) {
4353                previousElementValue = modelValue;  // Make sure we ignore events (propertychange) that result from updating the value
4354                element.value = modelValue;
4355            }
4356        };
4357
4358        var onEvent = function (event, handler) {
4359            ko.utils.registerEventHandler(element, event, handler);
4360        };
4361
4362        if (DEBUG && ko.bindingHandlers['textInput']['_forceUpdateOn']) {
4363            // Provide a way for tests to specify exactly which events are bound
4364            ko.utils.arrayForEach(ko.bindingHandlers['textInput']['_forceUpdateOn'], function(eventName) {
4365                if (eventName.slice(0,5) == 'after') {
4366                    onEvent(eventName.slice(5), deferUpdateModel);
4367                } else {
4368                    onEvent(eventName, updateModel);
4369                }
4370            });
4371        } else {
4372            if (ko.utils.ieVersion < 10) {
4373                // Internet Explorer <= 8 doesn't support the 'input' event, but does include 'propertychange' that fires whenever
4374                // any property of an element changes. Unlike 'input', it also fires if a property is changed from JavaScript code,
4375                // but that's an acceptable compromise for this binding. IE 9 does support 'input', but since it doesn't fire it
4376                // when using autocomplete, we'll use 'propertychange' for it also.
4377                onEvent('propertychange', function(event) {
4378                    if (event.propertyName === 'value') {
4379                        updateModel(event);
4380                    }
4381                });
4382
4383                if (ko.utils.ieVersion == 8) {
4384                    // IE 8 has a bug where it fails to fire 'propertychange' on the first update following a value change from
4385                    // JavaScript code. It also doesn't fire if you clear the entire value. To fix this, we bind to the following
4386                    // events too.
4387                    onEvent('keyup', updateModel);      // A single keystoke
4388                    onEvent('keydown', updateModel);    // The first character when a key is held down
4389                }
4390                if (ko.utils.ieVersion >= 8) {
4391                    // Internet Explorer 9 doesn't fire the 'input' event when deleting text, including using
4392                    // the backspace, delete, or ctrl-x keys, clicking the 'x' to clear the input, dragging text
4393                    // out of the field, and cutting or deleting text using the context menu. 'selectionchange'
4394                    // can detect all of those except dragging text out of the field, for which we use 'dragend'.
4395                    // These are also needed in IE8 because of the bug described above.
4396                    registerForSelectionChangeEvent(element, updateModel);  // 'selectionchange' covers cut, paste, drop, delete, etc.
4397                    onEvent('dragend', deferUpdateModel);
4398                }
4399            } else {
4400                // All other supported browsers support the 'input' event, which fires whenever the content of the element is changed
4401                // through the user interface.
4402                onEvent('input', updateModel);
4403
4404                if (safariVersion < 5 && ko.utils.tagNameLower(element) === "textarea") {
4405                    // Safari <5 doesn't fire the 'input' event for <textarea> elements (it does fire 'textInput'
4406                    // but only when typing). So we'll just catch as much as we can with keydown, cut, and paste.
4407                    onEvent('keydown', deferUpdateModel);
4408                    onEvent('paste', deferUpdateModel);
4409                    onEvent('cut', deferUpdateModel);
4410                } else if (operaVersion < 11) {
4411                    // Opera 10 doesn't always fire the 'input' event for cut, paste, undo & drop operations.
4412                    // We can try to catch some of those using 'keydown'.
4413                    onEvent('keydown', deferUpdateModel);
4414                } else if (firefoxVersion < 4.0) {
4415                    // Firefox <= 3.6 doesn't fire the 'input' event when text is filled in through autocomplete
4416                    onEvent('DOMAutoComplete', updateModel);
4417
4418                    // Firefox <=3.5 doesn't fire the 'input' event when text is dropped into the input.
4419                    onEvent('dragdrop', updateModel);       // <3.5
4420                    onEvent('drop', updateModel);           // 3.5
4421                }
4422            }
4423        }
4424
4425        // Bind to the change event so that we can catch programmatic updates of the value that fire this event.
4426        onEvent('change', updateModel);
4427
4428        ko.computed(updateView, null, { disposeWhenNodeIsRemoved: element });
4429    }
4430};
4431ko.expressionRewriting.twoWayBindings['textInput'] = true;
4432
4433// textinput is an alias for textInput
4434ko.bindingHandlers['textinput'] = {
4435    // preprocess is the only way to set up a full alias
4436    'preprocess': function (value, name, addBinding) {
4437        addBinding('textInput', value);
4438    }
4439};
4440
4441})();ko.bindingHandlers['uniqueName'] = {
4442    'init': function (element, valueAccessor) {
4443        if (valueAccessor()) {
4444            var name = "ko_unique_" + (++ko.bindingHandlers['uniqueName'].currentIndex);
4445            ko.utils.setElementName(element, name);
4446        }
4447    }
4448};
4449ko.bindingHandlers['uniqueName'].currentIndex = 0;
4450ko.bindingHandlers['value'] = {
4451    'after': ['options', 'foreach'],
4452    'init': function (element, valueAccessor, allBindings) {
4453        // If the value binding is placed on a radio/checkbox, then just pass through to checkedValue and quit
4454        if (element.tagName.toLowerCase() == "input" && (element.type == "checkbox" || element.type == "radio")) {
4455            ko.applyBindingAccessorsToNode(element, { 'checkedValue': valueAccessor });
4456            return;
4457        }
4458
4459        // Always catch "change" event; possibly other events too if asked
4460        var eventsToCatch = ["change"];
4461        var requestedEventsToCatch = allBindings.get("valueUpdate");
4462        var propertyChangedFired = false;
4463        var elementValueBeforeEvent = null;
4464
4465        if (requestedEventsToCatch) {
4466            if (typeof requestedEventsToCatch == "string") // Allow both individual event names, and arrays of event names
4467                requestedEventsToCatch = [requestedEventsToCatch];
4468            ko.utils.arrayPushAll(eventsToCatch, requestedEventsToCatch);
4469            eventsToCatch = ko.utils.arrayGetDistinctValues(eventsToCatch);
4470        }
4471
4472        var valueUpdateHandler = function() {
4473            elementValueBeforeEvent = null;
4474            propertyChangedFired = false;
4475            var modelValue = valueAccessor();
4476            var elementValue = ko.selectExtensions.readValue(element);
4477            ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'value', elementValue);
4478        }
4479
4480        // Workaround for https://github.com/SteveSanderson/knockout/issues/122
4481        // IE doesn't fire "change" events on textboxes if the user selects a value from its autocomplete list
4482        var ieAutoCompleteHackNeeded = ko.utils.ieVersion && element.tagName.toLowerCase() == "input" && element.type == "text"
4483                                       && element.autocomplete != "off" && (!element.form || element.form.autocomplete != "off");
4484        if (ieAutoCompleteHackNeeded && ko.utils.arrayIndexOf(eventsToCatch, "propertychange") == -1) {
4485            ko.utils.registerEventHandler(element, "propertychange", function () { propertyChangedFired = true });
4486            ko.utils.registerEventHandler(element, "focus", function () { propertyChangedFired = false });
4487            ko.utils.registerEventHandler(element, "blur", function() {
4488                if (propertyChangedFired) {
4489                    valueUpdateHandler();
4490                }
4491            });
4492        }
4493
4494        ko.utils.arrayForEach(eventsToCatch, function(eventName) {
4495            // The syntax "after<eventname>" means "run the handler asynchronously after the event"
4496            // This is useful, for example, to catch "keydown" events after the browser has updated the control
4497            // (otherwise, ko.selectExtensions.readValue(this) will receive the control's value *before* the key event)
4498            var handler = valueUpdateHandler;
4499            if (ko.utils.stringStartsWith(eventName, "after")) {
4500                handler = function() {
4501                    // The elementValueBeforeEvent variable is non-null *only* during the brief gap between
4502                    // a keyX event firing and the valueUpdateHandler running, which is scheduled to happen
4503                    // at the earliest asynchronous opportunity. We store this temporary information so that
4504                    // if, between keyX and valueUpdateHandler, the underlying model value changes separately,
4505                    // we can overwrite that model value change with the value the user just typed. Otherwise,
4506                    // techniques like rateLimit can trigger model changes at critical moments that will
4507                    // override the user's inputs, causing keystrokes to be lost.
4508                    elementValueBeforeEvent = ko.selectExtensions.readValue(element);
4509                    setTimeout(valueUpdateHandler, 0);
4510                };
4511                eventName = eventName.substring("after".length);
4512            }
4513            ko.utils.registerEventHandler(element, eventName, handler);
4514        });
4515
4516        var updateFromModel = function () {
4517            var newValue = ko.utils.unwrapObservable(valueAccessor());
4518            var elementValue = ko.selectExtensions.readValue(element);
4519
4520            if (elementValueBeforeEvent !== null && newValue === elementValueBeforeEvent) {
4521                setTimeout(updateFromModel, 0);
4522                return;
4523            }
4524
4525            var valueHasChanged = (newValue !== elementValue);
4526
4527            if (valueHasChanged) {
4528                if (ko.utils.tagNameLower(element) === "select") {
4529                    var allowUnset = allBindings.get('valueAllowUnset');
4530                    var applyValueAction = function () {
4531                        ko.selectExtensions.writeValue(element, newValue, allowUnset);
4532                    };
4533                    applyValueAction();
4534
4535                    if (!allowUnset && newValue !== ko.selectExtensions.readValue(element)) {
4536                        // If you try to set a model value that can't be represented in an already-populated dropdown, reject that change,
4537                        // because you're not allowed to have a model value that disagrees with a visible UI selection.
4538                        ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, "change"]);
4539                    } else {
4540                        // Workaround for IE6 bug: It won't reliably apply values to SELECT nodes during the same execution thread
4541                        // right after you've changed the set of OPTION nodes on it. So for that node type, we'll schedule a second thread
4542                        // to apply the value as well.
4543                        setTimeout(applyValueAction, 0);
4544                    }
4545                } else {
4546                    ko.selectExtensions.writeValue(element, newValue);
4547                }
4548            }
4549        };
4550
4551        ko.computed(updateFromModel, null, { disposeWhenNodeIsRemoved: element });
4552    },
4553    'update': function() {} // Keep for backwards compatibility with code that may have wrapped value binding
4554};
4555ko.expressionRewriting.twoWayBindings['value'] = true;
4556ko.bindingHandlers['visible'] = {
4557    'update': function (element, valueAccessor) {
4558        var value = ko.utils.unwrapObservable(valueAccessor());
4559        var isCurrentlyVisible = !(element.style.display == "none");
4560        if (value && !isCurrentlyVisible)
4561            element.style.display = "";
4562        else if ((!value) && isCurrentlyVisible)
4563            element.style.display = "none";
4564    }
4565};
4566// 'click' is just a shorthand for the usual full-length event:{click:handler}
4567makeEventHandlerShortcut('click');
4568// If you want to make a custom template engine,
4569//
4570// [1] Inherit from this class (like ko.nativeTemplateEngine does)
4571// [2] Override 'renderTemplateSource', supplying a function with this signature:
4572//
4573//        function (templateSource, bindingContext, options) {
4574//            // - templateSource.text() is the text of the template you should render
4575//            // - bindingContext.$data is the data you should pass into the template
4576//            //   - you might also want to make bindingContext.$parent, bindingContext.$parents,
4577//            //     and bindingContext.$root available in the template too
4578//            // - options gives you access to any other properties set on "data-bind: { template: options }"
4579//            // - templateDocument is the document object of the template
4580//            //
4581//            // Return value: an array of DOM nodes
4582//        }
4583//
4584// [3] Override 'createJavaScriptEvaluatorBlock', supplying a function with this signature:
4585//
4586//        function (script) {
4587//            // Return value: Whatever syntax means "Evaluate the JavaScript statement 'script' and output the result"
4588//            //               For example, the jquery.tmpl template engine converts 'someScript' to '${ someScript }'
4589//        }
4590//
4591//     This is only necessary if you want to allow data-bind attributes to reference arbitrary template variables.
4592//     If you don't want to allow that, you can set the property 'allowTemplateRewriting' to false (like ko.nativeTemplateEngine does)
4593//     and then you don't need to override 'createJavaScriptEvaluatorBlock'.
4594
4595ko.templateEngine = function () { };
4596
4597ko.templateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options, templateDocument) {
4598    throw new Error("Override renderTemplateSource");
4599};
4600
vendor: 6,526 bytes, lines 4601-4715
4601ko.templateEngine.prototype['createJavaScriptEvaluatorBlock'] = function (script) {
4602    throw new Error("Override createJavaScriptEvaluatorBlock");
4603};
4604
4605ko.templateEngine.prototype['makeTemplateSource'] = function(template, templateDocument) {
4606    // Named template
4607    if (typeof template == "string") {
4608        templateDocument = templateDocument || document;
4609        var elem = templateDocument.getElementById(template);
4610        if (!elem)
4611            throw new Error("Cannot find template with ID " + template);
4612        return new ko.templateSources.domElement(elem);
4613    } else if ((template.nodeType == 1) || (template.nodeType == 8)) {
4614        // Anonymous template
4615        return new ko.templateSources.anonymousTemplate(template);
4616    } else
4617        throw new Error("Unknown template type: " + template);
4618};
4619
4620ko.templateEngine.prototype['renderTemplate'] = function (template, bindingContext, options, templateDocument) {
4621    var templateSource = this['makeTemplateSource'](template, templateDocument);
4622    return this['renderTemplateSource'](templateSource, bindingContext, options, templateDocument);
4623};
4624
4625ko.templateEngine.prototype['isTemplateRewritten'] = function (template, templateDocument) {
4626    // Skip rewriting if requested
4627    if (this['allowTemplateRewriting'] === false)
4628        return true;
4629    return this['makeTemplateSource'](template, templateDocument)['data']("isRewritten");
4630};
4631
4632ko.templateEngine.prototype['rewriteTemplate'] = function (template, rewriterCallback, templateDocument) {
4633    var templateSource = this['makeTemplateSource'](template, templateDocument);
4634    var rewritten = rewriterCallback(templateSource['text']());
4635    templateSource['text'](rewritten);
4636    templateSource['data']("isRewritten", true);
4637};
4638
4639ko.exportSymbol('templateEngine', ko.templateEngine);
4640
4641ko.templateRewriting = (function () {
4642    var memoizeDataBindingAttributeSyntaxRegex = /(<([a-z]+\d*)(?:\s+(?!data-bind\s*=\s*)[a-z0-9\-]+(?:=(?:\"[^\"]*\"|\'[^\']*\'|[^>]*))?)*\s+)data-bind\s*=\s*(["'])([\s\S]*?)\3/gi;
4643    var memoizeVirtualContainerBindingSyntaxRegex = /<!--\s*ko\b\s*([\s\S]*?)\s*-->/g;
4644
4645    function validateDataBindValuesForRewriting(keyValueArray) {
4646        var allValidators = ko.expressionRewriting.bindingRewriteValidators;
4647        for (var i = 0; i < keyValueArray.length; i++) {
4648            var key = keyValueArray[i]['key'];
4649            if (allValidators.hasOwnProperty(key)) {
4650                var validator = allValidators[key];
4651
4652                if (typeof validator === "function") {
4653                    var possibleErrorMessage = validator(keyValueArray[i]['value']);
4654                    if (possibleErrorMessage)
4655                        throw new Error(possibleErrorMessage);
4656                } else if (!validator) {
4657                    throw new Error("This template engine does not support the '" + key + "' binding within its templates");
4658                }
4659            }
4660        }
4661    }
4662
4663    function constructMemoizedTagReplacement(dataBindAttributeValue, tagToRetain, nodeName, templateEngine) {
4664        var dataBindKeyValueArray = ko.expressionRewriting.parseObjectLiteral(dataBindAttributeValue);
4665        validateDataBindValuesForRewriting(dataBindKeyValueArray);
4666        var rewrittenDataBindAttributeValue = ko.expressionRewriting.preProcessBindings(dataBindKeyValueArray, {'valueAccessors':true});
4667
4668        // For no obvious reason, Opera fails to evaluate rewrittenDataBindAttributeValue unless it's wrapped in an additional
4669        // anonymous function, even though Opera's built-in debugger can evaluate it anyway. No other browser requires this
4670        // extra indirection.
4671        var applyBindingsToNextSiblingScript =
4672            "ko.__tr_ambtns(function($context,$element){return(function(){return{ " + rewrittenDataBindAttributeValue + " } })()},'" + nodeName.toLowerCase() + "')";
4673        return templateEngine['createJavaScriptEvaluatorBlock'](applyBindingsToNextSiblingScript) + tagToRetain;
4674    }
4675
4676    return {
4677        ensureTemplateIsRewritten: function (template, templateEngine, templateDocument) {
4678            if (!templateEngine['isTemplateRewritten'](template, templateDocument))
4679                templateEngine['rewriteTemplate'](template, function (htmlString) {
4680                    return ko.templateRewriting.memoizeBindingAttributeSyntax(htmlString, templateEngine);
4681                }, templateDocument);
4682        },
4683
4684        memoizeBindingAttributeSyntax: function (htmlString, templateEngine) {
4685            return htmlString.replace(memoizeDataBindingAttributeSyntaxRegex, function () {
4686                return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[4], /* tagToRetain: */ arguments[1], /* nodeName: */ arguments[2], templateEngine);
4687            }).replace(memoizeVirtualContainerBindingSyntaxRegex, function() {
4688                return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[1], /* tagToRetain: */ "<!-- ko -->", /* nodeName: */ "#comment", templateEngine);
4689            });
4690        },
4691
4692        applyMemoizedBindingsToNextSibling: function (bindings, nodeName) {
4693            return ko.memoization.memoize(function (domNode, bindingContext) {
4694                var nodeToBind = domNode.nextSibling;
4695                if (nodeToBind && nodeToBind.nodeName.toLowerCase() === nodeName) {
4696                    ko.applyBindingAccessorsToNode(nodeToBind, bindings, bindingContext);
4697                }
4698            });
4699        }
4700    }
4701})();
4702
4703
4704// Exported only because it has to be referenced by string lookup from within rewritten template
4705ko.exportSymbol('__tr_ambtns', ko.templateRewriting.applyMemoizedBindingsToNextSibling);
4706(function() {
4707    // A template source represents a read/write way of accessing a template. This is to eliminate the need for template loading/saving
4708    // logic to be duplicated in every template engine (and means they can all work with anonymous templates, etc.)
4709    //
4710    // Two are provided by default:
4711    //  1. ko.templateSources.domElement       - reads/writes the text content of an arbitrary DOM element
4712    //  2. ko.templateSources.anonymousElement - uses ko.utils.domData to read/write text *associated* with the DOM element, but
4713    //                                           without reading/writing the actual element text content, since it will be overwritten
4714    //                                           with the rendered template output.
4715    // You can implement your own template source if you want to fetch/store templates somewhere other than 
4715in DOM elements.
4716    // Template sources need to have the following functions:
4717    //   text() 			- returns the template text from your storage location
4718    //   text(value)		- writes the supplied template text to your storage location
4719    //   data(key)			- reads values stored using data(key, value) - see below
4720    //   data(key, value)	- associates "value" with this template and the key "key". Is used to store information like "isRewritten".
4721    //
4722    // Optionally, template sources can also have the following functions:
4723    //   nodes()            - returns a DOM element containing the nodes of this template, where available
4724    //   nodes(value)       - writes the given DOM element to your storage location
4725    // If a DOM element is available for a given template source, template engines are encouraged to use it in preference over text()
4726    // for improved speed. However, all templateSources must supply text() even if they don't supply nodes().
4727    //
4728    // Once you've implemented a templateSource, make your template engine use it by subclassing whatever template engine you were
4729    // using and overriding "makeTemplateSource" to return an instance of your custom template source.
4730
4731    ko.templateSources = {};
4732
4733    // ---- ko.templateSources.domElement -----
4734
4735    ko.templateSources.domElement = function(element) {
4736        this.domElement = element;
4737    }
4738
4739    ko.templateSources.domElement.prototype['text'] = function(/* valueToWrite */) {
4740        var tagNameLower = ko.utils.tagNameLower(this.domElement),
4741            elemContentsProperty = tagNameLower === "script" ? "text"
4742                                 : tagNameLower === "textarea" ? "value"
4743                                 : "innerHTML";
4744
4745        if (arguments.length == 0) {
4746            return this.domElement[elemContentsProperty];
4747        } else {
4748            var valueToWrite = arguments[0];
4749            if (elemContentsProperty === "innerHTML")
4750                ko.utils.setHtml(this.domElement, valueToWrite);
4751            else
4752                this.domElement[elemContentsProperty] = valueToWrite;
4753        }
4754    };
4755
4756    var dataDomDataPrefix = ko.utils.domData.nextKey() + "_";
4757    ko.templateSources.domElement.prototype['data'] = function(key /*, valueToWrite */) {
4758        if (arguments.length === 1) {
4759            return ko.utils.domData.get(this.domElement, dataDomDataPrefix + key);
4760        } else {
4761            ko.utils.domData.set(this.domElement, dataDomDataPrefix + key, arguments[1]);
4762        }
4763    };
4764
4765    // ---- ko.templateSources.anonymousTemplate -----
4766    // Anonymous templates are normally saved/retrieved as DOM nodes through "nodes".
4767    // For compatibility, you can also read "text"; it will be serialized from the nodes on demand.
4768    // Writing to "text" is still supported, but then the template data will not be available as DOM nodes.
4769
4770    var anonymousTemplatesDomDataKey = ko.utils.domData.nextKey();
4771    ko.templateSources.anonymousTemplate = function(element) {
4772        this.domElement = element;
4773    }
4774    ko.templateSources.anonymousTemplate.prototype = new ko.templateSources.domElement();
4775    ko.templateSources.anonymousTemplate.prototype.constructor = ko.templateSources.anonymousTemplate;
4776    ko.templateSources.anonymousTemplate.prototype['text'] = function(/* valueToWrite */) {
4777        if (arguments.length == 0) {
4778            var templateData = ko.utils.domData.get(this.domElement, anonymousTemplatesDomDataKey) || {};
4779            if (templateData.textData === undefined && templateData.containerData)
4780                templateData.textData = templateData.containerData.innerHTML;
4781            return templateData.textData;
4782        } else {
4783            var valueToWrite = arguments[0];
4784            ko.utils.domData.set(this.domElement, anonymousTemplatesDomDataKey, {textData: valueToWrite});
4785        }
4786    };
4787    ko.templateSources.domElement.prototype['nodes'] = function(/* valueToWrite */) {
4788        if (arguments.length == 0) {
4789            var templateData = ko.utils.domData.get(this.domElement, anonymousTemplatesDomDataKey) || {};
4790            return templateData.containerData;
4791        } else {
4792            var valueToWrite = arguments[0];
4793            ko.utils.domData.set(this.domElement, anonymousTemplatesDomDataKey, {containerData: valueToWrite});
4794        }
4795    };
4796
4797    ko.exportSymbol('templateSources', ko.templateSources);
vendor: 9,813 bytes, lines 4798-4974
4798    ko.exportSymbol('templateSources.domElement', ko.templateSources.domElement);
4799    ko.exportSymbol('templateSources.anonymousTemplate', ko.templateSources.anonymousTemplate);
4800})();
4801(function () {
4802    var _templateEngine;
4803    ko.setTemplateEngine = function (templateEngine) {
4804        if ((templateEngine != undefined) && !(templateEngine instanceof ko.templateEngine))
4805            throw new Error("templateEngine must inherit from ko.templateEngine");
4806        _templateEngine = templateEngine;
4807    }
4808
4809    function invokeForEachNodeInContinuousRange(firstNode, lastNode, action) {
4810        var node, nextInQueue = firstNode, firstOutOfRangeNode = ko.virtualElements.nextSibling(lastNode);
4811        while (nextInQueue && ((node = nextInQueue) !== firstOutOfRangeNode)) {
4812            nextInQueue = ko.virtualElements.nextSibling(node);
4813            action(node, nextInQueue);
4814        }
4815    }
4816
4817    function activateBindingsOnContinuousNodeArray(continuousNodeArray, bindingContext) {
4818        // To be used on any nodes that have been rendered by a template and have been inserted into some parent element
4819        // Walks through continuousNodeArray (which *must* be continuous, i.e., an uninterrupted sequence of sibling nodes, because
4820        // the algorithm for walking them relies on this), and for each top-level item in the virtual-element sense,
4821        // (1) Does a regular "applyBindings" to associate bindingContext with this node and to activate any non-memoized bindings
4822        // (2) Unmemoizes any memos in the DOM subtree (e.g., to activate bindings that had been memoized during template rewriting)
4823
4824        if (continuousNodeArray.length) {
4825            var firstNode = continuousNodeArray[0],
4826                lastNode = continuousNodeArray[continuousNodeArray.length - 1],
4827                parentNode = firstNode.parentNode,
4828                provider = ko.bindingProvider['instance'],
4829                preprocessNode = provider['preprocessNode'];
4830
4831            if (preprocessNode) {
4832                invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node, nextNodeInRange) {
4833                    var nodePreviousSibling = node.previousSibling;
4834                    var newNodes = preprocessNode.call(provider, node);
4835                    if (newNodes) {
4836                        if (node === firstNode)
4837                            firstNode = newNodes[0] || nextNodeInRange;
4838                        if (node === lastNode)
4839                            lastNode = newNodes[newNodes.length - 1] || nodePreviousSibling;
4840                    }
4841                });
4842
4843                // Because preprocessNode can change the nodes, including the first and last nodes, update continuousNodeArray to match.
4844                // We need the full set, including inner nodes, because the unmemoize step might remove the first node (and so the real
4845                // first node needs to be in the array).
4846                continuousNodeArray.length = 0;
4847                if (!firstNode) { // preprocessNode might have removed all the nodes, in which case there's nothing left to do
4848                    return;
4849                }
4850                if (firstNode === lastNode) {
4851                    continuousNodeArray.push(firstNode);
4852                } else {
4853                    continuousNodeArray.push(firstNode, lastNode);
4854                    ko.utils.fixUpContinuousNodeArray(continuousNodeArray, parentNode);
4855                }
4856            }
4857
4858            // Need to applyBindings *before* unmemoziation, because unmemoization might introduce extra nodes (that we don't want to re-bind)
4859            // whereas a regular applyBindings won't introduce new memoized nodes
4860            invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node) {
4861                if (node.nodeType === 1 || node.nodeType === 8)
4862                    ko.applyBindings(bindingContext, node);
4863            });
4864            invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node) {
4865                if (node.nodeType === 1 || node.nodeType === 8)
4866                    ko.memoization.unmemoizeDomNodeAndDescendants(node, [bindingContext]);
4867            });
4868
4869            // Make sure any changes done by applyBindings or unmemoize are reflected in the array
4870            ko.utils.fixUpContinuousNodeArray(continuousNodeArray, parentNode);
4871        }
4872    }
4873
4874    function getFirstNodeFromPossibleArray(nodeOrNodeArray) {
4875        return nodeOrNodeArray.nodeType ? nodeOrNodeArray
4876                                        : nodeOrNodeArray.length > 0 ? nodeOrNodeArray[0]
4877                                        : null;
4878    }
4879
4880    function executeTemplate(targetNodeOrNodeArray, renderMode, template, bindingContext, options) {
4881        options = options || {};
4882        var firstTargetNode = targetNodeOrNodeArray && getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
4883        var templateDocument = (firstTargetNode || template || {}).ownerDocument;
4884        var templateEngineToUse = (options['templateEngine'] || _templateEngine);
4885        ko.templateRewriting.ensureTemplateIsRewritten(template, templateEngineToUse, templateDocument);
4886        var renderedNodesArray = templateEngineToUse['renderTemplate'](template, bindingContext, options, templateDocument);
4887
4888        // Loosely check result is an array of DOM nodes
4889        if ((typeof renderedNodesArray.length != "number") || (renderedNodesArray.length > 0 && typeof renderedNodesArray[0].nodeType != "number"))
4890            throw new Error("Template engine must return an array of DOM nodes");
4891
4892        var haveAddedNodesToParent = false;
4893        switch (renderMode) {
4894            case "replaceChildren":
4895                ko.virtualElements.setDomNodeChildren(targetNodeOrNodeArray, renderedNodesArray);
4896                haveAddedNodesToParent = true;
4897                break;
4898            case "replaceNode":
4899                ko.utils.replaceDomNodes(targetNodeOrNodeArray, renderedNodesArray);
4900                haveAddedNodesToParent = true;
4901                break;
4902            case "ignoreTargetNode": break;
4903            default:
4904                throw new Error("Unknown renderMode: " + renderMode);
4905        }
4906
4907        if (haveAddedNodesToParent) {
4908            activateBindingsOnContinuousNodeArray(renderedNodesArray, bindingContext);
4909            if (options['afterRender'])
4910                ko.dependencyDetection.ignore(options['afterRender'], null, [renderedNodesArray, bindingContext['$data']]);
4911        }
4912
4913        return renderedNodesArray;
4914    }
4915
4916    function resolveTemplateName(template, data, context) {
4917        // The template can be specified as:
4918        if (ko.isObservable(template)) {
4919            // 1. An observable, with string value
4920            return template();
4921        } else if (typeof template === 'function') {
4922            // 2. A function of (data, context) returning a string
4923            return template(data, context);
4924        } else {
4925            // 3. A string
4926            return template;
4927        }
4928    }
4929
4930    ko.renderTemplate = function (template, dataOrBindingContext, options, targetNodeOrNodeArray, renderMode) {
4931        options = options || {};
4932        if ((options['templateEngine'] || _templateEngine) == undefined)
4933            throw new Error("Set a template engine before calling renderTemplate");
4934        renderMode = renderMode || "replaceChildren";
4935
4936        if (targetNodeOrNodeArray) {
4937            var firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
4938
4939            var whenToDispose = function () { return (!firstTargetNode) || !ko.utils.domNodeIsAttachedToDocument(firstTargetNode); }; // Passive disposal (on next evaluation)
4940            var activelyDisposeWhenNodeIsRemoved = (firstTargetNode && renderMode == "replaceNode") ? firstTargetNode.parentNode : firstTargetNode;
4941
4942            return ko.dependentObservable( // So the DOM is automatically updated when any dependency changes
4943                function () {
4944                    // Ensure we've got a proper binding context to work with
4945                    var bindingContext = (dataOrBindingContext && (dataOrBindingContext instanceof ko.bindingContext))
4946                        ? dataOrBindingContext
4947                        : new ko.bindingContext(ko.utils.unwrapObservable(dataOrBindingContext));
4948
4949                    var templateName = resolveTemplateName(template, bindingContext['$data'], bindingContext),
4950                        renderedNodesArray = executeTemplate(targetNodeOrNodeArray, renderMode, templateName, bindingContext, options);
4951
4952                    if (renderMode == "replaceNode") {
4953                        targetNodeOrNodeArray = renderedNodesArray;
4954                        firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
4955                    }
4956                },
4957                null,
4958                { disposeWhen: whenToDispose, disposeWhenNodeIsRemoved: activelyDisposeWhenNodeIsRemoved }
4959            );
4960        } else {
4961            // 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
4962            return ko.memoization.memoize(function (domNode) {
4963                ko.renderTemplate(template, dataOrBindingContext, options, domNode, "replaceNode");
4964            });
4965        }
4966    };
4967
4968    ko.renderTemplateForEach = function (template, arrayOrObservableArray, options, targetNode, parentBindingContext) {
4969        // Since setDomNodeChildrenFromArrayMapping always calls executeTemplateForArrayItem and then
4970        // activateBindingsCallback for added items, we can store the binding context in the former to use in the latter.
4971        var arrayItemContext;
4972
4973        // This will be called by setDomNodeChildrenFromArrayMapping to get the nodes to add to targetNode
4974        var executeTemplateForArrayItem = function (arrayValue, index) {
4975            // Support selecting template as a function of the data being rendered
4976            arrayItemContext = parentBindingContext['createChildContext'](arrayValue, options['as'], function(context) {
4977                context['$index'] = index;
4978            });
4979
4980            var templateName = resolveTemplateName(template, arrayValue, arrayItemContext);
4981            return executeTemplate(null, "ignoreTargetNode", templateName, arrayItemContext, options);
4982        }
4983
4984        // This will be called whenever setDomNodeChildrenFromArrayMapping has added nodes to targetNode
4985        var activateBindingsCallback = function(arrayValue, addedNodesArray, index) {
4986            activateBindingsOnContinuousNodeArray(addedNodesArray, arrayItemContext);
4987            if (options['afterRender'])
4988                options['afterRender'](addedNodesArray, arrayValue);
4989
4990            // release the "cache" variable, so that it can be collected by
4991            // the GC when its value isn't used from within the bindings anymore.
4992            arrayItemContext = null;
4993        };
4994
4995        return ko.dependentObservable(function () {
4996            var unwrappedArray = ko.utils.unwrapObservable(arrayOrObservableArray) || [];
4997            if (typeof unwrappedArray.length == "undefined") // Coerce single value into array
4998                unwrappedArray = [unwrappedArray];
4999
5000            // Filter out any entries marked as destroyed
5001            var filteredArray = ko.utils.arrayFilter(unwrappedArray, function(item) {
5002                return options['includeDestroyed'] || item === undefined || item === null || !ko.utils.unwrapObservable(item['_destroy']);
5003            });
5004
5005            // Call setDomNodeChildrenFromArrayMapping, ignoring any observables unwrapped within (most likely from a callback function).
5006            // If the array items are observables, though, they will be unwrapped in executeTemplateForArrayItem and managed within setDomNodeChildrenFromArrayMapping.
5007            ko.dependencyDetection.ignore(ko.utils.setDomNodeChildrenFromArrayMapping, null, [targetNode, filteredArray, executeTemplateForArrayItem, options, activateBindingsCallback]);
5008
5009        }, null, { disposeWhenNodeIsRemoved: targetNode });
5010    };
5011
5012    var templateComputedDomDataKey = ko.utils.domData.nextKey();
5013    function disposeOldComputedAndStoreNewOne(element, newComputed) {
5014        var oldComputed = ko.utils.domData.get(element, templateComputedDomDataKey);
5015        if (oldComputed && (typeof(oldComputed.dispose) == 'function'))
5016            oldComputed.dispose();
5017        ko.utils.domData.set(element, templateComputedDomDataKey, (newComputed && newComputed.isActive()) ? newComputed : undefined);
5018    }
5019
5020    ko.bindingHandlers['template'] = {
5021        'init': function(element, valueAccessor) {
5022            // Support anonymous templates
5023            var bindingValue = ko.utils.unwrapObservable(valueAccessor());
5024            if (typeof bindingValue == "string" || bindingValue['name']) {
5025                // It's a named template - clear the element
5026                ko.virtualElements.emptyNode(element);
5027            } else if ('nodes' in bindingValue) {
5028                // We've been given an array of DOM nodes. Save them as the template source.
5029                // There is no known use case for the node array being an observable array (if the output
5030                // varies, put that behavior *into* your template - that's what templates are for), and
5031                // the implementation would be a mess, so assert that it's not observable.
5032                var nodes = bindingValue['nodes'] || [];
5033                if (ko.isObservable(nodes)) {
5034                    throw new Error('The "nodes" option must be a plain, non-observable array.');
5035                }
5036                var container = ko.utils.moveCleanedNodesToContainerElement(nodes);
vendor: 10,685 bytes, lines 5036-5231
5036 // This also removes the nodes from their current parent
5037                new ko.templateSources.anonymousTemplate(element)['nodes'](container);
5038            } else {
5039                // It's an anonymous template - store the element contents, then clear the element
5040                var templateNodes = ko.virtualElements.childNodes(element),
5041                    container = ko.utils.moveCleanedNodesToContainerElement(templateNodes); // This also removes the nodes from their current parent
5042                new ko.templateSources.anonymousTemplate(element)['nodes'](container);
5043            }
5044            return { 'controlsDescendantBindings': true };
5045        },
5046        'update': function (element, valueAccessor, allBindings, viewModel, bindingContext) {
5047            var value = valueAccessor(),
5048                dataValue,
5049                options = ko.utils.unwrapObservable(value),
5050                shouldDisplay = true,
5051                templateComputed = null,
5052                templateName;
5053
5054            if (typeof options == "string") {
5055                templateName = value;
5056                options = {};
5057            } else {
5058                templateName = options['name'];
5059
5060                // Support "if"/"ifnot" conditions
5061                if ('if' in options)
5062                    shouldDisplay = ko.utils.unwrapObservable(options['if']);
5063                if (shouldDisplay && 'ifnot' in options)
5064                    shouldDisplay = !ko.utils.unwrapObservable(options['ifnot']);
5065
5066                dataValue = ko.utils.unwrapObservable(options['data']);
5067            }
5068
5069            if ('foreach' in options) {
5070                // Render once for each data point (treating data set as empty if shouldDisplay==false)
5071                var dataArray = (shouldDisplay && options['foreach']) || [];
5072                templateComputed = ko.renderTemplateForEach(templateName || element, dataArray, options, element, bindingContext);
5073            } else if (!shouldDisplay) {
5074                ko.virtualElements.emptyNode(element);
5075            } else {
5076                // Render once for this single data point (or use the viewModel if no data was provided)
5077                var innerBindingContext = ('data' in options) ?
5078                    bindingContext['createChildContext'](dataValue, options['as']) :  // Given an explitit 'data' value, we create a child binding context for it
5079                    bindingContext;                                                        // Given no explicit 'data' value, we retain the same binding context
5080                templateComputed = ko.renderTemplate(templateName || element, innerBindingContext, options, element);
5081            }
5082
5083            // It only makes sense to have a single template computed per element (otherwise which one should have its output displayed?)
5084            disposeOldComputedAndStoreNewOne(element, templateComputed);
5085        }
5086    };
5087
5088    // Anonymous templates can't be rewritten. Give a nice error message if you try to do it.
5089    ko.expressionRewriting.bindingRewriteValidators['template'] = function(bindingValue) {
5090        var parsedBindingValue = ko.expressionRewriting.parseObjectLiteral(bindingValue);
5091
5092        if ((parsedBindingValue.length == 1) && parsedBindingValue[0]['unknown'])
5093            return null; // It looks like a string literal, not an object literal, so treat it as a named template (which is allowed for rewriting)
5094
5095        if (ko.expressionRewriting.keyValueArrayContainsKey(parsedBindingValue, "name"))
5096            return null; // Named templates can be rewritten, so return "no error"
5097        return "This template engine does not support anonymous templates nested within its templates";
5098    };
5099
5100    ko.virtualElements.allowedBindings['template'] = true;
5101})();
5102
5103ko.exportSymbol('setTemplateEngine', ko.setTemplateEngine);
5104ko.exportSymbol('renderTemplate', ko.renderTemplate);
5105// Go through the items that have been added and deleted and try to find matches between them.
5106ko.utils.findMovesInArrayComparison = function (left, right, limitFailedCompares) {
5107    if (left.length && right.length) {
5108        var failedCompares, l, r, leftItem, rightItem;
5109        for (failedCompares = l = 0; (!limitFailedCompares || failedCompares < limitFailedCompares) && (leftItem = left[l]); ++l) {
5110            for (r = 0; rightItem = right[r]; ++r) {
5111                if (leftItem['value'] === rightItem['value']) {
5112                    leftItem['moved'] = rightItem['index'];
5113                    rightItem['moved'] = leftItem['index'];
5114                    right.splice(r, 1);         // This item is marked as moved; so remove it from right list
5115                    failedCompares = r = 0;     // Reset failed compares count because we're checking for consecutive failures
5116                    break;
5117                }
5118            }
5119            failedCompares += r;
5120        }
5121    }
5122};
5123
5124ko.utils.compareArrays = (function () {
5125    var statusNotInOld = 'added', statusNotInNew = 'deleted';
5126
5127    // Simple calculation based on Levenshtein distance.
5128    function compareArrays(oldArray, newArray, options) {
5129        // For backward compatibility, if the third arg is actually a bool, interpret
5130        // it as the old parameter 'dontLimitMoves'. Newer code should use { dontLimitMoves: true }.
5131        options = (typeof options === 'boolean') ? { 'dontLimitMoves': options } : (options || {});
5132        oldArray = oldArray || [];
5133        newArray = newArray || [];
5134
5135        if (oldArray.length <= newArray.length)
5136            return compareSmallArrayToBigArray(oldArray, newArray, statusNotInOld, statusNotInNew, options);
5137        else
5138            return compareSmallArrayToBigArray(newArray, oldArray, statusNotInNew, statusNotInOld, options);
5139    }
5140
5141    function compareSmallArrayToBigArray(smlArray, bigArray, statusNotInSml, statusNotInBig, options) {
5142        var myMin = Math.min,
5143            myMax = Math.max,
5144            editDistanceMatrix = [],
5145            smlIndex, smlIndexMax = smlArray.length,
5146            bigIndex, bigIndexMax = bigArray.length,
5147            compareRange = (bigIndexMax - smlIndexMax) || 1,
5148            maxDistance = smlIndexMax + bigIndexMax + 1,
5149            thisRow, lastRow,
5150            bigIndexMaxForRow, bigIndexMinForRow;
5151
5152        for (smlIndex = 0; smlIndex <= smlIndexMax; smlIndex++) {
5153            lastRow = thisRow;
5154            editDistanceMatrix.push(thisRow = []);
5155            bigIndexMaxForRow = myMin(bigIndexMax, smlIndex + compareRange);
5156            bigIndexMinForRow = myMax(0, smlIndex - 1);
5157            for (bigIndex = bigIndexMinForRow; bigIndex <= bigIndexMaxForRow; bigIndex++) {
5158                if (!bigIndex)
5159                    thisRow[bigIndex] = smlIndex + 1;
5160                else if (!smlIndex)  // Top row - transform empty array into new array via additions
5161                    thisRow[bigIndex] = bigIndex + 1;
5162                else if (smlArray[smlIndex - 1] === bigArray[bigIndex - 1])
5163                    thisRow[bigIndex] = lastRow[bigIndex - 1];                  // copy value (no edit)
5164                else {
5165                    var northDistance = lastRow[bigIndex] || maxDistance;       // not in big (deletion)
5166                    var westDistance = thisRow[bigIndex - 1] || maxDistance;    // not in small (addition)
5167                    thisRow[bigIndex] = myMin(northDistance, westDistance) + 1;
5168                }
5169            }
5170        }
5171
5172        var editScript = [], meMinusOne, notInSml = [], notInBig = [];
5173        for (smlIndex = smlIndexMax, bigIndex = bigIndexMax; smlIndex || bigIndex;) {
5174            meMinusOne = editDistanceMatrix[smlIndex][bigIndex] - 1;
5175            if (bigIndex && meMinusOne === editDistanceMatrix[smlIndex][bigIndex-1]) {
5176                notInSml.push(editScript[editScript.length] = {     // added
5177                    'status': statusNotInSml,
5178                    'value': bigArray[--bigIndex],
5179                    'index': bigIndex });
5180            } else if (smlIndex && meMinusOne === editDistanceMatrix[smlIndex - 1][bigIndex]) {
5181                notInBig.push(editScript[editScript.length] = {     // deleted
5182                    'status': statusNotInBig,
5183                    'value': smlArray[--smlIndex],
5184                    'index': smlIndex });
5185            } else {
5186                --bigIndex;
5187                --smlIndex;
5188                if (!options['sparse']) {
5189                    editScript.push({
5190                        'status': "retained",
5191                        'value': bigArray[bigIndex] });
5192                }
5193            }
5194        }
5195
5196        // Set a limit on the number of consecutive non-matching comparisons; having it a multiple of
5197        // smlIndexMax keeps the time complexity of this algorithm linear.
5198        ko.utils.findMovesInArrayComparison(notInSml, notInBig, smlIndexMax * 10);
5199
5200        return editScript.reverse();
5201    }
5202
5203    return compareArrays;
5204})();
5205
5206ko.exportSymbol('utils.compareArrays', ko.utils.compareArrays);
5207(function () {
5208    // Objective:
5209    // * Given an input array, a container DOM node, and a function from array elements to arrays of DOM nodes,
5210    //   map the array elements to arrays of DOM nodes, concatenate together all these arrays, and use them to populate the container DOM node
5211    // * Next time we're given the same combination of things (with the array possibly having mutated), update the container DOM node
5212    //   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
5213    //   previously mapped - retain those nodes, and just insert/delete other ones
5214
5215    // "callbackAfterAddingNodes" will be invoked after any "mapping"-generated nodes are inserted into the container node
5216    // You can use this, for example, to activate bindings on those nodes.
5217
5218    function mapNodeAndRefreshWhenChanged(containerNode, mapping, valueToMap, callbackAfterAddingNodes, index) {
5219        // Map this array value inside a dependentObservable so we re-map when any dependency changes
5220        var mappedNodes = [];
5221        var dependentObservable = ko.dependentObservable(function() {
5222            var newMappedNodes = mapping(valueToMap, index, ko.utils.fixUpContinuousNodeArray(mappedNodes, containerNode)) || [];
5223
5224            // On subsequent evaluations, just replace the previously-inserted DOM nodes
5225            if (mappedNodes.length > 0) {
5226                ko.utils.replaceDomNodes(mappedNodes, newMappedNodes);
5227                if (callbackAfterAddingNodes)
5228                    ko.dependencyDetection.ignore(callbackAfterAddingNodes, null, [valueToMap, newMappedNodes, index]);
5229            }
5230
5231            // Replace the contents of the mappedNodes array, thereby updating the record
5232            // of which nodes would be deleted if valueToMap was itself later removed
5233            mappedNodes.length = 0;
5234            ko.utils.arrayPushAll(mappedNodes, newMappedNodes);
5235        }, null, { disposeWhenNodeIsRemoved: containerNode, disposeWhen: function() { return !ko.utils.anyDomNodeIsAttachedToDocument(mappedNodes); } });
5236        return { mappedNodes : mappedNodes, dependentObservable : (dependentObservable.isActive() ? dependentObservable : undefined) };
5237    }
5238
5239    var lastMappingResultDomDataKey = ko.utils.domData.nextKey();
5240
5241    ko.utils.setDomNodeChildrenFromArrayMapping = function (domNode, array, mapping, options, callbackAfterAddingNodes) {
5242        // Compare the provided array against the previous one
5243        array = array || [];
5244        options = options || {};
5245        var isFirstExecution = ko.utils.domData.get(domNode, lastMappingResultDomDataKey) === undefined;
5246        var lastMappingResult = ko.utils.domData.get(domNode, lastMappingResultDomDataKey) || [];
5247        var lastArray = ko.utils.arrayMap(lastMappingResult, function (x) { return x.arrayEntry; });
5248        var editScript = ko.utils.compareArrays(lastArray, array, options['dontLimitMoves']);
5249
5250        // Build the new mapping result
5251        var newMappingResult = [];
5252        var lastMappingResultIndex = 0;
5253        var newMappingResultIndex = 0;
5254
5255        var nodesToDelete = [];
5256        var itemsToProcess = [];
5257        var itemsForBeforeRemoveCallbacks = [];
5258        var itemsForMoveCallbacks = [];
5259        var itemsForAfterAddCallbacks = [];
5260        var mapData;
5261
5262        function itemMovedOrRetained(editScriptIndex, oldPosition) {
5263            mapData = lastMappingResult[oldPosition];
5264            if (newMappingResultIndex !== oldPosition)
5265                itemsForMoveCallbacks[editScriptIndex] = mapData;
5266            // Since updating the index might change the nodes, do so before calling fixUpContinuousNodeArray
5267            mapData.indexObservable(newMappingResultIndex++);
5268            ko.utils.fixUpContinuousNodeArray(mapData.mappedNodes, domNode);
5269            newMappingResult.push(mapData);
5270            itemsToProcess.push(mapData);
5271        }
5272
5273        function callCallback(callback, items) {
5274            if (callback) {
5275                for (var i = 0, n = items.length; i < n; i++) {
5276                    if (items[i]) {
5277                        ko.utils.arrayForEach(items[i].mappedNodes, function(node) {
5278                            callback(node, i, items[i].arrayEntry);
5279                        });
5280                    }
5281                }
5282            }
5283        }
5284
5285        for (var i = 0, editScriptItem, movedIndex; editScriptItem = editScript[i]; i++) {
5286            movedIndex = editScriptItem['moved'];
5287            switch (editScriptItem['status']) {
5288                case "deleted":
5289                    if (movedIndex === undefined) {
5290                        mapData = lastMappingResult[lastMappingResultIndex];
5291
5292                        // Stop tracking changes to the mapping for these nodes
5293                        if (mapData.dependentObservable)
5294                            mapData.dependentObservable.dispose();
5295
5296                        // Queue these nodes for later removal
5297                        nodesToDelete.push.apply(nodesToDelete, ko.utils.fixUpContinuousNodeArray(mapData.mappedNodes, domNode));
5298                        if (options['beforeRemove']) {
5299                            itemsForBeforeRemoveCallbacks[i] = mapData;
5300                            itemsToProcess.push(mapData);
5301                        }
5302                    }
5303                    lastMappingResultIndex++;
5304                    break;
5305
5306                case "retained":
5307                    itemMovedOrRetained(i, lastMappingResultIndex++);
5308                    break;
5309
5310                case "added":
5311                    if (movedIndex !== undefined) {
5312                        itemMovedOrRetained(i, movedIndex);
5313                    } else {
5314                        mapData = { arrayEntry: editScriptItem['value'], indexObservable: ko.observable(newMappingResultIndex++) };
5315                        newMappingResult.push(mapData);
5316                        itemsToProcess.push(mapData);
5317                        if (!isFirstExecution)
5318                            itemsForAfterAddCallbacks[i] = mapData;
5319                    }
5320                    break;
5321            }
5322        }
5323
5324        // Call beforeMove first before any changes have been made to the DOM
5325        callCallback(options['beforeMove'], itemsForMoveCallbacks);
5326
5327        // Next remove nodes for deleted items (or just clean if there's a beforeRemove callback)
5328        ko.utils.arrayForEach(nodesToDelete, options['beforeRemove'] ? ko.cleanNode : ko.removeNode);
5329
5330        // Next add/reorder the remaining items (will include deleted items if there's a beforeRemove callback)
5331        for (var i = 0, nextNode = ko.virtualElements.firstChild(domNode), lastNode, node; mapData = itemsToProcess[i]; i++) {
5332            // Get nodes for newly added items
5333            if (!mapData.mappedNodes)
5334                ko.utils.extend(mapData, mapNodeAndRefreshWhenChanged(domNode, mapping, mapData.arrayEntry, callbackAfterAddingNodes, mapData.indexObservable));
5335
5336            // Put nodes in the right place if they aren't there already
5337            for (var j = 0; node = mapData.mappedNodes[j]; nextNode = node.nextSibling, lastNode = node, j++) {
5338                if (node !== nextNode)
5339                    ko.virtualElements.insertAfter(domNode, node, lastNode);
5340            }
5341
5342            // Run the callbacks for newly added nodes (for example, to apply bindings, etc.)
5343            if (!mapData.initialized && callbackAfterAddingNodes) {
5344                callbackAfterAddingNodes(mapData.arrayEntry, mapData.mappedNodes, mapData.indexObservable);
5345                mapData.initialized = true;
5346            }
5347        }
5348
5349        // If there's a beforeRemove callback, call it after reordering.
5350        // Note that we assume that the beforeRemove callback will usually be used to remove the nodes using
5351        // some sort of animation, which is why we first reorder the nodes that will be removed. If the
5352        // callback instead removes the nodes right away, it would be more efficient to skip reordering them.
5353        // Perhaps we'll make that change in the future if this scenario becomes more common.
5354        callCallback(options['beforeRemove'], itemsForBeforeRemoveCallbacks);
5355
5356        // Finally call afterMove and afterAdd callbacks
5357        callCallback(options['afterMove'], itemsForMoveCallbacks);
5358        callCallback(options['afterAdd'], itemsForAfterAddCallbacks);
5359
5360        // Store a copy of the array items we just considered so we can difference it next time
5361        ko.utils.domData.set(domNode, lastMappingResultDomDataKey, newMappingResult
vendor: 5,512 bytes, lines 5361-5475
5361);
5362    }
5363})();
5364
5365ko.exportSymbol('utils.setDomNodeChildrenFromArrayMapping', ko.utils.setDomNodeChildrenFromArrayMapping);
5366ko.nativeTemplateEngine = function () {
5367    this['allowTemplateRewriting'] = false;
5368}
5369
5370ko.nativeTemplateEngine.prototype = new ko.templateEngine();
5371ko.nativeTemplateEngine.prototype.constructor = ko.nativeTemplateEngine;
5372ko.nativeTemplateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options, templateDocument) {
5373    var useNodesIfAvailable = !(ko.utils.ieVersion < 9), // IE<9 cloneNode doesn't work properly
5374        templateNodesFunc = useNodesIfAvailable ? templateSource['nodes'] : null,
5375        templateNodes = templateNodesFunc ? templateSource['nodes']() : null;
5376
5377    if (templateNodes) {
5378        return ko.utils.makeArray(templateNodes.cloneNode(true).childNodes);
5379    } else {
5380        var templateText = templateSource['text']();
5381        return ko.utils.parseHtmlFragment(templateText, templateDocument);
5382    }
5383};
5384
5385ko.nativeTemplateEngine.instance = new ko.nativeTemplateEngine();
5386ko.setTemplateEngine(ko.nativeTemplateEngine.instance);
5387
5388ko.exportSymbol('nativeTemplateEngine', ko.nativeTemplateEngine);
5389(function() {
5390    ko.jqueryTmplTemplateEngine = function () {
5391        // Detect which version of jquery-tmpl you're using. Unfortunately jquery-tmpl
5392        // doesn't expose a version number, so we have to infer it.
5393        // Note that as of Knockout 1.3, we only support jQuery.tmpl 1.0.0pre and later,
5394        // which KO internally refers to as version "2", so older versions are no longer detected.
5395        var jQueryTmplVersion = this.jQueryTmplVersion = (function() {
5396            if (!jQueryInstance || !(jQueryInstance['tmpl']))
5397                return 0;
5398            // Since it exposes no official version number, we use our own numbering system. To be updated as jquery-tmpl evolves.
5399            try {
5400                if (jQueryInstance['tmpl']['tag']['tmpl']['open'].toString().indexOf('__') >= 0) {
5401                    // Since 1.0.0pre, custom tags should append markup to an array called "__"
5402                    return 2; // Final version of jquery.tmpl
5403                }
5404            } catch(ex) { /* Apparently not the version we were looking for */ }
5405
5406            return 1; // Any older version that we don't support
5407        })();
5408
5409        function ensureHasReferencedJQueryTemplates() {
5410            if (jQueryTmplVersion < 2)
5411                throw new Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");
5412        }
5413
5414        function executeTemplate(compiledTemplate, data, jQueryTemplateOptions) {
5415            return jQueryInstance['tmpl'](compiledTemplate, data, jQueryTemplateOptions);
5416        }
5417
5418        this['renderTemplateSource'] = function(templateSource, bindingContext, options, templateDocument) {
5419            templateDocument = templateDocument || document;
5420            options = options || {};
5421            ensureHasReferencedJQueryTemplates();
5422
5423            // Ensure we have stored a precompiled version of this template (don't want to reparse on every render)
5424            var precompiled = templateSource['data']('precompiled');
5425            if (!precompiled) {
5426                var templateText = templateSource['text']() || "";
5427                // Wrap in "with($whatever.koBindingContext) { ... }"
5428                templateText = "{{ko_with $item.koBindingContext}}" + templateText + "{{/ko_with}}";
5429
5430                precompiled = jQueryInstance['template'](null, templateText);
5431                templateSource['data']('precompiled', precompiled);
5432            }
5433
5434            var data = [bindingContext['$data']]; // Prewrap the data in an array to stop jquery.tmpl from trying to unwrap any arrays
5435            var jQueryTemplateOptions = jQueryInstance['extend']({ 'koBindingContext': bindingContext }, options['templateOptions']);
5436
5437            var resultNodes = executeTemplate(precompiled, data, jQueryTemplateOptions);
5438            resultNodes['appendTo'](templateDocument.createElement("div")); // Using "appendTo" forces jQuery/jQuery.tmpl to perform necessary cleanup work
5439
5440            jQueryInstance['fragments'] = {}; // Clear jQuery's fragment cache to avoid a memory leak after a large number of template renders
5441            return resultNodes;
5442        };
5443
5444        this['createJavaScriptEvaluatorBlock'] = function(script) {
5445            return "{{ko_code ((function() { return " + script + " })()) }}";
5446        };
5447
5448        this['addTemplate'] = function(templateName, templateMarkup) {
5449            document.write("<script type='text/html' id='" + templateName + "'>" + templateMarkup + "<" + "/script>");
5450        };
5451
5452        if (jQueryTmplVersion > 0) {
5453            jQueryInstance['tmpl']['tag']['ko_code'] = {
5454                open: "__.push($1 || '');"
5455            };
5456            jQueryInstance['tmpl']['tag']['ko_with'] = {
5457                open: "with($1) {",
5458                close: "} "
5459            };
5460        }
5461    };
5462
5463    ko.jqueryTmplTemplateEngine.prototype = new ko.templateEngine();
5464    ko.jqueryTmplTemplateEngine.prototype.constructor = ko.jqueryTmplTemplateEngine;
5465
5466    // Use this one by default *only if jquery.tmpl is referenced*
5467    var jqueryTmplTemplateEngineInstance = new ko.jqueryTmplTemplateEngine();
5468    if (jqueryTmplTemplateEngineInstance.jQueryTmplVersion > 0)
5469        ko.setTemplateEngine(jqueryTmplTemplateEngineInstance);
5470
5471    ko.exportSymbol('jqueryTmplTemplateEngine', ko.jqueryTmplTemplateEngine);
5472})();
5473}));
5474}());
5475})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.