<commit_before>'use strict';

let passport = require('passport');
let cookie = require('cookie-signature');
let auth = require('./auth');
let userLib = require('./user')();
let db = require('./databaseConfig');
let logger = require('./logging').getLogger(__filename);
let expressWinston = require('express-winston');
let winstonCloudWatch = require('winston-cloudwatch');
let winston = require('winston');

let cookieKey;
let cookieSecret;

const getLoggingTransport = function (jsonFormat) {
    let transports = [];
    if (process.env.NODE_ENV !== 'production') {
        transports.push(new winston.transports.Console({
            format: winston.format.combine(winston.format.colorize(), winston.format.simple())
        }));
    }
    if (process.env.CLOUD_WATCH_LOG_STREAM_NAME) {
        transports.push(new winstonCloudWatch({
            logGroupName: 'elyoosWebserver',
            logStreamName: process.env.CLOUD_WATCH_LOG_STREAM_NAME,
            level: 'info',
            jsonMessage: jsonFormat,
            awsRegion: process.env.AWS_REGION
        }));
    }
    return transports;
};

module.exports = function (app, nuxt) {

    app.get('/healthCheck', function (req, res) {
        res.type('text/plain');
        res.send("OK");
    });

    if (process.env.ROBOT_TEXT_ENABLE_CRAWLER === 'true') {
        app.get('/robots.txt', function (req, res) {
            res.type('text/plain');
            res.send("User-agent: *\nDisallow: ");
        });
    } else {
        app.get('/robots.txt', function (req, res) {
            res.type('text/plain');
            res.send("User-agent: *\nDisallow: /");
        });
    }

    app.on('middleware:after:session', function () {
        app.use(passport.initialize());
        app.use(passport.session());
        //Tell passport to use our newly created local strategy for authentication
        passport.use(auth.localStrategy());
        //Give passport a way to serialize and deserialize a user. In this case, by the user's id.
        passport.serializeUser(userLib.serialize);
        passport.deserializeUser(userLib.deserialize);

        if ('testing' !== process.env.NODE_ENV) {
            app.use(function (req, res, next) {
                //Needed because rolling is some how not working
                req.session.touch();
                next();
            });
        }

        if (nuxt && nuxt.render) {
            app.use(function (req, res, next) {
                if (req.originalUrl.match(/api/) === null) {
                    req.headers.cookie = cookieKey + '=s:' + cookie.sign(req.sessionID, cookieSecret);
                }
                req.session.save(async function () {
                    if (req.originalUrl.match(/api/) === null) {
                        try {
                            await nuxt.render(req, res);
                        } catch (err) {
                            logger.error('Nuxt rendering has failed', {error: err});
                        }
                    } else {
                        next();
                    }
                });
            });
        }
    });

    app.on('middleware:before:router', function () {
        app.use(expressWinston.logger({
            transports: getLoggingTransport(false)
        }));
    });

    app.on('middleware:after:router', function () {
        app.use(expressWinston.errorLogger({
            transports: getLoggingTransport(true),
            meta: true,
            msg: "HTTP {{req.method}} {{req.url}}",
            expressFormat: true,
            dynamicMeta: function(req) {
                return {
                    user: req.user ? req.user : null,
                    body: req.body ? req.body : null,
                };
            }
        }));
    });

    return {
        onconfig: function (config, next) {

            let dbConfig = config.get('databaseConfig');
            db.config(dbConfig);
            let cookieConfig = config.get('middleware').session.module.arguments.find(arg => arg.cookie);
            cookieKey = cookieConfig.key;
            cookieSecret = cookieConfig.secret;

            next(null, config);
        }
    };

};
<commit_msg>Bugfix: Check api expression at beginning.<commit_after>'use strict';

let passport = require('passport');
let cookie = require('cookie-signature');
let auth = require('./auth');
let userLib = require('./user')();
let db = require('./databaseConfig');
let logger = require('./logging').getLogger(__filename);
let expressWinston = require('express-winston');
let winstonCloudWatch = require('winston-cloudwatch');
let winston = require('winston');

let cookieKey;
let cookieSecret;

const getLoggingTransport = function (jsonFormat) {
    let transports = [];
    if (process.env.NODE_ENV !== 'production') {
        transports.push(new winston.transports.Console({
            format: winston.format.combine(winston.format.colorize(), winston.format.simple())
        }));
    }
    if (process.env.CLOUD_WATCH_LOG_STREAM_NAME) {
        transports.push(new winstonCloudWatch({
            logGroupName: 'elyoosWebserver',
            logStreamName: process.env.CLOUD_WATCH_LOG_STREAM_NAME,
            level: 'info',
            jsonMessage: jsonFormat,
            awsRegion: process.env.AWS_REGION
        }));
    }
    return transports;
};

module.exports = function (app, nuxt) {

    app.get('/healthCheck', function (req, res) {
        res.type('text/plain');
        res.send("OK");
    });

    if (process.env.ROBOT_TEXT_ENABLE_CRAWLER === 'true') {
        app.get('/robots.txt', function (req, res) {
            res.type('text/plain');
            res.send("User-agent: *\nDisallow: ");
        });
    } else {
        app.get('/robots.txt', function (req, res) {
            res.type('text/plain');
            res.send("User-agent: *\nDisallow: /");
        });
    }

    app.on('middleware:after:session', function () {
        app.use(passport.initialize());
        app.use(passport.session());
        //Tell passport to use our newly created local strategy for authentication
        passport.use(auth.localStrategy());
        //Give passport a way to serialize and deserialize a user. In this case, by the user's id.
        passport.serializeUser(userLib.serialize);
        passport.deserializeUser(userLib.deserialize);

        if ('testing' !== process.env.NODE_ENV) {
            app.use(function (req, res, next) {
                //Needed because rolling is some how not working
                req.session.touch();
                next();
            });
        }

        if (nuxt && nuxt.render) {
            app.use(function (req, res, next) {
                if (req.originalUrl.match(/^\/api\//) === null) {
                    req.headers.cookie = cookieKey + '=s:' + cookie.sign(req.sessionID, cookieSecret);
                }
                req.session.save(async function () {
                    if (req.originalUrl.match(/^\/api\//) === null) {
                        try {
                            await nuxt.render(req, res);
                        } catch (err) {
                            logger.error('Nuxt rendering has failed', {error: err});
                        }
                    } else {
                        next();
                    }
                });
            });
        }
    });

    app.on('middleware:before:router', function () {
        app.use(expressWinston.logger({
            transports: getLoggingTransport(false)
        }));
    });

    app.on('middleware:after:router', function () {
        app.use(expressWinston.errorLogger({
            transports: getLoggingTransport(true),
            meta: true,
            msg: "HTTP {{req.method}} {{req.url}}",
            expressFormat: true,
            dynamicMeta: function(req) {
                return {
                    user: req.user ? req.user : null,
                    body: req.body ? req.body : null,
                };
            }
        }));
    });

    return {
        onconfig: function (config, next) {

            let dbConfig = config.get('databaseConfig');
            db.config(dbConfig);
            let cookieConfig = config.get('middleware').session.module.arguments.find(arg => arg.cookie);
            cookieKey = cookieConfig.key;
            cookieSecret = cookieConfig.secret;

            next(null, config);
        }
    };

};
<|endoftext|>


<commit_before>function sqlite(args){
    var options = {
        columns: "*",
        table: "sqlite_master WHERE (type='table' OR type='view') AND name NOT LIKE '#_%'  ESCAPE '#'",
        limit: 50,
        offset: 0,
        orderby: null
    }
    $.extend(true, options, args);
    return $.ajax({
        url: sqliteEndpoint,
        dataType: 'json',
        cache: false,
        data: {
            q: 'SELECT ' + options.columns + ' FROM ' + options.table + ( options.orderby ? ' ORDER BY ' + options.orderby : '' ) + ' LIMIT ' + options.limit + ' OFFSET ' + options.offset
        }
    });
}

function showSlickGrid(table_name){
    sqlite({
        table: table_name
    }).done(function(data){
        var grid;
        var options = {
            enableColumnReorder: true,
            enableTextSelectionOnCells: true
        }
        // create column definitions from first row of data
        var columns = [];
        var names = [];
        for(var key in data[0]){
            columns.push({
                id: key,
                name: key,
                field: key,
                sortable: true
            });
            names.push(key);
        }

        var key = [location.pathname, 'columns', table_name]
        var storedColumns = store.get(JSON.stringify(key));
        var storedNames = [];
        if(storedColumns){
            $.each(storedColumns, function(i, col){
                storedNames.push(col.name);
            });
            names.sort();
            storedNames.sort();
            if(String(names) == String(storedNames)){
                columns = storedColumns;
            }
        }

        // create the table
        grid = new Slick.Grid("#datagrid", data, columns, options);
        var ordercolumn = null;
        var orderdirection = null;

        // handle sorting of data
        grid.onSort.subscribe(function(e, args){
            grid.scrollRowIntoView(0);
            ordercolumn = args.sortCol.field;
            orderdirection = args.sortAsc;
            sqlite({
                table: table_name,
                orderby: ordercolumn + ' ' + (orderdirection ? 'asc' : 'desc')
            }).done(function(newdata){
                data = newdata;
                grid.setData(data);
                grid.updateRowCount();
                grid.render();
            });
        });

        // infinite scrolling
        var loading = false;
        var allDataLoaded = false;
        var rowsToGet = 100;
        grid.onViewportChanged.subscribe(function (e, args) {
            if(!loading && !allDataLoaded && grid.getViewport().bottom + 20 > grid.getDataLength()){
                loading = true;
                var sqlite_options = {
                    table: table_name,
                    limit: rowsToGet,
                    offset: grid.getDataLength()
                }
                if(ordercolumn && orderdirection){
                    sqlite_options['orderby'] = ordercolumn + ' ' + (orderdirection ? 'asc' : 'desc');
                }
                sqlite(sqlite_options).done(function(newdata){
                    $.each(newdata, function(i,row){
                        data.push(row);
                    });
                    grid.updateRowCount();
                    grid.render();
                    loading = false;
                    if(newdata.length < rowsToGet){
                        allDataLoaded = true;
                    }
                });
            }
        });

        function saveColumnInfo(e, args){
            var key = [location.pathname, 'columns', table_name];
            store.set(JSON.stringify(key), args.grid.getColumns())
        }

        grid.onColumnsReordered.subscribe(saveColumnInfo);
        grid.onColumnsResized.subscribe(saveColumnInfo);

    });
}

$(function(){
    // TODO: Check fragment is supplied & contains box_url
    frag = window.location.hash.substr(1);
    obj = JSON.parse(decodeURIComponent(frag));
    sqliteEndpoint = obj.dataset_box_url + '/sqlite'

    sqlite().done(function(tables){
        if(tables.length == 0){
            $('
').addClass('alert').html('<button type="button" class="close" data-dismiss="alert">×</button> Your dataset is empty! We connected to your dataset fine, but couldn’t find any data. Is it empty?').appendTo('body');
        } else {
            var key = [location.pathname, 'tab'];
            var storedTableName = store.get(JSON.stringify(key));
            var name = storedTableName || tables[0]['name'];

            var $ul = $('
').addClass('nav nav-tabs');
            $.each(tables, function(i, table){
                $('
').append('' + table['name'] + '').bind('click', function(e){
                    e.preventDefault();
                    $(this).addClass('active').siblings('.active').removeClass('active');
                    showSlickGrid($(this).text());
                    var key = [location.pathname, 'tab'];
                    store.set(JSON.stringify(key), $(this).text());
                }).appendTo($ul);
            });
            $ul.appendTo('body');
            $('
').appendTo('body');

            showSlickGrid(name);
        }
    }).fail(function(jqXHR, textStatus, errorThrown){
        if(jqXHR.status == 403){
            var html = 'Forbidden access to your dataset API We received a 403 Forbidden status while reading your dataset. Does your box have a publish_token we don’t know about?'
        } else {
            var html = 'Unexpected response from dataset API ' + $.trim(jqXHR.responseText)
        }
        $('
').addClass('alert alert-error').html('<button type="button" class="close" data-dismiss="alert">×</button> ' + html).appendTo('body');
    });

});
<commit_msg>error handling for various url hash eventualities<commit_after>// Hint: Scroll down to the jQuery ready $(function(){...}) to see how everything starts off.

function sqlite(args){
    var options = {
        columns: "*",
        table: "sqlite_master WHERE (type='table' OR type='view') AND name NOT LIKE '#_%'  ESCAPE '#'",
        limit: 50,
        offset: 0,
        orderby: null
    }
    $.extend(true, options, args);
    return $.ajax({
        url: sqliteEndpoint,
        dataType: 'json',
        cache: false,
        data: {
            q: 'SELECT ' + options.columns + ' FROM ' + options.table + ( options.orderby ? ' ORDER BY ' + options.orderby : '' ) + ' LIMIT ' + options.limit + ' OFFSET ' + options.offset
        }
    });
}

function showSlickGrid(table_name){
    sqlite({
        table: table_name
    }).done(function(data){
        var grid;
        var options = {
            enableColumnReorder: true,
            enableTextSelectionOnCells: true
        }
        // create column definitions from first row of data
        var columns = [];
        var names = [];
        for(var key in data[0]){
            columns.push({
                id: key,
                name: key,
                field: key,
                sortable: true
            });
            names.push(key);
        }

        var key = [location.pathname, 'columns', table_name]
        var storedColumns = store.get(JSON.stringify(key));
        var storedNames = [];
        if(storedColumns){
            $.each(storedColumns, function(i, col){
                storedNames.push(col.name);
            });
            names.sort();
            storedNames.sort();
            if(String(names) == String(storedNames)){
                columns = storedColumns;
            }
        }

        // create the table
        grid = new Slick.Grid("#datagrid", data, columns, options);
        var ordercolumn = null;
        var orderdirection = null;

        // handle sorting of data
        grid.onSort.subscribe(function(e, args){
            grid.scrollRowIntoView(0);
            ordercolumn = args.sortCol.field;
            orderdirection = args.sortAsc;
            sqlite({
                table: table_name,
                orderby: ordercolumn + ' ' + (orderdirection ? 'asc' : 'desc')
            }).done(function(newdata){
                data = newdata;
                grid.setData(data);
                grid.updateRowCount();
                grid.render();
            });
        });

        // infinite scrolling
        var loading = false;
        var allDataLoaded = false;
        var rowsToGet = 100;
        grid.onViewportChanged.subscribe(function (e, args) {
            if(!loading && !allDataLoaded && grid.getViewport().bottom + 20 > grid.getDataLength()){
                loading = true;
                var sqlite_options = {
                    table: table_name,
                    limit: rowsToGet,
                    offset: grid.getDataLength()
                }
                if(ordercolumn && orderdirection){
                    sqlite_options['orderby'] = ordercolumn + ' ' + (orderdirection ? 'asc' : 'desc');
                }
                sqlite(sqlite_options).done(function(newdata){
                    $.each(newdata, function(i,row){
                        data.push(row);
                    });
                    grid.updateRowCount();
                    grid.render();
                    loading = false;
                    if(newdata.length < rowsToGet){
                        allDataLoaded = true;
                    }
                });
            }
        });

        function saveColumnInfo(e, args){
            var key = [location.pathname, 'columns', table_name];
            store.set(JSON.stringify(key), args.grid.getColumns())
        }

        grid.onColumnsReordered.subscribe(saveColumnInfo);
        grid.onColumnsResized.subscribe(saveColumnInfo);

    });
}

function createSpreadsheet(){
    sqlite().done(function(tables){
        if(tables.length == 0){
            $('
').addClass('alert').html('<button type="button" class="close" data-dismiss="alert">×</button> Your dataset is empty! We connected to your dataset fine, but couldn’t find any data. Is it empty?').appendTo('body');
        } else {
            var key = [location.pathname, 'tab'];
            var storedTableName = store.get(JSON.stringify(key));
            var name = storedTableName || tables[0]['name'];

            var $ul = $('
').addClass('nav nav-tabs');
            $.each(tables, function(i, table){
                $('
').append('' + table['name'] + '').bind('click', function(e){
                    e.preventDefault();
                    $(this).addClass('active').siblings('.active').removeClass('active');
                    showSlickGrid($(this).text());
                    var key = [location.pathname, 'tab'];
                    store.set(JSON.stringify(key), $(this).text());
                }).appendTo($ul);
            });
            $ul.appendTo('body');
            $('
').appendTo('body');

            showSlickGrid(name);
        }
    }).fail(function(jqXHR, textStatus, errorThrown){
        if(jqXHR.status == 403){
            var html = 'Forbidden access to your dataset API We received a 403 Forbidden status while reading your dataset. Does your box have a publish_token we don’t know about?'
        } else {
            var html = 'Unexpected response from dataset API ' + $.trim(jqXHR.responseText)
        }
        $('
').addClass('alert alert-error').html('<button type="button" class="close" data-dismiss="alert">×</button> ' + html).appendTo('body');
    });
}

$(function(){
    if(window.location.hash == ''){
        $('
').addClass('alert').html('<button type="button" class="close" data-dismiss="alert">×</button> Which dataset do you want to visualise? You didn’t supply a JSON object of settings in the URL hash. Are you sure you followed the right link?').appendTo('body');
        return false;
    }
    hash = window.location.hash.substr(1);
    try {
        settings = JSON.parse(decodeURIComponent(hash));
    } catch(e) {
        $('
').addClass('alert').html('<button type="button" class="close" data-dismiss="alert">×</button> Could not read settings from URL hash! The settings supplied in your URL hash are not a valid JSON object. Are you sure you followed the right link?').appendTo('body');
        return false
    }
    if('dataset_box_url' in settings){
        window.sqliteEndpoint = settings.dataset_box_url + '/sqlite'
        createSpreadsheet()
    } else {
        $('
').addClass('alert').html('<button type="button" class="close" data-dismiss="alert">×</button> Which dataset do you want to visualise? You supplied a JSON object in the URL hash, but it doesn’t contain a “dataset_box_url” key-value pair. Are you sure you followed the right link?').appendTo('body');
    }

});
<|endoftext|>


<commit_before>(function() {
    var color = window.color;
    color.bar = function ( el ) {
        return new Bar( el )
    }

    function Bar( el ) {
        this._el = el;
    }

    Bar.prototype._x0 = "";
    Bar.prototype._color = "";
    Bar.prototype._palette = window.color.palettes.set3;

    Bar.prototype.data = autodraw( getset( "_data" ) );
    Bar.prototype.x0 = autodraw( getset( "_x0" ) );
    Bar.prototype.x1 = autodraw( getset( "_x1", "" ) );
    Bar.prototype.x = alias( "x0" );
    Bar.prototype.y = autodraw( getset( "_y" ) );
    Bar.prototype.color = autodraw( getset( "_color" ) );
    Bar.prototype.palette = autodraw( getset( "_palette" ) );

    // draw once
    Bar.prototype.draw = function () {
        if ( !this._drawing ) {
            this._drawing = setTimeout( this._draw.bind( this ), 0 );
        }
        return this;
    }

    // actual drawing
    Bar.prototype._draw = function () {
        clearTimeout( this._drawing );
        delete this._drawing;
        draw( this );
        return this;
    }

    function draw( that ) {
        var el = that._el;
        el.innerHTML = "<svg></svg>";
        var svg = d3.select( el )
            .select( "svg" );

        svg.style({ height: "100%", width: "100%" });

        var height = svg.node().offsetHeight;
        var width = svg.node().offsetWidth;
        var _x0 = that._x0, _x1 = that._x1, _c = that._color, _y = that._y;

        // build the groups tree
        data = d3.nest()
            .key( function ( d ) { return d[ _x0 ] || "" } )
            .key( function ( d ) { return d[ _x1 ] || "" } )
            .key( function ( d ) { return d[ _c ]  || "" } )
            .rollup( function ( data ) {
                return data.reduce( function ( v, d ) {
                    return { y: v.y + d[ _y ], y0: 0 };
                }, { y: 0 } )
            })
            .entries( that._data );

        // extract the colors and bars from the data tree
        var colors = color.tree.dfs()
            .filter(function ( d, i, j ) { return j == 3 })
            .values( function ( d ) { return d.values || d })
            .entries( data );

        var bars = color.tree.dfs()
            .filter(function ( d, i, j ) { return j == 2 })
            .values( function ( d ) { return d.values || d })
            .entries( data );

        // stack the colors
        bars.map( function ( data ) {
            return data.values.map( function ( d ) {
                return [ d.values ]
            })
        })
        .forEach( d3.layout.stack() );

        // build the scales
        var allx0 = data.map( function ( d ) { return d.key });
        var x0 = d3.scale.ordinal()
            .domain( allx0 )
            .rangeRoundBands([ 0, width ], .1 );

        var allx1 = bars.map( function ( d ) { return d.key })
        var x1 = d3.scale.ordinal()
            .domain( allx1 )
            .rangeRoundBands( [ 0, x0.rangeBand() ], .01 )

        var ally = colors.map( function ( d ) { return d.values.y + d.values.y0 } );
        var y = d3.scale.linear()
            .domain([ 0, d3.max( ally ) ])
            .rangeRound([ 0, height ] );

        var allc = colors.map( function ( d ) { return d.key } );
        var clin = d3.scale.linear()
            .domain( d3.extent( allc ) )
            .range( [ that._palette.from, that._palette.to ] );

        var cord = d3.scale.ordinal()
            .domain( allc )
            .range( that._palette )

        var c = that._palette.from && that._palette.to ? clin : cord;

        // start drawing
        var groups = svg.selectAll( "g" )
            .data( data )
            .enter().append( "g" )
            .attr( "data-group", function ( d ) {
                return d.key;
            })

        groups.attr( "transform", function ( d ) {
            return "translate(" + x0( d.key ) + ",0)";
        })

        var bars = groups.selectAll( "g" )
            .data(function ( d ) { return d.values })
            .enter().append( "g" )
            .attr( "data-bar", function ( d ) {
                return d.key;
            });

        bars.attr( "transform", function ( d ) {
            return "translate(" + x1( d.key ) + ",0)";
        })

        var rects = bars.selectAll( "rect" )
            .data( function ( d ) { return d.values } )
            .enter().append( "rect" )

        rects
            .attr( "y", function ( d ) {
                return height - y( d.values.y ) - y( d.values.y0 )
            })
            .attr( "height", function ( d ) {
                return y( d.values.y );
            })
            .attr( "width", function ( d ) {
                return x1.rangeBand()
            })
            .attr( "fill", function ( d ) {
                return c( d.key );
            })
    }

    function getset ( key ) {
        return function ( value ) {
            if ( arguments.length == 0 ) {
                return this[ key ];
            }

            this[ key ] = value;
            return this;
        }
    }

    function autodraw ( fn ) {
        return function () {
            var rv = fn.apply( this, arguments );
            return rv == this ? this.draw() : rv;
        }
    }

    function alias ( name ) {
        return function () {
            return this[ name ].apply( this, arguments );
        }
    }

})()<commit_msg>Conventions<commit_after>(function() {
    var color = window.color;
    color.bar = function ( el ) {
        return new Bar( el )
    }

    function Bar( el ) {
        this._el = el;
    }

    Bar.prototype._x0 = "";
    Bar.prototype._color = "";
    Bar.prototype._palette = window.color.palettes.set3;

    Bar.prototype.data = autodraw( getset( "_data" ) );
    Bar.prototype.x0 = autodraw( getset( "_x0" ) );
    Bar.prototype.x1 = autodraw( getset( "_x1", "" ) );
    Bar.prototype.x = alias( "x0" );
    Bar.prototype.y = autodraw( getset( "_y" ) );
    Bar.prototype.color = autodraw( getset( "_color" ) );
    Bar.prototype.palette = autodraw( getset( "_palette" ) );

    // draw once
    Bar.prototype.draw = function () {
        if ( !this._drawing ) {
            this._drawing = setTimeout( this._draw.bind( this ), 0 );
        }
        return this;
    }

    // actual drawing
    Bar.prototype._draw = function () {
        clearTimeout( this._drawing );
        delete this._drawing;
        draw( this );
        return this;
    }

    function draw( that ) {
        var el = that._el;
        el.innerHTML = "<svg></svg>";
        var svg = d3.select( el )
            .select( "svg" );

        svg.style({ height: "100%", width: "100%" });

        var height = svg.node().offsetHeight;
        var width = svg.node().offsetWidth;
        var _x0 = that._x0, _x1 = that._x1, _c = that._color, _y = that._y;

        // build the groups tree
        data = d3.nest()
            .key( function ( d ) { return d[ _x0 ] || "" } )
            .key( function ( d ) { return d[ _x1 ] || "" } )
            .key( function ( d ) { return d[ _c ]  || "" } )
            .rollup( function ( data ) {
                return data.reduce( function ( v, d ) {
                    return { y: v.y + d[ _y ], y0: 0 };
                }, { y: 0 } )
            })
            .entries( that._data );

        // extract the colors and bars from the data tree
        var bars = color.tree.dfs()
            .filter( function ( d, i, j ) { return j == 2 } )
            .values( function ( d ) { return d.values || d } )
            .entries( data );

        var colors = color.tree.dfs()
            .filter( function ( d, i, j ) { return j == 3 } )
            .values( function ( d ) { return d.values || d } )
            .entries( data );

        // stack the colors
        bars.map( function ( data ) {
            return data.values.map( function ( d ) {
                return [ d.values ]
            })
        })
        .forEach( d3.layout.stack() );

        // build the scales
        var allx0 = data.map( function ( d ) { return d.key });
        var x0 = d3.scale.ordinal()
            .domain( allx0 )
            .rangeRoundBands([ 0, width ], .1 );

        var allx1 = bars.map( function ( d ) { return d.key })
        var x1 = d3.scale.ordinal()
            .domain( allx1 )
            .rangeRoundBands( [ 0, x0.rangeBand() ], .01 )

        var ally = colors.map( function ( d ) { return d.values.y + d.values.y0 } );
        var y = d3.scale.linear()
            .domain([ 0, d3.max( ally ) ])
            .rangeRound([ 0, height ] );

        var allc = colors.map( function ( d ) { return d.key } );
        var clin = d3.scale.linear()
            .domain( d3.extent( allc ) )
            .range( [ that._palette.from, that._palette.to ] );

        var cord = d3.scale.ordinal()
            .domain( allc )
            .range( that._palette )

        var c = that._palette.from && that._palette.to ? clin : cord;

        // start drawing
        var groups = svg.selectAll( "g" )
            .data( data )
            .enter().append( "g" )
            .attr( "data-group", function ( d ) {
                return d.key;
            })

        groups.attr( "transform", function ( d ) {
            return "translate(" + x0( d.key ) + ",0)";
        })

        var bars = groups.selectAll( "g" )
            .data(function ( d ) { return d.values })
            .enter().append( "g" )
            .attr( "data-bar", function ( d ) {
                return d.key;
            });

        bars.attr( "transform", function ( d ) {
            return "translate(" + x1( d.key ) + ",0)";
        })

        var rects = bars.selectAll( "rect" )
            .data( function ( d ) { return d.values } )
            .enter().append( "rect" )

        rects
            .attr( "y", function ( d ) {
                return height - y( d.values.y ) - y( d.values.y0 )
            })
            .attr( "height", function ( d ) {
                return y( d.values.y );
            })
            .attr( "width", function ( d ) {
                return x1.rangeBand()
            })
            .attr( "fill", function ( d ) {
                return c( d.key );
            })
    }

    function getset ( key ) {
        return function ( value ) {
            if ( arguments.length == 0 ) {
                return this[ key ];
            }

            this[ key ] = value;
            return this;
        }
    }

    function autodraw ( fn ) {
        return function () {
            var rv = fn.apply( this, arguments );
            return rv == this ? this.draw() : rv;
        }
    }

    function alias ( name ) {
        return function () {
            return this[ name ].apply( this, arguments );
        }
    }

})()<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import {
  bemHelper,
  prepareTemplateProps,
  getContainerNode
} from '../../lib/utils.js';
import autoHideContainerHOC from '../../decorators/autoHideContainer.js';
import headerFooterHOC from '../../decorators/headerFooter.js';
import StatsComponent from '../../components/Stats/Stats.js';
import cx from 'classnames';
import defaultTemplates from './defaultTemplates.js';

let bem = bemHelper('ais-stats');

/**
 * Display various stats about the current search state
 * @function stats
 * @param  {string|DOMElement} options.container CSS Selector or DOMElement to insert the widget
 * @param  {Object} [options.templates] Templates to use for the widget
 * @param  {string|Function} [options.templates.header=''] Header template
 * @param  {string|Function} [options.templates.body] Body template
 * @param  {string|Function} [options.templates.footer=''] Footer template
 * @param  {Function} [options.transformData] Function to change the object passed to the `body` template
 * @param  {boolean} [options.autoHideContainer=true] Hide the container when no results match
 * @param  {Object} [options.cssClasses] CSS classes to add
 * @param  {string|string[]} [options.cssClasses.root] CSS class to add to the root element
 * @param  {string|string[]} [options.cssClasses.header] CSS class to add to the header element
 * @param  {string|string[]} [options.cssClasses.body] CSS class to add to the body element
 * @param  {string|string[]} [options.cssClasses.footer] CSS class to add to the footer element
 * @param  {string|string[]} [options.cssClasses.time] CSS class to add to the element wrapping the time processingTimeMs
 * @return {Object}
 */
const usage = `Usage:
stats({
  container,
  [ template ],
  [ transformData ],
  [ autoHideContainer]
})`;
function stats({
    container,
    cssClasses: userCssClasses = {},
    autoHideContainer = true,
    templates = defaultTemplates,
    collapsible = false,
    transformData
  } = {}) {
  if (!container) throw new Error(usage);
  let containerNode = getContainerNode(container);

  let Stats = headerFooterHOC(StatsComponent);
  if (autoHideContainer === true) {
    Stats = autoHideContainerHOC(Stats);
  }

  if (!containerNode) {
    throw new Error(usage);
  }

  let cssClasses = {
    body: cx(bem('body'), userCssClasses.body),
    footer: cx(bem('footer'), userCssClasses.footer),
    header: cx(bem('header'), userCssClasses.header),
    root: cx(bem(null), userCssClasses.root),
    time: cx(bem('time'), userCssClasses.time)
  };

  return {
    init({templatesConfig}) {
      this._templateProps = prepareTemplateProps({
        transformData,
        defaultTemplates,
        templatesConfig,
        templates
      });
    },

    render: function({results}) {
      ReactDOM.render(
        <Stats
          collapsible={collapsible}
          cssClasses={cssClasses}
          hitsPerPage={results.hitsPerPage}
          nbHits={results.nbHits}
          nbPages={results.nbPages}
          page={results.page}
          processingTimeMS={results.processingTimeMS}
          query={results.query}
          shouldAutoHideContainer={results.nbHits === 0}
          templateProps={this._templateProps}
        />,
        containerNode
      );
    }
  };
}

export default stats;
<commit_msg>docs(stats): update stats doc about templating<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import {
  bemHelper,
  prepareTemplateProps,
  getContainerNode
} from '../../lib/utils.js';
import autoHideContainerHOC from '../../decorators/autoHideContainer.js';
import headerFooterHOC from '../../decorators/headerFooter.js';
import StatsComponent from '../../components/Stats/Stats.js';
import cx from 'classnames';
import defaultTemplates from './defaultTemplates.js';

let bem = bemHelper('ais-stats');

/**
 * Display various stats about the current search state
 * @function stats
 * @param  {string|DOMElement} options.container CSS Selector or DOMElement to insert the widget
 * @param  {Object} [options.templates] Templates to use for the widget
 * @param  {string|Function} [options.templates.header=''] Header template
 * @param  {string|Function} [options.templates.body] Body template, provided with `hasManyResults`,
 * `hasNoResults`, `hasOneResult`, `hitsPerPage`, `nbHits`, `nbPages`, `page`, `processingTimeMS`, `query`
 * @param  {string|Function} [options.templates.footer=''] Footer template
 * @param  {Function} [options.transformData] Function to change the object passed to the `body` template
 * @param  {boolean} [options.autoHideContainer=true] Hide the container when no results match
 * @param  {Object} [options.cssClasses] CSS classes to add
 * @param  {string|string[]} [options.cssClasses.root] CSS class to add to the root element
 * @param  {string|string[]} [options.cssClasses.header] CSS class to add to the header element
 * @param  {string|string[]} [options.cssClasses.body] CSS class to add to the body element
 * @param  {string|string[]} [options.cssClasses.footer] CSS class to add to the footer element
 * @param  {string|string[]} [options.cssClasses.time] CSS class to add to the element wrapping the time processingTimeMs
 * @return {Object}
 */
const usage = `Usage:
stats({
  container,
  [ template ],
  [ transformData ],
  [ autoHideContainer]
})`;
function stats({
    container,
    cssClasses: userCssClasses = {},
    autoHideContainer = true,
    templates = defaultTemplates,
    collapsible = false,
    transformData
  } = {}) {
  if (!container) throw new Error(usage);
  let containerNode = getContainerNode(container);

  let Stats = headerFooterHOC(StatsComponent);
  if (autoHideContainer === true) {
    Stats = autoHideContainerHOC(Stats);
  }

  if (!containerNode) {
    throw new Error(usage);
  }

  let cssClasses = {
    body: cx(bem('body'), userCssClasses.body),
    footer: cx(bem('footer'), userCssClasses.footer),
    header: cx(bem('header'), userCssClasses.header),
    root: cx(bem(null), userCssClasses.root),
    time: cx(bem('time'), userCssClasses.time)
  };

  return {
    init({templatesConfig}) {
      this._templateProps = prepareTemplateProps({
        transformData,
        defaultTemplates,
        templatesConfig,
        templates
      });
    },

    render: function({results}) {
      ReactDOM.render(
        <Stats
          collapsible={collapsible}
          cssClasses={cssClasses}
          hitsPerPage={results.hitsPerPage}
          nbHits={results.nbHits}
          nbPages={results.nbPages}
          page={results.page}
          processingTimeMS={results.processingTimeMS}
          query={results.query}
          shouldAutoHideContainer={results.nbHits === 0}
          templateProps={this._templateProps}
        />,
        containerNode
      );
    }
  };
}

export default stats;
<|endoftext|>


<commit_before>let gpVals = {
    triggerMin: 0.5,
    deadZones: [0.25, 0.25, 0.25, 0.25]
};
let input = {
    click: function(e) {
        if(game.currentInputHandler.click(p)) { return; }
        const p = input.getMousePos(e);
    },
    moveMouse: function(e) {
        const p = input.getMousePos(e);
        if(game.currentInputHandler.mouseMove(p)) { return; }
    },
    justPressed: {}, keys: {}, mainKey: undefined,
    IsFreshPauseOrConfirmPress: () => (input.justPressed[player.controls.pause] === 0) || (input.justPressed[player.controls.confirm] === 0),
    setMainKey: function(key) {
        if(key === undefined) {
            if(input.keys[player.controls.up] !== undefined) { input.mainKey = 0; }
            else if(input.keys[player.controls.left] !== undefined) { input.mainKey = 1; }
            else if(input.keys[player.controls.down] !== undefined) { input.mainKey = 2; }
            else if(input.keys[player.controls.right] !== undefined) { input.mainKey = 3; }
            else { input.mainKey = undefined; }
        } else if(input.mainKey === undefined) {
            input.mainKey = [player.controls.up, player.controls.left, player.controls.down, player.controls.right].indexOf(key);
        }
    },
    clearAllKeys: function() {
        input.mainKey = undefined;
        for(const key in input.keys) {
            clearInterval(input.keys[key]);
            input.keys[key] = undefined;
        }
    },
    IsIgnoredByKeyPress(key) {
        if(key.indexOf("Arrow") === 0) { return true; }
        if(key[0] === "F" && key.length > 1) { return true; }
        return ["Alt", "Shift", "Control", "CapsLock", "Tab", "Escape", "Backspace", "NumLock",
                "Delete", "End", "PageDown", "PageUp", "Home", "Insert", "ScrollLock", "Pause"].indexOf(key) >= 0;
    },
    GetKey: e => e.key.length === 1 ? e.key.toLowerCase() : e.key,
    keyDown: function(e) {
        const key = input.GetKey(e);
        input.justPressed[key] = input.justPressed[key] === undefined ? 0 : input.justPressed[key] + 1;
        if(player.options.controltype === 1) { input.SwitchControlType(0); }
        if([player.controls.up, player.controls.left, player.controls.down, player.controls.right].indexOf(e.key) >= 0 && game.currentInputHandler.freeMovement) {
            input.setMainKey(e.key);
            if(input.keys[e.key] !== undefined) { return; }
            input.keys[e.key] = setInterval(function() {
                game.currentInputHandler.keyPress(e.key);
            }, 50);
        } else if(input.IsIgnoredByKeyPress(key)) { game.currentInputHandler.keyPress(key); }
    },
    keyUp: function(e) {
        const key = input.GetKey(e);
        input.justPressed[key] = -1;
        if([player.controls.up, player.controls.left, player.controls.down, player.controls.right].indexOf(key) >= 0 && game.currentInputHandler.freeMovement) {
            clearInterval(input.keys[key]);
            input.keys[key] = undefined;
            input.setMainKey();
        }
    },
    keyPress: function(e) {
        if([player.controls.up, player.controls.left, player.controls.down, player.controls.right].indexOf(e.key) >= 0 && game.currentInputHandler.freeMovement) {
            return;
        }
        game.currentInputHandler.keyPress(key);
        input.justPressed[key]++;
    },
    getMousePos: function(e) {
        const rect = gfx.canvas["menutext"].getBoundingClientRect();
        const x = e.clientX - rect.left;
        const y = e.clientY - rect.top;
        return {
            x: Math.floor(x / 16 / gfx.scale),
            y: Math.floor(y / 16 / gfx.scale)
        };
    },
    SwitchControlType: function(newType) {
        player.options.controltype = newType;
        switch(newType) {
            case 1: player.controls = player.gamepadcontrols; break;
            case 0: player.controls = player.keyboardcontrols; break;
        }
    },
    gamepads: {}, gamepadQueryIdx: -1,
    gamepadButtons: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // buttons 0 - 15
        0, 0, 0, 0, // negative axes Lx Ly Rx Ry
        0, 0, 0, 0], // positive axes Lx Ly Rx Ry
    gamepadConnected: function(e) {
        input.gamepads[e.gamepad.index] = e.gamepad;
        console.log("Gamepad connected at index %d: %s. %d buttons, %d axes.", e.gamepad.index, e.gamepad.id, e.gamepad.buttons.length, e.gamepad.axes.length);
        input.SwitchControlType(1);
        input.gamepadQueryIdx = setInterval(input.QueryGamepads, 10);
    },
    gamepadDisconnected: function(e) {
        delete input.gamepads[e.gamepad.index];
        let hasKeys = false;
        for(const key in input.gamepads) { hasKeys = true; break; }
        if(!hasKeys) {
            console.log("no controllers left!");
            clearInterval(input.gamepadQueryIdx);
            input.gamepadQueryIdx = -1;
            input.SwitchControlType(0);
        }
    },
    QueryGamepads: function() {
        const gamepads = navigator.getGamepads();
        if(gamepads === undefined || gamepads === null) { return; }
        const buttonsDown = [];
        for(const gp in gamepads) {
            if(gamepads[gp] === null || gamepads[gp].id === undefined) { continue; }
            gamepads[gp].buttons.forEach((e, i) => {
                if(e.pressed && e.value >= gpVals.triggerMin && i < 16) { buttonsDown.push(i); }
            });
            gamepads[gp].axes.forEach((e, i) => {
                if(e <= -gpVals.deadZones[i]) {
                    buttonsDown.push(16 + i);
                } else if(e >= gpVals.deadZones[i]) {
                    buttonsDown.push(20 + i);
                }
            });
        }
        if(buttonsDown.length > 0 && player.options.controltype === 0) { input.SwitchControlType(1); }
        for(let i = 0; i < input.gamepadButtons.length; i++) {
            const prevState = input.gamepadButtons[i];
            const btn = (i < 16) ? ("Gamepad" + i) : ("GamepadA" + (i - 16));
            if(buttonsDown.indexOf(i) < 0 && buttonsDown.indexOf(-i) < 0) { // not pressed
                if(prevState > 0) { // just released
                    input.gamepadButtons[i] = -1;
                    input.justPressed[btn] = -1;
                    if([player.controls.up, player.controls.left, player.controls.down, player.controls.right].indexOf(btn) >= 0 && game.currentInputHandler.freeMovement) {
                        clearInterval(input.keys[btn]);
                        input.keys[btn] = undefined;
                        input.setMainKey();
                    }
                } else { input.gamepadButtons[i] = 0; } // not pressed
            } else { // pressed
                input.gamepadButtons[i]++;
                const btnVal = input.gamepadButtons[i];
                if(btnVal === 1 || (btnVal >= 45 && btnVal % 15 === 0)) {
                    input.justPressed[btn] = input.justPressed[btn] === undefined ? 0 : input.justPressed[btn] + 1;
                    if([player.controls.up, player.controls.left, player.controls.down, player.controls.right].indexOf(btn) >= 0 && game.currentInputHandler.freeMovement) {
                        input.setMainKey(btn);
                        if(input.keys[btn] !== undefined) { return; }
                        input.keys[btn] = setInterval(function() {
                            game.currentInputHandler.keyPress(btn);
                        }, 50);
                    } else { game.currentInputHandler.keyPress(btn); }
                }
            }
        }
    }
};<commit_msg>FIXED CASE SENSITIVITY OF KEYBOARD CONTROLS<commit_after>let gpVals = {
    triggerMin: 0.5,
    deadZones: [0.25, 0.25, 0.25, 0.25]
};
let input = {
    click: function(e) {
        if(game.currentInputHandler.click(p)) { return; }
        const p = input.getMousePos(e);
    },
    moveMouse: function(e) {
        const p = input.getMousePos(e);
        if(game.currentInputHandler.mouseMove(p)) { return; }
    },
    justPressed: {}, keys: {}, mainKey: undefined,
    IsFreshPauseOrConfirmPress: () => (input.justPressed[player.controls.pause] === 0) || (input.justPressed[player.controls.confirm] === 0),
    setMainKey: function(key) {
        if(key === undefined) {
            if(input.keys[player.controls.up] !== undefined) { input.mainKey = 0; }
            else if(input.keys[player.controls.left] !== undefined) { input.mainKey = 1; }
            else if(input.keys[player.controls.down] !== undefined) { input.mainKey = 2; }
            else if(input.keys[player.controls.right] !== undefined) { input.mainKey = 3; }
            else { input.mainKey = undefined; }
        } else if(input.mainKey === undefined) {
            input.mainKey = [player.controls.up, player.controls.left, player.controls.down, player.controls.right].indexOf(key);
        }
    },
    clearAllKeys: function() {
        input.mainKey = undefined;
        for(const key in input.keys) {
            clearInterval(input.keys[key]);
            input.keys[key] = undefined;
        }
    },
    IsIgnoredByKeyPress(key) {
        if(key.indexOf("Arrow") === 0) { return true; }
        if(key[0] === "F" && key.length > 1) { return true; }
        return ["Alt", "Shift", "Control", "CapsLock", "Tab", "Escape", "Backspace", "NumLock",
                "Delete", "End", "PageDown", "PageUp", "Home", "Insert", "ScrollLock", "Pause"].indexOf(key) >= 0;
    },
    GetKey: e => e.key.length === 1 ? e.key.toLowerCase() : e.key,
    keyDown: function(e) {
        const key = input.GetKey(e);
        input.justPressed[key] = input.justPressed[key] === undefined ? 0 : input.justPressed[key] + 1;
        if(player.options.controltype === 1) { input.SwitchControlType(0); }
        if([player.controls.up, player.controls.left, player.controls.down, player.controls.right].indexOf(key) >= 0 && game.currentInputHandler.freeMovement) {
            input.setMainKey(key);
            if(input.keys[key] !== undefined) { return; }
            input.keys[key] = setInterval(function() {
                game.currentInputHandler.keyPress(key);
            }, 50);
        } else if(input.IsIgnoredByKeyPress(key)) { game.currentInputHandler.keyPress(key); }
    },
    keyUp: function(e) {
        const key = input.GetKey(e);
        input.justPressed[key] = -1;
        if([player.controls.up, player.controls.left, player.controls.down, player.controls.right].indexOf(key) >= 0 && game.currentInputHandler.freeMovement) {
            clearInterval(input.keys[key]);
            input.keys[key] = undefined;
            input.setMainKey();
        }
    },
    keyPress: function(e) {
        const key = input.GetKey(e);
        if([player.controls.up, player.controls.left, player.controls.down, player.controls.right].indexOf(key) >= 0 && game.currentInputHandler.freeMovement) {
            return;
        }
        game.currentInputHandler.keyPress(key);
        input.justPressed[key]++;
    },
    getMousePos: function(e) {
        const rect = gfx.canvas["menutext"].getBoundingClientRect();
        const x = e.clientX - rect.left;
        const y = e.clientY - rect.top;
        return {
            x: Math.floor(x / 16 / gfx.scale),
            y: Math.floor(y / 16 / gfx.scale)
        };
    },
    SwitchControlType: function(newType) {
        player.options.controltype = newType;
        switch(newType) {
            case 1: player.controls = player.gamepadcontrols; break;
            case 0: player.controls = player.keyboardcontrols; break;
        }
    },
    gamepads: {}, gamepadQueryIdx: -1,
    gamepadButtons: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // buttons 0 - 15
        0, 0, 0, 0, // negative axes Lx Ly Rx Ry
        0, 0, 0, 0], // positive axes Lx Ly Rx Ry
    gamepadConnected: function(e) {
        input.gamepads[e.gamepad.index] = e.gamepad;
        console.log("Gamepad connected at index %d: %s. %d buttons, %d axes.", e.gamepad.index, e.gamepad.id, e.gamepad.buttons.length, e.gamepad.axes.length);
        input.SwitchControlType(1);
        input.gamepadQueryIdx = setInterval(input.QueryGamepads, 10);
    },
    gamepadDisconnected: function(e) {
        delete input.gamepads[e.gamepad.index];
        let hasKeys = false;
        for(const key in input.gamepads) { hasKeys = true; break; }
        if(!hasKeys) {
            console.log("no controllers left!");
            clearInterval(input.gamepadQueryIdx);
            input.gamepadQueryIdx = -1;
            input.SwitchControlType(0);
        }
    },
    QueryGamepads: function() {
        const gamepads = navigator.getGamepads();
        if(gamepads === undefined || gamepads === null) { return; }
        const buttonsDown = [];
        for(const gp in gamepads) {
            if(gamepads[gp] === null || gamepads[gp].id === undefined) { continue; }
            gamepads[gp].buttons.forEach((e, i) => {
                if(e.pressed && e.value >= gpVals.triggerMin && i < 16) { buttonsDown.push(i); }
            });
            gamepads[gp].axes.forEach((e, i) => {
                if(e <= -gpVals.deadZones[i]) {
                    buttonsDown.push(16 + i);
                } else if(e >= gpVals.deadZones[i]) {
                    buttonsDown.push(20 + i);
                }
            });
        }
        if(buttonsDown.length > 0 && player.options.controltype === 0) { input.SwitchControlType(1); }
        for(let i = 0; i < input.gamepadButtons.length; i++) {
            const prevState = input.gamepadButtons[i];
            const btn = (i < 16) ? ("Gamepad" + i) : ("GamepadA" + (i - 16));
            if(buttonsDown.indexOf(i) < 0 && buttonsDown.indexOf(-i) < 0) { // not pressed
                if(prevState > 0) { // just released
                    input.gamepadButtons[i] = -1;
                    input.justPressed[btn] = -1;
                    if([player.controls.up, player.controls.left, player.controls.down, player.controls.right].indexOf(btn) >= 0 && game.currentInputHandler.freeMovement) {
                        clearInterval(input.keys[btn]);
                        input.keys[btn] = undefined;
                        input.setMainKey();
                    }
                } else { input.gamepadButtons[i] = 0; } // not pressed
            } else { // pressed
                input.gamepadButtons[i]++;
                const btnVal = input.gamepadButtons[i];
                if(btnVal === 1 || (btnVal >= 45 && btnVal % 15 === 0)) {
                    input.justPressed[btn] = input.justPressed[btn] === undefined ? 0 : input.justPressed[btn] + 1;
                    if([player.controls.up, player.controls.left, player.controls.down, player.controls.right].indexOf(btn) >= 0 && game.currentInputHandler.freeMovement) {
                        input.setMainKey(btn);
                        if(input.keys[btn] !== undefined) { return; }
                        input.keys[btn] = setInterval(function() {
                            game.currentInputHandler.keyPress(btn);
                        }, 50);
                    } else { game.currentInputHandler.keyPress(btn); }
                }
            }
        }
    }
};<|endoftext|>


<commit_before>(function() {
var l = window.location;
var socks = [];
function setup(ii, addr) {
	var sock, i;
	if(addr == "")
		return;
	else if(addr == '/') {
		addr = (l.protocol == "https:" ? "wss://" : "ws://") + l.hostname + ":" + l.port;
	}
	try {
		sock = new WebSocket(addr, "ws");
	} catch(e) {
		console.log(e);
		return setTimeout(function() {
			setup(ii, addr);
		}, 500);
	}
	sock.onmessage = function(ev) {
		for(i = 0; i < socks.length; i++) {
			if(i != ii && socks[i] && socks[i].readyState==1)
				socks[i].send(ev.data);
		}
	};
	sock.onclose = sock.onerror = function() {
		setup(ii, addr);
	};
	socks[ii] = sock;
}

for(var i = 0; i < arguments.length; i++) {
	setup(i, arguments[i])
}

})("%s", "%s");
<commit_msg>closing all connections if one is going down.<commit_after>(function() {
var l = window.location;
var socks = [];
function setup(ii, addr) {
	var sock, i, closing = false;
	if(addr == "")
		return;
	else if(addr == '/') {
		addr = (l.protocol == "https:" ? "wss://" : "ws://") + l.hostname + ":" + l.port;
	}
	try {
		sock = new WebSocket(addr, "ws");
	} catch(e) {
		console.log(e);
		return setTimeout(function() {
			setup(ii, addr);
		}, 500);
	}
	sock.onmessage = function(ev) {
		for(i = 0; i < socks.length; i++) {
			if(i != ii && socks[i] && socks[i].readyState==1)
				socks[i].send(ev.data);
		}
	};
	sock.onclose = sock.onerror = function() {
		for(i = 0; i < socks.length; i++) {
			if(i != ii && socks[i] && socks[i].readyState<=1)
				socks[i].close();
		}
		if(!closing)
			setup(ii, addr);
		closing = true;
	};
	socks[ii] = sock;
}

for(var i = 0; i < arguments.length; i++) {
	setup(i, arguments[i])
}

})("%s", "%s");
<|endoftext|>


<commit_before>/*
global

chai,
jsforms,
analyzer
*/
'use strict';

const assert = chai.assert;

describe('Forms - Third Form', function () {

    describe('greeter', function () {

        it('should say "Hello!" by default', function () {
            assert.equal(jsforms.greet(), 'Hello!');
        });

        it('should say "Salutations!" when Salutations is passed', function () {
            assert.equal(jsforms.greet('Salutations'), 'Salutations!');
        });

        describe('Refactoring steps', function () {
            /*
            1 - Create function called isTypeOf
            2 - Replace typeof check in greet function with isTypeOf
            3 - Create function called eitherOnType
            4 - Replace ternary in greet function with eitherOnType
            */

            // Keep the tests passing!

            it('has a function called "isTypeOf" which takes parameters "type" and "value"', function () {
                const analyzerFunctionOptions = {
                    formNumber: 3,
                    analyzerName: 'containsFunction',
                    analyzerOptions: {
                        functionName: 'isTypeOf',
                        parameters: ['type', 'value']
                    }
                };

                return analyzer
                    .analyze(analyzerFunctionOptions)
                    .then(function ({ result }) {
                        assert.isTrue(result);
                    });
            });

            it('calls isTypeOf from greet', function () {
                const analyzerCallOptions = {
                    formNumber: 3,
                    analyzerName: 'containsCall',
                    analyzerOptions: {
                        parentName: 'greet',
                        methodName: 'isTypeOf'
                    }
                };

                const analyzerRefactorCallOptions = {
                    formNumber: 3,
                    analyzerName: 'containsCall',
                    analyzerOptions: {
                        parentName: 'eitherOnType',
                        methodName: 'isTypeOf'
                    }
                };

                return analyzer
                    .analyze(analyzerRefactorCallOptions)
                    .then(function ({ result }) {
                        if (!result) {
                            return analyzer
                                .analyze(analyzerCallOptions);
                        } else {
                            return Promise.resolve({ result: true });
                        }
                    })
                    .then(function ({ result }) {
                        assert.isTrue(result);
                    });
            });

            it('has a function called "eitherOnType" with parameters "type", "testValue", "defaultValue" -- return testValue if it matches type, otherwise return defaultValue', function () {
                const analyzerFunctionOptions = {
                    formNumber: 3,
                    analyzerName: 'containsFunction',
                    analyzerOptions: {
                        functionName: 'eitherOnType',
                        parameters: ['type', 'testValue', 'defaultValue']
                    }
                };

                return analyzer
                    .analyze(analyzerFunctionOptions)
                    .then(function ({ result }) {
                        assert.isTrue(result);
                    });
            });

            it('calls eitherOnType from greet', function () {
                const analyzerCallOptions = {
                    formNumber: 3,
                    analyzerName: 'containsCall',
                    analyzerOptions: {
                        parentName: 'greet',
                        methodName: 'eitherOnType'
                    }
                };

                return analyzer
                    .analyze(analyzerCallOptions)
                    .then(function ({ result }) {
                        assert.isTrue(result);
                    });
            });

        });

    });

    describe('square', function () {

        // Keep the tests passing!

        it('should square 1', function () {
            assert.equal(jsforms.square(1), 1);
        });

        it('should square 3', function () {
            assert.equal(jsforms.square(3), 9);
        });

    });

    describe('squareRoot', function () {

        // Keep the tests passing!

        it('should take the square root of 1', function () {
            assert.equal(jsforms.squareRoot(1), 1);
        });

        it('should take the square root of 4', function () {
            assert.equal(jsforms.squareRoot(4), 2);
        });

    });

    describe('sum', function () {

        it('should take the sum of one number', function () {
            assert.equal(jsforms.sum([1]), 1);
        });

        it('should add two numbers', function () {
            assert.equal(jsforms.sum([2, 3]), 5);
        });

        it('should add multiple numbers', function () {
            assert.equal(jsforms.sum([1, 3, 5, 7]), 16);
        });

        describe('Refactoring steps', function () {

            /*
            1 - Replace forEach with reduce -- assign calculated sum to "result" variable
            2 - Remove wrapping function from reduce -- pass add function directly to reduce
            3 - Remove assignment and return calculated result directly to caller
            */

            // Keep the tests passing!

            it('has been refactored to use reduce in the place of forEach, assigning the output to result', function () {
                const analyzerReduceOptions = {
                    formNumber: 3,
                    analyzerName: 'containsCall',
                    analyzerOptions: {
                        parentName: 'sum',
                        objectName: 'nums',
                        methodName: 'reduce'
                    }
                };

                const analyzerForEachOptions = {
                    formNumber: 3,
                    analyzerName: 'containsCall',
                    analyzerOptions: {
                        parentName: 'sum',
                        objectName: 'nums',
                        methodName: 'forEach'
                    }
                };

                return analyzer
                    .analyze(analyzerReduceOptions)
                    .then(function ({ result }) {
                        assert.isTrue(result, 'Reduce is not being used in the sum function.');
                        return analyzer
                            .analyze(analyzerForEachOptions);
                    })
                    .then(function ({ result }) {
                        assert.isFalse(result, 'ForEach is still being used in the sum function.')
                    });
            });

            it('has been refactored to pass the add function directly to reduce', function () {
                const analyzerReduceOptions = {
                    formNumber: 3,
                    analyzerName: 'containsCall',
                    analyzerOptions: {
                        parentName: 'sum',
                        objectName: 'nums',
                        methodName: 'reduce',
                        variableName: 'add'
                    }
                };

                return analyzer
                    .analyze(analyzerReduceOptions)
                    .then(function ({ result }) {
                        assert.isTrue(result, 'Add is not being passed directly to reduce, yet.');
                    });
            });

            it('has been refactored to not assign the sum before returning it', function () {
                const analyzerAssignmentOptions = {
                    formNumber: 3,
                    analyzerName: 'containsAssignment',
                    analyzerOptions: {
                        parentName: 'sum'
                    }
                };

                return analyzer
                    .analyze(analyzerAssignmentOptions)
                    .then(function ({ result }) {
                        assert.isFalse(result, 'Sum still contains an assignment. Is the reduced value being returned directly?');
                    });
            });

        });
    });

    describe('squareAll', function () {

        // Keep the tests passing!

        it('should square all numbers in a single-value array', function () {
            assert.equal(jsforms.squareAll([2]).toString(), '4');
        });

        it('should square multiple numbers', function () {
            assert.equal(jsforms.squareAll([1, 2, 3, 5]).toString(), '1,4,9,25');
        });

    });

    describe('sumOfSquares', function () {

        // Keep the tests passing!

        it('should square number in a 1-length array and return it', function () {
            assert.equal(jsforms.sumOfSquares([2]), 4);
        });

        it('should take the sum of squares of multiple numbers', function () {
            assert.equal(jsforms.sumOfSquares([1, 2, 3]), 14);
        });

    });

    describe('buildVector', function () {

        // Keep the tests passing!

        it('should return vector with valueOf function which does not return vector', function () {
            let vector = jsforms.buildVector([1, 2, 3]);

            assert.equal(vector.valueOf() !== vector, true);
        });

        it('should return a vector where toString returns a vector string', function () {
            let vector = jsforms.buildVector([1, 2, 3]);

            assert.equal(vector.toString(), '<1,2,3>');
        });

        describe('Getter properties and value immutability', function () {

            it.only('should have access to read, but not write, vector.points', function () {
                /*
                 * // Setting a getter on an object:
                 * Object.defineProperty(obj, key, {
                 *      get: () => value
                 * });
                 */

                const originalPoints = [1, 2, 3];

                let vector = jsforms.buildVector(originalPoints);

                assert.throws(() => vector.points = [4, 5, 6]);
            });

            it('should not change vector object when the original array is modified', function () {
                let originalArray = [1, 2, 3];
                let vector = jsforms.buildVector(originalArray);

                originalArray.push(4);

                assert.notEqual(vector.points.length, originalArray.length);
            });

            it('should not be possible to modify vector.points', function () {
                /*
                It's possible to disable modifying an object usig Object.freeze
                */
                let vector = jsforms.buildVector([1, 2, 3]);
                assert.throws(() => vector.points.push(4));
            });

        });

        describe('Constructor type check', function () {

            it('throws an error if constructor is called with a value which is not an array', function () {
                assert.throws(() => jsforms.buildVector('not an array'));
            });

            it('throws an error if constructor is called with an array of one value which is not a number', function () {
                assert.throws(() => jsforms.buildVector(['bad value']));
            });

            it('throws an error if constructor is called with an array which contains values other than numbers', function () {
                assert.throws(() => jsforms.buildVector([1, '2', 5, {}]));
            });

            describe('Refactoring steps', function () {
                it('has a function called "isArrayOfNumbers" with a parameter "values"', function () {
                    const analyzerFunction = {
                        formNumber: 3,
                        analyzerName: 'containsFunction',
                        analyzerOptions: {
                            functionName: 'isArrayOfNumbers',
                            parameters: ['values']
                        }
                    }

                    return analyzer
                        .analyze(analyzerFunction)
                        .then(function ({ result }) {
                            assert.isTrue(result, 'Cannot find a function  called "isArrayOfNumbers"');
                        });
                });

                it('has a call in Vector constructor to "isArrayOfNumbers" with "points" as an argument', function () {
                    const analyzerCallOptions = {
                        formNumber: 3,
                        analyzerName: 'containsCall',
                        analyzerOptions: {
                            parentName: 'Vector',
                            methodName: 'isArrayOfNumbers',
                            variableName: 'points'
                        }
                    };

                    return analyzer
                        .analyze(analyzerCallOptions)
                        .then(function ({ result }) {
                            assert.isTrue(result, 'Cannot find call to isArrayOfNumbers');
                        });
                });
            });

        });

    });

    describe('magnitude', function () {

        // Keep the tests passing!

        it('should return the magnitude of a one-value vector', function () {
            assert.equal(jsforms.magnitude([5]), 5);
        });

        it('should return only positive magnitude values', function () {
            assert.equal(jsforms.magnitude([-3]), 3);
        });

        it('should return the magnitude of a two-value vector', function () {
            assert.equal(jsforms.magnitude([6, 8]), 10);
        });

        it('should return the magnitude of a multi-value vector', function () {
            assert.equal(jsforms.magnitude([0, 12, 3, 4]), 13);
        });

    });

    describe('getVectorsShorterThan', function () {

        // Keep the tests passing!

        it('should return single vector when the only vector magnitude is acceptably short', function () {
            let vectors = [jsforms.buildVector([1, 2])];
            let result = jsforms.getVectorsShorterThan(5, vectors);

            assert.equal(result.length, 1);
            assert.equal(result[0].toString(), '<1,2>');
        });

        it('should return an empty array when the only vector magnitude is too long', function () {
            let length = 4;
            let vectors = [jsforms.buildVector([3, 4])];
            let result = jsforms.getVectorsShorterThan(length, vectors);

            assert.equal(result.length, 0)
        });

        it('should only filter vectors which are too long', function () {
            let length = 10;
            let vectors = [
                jsforms.buildVector([10, 10]),
                jsforms.buildVector([3, 4])
            ];

            let result = jsforms.getVectorsShorterThan(length, vectors);

            assert.equal(result.length, 1);
            assert.equal(result[0].toString(), '<3,4>');
        });

        it('should filter all vectors which are too long', function () {
            let vectors = [
                jsforms.buildVector([1, 2, 2]),
                jsforms.buildVector([10, 20]),
                jsforms.buildVector([3, 4]),
                jsforms.buildVector([1, 2, 10, 100])
            ];

            let result = jsforms.getVectorsShorterThan(10, vectors);

            let resultValues = [
                result[0].toString(),
                result[1].toString()
            ];

            assert.equal(resultValues.toString(), '<1,2,2>,<3,4>');
        });

    });

    // You're done!
    // Good job! I like what you got.

});

<commit_msg>Removed only from test in third form<commit_after>/*
global

chai,
jsforms,
analyzer
*/
'use strict';

const assert = chai.assert;

describe('Forms - Third Form', function () {

    describe('greeter', function () {

        it('should say "Hello!" by default', function () {
            assert.equal(jsforms.greet(), 'Hello!');
        });

        it('should say "Salutations!" when Salutations is passed', function () {
            assert.equal(jsforms.greet('Salutations'), 'Salutations!');
        });

        describe('Refactoring steps', function () {
            /*
            1 - Create function called isTypeOf
            2 - Replace typeof check in greet function with isTypeOf
            3 - Create function called eitherOnType
            4 - Replace ternary in greet function with eitherOnType
            */

            // Keep the tests passing!

            it('has a function called "isTypeOf" which takes parameters "type" and "value"', function () {
                const analyzerFunctionOptions = {
                    formNumber: 3,
                    analyzerName: 'containsFunction',
                    analyzerOptions: {
                        functionName: 'isTypeOf',
                        parameters: ['type', 'value']
                    }
                };

                return analyzer
                    .analyze(analyzerFunctionOptions)
                    .then(function ({ result }) {
                        assert.isTrue(result);
                    });
            });

            it('calls isTypeOf from greet', function () {
                const analyzerCallOptions = {
                    formNumber: 3,
                    analyzerName: 'containsCall',
                    analyzerOptions: {
                        parentName: 'greet',
                        methodName: 'isTypeOf'
                    }
                };

                const analyzerRefactorCallOptions = {
                    formNumber: 3,
                    analyzerName: 'containsCall',
                    analyzerOptions: {
                        parentName: 'eitherOnType',
                        methodName: 'isTypeOf'
                    }
                };

                return analyzer
                    .analyze(analyzerRefactorCallOptions)
                    .then(function ({ result }) {
                        if (!result) {
                            return analyzer
                                .analyze(analyzerCallOptions);
                        } else {
                            return Promise.resolve({ result: true });
                        }
                    })
                    .then(function ({ result }) {
                        assert.isTrue(result);
                    });
            });

            it('has a function called "eitherOnType" with parameters "type", "testValue", "defaultValue" -- return testValue if it matches type, otherwise return defaultValue', function () {
                const analyzerFunctionOptions = {
                    formNumber: 3,
                    analyzerName: 'containsFunction',
                    analyzerOptions: {
                        functionName: 'eitherOnType',
                        parameters: ['type', 'testValue', 'defaultValue']
                    }
                };

                return analyzer
                    .analyze(analyzerFunctionOptions)
                    .then(function ({ result }) {
                        assert.isTrue(result);
                    });
            });

            it('calls eitherOnType from greet', function () {
                const analyzerCallOptions = {
                    formNumber: 3,
                    analyzerName: 'containsCall',
                    analyzerOptions: {
                        parentName: 'greet',
                        methodName: 'eitherOnType'
                    }
                };

                return analyzer
                    .analyze(analyzerCallOptions)
                    .then(function ({ result }) {
                        assert.isTrue(result);
                    });
            });

        });

    });

    describe('square', function () {

        // Keep the tests passing!

        it('should square 1', function () {
            assert.equal(jsforms.square(1), 1);
        });

        it('should square 3', function () {
            assert.equal(jsforms.square(3), 9);
        });

    });

    describe('squareRoot', function () {

        // Keep the tests passing!

        it('should take the square root of 1', function () {
            assert.equal(jsforms.squareRoot(1), 1);
        });

        it('should take the square root of 4', function () {
            assert.equal(jsforms.squareRoot(4), 2);
        });

    });

    describe('sum', function () {

        it('should take the sum of one number', function () {
            assert.equal(jsforms.sum([1]), 1);
        });

        it('should add two numbers', function () {
            assert.equal(jsforms.sum([2, 3]), 5);
        });

        it('should add multiple numbers', function () {
            assert.equal(jsforms.sum([1, 3, 5, 7]), 16);
        });

        describe('Refactoring steps', function () {

            /*
            1 - Replace forEach with reduce -- assign calculated sum to "result" variable
            2 - Remove wrapping function from reduce -- pass add function directly to reduce
            3 - Remove assignment and return calculated result directly to caller
            */

            // Keep the tests passing!

            it('has been refactored to use reduce in the place of forEach, assigning the output to result', function () {
                const analyzerReduceOptions = {
                    formNumber: 3,
                    analyzerName: 'containsCall',
                    analyzerOptions: {
                        parentName: 'sum',
                        objectName: 'nums',
                        methodName: 'reduce'
                    }
                };

                const analyzerForEachOptions = {
                    formNumber: 3,
                    analyzerName: 'containsCall',
                    analyzerOptions: {
                        parentName: 'sum',
                        objectName: 'nums',
                        methodName: 'forEach'
                    }
                };

                return analyzer
                    .analyze(analyzerReduceOptions)
                    .then(function ({ result }) {
                        assert.isTrue(result, 'Reduce is not being used in the sum function.');
                        return analyzer
                            .analyze(analyzerForEachOptions);
                    })
                    .then(function ({ result }) {
                        assert.isFalse(result, 'ForEach is still being used in the sum function.')
                    });
            });

            it('has been refactored to pass the add function directly to reduce', function () {
                const analyzerReduceOptions = {
                    formNumber: 3,
                    analyzerName: 'containsCall',
                    analyzerOptions: {
                        parentName: 'sum',
                        objectName: 'nums',
                        methodName: 'reduce',
                        variableName: 'add'
                    }
                };

                return analyzer
                    .analyze(analyzerReduceOptions)
                    .then(function ({ result }) {
                        assert.isTrue(result, 'Add is not being passed directly to reduce, yet.');
                    });
            });

            it('has been refactored to not assign the sum before returning it', function () {
                const analyzerAssignmentOptions = {
                    formNumber: 3,
                    analyzerName: 'containsAssignment',
                    analyzerOptions: {
                        parentName: 'sum'
                    }
                };

                return analyzer
                    .analyze(analyzerAssignmentOptions)
                    .then(function ({ result }) {
                        assert.isFalse(result, 'Sum still contains an assignment. Is the reduced value being returned directly?');
                    });
            });

        });
    });

    describe('squareAll', function () {

        // Keep the tests passing!

        it('should square all numbers in a single-value array', function () {
            assert.equal(jsforms.squareAll([2]).toString(), '4');
        });

        it('should square multiple numbers', function () {
            assert.equal(jsforms.squareAll([1, 2, 3, 5]).toString(), '1,4,9,25');
        });

    });

    describe('sumOfSquares', function () {

        // Keep the tests passing!

        it('should square number in a 1-length array and return it', function () {
            assert.equal(jsforms.sumOfSquares([2]), 4);
        });

        it('should take the sum of squares of multiple numbers', function () {
            assert.equal(jsforms.sumOfSquares([1, 2, 3]), 14);
        });

    });

    describe('buildVector', function () {

        // Keep the tests passing!

        it('should return vector with valueOf function which does not return vector', function () {
            let vector = jsforms.buildVector([1, 2, 3]);

            assert.equal(vector.valueOf() !== vector, true);
        });

        it('should return a vector where toString returns a vector string', function () {
            let vector = jsforms.buildVector([1, 2, 3]);

            assert.equal(vector.toString(), '<1,2,3>');
        });

        describe('Getter properties and value immutability', function () {

            it('should have access to read, but not write, vector.points', function () {
                /*
                 * // Setting a getter on an object:
                 * Object.defineProperty(obj, key, {
                 *      get: () => value
                 * });
                 */

                const originalPoints = [1, 2, 3];

                let vector = jsforms.buildVector(originalPoints);

                assert.throws(() => vector.points = [4, 5, 6]);
            });

            it('should not change vector object when the original array is modified', function () {
                let originalArray = [1, 2, 3];
                let vector = jsforms.buildVector(originalArray);

                originalArray.push(4);

                assert.notEqual(vector.points.length, originalArray.length);
            });

            it('should not be possible to modify vector.points', function () {
                /*
                It's possible to disable modifying an object usig Object.freeze
                */
                let vector = jsforms.buildVector([1, 2, 3]);
                assert.throws(() => vector.points.push(4));
            });

        });

        describe('Constructor type check', function () {

            it('throws an error if constructor is called with a value which is not an array', function () {
                assert.throws(() => jsforms.buildVector('not an array'));
            });

            it('throws an error if constructor is called with an array of one value which is not a number', function () {
                assert.throws(() => jsforms.buildVector(['bad value']));
            });

            it('throws an error if constructor is called with an array which contains values other than numbers', function () {
                assert.throws(() => jsforms.buildVector([1, '2', 5, {}]));
            });

            describe('Refactoring steps', function () {
                it('has a function called "isArrayOfNumbers" with a parameter "values"', function () {
                    const analyzerFunction = {
                        formNumber: 3,
                        analyzerName: 'containsFunction',
                        analyzerOptions: {
                            functionName: 'isArrayOfNumbers',
                            parameters: ['values']
                        }
                    }

                    return analyzer
                        .analyze(analyzerFunction)
                        .then(function ({ result }) {
                            assert.isTrue(result, 'Cannot find a function  called "isArrayOfNumbers"');
                        });
                });

                it('has a call in Vector constructor to "isArrayOfNumbers" with "points" as an argument', function () {
                    const analyzerCallOptions = {
                        formNumber: 3,
                        analyzerName: 'containsCall',
                        analyzerOptions: {
                            parentName: 'Vector',
                            methodName: 'isArrayOfNumbers',
                            variableName: 'points'
                        }
                    };

                    return analyzer
                        .analyze(analyzerCallOptions)
                        .then(function ({ result }) {
                            assert.isTrue(result, 'Cannot find call to isArrayOfNumbers');
                        });
                });
            });

        });

    });

    describe('magnitude', function () {

        // Keep the tests passing!

        it('should return the magnitude of a one-value vector', function () {
            assert.equal(jsforms.magnitude([5]), 5);
        });

        it('should return only positive magnitude values', function () {
            assert.equal(jsforms.magnitude([-3]), 3);
        });

        it('should return the magnitude of a two-value vector', function () {
            assert.equal(jsforms.magnitude([6, 8]), 10);
        });

        it('should return the magnitude of a multi-value vector', function () {
            assert.equal(jsforms.magnitude([0, 12, 3, 4]), 13);
        });

    });

    describe('getVectorsShorterThan', function () {

        // Keep the tests passing!

        it('should return single vector when the only vector magnitude is acceptably short', function () {
            let vectors = [jsforms.buildVector([1, 2])];
            let result = jsforms.getVectorsShorterThan(5, vectors);

            assert.equal(result.length, 1);
            assert.equal(result[0].toString(), '<1,2>');
        });

        it('should return an empty array when the only vector magnitude is too long', function () {
            let length = 4;
            let vectors = [jsforms.buildVector([3, 4])];
            let result = jsforms.getVectorsShorterThan(length, vectors);

            assert.equal(result.length, 0)
        });

        it('should only filter vectors which are too long', function () {
            let length = 10;
            let vectors = [
                jsforms.buildVector([10, 10]),
                jsforms.buildVector([3, 4])
            ];

            let result = jsforms.getVectorsShorterThan(length, vectors);

            assert.equal(result.length, 1);
            assert.equal(result[0].toString(), '<3,4>');
        });

        it('should filter all vectors which are too long', function () {
            let vectors = [
                jsforms.buildVector([1, 2, 2]),
                jsforms.buildVector([10, 20]),
                jsforms.buildVector([3, 4]),
                jsforms.buildVector([1, 2, 10, 100])
            ];

            let result = jsforms.getVectorsShorterThan(10, vectors);

            let resultValues = [
                result[0].toString(),
                result[1].toString()
            ];

            assert.equal(resultValues.toString(), '<1,2,2>,<3,4>');
        });

    });

    // You're done!
    // Good job! I like what you got.

});

<|endoftext|>