<commit_before>(function () {

    var defaults = {
        chart: {
            gridlines: 'none',
            padding: {
                top: 6,
                bottom: 25,
                left: 0,
                right: 5
            }
        },

        xAxis: {
            rangePadding: 0,
            innerTickSize: 0,
            outerTickSize: 0,
            tickPadding: 6,
            titlePadding: 4,
            firstAndLast: true,
            orient: 'bottom',
            labels: {
                // format: 'd'
            },
            linearDomain: false,     // specify if a time domain should be treated linearly or ....
        },

        yAxis: {
            min: 0,
            max: undefined,
            smartAxis: true,
            innerTickSize: 6,
            outerTickSize: 6,
            tickPadding: 4,
            titlePadding: 4,
            orient: 'left',
            labels: {
                align: 'middle',
                format: 's' // d3 formats

            }
        }
    };

    /*
    * Provides a cartesian frame to the Narwhal instance
    *
    * Example:
    *
    *     new Narwhal(options)
    *           .cartesian();
    *
    * Now new visualizations have accecss to the cartesian frame functionality
    * @name .cartesian()
    */
    var cartesian = {
        dataSrc: [],

        init: function (options) {

            this.options = _.merge({}, defaults, options);

            if (!this.options.xAxis.firstAndLast) {
                this.options.chart.padding.right += 15;
            }

            return this;
        },

        adjustPadding: function () {
            var options = this.options.yAxis;
            var yLabels = [10000];
            var format = d3.format(options.labels.format);
            var yAxisText = _.map(yLabels, format).join('
');
            var yLabelBounds = _.nw.textBounds(yAxisText, '.y.axis');
            var xLabelBounds = _.nw.textBounds('jgitlhHJKQWE', '.x.axis');
            var maxTickSize = function (options) { return Math.max(options.outerTickSize || 0, options.innerTickSize || 0); };

            this.options.chart.padding.left = maxTickSize(this.options.yAxis) + (this.options.yAxis.tickPadding || 0) + yLabelBounds.width;
            this.options.chart.padding.bottom = maxTickSize(this.options.xAxis) + (this.options.xAxis.tickPadding || 0) + xLabelBounds.height;
        },

        adjustTitlePadding: function () {
            var titleBounds;
            if (this.options.xAxis.title || this.options.yAxis.title) {
                if(this.options.xAxis.title) {
                    titleBounds = _.nw.textBounds(this.options.xAxis.title, '.x.axis-title');
                    this.options.chart.padding.bottom += titleBounds.height + this.options.xAxis.titlePadding;
                }

                if(this.options.yAxis.title) {
                    titleBounds = _.nw.textBounds(this.options.yAxis.title, '.y.axis-title');
                    this.options.chart.padding.left += titleBounds.height + this.options.yAxis.titlePadding;
                }
            }
        },

        computeXScale: function () {
            if (!this.xDomain) throw new Error('You are trying to render without setting data (xDomain).');

            this.xScaleGenerator = _.nw.xScaleFactory(this.dataSrc, this.options);
            this.xScale = this.xScaleGenerator.scale(this.xDomain);
            this.rangeBand = this.xScaleGenerator.rangeBand();
        },

        computeYScale: function () {
            if (!this.yDomain) throw new Error('You are trying to render without setting data (yDomain).');

            var yScaleDomain = _.nw.extractScaleDomain(this.yDomain, this.options.yAxis.min, this.options.yAxis.max);
            this.yScaleGenerator = _.nw.yScaleFactory(this.dataSrc, this.options, this.yMin, this.yMax);
            this.yScale = this.yScaleGenerator.scale(yScaleDomain);
        },

        /*
        * Provides a scaling function based on the xAxis values.
        *
        * Example:
        *
        *     var scaledValue = this.xScale(100);
        *
        * @function this.xScale()
        * @param {Number|String} value The value to be scaled
        * @return {Number} The scaled value according to the current xAxis settings
        */
        xScale: function(val) { return val; },

        /*
        * Provides a scaling function based on the xAxis values.
        *
        * Example:
        *
        *     var scaledValue = this.xScale(100);
        *
        * @function this.yScale()
        * @param {Number} value The value to be scaled
        * @return {Number} The scaled value according to the current yAxis settings
        */
        yScale: function(val) { return val; },

        /*
        * Modifies the domain for the y axis.
        *
        * Example:
        *
        *     this.setYDomain([100, 200]);
        *
        * @param {Array} domain The domain array represeting the min and max values of to be visible in the y Axis
        */
        setYDomain: function (domain) {
            this.yScaleGenerator.setDomain(domain);
        },

        /*
        * Redraws the yAxis with the new settings and domain
        *
        * Example:
        *
        *     this.redrawYAxis(;
        *
        */
        redrawYAxis: function () {
            this.svg.select(".y.axis").call(this.yAxis());
            this.renderGridlines();
        },

        computeScales: function () {
            this.computeXScale();
            this.computeYScale();

            return this;
        },

        xAxis: function () {
            return this.xScaleGenerator.axis().orient(this.options.xAxis.orient);
        },

        yAxis: function () {
            return this.yScaleGenerator.axis().orient(this.options.yAxis.orient);
        },

        renderXAxis: function () {
            var xAxis = this.xAxis();
            var y = this.options.chart.plotHeight + this.options.chart.padding.top;
            this._xAxisGroup = this.svg
                .append('g')
                .attr('class', 'x axis')
                .attr('transform', 'translate(' + this.options.chart.padding.left + ',' + y + ')')
                .call(xAxis);

            this.xScaleGenerator.postProcessAxis(this._xAxisGroup);

            return this;
        },

        renderYAxis: function () {
            var options = this.options.yAxis;
            var alignmentOffset = { top: '.8em', middle: '.35em', bottom: '0' };
            var x = this.options.chart.padding.left;
            var y = this.options.chart.padding.top;
            var yAxis = this.yAxis();

            this._yAxisGroup = this.svg
                .append('g')
                .attr('class', 'y axis')
                .attr('transform', 'translate(' + x + ',' + y + ')')
                .call(yAxis);

            this._yAxisGroup
                .selectAll('text')
                    .attr('dy', alignmentOffset[options.labels.align]);

            return this;
        },

        renderAxisLabels: function () {
            var lineHeightAdjustment = this.titleOneEm * 0.25; // add 25% of font-size for a complete line-height
            var adjustFactor = 40/46.609; // this factor is to account for the difference between the actual svg size and what we get from the DOM
            var bounds, x, y;

            if (this.options.xAxis.title) {
                bounds = _.nw.textBounds(this.options.xAxis.title, '.x.axis-title');
                y = this.options.chart.padding.bottom;
                x = 0;
                this._xAxisGroup.append('text')
                    .attr('class', 'x axis-title')
                    .attr('x', x)
                    .attr('y', y)
                    .attr('dx', (this.options.chart.plotWidth - bounds.width) / 2)
                    .attr('dy', -2) // just because
                    .text(this.options.xAxis.title);
            }

            if (this.options.yAxis.title) {
                bounds = _.nw.textBounds(this.options.yAxis.title, '.y.axis-title');
                y = -this.options.chart.padding.left + bounds.height * adjustFactor;
                x = 0;
                this._yAxisGroup.append('text')
                    .attr('class', 'y axis-title')
                    .attr('transform', 'rotate(-90)')
                    .attr('x', x)
                    .attr('y', y)
                    .attr('dx', -(this.options.chart.plotHeight + bounds.width) / 2)
                    .attr('dy', 0)
                    .text(this.options.yAxis.title);
            }
        },

        renderGridlines: function () {
            var option = this.options.chart.gridlines;
            var horizontal = option === 'horizontal' || option === 'both';
            var vertical = option === 'vertical' || option === 'both';

            function getYTicks(axis, smart) {
                var tickValues = axis.tickValues();

                if(!tickValues) {
                    var numTicks = axis.ticks()[0];
                    return axis.scale().ticks(numTicks).slice(1);
                }

                smart && tickValues.pop();

                return tickValues.slice(1);
            }

            function getXTicks(axis) {
                return axis.tickValues() || (axis.scale().ticks ? axis.scale().ticks().slice(1) : axis.scale().domain());
            }

            var ticks, gr;
            var x = this.xScale;
            var y = this.yScale;

            if(horizontal) {

                // remove previous lines (TODO: we need a better way)
                this._yAxisGroup.select('g.grid-lines').remove();
                gr = this._yAxisGroup
                    .append('svg:g')
                    .attr('class', 'grid-lines');

                ticks = getYTicks(this.yAxis(), this.options.yAxis.smartAxis);
                var w = this.options.chart.plotWidth;

                gr.selectAll('.grid-line')
                    .data(ticks)
                    .enter().append('line')
                        .attr('class', 'grid-line')
                        .attr('x1', 0)
                        .attr('x2', w)
                        .attr('y1', y)
                        .attr('y2', y);
            }

            if(vertical) {
                // remove previous lines (TODO: we need a better way)
                this._xAxisGroup.select('g.grid-lines').remove();
                gr = this._xAxisGroup.append('svg:g').attr('class', 'grid-lines');
                ticks = getXTicks(this.xAxis());
                var offset = this.rangeBand / 2;
                var h = this.options.chart.plotHeight;

                gr.selectAll('.grid-line')
                    .data(ticks)
                    .enter().append('line')
                        .attr('class', 'grid-line')
                        .attr('x1', function (d) { return x(d) + offset; })
                        .attr('x2', function (d) { return x(d) + offset; })
                        .attr('y1', -h)
                        .attr('y2', 0);
            }

            return this;
        },

        render: function () {
            this.composeOptions();

            this.adjustDomain();

            this.calcMetrics();

            this.computeScales();

            this.baseRender();

            this.renderXAxis()
                .renderYAxis()
                .renderGridlines()
                .renderAxisLabels();

            this.renderVisualizations();

            return this;
        },

        datum: function (d, index) {
            if(_.isObject(d) && _.isArray(d.data))
                return _.map(d.data, _.bind(this.datum, this));

            return {
                y: _.isObject(d) ? d.y : d,
                x: _.isObject(d) ? d.x : this.options.xAxis.categories ? this.options.xAxis.categories[index] : index
            };
        },

        data: function (series) {

            if (series instanceof Array && !series.length) {
                return this;
            } else if (series instanceof Array && !series[0].data) {
                this.dataSrc = _.map(series, _.bind(this.datum, this));
                this.xDomain = this.extractXDomain(this.dataSrc);
                this.yDomain = this.options.chart.stacked ? this.extractYStackedDomain(this.dataSrc) : this.extractYDomain(this.dataSrc);
                this.yMax = this.getYAxisDataMax(this.dataSrc);
                this.yMin = this.getYAxisDataMin(this.dataSrc);
            } else if (series instanceof Array && series[0].data) {
                // we have an array of series
                _.each(series, function (set) { this.data(set.data); }, this);
            }

            return this;
        },

        getYAxisDataMax: function (data) {
            return Math.max(this.yMax || 0, _.max(_.pluck(data, 'y')));
        },

        getYAxisDataMin: function (data) {
            return Math.min(this.yMin || 0, _.min(_.pluck(data, 'y')));
        },

        extractXDomain: function(data) {
            return  this.options.xAxis.categories ? this.options.xAxis.categories : _.pluck(data, 'x');
        },

        extractYDomain: function (data) {
            var max = this.yDomain ? Math.max(this.yDomain[1], _.max(_.pluck(data, 'y'))) : _.max(_.pluck(data, 'y'));
            var min = this.yDomain ? Math.min(this.yDomain[0], _.min(_.pluck(data, 'y'))) : _.min(_.pluck(data, 'y'));

            return [min, max];
        },

        extractYStackedDomain: function (data) {
            var dataSets = _.pluck(data, 'data');
            var maxLength = _.max(dataSets, function (d) { return d.length; });
            var stackY = [];

            for (var j=0; j<maxLength; j++) {
                _.each(dataSets, function (datum) {
                    stackY[j] = datum && datum.y ? (stackY[j] || 0) + datum.y : (stackY[j] || 0);
                });
            }

            return [_.min(stackY), _.max(stackY)];
        },

        adjustDomain: function () {
            this.yDomain = this.yDomain ? this.yDomain : [0, 10];
            this.xDomain = this.xDomain ? this.xDomain : [];
        }
    };

    Narwhal.expose('cartesian', cartesian);

})();
<commit_msg>Fixed autopadding for yAxis<commit_after>(function () {

    var defaults = {
        chart: {
            gridlines: 'none',
            padding: {
                top: 6,
                bottom: 25,
                left: 0,
                right: 5
            }
        },

        xAxis: {
            rangePadding: 0,
            innerTickSize: 0,
            outerTickSize: 0,
            tickPadding: 6,
            titlePadding: 4,
            firstAndLast: true,
            orient: 'bottom',
            labels: {
                // format: 'd'
            },
            linearDomain: false,     // specify if a time domain should be treated linearly or ....
        },

        yAxis: {
            min: 0,
            max: undefined,
            smartAxis: true,
            innerTickSize: 6,
            outerTickSize: 6,
            tickPadding: 4,
            titlePadding: 4,
            orient: 'left',
            labels: {
                align: 'middle',
                format: 's' // d3 formats

            }
        }
    };

    /*
    * Provides a cartesian frame to the Narwhal instance
    *
    * Example:
    *
    *     new Narwhal(options)
    *           .cartesian();
    *
    * Now new visualizations have accecss to the cartesian frame functionality
    * @name .cartesian()
    */
    var cartesian = {
        dataSrc: [],

        init: function (options) {

            this.options = _.merge({}, defaults, options);

            if (!this.options.xAxis.firstAndLast) {
                this.options.chart.padding.right += 15;
            }

            return this;
        },

        adjustPadding: function () {
            var options = this.options.yAxis;
            var yLabels = this.yDomain.slice().concat([_.nw.niceRound(this.yDomain[1])]);
            var format = d3.format(options.labels.format);
            var yAxisText = _.map(yLabels, format).join('
');
            var yLabelBounds = _.nw.textBounds(yAxisText, '.y.axis');
            var xLabelBounds = _.nw.textBounds('jgitlhHJKQWE', '.x.axis');
            var maxTickSize = function (options) { return Math.max(options.outerTickSize || 0, options.innerTickSize || 0); };

            this.options.chart.padding.left = maxTickSize(this.options.yAxis) + (this.options.yAxis.tickPadding || 0) + yLabelBounds.width;
            this.options.chart.padding.bottom = maxTickSize(this.options.xAxis) + (this.options.xAxis.tickPadding || 0) + xLabelBounds.height;
        },

        adjustTitlePadding: function () {
            var titleBounds;
            if (this.options.xAxis.title || this.options.yAxis.title) {
                if(this.options.xAxis.title) {
                    titleBounds = _.nw.textBounds(this.options.xAxis.title, '.x.axis-title');
                    this.options.chart.padding.bottom += titleBounds.height + this.options.xAxis.titlePadding;
                }

                if(this.options.yAxis.title) {
                    titleBounds = _.nw.textBounds(this.options.yAxis.title, '.y.axis-title');
                    this.options.chart.padding.left += titleBounds.height + this.options.yAxis.titlePadding;
                }
            }
        },

        computeXScale: function () {
            if (!this.xDomain) throw new Error('You are trying to render without setting data (xDomain).');

            this.xScaleGenerator = _.nw.xScaleFactory(this.dataSrc, this.options);
            this.xScale = this.xScaleGenerator.scale(this.xDomain);
            this.rangeBand = this.xScaleGenerator.rangeBand();
        },

        computeYScale: function () {
            if (!this.yDomain) throw new Error('You are trying to render without setting data (yDomain).');

            var yScaleDomain = _.nw.extractScaleDomain(this.yDomain, this.options.yAxis.min, this.options.yAxis.max);
            this.yScaleGenerator = _.nw.yScaleFactory(this.dataSrc, this.options, this.yMin, this.yMax);
            this.yScale = this.yScaleGenerator.scale(yScaleDomain);
        },

        /*
        * Provides a scaling function based on the xAxis values.
        *
        * Example:
        *
        *     var scaledValue = this.xScale(100);
        *
        * @function this.xScale()
        * @param {Number|String} value The value to be scaled
        * @return {Number} The scaled value according to the current xAxis settings
        */
        xScale: function(val) { return val; },

        /*
        * Provides a scaling function based on the xAxis values.
        *
        * Example:
        *
        *     var scaledValue = this.xScale(100);
        *
        * @function this.yScale()
        * @param {Number} value The value to be scaled
        * @return {Number} The scaled value according to the current yAxis settings
        */
        yScale: function(val) { return val; },

        /*
        * Modifies the domain for the y axis.
        *
        * Example:
        *
        *     this.setYDomain([100, 200]);
        *
        * @param {Array} domain The domain array represeting the min and max values of to be visible in the y Axis
        */
        setYDomain: function (domain) {
            this.yScaleGenerator.setDomain(domain);
        },

        /*
        * Redraws the yAxis with the new settings and domain
        *
        * Example:
        *
        *     this.redrawYAxis(;
        *
        */
        redrawYAxis: function () {
            this.svg.select(".y.axis").call(this.yAxis());
            this.renderGridlines();
        },

        computeScales: function () {
            this.computeXScale();
            this.computeYScale();

            return this;
        },

        xAxis: function () {
            return this.xScaleGenerator.axis().orient(this.options.xAxis.orient);
        },

        yAxis: function () {
            return this.yScaleGenerator.axis().orient(this.options.yAxis.orient);
        },

        renderXAxis: function () {
            var xAxis = this.xAxis();
            var y = this.options.chart.plotHeight + this.options.chart.padding.top;
            this._xAxisGroup = this.svg
                .append('g')
                .attr('class', 'x axis')
                .attr('transform', 'translate(' + this.options.chart.padding.left + ',' + y + ')')
                .call(xAxis);

            this.xScaleGenerator.postProcessAxis(this._xAxisGroup);

            return this;
        },

        renderYAxis: function () {
            var options = this.options.yAxis;
            var alignmentOffset = { top: '.8em', middle: '.35em', bottom: '0' };
            var x = this.options.chart.padding.left;
            var y = this.options.chart.padding.top;
            var yAxis = this.yAxis();

            this._yAxisGroup = this.svg
                .append('g')
                .attr('class', 'y axis')
                .attr('transform', 'translate(' + x + ',' + y + ')')
                .call(yAxis);

            this._yAxisGroup
                .selectAll('text')
                    .attr('dy', alignmentOffset[options.labels.align]);

            return this;
        },

        renderAxisLabels: function () {
            var lineHeightAdjustment = this.titleOneEm * 0.25; // add 25% of font-size for a complete line-height
            var adjustFactor = 40/46.609; // this factor is to account for the difference between the actual svg size and what we get from the DOM
            var bounds, x, y;

            if (this.options.xAxis.title) {
                bounds = _.nw.textBounds(this.options.xAxis.title, '.x.axis-title');
                y = this.options.chart.padding.bottom;
                x = 0;
                this._xAxisGroup.append('text')
                    .attr('class', 'x axis-title')
                    .attr('x', x)
                    .attr('y', y)
                    .attr('dx', (this.options.chart.plotWidth - bounds.width) / 2)
                    .attr('dy', -2) // just because
                    .text(this.options.xAxis.title);
            }

            if (this.options.yAxis.title) {
                bounds = _.nw.textBounds(this.options.yAxis.title, '.y.axis-title');
                y = -this.options.chart.padding.left + bounds.height * adjustFactor;
                x = 0;
                this._yAxisGroup.append('text')
                    .attr('class', 'y axis-title')
                    .attr('transform', 'rotate(-90)')
                    .attr('x', x)
                    .attr('y', y)
                    .attr('dx', -(this.options.chart.plotHeight + bounds.width) / 2)
                    .attr('dy', 0)
                    .text(this.options.yAxis.title);
            }
        },

        renderGridlines: function () {
            var option = this.options.chart.gridlines;
            var horizontal = option === 'horizontal' || option === 'both';
            var vertical = option === 'vertical' || option === 'both';

            function getYTicks(axis, smart) {
                var tickValues = axis.tickValues();

                if(!tickValues) {
                    var numTicks = axis.ticks()[0];
                    return axis.scale().ticks(numTicks).slice(1);
                }

                smart && tickValues.pop();

                return tickValues.slice(1);
            }

            function getXTicks(axis) {
                return axis.tickValues() || (axis.scale().ticks ? axis.scale().ticks().slice(1) : axis.scale().domain());
            }

            var ticks, gr;
            var x = this.xScale;
            var y = this.yScale;

            if(horizontal) {

                // remove previous lines (TODO: we need a better way)
                this._yAxisGroup.select('g.grid-lines').remove();
                gr = this._yAxisGroup
                    .append('svg:g')
                    .attr('class', 'grid-lines');

                ticks = getYTicks(this.yAxis(), this.options.yAxis.smartAxis);
                var w = this.options.chart.plotWidth;

                gr.selectAll('.grid-line')
                    .data(ticks)
                    .enter().append('line')
                        .attr('class', 'grid-line')
                        .attr('x1', 0)
                        .attr('x2', w)
                        .attr('y1', y)
                        .attr('y2', y);
            }

            if(vertical) {
                // remove previous lines (TODO: we need a better way)
                this._xAxisGroup.select('g.grid-lines').remove();
                gr = this._xAxisGroup.append('svg:g').attr('class', 'grid-lines');
                ticks = getXTicks(this.xAxis());
                var offset = this.rangeBand / 2;
                var h = this.options.chart.plotHeight;

                gr.selectAll('.grid-line')
                    .data(ticks)
                    .enter().append('line')
                        .attr('class', 'grid-line')
                        .attr('x1', function (d) { return x(d) + offset; })
                        .attr('x2', function (d) { return x(d) + offset; })
                        .attr('y1', -h)
                        .attr('y2', 0);
            }

            return this;
        },

        render: function () {
            this.composeOptions();

            this.adjustDomain();

            this.calcMetrics();

            this.computeScales();

            this.baseRender();

            this.renderXAxis()
                .renderYAxis()
                .renderGridlines()
                .renderAxisLabels();

            this.renderVisualizations();

            return this;
        },

        datum: function (d, index) {
            if(_.isObject(d) && _.isArray(d.data))
                return _.map(d.data, _.bind(this.datum, this));

            return {
                y: _.isObject(d) ? d.y : d,
                x: _.isObject(d) ? d.x : this.options.xAxis.categories ? this.options.xAxis.categories[index] : index
            };
        },

        data: function (series) {

            if (series instanceof Array && !series.length) {
                return this;
            } else if (series instanceof Array && !series[0].data) {
                this.dataSrc = _.map(series, _.bind(this.datum, this));
                this.xDomain = this.extractXDomain(this.dataSrc);
                this.yDomain = this.options.chart.stacked ? this.extractYStackedDomain(this.dataSrc) : this.extractYDomain(this.dataSrc);
                this.yMax = this.getYAxisDataMax(this.dataSrc);
                this.yMin = this.getYAxisDataMin(this.dataSrc);
            } else if (series instanceof Array && series[0].data) {
                // we have an array of series
                _.each(series, function (set) { this.data(set.data); }, this);
            }

            return this;
        },

        getYAxisDataMax: function (data) {
            return Math.max(this.yMax || 0, _.max(_.pluck(data, 'y')));
        },

        getYAxisDataMin: function (data) {
            return Math.min(this.yMin || 0, _.min(_.pluck(data, 'y')));
        },

        extractXDomain: function(data) {
            return  this.options.xAxis.categories ? this.options.xAxis.categories : _.pluck(data, 'x');
        },

        extractYDomain: function (data) {
            var max = this.yDomain ? Math.max(this.yDomain[1], _.max(_.pluck(data, 'y'))) : _.max(_.pluck(data, 'y'));
            var min = this.yDomain ? Math.min(this.yDomain[0], _.min(_.pluck(data, 'y'))) : _.min(_.pluck(data, 'y'));

            return [min, max];
        },

        extractYStackedDomain: function (data) {
            var dataSets = _.pluck(data, 'data');
            var maxLength = _.max(dataSets, function (d) { return d.length; });
            var stackY = [];

            for (var j=0; j<maxLength; j++) {
                _.each(dataSets, function (datum) {
                    stackY[j] = datum && datum.y ? (stackY[j] || 0) + datum.y : (stackY[j] || 0);
                });
            }

            return [_.min(stackY), _.max(stackY)];
        },

        adjustDomain: function () {
            this.yDomain = this.yDomain ? this.yDomain : [0, 10];
            this.xDomain = this.xDomain ? this.xDomain : [];
        }
    };

    Narwhal.expose('cartesian', cartesian);

})();
<|endoftext|>


<commit_before>/**
 * InvertedIndex Class
 * @class
 */
class invertedIndex {
  /**
   * class constructor
   * @constructor
   */
  constructor() {
    this.indexMap = {};
  }

  /**
   * Sanitizes text by removing invalid symbols.
   * @function
   * @param {String} indexes - String to sanitize
   * @return {Array} array of words without special characters or symbols.
   */
  sanitize(indexes) {
    return indexes.map(word => word.toLowerCase()
      .replace(/[!''@#$%^&*,'.]/g, ""));
  }

  /**
   * Create File Index
   * @function
   * @param {String} fileName-Uploaded file
   * @param {String} fileContent- Contents of the Json file.
   * @return {Array} returns filename, merged and sanitized contents of the json file
   */
  createIndex(fileName, fileContent) {
    const completeIndex = [];
    for (let value of fileContent) {
      const title = value.title;
      const splitTitle = title.split(' ');
      const textTitle = this.sanitize(splitTitle);

      const text = value.text;
      const splitText = text.split(' ');
      const content = this.sanitize(splitText);

      const mergeWords = content.concat(textTitle);
      completeIndex.push(mergeWords);
    }
    this.storeIndex(fileName, completeIndex);
    return [fileName, completeIndex];
  }

  /**
   * Stores the File Index
   * @function
   * @param {String} fileName
   * @param {String} fileContents
   * @return {Array} stores fileName and fileContent in the indexMap
   */
  storeIndex(textTitle, completeIndex) {
    const words = {};

    for (let pos in completeIndex) {
      completeIndex[pos].forEach((word) => {
        if (words[word]) {
          if (words[word].indexOf(pos) === -1) {
            words[word].push(pos);
          }
        } else {
          words[word] = [pos];
        }
      });
    }
    return this.indexMap[textTitle] = words;
  }

  /**
   * Get File Index
   * @function
   * @param {String} fileName
   * @return {Object} returns file contents
   */
  getIndex(fileName) {
    return this.indexMap[fileName];
  }

  /**
   * Search Index
   * @function
   * @param {String} fileName
   * @param {String} terms
   * @return {Object} returns search results
   */
  searchIndex(fileName, terms) {
    const searchResult = {};
    let query = terms.split(' ');
    let sanitizeQuery = this.sanitize(query);
    var result = this.indexMap;

    sanitizeQuery.forEach((term) => {
      if (result[fileName][term]) {
        searchResult[term] = result[fileName][term];
      }
    });
    return searchResult;
  }
}<commit_msg>feature(search): Update code documentation and address formatting issues<commit_after>/**
 * InvertedIndex Class
 * @class
 */
class invertedIndex {
  /**
   * class constructor
   * @constructor
   */
  constructor() {
    this.indexMap = {};
  }

  /**
   * Sanitizes text by removing invalid symbols.
   * @function
   * @param {String} indexes - String to sanitize
   * @return {Array} array of words without special characters or symbols.
   */
  sanitize(indexes) {
    return indexes.map(word => word.toLowerCase()
      .replace(/[!''@#$%^&*,'.]/g, ''));
  }

  /**
   * Create File Index
   * @function
   * @param {String} fileName-Uploaded file
   * @param {String} fileContent- Contents of the Json file.
   * @return {Array} filename,merged & sanitized contents of the Json file
   */
  createIndex(fileName, fileContent) {
    const completeIndex = [];
    for (let value of fileContent) {
      const title = value.title;
      const splitTitle = title.split(' ');
      const textTitle = this.sanitize(splitTitle);

      const text = value.text;
      const splitText = text.split(' ');
      const content = this.sanitize(splitText);

      const mergeWords = content.concat(textTitle);
      completeIndex.push(mergeWords);
    }
    this.storeIndex(fileName, completeIndex);
    return [fileName, completeIndex];
  }

  /**
   * Stores the File Index
   * @function
   * @param {String} fileName
   * @param {String} fileContents
   * @return {Array} stores fileName and fileContent in the indexMap
   */
  storeIndex(textTitle, completeIndex) {
    const words = {};

    for (let pos in completeIndex) {
      completeIndex[pos].forEach((word) => {
        if (words[word]) {
          if (words[word].indexOf(pos) === -1) {
            words[word].push(pos);
          }
        } else {
          words[word] = [pos];
        }
      });
    }
    return this.indexMap[textTitle] = words;
  }

  /**
   * Get File Index
   * @function
   * @param {String} fileName
   * @return {Object} returns file contents
   */
  getIndex(fileName) {
    return this.indexMap[fileName];
  }

  /**
   * Search Index
   * @function
   * @param {String} fileName
   * @param {String} terms
   * @return {Object} returns search results
   */
  searchIndex(fileName, terms) {
    const searchResult = {};
    let query = terms.split(' ');
    let sanitizeQuery = this.sanitize(query);
    var result = this.indexMap;

    sanitizeQuery.forEach((term) => {
      if (result[fileName][term]) {
        searchResult[term] = result[fileName][term];
      }
    });
    return searchResult;
  }
}<|endoftext|>


<commit_before>"use strict";

module.exports = function(entity, game) { // eslint-disable-line no-unused-vars
	game.entities.remove(entity, "failure");
	game.entities.remove(entity, "onTap");
	game.entities.set(entity, "image", {
		"name": "egg-cracked.png"
	});
};
<commit_msg>Add dino<commit_after>"use strict";

module.exports = function(entity, game) { // eslint-disable-line no-unused-vars
	game.entities.remove(entity, "failure");
	game.entities.remove(entity, "onTap");
	var last = game.entities.find("failure").length === 0;
	game.entities.set(entity, "image", {
		"name": last ? "egg-dino.png" : "egg-cracked.png"
	});
};
<|endoftext|>


<commit_before>//= require folio/webp
//= require photoswipe/dist/photoswipe
//= require photoswipe/dist/photoswipe-ui-default

window.Folio = window.Folio || {}
window.Folio.Lightbox = {}

window.Folio.Lightbox.calls = []

window.Folio.Lightbox.instances = []

window.Folio.Lightbox.bind = (selector, options) => {
  options = options || {}

  window.Folio.Lightbox.calls.push([selector, options])

  const init = () => {
    const $items = $(selector)

    if ($items.length === 0) return

    if (options.individual) {
      $items.each(function () {
        let subSelector = `.${this.className.replace(/\s+/g, '.')}`

        if (options.itemSelector) {
          subSelector = `${subSelector} ${options.itemSelector}`
        }

        window.Folio.Lightbox.instances.push(new window.Folio.Lightbox.Lightbox({ subSelector, options }))
      })
    } else if (options.fromData) {
      $items.each((i, el) => {
        window.Folio.Lightbox.instances.push(new window.Folio.Lightbox.Lightbox({ selector, options, data: $(el).data('lightbox-image-data') }))
      })
    } else {
      window.Folio.Lightbox.instances.push(new window.Folio.Lightbox.Lightbox({ selector, options }))
    }
  }

  if (typeof Turbolinks !== 'undefined' && Turbolinks !== null) {
    $(document)
      .on('turbolinks:load', init)
      .on('turbolinks:before-render', function () {
        if (window.Folio.Lightbox.instances.length === 0) return

        window.Folio.Lightbox.instances.forEach((instance) => {
          instance.destroy()
        })

        window.Folio.Lightbox.instances = []
      })
  } else {
    $(() => setTimeout(init, 0))
  }
}

window.Folio.Lightbox.updateAll = () => {
  window.Folio.Lightbox.instances.forEach((instance) => instance.destroy())

  window.Folio.Lightbox.instances = []

  window.Folio.Lightbox.calls.forEach((call) => window.Folio.Lightbox.bind(call[0], call[1]))
}

window.Folio.Lightbox.Lightbox = class FolioLightbox {
  constructor (attrs) {
    this.selector = attrs.selector
    this.options = attrs.options

    if (attrs.additionalSelector) {
      this.fullSelector = `${this.selector}, ${attrs.additionalSelector}`
    } else {
      this.fullSelector = this.selector
    }

    this.eventIdentifier = 'folioLightbox'
    this.$html = $(document.documentElement)

    this.bind(attrs.data)
  }

  pswp () {
    this.$pswp || (this.$pswp = $('.pswp'))
    return this.$pswp
  }

  bind (data) {
    this.unbind()
    const that = this

    $(document).on(`click.${this.eventIdentifier}`, this.fullSelector, function (e) {
      e.preventDefault()

      const items = data || that.items()
      let index = 0

      if (typeof that.options.forceIndex !== 'undefined') {
        index = that.options.forceIndex
      } else {
        items.forEach((item, i) => {
          if (item.el === this) {
            index = i
          }
        })
      }

      that.photoSwipe = new PhotoSwipe(that.pswp()[0], PhotoSwipeUI_Default, items, {
        index: index,
        bgOpacity: 0.7,
        showHideOpacity: true,
        history: false,
        errorMsg: that.pswp().data('error-msg')
      })

      that.photoSwipe.init()
    })
  }

  items () {
    const items = []

    $(this.selector).each((i, el) => {
      const item = this.item(i, el)

      if (item) items.push(item)
    })

    return items
  }

  item (index, el) {
    let $el = $(el)

    if ($el.hasClass('f-image--sensitive-content')) {
      if (!this.$html.hasClass('f-html--show-sensitive-content')) return
    }

    if (!$el.data('lightbox-src')) {
      $el = $(el).find('[data-lightbox-src]')
    }

    if (!$el.length) return null

    return {
      w: parseInt($el.data('lightbox-width')),
      h: parseInt($el.data('lightbox-height')),
      title: $el.data('lightbox-title') || $el.next('figcaption').text(),
      src: window.Folio.Webp.supported ? $el.data('lightbox-webp-src') : $el.data('lightbox-src'),
      el: el
    }
  }

  unbind () {
    $(document).off(`click.${this.eventIdentifier}`, this.fullSelector)
  }

  destroy () {
    try {
      this.photoSwipe.close()
      this.photoSwipe.destroy()
    } catch (_error) {
    }

    this.photoSwipe = null
    this.unbind()
    this.$pswp = null
  }
}
<commit_msg>fix individual lightboxes js<commit_after>//= require folio/webp
//= require photoswipe/dist/photoswipe
//= require photoswipe/dist/photoswipe-ui-default

window.Folio = window.Folio || {}
window.Folio.Lightbox = {}

window.Folio.Lightbox.calls = []

window.Folio.Lightbox.instances = []

window.Folio.Lightbox.bind = (selector, options) => {
  options = options || {}

  window.Folio.Lightbox.calls.push([selector, options])

  const init = () => {
    const $items = $(selector)

    if ($items.length === 0) return

    if (options.individual) {
      $items.each(function () {
        let subSelector = `.${this.className.replace(/\s+/g, '.')}`

        if (options.itemSelector) {
          subSelector = `${subSelector} ${options.itemSelector}`
        }

        window.Folio.Lightbox.instances.push(new window.Folio.Lightbox.Lightbox({ selector, subSelector, options }))
      })
    } else if (options.fromData) {
      $items.each((i, el) => {
        window.Folio.Lightbox.instances.push(new window.Folio.Lightbox.Lightbox({ selector, options, data: $(el).data('lightbox-image-data') }))
      })
    } else {
      window.Folio.Lightbox.instances.push(new window.Folio.Lightbox.Lightbox({ selector, options }))
    }
  }

  if (typeof Turbolinks !== 'undefined' && Turbolinks !== null) {
    $(document)
      .on('turbolinks:load', init)
      .on('turbolinks:before-render', function () {
        if (window.Folio.Lightbox.instances.length === 0) return

        window.Folio.Lightbox.instances.forEach((instance) => {
          instance.destroy()
        })

        window.Folio.Lightbox.instances = []
      })
  } else {
    $(() => setTimeout(init, 0))
  }
}

window.Folio.Lightbox.updateAll = () => {
  window.Folio.Lightbox.instances.forEach((instance) => instance.destroy())

  window.Folio.Lightbox.instances = []

  window.Folio.Lightbox.calls.forEach((call) => window.Folio.Lightbox.bind(call[0], call[1]))
}

window.Folio.Lightbox.Lightbox = class FolioLightbox {
  constructor (attrs) {
    this.selector = attrs.selector
    this.options = attrs.options

    if (attrs.additionalSelector) {
      this.fullSelector = `${this.selector}, ${attrs.additionalSelector}`
    } else {
      this.fullSelector = this.selector
    }

    this.eventIdentifier = 'folioLightbox'
    this.$html = $(document.documentElement)

    this.bind(attrs.data)
  }

  pswp () {
    this.$pswp || (this.$pswp = $('.pswp'))
    return this.$pswp
  }

  bind (data) {
    this.unbind()
    const that = this

    $(document).on(`click.${this.eventIdentifier}`, this.fullSelector, function (e) {
      e.preventDefault()

      const items = data || that.items()
      let index = 0

      if (typeof that.options.forceIndex !== 'undefined') {
        index = that.options.forceIndex
      } else {
        items.forEach((item, i) => {
          if (item.el === this) {
            index = i
          }
        })
      }

      that.photoSwipe = new PhotoSwipe(that.pswp()[0], PhotoSwipeUI_Default, items, {
        index: index,
        bgOpacity: 0.7,
        showHideOpacity: true,
        history: false,
        errorMsg: that.pswp().data('error-msg')
      })

      that.photoSwipe.init()
    })
  }

  items () {
    const items = []

    $(this.selector).each((i, el) => {
      const item = this.item(i, el)

      if (item) items.push(item)
    })

    return items
  }

  item (index, el) {
    let $el = $(el)

    if ($el.hasClass('f-image--sensitive-content')) {
      if (!this.$html.hasClass('f-html--show-sensitive-content')) return
    }

    if (!$el.data('lightbox-src')) {
      $el = $(el).find('[data-lightbox-src]')
    }

    if (!$el.length) return null

    return {
      w: parseInt($el.data('lightbox-width')),
      h: parseInt($el.data('lightbox-height')),
      title: $el.data('lightbox-title') || $el.next('figcaption').text(),
      src: window.Folio.Webp.supported ? $el.data('lightbox-webp-src') : $el.data('lightbox-src'),
      el: el
    }
  }

  unbind () {
    $(document).off(`click.${this.eventIdentifier}`, this.fullSelector)
  }

  destroy () {
    try {
      this.photoSwipe.close()
      this.photoSwipe.destroy()
    } catch (_error) {
    }

    this.photoSwipe = null
    this.unbind()
    this.$pswp = null
  }
}
<|endoftext|>


<commit_before>/*
 * Converts JSON data received from the server to flat array of values.
 */
function jsonToValuesArray(jsonData) {
  var errMsgs = [];
  for (var key in jsonData) {
  	var values = jsonData[key];
    $.each(values, function (idx, val) {
      errMsgs.push(val);
	});
  }
  return errMsgs;
}

/*
 * Calls callback function on AJAX success (because built-in functions don't
 * work!)
 */
$.fn.onAjaxComplete = function (cb) {
  $(this)
  .on('ajax:success', function () {
	cb();
  })
  .on('ajax:error', function () {
	cb();
  });
}

// Number of all tutorial steps
var TUTORIAL_STEPS_CNT = 26;

/**
 * Initializes tutorial steps for the current page.
 * NOTE: You can specify steps manually in JS with steps parameter (preferred
 * way), or hardcode them in HTML
 * NOTE: If some steps edit page, then this function needs to be called several
 * times for the same page, but for different steps. The same goes if the page
 * has discontinuous tutorial steps. In such cases, use steps branching, e.g.:
 * @example
 * var tutorialData = Cookies.get('tutorial_data');
 * if (tutorialData) {
 *   tutorialData = JSON.parse(tutorialData);
 *   var stepNum = parseInt(Cookies.get('current_tutorial_step'), 10);
 *
 *   if (stepNum >= 6 && stepNum <= 7) {
 *     ...
 *   } else if ...
 * NOTE: If an element the popup is pointing at is of lesser horizontal length
 * than the popup itself, then it will not be positioned correctly if it's
 * position is top or bottom, so set/change the step's position to either left
 * or right (and don't use any custom styling!), e.g.:
 * @example
 * var steps = [
 *   {
 *     ...
 *     position: 'right'
 *   },
 *   {
 *   ...
 * ];
 * NOTE: If only one page step is needed, then make pageFirstStepN ==
 * pageLastStepN (both represent the one and only step number)
 *
 * @param  {number} pageFirstStepN Page's first step number
 * @param  {number} pageLastStepN Page's last step number
 * @param  {string} nextPagePath Next page absolute path
 * @param {function} beforeCb Callback called before the tutorial starts. Mainly
 *  used for setting 'pointer-events: none' on the elements the page's steps
 *  highlight.
 * @param {function} endCb Callback called after the tutorial ends. Mainly used
 *  for setting 'pointer-events: auto' on the elements the page's steps
 *  highlight.
 * @param {object} steps Optional JSON containing introJs steps. They can be
 *  specified here, or hardcoded in HTML.
 */
function initPageTutorialSteps(pageFirstStepN, pageLastStepN, nextPagePath,
                               beforeCb, endCb, steps) {
  var tutorialData = Cookies.get('tutorial_data');
  if (tutorialData) {
    tutorialData = JSON.parse(tutorialData);
    var stepNum = parseInt(Cookies.get('current_tutorial_step'), 10);
    if (isNaN(stepNum)) {
      // Cookies data initialization
      stepNum = 1;
      Cookies.set('current_tutorial_step', stepNum);
      tutorialData[0].backPagesPaths = [];
      Cookies.set('tutorial_data', tutorialData);
    }
    var thisPagePath = window.location.pathname;
    beforeCb();

    // Initialize tutorial for the current page's steps
    var doneLabel = (pageLastStepN === TUTORIAL_STEPS_CNT) ?
     'Start using sciNote' : 'End tutorial';
    if (_.isUndefined(steps)) {
      introJs()
       .setOptions({
         overlayOpacity: '0.2',
         prevLabel: 'Back',
         nextLabel: 'Next',
         skipLabel: 'End tutorial',
         doneLabel: doneLabel,
         showBullets: false,
         showStepNumbers: false,
         exitOnOverlayClick: false,
         exitOnEsc: false,
         disableInteraction: true,
         keyboardNavigation: false,
         tooltipClass: 'custom next-page-link'
       })
       .onexit(function() {
         location.reload();
       })
       .oncomplete(function() {
         location.reload();
       })
       .goToStep(stepNum - (pageFirstStepN - 1))
       .onexit(function() {
         Cookies.remove('tutorial_data');
         Cookies.remove('current_tutorial_step');
       })
       .oncomplete(function() {
         Cookies.remove('tutorial_data');
         Cookies.remove('current_tutorial_step');
       })
       .start();
    } else {
      if (pageFirstStepN === pageLastStepN) {
        // Only one page step, so add another fake one, so the back and next
        // buttons are added to the popup
        steps.push({});
      }
      introJs()
       .setOptions({
         overlayOpacity: '0.2',
         prevLabel: 'Back',
         nextLabel: 'Next',
         skipLabel: 'End tutorial',
         doneLabel: doneLabel,
         showBullets: false,
         showStepNumbers: false,
         exitOnOverlayClick: false,
         exitOnEsc: false,
         disableInteraction: true,
         keyboardNavigation: false,
         tooltipClass: 'custom next-page-link',
         steps: steps
       })
       .onexit(function() {
         location.reload();
       })
       .oncomplete(function() {
         location.reload();
       })
       .goToStep(stepNum - (pageFirstStepN - 1))
       .onexit(function() {
         Cookies.remove('tutorial_data');
         Cookies.remove('current_tutorial_step');
       })
       .oncomplete(function() {
         Cookies.remove('tutorial_data');
         Cookies.remove('current_tutorial_step');
       })
       .start();
    }

    // Page navigation when coming to this page from previous/next page
    $(function() {
      if (stepNum === pageFirstStepN && stepNum > 1) {
        $('.introjs-prevbutton').removeClass('introjs-disabled');
      } else if (stepNum === pageLastStepN && stepNum < TUTORIAL_STEPS_CNT) {
        $('.introjs-nextbutton').removeClass('introjs-disabled');
      }
    });

    // Page navigation when already on this page

    $('.introjs-skipbutton').click(function() {
      Cookies.remove('tutorial_data');
      Cookies.remove('current_tutorial_step');

      endCb();
    });

    $('.introjs-prevbutton').click(function() {
      if (stepNum > 1) {
        Cookies.set('current_tutorial_step', --stepNum);

        if (stepNum === pageFirstStepN && stepNum > 1) {
          $('.introjs-prevbutton').removeClass('introjs-disabled');
        } else if (stepNum < pageFirstStepN) {
          // Go to previous page;

          var prevPagePath = tutorialData[0].backPagesPaths.pop();
          Cookies.set('tutorial_data', tutorialData);
          $('.introjs-prevbutton').attr('href', prevPagePath);
          introJs().exit();
          endCb();
        }
      }
    });

    $('.introjs-nextbutton').click(function() {
      if (stepNum < TUTORIAL_STEPS_CNT) {
        Cookies.set('current_tutorial_step', ++stepNum);

        if (stepNum === pageLastStepN && stepNum < TUTORIAL_STEPS_CNT) {
          $('.introjs-nextbutton').removeClass('introjs-disabled');
        } else if (stepNum > pageLastStepN) {
          // Go to next page

          tutorialData[0].backPagesPaths.push(thisPagePath);
          Cookies.set('tutorial_data', tutorialData);
          $('.introjs-nextbutton').attr('href', nextPagePath);
          introJs().exit();
          endCb();
        }
      }
    });
  }
}
<commit_msg>Minor refactoring.<commit_after>/*
 * Converts JSON data received from the server to flat array of values.
 */
function jsonToValuesArray(jsonData) {
  var errMsgs = [];
  for (var key in jsonData) {
  	var values = jsonData[key];
    $.each(values, function (idx, val) {
      errMsgs.push(val);
	});
  }
  return errMsgs;
}

/*
 * Calls callback function on AJAX success (because built-in functions don't
 * work!)
 */
$.fn.onAjaxComplete = function (cb) {
  $(this)
  .on('ajax:success', function () {
	cb();
  })
  .on('ajax:error', function () {
	cb();
  });
}

// Number of all tutorial steps
var TUTORIAL_STEPS_CNT = 26;

/**
 * Initializes tutorial steps for the current page.
 * NOTE: You can specify steps manually in JS with steps parameter (preferred
 * way), or hardcode them in HTML
 * NOTE: If some steps edit page, then this function needs to be called several
 * times for the same page, but for different steps. The same goes if the page
 * has discontinuous tutorial steps. In such cases, use steps branching, e.g.:
 * @example
 * var tutorialData = Cookies.get('tutorial_data');
 * if (tutorialData) {
 *   tutorialData = JSON.parse(tutorialData);
 *   var stepNum = parseInt(Cookies.get('current_tutorial_step'), 10);
 *
 *   if (stepNum >= 6 && stepNum <= 7) {
 *     ...
 *   } else if ...
 * NOTE: If an element the popup is pointing at is of lesser horizontal length
 * than the popup itself, then it will not be positioned correctly if it's
 * position is top or bottom, so set/change the step's position to either left
 * or right (and don't use any custom styling!), e.g.:
 * @example
 * var steps = [
 *   {
 *     ...
 *     position: 'right'
 *   },
 *   {
 *   ...
 * ];
 * NOTE: If only one page step is needed, then make pageFirstStepN ==
 * pageLastStepN (both represent the one and only step number)
 *
 * @param  {number} pageFirstStepN Page's first step number
 * @param  {number} pageLastStepN Page's last step number
 * @param  {string} nextPagePath Next page absolute path
 * @param {function} beforeCb Callback called before the tutorial starts. Mainly
 *  used for setting 'pointer-events: none' on the elements the page's steps
 *  highlight.
 * @param {function} endCb Callback called after the tutorial ends. Mainly used
 *  for setting 'pointer-events: auto' on the elements the page's steps
 *  highlight.
 * @param {object} steps Optional JSON containing introJs steps. They can be
 *  specified here, or hardcoded in HTML.
 */
function initPageTutorialSteps(pageFirstStepN, pageLastStepN, nextPagePath,
                               beforeCb, endCb, steps) {
  var tutorialData = Cookies.get('tutorial_data');
  if (tutorialData) {
    tutorialData = JSON.parse(tutorialData);
    var stepNum = parseInt(Cookies.get('current_tutorial_step'), 10);
    if (isNaN(stepNum)) {
      // Cookies data initialization
      stepNum = 1;
      Cookies.set('current_tutorial_step', stepNum);
      tutorialData[0].backPagesPaths = [];
      Cookies.set('tutorial_data', tutorialData);
    }
    var thisPagePath = window.location.pathname;
    beforeCb();

    // Initialize tutorial for the current page's steps
    var doneLabel = (pageLastStepN === TUTORIAL_STEPS_CNT) ?
     'Start using sciNote' : 'End tutorial';
    if (_.isUndefined(steps)) {
      introJs()
       .setOptions({
         overlayOpacity: '0.2',
         prevLabel: 'Back',
         nextLabel: 'Next',
         skipLabel: 'End tutorial',
         doneLabel: doneLabel,
         showBullets: false,
         showStepNumbers: false,
         exitOnOverlayClick: false,
         exitOnEsc: false,
         disableInteraction: true,
         keyboardNavigation: false,
         tooltipClass: 'custom next-page-link'
       })
       .goToStep(stepNum - (pageFirstStepN - 1))
       .onexit(function() {
         Cookies.remove('tutorial_data');
         Cookies.remove('current_tutorial_step');
         location.reload();
       })
       .oncomplete(function() {
         Cookies.remove('tutorial_data');
         Cookies.remove('current_tutorial_step');
         location.reload();
       })
       .start();
    } else {
      if (pageFirstStepN === pageLastStepN) {
        // Only one page step, so add another fake one, so the back and next
        // buttons are added to the popup
        steps.push({});
      }
      introJs()
       .setOptions({
         overlayOpacity: '0.2',
         prevLabel: 'Back',
         nextLabel: 'Next',
         skipLabel: 'End tutorial',
         doneLabel: doneLabel,
         showBullets: false,
         showStepNumbers: false,
         exitOnOverlayClick: false,
         exitOnEsc: false,
         disableInteraction: true,
         keyboardNavigation: false,
         tooltipClass: 'custom next-page-link',
         steps: steps
       })
       .onexit(function() {
         location.reload();
       })
       .oncomplete(function() {
         location.reload();
       })
       .goToStep(stepNum - (pageFirstStepN - 1))
       .onexit(function() {
         Cookies.remove('tutorial_data');
         Cookies.remove('current_tutorial_step');
       })
       .oncomplete(function() {
         Cookies.remove('tutorial_data');
         Cookies.remove('current_tutorial_step');
       })
       .start();
    }

    // Page navigation when coming to this page from previous/next page
    $(function() {
      if (stepNum === pageFirstStepN && stepNum > 1) {
        $('.introjs-prevbutton').removeClass('introjs-disabled');
      } else if (stepNum === pageLastStepN && stepNum < TUTORIAL_STEPS_CNT) {
        $('.introjs-nextbutton').removeClass('introjs-disabled');
      }
    });

    // Page navigation when already on this page

    $('.introjs-skipbutton').click(function() {
      Cookies.remove('tutorial_data');
      Cookies.remove('current_tutorial_step');

      endCb();
    });

    $('.introjs-prevbutton').click(function() {
      if (stepNum > 1) {
        Cookies.set('current_tutorial_step', --stepNum);

        if (stepNum === pageFirstStepN && stepNum > 1) {
          $('.introjs-prevbutton').removeClass('introjs-disabled');
        } else if (stepNum < pageFirstStepN) {
          // Go to previous page;

          var prevPagePath = tutorialData[0].backPagesPaths.pop();
          Cookies.set('tutorial_data', tutorialData);
          $('.introjs-prevbutton').attr('href', prevPagePath);
          introJs().exit();
          endCb();
        }
      }
    });

    $('.introjs-nextbutton').click(function() {
      if (stepNum < TUTORIAL_STEPS_CNT) {
        Cookies.set('current_tutorial_step', ++stepNum);

        if (stepNum === pageLastStepN && stepNum < TUTORIAL_STEPS_CNT) {
          $('.introjs-nextbutton').removeClass('introjs-disabled');
        } else if (stepNum > pageLastStepN) {
          // Go to next page

          tutorialData[0].backPagesPaths.push(thisPagePath);
          Cookies.set('tutorial_data', tutorialData);
          $('.introjs-nextbutton').attr('href', nextPagePath);
          introJs().exit();
          endCb();
        }
      }
    });
  }
}
<|endoftext|>


<commit_before>/**
 * Schedule view. Displays periods of selected courses in a week grid.
 * @param {Object} data - Object containing schedule data as returned from the API
 * @return {undefined}
 * @memberOf Yacs.views
 */
Yacs.views.schedule = function (data) {
  Yacs.setContents(HandlebarsTemplates.schedule(data));
  var scheduleElement = document.querySelector('#scheduleContainer');
  var leftSwitchElement = document.querySelector('#leftSwitch');
  var rightSwitchElement = document.querySelector('#rightSwitch');
  var clearSwitchElement = document.querySelector('#clearButton');
  var scheduleNumElement = document.querySelector('#scheduleNum');
  var crnListElement = document.querySelector('#crnList');
  var schedule = new Schedule(scheduleContainer);
  var scheduleIndex = 0;

  // this function will be deprecated when backend is updated to use minutes-since-midnight format
  // see issue #102
  var toMinutes = function (timeString) {
    var int = parseInt(timeString);
    return Math.floor(int / 100) * 60 + int % 100;
  }

  var transformSchedule = function (schedule) {
    var events = [];
    var crns = [];

    schedule.sections.forEach(function (section) {
      var color = crns.indexOf(section.crn);
      if (color === -1) {
        crns.push(section.crn);
        color = crns.length - 1;
      }

      section.periods.forEach(function (period) {
        events.push({
          start: toMinutes(period.start),
          end: toMinutes(period.end),
          day: period.day,
          colorNum: color,
          title: section.department_code + ' ' + section.course_number + ' - ' + section.name
        });
      });
    });
    return { events: events, crns: crns };
  };

  var showSchedule = function (index) {
    var scheduleData = transformSchedule(data.schedules[index]);
    schedule.setEvents(scheduleData.events)
    scheduleNumElement.textContent = index + 1;
    crnListElement.textContent = 'CRNs: ' + scheduleData.crns.join(', ');
  }

  if(data.schedules.length == 0) {
    // TODO: this will happen if there are no available schedules
    return;
  }

  Yacs.on('click', leftSwitchElement, function () {
    scheduleIndex = (--scheduleIndex < 0 ? data.schedules.length - 1 : scheduleIndex);
    showSchedule(scheduleIndex);
  });
  Yacs.on('click', rightSwitchElement, function () {
    scheduleIndex = (++scheduleIndex < data.schedules.length ? scheduleIndex : 0);
    showSchedule(scheduleIndex);
  });
  Yacs.on('click', clearSwitchElement, function () {
      schedule.clearEvents();
      scheduleNumElement.textContent = 0;
      crnListElement.textContent = "";
  });

  showSchedule(scheduleIndex);
};
<commit_msg>changed the indentation<commit_after>/**
 * Schedule view. Displays periods of selected courses in a week grid.
 * @param {Object} data - Object containing schedule data as returned from the API
 * @return {undefined}
 * @memberOf Yacs.views
 */
Yacs.views.schedule = function (data) {
  Yacs.setContents(HandlebarsTemplates.schedule(data));
  var scheduleElement = document.querySelector('#scheduleContainer');
  var leftSwitchElement = document.querySelector('#leftSwitch');
  var rightSwitchElement = document.querySelector('#rightSwitch');
  var clearSwitchElement = document.querySelector('#clearButton');
  var scheduleNumElement = document.querySelector('#scheduleNum');
  var crnListElement = document.querySelector('#crnList');
  var schedule = new Schedule(scheduleContainer);
  var scheduleIndex = 0;

  // this function will be deprecated when backend is updated to use minutes-since-midnight format
  // see issue #102
  var toMinutes = function (timeString) {
    var int = parseInt(timeString);
    return Math.floor(int / 100) * 60 + int % 100;
  }

  var transformSchedule = function (schedule) {
    var events = [];
    var crns = [];

    schedule.sections.forEach(function (section) {
      var color = crns.indexOf(section.crn);
      if (color === -1) {
        crns.push(section.crn);
        color = crns.length - 1;
      }

      section.periods.forEach(function (period) {
        events.push({
          start: toMinutes(period.start),
          end: toMinutes(period.end),
          day: period.day,
          colorNum: color,
          title: section.department_code + ' ' + section.course_number + ' - ' + section.name
        });
      });
    });
    return { events: events, crns: crns };
  };

  var showSchedule = function (index) {
    var scheduleData = transformSchedule(data.schedules[index]);
    schedule.setEvents(scheduleData.events)
    scheduleNumElement.textContent = index + 1;
    crnListElement.textContent = 'CRNs: ' + scheduleData.crns.join(', ');
  }

  if(data.schedules.length == 0) {
    // TODO: this will happen if there are no available schedules
    return;
  }

  Yacs.on('click', leftSwitchElement, function () {
    scheduleIndex = (--scheduleIndex < 0 ? data.schedules.length - 1 : scheduleIndex);
    showSchedule(scheduleIndex);
  });
  Yacs.on('click', rightSwitchElement, function () {
    scheduleIndex = (++scheduleIndex < data.schedules.length ? scheduleIndex : 0);
    showSchedule(scheduleIndex);
  });
  Yacs.on('click', clearSwitchElement, function () {
	  schedule.clearEvents();
	  scheduleNumElement.textContent = 0;
	  crnListElement.textContent = "";
  });

  showSchedule(scheduleIndex);
};
<|endoftext|>


<commit_before>"use strict";

const os = require("os");
const util = require("util");
const RateLimiter = require("limiter").RateLimiter;
const workway = require("workway");
const finance = require("finance");

const log = require("../util").log;

const limiter = new RateLimiter(1, 500);

log("Finance worker engaged");

finance.crm.configure({

    liveDomain: os.hostname(),

    // liveDomain: "foo.com",
    liveUrl: process.env.CONPA_LIVE_URL || "http://localhost:5984",
    liveDb: "conpa",
    testingUrl: process.env.CONPA_TEST_URL || "http://localhost:5984",
    testingDb: "conpa-staging",
    design: "ConPA"
});

function throttleRequest(callback, args) {
    return new Promise((resolve, reject) => {
        limiter.removeTokens(1, () => {
            function cb(err, res) {
                if (err) {
                    reject(err);
                }
                resolve(res);
            }

            if (args) {
                return callback(args, cb);
            }
            return callback(cb);
        });
    });
}

finance.crm.getPortfolioCount[util.promisify.custom] = function() {
    return throttleRequest(finance.crm.getPortfolioCount);
};

finance.crm.getMostUsedAssets[util.promisify.custom] = function() {
    return throttleRequest(finance.crm.getMostUsedAssets);
};

finance.crm.getLastCreatedPortfolios[util.promisify.custom] = function(args) {
    return throttleRequest(finance.crm.getLastCreatedPortfolios, args);
};

finance.crm.getBestPerformingPortfolios[util.promisify.custom] = function(args) {
    return throttleRequest(finance.crm.getBestPerformingPortfolios, args);
};
finance.crm.getWorstPerformingPortfolios[util.promisify.custom] = function(args) {
    return throttleRequest(finance.crm.getWorstPerformingPortfolios, args);
};
finance.crm.getHighProfileRiskPortfolios[util.promisify.custom] = function(args) {
    return throttleRequest(finance.crm.getHighProfileRiskPortfolios, args);
};
finance.crm.getLowProfileRiskPortfolios[util.promisify.custom] = function(args) {
    return throttleRequest(finance.crm.getLowProfileRiskPortfolios, args);
};
finance.crm.getHighProfileReturnPortfolios[util.promisify.custom] = function(args) {
    return throttleRequest(finance.crm.getHighProfileReturnPortfolios, args);
};
finance.crm.getLowProfileReturnPortfolios[util.promisify.custom] = function(args) {
    return throttleRequest(finance.crm.getLowProfileReturnPortfolios, args);
};

finance.crm.putPortfolioOnCRM[util.promisify.custom] = function(args) {
    return throttleRequest(finance.crm.putPortfolioOnCRM, args);
};

workway({
    getOptimalPortfolio: util.promisify(finance.portfolio.getOptimalPortfolio),
    getScriptOptimalPortfolio: util.promisify(finance.portfolio.getScriptOptimalPortfolio),
    getKeyStatistics: util.promisify(finance.keystatistics.getKeyStatistics),
    savePortfolio: util.promisify(finance.crm.putPortfolioOnCRM),
    getPortfolioCount: util.promisify(finance.crm.getPortfolioCount),
    getMostUsedAssets: util.promisify(finance.crm.getMostUsedAssets),
    getLastCreatedPortfolios: util.promisify(finance.crm.getLastCreatedPortfolios),
    getBestPerformingPortfolios: util.promisify(finance.crm.getBestPerformingPortfolios),
    getWorstPerformingPortfolios: util.promisify(finance.crm.getWorstPerformingPortfolios),
    getHighProfileRiskPortfolios: util.promisify(finance.crm.getHighProfileRiskPortfolios),
    getLowProfileRiskPortfolios: util.promisify(finance.crm.getLowProfileRiskPortfolios),
    getHighProfileReturnPortfolios: util.promisify(finance.crm.getHighProfileReturnPortfolios),
    getLowProfileReturnPortfolios: util.promisify(finance.crm.getLowProfileReturnPortfolios)
});
<commit_msg>Refactor finance worker for drying rate limiter.<commit_after>"use strict";

const os = require("os");
const util = require("util");
const RateLimiter = require("limiter").RateLimiter;
const workway = require("workway");
const finance = require("finance");

const log = require("../util").log;

const limiter = new RateLimiter(1, 500);

log("Finance worker engaged");

finance.crm.configure({

    liveDomain: os.hostname(),

    // liveDomain: "foo.com",
    liveUrl: process.env.CONPA_LIVE_URL || "http://localhost:5984",
    liveDb: "conpa",
    testingUrl: process.env.CONPA_TEST_URL || "http://localhost:5984",
    testingDb: "conpa-staging",
    design: "ConPA"
});

function throttleRequest(callback, args) {
    return new Promise((resolve, reject) => {
        limiter.removeTokens(1, () => {
            function cb(err, res) {
                if (err) {
                    reject(err);
                }
                resolve(res);
            }

            if (args) {
                return callback(args, cb);
            }
            return callback(cb);
        });
    });
}

const apis = [
    { name: "getOptimalPortfolio", domain: "portfolio", limit: false },
    { name: "getScriptOptimalPortfolio", domain: "portfolio", limit: false },
    { name: "getKeyStatistics", domain: "keystatistics", limit: false },
    { name: "savePortfolio", domain: "crm", key: "putPortfolioOnCRM", limit: true },
    { name: "getPortfolioCount", domain: "crm", limit: true },
    { name: "getMostUsedAssets", domain: "crm", limit: true },
    { name: "getLastCreatedPortfolios", domain: "crm", limit: true },
    { name: "getBestPerformingPortfolios", domain: "crm", limit: true },
    { name: "getWorstPerformingPortfolios", domain: "crm", limit: true },
    { name: "getHighProfileRiskPortfolios", domain: "crm", limit: true },
    { name: "getLowProfileRiskPortfolios", domain: "crm", limit: true },
    { name: "getHighProfileReturnPortfolios", domain: "crm", limit: true },
    { name: "getLowProfileReturnPortfolios", domain: "crm", limit: true }
];

const workwayApis = {};

apis.forEach(api => {
    const name = api.name;
    const domain = api.domain;
    const key = api.key || api.name;

    if (api.limit) {
        finance[domain][key][util.promisify.custom] = function(arg) {
            return throttleRequest(finance[domain][key], arg);
        };
    }

    workwayApis[name] = util.promisify(finance[domain][key]);
});

workway(workwayApis);
<|endoftext|>


<commit_before>exports.calculate = function (avatar) {

  const repositories = avatar.repository
  const streak = avatar.currentStreak
  const information = avatar.information
  const hp = calculateHP()
  const mp = calculateMP()
  const pAtack = calculatePAtack()
  const pDef = calculatePDef()
  const castSpeed = calculateCastSpeed()
  const criticalChance = calculateCriticalChance()
  const accuracy = calculateAccuracy()
  const stamina = calculateStamina()

  function calculateHP () {
    return ((information.commits + streak) * information.commitsAverage) + (information.followers + getFollowingInformation() + getStarInformation())
  }

  function calculateMP () {
    return ((information.commits + streak) * information.commitsAverage)
  }

  function calculatePAtack () {
    return ((getRepositoryForks() + getRepositoryStar() + repositories.repositories.full.length + information.commits) * getRepositoriesRelevants()) + (information.commits * 2)
  }

  function calculatePDef () {
    return ((getRepositoryForks() + information.followers + getFollowingInformation() + getRepositoryStar() + repositories.repositories.full.length) * getRepositoriesRelevants()) +
      (information.commits * information.commitsAverage)
  }

  function calculateCastSpeed () {
    return (information.commits + streak) * getInformationOrganization()
  }

  function calculateCriticalChance () {
    return (information.commits + streak + information.followers + getFollowingInformation()) * getInformationOrganization()
  }

  function calculateAccuracy () {
    return ((information.followers) + getFollowingInformation()) * ((getInformationOrganization() * information.commitsAverage) * getRepositoriesRelevants()) + information.commits + streak
  }

  function calculateStamina () {
    return (information.commits * information.commitsAverage)
  }

  function getInformationOrganization () {
    return information.organizations === 0 ? 1 : information.organizations >= 5 ? 5 : information.organizations
  }

  function getStarInformation () {
    return information.stars > 1000 ? 1000 : information.stars
  }

  function getFollowingInformation () {
    return information.following > 1000 ? 1000 : information.following
  }

  function getRepositoryStar () {
    return repositories.stars >= 4 ? (repositories.stars / 2) : 1
  }

  function getRepositoryForks () {
    return repositories.forks >= 4 ? (repositories.forks / 2) : 1
  }

  function getRepositoriesRelevants () {
    return repositories.repositories.relevants.length === 0 ? 1 : repositories.repositories.relevants.length
  }

  return {
    HP: parseInt(hp),
    TOTAL_HP: parseInt(hp),
    MP: parseInt(mp),
    P_ATCK: parseInt(pAtack),
    P_DEF: parseInt(pDef),
    SPEED: parseInt(castSpeed),
    CRITICAL: parseInt(criticalChance),
    ACCURACY: parseInt(accuracy),
    STAMINA: parseInt(stamina)
  }
}
<commit_msg>add lines<commit_after>exports.calculate = function (avatar) {
  const repositories = avatar.repository
  const streak = avatar.currentStreak
  const information = avatar.information
  const hp = calculateHP()
  const mp = calculateMP()
  const pAtack = calculatePAtack()
  const pDef = calculatePDef()
  const castSpeed = calculateCastSpeed()
  const criticalChance = calculateCriticalChance()
  const accuracy = calculateAccuracy()
  const stamina = calculateStamina()

  function calculateHP () {
    return ((information.commits + streak) * information.commitsAverage) + (information.followers + getFollowingInformation() + getStarInformation())
  }

  function calculateMP () {
    return ((information.commits + streak) * information.commitsAverage)
  }

  function calculatePAtack () {
    return ((getRepositoryForks() + getRepositoryStar() + repositories.repositories.full.length + information.commits) * getRepositoriesRelevants()) + (information.commits * 2)
  }

  function calculatePDef () {
    return ((getRepositoryForks() + information.followers + getFollowingInformation() + getRepositoryStar() + repositories.repositories.full.length) * getRepositoriesRelevants()) +
      (information.commits * information.commitsAverage)
  }

  function calculateCastSpeed () {
    return (information.commits + streak) * getInformationOrganization()
  }

  function calculateCriticalChance () {
    return (information.commits + streak + information.followers + getFollowingInformation()) * getInformationOrganization()
  }

  function calculateAccuracy () {
    return ((information.followers) + getFollowingInformation()) * ((getInformationOrganization() * information.commitsAverage) * getRepositoriesRelevants()) + information.commits + streak
  }

  function calculateStamina () {
    return (information.commits * information.commitsAverage)
  }

  function getInformationOrganization () {
    return information.organizations === 0 ? 1 : information.organizations >= 5 ? 5 : information.organizations
  }

  function getStarInformation () {
    return information.stars > 1000 ? 1000 : information.stars
  }

  function getFollowingInformation () {
    return information.following > 1000 ? 1000 : information.following
  }

  function getRepositoryStar () {
    return repositories.stars >= 4 ? (repositories.stars / 2) : 1
  }

  function getRepositoryForks () {
    return repositories.forks >= 4 ? (repositories.forks / 2) : 1
  }

  function getRepositoriesRelevants () {
    return repositories.repositories.relevants.length === 0 ? 1 : repositories.repositories.relevants.length
  }

  return {
    HP: parseInt(hp),
    TOTAL_HP: parseInt(hp),
    MP: parseInt(mp),
    P_ATCK: parseInt(pAtack),
    P_DEF: parseInt(pDef),
    SPEED: parseInt(castSpeed),
    CRITICAL: parseInt(criticalChance),
    ACCURACY: parseInt(accuracy),
    STAMINA: parseInt(stamina)
  }
}
<|endoftext|>


<commit_before>/**
 * @fileoverview Class OTAInput is used to configure and create a process in
 * the backend to to start OTA package generation.
 * @package vue-uuid
 * @package ApiServices
 */
import { uuid } from 'vue-uuid'
import ApiServices from './ApiService.js'

export class OTAConfiguration {
  /**
   * Initialize the input for the api /run/<id>
   */
  constructor() {
    /**
     * Please refer to:
     * https://cs.android.com/android/platform/superproject/+/master:build/make/tools/releasetools/ota_from_target_files.py
     * for the complete and up-to-date configurations that can be set for
     * the OTA package generation.
     * TODO (lishutong): there are dependencies on this flags,
     * disable checkboxes of which dependencies are not fulfilled.
     */
    this.verbose = false,
    this.target = '',
    this.incremental = '',
    this.isIncremental = false,
    this.partial = [],
    this.isPartial = false,
    this.extra_keys = [],
    this.extra = '',
    this.id = uuid.v1()
  }

  /**
   * Start the generation process, will throw an error if not succeed
   */
  async sendForm() {
    for (let flag of OTAExtraFlags.slice(3, OTAflags.length)) {
      if (this[flag.key]) {
        this.extra_keys.push(flag.key)
      }
    }
    try {
      let response = await ApiServices.postInput(JSON.stringify(this), this.id)
      return response.data
    } catch (err) {
      throw err
    }
  }
}

export const OTABasicFlags = [
  {
    key: 'isIncremental',
    label: 'Incremental OTA',
    requireArg: 'incremental'
  },
  {
    key: 'isPartial',
    label: 'Partial OTA',
    requireArg: 'partial'
  },
  {
    key: 'verbose',
    label: 'Verbose'
  },]

export const OTAExtraFlags = [
  {
    key: 'downgrade',
    label: 'Downgrade',
    depend: ['isIncremental']
  },
  {
    key: 'override_timestamp',
    label: 'Override time stamp'
  },
  {
    key: 'wipe_user_data',
    label: 'Wipe User data'
  },
  //{
  //  key: 'retrofit_dynamic_partitions',
  //  label: 'Support dynamic partition'
  //},
  {
    key: 'skip_compatibility_check',
    label: 'Skip compatibility check'
  },
  //{
  //  key: 'output_metadata_path',
  //  label: 'Output metadata path'
  //},
  {
    key: 'force_non_ab',
    label: 'Generate non-A/B package'
  },
  /** TODO(lishutong): the following comments are flags
  * that requires file operation, will add these functions later.
  */
  //{key: 'oem_settings', label: 'Specify the OEM properties',
  //  requireArg: 'oem_settings_files'},
  //{key: 'binary', label: 'Use given binary', requireArg: 'binary_file',
  //  depend: ['force_non_ab']},
  {
    key: 'block',
    label: 'Block-based OTA',
    depend: ['force_non_ab']
  },
  //{key: 'extra_script', label: 'Extra script', requireArg: 'script_file',
  //  depend: ['force_non_ab']},
  {
    key: 'full_bootloader',
    label: 'Full bootloader',
    depend: ['force_non_ab', 'isIncremental']
  },
  {
    key: 'full_radio',
    label: 'Full radio',
    depend: ['force_non_ab', 'isIncremental']
  },
  //{key: 'log_diff', label: 'Log difference',
  //  requireArg: 'log_diff_path',depend: ['force_non_ab', 'isIncremental']},
  //{key: 'oem_no_mount', label: 'Do not mount OEM partition',
  //  depend: ['force_non_ab', 'oem_settings']},
  //{
  //  key: 'stash_threshold',
  //  label: 'Threshold for maximum stash size',
  //  requireArg: 'stash_threshold_float',
  //  depend: ['force_non_ab']
  //},
  //{
  //  key: 'worker_threads',
  //  label: 'Number of worker threads',
  //  requireArg: 'worker_threads_int',
  //  depend: ['force_non_ab', 'isIncremental']
  //},
  //{
  //  key: 'verify',
  //  label: 'Verify the checksum',
  //  depend: ['force_non_ab', 'isIncremental']
  //},
  {
    key: 'two_step',
    label: 'Generate two-step OTA',
    depend: ['force_non_ab']
  },
  {
    key: 'disable_fec_computation',
    label: 'Disable the on device FEC computation',
    depend: ['isIncremental'],
    exclude: ['force_non_ab']
  },
  {
    key: 'include_secondary',
    label: 'Include secondary slot images',
    exclude: ['force_non_ab', 'isIncremental']
  },
  //{key: 'payload_signer', label: 'Specify the signer',
  //  requireArg: ['payload_signer_singer'], exclude: ['force_non_ab']},
  //{key: 'payload_singer_args', label: 'Specify the args for signer',
  // requireArg: ['payload_signer_args_args], exclude: ['force_non_ab']},
  //{
  //  key: 'payload_signer_maximum_signature_size',
  //  label: 'The maximum signature size (in bytes)',
  //  requireArg: ['payload_signer_maximum_signature_size_int'],
  //  exclude: ['force_non_ab']
  //},
  //{key: 'boot_variable_file', label: 'Specify values of ro.boot.*',
  //  requireArg: ['boot_variable_file_file'], exclude: ['force_non_ab']},
  {
    key: 'skip_postinstall',
    label: 'Skip the postinstall',
    exclude: ['force_non_ab']
  },
  //{key: 'custom_image', label: 'Use custom image',
  // requireArg: ['custom_image_files'], exclude: ['force_non_ab]},
  {
    key: 'disable_vabc',
    label: 'Disable Virtual A/B compression',
    exclude: ['force_non_ab']
  },
  {
    key: 'vabc_downgrade',
    label: "Don't disable VABC for downgrading",
    depend: ['isIncremental', 'downgrade'],
    exclude: ['force_non_ab']
  },
]

/** export const requireArgs = new Map([
  [
    "stash_threshold_float",
    {
      type: "BaseInput",
      label: "Threshold for maximum stash size"
    }
  ],
  [
    "worker_threads",
    {
      type: "BaseInput",
      label: "Number of worker threads"
    }
  ],
  [
    "payload_signer_maximum_signature_size",
    {
      type: "BaseInput",
      label: "The maximum signature size (in bytes)"
    }
  ],
]) */<commit_msg>Fix a bug that job might not be able to be started properly.<commit_after>/**
 * @fileoverview Class OTAInput is used to configure and create a process in
 * the backend to to start OTA package generation.
 * @package vue-uuid
 * @package ApiServices
 */
import { uuid } from 'vue-uuid'
import ApiServices from './ApiService.js'

export class OTAConfiguration {
  /**
   * Initialize the input for the api /run/<id>
   */
  constructor() {
    /**
     * Please refer to:
     * https://cs.android.com/android/platform/superproject/+/master:build/make/tools/releasetools/ota_from_target_files.py
     * for the complete and up-to-date configurations that can be set for
     * the OTA package generation.
     * TODO (lishutong): there are dependencies on this flags,
     * disable checkboxes of which dependencies are not fulfilled.
     */
    this.verbose = false,
    this.target = '',
    this.incremental = '',
    this.isIncremental = false,
    this.partial = [],
    this.isPartial = false,
    this.extra_keys = [],
    this.extra = '',
    this.id = uuid.v1()
  }

  /**
   * Start the generation process, will throw an error if not succeed
   */
  async sendForm() {
    for (let flag of OTAExtraFlags) {
      if (this[flag.key]) {
        this.extra_keys.push(flag.key)
      }
    }
    try {
      let response = await ApiServices.postInput(JSON.stringify(this), this.id)
      return response.data
    } catch (err) {
      throw err
    }
  }
}

export const OTABasicFlags = [
  {
    key: 'isIncremental',
    label: 'Incremental OTA',
    requireArg: 'incremental'
  },
  {
    key: 'isPartial',
    label: 'Partial OTA',
    requireArg: 'partial'
  },
  {
    key: 'verbose',
    label: 'Verbose'
  },]

export const OTAExtraFlags = [
  {
    key: 'downgrade',
    label: 'Downgrade',
    depend: ['isIncremental']
  },
  {
    key: 'override_timestamp',
    label: 'Override time stamp'
  },
  {
    key: 'wipe_user_data',
    label: 'Wipe User data'
  },
  //{
  //  key: 'retrofit_dynamic_partitions',
  //  label: 'Support dynamic partition'
  //},
  {
    key: 'skip_compatibility_check',
    label: 'Skip compatibility check'
  },
  //{
  //  key: 'output_metadata_path',
  //  label: 'Output metadata path'
  //},
  {
    key: 'force_non_ab',
    label: 'Generate non-A/B package'
  },
  /** TODO(lishutong): the following comments are flags
  * that requires file operation, will add these functions later.
  */
  //{key: 'oem_settings', label: 'Specify the OEM properties',
  //  requireArg: 'oem_settings_files'},
  //{key: 'binary', label: 'Use given binary', requireArg: 'binary_file',
  //  depend: ['force_non_ab']},
  {
    key: 'block',
    label: 'Block-based OTA',
    depend: ['force_non_ab']
  },
  //{key: 'extra_script', label: 'Extra script', requireArg: 'script_file',
  //  depend: ['force_non_ab']},
  {
    key: 'full_bootloader',
    label: 'Full bootloader',
    depend: ['force_non_ab', 'isIncremental']
  },
  {
    key: 'full_radio',
    label: 'Full radio',
    depend: ['force_non_ab', 'isIncremental']
  },
  //{key: 'log_diff', label: 'Log difference',
  //  requireArg: 'log_diff_path',depend: ['force_non_ab', 'isIncremental']},
  //{key: 'oem_no_mount', label: 'Do not mount OEM partition',
  //  depend: ['force_non_ab', 'oem_settings']},
  //{
  //  key: 'stash_threshold',
  //  label: 'Threshold for maximum stash size',
  //  requireArg: 'stash_threshold_float',
  //  depend: ['force_non_ab']
  //},
  //{
  //  key: 'worker_threads',
  //  label: 'Number of worker threads',
  //  requireArg: 'worker_threads_int',
  //  depend: ['force_non_ab', 'isIncremental']
  //},
  //{
  //  key: 'verify',
  //  label: 'Verify the checksum',
  //  depend: ['force_non_ab', 'isIncremental']
  //},
  {
    key: 'two_step',
    label: 'Generate two-step OTA',
    depend: ['force_non_ab']
  },
  {
    key: 'disable_fec_computation',
    label: 'Disable the on device FEC computation',
    depend: ['isIncremental'],
    exclude: ['force_non_ab']
  },
  {
    key: 'include_secondary',
    label: 'Include secondary slot images',
    exclude: ['force_non_ab', 'isIncremental']
  },
  //{key: 'payload_signer', label: 'Specify the signer',
  //  requireArg: ['payload_signer_singer'], exclude: ['force_non_ab']},
  //{key: 'payload_singer_args', label: 'Specify the args for signer',
  // requireArg: ['payload_signer_args_args], exclude: ['force_non_ab']},
  //{
  //  key: 'payload_signer_maximum_signature_size',
  //  label: 'The maximum signature size (in bytes)',
  //  requireArg: ['payload_signer_maximum_signature_size_int'],
  //  exclude: ['force_non_ab']
  //},
  //{key: 'boot_variable_file', label: 'Specify values of ro.boot.*',
  //  requireArg: ['boot_variable_file_file'], exclude: ['force_non_ab']},
  {
    key: 'skip_postinstall',
    label: 'Skip the postinstall',
    exclude: ['force_non_ab']
  },
  //{key: 'custom_image', label: 'Use custom image',
  // requireArg: ['custom_image_files'], exclude: ['force_non_ab]},
  {
    key: 'disable_vabc',
    label: 'Disable Virtual A/B compression',
    exclude: ['force_non_ab']
  },
  {
    key: 'vabc_downgrade',
    label: "Don't disable VABC for downgrading",
    depend: ['isIncremental', 'downgrade'],
    exclude: ['force_non_ab']
  },
]

/** export const requireArgs = new Map([
  [
    "stash_threshold_float",
    {
      type: "BaseInput",
      label: "Threshold for maximum stash size"
    }
  ],
  [
    "worker_threads",
    {
      type: "BaseInput",
      label: "Number of worker threads"
    }
  ],
  [
    "payload_signer_maximum_signature_size",
    {
      type: "BaseInput",
      label: "The maximum signature size (in bytes)"
    }
  ],
]) */<|endoftext|>


<commit_before>// @flow
import { SelectInput, CheckBox } from 'app/components/Form';
import Tooltip from 'app/components/Tooltip';

/*
 * Usage inside redux-form:
 *
 *   <Fields
 *     component={ObjectPermissions}
 *     names={[
 *       'requireAuth',
 *       'canViewGroups',
 *       'canEditUsers',
 *       'canEditGroups'
 *     ]}
 *   />
 *
 * To omit some of the fields, just omit the name in the 'names' prop.
 *
 * You also have to run the values through the 'normalizeObjectPermissions' function below
 *
 * */
const ObjectPermissions = ({
  canEditUsers,
  canEditGroups,
  canViewGroups,
  requireAuth,
  ...props
}: {
  canEditUsers?: any,
  canEditGroups?: any,
  canViewGroups?: any,
  requireAuth?: any,
}) => {
  return [
    requireAuth && (
      <Tooltip content="Gi alle brukere lesetilgang. Dette inkluderer også brukere som ikke har logget inn.">
        <CheckBox.Field
          inverted
          {...requireAuth}
          label="Apen for alle - offentlig på nettet."
        />
      </Tooltip>
    ),
    canEditGroups && (
      <SelectInput.AutocompleteField
        {...canEditGroups}
        label="Grupper med endretilgang"
        isMulti
        placeholder="Velg grupper"
        filter={['users.abakusgroup']}
      />
    ),
    canViewGroups && (
      <SelectInput.AutocompleteField
        {...canViewGroups}
        label="Grupper med lesetilgang"
        isMulti
        placeholder="Velg grupper"
        filter={['users.abakusgroup']}
      />
    ),
    canEditUsers && (
      <SelectInput.AutocompleteField
        {...canEditUsers}
        label="Brukere med endretilgang"
        isMulti
        placeholder="Velg brukere"
        filter={['users.user']}
      />
    ),
  ].filter(Boolean);
};

const toIds = (mapping) => mapping.value;

export const normalizeObjectPermissions = ({
  requireAuth,
  canViewGroups: initialCanViewGroups,
  canEditGroups: initialCanEditGroups,
  canEditUsers: initialCanEditUsers,
}: Object) => {
  const canEditUsers = initialCanEditUsers && initialCanEditUsers.map(toIds);
  const canViewGroups = initialCanViewGroups && initialCanViewGroups.map(toIds);
  const canEditGroups = initialCanEditGroups && initialCanEditGroups.map(toIds);
  return {
    requireAuth: !!requireAuth,
    ...(canEditUsers ? { canEditUsers } : {}),
    //$FlowFixMe
    ...(canEditGroups ? { canEditGroups } : {}),
    ...(canViewGroups ? { canViewGroups } : {}),
  };
};
export const objectPermissionsToInitialValues = ({
  canViewGroups: initialCanViewGroups,
  canEditGroups: initialCanEditGroups,
  canEditUsers: initialCanEditUsers,
}: Object) => {
  const canEditGroups =
    initialCanEditGroups &&
    initialCanEditGroups.filter(Boolean).map((group) => ({
      ...group,
      label: group.name,
      value: group.id,
    }));
  const canViewGroups =
    initialCanViewGroups &&
    initialCanViewGroups.filter(Boolean).map((group) => ({
      ...group,
      label: group.name,
      value: group.id,
    }));
  const canEditUsers =
    initialCanEditUsers &&
    initialCanEditUsers.filter(Boolean).map((user) => ({
      ...user,
      label: user.fullName,
      value: user.id,
    }));
  return {
    ...(canEditUsers ? { canEditUsers } : {}),
    //$FlowFixMe
    ...(canEditGroups ? { canEditGroups } : {}),
    ...(canViewGroups ? { canViewGroups } : {}),
  };
};

export const objectPermissionsInitialValues = {
  requireAuth: true,
  canEditUsers: [],
  canEditGroups: [],
  canViewGroups: [],
};

export default ObjectPermissions;
<commit_msg>Fix Typo<commit_after>// @flow
import { SelectInput, CheckBox } from 'app/components/Form';
import Tooltip from 'app/components/Tooltip';

/*
 * Usage inside redux-form:
 *
 *   <Fields
 *     component={ObjectPermissions}
 *     names={[
 *       'requireAuth',
 *       'canViewGroups',
 *       'canEditUsers',
 *       'canEditGroups'
 *     ]}
 *   />
 *
 * To omit some of the fields, just omit the name in the 'names' prop.
 *
 * You also have to run the values through the 'normalizeObjectPermissions' function below
 *
 * */
const ObjectPermissions = ({
  canEditUsers,
  canEditGroups,
  canViewGroups,
  requireAuth,
  ...props
}: {
  canEditUsers?: any,
  canEditGroups?: any,
  canViewGroups?: any,
  requireAuth?: any,
}) => {
  return [
    requireAuth && (
      <Tooltip content="Gi alle brukere lesetilgang. Dette inkluderer også brukere som ikke har logget inn.">
        <CheckBox.Field
          inverted
          {...requireAuth}
          label="Åpen for alle - offentlig på nettet."
        />
      </Tooltip>
    ),
    canEditGroups && (
      <SelectInput.AutocompleteField
        {...canEditGroups}
        label="Grupper med endretilgang"
        isMulti
        placeholder="Velg grupper"
        filter={['users.abakusgroup']}
      />
    ),
    canViewGroups && (
      <SelectInput.AutocompleteField
        {...canViewGroups}
        label="Grupper med lesetilgang"
        isMulti
        placeholder="Velg grupper"
        filter={['users.abakusgroup']}
      />
    ),
    canEditUsers && (
      <SelectInput.AutocompleteField
        {...canEditUsers}
        label="Brukere med endretilgang"
        isMulti
        placeholder="Velg brukere"
        filter={['users.user']}
      />
    ),
  ].filter(Boolean);
};

const toIds = (mapping) => mapping.value;

export const normalizeObjectPermissions = ({
  requireAuth,
  canViewGroups: initialCanViewGroups,
  canEditGroups: initialCanEditGroups,
  canEditUsers: initialCanEditUsers,
}: Object) => {
  const canEditUsers = initialCanEditUsers && initialCanEditUsers.map(toIds);
  const canViewGroups = initialCanViewGroups && initialCanViewGroups.map(toIds);
  const canEditGroups = initialCanEditGroups && initialCanEditGroups.map(toIds);
  return {
    requireAuth: !!requireAuth,
    ...(canEditUsers ? { canEditUsers } : {}),
    //$FlowFixMe
    ...(canEditGroups ? { canEditGroups } : {}),
    ...(canViewGroups ? { canViewGroups } : {}),
  };
};
export const objectPermissionsToInitialValues = ({
  canViewGroups: initialCanViewGroups,
  canEditGroups: initialCanEditGroups,
  canEditUsers: initialCanEditUsers,
}: Object) => {
  const canEditGroups =
    initialCanEditGroups &&
    initialCanEditGroups.filter(Boolean).map((group) => ({
      ...group,
      label: group.name,
      value: group.id,
    }));
  const canViewGroups =
    initialCanViewGroups &&
    initialCanViewGroups.filter(Boolean).map((group) => ({
      ...group,
      label: group.name,
      value: group.id,
    }));
  const canEditUsers =
    initialCanEditUsers &&
    initialCanEditUsers.filter(Boolean).map((user) => ({
      ...user,
      label: user.fullName,
      value: user.id,
    }));
  return {
    ...(canEditUsers ? { canEditUsers } : {}),
    //$FlowFixMe
    ...(canEditGroups ? { canEditGroups } : {}),
    ...(canViewGroups ? { canViewGroups } : {}),
  };
};

export const objectPermissionsInitialValues = {
  requireAuth: true,
  canEditUsers: [],
  canEditGroups: [],
  canViewGroups: [],
};

export default ObjectPermissions;
<|endoftext|>


<commit_before>//@flow

import React, { PureComponent } from 'react';

type Props = {
  src: any,
  alt: string,
  className?: string,
  base64: string,
  style?: Object,
  beforeLoadstyle?: Object,
  onLoadStyle?: Object,
  blurStr: string,
  contrastStr: string,
  transtionTime: string,
  transitionDelay: string
};

type State = {
  src: any,
  style: Object
};

export default class ProgressiveImage extends PureComponent<Props, State> {
  props: Props;

  state: State = {
    src: this.props.base64,
    style: {
      ...this.props.beforeLoadstyle,
      filter: `blur(${this.props.blurStr}) contrast(${this.props.contrastStr})`,
      transition: `filter ${this.props.transtionTime} linear ${
        this.props.transitionDelay
      }`
    }
  };

  static defaultProps = {
    base64:
      'data:image/png;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
    blurStr: '15px',
    contrastStr: '50%',
    transtionTime: '.2s',
    transitionDelay: '.05s'
  };

  fetchSrc: (url: string) => Promise<*> = url =>
    new Promise((resolve, reject) => {
      const img = new Image();
      img.onload = () => resolve(url);
      img.onerror = error => reject(error);
      img.src = url;
    });

  componentDidMount() {
    this.fetchSrc(this.props.src)
      .then(url => {
        this.setState({
          src: url,
          style: {
            ...this.state.style,
            ...this.props.onLoadStyle,
            filter: 'blur(0) contrast(100%)'
          }
        });
      })
      .catch(error => {
        throw error;
      });
  }

  render() {
    return (
      <img
        src={this.state.src}
        alt={this.props.alt}
        className={this.props.className}
        style={this.state.style}
      />
    );
  }
}
<commit_msg>Remove some random code not working<commit_after>//@flow

import React, { PureComponent } from 'react';

type Props = {
  src: any,
  alt: string,
  className?: string,
  base64: string,
  style?: Object,
  beforeLoadstyle?: Object,
  onLoadStyle?: Object,
  blurStr: string,
  contrastStr: string,
  transtionTime: string,
  transitionDelay: string
};

type State = {
  src: any,
  style: Object
};

export default class ProgressiveImage extends PureComponent<Props, State> {
  state = {
    src: this.props.base64,
    style: {
      ...this.props.beforeLoadstyle,
      filter: `blur(${this.props.blurStr}) contrast(${this.props.contrastStr})`,
      transition: `filter ${this.props.transtionTime} linear ${
        this.props.transitionDelay
      }`
    }
  };

  static defaultProps = {
    base64:
      'data:image/png;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
    blurStr: '15px',
    contrastStr: '50%',
    transtionTime: '.2s',
    transitionDelay: '.05s'
  };

  fetchSrc: (url: string) => Promise<*> = url =>
    new Promise((resolve, reject) => {
      const img = new Image();
      img.onload = () => resolve(url);
      img.onerror = error => reject(error);
      img.src = url;
    });

  componentDidMount() {
    this.fetchSrc(this.props.src)
      .then(url => {
        this.setState({
          src: url,
          style: {
            ...this.state.style,
            ...this.props.onLoadStyle,
            filter: 'blur(0) contrast(100%)'
          }
        });
      })
      .catch(error => {
        throw error;
      });
  }

  render() {
    return (
      <img
        src={this.state.src}
        alt={this.props.alt}
        className={this.props.className}
        style={this.state.style}
      />
    );
  }
}
<|endoftext|>