<commit_before>(function() {
    /** Utility functions
     *
     *  Note that these functions are only used inside Stapes, and therefore
     *  aren't that failsafe as the options in libraries
     *  such as Underscore.js, so that's why they're not usable outside
     *  the private scope.
     */
    var attributes = {},
        eventHandlers = {"-1" : {}},
        guid = 0;

    var util = {
        bind : function(fn, ctx) {
            return function() {
                return fn.apply(ctx, arguments);
            };
        },

        create : function(context, obj, newGuid) {
            var F = function(){};
            F.prototype = context;
            var instance = new F();

            if (obj) {
                instance.extend( obj );
            }

            if (newGuid) {
                instance._guid = guid++;
                attributes[instance._guid] = {};
                eventHandlers[instance._guid] = {};
            }

            return instance;
        },

        each : function(obj, fn) {
            for (var key in obj) {
                fn( obj[key], key );
            }
        },

        isArray : function(val) {
            return Object.prototype.toString.call( val ) === "[object Array]";
        },

        isObject : function(val) {
            return (typeof val === "object") && (!util.isArray(val) && val !== null);
        },

        // from http://stackoverflow.com/a/2117523/152809
        makeUuid : function() {
            return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
                var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
                return v.toString(16);
            });
        },

        toArray : function(arr) {
            return Array.prototype.slice.call(arr, 0);
        }
    };

    /** Private helper functions */
    function addEvent(event) {
        // If we don't have any handlers for this type of event, add a new
        // array we can use to push new handlers
        if (!eventHandlers[event.guid][event.type]) {
            eventHandlers[event.guid][event.type] = [];
        }

        // Push an event object
        eventHandlers[event.guid][event.type].push({
            "guid" : event.guid,
            "handler" : event.handler,
            "scope" : event.scope,
            "type" : event.type
        });
    }

    function addEventHandler(argTypeOrMap, argHandlerOrScope, argScope) {
        var eventMap = {},
            scope,
            guid = this._guid || -1;

        if (typeof argTypeOrMap === "string") {
            scope = argScope || false;
            eventMap[ argTypeOrMap ] = argHandlerOrScope;
        } else {
            scope = argHandlerOrScope || false;
            eventMap = argTypeOrMap;
        }

        for (var eventString in eventMap) {
            var handler = eventMap[ eventString ],
                events = eventString.split(" ");

            for (var i = 0, l = events.length; i < l; i++) {
                var eventType = events[i];

                addEvent.call(this, {
                    "guid" : guid,
                    "handler" : handler,
                    "scope" : scope,
                    "type" : eventType
                });
            }
        }
    }

    function emitEvents(type, data, explicitType, explicitGuid) {
        explicitType = explicitType || false;
        explicitGuid = explicitGuid || this._guid;

        util.each(eventHandlers[explicitGuid][type], function(event) {
            var scope = (event.scope) ? event.scope : this;
            if (explicitType) {
                event.type = explicitType;
            }
            event.scope = scope;
            event.handler.call(event.scope, data, event);
        });
    }

    function setAttribute(key, value) {
        // We need to do this before we actually add the item :)
        var itemExists = this.has(key);

        // Actually add the item to the attributes
        attributes[this._guid][key] = value;

        // Throw a generic event
        this.emit('change', key);

        // And a namespaced event as well, NOTE that we pass value instead of
        // key here!
        this.emit('change:' + key, value);

        // Also throw a specific event for this type of set
        var specificEvent = itemExists ? 'update' : 'create';

        this.emit(specificEvent, key);

        // And a namespaced event as well, NOTE that we pass value instead of key
        this.emit(specificEvent + ':' + key, value);
    }

    var Module = {
        create : function(obj) {
            return util.create(this, obj || false, true);
        },

        emit : function(types, data) {
            data = data || null;

            util.each(types.split(" "), util.bind(function(type) {
                // First 'all' type events: is there an 'all' handler in the
                // global stack?
                if (eventHandlers[-1].all) {
                    emitEvents.call(this, "all", data, type, -1);
                }

                // 'all' event for this specific module?
                if (eventHandlers[this._guid]["all"]) {
                    emitEvents.call(this, "all", data, type);
                }

                // Finally, normal events :)
                if (eventHandlers[this._guid][type]) {
                    emitEvents.call(this, type, data);
                }
            }, this));
        },

        extend : function(objectOrValues, valuesIfObject) {
            var object = (valuesIfObject) ? objectOrValues : this,
                values = (valuesIfObject) ? valuesIfObject : objectOrValues;

            util.each(values, function(value, key) {
                object[key] = value;
            });

            return this;
        },

        filter : function(fn) {
            var items = [];

            util.each(attributes[this._guid], function(item) {
                if (fn(item)) {
                    items.push(item);
                }
            });

            return items;
        },

        get : function(input) {
            if (typeof input === "string") {
                return this.has(input) ? attributes[this._guid][input] : null;
            } else if (typeof input === "function") {
                var items = this.filter(input);
                if (items.length) {
                    return items.length[0];
                }
            }
        },

        getAll : function() {
            return attributes[this._guid];
        },

        getAllAsArray : function() {
            var arr = [];

            util.each(attributes[this._guid], function(value, key) {
                if (util.isObject(value)) {
                    value.id = key;
                }

                arr.push(value);
            });

            return arr;

        },

        has : function(key) {
            return (typeof attributes[this._guid][key] !== "undefined");
        },

        init : function() {
            this.emit('ready');
            return this;
        },

        on : function() {
            addEventHandler.apply(this, arguments);
        },

        // Akin to set(), but makes a unique id
        push : function(input) {
            if (util.isArray(input)) {
                util.each(input, function(value) {
                    setAttribute.call(this, util.makeUuid(), value);
                });
            } else {
                setAttribute.call(this, util.makeUuid(), input);
            }
        },

        remove : function(input) {
            if (typeof input === "function") {
                util.each(attributes[this._guid], util.bind(function(item, key) {
                    if (input(item)) {
                        delete attributes[this._guid][key];
                        this.emit('delete change');
                    }
                }, this));
            } else {
                if (typeof input === "string") {
                    input = [input];
                }

                util.each(util.toArray(input), util.bind(function(id) {
                    if (this.has(id)) {
                        delete attributes[this._guid][id];
                        this.emit('delete change');
                    }
                }, this));
            }
        },

        set : function(objOrKey, value) {
            if (util.isObject(objOrKey)) {
                util.each(objOrKey, util.bind(function(value, key) {
                    setAttribute.call(this, key, value);
                }, this));
            } else {
                setAttribute.call(this, objOrKey, value);
            }
        },

        sub : function(obj) {
            return util.create(this, obj || false, false);
        },

        update : function(key, fn) {
            var item = this.get(key);
            fn(item);
            setAttribute.call(this, key, item);
        }
    };

    var Stapes = {
        "create" : function(obj) {
            return util.create(Module, obj || false, true);
        },

        "data" : function() {
            console.log(eventHandlers, attributes);
        },

        "extend" : function(obj) {
            util.each(obj, function(value, key) {
                Module[key] = value;
            });
        },

        "on" : function() {
            addEventHandler.apply(Module, arguments);
        }
    };

    // This library can be used as an AMD module, a Node.js module, or an
    // old fashioned global
    if (typeof exports !== "undefined") {
        // Server
        if (typeof module !== "undefined" && module.exports) {
            exports = module.exports = initalizer;
        }
        exports.Stapes = Stapes;
    } else if (typeof define === "function" && define.amd) {
        // AMD
        define(function() {
            return Stapes;
        });
    } else {
        // Global scope
        window.Stapes = Stapes;
    }
})();<commit_msg>fixing global events<commit_after>(function() {
    /** Utility functions
     *
     *  Note that these functions are only used inside Stapes, and therefore
     *  aren't that failsafe as the options in libraries
     *  such as Underscore.js, so that's why they're not usable outside
     *  the private scope.
     */
    var attributes = {},
        eventHandlers = {"-1" : {}},
        guid = 0;

    var util = {
        bind : function(fn, ctx) {
            return function() {
                return fn.apply(ctx, arguments);
            };
        },

        create : function(context, obj, newGuid) {
            var F = function(){};
            F.prototype = context;
            var instance = new F();

            if (obj) {
                instance.extend( obj );
            }

            if (newGuid) {
                instance._guid = guid++;
                attributes[instance._guid] = {};
                eventHandlers[instance._guid] = {};
            }

            return instance;
        },

        each : function(obj, fn) {
            for (var key in obj) {
                fn( obj[key], key );
            }
        },

        isArray : function(val) {
            return Object.prototype.toString.call( val ) === "[object Array]";
        },

        isObject : function(val) {
            return (typeof val === "object") && (!util.isArray(val) && val !== null);
        },

        // from http://stackoverflow.com/a/2117523/152809
        makeUuid : function() {
            return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
                var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
                return v.toString(16);
            });
        },

        toArray : function(arr) {
            return Array.prototype.slice.call(arr, 0);
        }
    };

    /** Private helper functions */
    function addEvent(event) {
        // If we don't have any handlers for this type of event, add a new
        // array we can use to push new handlers
        if (!eventHandlers[event.guid][event.type]) {
            eventHandlers[event.guid][event.type] = [];
        }

        // Push an event object
        eventHandlers[event.guid][event.type].push({
            "guid" : event.guid,
            "handler" : event.handler,
            "scope" : event.scope,
            "type" : event.type
        });
    }

    function addEventHandler(argTypeOrMap, argHandlerOrScope, argScope) {
        var eventMap = {},
            scope,
            guid = this._guid || -1;

        if (typeof argTypeOrMap === "string") {
            scope = argScope || false;
            eventMap[ argTypeOrMap ] = argHandlerOrScope;
        } else {
            scope = argHandlerOrScope || false;
            eventMap = argTypeOrMap;
        }

        for (var eventString in eventMap) {
            var handler = eventMap[ eventString ],
                events = eventString.split(" ");

            for (var i = 0, l = events.length; i < l; i++) {
                var eventType = events[i];

                addEvent.call(this, {
                    "guid" : guid,
                    "handler" : handler,
                    "scope" : scope,
                    "type" : eventType
                });
            }
        }
    }

    function emitEvents(type, data, explicitType, explicitGuid) {
        explicitType = explicitType || false;
        explicitGuid = explicitGuid || this._guid;

        util.each(eventHandlers[explicitGuid][type], util.bind(function(event) {
            var scope = (event.scope) ? event.scope : this;
            if (explicitType) {
                event.type = explicitType;
            }
            event.scope = scope;
            event.handler.call(event.scope, data, event);
        }, this));
    }

    function setAttribute(key, value) {
        // We need to do this before we actually add the item :)
        var itemExists = this.has(key);

        // Actually add the item to the attributes
        attributes[this._guid][key] = value;

        // Throw a generic event
        this.emit('change', key);

        // And a namespaced event as well, NOTE that we pass value instead of
        // key here!
        this.emit('change:' + key, value);

        // Also throw a specific event for this type of set
        var specificEvent = itemExists ? 'update' : 'create';

        this.emit(specificEvent, key);

        // And a namespaced event as well, NOTE that we pass value instead of key
        this.emit(specificEvent + ':' + key, value);
    }

    var Module = {
        create : function(obj) {
            return util.create(this, obj || false, true);
        },

        emit : function(types, data) {
            data = data || null;

            util.each(types.split(" "), util.bind(function(type) {
                // First 'all' type events: is there an 'all' handler in the
                // global stack?
                if (eventHandlers[-1].all) {
                    emitEvents.call(this, "all", data, type, -1);
                }

                // Catch all events for this type?
                if (eventHandlers[-1][type]) {
                    emitEvents.call(this, type, data, type, -1);
                }

                // 'all' event for this specific module?
                if (eventHandlers[this._guid]["all"]) {
                    emitEvents.call(this, "all", data, type);
                }

                // Finally, normal events :)
                if (eventHandlers[this._guid][type]) {
                    emitEvents.call(this, type, data);
                }
            }, this));
        },

        extend : function(objectOrValues, valuesIfObject) {
            var object = (valuesIfObject) ? objectOrValues : this,
                values = (valuesIfObject) ? valuesIfObject : objectOrValues;

            util.each(values, function(value, key) {
                object[key] = value;
            });

            return this;
        },

        filter : function(fn) {
            var items = [];

            util.each(attributes[this._guid], function(item) {
                if (fn(item)) {
                    items.push(item);
                }
            });

            return items;
        },

        get : function(input) {
            if (typeof input === "string") {
                return this.has(input) ? attributes[this._guid][input] : null;
            } else if (typeof input === "function") {
                var items = this.filter(input);
                if (items.length) {
                    return items.length[0];
                }
            }
        },

        getAll : function() {
            return attributes[this._guid];
        },

        getAllAsArray : function() {
            var arr = [];

            util.each(attributes[this._guid], function(value, key) {
                if (util.isObject(value)) {
                    value.id = key;
                }

                arr.push(value);
            });

            return arr;

        },

        has : function(key) {
            return (typeof attributes[this._guid][key] !== "undefined");
        },

        init : function() {
            this.emit('ready');
            return this;
        },

        on : function() {
            addEventHandler.apply(this, arguments);
        },

        // Akin to set(), but makes a unique id
        push : function(input) {
            if (util.isArray(input)) {
                util.each(input, function(value) {
                    setAttribute.call(this, util.makeUuid(), value);
                });
            } else {
                setAttribute.call(this, util.makeUuid(), input);
            }
        },

        remove : function(input) {
            if (typeof input === "function") {
                util.each(attributes[this._guid], util.bind(function(item, key) {
                    if (input(item)) {
                        delete attributes[this._guid][key];
                        this.emit('delete change');
                    }
                }, this));
            } else {
                if (typeof input === "string") {
                    input = [input];
                }

                util.each(util.toArray(input), util.bind(function(id) {
                    if (this.has(id)) {
                        delete attributes[this._guid][id];
                        this.emit('delete change');
                    }
                }, this));
            }
        },

        set : function(objOrKey, value) {
            if (util.isObject(objOrKey)) {
                util.each(objOrKey, util.bind(function(value, key) {
                    setAttribute.call(this, key, value);
                }, this));
            } else {
                setAttribute.call(this, objOrKey, value);
            }
        },

        sub : function(obj) {
            return util.create(this, obj || false, false);
        },

        update : function(key, fn) {
            var item = this.get(key);
            fn(item);
            setAttribute.call(this, key, item);
        }
    };

    var Stapes = {
        "create" : function(obj) {
            return util.create(Module, obj || false, true);
        },

        "data" : function() {
            console.log(eventHandlers, attributes);
        },

        "extend" : function(obj) {
            util.each(obj, function(value, key) {
                Module[key] = value;
            });
        },

        "on" : function() {
            addEventHandler.apply(Module, arguments);
        }
    };

    // This library can be used as an AMD module, a Node.js module, or an
    // old fashioned global
    if (typeof exports !== "undefined") {
        // Server
        if (typeof module !== "undefined" && module.exports) {
            exports = module.exports = initalizer;
        }
        exports.Stapes = Stapes;
    } else if (typeof define === "function" && define.amd) {
        // AMD
        define(function() {
            return Stapes;
        });
    } else {
        // Global scope
        window.Stapes = Stapes;
    }
})();<|endoftext|>


<commit_before>
const _filter = (complexFieldValue, filterFunc) => {
	let ret = [];
	if (complexFieldValue instanceof Array){
		let ret = [];
		return complexFieldValue.filter(_itm => {
			if (filterFunc(_itm)) ret.push(_itm);
		})
		return ret;
	}
	return filterFunc(complexFieldValue) ? complexFieldValue : undefined;
}

const pseudos = {

	"empty" : function(complexFieldValue){
		return _filter(complexFieldValue, (a)=>{
			return (typeof a !== 'object')
		});
	}

}

module.exports = { pseudos };
<commit_msg>add config<commit_after>//
//remember that
//	value is always not-array (may be object)
//
const pseudo = {

	"empty" : function(value){
		if (typeof value !== 'object') return value;
	}

}

module.exports = { pseudo };
<|endoftext|>


<commit_before>function setDimension(type, name, id) {
    if ($('#'+type).siblings('input').val() != id) {
        $('#'+type).html(name);
        $('#dimensions input[name='+type+']').val(id).trigger('change');
    }
}

dataviva.requireAttrs(['datasets', 'bra', 'cnae', 'cbo', 'course_sc', 'course_hedu', 'university'], function() {
    //dataviva.attrs.datasets
    //setDimension(type, name, id)
});

var selectorGraphs = Selector()
    .callback(function(d){
        setDimension(selectorGraphs.type(), d.name, d.id)
        $('#modal-selector').modal('hide');
    });

function select_dimension(id) {
    d3.select("#modal-selector-content").call(selectorGraphs.type(id));
    $('#modal-selector').modal('show');
}

var selectorCompare = Selector()
    .callback(function(d){
        if ($('#compare_with').siblings('input').val() != d.id) {
            $('#compare_with').html(d.name);
            $('#compare-location input[name=compare_with]').val(d.id).trigger('change');
            BuildGraph.compare = d.id;
        }
        BuildGraph.setCompare();
        $('#modal-selector').modal('hide');
    });

function select_compare() {
    d3.select("#modal-selector-content").call(selectorCompare.type('bra'));
    $('#modal-selector').modal('show');
}

function clean_selection(id) {
    if ($(id).siblings('input').val() != 'all') {
        $(id).html(dataviva.dictionary['select']);
        $(id).siblings('input').val('all').trigger('change');
    }
}

var BuildGraph = (function () {

    return {
        dataset: dataset,
        views: views,
        selectedView: selectedView,
        selectedGraph: selectedGraph,
        setCompare: setCompare,
        init: init,
        fillForm: fillForm
    }

    var selectedGraph, selectedView, dataset, views;

    function changeDataSet() {
        $('#datasets #dataset-empty-option').remove();
        BuildGraph.dataset = this.value;
        setDimensions(dataviva.datasets[this.value].dimensions);
        updateViews();
    }

    function setDimensions(dimensions) {
        $('#dimensions').empty();
        dimensions.forEach(function(dimension, index) {
            var div = $('

').addClass('form-group'),
                filter = $('<input></input>').attr('type', 'hidden').attr('name', dimension.id).attr('id', 'filter'+index).val('all'),
                label = $('').attr('for', dimension.id).addClass('control-label'),
                selector = $('<button></button>').attr('id', dimension.id).addClass('btn btn-block btn-outline btn-primary')
                                        .html(dataviva.dictionary['select'])
                                        .attr('onclick', 'select_dimension(id);'),
                cleaner = $('<button></button>').attr('for', dimension.id).addClass('btn btn-xs btn-link pull-right')
                                        .html(dataviva.dictionary['clean_selection'])
                                        .attr('onclick', 'clean_selection('+dimension.id+')');

            label.html(dataviva.dictionary[dimension.id]);
            filter.change(updateViews);

            if (dimension.name == 'School') {
                div.append(filter);
            } else {
                div.append(filter).append(label).append(selector).append(cleaner);
            }

            $('#dimensions').append(div);
        });
    }

    function updateViews() {
        $.ajax({
            method: "GET",
            url: "/" + dataviva.language + "/build_graph/views/" + BuildGraph.dataset +"/" +
                $('#dimensions #filter0').val() +
                ($('#compare-location input[name=compare_with]').val() ? '_' + $('#compare-location input[name=compare_with]').val() : '') + "/" +
                ($('#dimensions #filter1').val() == 'all' ? 'all' : $('#dimensions #filter1')[0].name) + "/" +
                ($('#dimensions #filter2').val() == 'all' ? 'all' : $('#dimensions #filter2')[0].name),
            data: {
                    filter1: $('#dimensions #filter1').val(),
                    filter2: $('#dimensions #filter2').val()
                },
            success: function (result) {
                setViews(result.views);
            }
        });
    }

    function setViews(views) {
        BuildGraph.views = views;
        $('#views').empty()

        var div = $('

').addClass('form-group');
            select = $('<select></select>').addClass('form-control'),
            label = $('').attr('for', 'titles').addClass('control-label'),

        label.html(dataviva.dictionary['views']);

        for(id in views){
            var option = $('<option value="'+id+'">'+views[id].name+'</option>');
            select.append(option);
        }

        select.change(function() {
            BuildGraph.selectedView = this.value;
            setGraphs(BuildGraph.views[this.value].graphs);
        });

        div.append(label).append(select);
        $('#views').append(div);

        // Try to keep the selected view, else keep whatever comes selected
        if ($.inArray(BuildGraph.selectedView, Object.keys(views)) > -1) {
            $('#views select').val(BuildGraph.selectedView);
        } else {
            BuildGraph.selectedView = views[$('#views select').val()].id;
        }

        setGraphs(views[BuildGraph.selectedView].graphs);
    }

    function setGraphs(graphs) {
        $('#graphs').empty()

        var div = $('

').attr('class', 'dropdown dropdown-select form-group');
            graphButton = $('<button data-toggle="dropdown" aria-expanded="true"></button>')
                            .attr('id', 'selected-graph')
                            .attr('class', 'btn btn-outline btn-block dropdown-toggle'),
            dropDownMenu = $('

')
                            .attr('class', 'dropdown-menu'),
            label = $('').attr('for', 'selected-graph').addClass('control-label');

        label.html(dataviva.dictionary['graphs']);

        for(id in graphs){
            var graphLink = $('')
                            .attr('id', id)
                            .attr('class', 'graph-link')
                            .data('url', "/" + dataviva.language + '/embed/' + graphs[id].url)
                            .html('' + graphs[id].name);

            var graphOption = $('

').append(graphLink);

            dropDownMenu.append(graphOption);
        }

        div.on( 'click', '.dropdown-menu li a', function(argument) {
           selectGraph(this);
        });

        div.append(label).append(graphButton).append(dropDownMenu);

        $('#graphs').append(div);

        // Try to keep the selected graph, else select the first graph
        if ($.inArray(BuildGraph.selectedGraph, Object.keys(graphs)) > -1) {
            selectGraph($('#'+BuildGraph.selectedGraph));
        } else {
            BuildGraph.selectedGraph = $('#selected-graph').data('graph');
            selectGraph($('#selected-graph').siblings('.dropdown-menu').find('li a').first());
        }
    }

    function selectGraph(graph) {
        BuildGraph.selectedGraph = $(graph).attr('id');

        var graphName = $(graph).html();

        //Adds active class to selected item
        $(graph).parents('.dropdown-menu').find('li').removeClass('active');
        $(graph).parent('li').addClass('active');

        //Displays selected text on dropdown-toggle button
        $('#selected-graph').data('graph', $(graph).attr('id'));
        $('#selected-graph').html(graphName);

        if (BuildGraph.selectedGraph == 'compare') {
            setCompare();
        } else {
            $('#compare-location').empty();
            delete BuildGraph.compare;
            $('#graph-wrapper').html('');
        }
    }

    function setCompare(){
        if (BuildGraph.compare) {
            $('#graph-wrapper').html('');
        } else {
            $('#compare-location').empty();

            var div = $('

').addClass('form-group'),
                label = $('').attr('for', 'compare_with').addClass('control-label'),
                cleaner = $('<button></button>').attr('for', 'compare_with').addClass('btn btn-xs btn-link pull-right')
                                        .html(dataviva.dictionary['clean_selection'])
                                        .attr('onclick', 'clean_selection('+'compare_with'+')'),
                selector = $('<button></button>').attr('id', 'compare_with').addClass('btn btn-block btn-outline btn-primary')
                                        .html(dataviva.dictionary['select'])
                                        .attr('onclick', 'select_compare();'),
                filter = $('<input></input>').attr('type', 'hidden').attr('name', 'compare_with').attr('id', 'compare_filter').val('all');

            label.html(dataviva.dictionary['compare_with']);
            filter.change(updateViews);

            div.append(filter).append(label).append(selector).append(cleaner);

            $('#compare-location').append(div);
        }
    }

    function init() {
        for (dataset in dataviva.datasets) {
            $('#datasets').append( $('<option value="'+dataset+'">'+dataviva.dictionary[dataset]+'</option>'));
        }

        $('#datasets').change(changeDataSet);
    }

    function getUrlParameter(sParam) {
        var sPageURL = decodeURIComponent(window.location.search.substring(1)),
            sURLVariables = sPageURL.split('&'),
            sParameterName,
            i;

        for (i = 0; i < sURLVariables.length; i++) {
            sParameterName = sURLVariables[i].split('=');

            if (sParameterName[0] === sParam) {
                return sParameterName[1] === undefined ? true : sParameterName[1];
            }
        }
    };

    function fillForm(){
        var url = window.location.href.split('?')[0];
        var urlFilters = url.split('build_graph/')[1].split('/');

        //Fill Dataset
        if (urlFilters[0]){
            var dataset = urlFilters[0];
        }

        $('#datasets').val(dataset);
        BuildGraph.dataset = dataset;
        setDimensions(dataviva.datasets[dataset].dimensions);

        //Fill Dimensions
        var filters = {};
        var datasetOption = $('#dimensions div').children('button:even');

        filters['f0'] = urlFilters[1];

        if(filters['f0']){
            $('#dimensions #filter0').val(filters['f0']);
            var valueText0 = (filters['f0'] == 'all') ? 'Selected' : dataviva.bra[filters['f0']].name;
            $('#dimensions #bra').text(valueText0);
        }

        var filter1 = datasetOption[1].id;
        var filter2 = (dataset != 'sc') ? datasetOption[2].id : 'course_sc';

        filters['f1'] = urlFilters[2];
        filters['f2'] = urlFilters[3];

        if(filters['f1']){
            $('#dimensions #filter1').val(filters['f1']);
            var valueText1 = (filters['f1'] == 'all') ?  'Selected' : dataviva[filter1][filters['f1']].name
            $('#dimensions #'+filter1).text(valueText1);
        }

        if(filters['f2']){
            $('#dimensions #filter2').val(filters['f2']);
            var valueText2 = (filters['f2'] == 'all') ? 'Selected' : dataviva[filter2][filters['f2']].name;
            $('#dimensions #'+filter2).text(valueText2);
        }

        $(document).ajaxComplete(function() {

            //Fill Parameters
            if (window.location.href.split('?')[1]){
                var urlParameters = window.location.href.split('?')[1];
                var parameters = {
                    'views': getUrlParameter('views'),
                    'graph': getUrlParameter('graph'),
                    'compare': getUrlParameter('compare'),
                };
            }

            var selectedViews = $('#views');

            $('#views div select option')
                .filter("[value='"+parameters.views+"']")
                .prop('selected', true)
                .siblings()
                .prop('selected', false);
        });

        updateViews();
    }
})();

$(document).ready(function () {
    dataviva.requireAttrs(['datasets'], function() {
        BuildGraph.init();
        BuildGraph.fillForm();
    });
});

<commit_msg>Updatdates fillForm function to handle with no views parameter.<commit_after>function setDimension(type, name, id) {
    if ($('#'+type).siblings('input').val() != id) {
        $('#'+type).html(name);
        $('#dimensions input[name='+type+']').val(id).trigger('change');
    }
}

dataviva.requireAttrs(['datasets', 'bra', 'cnae', 'cbo', 'course_sc', 'course_hedu', 'university'], function() {
    //dataviva.attrs.datasets
    //setDimension(type, name, id)
});

var selectorGraphs = Selector()
    .callback(function(d){
        setDimension(selectorGraphs.type(), d.name, d.id)
        $('#modal-selector').modal('hide');
    });

function select_dimension(id) {
    d3.select("#modal-selector-content").call(selectorGraphs.type(id));
    $('#modal-selector').modal('show');
}

var selectorCompare = Selector()
    .callback(function(d){
        if ($('#compare_with').siblings('input').val() != d.id) {
            $('#compare_with').html(d.name);
            $('#compare-location input[name=compare_with]').val(d.id).trigger('change');
            BuildGraph.compare = d.id;
        }
        BuildGraph.setCompare();
        $('#modal-selector').modal('hide');
    });

function select_compare() {
    d3.select("#modal-selector-content").call(selectorCompare.type('bra'));
    $('#modal-selector').modal('show');
}

function clean_selection(id) {
    if ($(id).siblings('input').val() != 'all') {
        $(id).html(dataviva.dictionary['select']);
        $(id).siblings('input').val('all').trigger('change');
    }
}

var BuildGraph = (function () {

    return {
        dataset: dataset,
        views: views,
        selectedView: selectedView,
        selectedGraph: selectedGraph,
        setCompare: setCompare,
        init: init,
        fillForm: fillForm
    }

    var selectedGraph, selectedView, dataset, views;

    function changeDataSet() {
        $('#datasets #dataset-empty-option').remove();
        BuildGraph.dataset = this.value;
        setDimensions(dataviva.datasets[this.value].dimensions);
        updateViews();
    }

    function setDimensions(dimensions) {
        $('#dimensions').empty();
        dimensions.forEach(function(dimension, index) {
            var div = $('

').addClass('form-group'),
                filter = $('<input></input>').attr('type', 'hidden').attr('name', dimension.id).attr('id', 'filter'+index).val('all'),
                label = $('').attr('for', dimension.id).addClass('control-label'),
                selector = $('<button></button>').attr('id', dimension.id).addClass('btn btn-block btn-outline btn-primary')
                                        .html(dataviva.dictionary['select'])
                                        .attr('onclick', 'select_dimension(id);'),
                cleaner = $('<button></button>').attr('for', dimension.id).addClass('btn btn-xs btn-link pull-right')
                                        .html(dataviva.dictionary['clean_selection'])
                                        .attr('onclick', 'clean_selection('+dimension.id+')');

            label.html(dataviva.dictionary[dimension.id]);
            filter.change(updateViews);

            if (dimension.name == 'School') {
                div.append(filter);
            } else {
                div.append(filter).append(label).append(selector).append(cleaner);
            }

            $('#dimensions').append(div);
        });
    }

    function updateViews() {
        $.ajax({
            method: "GET",
            url: "/" + dataviva.language + "/build_graph/views/" + BuildGraph.dataset +"/" +
                $('#dimensions #filter0').val() +
                ($('#compare-location input[name=compare_with]').val() ? '_' + $('#compare-location input[name=compare_with]').val() : '') + "/" +
                ($('#dimensions #filter1').val() == 'all' ? 'all' : $('#dimensions #filter1')[0].name) + "/" +
                ($('#dimensions #filter2').val() == 'all' ? 'all' : $('#dimensions #filter2')[0].name),
            data: {
                    filter1: $('#dimensions #filter1').val(),
                    filter2: $('#dimensions #filter2').val()
                },
            success: function (result) {
                setViews(result.views);
            }
        });
    }

    function setViews(views) {
        BuildGraph.views = views;
        $('#views').empty()

        var div = $('

').addClass('form-group');
            select = $('<select></select>').addClass('form-control'),
            label = $('').attr('for', 'titles').addClass('control-label'),

        label.html(dataviva.dictionary['views']);

        for(id in views){
            var option = $('<option value="'+id+'">'+views[id].name+'</option>');
            select.append(option);
        }

        select.change(function() {
            BuildGraph.selectedView = this.value;
            setGraphs(BuildGraph.views[this.value].graphs);
        });

        div.append(label).append(select);
        $('#views').append(div);

        // Try to keep the selected view, else keep whatever comes selected
        if ($.inArray(BuildGraph.selectedView, Object.keys(views)) > -1) {
            $('#views select').val(BuildGraph.selectedView);
        } else {
            BuildGraph.selectedView = views[$('#views select').val()].id;
        }

        setGraphs(views[BuildGraph.selectedView].graphs);
    }

    function setGraphs(graphs) {
        $('#graphs').empty()

        var div = $('

').attr('class', 'dropdown dropdown-select form-group');
            graphButton = $('<button data-toggle="dropdown" aria-expanded="true"></button>')
                            .attr('id', 'selected-graph')
                            .attr('class', 'btn btn-outline btn-block dropdown-toggle'),
            dropDownMenu = $('

')
                            .attr('class', 'dropdown-menu'),
            label = $('').attr('for', 'selected-graph').addClass('control-label');

        label.html(dataviva.dictionary['graphs']);

        for(id in graphs){
            var graphLink = $('')
                            .attr('id', id)
                            .attr('class', 'graph-link')
                            .data('url', "/" + dataviva.language + '/embed/' + graphs[id].url)
                            .html('' + graphs[id].name);

            var graphOption = $('

').append(graphLink);

            dropDownMenu.append(graphOption);
        }

        div.on( 'click', '.dropdown-menu li a', function(argument) {
           selectGraph(this);
        });

        div.append(label).append(graphButton).append(dropDownMenu);

        $('#graphs').append(div);

        // Try to keep the selected graph, else select the first graph
        if ($.inArray(BuildGraph.selectedGraph, Object.keys(graphs)) > -1) {
            selectGraph($('#'+BuildGraph.selectedGraph));
        } else {
            BuildGraph.selectedGraph = $('#selected-graph').data('graph');
            selectGraph($('#selected-graph').siblings('.dropdown-menu').find('li a').first());
        }
    }

    function selectGraph(graph) {
        BuildGraph.selectedGraph = $(graph).attr('id');

        var graphName = $(graph).html();

        //Adds active class to selected item
        $(graph).parents('.dropdown-menu').find('li').removeClass('active');
        $(graph).parent('li').addClass('active');

        //Displays selected text on dropdown-toggle button
        $('#selected-graph').data('graph', $(graph).attr('id'));
        $('#selected-graph').html(graphName);

        if (BuildGraph.selectedGraph == 'compare') {
            setCompare();
        } else {
            $('#compare-location').empty();
            delete BuildGraph.compare;
            $('#graph-wrapper').html('');
        }
    }

    function setCompare(){
        if (BuildGraph.compare) {
            $('#graph-wrapper').html('');
        } else {
            $('#compare-location').empty();

            var div = $('

').addClass('form-group'),
                label = $('').attr('for', 'compare_with').addClass('control-label'),
                cleaner = $('<button></button>').attr('for', 'compare_with').addClass('btn btn-xs btn-link pull-right')
                                        .html(dataviva.dictionary['clean_selection'])
                                        .attr('onclick', 'clean_selection('+'compare_with'+')'),
                selector = $('<button></button>').attr('id', 'compare_with').addClass('btn btn-block btn-outline btn-primary')
                                        .html(dataviva.dictionary['select'])
                                        .attr('onclick', 'select_compare();'),
                filter = $('<input></input>').attr('type', 'hidden').attr('name', 'compare_with').attr('id', 'compare_filter').val('all');

            label.html(dataviva.dictionary['compare_with']);
            filter.change(updateViews);

            div.append(filter).append(label).append(selector).append(cleaner);

            $('#compare-location').append(div);
        }
    }

    function init() {
        for (dataset in dataviva.datasets) {
            $('#datasets').append( $('<option value="'+dataset+'">'+dataviva.dictionary[dataset]+'</option>'));
        }

        $('#datasets').change(changeDataSet);
    }

    function getUrlParameter(sParam) {
        var sPageURL = decodeURIComponent(window.location.search.substring(1)),
            sURLVariables = sPageURL.split('&'),
            sParameterName,
            i;

        for (i = 0; i < sURLVariables.length; i++) {
            sParameterName = sURLVariables[i].split('=');

            if (sParameterName[0] === sParam) {
                return sParameterName[1] === undefined ? true : sParameterName[1];
            }
        }
    };

    function fillForm(){
        var url = window.location.href.split('?')[0];
        var urlFilters = url.split('build_graph/')[1].split('/');

        //Fill Dataset
        if (urlFilters[0]){
            var dataset = urlFilters[0];
        }

        $('#datasets').val(dataset);
        BuildGraph.dataset = dataset;
        setDimensions(dataviva.datasets[dataset].dimensions);

        //Fill Dimensions
        var filters = {};
        var datasetOption = $('#dimensions div').children('button:even');

        filters['f0'] = urlFilters[1];

        if(filters['f0']){
            $('#dimensions #filter0').val(filters['f0']);
            var valueText0 = (filters['f0'] == 'all') ? 'Selected' : dataviva.bra[filters['f0']].name;
            $('#dimensions #bra').text(valueText0);
        }

        var filter1 = datasetOption[1].id;
        var filter2 = (dataset != 'sc') ? datasetOption[2].id : 'course_sc';

        filters['f1'] = urlFilters[2];
        filters['f2'] = urlFilters[3];

        if(filters['f1']){
            $('#dimensions #filter1').val(filters['f1']);
            var valueText1 = (filters['f1'] == 'all') ?  'Selected' : dataviva[filter1][filters['f1']].name
            $('#dimensions #'+filter1).text(valueText1);
        }

        if(filters['f2']){
            $('#dimensions #filter2').val(filters['f2']);
            var valueText2 = (filters['f2'] == 'all') ? 'Selected' : dataviva[filter2][filters['f2']].name;
            $('#dimensions #'+filter2).text(valueText2);
        }

        $(document).ajaxComplete(function() {

            //Fill Parameters
            if (window.location.href.split('?')[1]){
                var urlParameters = window.location.href.split('?')[1];
                var parameters = {
                    'views': getUrlParameter('views'),
                    'graph': getUrlParameter('graph'),
                    'compare': getUrlParameter('compare'),
                };

                if(parameters.views){
                    $('#views div select option')
                        .filter("[value='"+parameters.views+"']")
                        .prop('selected', true)
                        .siblings()
                        .prop('selected', false);
                }
            }
        });

        updateViews();
    }
})();

$(document).ready(function () {
    dataviva.requireAttrs(['datasets'], function() {
        BuildGraph.init();
        BuildGraph.fillForm();
    });
});

<|endoftext|>


<commit_before>'use strict'

import React from 'react-native'
const {
  Component,
  Navigator,
  Settings,
  StyleSheet,
  Text,
  TouchableOpacity
} = React

const NavigationBarRouteMapper = {
  LeftButton: function (route, navigator, index, navState) {
    if (route.leftButton) {
      return route.leftButton
    }

    if (index === 0) {
      return null
    }

    const previousRoute = navState.routeStack[index - 1]
    // for some reason popn doesn't work, we'll likely ditch this routing anyways...
    const i = route.leftButtonPopN ? route.leftButtonPopN : 1
    const routes = navigator.getCurrentRoutes()
    const targetRoute = routes[routes.length - i - 1]

    return (
      <TouchableOpacity
        onPress={() => { navigator.popToRoute(targetRoute) }}
        style={styles.navBarLeftButton}>
        <Text style={[styles.navBarText, styles.navBarButtonText]}>
          {route.leftButtonTitle || previousRoute.title}
        </Text>
      </TouchableOpacity>
    )
  },

  RightButton: function (route, navigator, index, navState) {
    return route.rightButton
  },

  Title: function (route, navigator, index, navState) {
    return (
      <Text style={[styles.navBarText, styles.navBarTitleText]}>
        {route.title}
      </Text>
    )
  }
}

class KBNavigator extends Component {
  constructor () {
    super()

    this.pushQueue = []
  }
  componentWillMount () {
    // this.savedPath = []
    this.savedPath = Settings.get(this.props.saveName) || []
  }
  componentWillUnmount () { }

  push (route) {
    this.pushQueue.push(this.decorateRoute(route))
    this.clearPushQueue()
  }

  popToTop () {
    this.navigator.popToTop()
  }

  clearPushQueue () {
    if (!this.navigator) {
      return
    }

    // while loop to allow things to keep pushing while we iterate
    while (this.pushQueue.length) {
      this.navigator.push(this.pushQueue.shift())
    }
  }

  decorateRoute (route) {
    const decorated = {
      ...route,
      navSavedPath: this.savedPath.concat()
    }

    if (this.savedPath.length) {
      this.savedPath.shift()
    }

    return decorated
  }

  savePath () {
    if (!this.navigator) {
      return
    }

    let toSave = {}

    const routes = this.navigator.getCurrentRoutes().slice(1).map(function (r) {
      return {
        saveKey: r.saveKey,
        props: r.props
      }
    })

    toSave[this.props.saveName] = routes
    Settings.set(toSave)
  }

  configureScene (route) {
    return Navigator.SceneConfigs.FloatFromRight
  }

  render () {
    return (
      <Navigator
        debugOverlay={false}
        ref={(navigator) => {
          this.navigator = navigator
          this.clearPushQueue()
        }}
        style={styles.appContainer}
        initialRoute={this.decorateRoute(this.props.initialRoute)}
        renderScene={(route, navigator) => {
          this.savePath()

          return React.createElement(route.component, {
            navigator,
            kbNavigator: this,
            navSavedPath: route.navSavedPath,
            ...route.props
          }) }
        }
        navigationBar={
          <Navigator.NavigationBar
            routeMapper={NavigationBarRouteMapper}
            style={styles.navBar}
          />
        }
      />
    )
  }
}

KBNavigator.propTypes = {
  initialRoute: React.PropTypes.object,
  saveName: React.PropTypes.string
}

const styles = StyleSheet.create({
  navBar: {
    backgroundColor: 'white'
  },
  navBarText: {
    fontSize: 16,
    marginVertical: 10
  },
  navBarTitleText: {
    color: 'blue',
    fontWeight: '500',
    marginVertical: 9
  },
  navBarLeftButton: {
    paddingLeft: 10
  },
  navBarButtonText: {
    color: 'blue'
  }
})

export default KBNavigator
<commit_msg>using computed prop and not let<commit_after>'use strict'

import React from 'react-native'
const {
  Component,
  Navigator,
  Settings,
  StyleSheet,
  Text,
  TouchableOpacity
} = React

const NavigationBarRouteMapper = {
  LeftButton: function (route, navigator, index, navState) {
    if (route.leftButton) {
      return route.leftButton
    }

    if (index === 0) {
      return null
    }

    const previousRoute = navState.routeStack[index - 1]
    // for some reason popn doesn't work, we'll likely ditch this routing anyways...
    const i = route.leftButtonPopN ? route.leftButtonPopN : 1
    const routes = navigator.getCurrentRoutes()
    const targetRoute = routes[routes.length - i - 1]

    return (
      <TouchableOpacity
        onPress={() => { navigator.popToRoute(targetRoute) }}
        style={styles.navBarLeftButton}>
        <Text style={[styles.navBarText, styles.navBarButtonText]}>
          {route.leftButtonTitle || previousRoute.title}
        </Text>
      </TouchableOpacity>
    )
  },

  RightButton: function (route, navigator, index, navState) {
    return route.rightButton
  },

  Title: function (route, navigator, index, navState) {
    return (
      <Text style={[styles.navBarText, styles.navBarTitleText]}>
        {route.title}
      </Text>
    )
  }
}

class KBNavigator extends Component {
  constructor () {
    super()

    this.pushQueue = []
  }
  componentWillMount () {
    // this.savedPath = []
    this.savedPath = Settings.get(this.props.saveName) || []
  }
  componentWillUnmount () { }

  push (route) {
    this.pushQueue.push(this.decorateRoute(route))
    this.clearPushQueue()
  }

  popToTop () {
    this.navigator.popToTop()
  }

  clearPushQueue () {
    if (!this.navigator) {
      return
    }

    // while loop to allow things to keep pushing while we iterate
    while (this.pushQueue.length) {
      this.navigator.push(this.pushQueue.shift())
    }
  }

  decorateRoute (route) {
    const decorated = {
      ...route,
      navSavedPath: this.savedPath.concat()
    }

    if (this.savedPath.length) {
      this.savedPath.shift()
    }

    return decorated
  }

  savePath () {
    if (!this.navigator) {
      return
    }

    const routes = this.navigator.getCurrentRoutes().slice(1).map(function (r) {
      return {
        saveKey: r.saveKey,
        props: r.props
      }
    })

    Settings.set({
      [this.props.saveName]: routes
    })
  }

  configureScene (route) {
    return Navigator.SceneConfigs.FloatFromRight
  }

  render () {
    return (
      <Navigator
        debugOverlay={false}
        ref={(navigator) => {
          this.navigator = navigator
          this.clearPushQueue()
        }}
        style={styles.appContainer}
        initialRoute={this.decorateRoute(this.props.initialRoute)}
        renderScene={(route, navigator) => {
          this.savePath()

          return React.createElement(route.component, {
            navigator,
            kbNavigator: this,
            navSavedPath: route.navSavedPath,
            ...route.props
          }) }
        }
        navigationBar={
          <Navigator.NavigationBar
            routeMapper={NavigationBarRouteMapper}
            style={styles.navBar}
          />
        }
      />
    )
  }
}

KBNavigator.propTypes = {
  initialRoute: React.PropTypes.object,
  saveName: React.PropTypes.string
}

const styles = StyleSheet.create({
  navBar: {
    backgroundColor: 'white'
  },
  navBarText: {
    fontSize: 16,
    marginVertical: 10
  },
  navBarTitleText: {
    color: 'blue',
    fontWeight: '500',
    marginVertical: 9
  },
  navBarLeftButton: {
    paddingLeft: 10
  },
  navBarButtonText: {
    color: 'blue'
  }
})

export default KBNavigator
<|endoftext|>


<commit_before>var mainState = {

	preload: function() {
		game.load.imagine("player","assets/player.png");

	},
create: function()
  game.state.backgroundColor = '#3498db';

  game.physics.startSystem(phaser.physics.ARCADE);

  game.renderer.rendererSession.roundpixels = true;
  var player = game.add.sprite(game.width/250, 170, 'player');
  this.player = game.add.spirite(game.width/2, height/2,"player");
  this.player.anchor.setTo(0.5,0.5);

game.physics.arcade.enable(this.player);

this.player.body.gravity.y = 500;

this.cursor = game.input.keyboard.createCursorKeys();

},

	update: function(){
		this.movePlayer();

	},

	movePlayer: function(){
		if(this.cursor.left.isDown){
			this.player.body.velocity.x = -200;
		}
		else if(this.cursor.right.isDown){
			this.player.body.velocity.x =200;

		}
		else{
			this.player.body.velocity.x = 0;

		}
		if(this.cursor.up.isDown && this.player.body.touching.down){
			this.player.body.velocity.y = -320;

		}
		}
	}
};
var game = new phaser.Game(500, 340, phaser.AUTO,'gameDiv');

game.state.add("main",mainState);
 game.state.start("main");

<commit_msg>Update main.js<commit_after>var mainState = {

	preload: function() {
		game.load.imagine("player","assets/player.png");
	},
create: function()
  game.state.backgroundColor = '#3498db';
  game.physics.startSystem(phaser.Physics.ARCADE);
  game.renderer.rendererSession.roundPixels = true;
  var player = game.add.sprite(game.width/250, 170, 'player');
  this.player = game.add.sprite(game.width/2, height/2,'player');
  this.player.anchor.setTo(0.5,0.5);
  game.physics.arcade.enable(this.player);
  this.player.body.gravity.y = 500;
  this.cursor = game.input.keyboard.createCursorKeys();
},
	update: function(){
		this.movePlayer();
	},

	movePlayer: function(){
		if(this.cursor.left.isDown){
			this.player.body.velocity.x = -200;
		}
		else if(this.cursor.right.isDown){
			this.player.body.velocity.x =200;

		}
		else{
			this.player.body.velocity.x = 0;

		}
		if(this.cursor.up.isDown && this.player.body.touching.down){
			this.player.body.velocity.y = -320;
		}
		}
	}
};
var game = new phaser.Game(500, 340, Phaser.AUTO,'gameDiv');

game.state.add("main",mainState);
 game.state.start("main");

<|endoftext|>


<commit_before>// @flow

import { MiddlewareRegistry } from '../base/redux';

import { ENDPOINT_MESSAGE_RECEIVED } from './actionTypes';
import {
    removeTranscriptMessage,
    updateTranscriptMessage
} from './actions';

const logger = require('jitsi-meet-logger').getLogger(__filename);

declare var APP: Object;

/**
 * The type of json-message which indicates that json carries a
 * transcription result.
 */
const JSON_TYPE_TRANSCRIPTION_RESULT = 'transcription-result';

/**
 * The type of json-message which indicates that json carries a
 * translation result.
 */
const JSON_TYPE_TRANSLATION_RESULT = 'translation-result';

/**
 * The local participant property which is used to store the language
 * preference for translation for a participant.
 */
const P_NAME_TRANSLATION_LANGUAGE = 'translation_language';

/**
* Time after which the rendered subtitles will be removed.
*/
const REMOVE_AFTER_MS = 3000;

/**
 * Middleware that catches actions related to transcript messages
 * to be rendered in {@link TranscriptionSubtitles }
 *
 * @param {Store} store - Redux store.
 * @returns {Function}
 */
MiddlewareRegistry.register(store => next => action => {

    switch (action.type) {
    case ENDPOINT_MESSAGE_RECEIVED:
        return _endpointMessageReceived(store, next, action);
    }

    return next(action);
});

/**
 * Notifies the feature transcription that the action
 * {@code ENDPOINT_MESSAGE_RECEIVED} is being dispatched within a specific redux
 * store.
 *
 * @param {Store} store - The redux store in which the specified {@code action}
 * is being dispatched.
 * @param {Dispatch} next - The redux {@code dispatch} function to
 * dispatch the specified {@code action} to the specified {@code store}.
 * @param {Action} action - The redux action {@code ENDPOINT_MESSAGE_RECEIVED}
 * which is being dispatched in the specified {@code store}.
 * @private
 * @returns {Object} The value returned by {@code next(action)}.
 */
function _endpointMessageReceived({ dispatch, getState }, next, action) {
    const json = action.json;
    const translationLanguage
        = getState()['features/base/conference'].conference
            .getLocalParticipantProperty(P_NAME_TRANSLATION_LANGUAGE);

    try {
        const transcriptMessageID = json.message_id;
        const participantName = json.participant.name;
        const isInterim = json.is_interim;
        const stability = json.stability;

        if (json.type === JSON_TYPE_TRANSLATION_RESULT
            && json.language === translationLanguage) {
            // Displays final results in the target language if translation is
            // enabled.

            const newTranscriptMessage = {
                participantName,
                final: json.text
            };

            dispatch(updateTranscriptMessage(transcriptMessageID,
                newTranscriptMessage));

            setTimeout(() => {
                dispatch(removeTranscriptMessage(transcriptMessageID));
            }, REMOVE_AFTER_MS);

        } else if (json.type === JSON_TYPE_TRANSCRIPTION_RESULT
            && !translationLanguage) {
            // Displays interim and final results without any translation if
            // translations are disabled.

            const text = json.transcript[0].text;

            // We update the previous transcript message with the same
            // message ID or adds a new transcript message if it does not
            // exist in the map.
            const newTranscriptMessage
                = { ...getState()['features/subtitles'].transcriptMessages
                    .get(transcriptMessageID) || { participantName } };

            // If this is final result, update the state as a final result
            // and start a count down to remove the subtitle from the state
            if (!isInterim) {

                newTranscriptMessage.final = text;
                dispatch(updateTranscriptMessage(transcriptMessageID,
                    newTranscriptMessage));

                setTimeout(() => {
                    dispatch(removeTranscriptMessage(transcriptMessageID));
                }, REMOVE_AFTER_MS);
            } else if (stability > 0.85) {

                // If the message has a high stability, we can update the
                // stable field of the state and remove the previously
                // unstable results

                newTranscriptMessage.stable = text;
                newTranscriptMessage.unstable = undefined;
                dispatch(updateTranscriptMessage(transcriptMessageID,
                    newTranscriptMessage));
            } else {
                // Otherwise, this result has an unstable result, which we
                // add to the state. The unstable result will be appended
                // after the stable part.

                newTranscriptMessage.unstable = text;
                dispatch(updateTranscriptMessage(transcriptMessageID,
                    newTranscriptMessage));
            }
        }
    } catch (error) {
        logger.error('Error occurred while updating transcriptions\n', error);
    }

    return next(action);
}
<commit_msg>fix: add a timer which automatically clears subtitles (#3349)<commit_after>// @flow

import { MiddlewareRegistry } from '../base/redux';

import { ENDPOINT_MESSAGE_RECEIVED } from './actionTypes';
import {
    removeTranscriptMessage,
    updateTranscriptMessage
} from './actions';

const logger = require('jitsi-meet-logger').getLogger(__filename);

/**
 * The type of json-message which indicates that json carries a
 * transcription result.
 */
const JSON_TYPE_TRANSCRIPTION_RESULT = 'transcription-result';

/**
 * The type of json-message which indicates that json carries a
 * translation result.
 */
const JSON_TYPE_TRANSLATION_RESULT = 'translation-result';

/**
 * The local participant property which is used to store the language
 * preference for translation for a participant.
 */
const P_NAME_TRANSLATION_LANGUAGE = 'translation_language';

/**
* Time after which the rendered subtitles will be removed.
*/
const REMOVE_AFTER_MS = 3000;

/**
 * Middleware that catches actions related to transcript messages
 * to be rendered in {@link TranscriptionSubtitles }
 *
 * @param {Store} store - Redux store.
 * @returns {Function}
 */
MiddlewareRegistry.register(store => next => action => {

    switch (action.type) {
    case ENDPOINT_MESSAGE_RECEIVED:
        return _endpointMessageReceived(store, next, action);
    }

    return next(action);
});

/**
 * Notifies the feature transcription that the action
 * {@code ENDPOINT_MESSAGE_RECEIVED} is being dispatched within a specific redux
 * store.
 *
 * @param {Store} store - The redux store in which the specified {@code action}
 * is being dispatched.
 * @param {Dispatch} next - The redux {@code dispatch} function to
 * dispatch the specified {@code action} to the specified {@code store}.
 * @param {Action} action - The redux action {@code ENDPOINT_MESSAGE_RECEIVED}
 * which is being dispatched in the specified {@code store}.
 * @private
 * @returns {Object} The value returned by {@code next(action)}.
 */
function _endpointMessageReceived({ dispatch, getState }, next, action) {
    const json = action.json;
    const translationLanguage
        = getState()['features/base/conference'].conference
            .getLocalParticipantProperty(P_NAME_TRANSLATION_LANGUAGE);

    try {
        const transcriptMessageID = json.message_id;
        const participantName = json.participant.name;
        const isInterim = json.is_interim;
        const stability = json.stability;

        if (json.type === JSON_TYPE_TRANSLATION_RESULT
            && json.language === translationLanguage) {
            // Displays final results in the target language if translation is
            // enabled.

            const newTranscriptMessage = {
                participantName,
                final: json.text,
                clearTimeOut: undefined
            };

            setClearerOnTranscriptMessage(dispatch,
                transcriptMessageID, newTranscriptMessage);
            dispatch(updateTranscriptMessage(transcriptMessageID,
                newTranscriptMessage));

        } else if (json.type === JSON_TYPE_TRANSCRIPTION_RESULT
            && !translationLanguage) {
            // Displays interim and final results without any translation if
            // translations are disabled.

            const text = json.transcript[0].text;

            // We update the previous transcript message with the same
            // message ID or adds a new transcript message if it does not
            // exist in the map.
            const newTranscriptMessage
                = { ...getState()['features/subtitles'].transcriptMessages
                    .get(transcriptMessageID) || { participantName } };

            setClearerOnTranscriptMessage(dispatch,
                transcriptMessageID, newTranscriptMessage);

            // If this is final result, update the state as a final result
            // and start a count down to remove the subtitle from the state
            if (!isInterim) {

                newTranscriptMessage.final = text;
                dispatch(updateTranscriptMessage(transcriptMessageID,
                    newTranscriptMessage));
            } else if (stability > 0.85) {

                // If the message has a high stability, we can update the
                // stable field of the state and remove the previously
                // unstable results

                newTranscriptMessage.stable = text;
                newTranscriptMessage.unstable = undefined;
                dispatch(updateTranscriptMessage(transcriptMessageID,
                    newTranscriptMessage));
            } else {
                // Otherwise, this result has an unstable result, which we
                // add to the state. The unstable result will be appended
                // after the stable part.

                newTranscriptMessage.unstable = text;
                dispatch(updateTranscriptMessage(transcriptMessageID,
                    newTranscriptMessage));
            }
        }
    } catch (error) {
        logger.error('Error occurred while updating transcriptions\n', error);
    }

    return next(action);
}

/**
 * Set a timeout on a TranscriptMessage object so it clears itself when it's not
 * updated.
 *
 * @param {Function} dispatch - Dispatch remove action to store.
 * @param {string} transcriptMessageID - The id of the message to remove.
 * @param {Object} transcriptMessage - The message to remove.
 *
 * @returns {void}
 */
function setClearerOnTranscriptMessage(
        dispatch,
        transcriptMessageID,
        transcriptMessage) {
    if (transcriptMessage.clearTimeOut) {
        clearTimeout(transcriptMessage.clearTimeOut);
    }

    transcriptMessage.clearTimeOut = setTimeout(() => {
        dispatch(removeTranscriptMessage(transcriptMessageID));
    }, REMOVE_AFTER_MS);
}
<|endoftext|>


<commit_before>import Vue from 'vue'

describe('ref', () => {
  const components = {
    test: {
      id: 'test'
    },
    test2: {
      id: 'test2'
    }
  }

  it('should work', () => {
    const vm = new Vue({
      data: {
        value: 'bar'
      },
      template: `

        <test ref="foo"></test>
        <test2 :ref="value"></test2>

`,
      components
    })
    vm.$mount()
    expect(vm.$refs.foo).toBeTruthy()
    expect(vm.$refs.foo.$options.id).toBe('test')
    expect(vm.$refs.bar).toBeTruthy()
    expect(vm.$refs.bar.$options.id).toBe('test2')
  })

  it('should dynamically update refs', done => {
    const vm = new Vue({
      data: {
        value: 'foo'
      },
      template: '

'
    }).$mount()
    expect(vm.$refs.foo).toBe(vm.$el)
    vm.value = 'bar'
    waitForUpdate(() => {
      expect(vm.$refs.foo).toBeUndefined()
      expect(vm.$refs.bar).toBe(vm.$el)
    }).then(done)
  })

  it('should work as a hyperscript prop', () => {
    const vm = new Vue({
      components,
      render (h) {
        return h('div', null, [
          h('test', { ref: 'test' })
        ])
      }
    })
    vm.$mount()
    expect(vm.$refs.test).toBeTruthy()
    expect(vm.$refs.test.$options.id).toBe('test')
  })

  it('should accept HOC component', () => {
    const vm = new Vue({
      template: '<test ref="test"></test>',
      components
    })
    vm.$mount()
    expect(vm.$refs.test).toBeTruthy()
    expect(vm.$refs.test.$options.id).toBe('test')
  })

  it('should accept dynamic component', done => {
    const vm = new Vue({
      template: `

        <component :is="test" ref="test"></component>

`,
      components,
      data: { test: 'test' }
    })
    vm.$mount()
    expect(vm.$refs.test.$options.id).toBe('test')
    vm.test = 'test2'
    waitForUpdate(() => {
      expect(vm.$refs.test.$options.id).toBe('test2')
      vm.test = ''
    }).then(() => {
      expect(vm.$refs.test).toBeUndefined()
    }).then(done)
  })

  it('should register as Array when used with v-for', done => {
    const vm = new Vue({
      data: {
        items: [1, 2, 3]
      },
      template: `

{{n}}

      `
    }).$mount()
    assertRefs()
    // updating
    vm.items.push(4)
    waitForUpdate(assertRefs)
      .then(() => { vm.items = [] })
      .then(assertRefs)
      .then(done)

    function assertRefs () {
      expect(Array.isArray(vm.$refs.list)).toBe(true)
      expect(vm.$refs.list.length).toBe(vm.items.length)
      expect(vm.$refs.list.every((item, i) => item.textContent === String(i + 1))).toBe(true)
    }
  })

  it('should register as Array when used with v-for (components)', done => {
    const vm = new Vue({
      data: {
        items: [1, 2, 3]
      },
      template: `

          <test v-for="n in items" ref="list" :n="n"></test>

      `,
      components: {
        test: {
          props: ['n'],
          template: '
{{ n }}
'
        }
      }
    }).$mount()
    assertRefs()
    // updating
    vm.items.push(4)
    waitForUpdate(assertRefs)
      .then(() => { vm.items = [] })
      .then(assertRefs)
      .then(done)

    function assertRefs () {
      expect(Array.isArray(vm.$refs.list)).toBe(true)
      expect(vm.$refs.list.length).toBe(vm.items.length)
      expect(vm.$refs.list.every((comp, i) => comp.$el.textContent === String(i + 1))).toBe(true)
    }
  })
})
<commit_msg>include templates in ref spec<commit_after>import Vue from 'vue'

describe('ref', () => {
  const components = {
    test: {
      id: 'test',
      template: '
test
'
    },
    test2: {
      id: 'test2',
      template: '
test2
'
    }
  }

  it('should work', () => {
    const vm = new Vue({
      data: {
        value: 'bar'
      },
      template: `

        <test ref="foo"></test>
        <test2 :ref="value"></test2>

`,
      components
    })
    vm.$mount()
    expect(vm.$refs.foo).toBeTruthy()
    expect(vm.$refs.foo.$options.id).toBe('test')
    expect(vm.$refs.bar).toBeTruthy()
    expect(vm.$refs.bar.$options.id).toBe('test2')
  })

  it('should dynamically update refs', done => {
    const vm = new Vue({
      data: {
        value: 'foo'
      },
      template: '

'
    }).$mount()
    expect(vm.$refs.foo).toBe(vm.$el)
    vm.value = 'bar'
    waitForUpdate(() => {
      expect(vm.$refs.foo).toBeUndefined()
      expect(vm.$refs.bar).toBe(vm.$el)
    }).then(done)
  })

  it('should work as a hyperscript prop', () => {
    const vm = new Vue({
      components,
      render (h) {
        return h('div', null, [
          h('test', { ref: 'test' })
        ])
      }
    })
    vm.$mount()
    expect(vm.$refs.test).toBeTruthy()
    expect(vm.$refs.test.$options.id).toBe('test')
  })

  it('should accept HOC component', () => {
    const vm = new Vue({
      template: '<test ref="test"></test>',
      components
    })
    vm.$mount()
    expect(vm.$refs.test).toBeTruthy()
    expect(vm.$refs.test.$options.id).toBe('test')
  })

  it('should accept dynamic component', done => {
    const vm = new Vue({
      template: `

        <component :is="test" ref="test"></component>

`,
      components,
      data: { test: 'test' }
    })
    vm.$mount()
    expect(vm.$refs.test.$options.id).toBe('test')
    vm.test = 'test2'
    waitForUpdate(() => {
      expect(vm.$refs.test.$options.id).toBe('test2')
      vm.test = ''
    }).then(() => {
      expect(vm.$refs.test).toBeUndefined()
    }).then(done)
  })

  it('should register as Array when used with v-for', done => {
    const vm = new Vue({
      data: {
        items: [1, 2, 3]
      },
      template: `

{{n}}

      `
    }).$mount()
    assertRefs()
    // updating
    vm.items.push(4)
    waitForUpdate(assertRefs)
      .then(() => { vm.items = [] })
      .then(assertRefs)
      .then(done)

    function assertRefs () {
      expect(Array.isArray(vm.$refs.list)).toBe(true)
      expect(vm.$refs.list.length).toBe(vm.items.length)
      expect(vm.$refs.list.every((item, i) => item.textContent === String(i + 1))).toBe(true)
    }
  })

  it('should register as Array when used with v-for (components)', done => {
    const vm = new Vue({
      data: {
        items: [1, 2, 3]
      },
      template: `

          <test v-for="n in items" ref="list" :n="n"></test>

      `,
      components: {
        test: {
          props: ['n'],
          template: '
{{ n }}
'
        }
      }
    }).$mount()
    assertRefs()
    // updating
    vm.items.push(4)
    waitForUpdate(assertRefs)
      .then(() => { vm.items = [] })
      .then(assertRefs)
      .then(done)

    function assertRefs () {
      expect(Array.isArray(vm.$refs.list)).toBe(true)
      expect(vm.$refs.list.length).toBe(vm.items.length)
      expect(vm.$refs.list.every((comp, i) => comp.$el.textContent === String(i + 1))).toBe(true)
    }
  })
})
<|endoftext|>


<commit_before>var Cache = require('magazine'),
    cadence = require('cadence'),
    Cursor = require('./cursor'),
    fs = require('fs'),
    Queue = require('./queue'),
    Script = require('./script'),
    Sheaf = require('./sheaf'),
    Balancer = require('./balancer'),
    Descent = require('./descent'),
    Locker = require('./locker'),
    Player = require('./player'),
    Logger = require('./logger'),
    ok = require('assert').ok,
    path = require('path')

var Interrupt = require('interrupt').createInterrupter('b-tree')
var Turnstile = require('turnstile')

var Journalist = require('./journalist')

// TODO temporary
var scram = require('./scram')

function extend(to, from) {
    for (var key in from) to[key] = from[key]
    return to
}

// TODO Branch and leaf size, can we just sort that out in a call to balance?
function Strata (options) {
    this.options = options
    if (!options.serializers) {
        var json = require('./json')
        options.serializers = {
            key: json.serializer,
            record: json.serializer
        }
        options.deserializers = {
            key: json.deserialize,
            record: json.deserialize
        }
    }
    if (!options.framer) {
        var UTF8 = require('./frame/utf8')
        options.framer = new UTF8(options.checksum || 'sha1')
    }
    options.player = new Player(options)
    this.sheaf = options.sheaf = new Sheaf(options)
    this.logger = new Logger(options)

    this.housekeeper = new Turnstile
    this.writer = new Turnstile
    this._sheaf = new Cache().createMagazine()
    this._journalist = new Journalist(options.directory, this._sheaf)
    this._cursors = []
}

Strata.prototype.create = cadence(function (async, options) {
    var directory = this.options.directory
    async(function () {
        fs.stat(directory, async())
    }, function (stat) {
        Interrupt.assert(stat.isDirectory(), 'create.not.directory', { directory: directory })
        fs.readdir(this.sheaf.directory, async())
    }, function (files) {
        Interrupt.assert(files.filter(function (f) {
            return ! /^\./.test(f)
        }).length == 0, 'create.directory.not.empty', { directory: directory })
    }, function () {
        fs.mkdir(path.resolve(directory, 'pages'), 0755, async())
    }, function () {
        fs.writeFile(path.resolve(directory, 'instance'), '0\n', async())
    }, function () {
        async(function () {
            var cartridge = this._journalist.hold([ 'pages', '0' ])
            async([function () {
                cartridge.release()
            }], function () {
                cartridge.value.write(JSON.stringify({ method: 'add', index: 0, value: { id: 1 } }) + '\n', async())
            })
        }, function () {
            this._journalist.close([ 'pages', '0' ], async())
        }, function () {
            this._journalist.hold([ 'pages', '1' ]).release()
            this._journalist.close([ 'pages', '1' ], async())
        }, function () {
            this._sheaf.hold(-1, { items: [{ id: 0 }]  })
        })
    })
})

Strata.prototype.open = cadence(function (async) {
    this.sheaf.createMagazine()

    // TODO instead of rescue, you might try/catch the parts that you know
    // are likely to cause errors and raise an error of a Strata type.

    // TODO or you might need some way to catch a callback error. Maybe an
    // outer most catch block?

    // TODO or if you're using Cadence, doesn't the callback get wrapped
    // anyway?
    async(function () {
        fs.stat(this.sheaf.directory, async())
    }, function stat (error, stat) {
        fs.readdir(path.join(this.sheaf.directory, 'pages'), async())
    }, function (files) {
        files.forEach(function (file) {
            if (/^\d+\.\d+$/.test(file)) {
                this.sheaf.nextAddress = Math.max(+(file.split('.').shift()) + 1, this.sheaf.nextAddress)
            }
        }, this)
    })
})

Strata.prototype.close = cadence(function (async) {
    return
    // TODO that's a lot of indirection.
    var cartridge = this.sheaf.metaRoot.cartridge, lock = cartridge.value.page.lock

    lock.unlock()
    // TODO
    lock.dispose()

    cartridge.release()

    var purge = this.sheaf.magazine.purge()
    while (purge.cartridge) {
        purge.cartridge.remove()
        purge.next()
    }
    purge.release()

    ok(!this.sheaf.magazine.count, 'pages still held by cache')
})

Strata.prototype.left = function (descents, exclusive, callback) {
    this.toLeaf(descents[0].left, descents, null, exclusive, callback)
}

Strata.prototype.right = function (descents, exclusive, callback) {
    this.toLeaf(descents[0].right, descents, null, exclusive, callback)
}

Strata.prototype.key = function (key) {
    return function (descents, exclusive, callback) {
        this.toLeaf(descents[0].key(key), descents, null, exclusive, callback)
    }
}

Strata.prototype.leftOf = function (key) {
    return cadence(function (async, descents, exclusive) {
        var conditions = [ descents[0].leaf, descents[0].found([key]) ]
        async(function () {
            descents[0].descend(descents[0].key(key), function () {
                return conditions.some(function (condition) {
                    return condition.call(descents[0])
                })
            }, async())
        }, function (page, index) {
            if (descents[0].page.address % 2) {
                return [ new Cursor(this.sheaf, this.logger, descents, false, key) ]
            } else {
                descents[0].setIndex(descents[0].index - 1)
                this.toLeaf(descents[0].right, descents, null, exclusive, async())
            }
        })
    })
}

Strata.prototype.toLeaf = cadence(function (async, sought, descents, key, exclusive) {
    async(function () {
        descents[0].descend(sought, descents[0].penultimate, async())
    }, function () {
        if (exclusive) descents[0].exclude()
        descents[0].descend(sought, descents[0].leaf, async())
    }, function () {
        return [ new Cursor(this.sheaf, this.logger, descents, exclusive, key) ]
    })
})

Strata.prototype.cursor = cadence(function (async, key, exclusive) {
    // We hold onto all cartridges until we're done, even retries, so we're
    // going to end up holding cartridges two or more times, but we'll make
    // progress eventually and release everything.
    var cartridges = []
    async([function () {
        cartridges.forEach(function (cartridge) { cartridge.release() })
    }], function () {
        async.block(function () {
            var cartridge, index = 0
            cartridges.push(cartridge = this._sheaf.hold(-1, null))
            for (;;) {
                var id = cartridge.value.items[index].id
                cartridges.push(cartridge = this._sheaf.hold(id))
                if (cartridge.value == null) {
                    return async(function () {
                        this._journalist.load(id, async())
                    }, function () {
                        return [ async.continue ]
                    })
                }
                var page = cartridge.value
                index = this.sheaf.find(cartridge.value, key, page.leaf ? page.ghosts : 1)
                if (page.leaf) {
                    break
                } else if (index < 0) {
                    // On a branch, unless we hit the key exactly, we're
                    // pointing at the insertion point which is right after
                    // the branching we're supposed to decend, so back it up
                    // one unless it's a bullseye.
                    index = ~index - 1
                }
            }
            // Pop the last cartridge to give to the cursor; we don't release it
            // the cursor does.
            return new Cursor(this.sheaf, cartridges.pop(), key, index)
        })
    })
    return
    var descents = [ new Descent(this.sheaf, this.sheaf.createLocker()) ]
    async([function () {
        if (descents.length) {
            descents[0].locker.unlock(descents[0].page)
            descents[0].locker.dispose()
        }
    }], function () {
        if  (typeof key == 'function') {
            key.call(this, descents, exclusive, async())
        } else {
            this.toLeaf(descents[0].key(key), descents, key, exclusive, async())
        }
    }, function (cursor) {
        return [ cursor ]
    })
})

Strata.prototype.iterator = function (key, callback) {
    this.cursor(key, false, callback)
}

Strata.prototype.mutator = function (key, callback) {
    this.cursor(key, true, callback)
}

Strata.prototype.balance = function (callback) {
    new Balancer(this.sheaf, this.logger).balance(callback)
}

Strata.prototype.vivify = cadence(function (async) {
    var locker = this.sheaf.createLocker(), root

    function record (item) {
        return { address: item.address }
    }

    var expand = cadence(function (async, parent, pages, index) {
        async(function () {
            if (index < pages.length) {
                var address = pages[index].address
                async(function () {
                    locker.lock(address, false, async())
                }, [function (page) {
                    locker.unlock(page)
                }])
            } else {
                return [ async.return, pages ]
            }
        }, function (page) {
            if (page.address % 2 == 0) {
                async(function () {
                    pages[index].children = page.items.map(record)
                    if (index) {
                        pages[index].key = parent.items[index].key
                    }
                    expand.call(this, page, pages[index].children, 0, async())
                }, function () {
                    expand.call(this, parent, pages, index + 1, async())
                })
            } else {
                async(function () {
                    pages[index].children = []
                    pages[index].ghosts = page.ghosts

                    for (var i = 0, I = page.items.length; i < I; i++) {
                        pages[index].children.push(page.items[i].record)
                    }
                }, function () {
                    expand.call(this, parent, pages, index + 1, async())
                })
            }
        }, function () {
            return [ pages ]
        })
    })

    async(function () {
        locker.lock(0, false, async())
    }, function (page) {
        async([function () {
            locker.unlock(page)
            locker.dispose()
        }], function () {
            expand.call(this, page, root = page.items.map(record), 0, async())
        })
    })
})

Strata.prototype.purge = function (downTo) {
    var purge = this.sheaf.magazine.purge()
    while (purge.cartridge && this.sheaf.magazine.heft > downTo) {
        purge.cartridge.remove()
        purge.next()
    }
    purge.release()
}

Strata.prototype.__defineGetter__('balanced', function () {
    ok(false)
    return ! Object.keys(this.sheaf.lengths).length
})

module.exports = Strata
<commit_msg>Get rid of Journalist load.<commit_after>var Cache = require('magazine'),
    cadence = require('cadence'),
    Cursor = require('./cursor'),
    fs = require('fs'),
    Queue = require('./queue'),
    Script = require('./script'),
    Sheaf = require('./sheaf'),
    Balancer = require('./balancer'),
    Descent = require('./descent'),
    Locker = require('./locker'),
    Player = require('./player'),
    Logger = require('./logger'),
    ok = require('assert').ok,
    path = require('path')

var Interrupt = require('interrupt').createInterrupter('b-tree')
var Turnstile = require('turnstile')

var Journalist = require('./journalist')

var mkdirp = require('mkdirp')

// TODO temporary
var scram = require('./scram')

function extend(to, from) {
    for (var key in from) to[key] = from[key]
    return to
}

// TODO Branch and leaf size, can we just sort that out in a call to balance?
function Strata (options) {
    this.options = options
    if (!options.serializers) {
        var json = require('./json')
        options.serializers = {
            key: json.serializer,
            record: json.serializer
        }
        options.deserializers = {
            key: json.deserialize,
            record: json.deserialize
        }
    }
    if (!options.framer) {
        var UTF8 = require('./frame/utf8')
        options.framer = new UTF8(options.checksum || 'sha1')
    }
    options.player = new Player(options)
    this.sheaf = options.sheaf = new Sheaf(options)
    this.logger = new Logger(options)

    this.housekeeper = new Turnstile
    this.writer = new Turnstile
    this._sheaf = new Cache().createMagazine()
    this._journalist = new Journalist(options.directory, this._sheaf)
    this._cursors = []
}

Strata.prototype.create = cadence(function (async, options) {
    var directory = this.options.directory
    async(function () {
        fs.stat(directory, async())
    }, function (stat) {
        Interrupt.assert(stat.isDirectory(), 'create.not.directory', { directory: directory })
        fs.readdir(this.sheaf.directory, async())
    }, function (files) {
        Interrupt.assert(files.filter(function (f) {
            return ! /^\./.test(f)
        }).length == 0, 'create.directory.not.empty', { directory: directory })
    }, function () {
        mkdirp(path.resolve(directory, 'pages'), 0755, async())
    }, function () {
        fs.writeFile(path.resolve(directory, 'instance'), '0\n', async())
    }, function () {
        async(function () {
            mkdirp(path.resolve(directory, 'pages'), 0755, async())
        }, function () {
            fs.writeFile(path.resolve(directory, 'pages', '0'), JSON.stringify({ method: 'add', index: 0, value: { id: 1 } }) + '\n', async())
        }, function () {
            mkdirp(path.resolve(directory, 'pages'), 0755, async())
        }, function () {
            fs.writeFile(path.resolve(directory, 'pages', '1'), Buffer.alloc(0), async())
        }, function () {
            this._sheaf.hold(-1, { items: [{ id: 0 }]  })
        })
    })
})

Strata.prototype.open = cadence(function (async) {
    this.sheaf.createMagazine()

    // TODO instead of rescue, you might try/catch the parts that you know
    // are likely to cause errors and raise an error of a Strata type.

    // TODO or you might need some way to catch a callback error. Maybe an
    // outer most catch block?

    // TODO or if you're using Cadence, doesn't the callback get wrapped
    // anyway?
    async(function () {
        fs.stat(this.sheaf.directory, async())
    }, function stat (error, stat) {
        fs.readdir(path.join(this.sheaf.directory, 'pages'), async())
    }, function (files) {
        files.forEach(function (file) {
            if (/^\d+\.\d+$/.test(file)) {
                this.sheaf.nextAddress = Math.max(+(file.split('.').shift()) + 1, this.sheaf.nextAddress)
            }
        }, this)
    })
})

Strata.prototype.close = cadence(function (async) {
    return
    // TODO that's a lot of indirection.
    var cartridge = this.sheaf.metaRoot.cartridge, lock = cartridge.value.page.lock

    lock.unlock()
    // TODO
    lock.dispose()

    cartridge.release()

    var purge = this.sheaf.magazine.purge()
    while (purge.cartridge) {
        purge.cartridge.remove()
        purge.next()
    }
    purge.release()

    ok(!this.sheaf.magazine.count, 'pages still held by cache')
})

Strata.prototype.left = function (descents, exclusive, callback) {
    this.toLeaf(descents[0].left, descents, null, exclusive, callback)
}

Strata.prototype.right = function (descents, exclusive, callback) {
    this.toLeaf(descents[0].right, descents, null, exclusive, callback)
}

Strata.prototype.key = function (key) {
    return function (descents, exclusive, callback) {
        this.toLeaf(descents[0].key(key), descents, null, exclusive, callback)
    }
}

Strata.prototype.leftOf = function (key) {
    return cadence(function (async, descents, exclusive) {
        var conditions = [ descents[0].leaf, descents[0].found([key]) ]
        async(function () {
            descents[0].descend(descents[0].key(key), function () {
                return conditions.some(function (condition) {
                    return condition.call(descents[0])
                })
            }, async())
        }, function (page, index) {
            if (descents[0].page.address % 2) {
                return [ new Cursor(this.sheaf, this.logger, descents, false, key) ]
            } else {
                descents[0].setIndex(descents[0].index - 1)
                this.toLeaf(descents[0].right, descents, null, exclusive, async())
            }
        })
    })
}

Strata.prototype.toLeaf = cadence(function (async, sought, descents, key, exclusive) {
    async(function () {
        descents[0].descend(sought, descents[0].penultimate, async())
    }, function () {
        if (exclusive) descents[0].exclude()
        descents[0].descend(sought, descents[0].leaf, async())
    }, function () {
        return [ new Cursor(this.sheaf, this.logger, descents, exclusive, key) ]
    })
})

Strata.prototype.cursor = cadence(function (async, key, exclusive) {
    // We hold onto all cartridges until we're done, even retries, so we're
    // going to end up holding cartridges two or more times, but we'll make
    // progress eventually and release everything.
    var cartridges = []
    async([function () {
        cartridges.forEach(function (cartridge) { cartridge.release() })
    }], function () {
        async.block(function () {
            var cartridge, index = 0
            cartridges.push(cartridge = this._sheaf.hold(-1, null))
            for (;;) {
                var id = cartridge.value.items[index].id
                cartridges.push(cartridge = this._sheaf.hold(id))
                if (cartridge.value == null) {
                    return async(function () {
                        this._journalist.load(id, async())
                    }, function () {
                        return [ async.continue ]
                    })
                }
                var page = cartridge.value
                index = this.sheaf.find(cartridge.value, key, page.leaf ? page.ghosts : 1)
                if (page.leaf) {
                    break
                } else if (index < 0) {
                    // On a branch, unless we hit the key exactly, we're
                    // pointing at the insertion point which is right after
                    // the branching we're supposed to decend, so back it up
                    // one unless it's a bullseye.
                    index = ~index - 1
                }
            }
            // Pop the last cartridge to give to the cursor; we don't release it
            // the cursor does.
            return new Cursor(this.sheaf, cartridges.pop(), key, index)
        })
    })
    return
    var descents = [ new Descent(this.sheaf, this.sheaf.createLocker()) ]
    async([function () {
        if (descents.length) {
            descents[0].locker.unlock(descents[0].page)
            descents[0].locker.dispose()
        }
    }], function () {
        if  (typeof key == 'function') {
            key.call(this, descents, exclusive, async())
        } else {
            this.toLeaf(descents[0].key(key), descents, key, exclusive, async())
        }
    }, function (cursor) {
        return [ cursor ]
    })
})

Strata.prototype.iterator = function (key, callback) {
    this.cursor(key, false, callback)
}

Strata.prototype.mutator = function (key, callback) {
    this.cursor(key, true, callback)
}

Strata.prototype.balance = function (callback) {
    new Balancer(this.sheaf, this.logger).balance(callback)
}

Strata.prototype.vivify = cadence(function (async) {
    var locker = this.sheaf.createLocker(), root

    function record (item) {
        return { address: item.address }
    }

    var expand = cadence(function (async, parent, pages, index) {
        async(function () {
            if (index < pages.length) {
                var address = pages[index].address
                async(function () {
                    locker.lock(address, false, async())
                }, [function (page) {
                    locker.unlock(page)
                }])
            } else {
                return [ async.return, pages ]
            }
        }, function (page) {
            if (page.address % 2 == 0) {
                async(function () {
                    pages[index].children = page.items.map(record)
                    if (index) {
                        pages[index].key = parent.items[index].key
                    }
                    expand.call(this, page, pages[index].children, 0, async())
                }, function () {
                    expand.call(this, parent, pages, index + 1, async())
                })
            } else {
                async(function () {
                    pages[index].children = []
                    pages[index].ghosts = page.ghosts

                    for (var i = 0, I = page.items.length; i < I; i++) {
                        pages[index].children.push(page.items[i].record)
                    }
                }, function () {
                    expand.call(this, parent, pages, index + 1, async())
                })
            }
        }, function () {
            return [ pages ]
        })
    })

    async(function () {
        locker.lock(0, false, async())
    }, function (page) {
        async([function () {
            locker.unlock(page)
            locker.dispose()
        }], function () {
            expand.call(this, page, root = page.items.map(record), 0, async())
        })
    })
})

Strata.prototype.purge = function (downTo) {
    var purge = this.sheaf.magazine.purge()
    while (purge.cartridge && this.sheaf.magazine.heft > downTo) {
        purge.cartridge.remove()
        purge.next()
    }
    purge.release()
}

Strata.prototype.__defineGetter__('balanced', function () {
    ok(false)
    return ! Object.keys(this.sheaf.lengths).length
})

module.exports = Strata
<|endoftext|>