<commit_before>L.PhotonBase = L.Class.extend({

    forEach: function (els, callback) {
        Array.prototype.forEach.call(els, callback);
    },

    ajax: function (callback, thisobj) {
        if (typeof this.xhr === 'object') {
            this.xhr.abort();
        }
        this.xhr = new XMLHttpRequest();
        var self = this;
        this.xhr.open('GET', this.options.url + this.buildQueryString(this.getParams()), true);

        this.xhr.onload = function(e) {
            self.fire('ajax:return');
            if (this.status === 200) {
                if (callback) {
                    var raw = this.response;
                    raw = JSON.parse(raw);
                    callback.call(thisobj || this, raw);
                }
            }
            delete this.xhr;
        };

        this.fire('ajax:send');
        this.xhr.send();
    },

    buildQueryString: function (params) {
        var queryString = [];
        for (var key in params) {
            if (params[key]) {
                queryString.push(encodeURIComponent(key) + '=' + encodeURIComponent(params[key]));
            }
        }
        return queryString.join('&');
    },

    featureToPopupContent: function (feature) {
        var container = L.DomUtil.create('div', 'leaflet-photon-popup'),
            title = L.DomUtil.create('h3', '', container);
        title.innerHTML = feature.properties.label;
        return container;
    }

});

L.PhotonSearch = L.PhotonBase.extend({

    includes: L.Mixin.Events,

    options: {
        url: 'http://photon.komoot.de/api/?',
        placeholder: 'Start typing...',
        minChar: 3,
        limit: 5,
        submitDelay: 300,
        includePosition: true,
        noResultLabel: 'No result',
        feedbackEmail: 'photon@komoot.de'  // Set to null to remove feedback box
    },

    CACHE: '',
    RESULTS: [],
    KEYS: {
        LEFT: 37,
        UP: 38,
        RIGHT: 39,
        DOWN: 40,
        TAB: 9,
        RETURN: 13,
        ESC: 27,
        APPLE: 91,
        SHIFT: 16,
        ALT: 17,
        CTRL: 18
    },

    initialize: function (map, input, options) {
        this.map = map;
        this.input = input;
        L.setOptions(this, options);
        var CURRENT = null;

        try {
            Object.defineProperty(this, 'CURRENT', {
                get: function () {
                    return CURRENT;
                },
                set: function (index) {
                    if (typeof index === 'object') {
                        index = this.resultToIndex(index);
                    }
                    CURRENT = index;
                }
            });
        } catch (e) {
            // Hello IE8
        }
        this.input.type = 'text';
        this.input.placeholder = this.options.placeholder;
        this.input.autocomplete = 'off';
        L.DomEvent.disableClickPropagation(this.input);

        L.DomEvent.on(this.input, 'keydown', this.onKeyDown, this);
        L.DomEvent.on(this.input, 'keyup', this.onKeyUp, this);
        L.DomEvent.on(this.input, 'blur', this.onBlur, this);
        L.DomEvent.on(this.input, 'focus', this.onFocus, this);
        this.createResultsContainer();
    },

    createResultsContainer: function () {
        this.resultsContainer = L.DomUtil.create('ul', 'photon-autocomplete', document.querySelector('body'));
    },

    resizeContainer: function()
    {
        var l = this.getLeft(this.input);
        var t = this.getTop(this.input) + this.input.offsetHeight;
        this.resultsContainer.style.left = l + 'px';
        this.resultsContainer.style.top = t + 'px';
        var width = this.options.width ? this.options.width : this.input.offsetWidth - 2;
        this.resultsContainer.style.width = width + 'px';
    },

    onKeyDown: function (e) {
        switch (e.keyCode) {
            case this.KEYS.TAB:
                if(this.CURRENT !== null)
                {
                    this.setChoice();
                }
                L.DomEvent.stop(e);
                break;
            case this.KEYS.RETURN:
                L.DomEvent.stop(e);
                this.setChoice();
                break;
            case this.KEYS.ESC:
                L.DomEvent.stop(e);
                this.hide();
                this.input.blur();
                break;
            case this.KEYS.DOWN:
                if(this.RESULTS.length > 0) {
                    if(this.CURRENT !== null && this.CURRENT < this.RESULTS.length - 1) { // what if one resutl?
                        this.CURRENT++;
                        this.highlight();
                    }
                    else if(this.CURRENT === null) {
                        this.CURRENT = 0;
                        this.highlight();
                    }
                }
                break;
            case this.KEYS.UP:
                if(this.CURRENT !== null) {
                    L.DomEvent.stop(e);
                }
                if(this.RESULTS.length > 0) {
                    if(this.CURRENT > 0) {
                        this.CURRENT--;
                        this.highlight();
                    }
                    else if(this.CURRENT === 0) {
                        this.CURRENT = null;
                        this.highlight();
                    }
                }
                break;
        }
    },

    onKeyUp: function (e) {
        var special = [
            this.KEYS.TAB,
            this.KEYS.RETURN,
            this.KEYS.LEFT,
            this.KEYS.RIGHT,
            this.KEYS.DOWN,
            this.KEYS.UP,
            this.KEYS.APPLE,
            this.KEYS.SHIFT,
            this.KEYS.ALT,
            this.KEYS.CTRL
        ];
        if (special.indexOf(e.keyCode) === -1)
        {
            if (typeof this.submitDelay === 'number') {
                window.clearTimeout(this.submitDelay);
                delete this.submitDelay;
            }
            this.submitDelay = window.setTimeout(L.Util.bind(this.search, this), this.options.submitDelay);
        }
    },

    onBlur: function (e) {
        this.fire('blur');
        var self = this;
        setTimeout(function () {
            self.hide();
        }, 100);
    },

    onFocus: function (e) {
        this.fire('focus');
        this.input.select();
    },

    clear: function () {
        this.RESULTS = [];
        this.CURRENT = null;
        this.CACHE = '';
        this.resultsContainer.innerHTML = '';
    },

    hide: function() {
        this.fire('hide');
        this.clear();
        this.resultsContainer.style.display = 'none';
    },

    setChoice: function (choice) {
        choice = choice || this.RESULTS[this.CURRENT];
        if (choice) {
            this.hide();
            this.input.value = '';
            this.fire('selected', {choice: choice.feature});
            this.onSelected(choice.feature);
        }
    },

    search: function() {
        var val = this.input.value;
        var minChar = typeof this.options.minChar === 'function' ? this.options.minChar(val) : val.length >= this.options.minChar;
        if (!val || !minChar) return this.clear();
        if(val + '' === this.CACHE + '') return;
        else this.CACHE = val;
        this._doSearch();
    },

    _doSearch: function () {
        this.ajax(this.handleResults, this);
    },

    _onSelected: function (feature) {
        this.map.setView([feature.geometry.coordinates[1], feature.geometry.coordinates[0]], 16);
    },

    onSelected: function (choice) {
        return (this.options.onSelected || this._onSelected).call(this, choice);
    },

    _formatResult: function (feature, el) {
        var title = L.DomUtil.create('strong', '', el),
            detailsContainer = L.DomUtil.create('small', '', el),
            details = [],
            type = this.formatType(feature);
        title.innerHTML = feature.properties.name;
        if (type) details.push(type);
        if (feature.properties.city && feature.properties.city !== feature.properties.name) {
            details.push(feature.properties.city);
        }
        if (feature.properties.country) details.push(feature.properties.country);
        detailsContainer.innerHTML = details.join(', ');
    },

    formatResult: function (feature, el) {
        return (this.options.formatResult || this._formatResult).call(this, feature, el);
    },

    formatType: function (feature) {
        return (this.options.formatType || this._formatType).call(this, feature);
    },

    _formatType: function (feature) {
        return feature.properties.osm_value;
    },

    createResult: function (feature) {
        var el = L.DomUtil.create('li', '', this.resultsContainer);
        this.formatResult(feature, el);
        var result = {
            feature: feature,
            el: el
        };
        // Touch handling needed
        L.DomEvent.on(el, 'mouseover', function (e) {
            this.CURRENT = result;
            this.highlight();
        }, this);
        L.DomEvent.on(el, 'mousedown', function (e) {
            this.setChoice();
        }, this);
        return result;
    },

    resultToIndex: function (result) {
        var out = null;
        this.forEach(this.RESULTS, function (item, index) {
            if (item === result) {
                out = index;
                return;
            }
        });
        return out;
    },

    handleResults: function(geojson) {
        var self = this;
        this.clear();
        this.resultsContainer.style.display = 'block';
        this.resizeContainer();
        this.forEach(geojson.features, function (feature) {
            self.RESULTS.push(self.createResult(feature));
        });
        if (geojson.features.length === 0) {
            var noresult = L.DomUtil.create('li', 'photon-no-result', this.resultsContainer);
            noresult.innerHTML = this.options.noResultLabel;
        }
        if (this.options.feedbackEmail) {
            var feedback = L.DomUtil.create('a', 'photon-feedback', this.resultsContainer);
            feedback.href = 'mailto:' + this.options.feedbackEmail;
            feedback.innerHTML = 'Feedback';
        }
        this.CURRENT = 0;
        this.highlight();
        if (this.options.resultsHandler) {
            this.options.resultsHandler(geojson);
        }
    },

    highlight: function () {
        var self = this;
        this.forEach(this.RESULTS, function (item, index) {
            if (index === self.CURRENT) {
                L.DomUtil.addClass(item.el, 'on');
            }
            else {
                L.DomUtil.removeClass(item.el, 'on');
            }
        });
    },

    getLeft: function (el) {
        var tmp = el.offsetLeft;
        el = el.offsetParent;
        while(el) {
            tmp += el.offsetLeft;
            el = el.offsetParent;
        }
        return tmp;
    },

    getTop: function (el) {
        var tmp = el.offsetTop;
        el = el.offsetParent;
        while(el) {
            tmp += el.offsetTop;
            el = el.offsetParent;
        }
        return tmp;
    },

    getParams: function () {
        return {
            q: this.CACHE,
            lang: this.options.lang,
            limit: this.options.limit,
            lat: this.options.includePosition ? this.map.getCenter().lat : null,
            lon: this.options.includePosition ? this.map.getCenter().lng : null
        };
    }

});

L.Control.Photon = L.Control.extend({

    includes: L.Mixin.Events,

    onAdd: function (map, options) {
        this.map = map;
        this.container = L.DomUtil.create('div', 'leaflet-photon');

        this.options = L.Util.extend(this.options, options);

        this.input = L.DomUtil.create('input', 'photon-input', this.container);
        this.search = new L.PhotonSearch(map, this.input, this.options);
        this.search.on('blur', this.forwardEvent, this);
        this.search.on('focus', this.forwardEvent, this);
        this.search.on('hide', this.forwardEvent, this);
        this.search.on('selected', this.forwardEvent, this);
        this.search.on('ajax:send', this.forwardEvent, this);
        this.search.on('ajax:return', this.forwardEvent, this);
        return this.container;
    },

    // TODO onRemove

    forwardEvent: function (e) {
        this.fire(e.type, e);
    }

});

L.Map.addInitHook(function () {
    if (this.options.photonControl) {
        this.photonControl = new L.Control.Photon(this.options.photonControlOptions || {});
        this.addControl(this.photonControl);
    }
});

L.PhotonReverse = L.PhotonBase.extend({

    includes: L.Mixin.Events,

    options: {
        url: 'http://photon.komoot.de/reverse/?',
        limit: 1,
        handleResults: null
    },

    initialize: function (options) {
        L.setOptions(this, options);
    },

    doReverse: function (latlng) {
        latlng = L.latLng(latlng);
        this.fire('reverse', {latlng: latlng});
        this.latlng = latlng;
        this.ajax(this.handleResults, this);
    },

    _handleResults: function (data) {
        /*eslint-disable no-console */
        console.log(data);
        /*eslint-enable no-alert */
    },

    handleResults: function (data) {
        return (this.options.handleResults || this._handleResults).call(this, data);
    },

    getParams: function () {
        return {
            lang: this.options.lang,
            limit: this.options.limit,
            lat: this.latlng.lat,
            lon: this.latlng.lng
        };
    }

});
<commit_msg>Use input instead of keyUp to trigger search<commit_after>L.PhotonBase = L.Class.extend({

    forEach: function (els, callback) {
        Array.prototype.forEach.call(els, callback);
    },

    ajax: function (callback, thisobj) {
        if (typeof this.xhr === 'object') {
            this.xhr.abort();
        }
        this.xhr = new XMLHttpRequest();
        var self = this;
        this.xhr.open('GET', this.options.url + this.buildQueryString(this.getParams()), true);

        this.xhr.onload = function(e) {
            self.fire('ajax:return');
            if (this.status === 200) {
                if (callback) {
                    var raw = this.response;
                    raw = JSON.parse(raw);
                    callback.call(thisobj || this, raw);
                }
            }
            delete this.xhr;
        };

        this.fire('ajax:send');
        this.xhr.send();
    },

    buildQueryString: function (params) {
        var queryString = [];
        for (var key in params) {
            if (params[key]) {
                queryString.push(encodeURIComponent(key) + '=' + encodeURIComponent(params[key]));
            }
        }
        return queryString.join('&');
    },

    featureToPopupContent: function (feature) {
        var container = L.DomUtil.create('div', 'leaflet-photon-popup'),
            title = L.DomUtil.create('h3', '', container);
        title.innerHTML = feature.properties.label;
        return container;
    }

});

L.PhotonSearch = L.PhotonBase.extend({

    includes: L.Mixin.Events,

    options: {
        url: 'http://photon.komoot.de/api/?',
        placeholder: 'Start typing...',
        minChar: 3,
        limit: 5,
        submitDelay: 300,
        includePosition: true,
        noResultLabel: 'No result',
        feedbackEmail: 'photon@komoot.de'  // Set to null to remove feedback box
    },

    CACHE: '',
    RESULTS: [],
    KEYS: {
        LEFT: 37,
        UP: 38,
        RIGHT: 39,
        DOWN: 40,
        TAB: 9,
        RETURN: 13,
        ESC: 27,
        APPLE: 91,
        SHIFT: 16,
        ALT: 17,
        CTRL: 18
    },

    initialize: function (map, input, options) {
        this.map = map;
        this.input = input;
        L.setOptions(this, options);
        var CURRENT = null;

        try {
            Object.defineProperty(this, 'CURRENT', {
                get: function () {
                    return CURRENT;
                },
                set: function (index) {
                    if (typeof index === 'object') {
                        index = this.resultToIndex(index);
                    }
                    CURRENT = index;
                }
            });
        } catch (e) {
            // Hello IE8
        }
        this.input.type = 'text';
        this.input.placeholder = this.options.placeholder;
        this.input.autocomplete = 'off';
        L.DomEvent.disableClickPropagation(this.input);

        L.DomEvent.on(this.input, 'keydown', this.onKeyDown, this);
        L.DomEvent.on(this.input, 'input', this.onInput, this);
        L.DomEvent.on(this.input, 'blur', this.onBlur, this);
        L.DomEvent.on(this.input, 'focus', this.onFocus, this);
        this.createResultsContainer();
    },

    createResultsContainer: function () {
        this.resultsContainer = L.DomUtil.create('ul', 'photon-autocomplete', document.querySelector('body'));
    },

    resizeContainer: function()
    {
        var l = this.getLeft(this.input);
        var t = this.getTop(this.input) + this.input.offsetHeight;
        this.resultsContainer.style.left = l + 'px';
        this.resultsContainer.style.top = t + 'px';
        var width = this.options.width ? this.options.width : this.input.offsetWidth - 2;
        this.resultsContainer.style.width = width + 'px';
    },

    onKeyDown: function (e) {
        switch (e.keyCode) {
            case this.KEYS.TAB:
                if(this.CURRENT !== null)
                {
                    this.setChoice();
                }
                L.DomEvent.stop(e);
                break;
            case this.KEYS.RETURN:
                L.DomEvent.stop(e);
                this.setChoice();
                break;
            case this.KEYS.ESC:
                L.DomEvent.stop(e);
                this.hide();
                this.input.blur();
                break;
            case this.KEYS.DOWN:
                if(this.RESULTS.length > 0) {
                    if(this.CURRENT !== null && this.CURRENT < this.RESULTS.length - 1) { // what if one resutl?
                        this.CURRENT++;
                        this.highlight();
                    }
                    else if(this.CURRENT === null) {
                        this.CURRENT = 0;
                        this.highlight();
                    }
                }
                break;
            case this.KEYS.UP:
                if(this.CURRENT !== null) {
                    L.DomEvent.stop(e);
                }
                if(this.RESULTS.length > 0) {
                    if(this.CURRENT > 0) {
                        this.CURRENT--;
                        this.highlight();
                    }
                    else if(this.CURRENT === 0) {
                        this.CURRENT = null;
                        this.highlight();
                    }
                }
                break;
        }
    },

    onInput: function (e) {
        if (typeof this.submitDelay === 'number') {
            window.clearTimeout(this.submitDelay);
            delete this.submitDelay;
        }
        this.submitDelay = window.setTimeout(L.Util.bind(this.search, this), this.options.submitDelay);
    },

    onBlur: function (e) {
        this.fire('blur');
        var self = this;
        setTimeout(function () {
            self.hide();
        }, 100);
    },

    onFocus: function (e) {
        this.fire('focus');
        this.input.select();
    },

    clear: function () {
        this.RESULTS = [];
        this.CURRENT = null;
        this.CACHE = '';
        this.resultsContainer.innerHTML = '';
    },

    hide: function() {
        this.fire('hide');
        this.clear();
        this.resultsContainer.style.display = 'none';
    },

    setChoice: function (choice) {
        choice = choice || this.RESULTS[this.CURRENT];
        if (choice) {
            this.hide();
            this.input.value = '';
            this.fire('selected', {choice: choice.feature});
            this.onSelected(choice.feature);
        }
    },

    search: function() {
        var val = this.input.value;
        var minChar = typeof this.options.minChar === 'function' ? this.options.minChar(val) : val.length >= this.options.minChar;
        if (!val || !minChar) return this.clear();
        if(val + '' === this.CACHE + '') return;
        else this.CACHE = val;
        this._doSearch();
    },

    _doSearch: function () {
        this.ajax(this.handleResults, this);
    },

    _onSelected: function (feature) {
        this.map.setView([feature.geometry.coordinates[1], feature.geometry.coordinates[0]], 16);
    },

    onSelected: function (choice) {
        return (this.options.onSelected || this._onSelected).call(this, choice);
    },

    _formatResult: function (feature, el) {
        var title = L.DomUtil.create('strong', '', el),
            detailsContainer = L.DomUtil.create('small', '', el),
            details = [],
            type = this.formatType(feature);
        title.innerHTML = feature.properties.name;
        if (type) details.push(type);
        if (feature.properties.city && feature.properties.city !== feature.properties.name) {
            details.push(feature.properties.city);
        }
        if (feature.properties.country) details.push(feature.properties.country);
        detailsContainer.innerHTML = details.join(', ');
    },

    formatResult: function (feature, el) {
        return (this.options.formatResult || this._formatResult).call(this, feature, el);
    },

    formatType: function (feature) {
        return (this.options.formatType || this._formatType).call(this, feature);
    },

    _formatType: function (feature) {
        return feature.properties.osm_value;
    },

    createResult: function (feature) {
        var el = L.DomUtil.create('li', '', this.resultsContainer);
        this.formatResult(feature, el);
        var result = {
            feature: feature,
            el: el
        };
        // Touch handling needed
        L.DomEvent.on(el, 'mouseover', function (e) {
            this.CURRENT = result;
            this.highlight();
        }, this);
        L.DomEvent.on(el, 'mousedown', function (e) {
            this.setChoice();
        }, this);
        return result;
    },

    resultToIndex: function (result) {
        var out = null;
        this.forEach(this.RESULTS, function (item, index) {
            if (item === result) {
                out = index;
                return;
            }
        });
        return out;
    },

    handleResults: function(geojson) {
        var self = this;
        this.clear();
        this.resultsContainer.style.display = 'block';
        this.resizeContainer();
        this.forEach(geojson.features, function (feature) {
            self.RESULTS.push(self.createResult(feature));
        });
        if (geojson.features.length === 0) {
            var noresult = L.DomUtil.create('li', 'photon-no-result', this.resultsContainer);
            noresult.innerHTML = this.options.noResultLabel;
        }
        if (this.options.feedbackEmail) {
            var feedback = L.DomUtil.create('a', 'photon-feedback', this.resultsContainer);
            feedback.href = 'mailto:' + this.options.feedbackEmail;
            feedback.innerHTML = 'Feedback';
        }
        this.CURRENT = 0;
        this.highlight();
        if (this.options.resultsHandler) {
            this.options.resultsHandler(geojson);
        }
    },

    highlight: function () {
        var self = this;
        this.forEach(this.RESULTS, function (item, index) {
            if (index === self.CURRENT) {
                L.DomUtil.addClass(item.el, 'on');
            }
            else {
                L.DomUtil.removeClass(item.el, 'on');
            }
        });
    },

    getLeft: function (el) {
        var tmp = el.offsetLeft;
        el = el.offsetParent;
        while(el) {
            tmp += el.offsetLeft;
            el = el.offsetParent;
        }
        return tmp;
    },

    getTop: function (el) {
        var tmp = el.offsetTop;
        el = el.offsetParent;
        while(el) {
            tmp += el.offsetTop;
            el = el.offsetParent;
        }
        return tmp;
    },

    getParams: function () {
        return {
            q: this.CACHE,
            lang: this.options.lang,
            limit: this.options.limit,
            lat: this.options.includePosition ? this.map.getCenter().lat : null,
            lon: this.options.includePosition ? this.map.getCenter().lng : null
        };
    }

});

L.Control.Photon = L.Control.extend({

    includes: L.Mixin.Events,

    onAdd: function (map, options) {
        this.map = map;
        this.container = L.DomUtil.create('div', 'leaflet-photon');

        this.options = L.Util.extend(this.options, options);

        this.input = L.DomUtil.create('input', 'photon-input', this.container);
        this.search = new L.PhotonSearch(map, this.input, this.options);
        this.search.on('blur', this.forwardEvent, this);
        this.search.on('focus', this.forwardEvent, this);
        this.search.on('hide', this.forwardEvent, this);
        this.search.on('selected', this.forwardEvent, this);
        this.search.on('ajax:send', this.forwardEvent, this);
        this.search.on('ajax:return', this.forwardEvent, this);
        return this.container;
    },

    // TODO onRemove

    forwardEvent: function (e) {
        this.fire(e.type, e);
    }

});

L.Map.addInitHook(function () {
    if (this.options.photonControl) {
        this.photonControl = new L.Control.Photon(this.options.photonControlOptions || {});
        this.addControl(this.photonControl);
    }
});

L.PhotonReverse = L.PhotonBase.extend({

    includes: L.Mixin.Events,

    options: {
        url: 'http://photon.komoot.de/reverse/?',
        limit: 1,
        handleResults: null
    },

    initialize: function (options) {
        L.setOptions(this, options);
    },

    doReverse: function (latlng) {
        latlng = L.latLng(latlng);
        this.fire('reverse', {latlng: latlng});
        this.latlng = latlng;
        this.ajax(this.handleResults, this);
    },

    _handleResults: function (data) {
        /*eslint-disable no-console */
        console.log(data);
        /*eslint-enable no-alert */
    },

    handleResults: function (data) {
        return (this.options.handleResults || this._handleResults).call(this, data);
    },

    getParams: function () {
        return {
            lang: this.options.lang,
            limit: this.options.limit,
            lat: this.latlng.lat,
            lon: this.latlng.lng
        };
    }

});
<|endoftext|>


<commit_before>/**
 * Created with JetBrains WebStorm.
 * User: mschwartz
 * Date: 6/23/13
 * Time: 9:30 AM
 * To change this template use File | Settings | File Templates.
 */

/** @module Collection */

/*global require, exports, Packages, toString */

/**
 * MongoDB Collection module
 */
"use strict";

importClass(com.mongodb.Mongo);
importClass(com.mongodb.jvm.BSON);

var {BasicDBObject} = Packages.com.mongodb,
    {Cursor} = require('Cursor'),
    BSON = com.mongodb.jvm.BSON,
// JSON converstion with support for MongoDB extended notation
    Json = com.threecrickets.jvm.json.JSON;

com.threecrickets.jvm.json.JSON.implementation = new com.mongodb.jvm.rhino.MongoRhinoJsonImplementation()
//    Json.implementation = new Packages.com.mongodb.jvm.rhino.MongoRhinoJsonImplementation();

function serialize( o ) {
//    o = BSON.to(o || {});
//    console.dir(o instanceof BasicDBObject);
//    return o;
//    return new BasicDBObject(BSON.to(o || {}));

    if ( o === undefined ) {
        return new BasicDBObject();
    }
o = Json.from(Json.to(o));
//    o = JSON.parse(Json.stringify(o));
    if ( toString.apply(o) === '[object Array]' ) {
        var a = [];
        decaf.each(o, function( oo ) {
            a.push(new BasicDBObject(oo));
        });
        return a;
    }
    return new BasicDBObject(o);
}

/**
 *
 * @param handle
 * @constructor
 */
function Collection( handle ) {
    this.handle = handle;
}

decaf.extend(Collection.prototype, {

    /**
     *
     * @param doc
     * @returns {*}
     */
    aggregate : function( doc ) {
        return this.handle.aggregate(serialize(doc));
    },

    /**
     *
     * @param query
     * @returns {*}
     */
    count : function( query ) {
        return query ? this.handle.count(serialize(query)) : this.handle.count();
    },

    /**
     *
     * @param keys
     * @param options
     * @returns {*}
     */
    createIndex : function( keys, options ) {
        console.warn('Collection.createIndex is deprecated since version 1.8');
        return this.handle.createIndex(serialize(keys), serialize(options));
    },

    /**
     *
     * @param index
     * @returns {*}
     */
    getIndexStats : function( index ) {
        return this.handle.getIndexStats(serialize(index));
    },

    /**
     *
     * @returns {Function|*|size|Number|Number|Number|string|string|InputStream.size|OutputStream.size|mimePart.size|number}
     */
    dataSize : function() {
        return this.handle.stats().size;
    },

    /**
     *
     * @param field
     * @param query
     * @returns {*}
     */
    distinct : function( field, query ) {
        return query ? this.handle.distinct(field, serialize(query)) : this.handle.distinct(field);
    },

    /**
     *
     * @returns {*}
     */
    drop : function() {
        return this.handle.drop();
    },

    /**
     *
     * @returns {*}
     */
    dropIndexes : function() {
        return this.handle.dropIndexes();
    },

    /**
     *
     * @param keys
     * @param options
     * @returns {*}
     */
    ensureIndex : function( keys, options ) {
        debugger;
        if ( options ) {
            return this.handle.createIndex(serialize(keys), serialize(options));
        }
        else {
            return this.handle.createIndex(serialize(keys));
        }

//        keys = serialize(keys);
//        if (options) {
//            options = serialize(options);
//            return this.handle.createIndex(keys, options);
//        }
//        else {
//            return this.handle.createIndex(keys);
//        }
//        return options ? this.handle.ensureIndex(serialize(keys), serialize(options)) : this.handle.ensureIndex(serialize(keys));
    },

    /**
     *
     * @param o
     * @returns {*}
     */
    insert : function( o ) {
        var bson = serialize(o);
//        o = serialize(o);
        var result = this.handle.insert(bson);
        debugger;
        return BSON.from(result.cachedLastError);
        return BSON.from(o); // JSON.parse(o);
    },

    /**
     *
     * @param o
     * @param projection
     * @returns {Packages.com.mongodb}
     */
    find : function( o, projection ) {
        return new Cursor(projection ? this.handle.find(serialize(o), serialize(projection)) : this.handle.find(serialize(o)));
    },

    /**
     *
     * @param o
     * @param projection
     * @returns {*}
     */
    findOne : function( o, projection ) {
        var result = projection ? this.handle.findOne(serialize(o), serialize(projection)) : this.handle.findOne(serialize(o));
        if ( !result ) {
            return false;
        }
        return BSON.from(result); // (result.toString()); // JSON.parse(result.toString());
    },

    /**
     *
     * @param config
     * @returns {*}
     */
    findAndModify : function( config ) {
        var query = serialize(config.query),
            update = serialize(config.update),
            sort = config.sort ? serialize(config.sort) : null,
            fields = config.fields ? serialize(config.fields) : null;

        return this.handle.findAndModify(query, fields, sort, config.remove || false, update, config.new || false, config.upsert || false);
    },

    /**
     *
     * @returns {*}
     */
    getIndexes : function() {
        return this.handle.getIndexes();
    },

    /**
     *
     * @param doc
     * @returns {*}
     */
    group : function( doc ) {
        return this.handle.group(serialize(doc));
    },

    /**
     *
     * @returns {*}
     */
    isCapped : function() {
        return this.handle.isCapped();
    },

    /**
     *
     * @returns {*}
     */
    mapReduce : function() {
        return this.handle.mapReduce(arguments);
    },

    /**
     *
     * @returns {*}
     */
    reIndex : function() {
        return this.handle.reIndex();
    },

    /**
     *
     * @param query
     * @returns {*}
     */
    remove : function( query ) {
        return this.handle.remove(serialize(query));
    },

    /**
     *
     * @param target
     * @param dropTarget
     * @returns {*}
     */
    renameCollection : function( target, dropTarget ) {
        return dropTarget ? this.handle.renameCollection(target, true) : this.handle.renameCollection(target);
    },

    /**
     *
     * @param o
     * @returns {*}
     */
    save : function( o ) {
        return this.handle.save(serialize(o));
    },

    /**
     *
     * @param scale
     * @returns {*}
     */
    stats : function( scale ) {
        return scale ? this.handle.stats(scale) : this.handle.stats();
    },

    /**
     *
     * @returns {Function}
     */
    storageSize : function() {
        return this.handle.stats().storageSize;
    },

    /**
     *
     * @returns {*}
     */
    totalSize : function() {
        var stats = this.stats();
        return stats.storageSize + stats.totalIndexSize;
    },

    /**
     *
     * @param query
     * @param update
     * @param options
     * @returns {*}
     */
    update : function( query, update, options ) {
        options = options || {};
        return this.handle.update(serialize(query), serialize(update), options.upsert || false, options.multi || false);
    },

    /**
     *
     * @param full
     * @returns {*}
     */
    validate : function( full ) {
        full = full || false;
        var db = this.handle.getDB(),
            name = this.handle.getName();

        return db.runCommand(serialize({ validate : name, full : full }));
    }

});

decaf.extend(exports, {
    Collection : Collection
});
<commit_msg>debug<commit_after>/**
 * Created with JetBrains WebStorm.
 * User: mschwartz
 * Date: 6/23/13
 * Time: 9:30 AM
 * To change this template use File | Settings | File Templates.
 */

/** @module Collection */

/*global require, exports, Packages, toString */

/**
 * MongoDB Collection module
 */
"use strict";

importClass(com.mongodb.Mongo);
importClass(com.mongodb.jvm.BSON);

var {BasicDBObject} = Packages.com.mongodb,
    {Cursor} = require('Cursor'),
    BSON = com.mongodb.jvm.BSON,
// JSON converstion with support for MongoDB extended notation
    Json = com.threecrickets.jvm.json.JSON;

com.threecrickets.jvm.json.JSON.implementation = new com.mongodb.jvm.rhino.MongoRhinoJsonImplementation()
//    Json.implementation = new Packages.com.mongodb.jvm.rhino.MongoRhinoJsonImplementation();

function serialize( o ) {
//    o = BSON.to(o || {});
//    console.dir(o instanceof BasicDBObject);
//    return o;
//    return new BasicDBObject(BSON.to(o || {}));

    if ( o === undefined ) {
        return new BasicDBObject();
    }
//o = Json.from(Json.to(o));
//    o = JSON.parse(Json.stringify(o));
    if ( toString.apply(o) === '[object Array]' ) {
        var a = [];
        decaf.each(o, function( oo ) {
            a.push(new BasicDBObject(oo));
        });
        return a;
    }
    return BSON.to(o);
//    return new BasicDBObject(o);
}

/**
 *
 * @param handle
 * @constructor
 */
function Collection( handle ) {
    this.handle = handle;
}

decaf.extend(Collection.prototype, {

    /**
     *
     * @param doc
     * @returns {*}
     */
    aggregate : function( doc ) {
        return this.handle.aggregate(serialize(doc));
    },

    /**
     *
     * @param query
     * @returns {*}
     */
    count : function( query ) {
        return query ? this.handle.count(serialize(query)) : this.handle.count();
    },

    /**
     *
     * @param keys
     * @param options
     * @returns {*}
     */
    createIndex : function( keys, options ) {
        console.warn('Collection.createIndex is deprecated since version 1.8');
        return this.handle.createIndex(serialize(keys), serialize(options));
    },

    /**
     *
     * @param index
     * @returns {*}
     */
    getIndexStats : function( index ) {
        return this.handle.getIndexStats(serialize(index));
    },

    /**
     *
     * @returns {Function|*|size|Number|Number|Number|string|string|InputStream.size|OutputStream.size|mimePart.size|number}
     */
    dataSize : function() {
        return this.handle.stats().size;
    },

    /**
     *
     * @param field
     * @param query
     * @returns {*}
     */
    distinct : function( field, query ) {
        return query ? this.handle.distinct(field, serialize(query)) : this.handle.distinct(field);
    },

    /**
     *
     * @returns {*}
     */
    drop : function() {
        return this.handle.drop();
    },

    /**
     *
     * @returns {*}
     */
    dropIndexes : function() {
        return this.handle.dropIndexes();
    },

    /**
     *
     * @param keys
     * @param options
     * @returns {*}
     */
    ensureIndex : function( keys, options ) {
        debugger;
        if ( options ) {
            return this.handle.ensureIndex(serialize(keys), serialize(options));
        }
        else {
            return this.handle.ensureIndex(serialize(keys));
        }

//        keys = serialize(keys);
//        if (options) {
//            options = serialize(options);
//            return this.handle.createIndex(keys, options);
//        }
//        else {
//            return this.handle.createIndex(keys);
//        }
//        return options ? this.handle.ensureIndex(serialize(keys), serialize(options)) : this.handle.ensureIndex(serialize(keys));
    },

    /**
     *
     * @param o
     * @returns {*}
     */
    insert : function( o ) {
        var bson = serialize(o);
//        o = serialize(o);
        var result = this.handle.insert(bson);
        debugger;
        return BSON.from(result.cachedLastError);
        return BSON.from(o); // JSON.parse(o);
    },

    /**
     *
     * @param o
     * @param projection
     * @returns {Packages.com.mongodb}
     */
    find : function( o, projection ) {
        return new Cursor(projection ? this.handle.find(serialize(o), serialize(projection)) : this.handle.find(serialize(o)));
    },

    /**
     *
     * @param o
     * @param projection
     * @returns {*}
     */
    findOne : function( o, projection ) {
        var result = projection ? this.handle.findOne(serialize(o), serialize(projection)) : this.handle.findOne(serialize(o));
        if ( !result ) {
            return false;
        }
        return BSON.from(result); // (result.toString()); // JSON.parse(result.toString());
    },

    /**
     *
     * @param config
     * @returns {*}
     */
    findAndModify : function( config ) {
        var query = serialize(config.query),
            update = serialize(config.update),
            sort = config.sort ? serialize(config.sort) : null,
            fields = config.fields ? serialize(config.fields) : null;

        return this.handle.findAndModify(query, fields, sort, config.remove || false, update, config.new || false, config.upsert || false);
    },

    /**
     *
     * @returns {*}
     */
    getIndexes : function() {
        return this.handle.getIndexes();
    },

    /**
     *
     * @param doc
     * @returns {*}
     */
    group : function( doc ) {
        return this.handle.group(serialize(doc));
    },

    /**
     *
     * @returns {*}
     */
    isCapped : function() {
        return this.handle.isCapped();
    },

    /**
     *
     * @returns {*}
     */
    mapReduce : function() {
        return this.handle.mapReduce(arguments);
    },

    /**
     *
     * @returns {*}
     */
    reIndex : function() {
        return this.handle.reIndex();
    },

    /**
     *
     * @param query
     * @returns {*}
     */
    remove : function( query ) {
        return this.handle.remove(serialize(query));
    },

    /**
     *
     * @param target
     * @param dropTarget
     * @returns {*}
     */
    renameCollection : function( target, dropTarget ) {
        return dropTarget ? this.handle.renameCollection(target, true) : this.handle.renameCollection(target);
    },

    /**
     *
     * @param o
     * @returns {*}
     */
    save : function( o ) {
        return this.handle.save(serialize(o));
    },

    /**
     *
     * @param scale
     * @returns {*}
     */
    stats : function( scale ) {
        return scale ? this.handle.stats(scale) : this.handle.stats();
    },

    /**
     *
     * @returns {Function}
     */
    storageSize : function() {
        return this.handle.stats().storageSize;
    },

    /**
     *
     * @returns {*}
     */
    totalSize : function() {
        var stats = this.stats();
        return stats.storageSize + stats.totalIndexSize;
    },

    /**
     *
     * @param query
     * @param update
     * @param options
     * @returns {*}
     */
    update : function( query, update, options ) {
        options = options || {};
        return this.handle.update(serialize(query), serialize(update), options.upsert || false, options.multi || false);
    },

    /**
     *
     * @param full
     * @returns {*}
     */
    validate : function( full ) {
        full = full || false;
        var db = this.handle.getDB(),
            name = this.handle.getName();

        return db.runCommand(serialize({ validate : name, full : full }));
    }

});

decaf.extend(exports, {
    Collection : Collection
});
<|endoftext|>


<commit_before>let async = require('async');

// TODO: make all of this async
class GethCommands {
  constructor(options) {
    this.config = options && options.hasOwnProperty('config') ? options.config : {};
    this.env = options && options.hasOwnProperty('env') ? options.env : 'development';
    this.name = "Go-Ethereum (https://github.com/ethereum/go-ethereum)";
    this.geth_bin = this.config.geth_bin || "geth";
  }

  commonOptions() {
    let config = this.config;
    let cmd = "";

    cmd += this.determineNetworkType(config);

    if (config.datadir) {
      cmd += "--datadir=\"" + config.datadir + "\" ";
    }

    if (config.light) {
      cmd += "--light ";
    }

    if (config.fast) {
      cmd += "--fast ";
    }

    if (config.account && config.account.password) {
      cmd += "--password " + config.account.password + " ";
    }

    return cmd;
  }

  determineVersion() {
    return this.geth_bin + " version";
  }

  determineNetworkType(config) {
    let cmd = "";
    if (config.networkType === 'testnet') {
      cmd += "--testnet ";
    } else if (config.networkType === 'olympic') {
      cmd += "--olympic ";
    } else if (config.networkType === 'rinkeby') {
      cmd += "--rinkeby ";
    } else if (config.networkType === 'custom') {
      cmd += "--networkid " + config.networkId + " ";
    }
    return cmd;
  }

  initGenesisCommmand() {
    let config = this.config;
    let cmd = this.geth_bin + " " + this.commonOptions();

    if (config.genesisBlock) {
      cmd += "init \"" + config.genesisBlock + "\" ";
    }

    return cmd;
  }

  newAccountCommand() {
    return this.geth_bin + " " + this.commonOptions() + "account new ";
  }

  listAccountsCommand() {
    return this.geth_bin + " " + this.commonOptions() + "account list ";
  }

  determineRpcOptions(config) {
    let cmd = "";

    cmd += "--port " + config.port + " ";
    cmd += "--rpc ";
    cmd += "--rpcport " + config.rpcPort + " ";
    cmd += "--rpcaddr " + config.rpcHost + " ";
    if (config.rpcCorsDomain) {
      if (config.rpcCorsDomain === '*') {
        console.log('==================================');
        console.log('rpcCorsDomain set to *');
        console.log('make sure you know what you are doing');
        console.log('==================================');
      }
      cmd += "--rpccorsdomain=\"" + config.rpcCorsDomain + "\" ";
    } else {
      console.log('==================================');
      console.log('warning: cors is not set');
      console.log('==================================');
    }

    return cmd;
  }

  determineWsOptions(config) {
    let cmd = "";

    if (config.wsRPC) {
      cmd += "--ws ";
      cmd += "--wsport " + config.wsPort + " ";
      cmd += "--wsaddr " + config.wsHost + " ";
      if (config.wsOrigins) {
        if (config.wsOrigins === '*') {
          console.log('==================================');
          console.log('rpcCorsDomain set to *');
          console.log('make sure you know what you are doing');
          console.log('==================================');
        }
        cmd += "--wsorigins \"" + config.wsOrigins + "\" ";
      } else {
        console.log('==================================');
        console.log('warning: cors is not set');
        console.log('==================================');
      }
    }

    return cmd;
  }

  mainCommand(address, done) {
    let self = this;
    let config = this.config;
    let rpc_api = (this.config.rpcApi || ['eth', 'web3', 'net']);
    let ws_api = (this.config.wsApi || ['eth', 'web3', 'net']);

    async.series([
      function commonOptions(callback) {
        let cmd = self.commonOptions();
        callback(null, cmd);
      },
      function rpcOptions(callback) {
        let cmd = self.determineRpcOptions(self.config);
        callback(null, cmd);
      },
      function wsOptions(callback) {
        let cmd = self.determineWsOptions(self.config);
        callback(null, cmd);
      },
      function dontGetPeers(callback) {
        if (config.nodiscover) {
          return callback(null, "--nodiscover");
        }
        callback(null, "");
      },
      function vmDebug(callback) {
        if (config.vmdebug) {
          return callback(null, "--vmdebug");
        }
        callback(null, "");
      },
      function maxPeers(callback) {
        let cmd = "--maxpeers " + config.maxpeers;
        callback(null, cmd);
      },
      function mining(callback) {
        if (config.mineWhenNeeded || config.mine) {
          return callback(null, "--mine ");
        }
        callback("");
      },
      function bootnodes(callback) {
        if (config.bootnodes && config.bootnodes !== "" && config.bootnodes !== []) {
          return callback(null, "--bootnodes " + config.bootnodes);
        }
        callback("");
      },
      function whisper(callback) {
        if (config.whisper) {
          rpc_api.push('shh');
          if (ws_api.indexOf('shh') === -1) {
            ws_api.push('shh');
          }
          return callback(null, "--shh ");
        }
        callback("");
      },
      function rpcApi(callback) {
        callback(null, '--rpcapi "' + rpc_api.join(',') + '"');
      },
      function wsApi(callback) {
        callback(null, '--wsapi "' + ws_api.join(',') + '"');
      },
      function accountToUnlock(callback) {
        let accountAddress = "";
        if(config.hasOwnProperty('address') && config.account.hasOwnProperty('address')) {
          accountAddress = config.account.address;
        } else {
          accountAddress = address;
        }
        if (accountAddress) {
          return callback(null, "--unlock=" + accountAddress);
        }
        callback(null, "");
      },
      function gasLimit(callback) {
        if (config.targetGasLimit) {
          return callback(null, "--targetgaslimit " + config.targetGasLimit);
        }
        callback(null, "");
      },
      function mineWhenNeeded(callback) {
        if (config.mineWhenNeeded) {
          return callback(null, "js .embark/" + self.env + "/js/mine.js");
        }
        callback(null, "");
      }
    ], function (err, results) {
      if (err) {
        throw new Error(err.message);
      }
      done(self.geth_bin + " " + results.join(" "));
    });
  }
}

module.exports = GethCommands;
<commit_msg>Revert "Add networkType rinkeby"<commit_after>let async = require('async');

// TODO: make all of this async
class GethCommands {
  constructor(options) {
    this.config = options && options.hasOwnProperty('config') ? options.config : {};
    this.env = options && options.hasOwnProperty('env') ? options.env : 'development';
    this.name = "Go-Ethereum (https://github.com/ethereum/go-ethereum)";
    this.geth_bin = this.config.geth_bin || "geth";
  }

  commonOptions() {
    let config = this.config;
    let cmd = "";

    cmd += this.determineNetworkType(config);

    if (config.datadir) {
      cmd += "--datadir=\"" + config.datadir + "\" ";
    }

    if (config.light) {
      cmd += "--light ";
    }

    if (config.fast) {
      cmd += "--fast ";
    }

    if (config.account && config.account.password) {
      cmd += "--password " + config.account.password + " ";
    }

    return cmd;
  }

  determineVersion() {
    return this.geth_bin + " version";
  }

  determineNetworkType(config) {
    let cmd = "";
    if (config.networkType === 'testnet') {
      cmd += "--testnet ";
    } else if (config.networkType === 'olympic') {
      cmd += "--olympic ";
    } else if (config.networkType === 'custom') {
      cmd += "--networkid " + config.networkId + " ";
    }
    return cmd;
  }

  initGenesisCommmand() {
    let config = this.config;
    let cmd = this.geth_bin + " " + this.commonOptions();

    if (config.genesisBlock) {
      cmd += "init \"" + config.genesisBlock + "\" ";
    }

    return cmd;
  }

  newAccountCommand() {
    return this.geth_bin + " " + this.commonOptions() + "account new ";
  }

  listAccountsCommand() {
    return this.geth_bin + " " + this.commonOptions() + "account list ";
  }

  determineRpcOptions(config) {
    let cmd = "";

    cmd += "--port " + config.port + " ";
    cmd += "--rpc ";
    cmd += "--rpcport " + config.rpcPort + " ";
    cmd += "--rpcaddr " + config.rpcHost + " ";
    if (config.rpcCorsDomain) {
      if (config.rpcCorsDomain === '*') {
        console.log('==================================');
        console.log('rpcCorsDomain set to *');
        console.log('make sure you know what you are doing');
        console.log('==================================');
      }
      cmd += "--rpccorsdomain=\"" + config.rpcCorsDomain + "\" ";
    } else {
      console.log('==================================');
      console.log('warning: cors is not set');
      console.log('==================================');
    }

    return cmd;
  }

  determineWsOptions(config) {
    let cmd = "";

    if (config.wsRPC) {
      cmd += "--ws ";
      cmd += "--wsport " + config.wsPort + " ";
      cmd += "--wsaddr " + config.wsHost + " ";
      if (config.wsOrigins) {
        if (config.wsOrigins === '*') {
          console.log('==================================');
          console.log('rpcCorsDomain set to *');
          console.log('make sure you know what you are doing');
          console.log('==================================');
        }
        cmd += "--wsorigins \"" + config.wsOrigins + "\" ";
      } else {
        console.log('==================================');
        console.log('warning: cors is not set');
        console.log('==================================');
      }
    }

    return cmd;
  }

  mainCommand(address, done) {
    let self = this;
    let config = this.config;
    let rpc_api = (this.config.rpcApi || ['eth', 'web3', 'net']);
    let ws_api = (this.config.wsApi || ['eth', 'web3', 'net']);

    async.series([
      function commonOptions(callback) {
        let cmd = self.commonOptions();
        callback(null, cmd);
      },
      function rpcOptions(callback) {
        let cmd = self.determineRpcOptions(self.config);
        callback(null, cmd);
      },
      function wsOptions(callback) {
        let cmd = self.determineWsOptions(self.config);
        callback(null, cmd);
      },
      function dontGetPeers(callback) {
        if (config.nodiscover) {
          return callback(null, "--nodiscover");
        }
        callback(null, "");
      },
      function vmDebug(callback) {
        if (config.vmdebug) {
          return callback(null, "--vmdebug");
        }
        callback(null, "");
      },
      function maxPeers(callback) {
        let cmd = "--maxpeers " + config.maxpeers;
        callback(null, cmd);
      },
      function mining(callback) {
        if (config.mineWhenNeeded || config.mine) {
          return callback(null, "--mine ");
        }
        callback("");
      },
      function bootnodes(callback) {
        if (config.bootnodes && config.bootnodes !== "" && config.bootnodes !== []) {
          return callback(null, "--bootnodes " + config.bootnodes);
        }
        callback("");
      },
      function whisper(callback) {
        if (config.whisper) {
          rpc_api.push('shh');
          if (ws_api.indexOf('shh') === -1) {
            ws_api.push('shh');
          }
          return callback(null, "--shh ");
        }
        callback("");
      },
      function rpcApi(callback) {
        callback(null, '--rpcapi "' + rpc_api.join(',') + '"');
      },
      function wsApi(callback) {
        callback(null, '--wsapi "' + ws_api.join(',') + '"');
      },
      function accountToUnlock(callback) {
        let accountAddress = "";
        if(config.hasOwnProperty('address') && config.account.hasOwnProperty('address')) {
          accountAddress = config.account.address;
        } else {
          accountAddress = address;
        }
        if (accountAddress) {
          return callback(null, "--unlock=" + accountAddress);
        }
        callback(null, "");
      },
      function gasLimit(callback) {
        if (config.targetGasLimit) {
          return callback(null, "--targetgaslimit " + config.targetGasLimit);
        }
        callback(null, "");
      },
      function mineWhenNeeded(callback) {
        if (config.mineWhenNeeded) {
          return callback(null, "js .embark/" + self.env + "/js/mine.js");
        }
        callback(null, "");
      }
    ], function (err, results) {
      if (err) {
        throw new Error(err.message);
      }
      done(self.geth_bin + " " + results.join(" "));
    });
  }
}

module.exports = GethCommands;
<|endoftext|>


<commit_before>!(function () {
    'use strict';

    /**
     * @ngdoc object
     * @name ng.$interpolateProvider
     * @function
     *
     * @description
     *
     * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
     *
     * @example
     <doc:example module="customInterpolationApp">
     <doc:source>

     //demo.label//

     </doc:source>
     <doc:scenario>
     it('should interpolate binding with custom symbols', function() {
      expect(binding('demo.label')).toBe('This binding is brought you by // interpolation symbols.');
     });
     </doc:scenario>
     </doc:example>
     */
    angular.module("rh.unwrapPromises", []).provider("$interpolate", function $InterpolateProvider($parseProvider) {
        var $interpolateMinErr = function () {
            var code = arguments[0],
                prefix = '[$interpolate:' + code + '] ',
                template = arguments[1],
                templateArgs = arguments,
                stringify = function (obj) {
                    if (angular.isFunction(obj)) {
                        return obj.toString().replace(/ \{[\s\S]*$/, '');
                    } else if (angular.isUndefined(obj)) {
                        return 'undefined';
                    } else if (!angular.isString(obj)) {
                        return JSON.stringify(obj);
                    }
                    return obj;
                },
                message, i;

            message = prefix + template.replace(/\{\d+\}/g, function (match) {
                var index = +match.slice(1, -1), arg;

                if (index + 2 < templateArgs.length) {
                    arg = templateArgs[index + 2];
                    if (angular.isFunction(arg)) {
                        return arg.toString().replace(/ ?\{[\s\S]*$/, '');
                    } else if (angular.isUndefined(arg)) {
                        return 'undefined';
                    } else if (!angular.isString(arg)) {
                        return angular.toJson(arg);
                    }
                    return arg;
                }
                return match;
            });

            message = message + '\nhttp://errors.angularjs.org/' + angular.version.full + '/' +
                '$interpolate/' + code;
            for (i = 2; i < arguments.length; i++) {
                message = message + (i == 2 ? '?' : '&') + 'p' + (i - 2) + '=' +
                    encodeURIComponent(stringify(arguments[i]));
            }

            return new Error(message);
        };

        var startSymbol = '{{',
            endSymbol = '}}',
            upStartSymbol = '{||', // up == unwrap promise
            upEndSymbol = '||}';

        /**
         * @ngdoc method
         * @name ng.$interpolateProvider#startSymbol
         * @methodOf ng.$interpolateProvider
         * @description
         * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
         *
         * @param {string=} value new value to set the starting symbol to.
         * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
         */
        this.startSymbol = function (value) {
            if (value) {
                startSymbol = value;
                return this;
            } else {
                return startSymbol;
            }
        };

        /**
         * @ngdoc method
         * @name ng.$interpolateProvider#startSymbol.unwrapPromises
         * @methodOf ng.$interpolateProvider
         * @description
         * Symbol to denote start of expression, with unwrapping promises enabled, in the interpolated string.
         * Defaults to `{||`.
         *
         * @param {string=} value new value to set the starting symbol to.
         * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
         */
        this.startSymbol.unwrapPromises = function (value) {
            if (value) {
                upStartSymbol = value;
                return this;
            } else {
                return upStartSymbol;
            }
        };

        /**
         * @ngdoc method
         * @name ng.$interpolateProvider#endSymbol
         * @methodOf ng.$interpolateProvider
         * @description
         * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
         *
         * @param {string=} value new value to set the ending symbol to.
         * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
         */
        this.endSymbol = function (value) {
            if (value) {
                endSymbol = value;
                return this;
            } else {
                return endSymbol;
            }
        };

        /**
         * @ngdoc method
         * @name ng.$interpolateProvider#endSymbol.unwrapPromises
         * @methodOf ng.$interpolateProvider
         * @description
         * Symbol to denote the end of expression, with unwrapping promises enabled, in the interpolated string.
         * Defaults to `||}`.
         *
         * @param {string=} value new value to set the ending symbol to.
         * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
         */
        this.endSymbol.unwrapPromises = function (value) {
            if (value) {
                upEndSymbol = value;
                return this;
            } else {
                return upEndSymbol;
            }
        };

        this.$get = ['$parse', '$exceptionHandler', '$sce', function ($parse, $exceptionHandler, $sce) {
            var startSymbolLength = startSymbol.length,
                endSymbolLength = endSymbol.length,
                upStartSymbolLength = upStartSymbol.length,
                upEndSymbolLength = upEndSymbol.length;

            /**
             * @ngdoc function
             * @name ng.$interpolate
             * @function
             *
             * @requires $parse
             * @requires $sce
             *
             * @description
             *
             * Compiles a string with markup into an interpolation function. This service is used by the
             * HTML {@link ng.$compile $compile} service for data binding. See
             * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
             * interpolation markup.
             *
             *

             var $interpolate = ...; // injected
             var exp = $interpolate('Hello {{name}}!');
             expect(exp({name:'Angular'}).toEqual('Hello Angular!');

             *
             *
             * @param {string} text The text with markup to interpolate.
             * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
             *    embedded expression in order to return an interpolation function. Strings with no
             *    embedded expression will return null for the interpolation function.
             * @param {string=} trustedContext when provided, the returned function passes the interpolated
             *    result through {@link ng.$sce#methods_getTrusted $sce.getTrusted(interpolatedResult,
             *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
             *    provides Strict Contextual Escaping for details.
             * @returns {function(context)} an interpolation function which is used to compute the
             *    interpolated string. The function has these parameters:
             *
             *    * `context`: an object against which any expressions embedded in the strings are evaluated
             *      against.
             *
             */
            function $interpolate(text, mustHaveExpression, trustedContext) {
                var startIndex,
                    endIndex,
                    index = 0,
                    parts = [],
                    length = text.length,
                    hasInterpolation = false,
                    fn,
                    exp,
                    concat = [];

                while (index < length) {
                    if (((startIndex = text.indexOf(startSymbol, index)) != -1) &&
                        ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1)) {
                        (index != startIndex) && interUnwrapPromise(text.substring(index, startIndex));
                        parts.push(fn = $parse(exp = text.substring(startIndex + startSymbolLength, endIndex)));
                        fn.exp = exp;
                        index = endIndex + endSymbolLength;
                        hasInterpolation = true;
                    } else {
                        // we did not find anything, so we have to add the remainder to the parts array
                        (index != length) && interUnwrapPromise(text.substring(index));
                        index = length;
                    }
                }

                function interUnwrapPromise(part) {
                    var startIndex, index = 0, length = part.length;
                    while (index < length) {
                        if (((startIndex = part.indexOf(upStartSymbol, index)) != -1) &&
                            ((endIndex = part.indexOf(upEndSymbol, startIndex + upStartSymbolLength)) != -1)) {
                            (index != startIndex) && parts.push(part.substring(index, startIndex));
                            parts.push(fn = parseUPExpr(exp = part.substring(startIndex + upStartSymbolLength, endIndex)));
                            fn.exp = exp;
                            index = endIndex + upEndSymbolLength;
                            hasInterpolation = true;
                        } else {
                            // we did not find anything, so we have to add the remainder to the parts array
                            (index != length) && parts.push(part.substring(index));
                            index = length;
                        }
                    }
                }

                function parseUPExpr(expr){
                    var exprFn,
                        origUP = $parseProvider.unwrapPromises(),
                        origLog = $parseProvider.logPromiseWarnings();
                    $parseProvider.unwrapPromises(true);
                    $parseProvider.logPromiseWarnings(false);
                    exprFn = $parse(expr);
                    $parseProvider.unwrapPromises(origUP);
                    $parseProvider.logPromiseWarnings(origLog);
                    return exprFn;
                }

                if (!(length = parts.length)) {
                    // we added, nothing, must have been an empty string.
                    parts.push('');
                    length = 1;
                }

                // Concatenating expressions makes it hard to reason about whether some combination of
                // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
                // single expression be used for iframe[src], object[src], etc., we ensure that the value
                // that's used is assigned or constructed by some JS code somewhere that is more testable or
                // make it obvious that you bound the value to some user controlled value.  This helps reduce
                // the load when auditing for XSS issues.
                if (trustedContext && parts.length > 1) {
                    throw $interpolateMinErr('noconcat',
                        "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
                            "interpolations that concatenate multiple expressions when a trusted value is " +
                            "required.  See http://docs.angularjs.org/api/ng.$sce", text);
                }

                if (!mustHaveExpression || hasInterpolation) {
                    concat.length = length;
                    fn = function (context) {
                        try {
                            for (var i = 0, ii = length, part; i < ii; i++) {
                                if (typeof (part = parts[i]) == 'function') {
                                    part = part(context);
                                    if (trustedContext) {
                                        part = $sce.getTrusted(trustedContext, part);
                                    } else {
                                        part = $sce.valueOf(part);
                                    }
                                    if (part === null || angular.isUndefined(part)) {
                                        part = '';
                                    } else if (typeof part != 'string') {
                                        part = angular.toJson(part);
                                    }
                                }
                                concat[i] = part;
                            }
                            return concat.join('');
                        }
                        catch (err) {
                            var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
                                err.toString());
                            $exceptionHandler(newErr);
                        }
                    };
                    fn.exp = text;
                    fn.parts = parts;
                    return fn;
                }
            }

            /**
             * @ngdoc method
             * @name ng.$interpolate#startSymbol
             * @methodOf ng.$interpolate
             * @description
             * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
             *
             * Use {@link ng.$interpolateProvider#startSymbol $interpolateProvider#startSymbol} to change
             * the symbol.
             *
             * @returns {string} start symbol.
             */
            $interpolate.startSymbol = function () {
                return startSymbol;
            };

            /**
             * @ngdoc method
             * @name ng.$interpolate#startSymbol.unwrapPromises
             * @methodOf ng.$interpolate
             * @description
             * Symbol to denote the start of expression, with unwrapping promises enabled, in the interpolated string.
             * Defaults to `{||`.
             *
             * Use {@link ng.$interpolateProvider#startSymbol.unwrapPromises $interpolateProvider#startSymbol.unwrapPromises}
             * to change the symbol.
             *
             * @returns {string} start symbol.
             */
            $interpolate.startSymbol.unwrapPromises = function () {
                return upStartSymbol;
            };

            /**
             * @ngdoc method
             * @name ng.$interpolate#endSymbol
             * @methodOf ng.$interpolate
             * @description
             * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
             *
             * Use {@link ng.$interpolateProvider#endSymbol $interpolateProvider#endSymbol} to change
             * the symbol.
             *
             * @returns {string} start symbol.
             */
            $interpolate.endSymbol = function () {
                return endSymbol;
            };

            /**
             * @ngdoc method
             * @name ng.$interpolate#endSymbol
             * @methodOf ng.$interpolate
             * @description
             * Symbol to denote the end of expression, with unwrapping promises enabled, in the interpolated string.
             * Defaults to `||}`.
             *
             * Use {@link ng.$interpolateProvider#endSymbol.unwrapPromises $interpolateProvider#endSymbol.unwrapPromises}
             * to change the symbol.
             *
             * @returns {string} start symbol.
             */
            $interpolate.endSymbol.unwrapPromises = function () {
                return upEndSymbol;
            };

            return $interpolate;
        }];
    })
    ;
}());<commit_msg>docs($interpolate): added note for new syntax defaults<commit_after>!(function () {
    'use strict';

    /**
     * @ngdoc object
     * @name ng.$interpolateProvider
     * @function
     *
     * @description
     *
     * Used for configuring the interpolation markup.
     * Defaults to `{{` and `}}`, as well as `{||` and `||}` for expression requiring promise unwrapping.
     *
     * @example
     <doc:example module="customInterpolationApp">
     <doc:source>

     //demo.label//

     </doc:source>
     <doc:scenario>
     it('should interpolate binding with custom symbols', function() {
      expect(binding('demo.label')).toBe('This binding is brought you by // interpolation symbols.');
     });
     </doc:scenario>
     </doc:example>
     */
    angular.module("rh.unwrapPromises", []).provider("$interpolate", function $InterpolateProvider($parseProvider) {
        var $interpolateMinErr = function () {
            var code = arguments[0],
                prefix = '[$interpolate:' + code + '] ',
                template = arguments[1],
                templateArgs = arguments,
                stringify = function (obj) {
                    if (angular.isFunction(obj)) {
                        return obj.toString().replace(/ \{[\s\S]*$/, '');
                    } else if (angular.isUndefined(obj)) {
                        return 'undefined';
                    } else if (!angular.isString(obj)) {
                        return JSON.stringify(obj);
                    }
                    return obj;
                },
                message, i;

            message = prefix + template.replace(/\{\d+\}/g, function (match) {
                var index = +match.slice(1, -1), arg;

                if (index + 2 < templateArgs.length) {
                    arg = templateArgs[index + 2];
                    if (angular.isFunction(arg)) {
                        return arg.toString().replace(/ ?\{[\s\S]*$/, '');
                    } else if (angular.isUndefined(arg)) {
                        return 'undefined';
                    } else if (!angular.isString(arg)) {
                        return angular.toJson(arg);
                    }
                    return arg;
                }
                return match;
            });

            message = message + '\nhttp://errors.angularjs.org/' + angular.version.full + '/' +
                '$interpolate/' + code;
            for (i = 2; i < arguments.length; i++) {
                message = message + (i == 2 ? '?' : '&') + 'p' + (i - 2) + '=' +
                    encodeURIComponent(stringify(arguments[i]));
            }

            return new Error(message);
        };

        var startSymbol = '{{',
            endSymbol = '}}',
            upStartSymbol = '{||', // up == unwrap promise
            upEndSymbol = '||}';

        /**
         * @ngdoc method
         * @name ng.$interpolateProvider#startSymbol
         * @methodOf ng.$interpolateProvider
         * @description
         * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
         *
         * @param {string=} value new value to set the starting symbol to.
         * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
         */
        this.startSymbol = function (value) {
            if (value) {
                startSymbol = value;
                return this;
            } else {
                return startSymbol;
            }
        };

        /**
         * @ngdoc method
         * @name ng.$interpolateProvider#startSymbol.unwrapPromises
         * @methodOf ng.$interpolateProvider
         * @description
         * Symbol to denote start of expression, with unwrapping promises enabled, in the interpolated string.
         * Defaults to `{||`.
         *
         * @param {string=} value new value to set the starting symbol to.
         * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
         */
        this.startSymbol.unwrapPromises = function (value) {
            if (value) {
                upStartSymbol = value;
                return this;
            } else {
                return upStartSymbol;
            }
        };

        /**
         * @ngdoc method
         * @name ng.$interpolateProvider#endSymbol
         * @methodOf ng.$interpolateProvider
         * @description
         * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
         *
         * @param {string=} value new value to set the ending symbol to.
         * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
         */
        this.endSymbol = function (value) {
            if (value) {
                endSymbol = value;
                return this;
            } else {
                return endSymbol;
            }
        };

        /**
         * @ngdoc method
         * @name ng.$interpolateProvider#endSymbol.unwrapPromises
         * @methodOf ng.$interpolateProvider
         * @description
         * Symbol to denote the end of expression, with unwrapping promises enabled, in the interpolated string.
         * Defaults to `||}`.
         *
         * @param {string=} value new value to set the ending symbol to.
         * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
         */
        this.endSymbol.unwrapPromises = function (value) {
            if (value) {
                upEndSymbol = value;
                return this;
            } else {
                return upEndSymbol;
            }
        };

        this.$get = ['$parse', '$exceptionHandler', '$sce', function ($parse, $exceptionHandler, $sce) {
            var startSymbolLength = startSymbol.length,
                endSymbolLength = endSymbol.length,
                upStartSymbolLength = upStartSymbol.length,
                upEndSymbolLength = upEndSymbol.length;

            /**
             * @ngdoc function
             * @name ng.$interpolate
             * @function
             *
             * @requires $parse
             * @requires $sce
             *
             * @description
             *
             * Compiles a string with markup into an interpolation function. This service is used by the
             * HTML {@link ng.$compile $compile} service for data binding. See
             * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
             * interpolation markup.
             *
             *

             var $interpolate = ...; // injected
             var exp = $interpolate('Hello {{name}}!');
             expect(exp({name:'Angular'}).toEqual('Hello Angular!');

             *
             *
             * @param {string} text The text with markup to interpolate.
             * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
             *    embedded expression in order to return an interpolation function. Strings with no
             *    embedded expression will return null for the interpolation function.
             * @param {string=} trustedContext when provided, the returned function passes the interpolated
             *    result through {@link ng.$sce#methods_getTrusted $sce.getTrusted(interpolatedResult,
             *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
             *    provides Strict Contextual Escaping for details.
             * @returns {function(context)} an interpolation function which is used to compute the
             *    interpolated string. The function has these parameters:
             *
             *    * `context`: an object against which any expressions embedded in the strings are evaluated
             *      against.
             *
             */
            function $interpolate(text, mustHaveExpression, trustedContext) {
                var startIndex,
                    endIndex,
                    index = 0,
                    parts = [],
                    length = text.length,
                    hasInterpolation = false,
                    fn,
                    exp,
                    concat = [];

                while (index < length) {
                    if (((startIndex = text.indexOf(startSymbol, index)) != -1) &&
                        ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1)) {
                        (index != startIndex) && interUnwrapPromise(text.substring(index, startIndex));
                        parts.push(fn = $parse(exp = text.substring(startIndex + startSymbolLength, endIndex)));
                        fn.exp = exp;
                        index = endIndex + endSymbolLength;
                        hasInterpolation = true;
                    } else {
                        // we did not find anything, so we have to add the remainder to the parts array
                        (index != length) && interUnwrapPromise(text.substring(index));
                        index = length;
                    }
                }

                function interUnwrapPromise(part) {
                    var startIndex, index = 0, length = part.length;
                    while (index < length) {
                        if (((startIndex = part.indexOf(upStartSymbol, index)) != -1) &&
                            ((endIndex = part.indexOf(upEndSymbol, startIndex + upStartSymbolLength)) != -1)) {
                            (index != startIndex) && parts.push(part.substring(index, startIndex));
                            parts.push(fn = parseUPExpr(exp = part.substring(startIndex + upStartSymbolLength, endIndex)));
                            fn.exp = exp;
                            index = endIndex + upEndSymbolLength;
                            hasInterpolation = true;
                        } else {
                            // we did not find anything, so we have to add the remainder to the parts array
                            (index != length) && parts.push(part.substring(index));
                            index = length;
                        }
                    }
                }

                function parseUPExpr(expr){
                    var exprFn,
                        origUP = $parseProvider.unwrapPromises(),
                        origLog = $parseProvider.logPromiseWarnings();
                    $parseProvider.unwrapPromises(true);
                    $parseProvider.logPromiseWarnings(false);
                    exprFn = $parse(expr);
                    $parseProvider.unwrapPromises(origUP);
                    $parseProvider.logPromiseWarnings(origLog);
                    return exprFn;
                }

                if (!(length = parts.length)) {
                    // we added, nothing, must have been an empty string.
                    parts.push('');
                    length = 1;
                }

                // Concatenating expressions makes it hard to reason about whether some combination of
                // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
                // single expression be used for iframe[src], object[src], etc., we ensure that the value
                // that's used is assigned or constructed by some JS code somewhere that is more testable or
                // make it obvious that you bound the value to some user controlled value.  This helps reduce
                // the load when auditing for XSS issues.
                if (trustedContext && parts.length > 1) {
                    throw $interpolateMinErr('noconcat',
                        "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
                            "interpolations that concatenate multiple expressions when a trusted value is " +
                            "required.  See http://docs.angularjs.org/api/ng.$sce", text);
                }

                if (!mustHaveExpression || hasInterpolation) {
                    concat.length = length;
                    fn = function (context) {
                        try {
                            for (var i = 0, ii = length, part; i < ii; i++) {
                                if (typeof (part = parts[i]) == 'function') {
                                    part = part(context);
                                    if (trustedContext) {
                                        part = $sce.getTrusted(trustedContext, part);
                                    } else {
                                        part = $sce.valueOf(part);
                                    }
                                    if (part === null || angular.isUndefined(part)) {
                                        part = '';
                                    } else if (typeof part != 'string') {
                                        part = angular.toJson(part);
                                    }
                                }
                                concat[i] = part;
                            }
                            return concat.join('');
                        }
                        catch (err) {
                            var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
                                err.toString());
                            $exceptionHandler(newErr);
                        }
                    };
                    fn.exp = text;
                    fn.parts = parts;
                    return fn;
                }
            }

            /**
             * @ngdoc method
             * @name ng.$interpolate#startSymbol
             * @methodOf ng.$interpolate
             * @description
             * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
             *
             * Use {@link ng.$interpolateProvider#startSymbol $interpolateProvider#startSymbol} to change
             * the symbol.
             *
             * @returns {string} start symbol.
             */
            $interpolate.startSymbol = function () {
                return startSymbol;
            };

            /**
             * @ngdoc method
             * @name ng.$interpolate#startSymbol.unwrapPromises
             * @methodOf ng.$interpolate
             * @description
             * Symbol to denote the start of expression, with unwrapping promises enabled, in the interpolated string.
             * Defaults to `{||`.
             *
             * Use {@link ng.$interpolateProvider#startSymbol.unwrapPromises $interpolateProvider#startSymbol.unwrapPromises}
             * to change the symbol.
             *
             * @returns {string} start symbol.
             */
            $interpolate.startSymbol.unwrapPromises = function () {
                return upStartSymbol;
            };

            /**
             * @ngdoc method
             * @name ng.$interpolate#endSymbol
             * @methodOf ng.$interpolate
             * @description
             * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
             *
             * Use {@link ng.$interpolateProvider#endSymbol $interpolateProvider#endSymbol} to change
             * the symbol.
             *
             * @returns {string} start symbol.
             */
            $interpolate.endSymbol = function () {
                return endSymbol;
            };

            /**
             * @ngdoc method
             * @name ng.$interpolate#endSymbol
             * @methodOf ng.$interpolate
             * @description
             * Symbol to denote the end of expression, with unwrapping promises enabled, in the interpolated string.
             * Defaults to `||}`.
             *
             * Use {@link ng.$interpolateProvider#endSymbol.unwrapPromises $interpolateProvider#endSymbol.unwrapPromises}
             * to change the symbol.
             *
             * @returns {string} start symbol.
             */
            $interpolate.endSymbol.unwrapPromises = function () {
                return upEndSymbol;
            };

            return $interpolate;
        }];
    })
    ;
}());<|endoftext|>


<commit_before>/**
 * Stores JSON data in a sorted set
 */
var _ = require('lodash');
var nodefn = require('when/node');
var IndexMixin = require('./index_mixin');

var MultiIndexMixin = _.extend({}, IndexMixin, {
  // indexProperties or indexKeys must be defined:
  // indexProperties: [{value: 'xx'}, {value: 'yy'}]
  // - used for replacing templated values in indexKey
  // unionKey: 'xx'
  // - key for storing set union temporarily

  // setup index keys,
  // this must be called before constructor which replaces tokens in indexKey
  setupIndexes: function(options) {
    if (!this.indexKeys && (!options.indexProperties || !_.isArray(options.indexProperties))) {
      throw new Error('indexProperties Array must be given as options');
    }
    if (!this.indexKeys) {
      this.indexKeys = [];
      _.each(options.indexProperties, function(prop) {
        this.indexKeys.push(this._replaceTemplatedVals(this.indexKey, prop));
      }, this);
    } else {
      this.indexKeys = _.map(this.indexKeys, function(key) {
        return this._replaceTemplatedVals(key, options);
      }, this);
    }
    this.unionKey = this._replaceTemplatedVals(this.unionKey, options);
  },

  // override readFromIndex to read from multiple indexes
  readFromIndex: function(options) {
    if (!this.indexDb) {
      throw new Error('indexDb must be defined');
    }
    if (!this.indexDb.readFromIndexes) {
      throw new Error('indexDb does not support reading from multiple indexes');
    }
    options = options ? _.clone(options) : {};
    options.indexKeys = this.indexKeys;
    if (this.indexKey && options.indexKeys.indexOf(this.indexKey) === -1) {
      options.indexKeys.push(this.indexKey);
    }
    options.unionKey = this.unionKey;
    var args = [this, options];
    return nodefn.apply(_.bind(this.indexDb.readFromIndexes, this.indexDb), args);
  }

});

module.exports = MultiIndexMixin;
<commit_msg>Added optional intersectionKey to MultiIndexMixin<commit_after>/**
 * Stores JSON data in a sorted set
 */
var _ = require('lodash');
var nodefn = require('when/node');
var IndexMixin = require('./index_mixin');

var MultiIndexMixin = _.extend({}, IndexMixin, {
  // indexProperties or indexKeys must be defined:
  // indexProperties: [{value: 'xx'}, {value: 'yy'}]
  // - used for replacing templated values in indexKey
  // unionKey: 'xx'
  // - key for storing set union temporarily

  // setup index keys,
  // this must be called before constructor which replaces tokens in indexKey
  setupIndexes: function(options) {
    if (!this.indexKeys && (!options.indexProperties || !_.isArray(options.indexProperties))) {
      throw new Error('indexProperties Array must be given as options');
    }
    if (!this.indexKeys) {
      this.indexKeys = [];
      _.each(options.indexProperties, function(prop) {
        this.indexKeys.push(this._replaceTemplatedVals(this.indexKey, prop));
      }, this);
    } else {
      this.indexKeys = _.map(this.indexKeys, function(key) {
        return this._replaceTemplatedVals(key, options);
      }, this);
    }
    this.unionKey = this._replaceTemplatedVals(this.unionKey, options);
  },

  // override readFromIndex to read from multiple indexes
  readFromIndex: function(options) {
    if (!this.indexDb) {
      throw new Error('indexDb must be defined');
    }
    if (!this.indexDb.readFromIndexes) {
      throw new Error('indexDb does not support reading from multiple indexes');
    }
    options = options ? _.clone(options) : {};
    options.indexKeys = this.indexKeys;
    if (this.indexKey && options.indexKeys.indexOf(this.indexKey) === -1) {
      options.indexKeys.push(this.indexKey);
    }
    options.unionKey = this.unionKey;
    options.intersectionKey = this.intersectionKey;
    var args = [this, options];
    return nodefn.apply(_.bind(this.indexDb.readFromIndexes, this.indexDb), args);
  }

});

module.exports = MultiIndexMixin;
<|endoftext|>