<commit_before>// knockout-arrayTransforms 0.3.0 (https://github.com/mwiencek/knockout-arrayTransforms)
// Released under the MIT (X11) License; see the LICENSE file in the official code repository.

(function (factory) {
    if (typeof module !== "undefined" && typeof module.exports !== "undefined") {
        factory(module.exports = require("knockout"));
    } else if (typeof define === "function" && define.amd) {
        define(["knockout"], factory);
    } else {
        factory(window.ko);
    }
})(function (ko) {

    var transformClasses = emptyObject();

    function applyChanges(changes) {
        var mappedItems = this.mappedItems,
            moves = emptyObject(),
            offset = 0;

        for (var i = 0, change; change = changes[i]; i++) {
            var status = change.status;

            if (status === "retained") {
                continue;
            }

            var index = change.index,
                moved = change.moved,
                value = change.value,
                item = change.mappedItem;

            if (moved !== undefined) {
                // For added statuses, index is a position in the new
                // array and moved is a position in the old array. For
                // deleted statuses, it's the opposite.
                if (status === "added") {
                    var to = index, from = moved + offset;

                } else if (status === "deleted") {
                    var to = moved, from = index + offset;
                }

                if (moves[to] === undefined) {
                    moves[to] = true;
                    item = mappedItems[from];
                    mappedItems.splice(from, 1)
                    mappedItems.splice(to, 0, item);
                    movedIndex(mappedItems, "index", to, from);
                    this.valueMoved(value, to, from, item.mappedValue, item);
                }
            }

            if (status === "added") {
                if (moved === undefined) {
                    item = emptyObject();
                    item.index = index;
                    item.value = value;
                    mapValue(this, item);
                    mappedItems.splice(index, 0, item);
                    addedIndex(mappedItems, "index", index);
                    this.valueAdded(value, index, item.mappedValue, item);
                }
                offset++;

            } else if (status === "deleted") {
                if (moved === undefined) {
                    item = mappedItems.splice(index + offset, 1)[0];
                    if (item.computed) {
                        item.computed.dispose();
                    }
                    deletedIndex(mappedItems, "index", index + offset);
                    this.valueDeleted(value, index + offset, item.mappedValue, item);
                }
                offset--;
            }
        }
    };

    function updateIndex(items, prop, start, end, offset) {
        while (start <= end) {
            items[start++][prop] += offset;
        }
    }

    function addedIndex(array, prop, index) {
        updateIndex(array, prop, index + 1, array.length - 1, 1);
    }

    function deletedIndex(array, prop, index) {
        updateIndex(array, prop, index, array.length - 1, -1);
    }

    function movedIndex(array, prop, to, from) {
        if (to > from) {
            updateIndex(array, prop, from, to - 1, -1);
        } else {
            updateIndex(array, prop, to + 1, from, 1);
        }
    }

    function emptyObject() {
        return Object.create ? Object.create(null) : {};
    }

    function exactlyEqual(a, b) { return a === b }

    function mapValue(state, item) {
        var callback = state.callback;

        if (callback === undefined) {
            item.mappedValue = item.value;
            return;
        }

        var owner = state, method = "callback";

        if (typeof callback !== "function") {
            owner = item.value;
            method = callback;
            callback = owner[method];

            if (typeof callback !== "function") {
                item.mappedValue = callback;
                return;

            } else if (ko.isObservable(callback)) {
                watchItem(state, item, callback);
                return;
            }
        }

        var computedValue = ko.computed(function () {
            return owner[method](item.value, item.index);
        });

        if (computedValue.isActive()) {
            computedValue.equalityComparer = exactlyEqual;
            watchItem(state, item, computedValue);
            return computedValue;
        } else {
            item.mappedValue = computedValue.peek();
        }
    }

    function watchItem(self, item, observable) {
        item.mappedValue = observable.peek();

        observable.subscribe(function (newValue) {
            var oldValue = item.mappedValue;
            item.mappedValue = newValue;
            self.valueMutated(item.value, newValue, oldValue, item);
        });
    }

    function makeTransform(proto) {
        function TransformState(original, callback, options) {
            this.original = original;
            this.mappedItems = [];
            this.callback = callback;

            var transform = this.transform = this.init(options);
            if (ko.isObservable(transform) && transform.cacheDiffForKnownOperation) {
                this.transformedArray = transform.peek();
            }
        }

        TransformState.prototype.applyChanges = applyChanges;
        ko.utils.extend(TransformState.prototype, proto);
        transformClasses[proto.name] = TransformState;

        ko.observableArray.fn[proto.name] = function (callback, options) {
            var state = new TransformState(this, callback, options),
                originalArray = this.peek(),
                initialChanges = [];

            this.subscribe(function (changes) {
                state.applyChanges(changes);
            }, null, "arrayChange");

            for (var i = 0, len = originalArray.length; i < len; i++) {
                initialChanges.push({ status: "added", value: originalArray[i], index: i });
            }

            state.applyChanges(initialChanges);
            return state.transform;
        };
    };

    makeTransform({
        name: "sortBy",
        init: function () {
            this.keyCounts = emptyObject();
            this.sortedItems = [];
            return ko.observableArray([]);
        },
        valueAdded: function (value, index, sortKey, item) {
            var mappedIndex = this.sortedIndexOf(sortKey, value, item),
                sortedItems = this.sortedItems,
                keyCounts = this.keyCounts;

            item.mappedIndex = mappedIndex;
            sortedItems.splice(mappedIndex, 0, item);
            addedIndex(sortedItems, "mappedIndex", mappedIndex);
            keyCounts[sortKey] = (keyCounts[sortKey] + 1) || 1;
            this.transform.splice(mappedIndex, 0, value);
        },
        valueDeleted: function (value, index, sortKey, item) {
            var mappedIndex = item.mappedIndex,
                sortedItems = this.sortedItems;

            sortedItems.splice(mappedIndex, 1);
            deletedIndex(sortedItems, "mappedIndex", mappedIndex);
            this.keyCounts[sortKey]--;
            this.transform.splice(mappedIndex, 1);
        },
        valueMoved: function (value, to, from, sortKey, item) {
            var oldIndex = item.mappedIndex,
                newIndex = this.sortedIndexOf(sortKey, value, item);

            if (oldIndex !== newIndex) {
                this.moveValue(value, sortKey, oldIndex, newIndex, item);
            }
        },
        valueMutated: function (value, newKey, oldKey, item) {
            // Revert to the old key temporarily, since it's already sorted,
            // otherwise the binary search won't work
            item.mappedValue = oldKey;

            var oldIndex = item.mappedIndex,
                newIndex = this.sortedIndexOf(newKey, value, item);

            item.mappedValue = newKey;

            if (oldIndex !== newIndex) {
                this.moveValue(value, newKey, oldIndex, newIndex, item, true);

                var keyCounts = this.keyCounts;
                keyCounts[oldKey]--;
                keyCounts[newKey] = (keyCounts[newKey] + 1) || 1;
            }
        },
        moveValue: function (value, sortKey, oldIndex, newIndex, item, isMutation) {
            var sortedItems = this.sortedItems;

            sortedItems.splice(oldIndex, 1);
            this.transform.splice(oldIndex, 1);

            // If we're here because of a move in the original array, rather
            // than a mutated value, then the mappedItems array has already
            // been reordered, thus newIndex is correctly adjusted.
            if (isMutation && oldIndex < newIndex) {
                newIndex--;
            }

            item.mappedIndex = newIndex;
            sortedItems.splice(newIndex, 0, item);

            movedIndex(sortedItems, "mappedIndex", newIndex, oldIndex);
            this.transform.splice(newIndex, 0, value);
        },
        sortedIndexOf: function (key, value, item) {
            var sortedItems = this.sortedItems,
                length = sortedItems.length;

            if (length === 0) {
                return 0;
            }

            var start = 0, end = length - 1, index;

            while (start <= end) {
                index = (start + end) >> 1;

                if (sortedItems[index].mappedValue < key) {
                    start = index + 1;
                } else {
                    end = index;
                    if (start === end) {
                        break;
                    }
                }
            }

            // Keep things stably sorted. Only incurs a cost if there are
            // multiple of this key.
            var count = this.keyCounts[key], offset = 0;

            if (count) {
                var mappedItems = this.mappedItems;

                for (var i = 0; i < length; i++) {
                    if (mappedItems[i] === item) {
                        break;
                    }
                    if (mappedItems[i].mappedValue === key) {
                        offset++;
                    }
                    if (offset === count) {
                        break;
                    }
                }
            }

            return start + offset;
        }
    });

    function updateFilterMapping() {
        var mappedItems = this.mappedItems,
            mappedIndexProp = this.mappedIndexProp,
            transformedArray = this.transformedArray,
            currentItem,
            currentIndex = 0;

        for (var i = 0, len = mappedItems.length; i < len; i++) {
            currentItem = mappedItems[i];

            if (this.getVisibility(currentItem.mappedValue)) {
                currentItem[mappedIndexProp] = currentIndex;
                transformedArray[currentIndex++] = currentItem.value;
            }
        }
        transformedArray.length = currentIndex;
        this.transform.notifySubscribers(transformedArray);
    }

    makeTransform({
        name: "filter",
        mappedIndexProp: "mappedIndex",
        init: function () {
            return ko.observableArray([]);
        },
        valueAdded: function (value, index, visible) {
            if (this.getVisibility(visible)) {
                this.updateMapping();
            }
        },
        valueDeleted: function (value, index, visible, item) {
            if (this.getVisibility(visible)) {
                this.makeInvisible(value, index, item[this.mappedIndexProp]);
            }
        },
        valueMoved: function (value, to, from, visible) {
            if (this.getVisibility(visible)) {
                this.updateMapping();
            }
        },
        valueMutated: function (value, shouldBeVisible, currentlyVisible, item) {
            if (shouldBeVisible && !currentlyVisible) {
                this.updateMapping();

            } else if (!shouldBeVisible && currentlyVisible) {
                this.makeInvisible(value, item.index, item[this.mappedIndexProp]);
            }
        },
        makeInvisible: function (value, index, mappedIndex) {
            this.transform.splice(mappedIndex, 1);
            deletedIndex(this.mappedItems, this.mappedIndexProp, index);
        },
        updateMapping: updateFilterMapping,
        getVisibility: Boolean
    });

    function getGroupVisibility(groupKey) {
        return String(groupKey) === this.groupKey;
    }

    makeTransform({
        name: "groupBy",
        init: function () {
            this.groups = emptyObject();
            return ko.observableArray([]);
        },
        applyChanges: function (changes) {
            var groups = this.groups;

            applyChanges.call(this, changes);

            for (var key in groups) {
                if (groups[key].transformedArray.length === 0) {
                    this.deleteGroup(key);
                }
            }
        },
        valueAdded: function (value, index, groupKey, item) {
            groupKey = String(groupKey);

            var groups = this.groups;

            if (!groups[groupKey]) {
                var group = new transformClasses.filter(this.original);
                groups[groupKey] = group;

                group.groupKey = groupKey;
                group.mappedItems = this.mappedItems;
                group.mappedIndexProp = "mappedIndex." + groupKey;
                group.getVisibility = getGroupVisibility;

                var object = emptyObject();
                object.key = groupKey;
                object.values = group.transform;

                this.transform.push(object);
            }

            for (var key in groups) {
                groups[key].valueAdded(value, index, groupKey, item);
            }
        },
        valueDeleted: function (value, index, groupKey, item) {
            var groups = this.groups;

            for (var key in groups) {
                groups[key].valueDeleted(value, index, groupKey, item);
            }
        },
        valueMoved: function (value, to, from, groupKey, item) {
            var groups = this.groups;

            for (var key in groups) {
                groups[key].valueMoved(value, to, from, groupKey, item);
            }
        },
        valueMutated: function (value, newGroupKey, oldGroupKey, item) {
            var groups = this.groups,
                oldGroup = groups[oldGroupKey],
                index = item.index;

            oldGroup.makeInvisible(value, index, this.mappedItems[index][oldGroup.mappedIndexProp]);
            groups[newGroupKey].updateMapping();

            if (oldGroup.transformedArray.length === 0) {
                this.deleteGroup(String(oldGroupKey));
            }
        },
        deleteGroup: function (groupKey) {
            var transformedArray = this.transformedArray;

            delete this.groups[groupKey];

            for (var i = 0, len = transformedArray.length, object; i < len; i++) {
                object = transformedArray[i];

                if (object.key === groupKey) {
                    this.transform.splice(i, 1);
                    return;
                }
            }
        }
    });

    makeTransform({
        name: "map",
        init: function () {
            return ko.observableArray([]);
        },
        valueAdded: function (value, index, mappedValue) {
            this.transform.splice(index, 0, mappedValue);
        },
        valueDeleted: function (value, index) {
            this.transform.splice(index, 1);
        },
        valueMoved: function (value, to, from, mappedValue) {
            this.transform.splice(from, 1);
            this.transform.splice(to, 0, mappedValue);
        },
        valueMutated: function (value, newMappedValue, oldMappedValue, item) {
            this.transform.splice(item.index, 1);
            this.transform.splice(item.index, 0, newMappedValue);
        }
    });

    var allOrAny = {
        init: function () {
            this.truthinessCount = 0;
            return ko.observable(this.getTruthiness());
        },
        valueAdded: function (value, index, truthiness) {
            this.valueMutated(null, truthiness, false);
        },
        valueDeleted: function (value, index, truthiness) {
            this.valueMutated(null, false, truthiness);
        },
        valueMoved: function noop() {},
        valueMutated: function (value, newTruthiness, oldTruthiness) {
            if (newTruthiness && !oldTruthiness) {
                this.truthinessCount++;
            } else if (oldTruthiness && !newTruthiness) {
                this.truthinessCount--;
            }
            this.transform(this.getTruthiness());
        }
    };

    makeTransform(ko.utils.extend({
        name: "any",
        getTruthiness: function () {
            return this.truthinessCount > 0;
        }
    }, allOrAny));

    makeTransform(ko.utils.extend({
        name: "all",
        getTruthiness: function () {
            return this.truthinessCount === this.mappedItems.length;
        }
    }, allOrAny));

    ko.observableArray.fn.some = ko.observableArray.fn.any;
    ko.observableArray.fn.every = ko.observableArray.fn.all;

    ko.arrayTransforms = {
        makeTransform: makeTransform
    };
});
<commit_msg>Small tweaks here and there<commit_after>// knockout-arrayTransforms 0.3.0 (https://github.com/mwiencek/knockout-arrayTransforms)
// Released under the MIT (X11) License; see the LICENSE file in the official code repository.

(function (factory) {
    if (typeof module !== "undefined" && typeof module.exports !== "undefined") {
        factory(module.exports = require("knockout"));
    } else if (typeof define === "function" && define.amd) {
        define(["knockout"], factory);
    } else {
        factory(window.ko);
    }
})(function (ko) {

    var transformClasses = emptyObject();

    function applyChanges(changes) {
        var mappedItems = this.mappedItems,
            moves = emptyObject(),
            offset = 0;

        for (var i = 0, change; change = changes[i]; i++) {
            var status = change.status;

            if (status === "retained") {
                continue;
            }

            var index = change.index,
                moved = change.moved,
                value = change.value,
                item = change.mappedItem;

            if (moved !== undefined) {
                // For added statuses, index is a position in the new
                // array and moved is a position in the old array. For
                // deleted statuses, it's the opposite.
                if (status === "added") {
                    var to = index, from = moved + offset;

                } else if (status === "deleted") {
                    var to = moved, from = index + offset;
                }

                if (moves[to] === undefined) {
                    moves[to] = true;
                    item = mappedItems[from];
                    mappedItems.splice(from, 1)
                    mappedItems.splice(to, 0, item);
                    movedIndex(mappedItems, "index", to, from);
                    this.valueMoved(value, to, from, item.mappedValue, item);
                }
            }

            if (status === "added") {
                if (moved === undefined) {
                    item = emptyObject();
                    item.index = index;
                    item.value = value;
                    mapValue(this, item);
                    mappedItems.splice(index, 0, item);
                    addedIndex(mappedItems, "index", index);
                    this.valueAdded(value, index, item.mappedValue, item);
                }
                offset++;

            } else if (status === "deleted") {
                if (moved === undefined) {
                    item = mappedItems.splice(index + offset, 1)[0];
                    if (item.computed) {
                        item.computed.dispose();
                    }
                    deletedIndex(mappedItems, "index", index + offset);
                    this.valueDeleted(value, index + offset, item.mappedValue, item);
                }
                offset--;
            }
        }
    };

    function updateIndex(items, prop, start, end, offset) {
        while (start <= end) {
            items[start++][prop] += offset;
        }
    }

    function addedIndex(array, prop, index) {
        updateIndex(array, prop, index + 1, array.length - 1, 1);
    }

    function deletedIndex(array, prop, index) {
        updateIndex(array, prop, index, array.length - 1, -1);
    }

    function movedIndex(array, prop, to, from) {
        if (to > from) {
            updateIndex(array, prop, from, to - 1, -1);
        } else {
            updateIndex(array, prop, to + 1, from, 1);
        }
    }

    function emptyObject() {
        return Object.create ? Object.create(null) : {};
    }

    function exactlyEqual(a, b) { return a === b }

    function mapValue(state, item) {
        var callback = state.callback;

        if (callback === undefined) {
            item.mappedValue = item.value;
            return;
        }

        var owner = state, method = "callback";

        if (typeof callback !== "function") {
            owner = item.value;
            method = callback;
            callback = owner[method];

            if (typeof callback !== "function") {
                item.mappedValue = callback;
                return;

            } else if (ko.isObservable(callback)) {
                watchItem(state, item, callback);
                return;
            }
        }

        var computedValue = ko.computed(function () {
            return owner[method](item.value, item.index);
        });

        if (computedValue.isActive()) {
            computedValue.equalityComparer = exactlyEqual;
            watchItem(state, item, computedValue);
            return computedValue;
        } else {
            item.mappedValue = computedValue.peek();
        }
    }

    function watchItem(self, item, observable) {
        item.mappedValue = observable.peek();

        observable.subscribe(function (newValue) {
            var oldValue = item.mappedValue;
            item.mappedValue = newValue;
            self.valueMutated(item.value, newValue, oldValue, item);
        });
    }

    function makeTransform(proto) {
        function TransformState(original, callback, options) {
            this.original = original;
            this.mappedItems = [];
            this.callback = callback;

            var transform = this.transform = this.init(options);
            if (ko.isObservable(transform) && transform.cacheDiffForKnownOperation) {
                this.transformedArray = transform.peek();
            }
        }

        TransformState.prototype.applyChanges = applyChanges;
        ko.utils.extend(TransformState.prototype, proto);
        transformClasses[proto.name] = TransformState;

        ko.observableArray.fn[proto.name] = function (callback, options) {
            var state = new TransformState(this, callback, options),
                originalArray = this.peek(),
                initialChanges = [];

            this.subscribe(function (changes) {
                state.applyChanges(changes);
            }, null, "arrayChange");

            for (var i = 0, len = originalArray.length; i < len; i++) {
                initialChanges.push({ status: "added", value: originalArray[i], index: i });
            }

            state.applyChanges(initialChanges);
            return state.transform;
        };
    };

    makeTransform({
        name: "sortBy",
        init: function () {
            this.keyCounts = emptyObject();
            this.sortedItems = [];
            return ko.observableArray([]);
        },
        valueAdded: function (value, index, sortKey, item) {
            var mappedIndex = this.sortedIndexOf(sortKey, value, item),
                sortedItems = this.sortedItems,
                keyCounts = this.keyCounts;

            item.mappedIndex = mappedIndex;
            sortedItems.splice(mappedIndex, 0, item);
            addedIndex(sortedItems, "mappedIndex", mappedIndex);
            keyCounts[sortKey] = (keyCounts[sortKey] || 0) + 1;
            this.transform.splice(mappedIndex, 0, value);
        },
        valueDeleted: function (value, index, sortKey, item) {
            var mappedIndex = item.mappedIndex,
                sortedItems = this.sortedItems;

            sortedItems.splice(mappedIndex, 1);
            deletedIndex(sortedItems, "mappedIndex", mappedIndex);
            this.keyCounts[sortKey]--;
            this.transform.splice(mappedIndex, 1);
        },
        valueMoved: function (value, to, from, sortKey, item) {
            var oldIndex = item.mappedIndex,
                newIndex = this.sortedIndexOf(sortKey, value, item);

            if (oldIndex !== newIndex) {
                this.moveValue(value, sortKey, oldIndex, newIndex, item);
            }
        },
        valueMutated: function (value, newKey, oldKey, item) {
            // Revert to the old key temporarily, since it's already sorted,
            // otherwise the binary search won't work
            item.mappedValue = oldKey;

            var oldIndex = item.mappedIndex,
                newIndex = this.sortedIndexOf(newKey, value, item);

            item.mappedValue = newKey;

            if (oldIndex !== newIndex) {
                this.moveValue(value, newKey, oldIndex, newIndex, item, true);

                var keyCounts = this.keyCounts;
                keyCounts[oldKey]--;
                keyCounts[newKey] = (keyCounts[newKey] || 0) + 1;
            }
        },
        moveValue: function (value, sortKey, oldIndex, newIndex, item, isMutation) {
            var sortedItems = this.sortedItems;

            sortedItems.splice(oldIndex, 1);
            this.transform.splice(oldIndex, 1);

            // If we're here because of a move in the original array, rather
            // than a mutated value, then the mappedItems array has already
            // been reordered, thus newIndex is correctly adjusted.
            if (isMutation && oldIndex < newIndex) {
                newIndex--;
            }

            item.mappedIndex = newIndex;
            sortedItems.splice(newIndex, 0, item);

            movedIndex(sortedItems, "mappedIndex", newIndex, oldIndex);
            this.transform.splice(newIndex, 0, value);
        },
        sortedIndexOf: function (key, value, item) {
            var sortedItems = this.sortedItems,
                length = sortedItems.length;

            if (!length) {
                return 0;
            }

            var start = 0, end = length - 1, index;

            while (start <= end) {
                index = (start + end) >> 1;

                if (sortedItems[index].mappedValue < key) {
                    start = index + 1;
                } else if ((end = index) === start) {
                    break;
                }
            }

            // Keep things stably sorted. Only incurs a cost if there are
            // multiple of this key.
            var count = this.keyCounts[key], offset = 0;

            if (count) {
                var mappedItems = this.mappedItems, mappedItem;

                for (var i = 0; i < length; i++) {
                    mappedItem = mappedItems[i];

                    if (mappedItem === item) {
                        break;
                    }
                    if (mappedItem.mappedValue === key) {
                        offset++;
                    }
                    if (offset === count) {
                        break;
                    }
                }
            }

            return start + offset;
        }
    });

    function updateFilterMapping() {
        var mappedItems = this.mappedItems,
            mappedIndexProp = this.mappedIndexProp,
            transformedArray = this.transformedArray,
            currentItem,
            currentIndex = 0;

        for (var i = 0, len = mappedItems.length; i < len; i++) {
            currentItem = mappedItems[i];

            if (this.getVisibility(currentItem.mappedValue)) {
                currentItem[mappedIndexProp] = currentIndex;
                transformedArray[currentIndex++] = currentItem.value;
            }
        }
        transformedArray.length = currentIndex;
        this.transform.notifySubscribers(transformedArray);
    }

    makeTransform({
        name: "filter",
        mappedIndexProp: "mappedIndex",
        init: function () {
            return ko.observableArray([]);
        },
        valueAdded: function (value, index, visible) {
            if (visible) {
                this.updateMapping();
            }
        },
        valueDeleted: function (value, index, visible, item) {
            if (visible) {
                this.makeInvisible(value, index, item[this.mappedIndexProp]);
            }
        },
        valueMoved: function (value, to, from, visible) {
            if (visible) {
                this.updateMapping();
            }
        },
        valueMutated: function (value, shouldBeVisible, currentlyVisible, item) {
            if (shouldBeVisible && !currentlyVisible) {
                this.updateMapping();

            } else if (!shouldBeVisible && currentlyVisible) {
                this.makeInvisible(value, item.index, item[this.mappedIndexProp]);
            }
        },
        makeInvisible: function (value, index, mappedIndex) {
            this.transform.splice(mappedIndex, 1);
            deletedIndex(this.mappedItems, this.mappedIndexProp, index);
        },
        updateMapping: updateFilterMapping,
        getVisibility: Boolean
    });

    function getGroupVisibility(groupKey) {
        return String(groupKey) === this.groupKey;
    }

    makeTransform({
        name: "groupBy",
        init: function () {
            this.groups = emptyObject();
            return ko.observableArray([]);
        },
        applyChanges: function (changes) {
            var groups = this.groups;

            applyChanges.call(this, changes);

            for (var key in groups) {
                if (!groups[key].transformedArray.length) {
                    this.deleteGroup(key);
                }
            }
        },
        valueAdded: function (value, index, groupKey, item) {
            groupKey = String(groupKey);

            var groups = this.groups;

            if (!groups[groupKey]) {
                var group = new transformClasses.filter(this.original);
                groups[groupKey] = group;

                group.groupKey = groupKey;
                group.mappedItems = this.mappedItems;
                group.mappedIndexProp = "mappedIndex." + groupKey;
                group.getVisibility = getGroupVisibility;

                var object = emptyObject();
                object.key = groupKey;
                object.values = group.transform;

                this.transform.push(object);
            }

            for (var key in groups) {
                groups[key].valueAdded(value, index, key === groupKey, item);
            }
        },
        valueDeleted: function (value, index, groupKey, item) {
            groupKey = String(groupKey);

            var groups = this.groups;

            for (var key in groups) {
                groups[key].valueDeleted(value, index, key === groupKey, item);
            }
        },
        valueMoved: function (value, to, from, groupKey, item) {
            groupKey = String(groupKey);

            var groups = this.groups;

            for (var key in groups) {
                groups[key].valueMoved(value, to, from, key === groupKey, item);
            }
        },
        valueMutated: function (value, newGroupKey, oldGroupKey, item) {
            var groups = this.groups,
                oldGroup = groups[oldGroupKey];

            oldGroup.makeInvisible(value, item.index, item[oldGroup.mappedIndexProp]);
            groups[newGroupKey].updateMapping();

            if (!oldGroup.transformedArray.length) {
                this.deleteGroup(String(oldGroupKey));
            }
        },
        deleteGroup: function (groupKey) {
            var transformedArray = this.transformedArray;

            delete this.groups[groupKey];

            for (var i = 0, len = transformedArray.length; i < len; i++) {
                if (transformedArray[i].key === groupKey) {
                    return this.transform.splice(i, 1);
                }
            }
        }
    });

    makeTransform({
        name: "map",
        init: function () {
            return ko.observableArray([]);
        },
        valueAdded: function (value, index, mappedValue) {
            this.transform.splice(index, 0, mappedValue);
        },
        valueDeleted: function (value, index) {
            this.transform.splice(index, 1);
        },
        valueMoved: function (value, to, from, mappedValue) {
            this.transform.splice(from, 1);
            this.transform.splice(to, 0, mappedValue);
        },
        valueMutated: function (value, newMappedValue, oldMappedValue, item) {
            this.transform.splice(item.index, 1);
            this.transform.splice(item.index, 0, newMappedValue);
        }
    });

    var allOrAny = {
        init: function () {
            this.truthinessCount = 0;
            return ko.observable(this.getTruthiness());
        },
        valueAdded: function (value, index, truthiness) {
            this.valueMutated(null, truthiness, false);
        },
        valueDeleted: function (value, index, truthiness) {
            this.valueMutated(null, false, truthiness);
        },
        valueMoved: function noop() {},
        valueMutated: function (value, newTruthiness, oldTruthiness) {
            if (newTruthiness && !oldTruthiness) {
                this.truthinessCount++;
            } else if (oldTruthiness && !newTruthiness) {
                this.truthinessCount--;
            }
            this.transform(this.getTruthiness());
        }
    };

    makeTransform(ko.utils.extend({
        name: "any",
        getTruthiness: function () {
            return this.truthinessCount > 0;
        }
    }, allOrAny));

    makeTransform(ko.utils.extend({
        name: "all",
        getTruthiness: function () {
            return this.truthinessCount === this.mappedItems.length;
        }
    }, allOrAny));

    ko.observableArray.fn.some = ko.observableArray.fn.any;
    ko.observableArray.fn.every = ko.observableArray.fn.all;

    ko.arrayTransforms = {
        makeTransform: makeTransform
    };
});
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

var Event = require('org.chromium.common.events');
var mobile = require('org.chromium.bootstrap.mobile.impl');
var runtime = require('org.chromium.runtime.runtime');
var ChromeExtensionURLs = require('org.chromium.bootstrap.helpers.ChromeExtensionURLs');

// The AppWindow created by chrome.app.window.create.
var createdAppWindow = null;
var dummyNode = document.createElement('a');

function AppWindow() {
  this.contentWindow = mobile.fgWindow;
  this.id = '';
}

function unsupportedApi(api) {
  return function() {
    console.warn(api + ' is not supported on mobile.');
  };
}

AppWindow.prototype = {
  restore: unsupportedApi('AppWindow.restore'),
  moveTo: unsupportedApi('AppWindow.moveTo'),
  clearAttention: unsupportedApi('AppWindow.clearAttention'),
  minimize: unsupportedApi('AppWindow.minimize'),
  drawAttention: unsupportedApi('AppWindow.drawAttention'),
  focus: unsupportedApi('AppWindow.focus'),
  resizeTo: unsupportedApi('AppWindow.resizeTo'),
  maximize: unsupportedApi('AppWindow.maximize'),
  close: unsupportedApi('AppWindow.close'),
  setBounds: unsupportedApi('AppWindow.setBounds'),
  onBoundsChanged: new Event('onBoundsChanged'),
  onClosed: new Event('onClosed')
};
AppWindow.prototype.getBounds = function() {
  return {
    width: 0,
    height: 0,
    left: 0,
    top: 0
  };
};

function copyAttributes(srcNode, destNode) {
  var attrs = srcNode.attributes;
  for (var i = 0, attr; attr = attrs[i]; ++i) {
    destNode.setAttribute(attr.name, attr.value);
  }
}

function applyAttributes(attrText, destNode) {
  dummyNode.innerHTML = '<a ' + attrText + '>';
  copyAttributes(dummyNode.firstChild, destNode);
}

// Evals the scripts in order.
function evalScripts(rootNode, afterFunc) {
  var scripts = rootNode.getElementsByTagName('script');
  var doc = rootNode.ownerDocument;
  var numRemaining = scripts.length;
  function onLoadCallback(a) {
    if (!numRemaining--) {
      afterFunc && afterFunc();
    }
  }
  for (var i = 0, script; script = scripts[i]; ++i) {
    if (script.type && !(/text\/javascript/i.exec(script.type) ||
                         /application\/javascript/i.exec(script.type) ||
                         /application\/dart/i.exec(script.type))) {
      onLoadCallback();
    } else if (script.src) {
      var replacement = doc.createElement('script');
      copyAttributes(script, replacement);
      replacement.onload = onLoadCallback;
      replacement.onerror = onLoadCallback;
      replacement.async = false;
      script.parentNode.replaceChild(replacement, script);
    } else {
      // Skip over inline scripts.
      console.warn('Refused to execute inline script because it violates the following Content Security Policy directive: "default-src \'self\' chrome-extension-resource:"');
      console.warn('Script contents:');
      console.warn(script.textContent.slice(0, 100) + (script.textContent.length > 100 ? '<truncated>' : ''));
      onLoadCallback();
    }
  }
  // Handle the no scripts case.
  onLoadCallback();
}

function rewritePage(pageContent, filePath) {
  var fgBody = document.body;
  var fgHead = fgBody.previousElementSibling;

  // fgHead.innerHTML causes a DOMException on Android 2.3.
  while (fgHead.lastChild) {
    fgHead.removeChild(fgHead.lastChild);
  }

  var startIndex = pageContent.search(/<html([\s\S]*?)>/i);
  if (startIndex != -1) {
    startIndex += RegExp.lastMatch.length;
    // Copy over the attributes of the <html> tag.
    applyAttributes(RegExp.lastParen, fgBody.parentNode);
  } else {
    startIndex = 0;
  }

  // Put everything before the body tag in the head.
  var endIndex = pageContent.search(/<body([\s\S]*?)>/i);
  if (endIndex == -1) {
    mobile.eventIframe.insertAdjacentHTML('afterend', 'Load error: Page is missing body tag.');
  } else {
    applyAttributes(RegExp.lastParen, fgBody);

    // Don't bother removing the <body>, </body>, </html>. The browser's sanitizer removes them for us.
    var headHtml = pageContent.slice(startIndex, endIndex);
    pageContent = pageContent.slice(endIndex);

    fgHead.insertAdjacentHTML('beforeend', '<link rel="stylesheet" href="' + runtime.getURL('plugins/org.chromium.bootstrap/chromeappstyles.css') + '">');
    fgHead.insertAdjacentHTML('beforeend', headHtml);
    evalScripts(fgHead, function() {
      mobile.eventIframe.insertAdjacentHTML('afterend', pageContent);
      evalScripts(fgBody, ChromeExtensionURLs.releaseReadyWait);
    });
  }
}

function fixLocationObjects(wnd) {
  var hostDescriptor = {
    configurable: true,
    enumerable: true,
    get: function() {
      var parts = /^([^:]*):\/\/([^/]*)(\/[^#?]*)/.exec(this.href);
      return parts[2];
    }
  };
  var pathnameDescriptor = {
    configurable: true,
    enumerable: true,
    get: function() {
      var parts = /^([^:]*):\/\/([^/]*)(\/[^#?]*)/.exec(this.href);
      return parts[3];
    }
  };
  var originDescriptor = {
    configurable: true,
    enumerable: true,
    get: function() {
      var parts = /^([^:]*:\/\/[^/]*)(\/[^#?]*)/.exec(this.href);
      return parts[1];
    }
  };
  function fixInstance(l) {
    Object.defineProperty(l, 'host', hostDescriptor);
    Object.defineProperty(l, 'hostname', hostDescriptor);
    Object.defineProperty(l, 'pathname', pathnameDescriptor);
    Object.defineProperty(l, 'origin', originDescriptor);
  }
  // Android KK incorrectly parses chrome-extension:// URLs
  if (wnd.location.host === '') {
    fixInstance(wnd.location);
    var origCreateElement = wnd.document.createElement;
    // Also fix up the methods for anchor tags. Angular's location object requires this.
    wnd.document.createElement = function(tagName) {
      var ret = origCreateElement.apply(this, arguments);
      if (tagName === 'a' || tagName === 'A') {
        fixInstance(ret);
      }
      return ret;
    };
  }
  // This is needed for both pre- and post-KK Android, but throws an exception on Safari
  if (wnd.document.domain === '') {
    try {
      Object.defineProperty(wnd.document, 'domain', {
        configurable: false,
        enumerable: true,
        get: function() {
          return this.location.host;
        }
      });
    } catch (e) {}
  }
}

exports.create = function(filePath, options, callback) {
  if (createdAppWindow) {
    console.log('ERROR - chrome.app.window.create called multiple times. This is unsupported.');
    return;
  }
  createdAppWindow = new AppWindow();

  var anchorEl = mobile.bgWindow.document.createElement('a');
  anchorEl.href = filePath;
  var resolvedUrl = anchorEl.href;
  // Use background page's XHR so that relative URLs are relative to it.
  var xhr = new XMLHttpRequest();
  xhr.open('GET', resolvedUrl, true);
  // Android pre KK doesn't support onloadend.
  xhr.onload = xhr.onerror = function() {
    // Change the page URL before the callback.
    history.replaceState(null, null, resolvedUrl);
    fixLocationObjects(mobile.fgWindow);
    fixLocationObjects(mobile.bgWindow);
    // Call the callback before the page contents loads.
    if (callback) {
      callback(createdAppWindow);
    }
    var pageContent = xhr.responseText || 'Page load failed.';
    rewritePage(pageContent, filePath);
  };
  xhr.send();
};

exports.current = function() {
  return window == mobile.fgWindow ? createdAppWindow : null;
};

<commit_msg>Correct URL manipulation methods for data urls (Fixes #201)<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

var Event = require('org.chromium.common.events');
var mobile = require('org.chromium.bootstrap.mobile.impl');
var runtime = require('org.chromium.runtime.runtime');
var ChromeExtensionURLs = require('org.chromium.bootstrap.helpers.ChromeExtensionURLs');

// The AppWindow created by chrome.app.window.create.
var createdAppWindow = null;
var dummyNode = document.createElement('a');

function AppWindow() {
  this.contentWindow = mobile.fgWindow;
  this.id = '';
}

function unsupportedApi(api) {
  return function() {
    console.warn(api + ' is not supported on mobile.');
  };
}

AppWindow.prototype = {
  restore: unsupportedApi('AppWindow.restore'),
  moveTo: unsupportedApi('AppWindow.moveTo'),
  clearAttention: unsupportedApi('AppWindow.clearAttention'),
  minimize: unsupportedApi('AppWindow.minimize'),
  drawAttention: unsupportedApi('AppWindow.drawAttention'),
  focus: unsupportedApi('AppWindow.focus'),
  resizeTo: unsupportedApi('AppWindow.resizeTo'),
  maximize: unsupportedApi('AppWindow.maximize'),
  close: unsupportedApi('AppWindow.close'),
  setBounds: unsupportedApi('AppWindow.setBounds'),
  onBoundsChanged: new Event('onBoundsChanged'),
  onClosed: new Event('onClosed')
};
AppWindow.prototype.getBounds = function() {
  return {
    width: 0,
    height: 0,
    left: 0,
    top: 0
  };
};

function copyAttributes(srcNode, destNode) {
  var attrs = srcNode.attributes;
  for (var i = 0, attr; attr = attrs[i]; ++i) {
    destNode.setAttribute(attr.name, attr.value);
  }
}

function applyAttributes(attrText, destNode) {
  dummyNode.innerHTML = '<a ' + attrText + '>';
  copyAttributes(dummyNode.firstChild, destNode);
}

// Evals the scripts in order.
function evalScripts(rootNode, afterFunc) {
  var scripts = rootNode.getElementsByTagName('script');
  var doc = rootNode.ownerDocument;
  var numRemaining = scripts.length;
  function onLoadCallback(a) {
    if (!numRemaining--) {
      afterFunc && afterFunc();
    }
  }
  for (var i = 0, script; script = scripts[i]; ++i) {
    if (script.type && !(/text\/javascript/i.exec(script.type) ||
                         /application\/javascript/i.exec(script.type) ||
                         /application\/dart/i.exec(script.type))) {
      onLoadCallback();
    } else if (script.src) {
      var replacement = doc.createElement('script');
      copyAttributes(script, replacement);
      replacement.onload = onLoadCallback;
      replacement.onerror = onLoadCallback;
      replacement.async = false;
      script.parentNode.replaceChild(replacement, script);
    } else {
      // Skip over inline scripts.
      console.warn('Refused to execute inline script because it violates the following Content Security Policy directive: "default-src \'self\' chrome-extension-resource:"');
      console.warn('Script contents:');
      console.warn(script.textContent.slice(0, 100) + (script.textContent.length > 100 ? '<truncated>' : ''));
      onLoadCallback();
    }
  }
  // Handle the no scripts case.
  onLoadCallback();
}

function rewritePage(pageContent, filePath) {
  var fgBody = document.body;
  var fgHead = fgBody.previousElementSibling;

  // fgHead.innerHTML causes a DOMException on Android 2.3.
  while (fgHead.lastChild) {
    fgHead.removeChild(fgHead.lastChild);
  }

  var startIndex = pageContent.search(/<html([\s\S]*?)>/i);
  if (startIndex != -1) {
    startIndex += RegExp.lastMatch.length;
    // Copy over the attributes of the <html> tag.
    applyAttributes(RegExp.lastParen, fgBody.parentNode);
  } else {
    startIndex = 0;
  }

  // Put everything before the body tag in the head.
  var endIndex = pageContent.search(/<body([\s\S]*?)>/i);
  if (endIndex == -1) {
    mobile.eventIframe.insertAdjacentHTML('afterend', 'Load error: Page is missing body tag.');
  } else {
    applyAttributes(RegExp.lastParen, fgBody);

    // Don't bother removing the <body>, </body>, </html>. The browser's sanitizer removes them for us.
    var headHtml = pageContent.slice(startIndex, endIndex);
    pageContent = pageContent.slice(endIndex);

    fgHead.insertAdjacentHTML('beforeend', '<link rel="stylesheet" href="' + runtime.getURL('plugins/org.chromium.bootstrap/chromeappstyles.css') + '">');
    fgHead.insertAdjacentHTML('beforeend', headHtml);
    evalScripts(fgHead, function() {
      mobile.eventIframe.insertAdjacentHTML('afterend', pageContent);
      evalScripts(fgBody, ChromeExtensionURLs.releaseReadyWait);
    });
  }
}

function fixLocationObjects(wnd) {
  var hostDescriptor = {
    configurable: true,
    enumerable: true,
    get: function() {
      var parts = /^([^:]*):\/\/([^/]*)(\/[^#?]*)/.exec(this.href);
      return parts ? parts[2] : "";
    }
  };
  var pathnameDescriptor = {
    configurable: true,
    enumerable: true,
    get: function() {
      var parts = /^([^:]*):\/\/([^/]*)(\/[^#?]*)/.exec(this.href);
      return parts ? parts[3] : this.href;
    }
  };
  var originDescriptor = {
    configurable: true,
    enumerable: true,
    get: function() {
      var parts = /^([^:]*:\/\/[^/]*)(\/[^#?]*)/.exec(this.href);
      return parts ? parts[1] : "null";
    }
  };
  function fixInstance(l) {
    Object.defineProperty(l, 'host', hostDescriptor);
    Object.defineProperty(l, 'hostname', hostDescriptor);
    Object.defineProperty(l, 'pathname', pathnameDescriptor);
    Object.defineProperty(l, 'origin', originDescriptor);
  }
  // Android KK incorrectly parses chrome-extension:// URLs
  if (wnd.location.host === '') {
    fixInstance(wnd.location);
    var origCreateElement = wnd.document.createElement;
    // Also fix up the methods for anchor tags. Angular's location object requires this.
    wnd.document.createElement = function(tagName) {
      var ret = origCreateElement.apply(this, arguments);
      if (tagName === 'a' || tagName === 'A') {
        fixInstance(ret);
      }
      return ret;
    };
  }
  // This is needed for both pre- and post-KK Android, but throws an exception on Safari
  if (wnd.document.domain === '') {
    try {
      Object.defineProperty(wnd.document, 'domain', {
        configurable: false,
        enumerable: true,
        get: function() {
          return this.location.host;
        }
      });
    } catch (e) {}
  }
}

exports.create = function(filePath, options, callback) {
  if (createdAppWindow) {
    console.log('ERROR - chrome.app.window.create called multiple times. This is unsupported.');
    return;
  }
  createdAppWindow = new AppWindow();

  var anchorEl = mobile.bgWindow.document.createElement('a');
  anchorEl.href = filePath;
  var resolvedUrl = anchorEl.href;
  // Use background page's XHR so that relative URLs are relative to it.
  var xhr = new XMLHttpRequest();
  xhr.open('GET', resolvedUrl, true);
  // Android pre KK doesn't support onloadend.
  xhr.onload = xhr.onerror = function() {
    // Change the page URL before the callback.
    history.replaceState(null, null, resolvedUrl);
    fixLocationObjects(mobile.fgWindow);
    fixLocationObjects(mobile.bgWindow);
    // Call the callback before the page contents loads.
    if (callback) {
      callback(createdAppWindow);
    }
    var pageContent = xhr.responseText || 'Page load failed.';
    rewritePage(pageContent, filePath);
  };
  xhr.send();
};

exports.current = function() {
  return window == mobile.fgWindow ? createdAppWindow : null;
};

<|endoftext|>


<commit_before>'use strict';

var path = require('path');
var webpack = require('webpack');
var HtmlPlugin = require('webpack-html-plugin');
var HasteResolverPlugin = require('haste-resolver-webpack-plugin');

var IP = '0.0.0.0';
var PORT = 3000;
var NODE_ENV = process.env.NODE_ENV;
var ROOT_PATH = path.resolve(__dirname, '..');
var PROD = 'production';
var DEV = 'development';
let isProd = NODE_ENV === 'production';

var config = {
  paths: {
    src: path.join(ROOT_PATH, '.'),
    index: path.join(ROOT_PATH, 'index.ios'),
  },
};

var webpackConfig = {
  ip: IP,
  port: PORT,
  devtool: 'cheap-module-eval-source-map',
  resolve: {
    alias: {
      'react-native': 'ReactWeb',
    },
    extensions: ['', '.js', '.ios.js', '.android.js', '.jsx'],
  },
  entry: isProd? [
    config.paths.index
  ]: [
    'webpack-dev-server/client?http://' + IP + ':' + PORT,
    'webpack/hot/only-dev-server',
    config.paths.index,
  ],
  output: {
    path: path.join(__dirname, 'output'),
    filename: 'bundle.js'
  },
  plugins: [
    new HasteResolverPlugin({
      platform: 'web',
      nodeModules: ['react-web']
    }),
    new webpack.DefinePlugin({
      'process.env': {
        'NODE_ENV': JSON.stringify(isProd? PROD: DEV),
      }
    }),
    isProd? new webpack.ProvidePlugin({
      React: "react"
    }): new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin(),
    new HtmlPlugin(),
  ],
  module: {
    loaders: [{
      test: /\.json$/,
      loader: 'json',
    }, {
      test: /\.jsx?$/,
      loader: 'react-hot',
      include: [config.paths.src],
      exclude: [/node_modules/]
    }, {
      test: /\.jsx?$/,
      loader: 'babel',
      query: {
        presets: ['es2015', 'react', 'stage-1']
      },
      include: [config.paths.src],
      exclude: /(node_modules\/(?!react))/
    }]
  }
};
webpackConfig.resolve.alias[path.basename(ROOT_PATH, '.')] = path.join(ROOT_PATH, '.');

module.exports = webpackConfig;
<commit_msg>Add .web.js support, and webpack will bundle the first matched from left to right order in resolve.extensions[]<commit_after>'use strict';

var path = require('path');
var webpack = require('webpack');
var HtmlPlugin = require('webpack-html-plugin');
var HasteResolverPlugin = require('haste-resolver-webpack-plugin');

var IP = '0.0.0.0';
var PORT = 3000;
var NODE_ENV = process.env.NODE_ENV;
var ROOT_PATH = path.resolve(__dirname, '..');
var PROD = 'production';
var DEV = 'development';
let isProd = NODE_ENV === 'production';

var config = {
  paths: {
    src: path.join(ROOT_PATH, '.'),
    index: path.join(ROOT_PATH, 'index.ios'),
  },
};

var webpackConfig = {
  ip: IP,
  port: PORT,
  devtool: 'cheap-module-eval-source-map',
  resolve: {
    alias: {
      'react-native': 'ReactWeb',
    },
    extensions: ['', '.js', '.web.js', '.ios.js', '.android.js', '.jsx'],
  },
  entry: isProd? [
    config.paths.index
  ]: [
    'webpack-dev-server/client?http://' + IP + ':' + PORT,
    'webpack/hot/only-dev-server',
    config.paths.index,
  ],
  output: {
    path: path.join(__dirname, 'output'),
    filename: 'bundle.js'
  },
  plugins: [
    new HasteResolverPlugin({
      platform: 'web',
      nodeModules: ['react-web']
    }),
    new webpack.DefinePlugin({
      'process.env': {
        'NODE_ENV': JSON.stringify(isProd? PROD: DEV),
      }
    }),
    isProd? new webpack.ProvidePlugin({
      React: "react"
    }): new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin(),
    new HtmlPlugin(),
  ],
  module: {
    loaders: [{
      test: /\.json$/,
      loader: 'json',
    }, {
      test: /\.jsx?$/,
      loader: 'react-hot',
      include: [config.paths.src],
      exclude: [/node_modules/]
    }, {
      test: /\.jsx?$/,
      loader: 'babel',
      query: {
        presets: ['es2015', 'react', 'stage-1']
      },
      include: [config.paths.src],
      exclude: /(node_modules\/(?!react))/
    }]
  }
};
webpackConfig.resolve.alias[path.basename(ROOT_PATH, '.')] = path.join(ROOT_PATH, '.');

module.exports = webpackConfig;
<|endoftext|>


<commit_before>/**
 * Module dependencies
 */

var _ = require('@sailshq/lodash');
var flaverr = require('flaverr');

/**
 * Module constants
 */

// Precompiled error message templates, one for each variety of recognized usage error.
// (Precompiled by Lodash into callable functions that return strings.  Pass in `details` to use.)
var USAGE_ERR_MSG_TEMPLATES = {

  E_VALIDATION: _.template(
    'Invalid data provided.\n'+
    'Provided values are not suitable for creating/updating records in this model.\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
    // ========================================================
    // TODO: Expand this template to also rely on additional information (it's a special case)
    //
    // example from Waterline <=v0.12:
    // ```
    // Invalid attributes sent to undefined:
    // • billingStatus
    //   • `in` validation rule failed for input: null
    //   ```
    //
    //  ^^yuck
    // ========================================================
  ),

  E_INVALID_NOOP: _.template(
    'Query is a no-op.\n'+
    '(It would have no effect and retrieve no useful information.)\n'+
    '\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
    // ===============================================================================================
    // NOTE: this error (^^^^^^) is so that there's some kind of default handling for
    // the no-op case.  This generic error is not always relevant or good.  And anyway,
    // most methods should handle E_NOOP explicitly.
    //
    // For example, if `.findOne()` notices an E_NOOP when forging, it simply swallows the error
    // and calls its callback in exactly the same way as it would if specified criteria MIGHT have
    // matched something but didn't.  The fact that it NEVER could have matched anything doesn't
    // particularly matter from a userland perspective, and since certain parts of `criteria` and
    // other query keys are often built _dynamically_, any more aggressive failure in this case would
    // be inconsiderate, at best.  Thus it makes sense to avoid considering this an error whenever
    // possible.
    // ===============================================================================================
  ),

  E_INVALID_META: _.template(
    'Invalid value provided for `meta`.\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
  ),

  E_INVALID_CRITERIA: _.template(
    'Invalid criteria.\n'+
    'Refer to the docs for up-to-date info on query language syntax:\n'+
    'http://sailsjs.com/docs/concepts/models-and-orm/query-language\n'+
    '\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
  ),

  E_INVALID_POPULATES: _.template(
    'Invalid populate(s).\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
  ),

  E_INVALID_NUMERIC_ATTR_NAME: _.template(
    'Invalid numeric attr name.\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
  ),

  E_INVALID_STREAM_ITERATEE: _.template(
    'Invalid iteratee function.\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
  ),

  E_INVALID_NEW_RECORD: _.template(
    'Invalid initial data for new record.\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
  ),

  E_INVALID_NEW_RECORDS: _.template(
    'Invalid initial data for new records.\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
  ),

  E_INVALID_VALUES_TO_SET: _.template(
    'Invalid data-- cannot perform update with the provided values.\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
  ),

  E_INVALID_TARGET_RECORD_IDS: _.template(
    'Invalid target record id(s).\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
  ),

  E_INVALID_COLLECTION_ATTR_NAME: _.template(
    'Invalid collection attr name.\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
  ),

  E_INVALID_ASSOCIATED_IDS: _.template(
    'Invalid associated id(s).\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
  ),
};

/**
 * buildUsageError()
 *
 * Build a new Error instance from the provided metadata.
 *
 * > Currently, this is designed for use with the `forgeStageTwoQuery()` utility, and its recognized
 * > error codes are all related to that use case.  But the idea is that, over time, this can also
 * > be used with any other sorts of new, end-developer-facing usage errors.
 *
 * ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 * @param {String} code                 [e.g. 'E_INVALID_CRITERIA']
 * @param {String} details              [e.g. 'The provided criteria contains an unrecognized property (`foo`):\n\'bar\'']
 * ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 * @returns {Error}
 *          @property {String} name   (==> 'UsageError')
 *          @property {String} message  [composed from `details` and a built-in template]
 *          @property {String} stack    [built automatically by `new Error()`]
 *          @property {String} code     [the specified `code`]
 *          @property {String} details  [the specified `details`]
 *
 * > The returned Error will have normalized properties and a standard,
 * > nicely-formatted error message built from stitching together the
 * > provided pieces of information.
 * >
 * > Note that, until we do automatic munging of stack traces, using
 * > this utility adds another internal item to the top of the trace.
 */

module.exports = function buildUsageError(code, details) {

  // Look up standard template for this particular error code.
  if (!USAGE_ERR_MSG_TEMPLATES[code]) {
    throw new Error('Consistency violation: Unrecognized error code: '+code);
  }

  // Build error message.
  var errorMessage = USAGE_ERR_MSG_TEMPLATES[code]({
    details: details
  });

  // Instantiate Error.
  // (This builds the stack trace.)
  var err = new Error(errorMessage);

  // Flavor the error with the appropriate `code`, direct access to the provided `details`,
  // and a consistent "name" (i.e. so it reads nicely when logged.)
  err = flaverr({
    name: 'UsageError',
    code: code,
    details: details
  }, err);

  // That's it!
  // Send it on back.
  return err;

};
<commit_msg>Fix E_NOOP error code (was E_INVALID_NOOP because of a find/replace.)<commit_after>/**
 * Module dependencies
 */

var _ = require('@sailshq/lodash');
var flaverr = require('flaverr');

/**
 * Module constants
 */

// Precompiled error message templates, one for each variety of recognized usage error.
// (Precompiled by Lodash into callable functions that return strings.  Pass in `details` to use.)
var USAGE_ERR_MSG_TEMPLATES = {

  E_VALIDATION: _.template(
    'Invalid value(s) provided.\n'+
    // 'Invalid value(s) provided for `'+modelIdentity+'` model.\n'+
    // 'Invalid value(s) provided for `'+modelIdentity+'` model:\n'+
    // ' • billingStatus\n'+
    // '   - Value was not in the configured whitelist (delinquent, new, paid)\n'+
    // ' • fooBar\n'+
    // '   - Value was an empty string.\n'+
    '\n'
    // ========================================================
    //
    // example from Waterline <=v0.12:
    // ```
    // Invalid attributes sent to undefined:
    // • billingStatus
    //   • `in` validation rule failed for input: null
    //   ```
    //
    //  ^^yuck
    // ========================================================
  ),

  E_NOOP: _.template(
    'Query is a no-op.\n'+
    '(It would have no effect and retrieve no useful information.)\n'+
    '\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
    // ===============================================================================================
    // NOTE: this error (^^^^^^) is so that there's some kind of default handling for
    // the no-op case.  This generic error is not always relevant or good.  And anyway,
    // most methods should handle E_NOOP explicitly.
    //
    // For example, if `.findOne()` notices an E_NOOP when forging, it simply swallows the error
    // and calls its callback in exactly the same way as it would if specified criteria MIGHT have
    // matched something but didn't.  The fact that it NEVER could have matched anything doesn't
    // particularly matter from a userland perspective, and since certain parts of `criteria` and
    // other query keys are often built _dynamically_, any more aggressive failure in this case would
    // be inconsiderate, at best.  Thus it makes sense to avoid considering this an error whenever
    // possible.
    // ===============================================================================================
  ),

  E_INVALID_META: _.template(
    'Invalid value provided for `meta`.\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
  ),

  E_INVALID_CRITERIA: _.template(
    'Invalid criteria.\n'+
    'Refer to the docs for up-to-date info on query language syntax:\n'+
    'http://sailsjs.com/docs/concepts/models-and-orm/query-language\n'+
    '\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
  ),

  E_INVALID_POPULATES: _.template(
    'Invalid populate(s).\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
  ),

  E_INVALID_NUMERIC_ATTR_NAME: _.template(
    'Invalid numeric attr name.\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
  ),

  E_INVALID_STREAM_ITERATEE: _.template(
    'Invalid iteratee function.\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
  ),

  E_INVALID_NEW_RECORD: _.template(
    'Invalid initial data for new record.\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
  ),

  E_INVALID_NEW_RECORDS: _.template(
    'Invalid initial data for new records.\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
  ),

  E_INVALID_VALUES_TO_SET: _.template(
    'Invalid data-- cannot perform update with the provided values.\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
  ),

  E_INVALID_TARGET_RECORD_IDS: _.template(
    'Invalid target record id(s).\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
  ),

  E_INVALID_COLLECTION_ATTR_NAME: _.template(
    'Invalid collection attr name.\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
  ),

  E_INVALID_ASSOCIATED_IDS: _.template(
    'Invalid associated id(s).\n'+
    'Details:\n'+
    '  <%= details %>'+
    '\n'
  ),
};

/**
 * buildUsageError()
 *
 * Build a new Error instance from the provided metadata.
 *
 * > Currently, this is designed for use with the `forgeStageTwoQuery()` utility, and its recognized
 * > error codes are all related to that use case.  But the idea is that, over time, this can also
 * > be used with any other sorts of new, end-developer-facing usage errors.
 *
 * ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 * @param {String} code                 [e.g. 'E_INVALID_CRITERIA']
 * @param {String} details              [e.g. 'The provided criteria contains an unrecognized property (`foo`):\n\'bar\'']
 * ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 * @returns {Error}
 *          @property {String} name   (==> 'UsageError')
 *          @property {String} message  [composed from `details` and a built-in template]
 *          @property {String} stack    [built automatically by `new Error()`]
 *          @property {String} code     [the specified `code`]
 *          @property {String} details  [the specified `details`]
 *
 * > The returned Error will have normalized properties and a standard,
 * > nicely-formatted error message built from stitching together the
 * > provided pieces of information.
 * >
 * > Note that, until we do automatic munging of stack traces, using
 * > this utility adds another internal item to the top of the trace.
 */

module.exports = function buildUsageError(code, details) {

  // Look up standard template for this particular error code.
  if (!USAGE_ERR_MSG_TEMPLATES[code]) {
    throw new Error('Consistency violation: Unrecognized error code: '+code);
  }

  // Build error message.
  var errorMessage = USAGE_ERR_MSG_TEMPLATES[code]({
    details: details
  });

  // Instantiate Error.
  // (This builds the stack trace.)
  var err = new Error(errorMessage);

  // Flavor the error with the appropriate `code`, direct access to the provided `details`,
  // and a consistent "name" (i.e. so it reads nicely when logged.)
  err = flaverr({
    name: 'UsageError',
    code: code,
    details: details
  }, err);

  // That's it!
  // Send it on back.
  return err;

};
<|endoftext|>


<commit_before>function ready(fn) {
  if (document.readyState != 'loading'){
    fn();
  } else {
    document.addEventListener('DOMContentLoaded', fn);
  }
}

function loadReusableComponents() {
  loadUQFavicon();

  addAppleTouchIcon();

  //insert elements, even before Polymer is loaded

  //first element of the original document
  var firstElement = document.body.children[0];

  //insert alerts before header
  var alerts = document.querySelector('uqlibrary-alerts');
  if (!alerts) {
    //as a back up insert header if it's not defined already
    alerts = document.createElement('uqlibrary-alerts');
    document.body.insertBefore(alerts, firstElement);
  }

  // insert header after body-tag
  var header = document.createElement('uq-minimal-header');
  document.body.insertBefore(header, firstElement);

  // insert sub footer before body-tag
  var subFooter = document.createElement('uql-connect-footer');
  document.body.appendChild(subFooter);

  // insert footer before body-tag
  var footer = document.createElement('uq-minimal-footer');
  document.body.appendChild(footer);

  window.addEventListener('WebComponentsReady', function() {
    // when polymer is ready - configure elements
  });
}

function loadUQFavicon() {
  var link = document.createElement('link'),
    href = '//assets.library.uq.edu.au/master/reusable-components/resources/favicon.ico';
  link.type = 'image/x-icon';
  link.rel = 'shortcut icon';
  link.href = href;
  document.getElementsByTagName('head')[0].appendChild(link);
  link.rel = 'icon'; //for IE
  document.getElementsByTagName('head')[0].appendChild(link);

}

function addAppleTouchIcon() {
  // replace apple-touch-icon
  var appleTouchIconlink = $('link[rel="apple-touch-icon"]'),
    link = document.createElement('link'),
    sizes = ['152x152', '120x120', '76x76'],
    rel = 'apple-touch-icon',
    href = '//assets.library.uq.edu.au/master/reusable-components/resources/images/apple-touch-icon.png';

  if (appleTouchIconlink) {
    appleTouchIconlink.attr('href', href);
  } else {
    link.rel = rel;
    link.href = href;
    document.getElementsByTagName('head')[0].appendChild(link);
  }

  for (var i = 0; i < sizes.length; i++) {
    var size = sizes[i],
      iconLink = document.createElement('link');
    iconLink.rel = rel;
    iconLink.sizes = size;
    iconLink.href = href.replace('icon.png','icon-' + size + '.png');
    document.getElementsByTagName('head')[0].appendChild(iconLink);
  }
}

ready(loadReusableComponents);
<commit_msg>end of day push [PT #129811761]<commit_after>function ready(fn) {
  if (document.readyState != 'loading'){
    fn();
  } else {
    document.addEventListener('DOMContentLoaded', fn);
  }
}

function loadReusableComponents() {
  loadUQFavicon();

  addBreadcrumbs();

  addAppleTouchIcon();

  //insert elements, even before Polymer is loaded

  //first element of the original document
  var firstElement = document.body.children[0];

  //insert alerts before header
  var alerts = document.querySelector('uqlibrary-alerts');
  if (!alerts) {
    //as a back up insert header if it's not defined already
    alerts = document.createElement('uqlibrary-alerts');
    document.body.insertBefore(alerts, firstElement);
  }

  // insert header after body-tag
  var header = document.createElement('uq-minimal-header');
  document.body.insertBefore(header, firstElement);

  // insert sub footer before body-tag
  var subFooter = document.createElement('uql-connect-footer');
  document.body.appendChild(subFooter);

  // insert footer before body-tag
  var footer = document.createElement('uq-minimal-footer');
  document.body.appendChild(footer);

  window.addEventListener('WebComponentsReady', function() {
    // when polymer is ready - configure elements
  });

}

function loadUQFavicon() {
  var link = document.createElement('link'),
    href = '//assets.library.uq.edu.au/master/reusable-components/resources/favicon.ico';
  link.type = 'image/x-icon';
  link.rel = 'shortcut icon';
  link.href = href;
  document.getElementsByTagName('head')[0].appendChild(link);
  link.rel = 'icon'; //for IE
  document.getElementsByTagName('head')[0].appendChild(link);

}

function addAppleTouchIcon() {
  // replace apple-touch-icon
  var appleTouchIconlink = ('link[rel="apple-touch-icon"]'),
    link = document.createElement('link'),
    sizes = ['152x152', '120x120', '76x76'],
    rel = 'apple-touch-icon',
    href = '//assets.library.uq.edu.au/master/reusable-components/resources/images/apple-touch-icon.png';

  if (appleTouchIconlink) {
    appleTouchIconlink.attr('href', href);
  } else {
    link.rel = rel;
    link.href = href;
    document.getElementsByTagName('head')[0].appendChild(link);
  }

  for (var i = 0; i < sizes.length; i++) {
    var size = sizes[i],
      iconLink = document.createElement('link');
    iconLink.rel = rel;
    iconLink.sizes = size;
    iconLink.href = href.replace('icon.png','icon-' + size + '.png');
    document.getElementsByTagName('head')[0].appendChild(iconLink);
  }
}

function addLink(labelText, hrefAddress) {
  // create anchor, add text, add link
  var anchorText = document.createTextNode(labelText);
  if (window.location.href != hrefAddress) {
    // return an anchor element
    var anchor = document.createElement('a');
    anchor.href = hrefAddress;
    anchor.appendChild(anchorText)
    return anchor;
  } else {
    // return a text node
    return anchorText;
  }

}

// usage: addBreadcrumbs('#head');
function addBreadcrumbs(parentElementIdentifier) {
  var parentBlock = document.querySelector(parentElementIdentifier);
  if (typeof(parentBlock) === undefined) {
    console.log('element '+parentElementIdentifier+' doesnt exist (careerhub/load.js)');
    return false;
  }

  // create ol
  var breadcrumbList = document.createElement('ol');
  breadcrumbList.class = 'breadcrumbList';

  // create first breadcrumb entry: home page
  // <paper-icon-button icon="home"></paper-icon-button>
  var homepageIcon = document.createElement('paper-icon-button');
  homepageIcon.icon= 'home';
  var homePageLink = 'https://www.library.uq.edu.au/';

  var anAnchor = document.createElement('a');
  anAnchor.href = homePageLink;
  anAnchor.appendChild(homepageIcon);

  var anLI = document.createElement('li');
  anLI.appendChild(anAnchor);
  breadcrumbList.appendChild(anLI);

  // create second breadcrumb entry: careerhub workgroup homepage
  var linktext = 'Library staff development';
  var theLink = 'https://www.careerhub.uq.edu.au/workgroups/library-staff-development';

  var childElement;
  var anchorText;
  if (window.location.href != theLink) {
    childElement = document.createElement('a');
    childElement.href = theLink;
    anchorText = document.createTextNode(linktext);
    childElement.appendChild(anchorText);
  } else {
    anchorText = document.createTextNode(linktext);
    childElement.appendChild(anchorText);
  }

  anLI = document.createElement('li');
  anLI.appendChild(childElement);
  breadcrumbList.appendChild(anLI);

  // if is event page, add another breadcrumb, as event title
  testElement = document.querySelector('.event_title');
  if (typeof(testElement) !== undefined) {
    // an event class means we are on a detail page
    var textProperty = 'textContent' in document ? 'textContent' : 'innerText';
    var theText = testElement.textContent;

    anLI = document.createElement('li');
    anLI.appendChild(theText);
    breadcrumbList.appendChild(anLI);
  }

  parentBlock.breadcrumbList(breadcrumbList, parentBlock.firstChild);
}

ready(loadReusableComponents);
<|endoftext|>


<commit_before>var myApp = angular.module('myApp', ['elasticsearch','ngMap']);

myApp.controller('viewcontroller',function ($scope, dataClient, esFactory, $interval, $window, $document, helper, $timeout) {

  var places = [],
      renderarray = [],
      categoryarray = [],
      streamedCheckin = [],
      searchedCheckinarray = [],
      draggedCheckin = [],
      infowindowarray= [],
      citysearched,
      index = 0,
      current_date = new Date().getTime()/1000;
      geocoder = new google.maps.Geocoder(),           //variable for geocoding
      infowindow = new google.maps.InfoWindow();      //variable for map infowindow

  $scope.activeContainer = '';

  $scope.init = function(){
      $scope.$on('mapInitialized', function(event, map) {
        $scope.mapobj = map;
        $scope.mapobj.setZoom(2);
        $scope.mapobj.setOptions({ minZoom: 2, maxZoom: 15 });
        $scope.mapobj.setCenter({lat: 0, lng: 0});
      });
      $scope.categoriesbox = false;
      $scope.checkinfrequency = "Count";
      $scope.freqtext = "";
      $scope.freqclass = "";
      $scope.inputcontainerHeight = { 'height': "5rem" };
      $('[data-toggle="popover"]').popover({
        placement:'right',
        html:true
      });
      $('[data-toggle="popover"]').mouseover(function() {
            $(this).popover('show');
        });
        $('[data-toggle="popover"]').mouseleave(function() {
            $(this).popover('hide');
      });
      $timeout(function(){
        var topHeight = $('#header').outerHeight() + 15;
        $('div[title="Zoom in"]').parents('.gmnoprint').addClass('zoomSet');
      },3000);
  };

  $scope.opencheckin = function(event,details){
   $window.open('https://'+details,'_blank');
  };

  $scope.changeCategory = function(sub){
    //sub.value = (sub.value==true ? false : true);
    $timeout(function(){
      $scope.showcategory(sub.name);
    },300);
  }

  $scope.showwindow = function(e,data,visible){
    for(var i=0;i<infowindowarray.length;i++){
      if(infowindowarray[i][1]==data[1] && infowindowarray[i][2]==data[2]){
        visible = false;
      }
    }
   if(visible){
      infowindow = new google.maps.InfoWindow();
      infowindow.setContent('

' + '' + '	' + '' + ''+ data[8] + ' says ' +'' + data[0] + '
Place : ' + data[7] + '

Visit this CheckIn

'+'
');
      var center = helper.getCenter($scope.mapobj.getZoom(), data);
      infowindow.setPosition(center);
      infowindow.setZIndex(2);
      infowindow.open($scope.mapobj);
      var current_date = new Date().getTime()/1000;
      infowindowarray[index] = [infowindow, data[1], data[2], current_date];
      index++;
    }
 };

  $scope.searchquerry = function(){
       try{
          //searchtext variable referred to the text in the search box
          if($scope.searchtext!=null && $scope.searchtext.replace(/\s/g,'').length){  //to check if search text is null
              $scope.activeContainer = 'active';
              var suggestClient = dataClient.getSuggestions($scope.searchtext);
              suggestClient.on('data',function (resp) {
                //$apply_solve
                $timeout(function(){
                  $scope.row = true;
                  $scope.categoriesbox = false;
                  $scope.suggestions = resp.suggest.mysuggester[0].options;
                },0);
              }).on('error',function (err) {
                  console.trace(err.message);
              });
          }else{
              $scope.suggestions = null;
              $scope.categoriesbox = false;
              $scope.row = false;
              $scope.activeContainer = '';
          }
      }catch(e){
          console.log('error in try'+e);
      }
  };

  $scope.changesearchtext = function(text){
       $scope.searchtext = text;
       $scope.row = false;
  }

  $scope.getData = function(){
    var searchClient = dataClient.getSearchCheckin(angular.lowercase($scope.searchtext));
    searchClient.on('data', function(res) {
        console.log(res);
        searchedCheckinarray = [];
        categoryarray = [];
        places = [];
        citysearched = angular.lowercase($scope.searchtext);
        $scope.row = false;    //to hide suggestions
        //No need $apply_solve
        //$scope.$apply();
        searchProcess(res);  //to fetch the data and to mark it on map
      }).on('error', function(err) {
        console.log("caught a stream error", err);
      });
  };

  function searchProcess (response){
    if($scope.searchtext!=null && $scope.searchtext.replace(/\s/g,'').length){
      $scope.categoriesbox = true;
      if(response.hits){
        var hit_length = response.hits.hits.length;
          var current_date =  new Date().getTime()/1000;
           for(var i=0;i<hit_length;i++){
            var current_hit = response.hits.hits[i];
            if (current_hit._source.category && current_hit._source.latitude && current_hit._source.longitude && current_hit._source.category) {
              categoryarray[current_hit._source.category] = true;
              var default_arr = helper.getMapArray(current_hit._source);
              var specific_arr = [
                'src/assets/img/red_marker.png',
                current_date
              ];
              var arr = default_arr.concat(specific_arr);
              searchedCheckinarray.push(arr);
            }
          }
       }
       //GeoCoding to search the city
       geocoder.geocode( { "address": $scope.searchtext }, function(results, status) {
         if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
           var location = results[0].geometry.location,
           latitude  = location.lat(),
           longitude  = location.lng();
           $scope.mapobj.setCenter({lat:latitude,lng:longitude});
           $scope.mapobj.setZoom(11);
           $scope.$apply();
         }
       });
       renderarray = [];
       places.push.apply(places,searchedCheckinarray);
       renderarray.push.apply(renderarray,searchedCheckinarray);
       if(draggedCheckin!=null) renderarray.push.apply(renderarray,draggedCheckin);
       if(streamedCheckin!=null) renderarray.push.apply(renderarray,streamedCheckin);
       $scope.places = renderarray;
       $scope.subjects = createJson(categoryarray,Object.keys(categoryarray));
       $scope.$digest();
       $scope.$apply();
       console.log($scope.places);
    }
 }

 var realtimeClient = dataClient.getliveData();
 realtimeClient.on('data', function(res) {
     streamProcess(res); //to fetch the data and to mark it on map
 }).on('error', function(err) {
   console.log("caught a stream error", err);
 });

 function streamProcess(response){
   if(response._source.latitude!=null && response._source.longitude!=null){
    var default_arr = helper.getMapArray(response._source);
    var specific_arr = [
      'src/assets/img/blue_marker.png',
      response._source.city,
      current_date
    ];
    var arr = default_arr.concat(specific_arr);

     streamedCheckin.push(arr);
     renderarray.push(arr);
     $scope.places = renderarray;

      $scope.streamStatus = helper.getStatus(streamedCheckin.length);
      $scope.checkinfrequency = $scope.streamStatus.checkinfrequency;
      $scope.color = $scope.streamStatus.color;
      $scope.freqtext = $scope.streamStatus.freqtext;
      $scope.freqclass = $scope.streamStatus.freqclass;

     $scope.$apply();
   }
 }

   $scope.draggedmap = function(){
     draggedCheckin = [];
     if($scope.mapobj.getZoom()>=5){
       var dragClient = dataClient.getDragData($scope.mapobj.getCenter().lat(),$scope.mapobj.getCenter().lng());
       dragClient.on('data', function(res) {
         dragProcess(res);  //to fetch the data and to mark it on map
       }).on('error', function(err) {
         console.log("caught a stream error", err);
       });
     }else if($scope.mapobj.getZoom()==4){
       draggedCheckin = [];
       renderarray = [];
       if(places!=null) renderarray.push.apply(renderarray,places);
       if(streamedCheckin!=null) renderarray.push.apply(renderarray,streamedCheckin);
       $scope.places = renderarray;
     }
   }

  function dragProcess(response){
     if(response.hits){
       for(var i=0;i<response.hits.hits.length;i++){
         if( response.hits.hits[i]._source){
           if(response.hits.hits[i]._source.latitude && response.hits.hits[i]._source.longitude){
             if(citysearched==response.hits.hits[i]._source.city)
             continue;
            var default_arr = helper.getMapArray(response.hits.hits[i]._source);
            var specific_arr = [
              'src/assets/img/orange_marker.png'
            ];
            var arr = default_arr.concat(specific_arr);

             draggedCheckin.push(arr);
           }
         }
       }
     }
     if(draggedCheckin.length!=0){
       renderarray = [];
       if(places!=null) renderarray.push.apply(renderarray,places);
       renderarray.push.apply(renderarray,draggedCheckin);
       if(streamedCheckin!=null) renderarray.push.apply(renderarray,streamedCheckin);
       $scope.places = renderarray;
       $scope.$digest();
       $scope.$apply();
     }
   }

 $scope.showcategory = function(data){
     places = [];
     if(categoryarray[data]==true) categoryarray[data]=false;
     else categoryarray[data]=true;
     for(var i=0;i<searchedCheckinarray.length;i++){
         if(categoryarray[searchedCheckinarray[i][4]] == true){
             var arr = [];
             for(var j=0;j<10;j++){
               arr[j] = searchedCheckinarray[i][j];
             }
             places.push(arr);
         }
     }
     renderarray = [];
     if(places!=null)renderarray.push.apply(renderarray,places);
     if(draggedCheckin!=null) renderarray.push.apply(renderarray,draggedCheckin);
     if(streamedCheckin!=null)renderarray.push.apply(renderarray,streamedCheckin);
     $scope.places = renderarray;
 };

 function createJson(key,array){
    var json = [];
    for(var i=0;i<array.length;i++){
      var object = {
        name: array[i],
        value: true
      };
        json.push(object);
      }
    return json;
  }

var removecheckin = function (){
  var nowTime = new Date().getTime()/1000;
  if(streamedCheckin.length!=0){
    if(citysearched==streamedCheckin[0][10]){
      streamedCheckin[0][9] = 'src/assets/img/red_marker.png';
      searchedCheckinarray.push(streamedCheckin[0]);
      categoryarray[streamedCheckin[0][4]] = true;
      $scope.subjects = createJson(categoryarray,Object.keys(categoryarray));
    }
    for(var i=places.length+draggedCheckin.length,j=0;i<places.length+streamedCheckin.length+draggedCheckin.length;i++,j++){
      if(nowTime-renderarray[i][11]<5)
         break;
      if(nowTime-renderarray[i][11]>=5){
         renderarray.splice(i,1);
         streamedCheckin.splice(j,1);
      }
    }
      $scope.places = renderarray;
   }

    $scope.streamStatus = helper.getStatus(streamedCheckin.length);
    $scope.checkinfrequency = $scope.streamStatus.checkinfrequency;
    $scope.color = $scope.streamStatus.color;
    $scope.freqtext = $scope.streamStatus.freqtext;
    $scope.freqclass = $scope.streamStatus.freqclass;
      //No need $apply_solve
      // $scope.$digest();
      // $scope.$apply();
  }
  function closewindow(){
    var nowTime = new Date().getTime()/1000;
    for(var i=0;i<infowindowarray.length;i++){
      if(nowTime-infowindowarray[i][3]<3)
         break;
      if(nowTime-infowindowarray[i][3]>=3){
         var popup = infowindowarray[i][0]
         popup.close();
         index--;
         infowindowarray.splice(i,1);
      }
    }
  }

 $interval(removecheckin,5000);
 $interval(closewindow,3000);

});
<commit_msg>sets default zoom level to 3 - avoids map repition<commit_after>var myApp = angular.module('myApp', ['elasticsearch','ngMap']);

myApp.controller('viewcontroller',function ($scope, dataClient, esFactory, $interval, $window, $document, helper, $timeout) {

  var places = [],
      renderarray = [],
      categoryarray = [],
      streamedCheckin = [],
      searchedCheckinarray = [],
      draggedCheckin = [],
      infowindowarray= [],
      citysearched,
      index = 0,
      current_date = new Date().getTime()/1000;
      geocoder = new google.maps.Geocoder(),           //variable for geocoding
      infowindow = new google.maps.InfoWindow();      //variable for map infowindow

  $scope.activeContainer = '';

  $scope.init = function(){
      $scope.$on('mapInitialized', function(event, map) {
        $scope.mapobj = map;
        $scope.mapobj.setZoom(3);
        $scope.mapobj.setOptions({ minZoom: 2, maxZoom: 15 });
        $scope.mapobj.setCenter({lat: 0, lng: 0});
      });
      $scope.categoriesbox = false;
      $scope.checkinfrequency = "Count";
      $scope.freqtext = "";
      $scope.freqclass = "";
      $scope.inputcontainerHeight = { 'height': "5rem" };
      $('[data-toggle="popover"]').popover({
        placement:'right',
        html:true
      });
      $('[data-toggle="popover"]').mouseover(function() {
            $(this).popover('show');
        });
        $('[data-toggle="popover"]').mouseleave(function() {
            $(this).popover('hide');
      });
      $timeout(function(){
        var topHeight = $('#header').outerHeight() + 15;
        $('div[title="Zoom in"]').parents('.gmnoprint').addClass('zoomSet');
      },3000);
  };

  $scope.opencheckin = function(event,details){
   $window.open('https://'+details,'_blank');
  };

  $scope.changeCategory = function(sub){
    //sub.value = (sub.value==true ? false : true);
    $timeout(function(){
      $scope.showcategory(sub.name);
    },300);
  }

  $scope.showwindow = function(e,data,visible){
    for(var i=0;i<infowindowarray.length;i++){
      if(infowindowarray[i][1]==data[1] && infowindowarray[i][2]==data[2]){
        visible = false;
      }
    }
   if(visible){
      infowindow = new google.maps.InfoWindow();
      infowindow.setContent('

' + '' + '	' + '' + ''+ data[8] + ' says ' +'' + data[0] + '
Place : ' + data[7] + '

Visit this CheckIn

'+'
');
      var center = helper.getCenter($scope.mapobj.getZoom(), data);
      infowindow.setPosition(center);
      infowindow.setZIndex(2);
      infowindow.open($scope.mapobj);
      var current_date = new Date().getTime()/1000;
      infowindowarray[index] = [infowindow, data[1], data[2], current_date];
      index++;
    }
 };

  $scope.searchquerry = function(){
       try{
          //searchtext variable referred to the text in the search box
          if($scope.searchtext!=null && $scope.searchtext.replace(/\s/g,'').length){  //to check if search text is null
              $scope.activeContainer = 'active';
              var suggestClient = dataClient.getSuggestions($scope.searchtext);
              suggestClient.on('data',function (resp) {
                //$apply_solve
                $timeout(function(){
                  $scope.row = true;
                  $scope.categoriesbox = false;
                  $scope.suggestions = resp.suggest.mysuggester[0].options;
                },0);
              }).on('error',function (err) {
                  console.trace(err.message);
              });
          }else{
              $scope.suggestions = null;
              $scope.categoriesbox = false;
              $scope.row = false;
              $scope.activeContainer = '';
          }
      }catch(e){
          console.log('error in try'+e);
      }
  };

  $scope.changesearchtext = function(text){
       $scope.searchtext = text;
       $scope.row = false;
  }

  $scope.getData = function(){
    var searchClient = dataClient.getSearchCheckin(angular.lowercase($scope.searchtext));
    searchClient.on('data', function(res) {
        console.log(res);
        searchedCheckinarray = [];
        categoryarray = [];
        places = [];
        citysearched = angular.lowercase($scope.searchtext);
        $scope.row = false;    //to hide suggestions
        //No need $apply_solve
        //$scope.$apply();
        searchProcess(res);  //to fetch the data and to mark it on map
      }).on('error', function(err) {
        console.log("caught a stream error", err);
      });
  };

  function searchProcess (response){
    if($scope.searchtext!=null && $scope.searchtext.replace(/\s/g,'').length){
      $scope.categoriesbox = true;
      if(response.hits){
        var hit_length = response.hits.hits.length;
          var current_date =  new Date().getTime()/1000;
           for(var i=0;i<hit_length;i++){
            var current_hit = response.hits.hits[i];
            if (current_hit._source.category && current_hit._source.latitude && current_hit._source.longitude && current_hit._source.category) {
              categoryarray[current_hit._source.category] = true;
              var default_arr = helper.getMapArray(current_hit._source);
              var specific_arr = [
                'src/assets/img/red_marker.png',
                current_date
              ];
              var arr = default_arr.concat(specific_arr);
              searchedCheckinarray.push(arr);
            }
          }
       }
       //GeoCoding to search the city
       geocoder.geocode( { "address": $scope.searchtext }, function(results, status) {
         if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
           var location = results[0].geometry.location,
           latitude  = location.lat(),
           longitude  = location.lng();
           $scope.mapobj.setCenter({lat:latitude,lng:longitude});
           $scope.mapobj.setZoom(11);
           $scope.$apply();
         }
       });
       renderarray = [];
       places.push.apply(places,searchedCheckinarray);
       renderarray.push.apply(renderarray,searchedCheckinarray);
       if(draggedCheckin!=null) renderarray.push.apply(renderarray,draggedCheckin);
       if(streamedCheckin!=null) renderarray.push.apply(renderarray,streamedCheckin);
       $scope.places = renderarray;
       $scope.subjects = createJson(categoryarray,Object.keys(categoryarray));
       $scope.$digest();
       $scope.$apply();
       console.log($scope.places);
    }
 }

 var realtimeClient = dataClient.getliveData();
 realtimeClient.on('data', function(res) {
     streamProcess(res); //to fetch the data and to mark it on map
 }).on('error', function(err) {
   console.log("caught a stream error", err);
 });

 function streamProcess(response){
   if(response._source.latitude!=null && response._source.longitude!=null){
    var default_arr = helper.getMapArray(response._source);
    var specific_arr = [
      'src/assets/img/blue_marker.png',
      response._source.city,
      current_date
    ];
    var arr = default_arr.concat(specific_arr);

     streamedCheckin.push(arr);
     renderarray.push(arr);
     $scope.places = renderarray;

      $scope.streamStatus = helper.getStatus(streamedCheckin.length);
      $scope.checkinfrequency = $scope.streamStatus.checkinfrequency;
      $scope.color = $scope.streamStatus.color;
      $scope.freqtext = $scope.streamStatus.freqtext;
      $scope.freqclass = $scope.streamStatus.freqclass;

     $scope.$apply();
   }
 }

   $scope.draggedmap = function(){
     draggedCheckin = [];
     if($scope.mapobj.getZoom()>=5){
       var dragClient = dataClient.getDragData($scope.mapobj.getCenter().lat(),$scope.mapobj.getCenter().lng());
       dragClient.on('data', function(res) {
         dragProcess(res);  //to fetch the data and to mark it on map
       }).on('error', function(err) {
         console.log("caught a stream error", err);
       });
     }else if($scope.mapobj.getZoom()==4){
       draggedCheckin = [];
       renderarray = [];
       if(places!=null) renderarray.push.apply(renderarray,places);
       if(streamedCheckin!=null) renderarray.push.apply(renderarray,streamedCheckin);
       $scope.places = renderarray;
     }
   }

  function dragProcess(response){
     if(response.hits){
       for(var i=0;i<response.hits.hits.length;i++){
         if( response.hits.hits[i]._source){
           if(response.hits.hits[i]._source.latitude && response.hits.hits[i]._source.longitude){
             if(citysearched==response.hits.hits[i]._source.city)
             continue;
            var default_arr = helper.getMapArray(response.hits.hits[i]._source);
            var specific_arr = [
              'src/assets/img/orange_marker.png'
            ];
            var arr = default_arr.concat(specific_arr);

             draggedCheckin.push(arr);
           }
         }
       }
     }
     if(draggedCheckin.length!=0){
       renderarray = [];
       if(places!=null) renderarray.push.apply(renderarray,places);
       renderarray.push.apply(renderarray,draggedCheckin);
       if(streamedCheckin!=null) renderarray.push.apply(renderarray,streamedCheckin);
       $scope.places = renderarray;
       $scope.$digest();
       $scope.$apply();
     }
   }

 $scope.showcategory = function(data){
     places = [];
     if(categoryarray[data]==true) categoryarray[data]=false;
     else categoryarray[data]=true;
     for(var i=0;i<searchedCheckinarray.length;i++){
         if(categoryarray[searchedCheckinarray[i][4]] == true){
             var arr = [];
             for(var j=0;j<10;j++){
               arr[j] = searchedCheckinarray[i][j];
             }
             places.push(arr);
         }
     }
     renderarray = [];
     if(places!=null)renderarray.push.apply(renderarray,places);
     if(draggedCheckin!=null) renderarray.push.apply(renderarray,draggedCheckin);
     if(streamedCheckin!=null)renderarray.push.apply(renderarray,streamedCheckin);
     $scope.places = renderarray;
 };

 function createJson(key,array){
    var json = [];
    for(var i=0;i<array.length;i++){
      var object = {
        name: array[i],
        value: true
      };
        json.push(object);
      }
    return json;
  }

var removecheckin = function (){
  var nowTime = new Date().getTime()/1000;
  if(streamedCheckin.length!=0){
    if(citysearched==streamedCheckin[0][10]){
      streamedCheckin[0][9] = 'src/assets/img/red_marker.png';
      searchedCheckinarray.push(streamedCheckin[0]);
      categoryarray[streamedCheckin[0][4]] = true;
      $scope.subjects = createJson(categoryarray,Object.keys(categoryarray));
    }
    for(var i=places.length+draggedCheckin.length,j=0;i<places.length+streamedCheckin.length+draggedCheckin.length;i++,j++){
      if(nowTime-renderarray[i][11]<5)
         break;
      if(nowTime-renderarray[i][11]>=5){
         renderarray.splice(i,1);
         streamedCheckin.splice(j,1);
      }
    }
      $scope.places = renderarray;
   }

    $scope.streamStatus = helper.getStatus(streamedCheckin.length);
    $scope.checkinfrequency = $scope.streamStatus.checkinfrequency;
    $scope.color = $scope.streamStatus.color;
    $scope.freqtext = $scope.streamStatus.freqtext;
    $scope.freqclass = $scope.streamStatus.freqclass;
      //No need $apply_solve
      // $scope.$digest();
      // $scope.$apply();
  }
  function closewindow(){
    var nowTime = new Date().getTime()/1000;
    for(var i=0;i<infowindowarray.length;i++){
      if(nowTime-infowindowarray[i][3]<3)
         break;
      if(nowTime-infowindowarray[i][3]>=3){
         var popup = infowindowarray[i][0]
         popup.close();
         index--;
         infowindowarray.splice(i,1);
      }
    }
  }

 $interval(removecheckin,5000);
 $interval(closewindow,3000);

});
<|endoftext|>