<commit_before>var Express = require('express');
var express = Express();
var http = require('http');
var server = http.Server(express);
var WebSocket = require('ws');
var WebSocketServer = WebSocket.Server;
var exec = require('child_process').exec;
var fs = require('fs');

var viewAccountName = "elijahparker";
var CLIENT_SERVER_PORT = 80;
var CLIENT_WS_PORT = 8101;

var wss = new WebSocketServer({
    port: CLIENT_WS_PORT
});

var EventEmitter = require("events").EventEmitter;

var app = new EventEmitter();

express.use(Express.static('/home/view/current/frontend/www'));

express.get('/socket/address', function(req, res) {
    var host = req.headers.host;
    var domain = host.split(':')[0];
    res.send({
        address: 'ws://' + domain + ':' + CLIENT_WS_PORT,
        server: 'local'
    });
});

var viewId = null;

wss.broadcast = function broadcast(data) {
    wss.clients.forEach(function each(client) {
        //console.log("client:", client);
        try {
            if (client) client.send(data);
        } catch (err) {
            console.log("broadcast error:", err);
        }
    });
};

wss.on('connection', function connection(ws) {
    ws.on('message', function incoming(message) {
        //console.log('received: %s', message);
        receive_message(message, ws);
    });
});

app.remote = false;
app.authCode = null;
var wsRemote;
var remotePingHandle = null;

function connectRemote() {
    if (app.remote) return;
    wsRemote = new WebSocket('ws://incoming.view.tl/socket/device', {
        headers: {
            'x-view-id': viewId
        }
    });

    wsRemote.on('message', function incoming(message) {
        //if (message.type != "pong") console.log('remote: %s', message);
        if(app.remote) {
            receive_message(message, wsRemote);
        } else {
            try {
                var msg = JSON.parse(message);
                if(msg.connected) {
                    app.remote = true;
                    app.authCode = null;
                    app.emit('auth-complete', app.authCode);
                    console.log("Connected to view.tl");
                    remotePingHandle = setInterval(function() {
                        send_message('ping', null, wsRemote);
                    }, 10000);
                    sendLogs();
                } else if(msg.code) {
                    app.authCode = msg.code;
                    app.emit('auth-required', app.authCode);
                }
            } catch (err) {
                console.log("Error while parsing message:", message, err);
                return;
            }
        }
    });

    wsRemote.once('open', function() {
    });

    wsRemote.once('close', function() {
        if (remotePingHandle) clearInterval(remotePingHandle);
        remotePingHandle = null;
        console.log("Disconnected from view.tl");
        app.remote = false;
        setTimeout(connectRemote);
    });

    wsRemote.once('error', function() {
        if (remotePingHandle) clearInterval(remotePingHandle);
        remotePingHandle = null;
        //console.log("Error connecting to view.tl");
        app.remote = false;
        setTimeout(connectRemote, 15000);
    });
}

// get cpu serial number as unique id for view device
exec('cat /proc/cpuinfo', function(error, stdout, stderr) {
    lines = stdout.split('\n');
    for(var i = 0; i < lines.length; i++) {
        if(lines[i].indexOf('Serial') === 0) {
            var matches = lines[i].match(/: ([0-9a-f]+)/i);
            if(matches.length > 1) {
                viewId = matches[1];
                console.log("VIEW_ID:", viewId);
                connectRemote();
            }
        }
    }
});

function sendLog(logfile, logname, callback) {
    if(app.remote) {
        console.log("Reading", logfile);
        fs.readFile(logfile, function(err, file) {
            if(!err) {
                if(file) {
                    console.log("sending log file to proxy: ", logfile);
                    var obj = {
                        logname: logname,
                        bzip2: file.toString('base64')
                    }
                    send_message('log', obj, wsRemote, function(err2) {
                        callback(null);
                    });
                } else {
                    callback(null);
                }
            } else {
                console.log("error sending log: ", err);
                callback(null);
            }
        });
    } else {
        callback(true);
    }
}

function sendLogs() {
    if(app.remote) {
        console.log("Checking for logs to upload...");
        var logs = fs.readdirSync("/home/view/logsForUpload");
        logs = logs.filter(function(log) {
            return log.match(/^log/) ? true : false;
        });

        if(logs && logs.length > 0) {
            var nextLogName = logs.pop();
            var nextLog = "/home/view/logsForUpload/" + nextLogName;
            sendLog(nextLog, nextLogName, function(err) {
                if(!err) {
                    fs.unlink(nextLog, function() {
                        setTimeout(sendLogs, 120 * 1000);
                    });
                }
            });
        }
    }
}

function send_message(type, object, socket, callback) {
    if (!object) object = {};
    if (typeof(type) === "string") {
        object.type = type;
    } else if (typeof(type) === "object" && type.type) {
        object = type;
    }

    var msg_string;
    try {
        msg_string = JSON.stringify(object);
    } catch (err) {
        console.log("Error encoding data to send:", err);
        return;
    }
    try {
        if (socket) {
            socket.send(msg_string, callback);
        } else {
            wss.broadcast(msg_string);
            if (app.remote) wsRemote.send(msg_string);
        }
    } catch (err) {
        console.log("Error sending message:", err);
        return;
    }
}

function receive_message(msg_string, socket) {
    try {
    	var buildReply = function(nMsg, nSocket) {
    		return function(type, object) {
    			if(!object) object = {};
    			object.ack = nMsg.ack;
    			object._cbId = nMsg._cbId;

                send_message(type, object, nSocket);
    		}
    	}

        var msg = JSON.parse(msg_string);
        if (!msg || !msg.type) {
            throw "invalid message: no type set";
        } else if (msg.type == "ping") {
            send_message('pong', {}, socket);
        } else if (msg.type == "pong") {
            // ignoring...
        } else {
        	msg.reply = buildReply(msg, socket);
        	app.emit("message", msg);
        }
    } catch (err) {
        console.log("Error while parsing message:", msg_string, err);
        return;
    }
}

app.send = send_message;
app.sendLogs = sendLogs;

server.listen(CLIENT_SERVER_PORT, function() {
    console.log('listening on *:' + CLIENT_SERVER_PORT);
});

module.exports = app;<commit_msg>log compress error<commit_after>var Express = require('express');
var express = Express();
var http = require('http');
var server = http.Server(express);
var WebSocket = require('ws');
var WebSocketServer = WebSocket.Server;
var exec = require('child_process').exec;
var fs = require('fs');

var viewAccountName = "elijahparker";
var CLIENT_SERVER_PORT = 80;
var CLIENT_WS_PORT = 8101;

var wss = new WebSocketServer({
    port: CLIENT_WS_PORT
});

var EventEmitter = require("events").EventEmitter;

var app = new EventEmitter();

express.use(Express.static('/home/view/current/frontend/www'));

express.get('/socket/address', function(req, res) {
    var host = req.headers.host;
    var domain = host.split(':')[0];
    res.send({
        address: 'ws://' + domain + ':' + CLIENT_WS_PORT,
        server: 'local'
    });
});

var viewId = null;

wss.broadcast = function broadcast(data) {
    wss.clients.forEach(function each(client) {
        //console.log("client:", client);
        try {
            if (client) client.send(data);
        } catch (err) {
            console.log("broadcast error:", err);
        }
    });
};

wss.on('connection', function connection(ws) {
    ws.on('message', function incoming(message) {
        //console.log('received: %s', message);
        receive_message(message, ws);
    });
});

app.remote = false;
app.authCode = null;
var wsRemote;
var remotePingHandle = null;

function connectRemote() {
    if (app.remote) return;
    wsRemote = new WebSocket('ws://incoming.view.tl/socket/device', {
        headers: {
            'x-view-id': viewId
        }
    });

    wsRemote.on('message', function incoming(message) {
        //if (message.type != "pong") console.log('remote: %s', message);
        if(app.remote) {
            receive_message(message, wsRemote);
        } else {
            try {
                var msg = JSON.parse(message);
                if(msg.connected) {
                    app.remote = true;
                    app.authCode = null;
                    app.emit('auth-complete', app.authCode);
                    console.log("Connected to view.tl");
                    remotePingHandle = setInterval(function() {
                        send_message('ping', null, wsRemote);
                    }, 10000);
                    sendLogs();
                } else if(msg.code) {
                    app.authCode = msg.code;
                    app.emit('auth-required', app.authCode);
                }
            } catch (err) {
                console.log("Error while parsing message:", message, err);
                return;
            }
        }
    });

    wsRemote.once('open', function() {
    });

    wsRemote.once('close', function() {
        if (remotePingHandle) clearInterval(remotePingHandle);
        remotePingHandle = null;
        console.log("Disconnected from view.tl");
        app.remote = false;
        setTimeout(connectRemote);
    });

    wsRemote.once('error', function() {
        if (remotePingHandle) clearInterval(remotePingHandle);
        remotePingHandle = null;
        //console.log("Error connecting to view.tl");
        app.remote = false;
        setTimeout(connectRemote, 15000);
    });
}

// get cpu serial number as unique id for view device
exec('cat /proc/cpuinfo', function(error, stdout, stderr) {
    lines = stdout.split('\n');
    for(var i = 0; i < lines.length; i++) {
        if(lines[i].indexOf('Serial') === 0) {
            var matches = lines[i].match(/: ([0-9a-f]+)/i);
            if(matches.length > 1) {
                viewId = matches[1];
                console.log("VIEW_ID:", viewId);
                connectRemote();
            }
        }
    }
});

function sendLog(logfile, logname, callback) {
    if(app.remote) {
        console.log("Reading", logfile);
        fs.readFile(logfile, function(err, file) {
            if(!err) {
                if(file) {
                    console.log("sending log file to proxy: ", logfile);
                    var obj = {
                        logname: logname,
                        bzip2: file.toString('base64')
                    }
                    send_message('log', obj, wsRemote, function(err2) {
                        callback(null);
                    });
                } else {
                    callback(null);
                }
            } else {
                console.log("error sending log: ", err);
                callback(null);
            }
        });
    } else {
        callback(true);
    }
}

function sendLogs() {
    if(app.remote) {
        console.log("Checking for logs to upload...");
        var logs = fs.readdirSync("/home/view/logsForUpload");
        logs = logs.filter(function(log) {
            return log.match(/^(log|TL)/) ? true : false;
        });

        if(logs && logs.length > 0) {
            var nextLogName = logs.pop();
            var nextLog = "/home/view/logsForUpload/" + nextLogName;
            sendLog(nextLog, nextLogName, function(err) {
                if(!err) {
                    fs.unlink(nextLog, function() {
                        setTimeout(sendLogs, 120 * 1000);
                    });
                }
            });
        }
    }
}

function send_message(type, object, socket, callback) {
    if (!object) object = {};
    if (typeof(type) === "string") {
        object.type = type;
    } else if (typeof(type) === "object" && type.type) {
        object = type;
    }

    var msg_string;
    try {
        msg_string = JSON.stringify(object);
    } catch (err) {
        console.log("Error encoding data to send:", err);
        return;
    }
    try {
        if (socket) {
            socket.send(msg_string, callback);
        } else {
            wss.broadcast(msg_string);
            if (app.remote) wsRemote.send(msg_string);
        }
    } catch (err) {
        console.log("Error sending message:", err);
        return;
    }
}

function receive_message(msg_string, socket) {
    try {
    	var buildReply = function(nMsg, nSocket) {
    		return function(type, object) {
    			if(!object) object = {};
    			object.ack = nMsg.ack;
    			object._cbId = nMsg._cbId;

                send_message(type, object, nSocket);
    		}
    	}

        var msg = JSON.parse(msg_string);
        if (!msg || !msg.type) {
            throw "invalid message: no type set";
        } else if (msg.type == "ping") {
            send_message('pong', {}, socket);
        } else if (msg.type == "pong") {
            // ignoring...
        } else {
        	msg.reply = buildReply(msg, socket);
        	app.emit("message", msg);
        }
    } catch (err) {
        console.log("Error while parsing message:", msg_string, err);
        return;
    }
}

app.send = send_message;
app.sendLogs = sendLogs;

server.listen(CLIENT_SERVER_PORT, function() {
    console.log('listening on *:' + CLIENT_SERVER_PORT);
});

module.exports = app;<|endoftext|>


<commit_before>(function($){
	window.xeNotifyMessage = function(text, count){
		var $bar;
		$bar = $('div.message.info');
		if(!$bar.length) {
			$bar = $('
')
				.hide()
				.css({
					'position'   : 'absolute',
					'z-index' : '100',
				})
				.prependTo(document.body);
		}

		text = text.replace('%d', count);
		$bar.html('
'+text+'
').height();
		$bar.show().animate({top:0});
	};
})(jQuery);
<commit_msg>알림 메시지 클릭시 2초 후에 메세지 닫기<commit_after>(function($){
	var $bar;
	window.xeNotifyMessage = function(text, count){
		$bar = $('div.message.info');
		if(!$bar.length) {
			$bar = $('
')
				.hide()
				.css({
					'position'   : 'absolute',
					'z-index' : '100',
				})
				.prependTo(document.body);
		}

		text = text.replace('%d', count);
		$bar.html('
'+text+'
').height();
		$bar.show().animate({top:0});
	};

	window.xeNotifyMessageClose = function(){
		setTimeout(function(){
			$bar.slideUp();
		}, 2000);
	};
})(jQuery);
<|endoftext|>


<commit_before>(function (global) {

    // xxx common constants in a separate file
    var METAFUN        = 'metafun'
    ,   METARET        = 'metaret'
    ,   FUNCTION       = 'function'
    ,   RESERVED       = 'reserved'

    ,   CALL    = 'call'
    ,   DOTCALL = 'dotcall'

    ,   TYPE_BRACKET      = 'bracket'
    ,   TYPEBRACKET_CURLY = 'curly'
    ;

    // ---------- Public API

    global.lp2fmtree = lp2fmtree;

    // ---------- Public API implementation

    function lp2fmtree( lp, /*?array of string?*/namespace, /*?object?*/workspace )
    // Input:  object returned by lightparse.
    //
    // Output: array of function/metafun declaration trees.
    //
    // Comment:
    //
    // `lp2fmtree` is used by ./metaret.js to support local metafuns
    // e.g. `metafun b` in:
    //
    // {{{
    // metafun a(self) { metaret b; metafun b(self) { return 1; } }
    // }}}
    //
    // -> declares `a` and `a.b`.
    //
    // It would be equivalent to write at the top level:
    // {{{
    // metafun a(self) { metaret a.b; }
    // metafun a.b(self) { return 1; }
    // }}}
    //
    // For a longer example see `sortedSearch` in ./index.html
    //
    // Guillaume Lathoud
    // glathoud@yahoo.fr
    {
        var isTopLevel = arguments.length < 2;

        namespace  ||  (namespace = []);
        workspace  ||  (workspace = { iAnonymous : 0 });

        var at = lp  instanceof Array  ?  lp  :  lp.allTree
        ,  ret = []
        ;
        for (var n = at.length, i = 0; i < n; i++)
        {
            var one  = at[ i ];

            // Detect a named function/metafunction declaration,

            var isFunction     = one.name === FUNCTION
            ,   isMetafunction = one.name === METAFUN

            ,   isAnonymousFunction = isFunction  &&  at[ i+1 ].type === TYPE_BRACKET
            ;

            if (((isFunction  ||  isMetafunction)  &&  at[ i+1 ].type !== TYPE_BRACKET)  ||
                isAnonymousFunction)
            {
                var begin = one.begin
                ,   end

                ,   dot_arr = []
                ,   next
                ;
                if (isAnonymousFunction)
                {
                    // Give some identity
                    dot_arr = [ 'anonymous#' + (workspace.iAnonymous++) ];
                }
                else
                {
                    // Fetch the name of the function or metafunction.
                    // Dots are supported (subnamespace).
                    do {
                        next = at[ ++i ];
                        dot_arr.push( next.name );
                    } while (
                        next.type !== DOTCALL  &&  next.type !== CALL
                    )
                }

                var param_arr = (next = at[ ++i ]).sepSplit.map( strip_comment_and_space );

                while (next.type !== TYPE_BRACKET  ||  next.typebracket !== TYPEBRACKET_CURLY)
                    next = at[ ++i ];

                var body_node = next
                ,   end       = body_node.end
                ,   body      = body_node.str

                ,   fullname_arr = namespace.concat( dot_arr )
                ,   fullname     = fullname_arr.join( '.' )
                ,   lastname     = fullname_arr[ fullname_arr.length - 1 ]
                ;

                // Support for local metafunctions: look at the
                // metafuns and functions within the body.

                var children = next.children  ?  lp2fmtree( next.children, fullname_arr, workspace )  :  [];

                // Remove children code from the body.

                for (var j = children.length; j--;)
                {
                    var kid = children[ j ]
                    ,     a = kid.begin - body_node.begin
                    ,     b = kid.end   - body_node.begin
                    ;
                    if (!kid.isAnonymousFunction)
                        body = body.substring( 0, a ) + body.substring( a, b ).replace( /[\s\S]/g, ' ' ) + body.substring( b );
                }

                var out = { begin : begin
                            , end : end
                            , fullname_arr : fullname_arr
                            , lastname     : lastname
                            , isFunction     : isFunction
                            , isMetafunction : isMetafunction
                            , isAnonymousFunction : isAnonymousFunction
                            , body_node : body_node
                            , fm_node : one
                            , fullname : fullname
                            , param_arr : param_arr
                            , param_str : param_arr.join( ',' )
                            , body : body
                            , children : children
                          };

                ret.push( out );
            }
            else if (one.children)
            {
                // Useful to find functions e.g. within `(...)`:
                // `(function (global) { ... })(this);`
                ret.push.apply( ret, lp2fmtree( one.children, namespace, workspace ) );
            }
        }

        // When done with the tree, walk it from the top
        if (isTopLevel)
            find_out_who_declares_what( ret, [].concat( lp.vardeclArr ) );

        return ret;
    }

    function strip_comment_and_space( o )
    {
        return o.str.replace( /\/\*[\s\S]*?\*\//g, '' ).replace( /(^\s+|\s+$)/g, '' );
    }

    function find_out_who_declares_what( arr, vardeclArr )
    {
        var n = arr.length;

        // Depth first - this can change `vardeclArr`

        for (var i = 0; i < n; i++)
        {
            var one = arr[ i ]
            ,   c   = one.children
            ;
            if (c  &&  c.length)
                find_out_who_declares_what( c, vardeclArr );
        }

        // then breadth

        for (var i = 0; i < n; i++)
        {
            var one = arr[ i ]
            , begin = one.begin
            ,   end = one.end

            , one_vda = one.vardeclArr = []
            ;
            for (var j = vardeclArr.length; j--;)
            {
                var vd = vardeclArr[ j ];
                if (vd.end < begin)
                    break;

                if (vd.begin < end)
                    one_vda.unshift( vardeclArr.splice( j, 1 )[ 0 ] );
            }
        }
    }

}(this));
<commit_msg>convenience access lastname2fmarr<commit_after>(function (global) {

    // xxx common constants in a separate file
    var METAFUN        = 'metafun'
    ,   METARET        = 'metaret'
    ,   FUNCTION       = 'function'
    ,   RESERVED       = 'reserved'

    ,   CALL    = 'call'
    ,   DOTCALL = 'dotcall'

    ,   TYPE_BRACKET      = 'bracket'
    ,   TYPEBRACKET_CURLY = 'curly'
    ;

    // ---------- Public API

    global.lp2fmtree = lp2fmtree;

    // ---------- Public API implementation

    function lp2fmtree( lp, /*?array of string?*/namespace, /*?object?*/workspace )
    // Input:  object returned by lightparse.
    //
    // Output: array of function/metafun declaration trees.
    //
    // Comment:
    //
    // `lp2fmtree` is used by ./metaret.js to support local metafuns
    // e.g. `metafun b` in:
    //
    // {{{
    // metafun a(self) { metaret b; metafun b(self) { return 1; } }
    // }}}
    //
    // -> declares `a` and `a.b`.
    //
    // It would be equivalent to write at the top level:
    // {{{
    // metafun a(self) { metaret a.b; }
    // metafun a.b(self) { return 1; }
    // }}}
    //
    // For a longer example see `sortedSearch` in ./index.html
    //
    // Guillaume Lathoud
    // glathoud@yahoo.fr
    {
        var isTopLevel = arguments.length < 2;

        namespace  ||  (namespace = []);
        workspace  ||  (workspace = { iAnonymous : 0, lastname2fmarr : {} });

        var at = lp  instanceof Array  ?  lp  :  lp.allTree
        ,  ret = []
        ;
        if (isTopLevel)
            ret.lastname2fmarr = workspace.lastname2fmarr;  // Convenience access (mainly for ./inline.js)

        for (var n = at.length, i = 0; i < n; i++)
        {
            var one  = at[ i ];

            // Detect a named function/metafunction declaration,

            var isFunction     = one.name === FUNCTION
            ,   isMetafunction = one.name === METAFUN

            ,   isAnonymousFunction = isFunction  &&  at[ i+1 ].type === TYPE_BRACKET
            ;

            if (((isFunction  ||  isMetafunction)  &&  at[ i+1 ].type !== TYPE_BRACKET)  ||
                isAnonymousFunction)
            {
                var begin = one.begin
                ,   end

                ,   dot_arr = []
                ,   next
                ;
                if (isAnonymousFunction)
                {
                    // Give some identity
                    dot_arr = [ 'anonymous#' + (workspace.iAnonymous++) ];
                }
                else
                {
                    // Fetch the name of the function or metafunction.
                    // Dots are supported (subnamespace).
                    do {
                        next = at[ ++i ];
                        dot_arr.push( next.name );
                    } while (
                        next.type !== DOTCALL  &&  next.type !== CALL
                    )
                }

                var param_arr = (next = at[ ++i ]).sepSplit.map( strip_comment_and_space );

                while (next.type !== TYPE_BRACKET  ||  next.typebracket !== TYPEBRACKET_CURLY)
                    next = at[ ++i ];

                var body_node = next
                ,   end       = body_node.end
                ,   body      = body_node.str

                ,   fullname_arr = namespace.concat( dot_arr )
                ,   fullname     = fullname_arr.join( '.' )
                ,   lastname     = fullname_arr[ fullname_arr.length - 1 ]
                ;

                // Support for local metafunctions: look at the
                // metafuns and functions within the body.

                var children = next.children  ?  lp2fmtree( next.children, fullname_arr, workspace )  :  [];

                // Remove children code from the body.

                for (var j = children.length; j--;)
                {
                    var kid = children[ j ]
                    ,     a = kid.begin - body_node.begin
                    ,     b = kid.end   - body_node.begin
                    ;
                    if (!kid.isAnonymousFunction)
                        body = body.substring( 0, a ) + body.substring( a, b ).replace( /[\s\S]/g, ' ' ) + body.substring( b );
                }

                var out = { begin : begin
                            , end : end
                            , fullname_arr : fullname_arr
                            , lastname     : lastname
                            , isFunction     : isFunction
                            , isMetafunction : isMetafunction
                            , isAnonymousFunction : isAnonymousFunction
                            , body_node : body_node
                            , fm_node : one
                            , fullname : fullname
                            , param_arr : param_arr
                            , param_str : param_arr.join( ',' )
                            , body : body
                            , children : children
                          };

                ret.push( out );

                // Convenience access
                if (!isAnonymousFunction)
                {
                    (workspace.lastname2fmarr[ lastname ]  ||  (workspace.lastname2fmarr[ lastname ] = []))
                        .push( out )
                    ;
                }
            }
            else if (one.children)
            {
                // Useful to find functions e.g. within `(...)`:
                // `(function (global) { ... })(this);`
                ret.push.apply( ret, lp2fmtree( one.children, namespace, workspace ) );
            }
        }

        // When done with the tree, walk it from the top
        if (isTopLevel)
            find_out_who_declares_what( ret, [].concat( lp.vardeclArr ) );

        return ret;
    }

    function strip_comment_and_space( o )
    {
        return o.str.replace( /\/\*[\s\S]*?\*\//g, '' ).replace( /(^\s+|\s+$)/g, '' );
    }

    function find_out_who_declares_what( arr, vardeclArr )
    {
        var n = arr.length;

        // Depth first - this can change `vardeclArr`

        for (var i = 0; i < n; i++)
        {
            var one = arr[ i ]
            ,   c   = one.children
            ;
            if (c  &&  c.length)
                find_out_who_declares_what( c, vardeclArr );
        }

        // then breadth

        for (var i = 0; i < n; i++)
        {
            var one = arr[ i ]
            , begin = one.begin
            ,   end = one.end

            , one_vda = one.vardeclArr = []
            ;
            for (var j = vardeclArr.length; j--;)
            {
                var vd = vardeclArr[ j ];
                if (vd.end < begin)
                    break;

                if (vd.begin < end)
                    one_vda.unshift( vardeclArr.splice( j, 1 )[ 0 ] );
            }
        }
    }

}(this));
<|endoftext|>


<commit_before>'use strict';

var dashboardControllers = angular.module('dashboardControllers', []);
dashboardApp.controller('DashboardCtrl', ["$scope",
   function DashboardCtrl($scope) {

       // table data definitions
       $scope.ratesGrid = {rows: 'ratesRows', columns: 'ratesCols'};
       $scope.gaugesGrid = {rows: 'gaugesRows', columns: 'gaugesCols'};
       $scope.histNodesGrid = {rows: 'histNodesRows', columns: 'histCols'};
       $scope.histMergedGrid = {rows: 'histMergedRows', columns: 'histCols'};

       // reload data from stream
       var stream = new EventSource("statman/stream");
       stream.addEventListener("message", function (e) {
           $scope.$apply(function() {
               $scope.updateUI($.parseJSON(e.data));
           });
       }, false);

       //TODO: update only what needs to be updated!!!
       //TODO: replace underscore with angular module
       $scope.updateUI = function (data) {
           // general
           $scope.hostname = data.hostname;

           // rates
           var rates = $scope.getByType(data, "counter");
           var ratesNodes = $scope.getNodes(rates);
           $scope.ratesCols = $scope.getNodeColumns(ratesNodes);
           $scope.ratesRows = $scope.postProcessData(ratesNodes, rates);

           // gauges
           var gauges = $scope.getByType(data, "gauge");
           var gaugesNodes = $scope.getNodes(gauges);
           $scope.gaugesCols = $scope.getNodeColumns(gaugesNodes);
           $scope.gaugesRows = $scope.postProcessData(gaugesNodes, gauges);

           // merged and node histagrams
           var histograms = $scope.getByType(data, "histogram");
           $scope.histCols = $scope.getHistogramColumns();
           $scope.histNodesRows = $scope.postProcessNodesHistograms(histograms);
           $scope.histMergedRows = $scope.postProcessHistograms(histograms);;
       };

       // helpers
       $scope.postProcessData = function(nodes, data) {
           var grouped = _.groupBy(data, "key");
           var keys = _.keys(grouped).sort();
           var result = [];

            _.each(keys, function (key) {
                var row = new Object();
                row.key = key;
                _.each(nodes, function (node, i) {
                    var d = _.find(grouped[key], function (c) {
                        return c.node == node;
                    });
                    if(d) {
                        row["node" + i] = $scope.formatNumber(
                            (d.rate != undefined) ? d.rate : d.value
                        );
                    } else {
                        row["node" + i] = "";
                    }
                });
                result.push(row);
           });
           return result;
       };
       $scope.postProcessHistograms = function(data) {
           var histograms = _.filter(data, function (h) {
               return h.node instanceof Array
           });
           var grouped = _.groupBy(histograms, function (h) {
               return h.id;
           });
           var result = [];

           _.each(grouped, function (grouped, i) {
               result.push(
                   $scope.getHistogramRow(grouped[0].id, grouped)
               );
           });
           return result;
       };
       $scope.postProcessNodesHistograms = function(data) {
           var histograms = _.reject(data, function (h) {
               return h.node instanceof Array
           });
           var nodes = _.uniq(_.pluck(histograms, 'node')).sort();
           var result = [];

           _.each(nodes, function (node) {
               var grouped = _.groupBy(
                   _.filter(histograms, function (h) {
                       return h.node == node;
                   }),
                   function (h) { return h.id }
               );
               _.each(grouped, function (grouped, i) {
                   var label = (i == "null") ? node : node + i;
                   result.push(
                       $scope.getHistogramRow(label, grouped)
                   );
               });
           });
           return result;
       };
       $scope.getHistogramRow = function (label, grouped) {
           var row = new Object();
           row.label = label;
           row.items = [];
           _.each(grouped, function (group) {
               row.items.push({
                   "key":  group.key,
                   "rate": $scope.formatNumber(group.rate),
                   "observations": $scope.formatNumber(group.observations),
                   "mean": $scope.formatMs(group.mean),
                   "sd":   $scope.formatNumber(group.sd),
                   "p95":  $scope.formatMs(group.p95),
                   "p99":  $scope.formatMs(group.p99),
                   "max":  $scope.formatMs(group.max)
               });
           });
           return row;
       };

       // columns builders
       $scope.getNodeColumns = function(nodes) {
           var columns = [{label: 'Key', field: 'key'}];
           _.each(nodes, function(node, i) {
               columns.push({label: node,
                             field: "node" + i,
                             headerClass: "alignRight"
                            });
           });
           return columns;
       };
       $scope.getHistogramColumns = function() {
           return [{label: ""}, {label: ""},
                   {label: "Rate per second", headerClass: "alignRight"},
                   {label: "Observations", headerClass: "alignRight"},
                   {label: "Mean (ms)", headerClass: "alignRight"},
                   {label: "Standard deviation", headerClass: "alignRight"},
                   {label: "95th (ms)", headerClass: "alignRight"},
                   {label: "99th (ms)", headerClass: "alignRight"},
                   {label: "Max (ms)", headerClass: "alignRight"}
                  ];
       };

       // data helpers
       $scope.getByType = function (data, type) {
           return  _.filter(data.metrics, function (m) {
               return m.type == type
           });
       };
       $scope.getNodes = function (data) {
           return _.uniq(_.map(data, function (item) {
               if (item.node instanceof Array) {
                   return item.node.sort().join(",");
               }
               return item.node
           }))
       };

       // formatting helpers
       $scope.formatMs = function (value) {
           return numeral( (value / 1000).toFixed(4) ).format('0,0.0000');
       };
       $scope.formatNumber = function (value) {
           return numeral(value).format('0,0');
       };
   }
]);<commit_msg>Code cleanup<commit_after>'use strict';

var dashboardControllers = angular.module('dashboardControllers', []);
dashboardApp.controller('DashboardCtrl', ["$scope",
   function DashboardCtrl($scope) {

       // table data definitions
       $scope.ratesGrid = {rows: 'ratesRows', columns: 'ratesCols'};
       $scope.gaugesGrid = {rows: 'gaugesRows', columns: 'gaugesCols'};
       $scope.histNodesGrid = {rows: 'histNodesRows', columns: 'histCols'};
       $scope.histMergedGrid = {rows: 'histMergedRows', columns: 'histCols'};

       // reload data from stream
       var stream = new EventSource("statman/stream");
       stream.addEventListener("message", function (e) {
           $scope.$apply(function() {
               $scope.updateUI($.parseJSON(e.data));
           });
       }, false);

       //TODO: update only what needs to be updated!!!
       $scope.updateUI = function (data) {
           // general
           $scope.hostname = data.hostname;

           // rates
           var rates = $scope.getByType(data, "counter");
           var ratesNodes = $scope.getNodes(rates);
           $scope.ratesCols = $scope.getNodeColumns(ratesNodes);
           $scope.ratesRows = $scope.postProcessData(ratesNodes, rates);

           // gauges
           var gauges = $scope.getByType(data, "gauge");
           var gaugesNodes = $scope.getNodes(gauges);
           $scope.gaugesCols = $scope.getNodeColumns(gaugesNodes);
           $scope.gaugesRows = $scope.postProcessData(gaugesNodes, gauges);

           // merged and node histagrams
           var histograms = $scope.getByType(data, "histogram");
           $scope.histCols = $scope.getHistogramColumns();
           $scope.histNodesRows = $scope.postProcessNodesHistograms(histograms);
           $scope.histMergedRows = $scope.postProcessHistograms(histograms);;
       };

       // helpers
       $scope.postProcessData = function(nodes, data) {
           var grouped = _.groupBy(data, "key");
           var keys = _.keys(grouped).sort();
           var result = [];

            _.each(keys, function (key) {
                var row = new Object();
                row.key = key;
                _.each(nodes, function (node, i) {
                    var d = _.find(grouped[key], function (c) {
                        return c.node == node;
                    });
                    if(d) {
                        row["node" + i] = $scope.formatNumber(
                            (d.rate != undefined) ? d.rate : d.value
                        );
                    } else {
                        row["node" + i] = "";
                    }
                });
                result.push(row);
           });
           return result;
       };
       $scope.postProcessHistograms = function(data) {
           var histograms = _.filter(data, function (h) {
               return h.node instanceof Array
           });
           var grouped = _.groupBy(histograms, function (h) {
               return h.id;
           });
           var result = [];

           _.each(grouped, function (grouped, i) {
               result.push(
                   $scope.getHistogramRow(grouped[0].id, grouped)
               );
           });
           return result;
       };
       $scope.postProcessNodesHistograms = function(data) {
           var histograms = _.reject(data, function (h) {
               return h.node instanceof Array
           });
           var nodes = _.uniq(_.pluck(histograms, 'node')).sort();
           var result = [];

           _.each(nodes, function (node) {
               var grouped = _.groupBy(
                   _.filter(histograms, function (h) {
                       return h.node == node;
                   }),
                   function (h) { return h.id }
               );
               _.each(grouped, function (grouped, i) {
                   var label = (i == "null") ? node + "/unknown" : node + i;
                   result.push(
                       $scope.getHistogramRow(label, grouped)
                   );
               });
           });
           return result;
       };
       $scope.getHistogramRow = function (label, grouped) {
           var row = new Object();
           row.label = label;
           row.items = [];
           _.each(grouped, function (group) {
               row.items.push({
                   "key":  group.key,
                   "rate": $scope.formatNumber(group.rate),
                   "observations": $scope.formatNumber(group.observations),
                   "mean": $scope.formatMs(group.mean),
                   "sd":   $scope.formatNumber(group.sd),
                   "p95":  $scope.formatMs(group.p95),
                   "p99":  $scope.formatMs(group.p99),
                   "max":  $scope.formatMs(group.max)
               });
           });
           return row;
       };

       // columns builders
       $scope.getNodeColumns = function(nodes) {
           var columns = [{label: 'Key', field: 'key'}];
           _.each(nodes, function(node, i) {
               columns.push({label: node,
                             field: "node" + i,
                             headerClass: "alignRight"
                            });
           });
           return columns;
       };
       $scope.getHistogramColumns = function() {
           return [{label: ""}, {label: ""},
                   {label: "Rate per second", headerClass: "alignRight"},
                   {label: "Observations",    headerClass: "alignRight"},
                   {label: "Mean (ms)",       headerClass: "alignRight"},
                   {label: "Standard deviation", headerClass: "alignRight"},
                   {label: "95th (ms)",       headerClass: "alignRight"},
                   {label: "99th (ms)",       headerClass: "alignRight"},
                   {label: "Max (ms)",        headerClass: "alignRight"}
                  ];
       };

       // data helpers
       $scope.getByType = function (data, type) {
           return  _.filter(data.metrics, function (m) {
               return m.type == type
           });
       };
       $scope.getNodes = function (data) {
           return _.uniq(_.map(data, function (item) {
               if (item.node instanceof Array) {
                   return item.node.sort().join(",");
               }
               return item.node
           }))
       };

       // formatting helpers
       $scope.formatMs = function (value) {
           return numeral( (value / 1000).toFixed(4) ).format('0,0.0000');
       };
       $scope.formatNumber = function (value) {
           return numeral(value).format('0,0');
       };
   }
]);<|endoftext|>


<commit_before>const express = require('express');

const router = express.Router();
const api = require('../api');

const { CONSENT_WITHOUT_PARENTS_MIN_AGE_YEARS } = require('../config/consent');
const setTheme = require('../helpers/theme');

let invalid = false;

const resetThemeForPrivacyDocuments = async (req, res) => {
	res.locals.currentSchoolData = await api(req).get(`registrationSchool/${req.params.classOrSchoolId}`);
	setTheme(res);
};

const checkValidRegistration = async (req) => {
	if (req.query.importHash) {
		const existingUser = await api(req).get(`/users/linkImport/${req.query.importHash}`);
		if (!existingUser.userId) {
			return true;
		}
	}
	return false;
};

/*
 * Warnings for users who wan't to use the old register version if not teacher
 */
router.get(['/register', '/register/*'], (req, res, next) => res.render('registration/deprecated_warning'));

/*
 * EzD Dataprivacy Routes
 */
router.post('/registration/pincreation', (req, res, next) => {
	if (req.body && req.body.email) {
		return api(req).post('/registrationPins/', {
			json: {
				email: req.body.email,
				mailTextForRole: req.body.mailTextForRole,
			},
		}).then((result) => {
			res.sendStatus((result || {}).status || 200);
		}).catch(err => res.status(500).send(err));
	}
	return res.sendStatus(500);
});

router.post(['/registration/submit', '/registration/submit/:sso/:accountId'], (req, res, next) => {
	// normalize form data
	req.body.roles = Array.isArray(req.body.roles) ? req.body.roles : [req.body.roles];

	return api(req)
		.post('/registration/', {
			json: req.body,
		})
		.then((response) => {
			const eMailAdresses = [response.user.email];
			if (response.parent) {
				eMailAdresses.push(response.parent.email);
			}
			eMailAdresses.forEach((eMailAdress) => {
				let passwordText = '';
				let studentInfotext = '';
				if (req.body.roles.includes('student')) {
					passwordText = `Startpasswort: ${req.body.password_1}`;
					studentInfotext = `Für Schüler: Nach dem ersten Login musst du ein persönliches Passwort festlegen.
Wenn du zwischen 14 und ${CONSENT_WITHOUT_PARENTS_MIN_AGE_YEARS} Jahre alt bist,
bestätige bitte zusätzlich die Einverständniserklärung,
damit du die ${res.locals.theme.short_title} nutzen kannst.`;
				}
				return api(req).post('/mails/', {
					json: {
						email: eMailAdress,
						subject: `Willkommen in der ${res.locals.theme.title}!`,
						headers: {},
						content: {
							text: `Hallo ${response.user.firstName}
mit folgenden Anmeldedaten kannst du dich in der ${res.locals.theme.title} einloggen:
Adresse: ${req.headers.origin || process.env.HOST}
E-Mail: ${response.user.email}
${passwordText}
${studentInfotext}
Viel Spaß und einen guten Start wünscht dir dein
${res.locals.theme.short_title}-Team`,
						},
					},
				});
			});
		})
		.then(() => {
			if (req.params.sso) {
				res.cookie(
					'jwt',
					req.cookies.jwt,
					{
						expires: new Date(Date.now() - 100000),
						httpOnly: false,
						hostOnly: true,
						secure: process.env.NODE_ENV === 'production',
					},
				);
			}
		})
		.then(() => {
			res.sendStatus(200);
		})
		.catch((err) => {
			let message = 'Ein unbekannter Fehler ist aufgetreten. Bitte versuche es erneut.'
			const customMessage = (err.error || {}).message || err.message;
			if (customMessage) { message = customMessage; }
			if (err && err.code) {
				if (err.code === 'ESOCKETTIMEDOUT') {
					message = 'Leider konnte deine Registrierung nicht abgeschlossen werden (Timeout). Bitte versuche es erneut.'
				}
			}
			return res.status(500).send(message);
		});
});

router.get(['/registration/:classOrSchoolId/byparent', '/registration/:classOrSchoolId/byparent/:sso/:accountId'],
	async (req, res, next) => {
		if (!RegExp('^[0-9a-fA-F]{24}$').test(req.params.classOrSchoolId)) {
			if (req.params.sso && !RegExp('^[0-9a-fA-F]{24}$').test(req.params.accountId)) {
				return res.sendStatus(400);
			}
		}

		const user = {};
		user.importHash = req.query.importHash;
		user.classOrSchoolId = req.params.classOrSchoolId;
		user.sso = req.params.sso === 'sso';
		user.account = req.params.accountId || '';

		invalid = await checkValidRegistration(req);

		await resetThemeForPrivacyDocuments(req, res);

		if (user.importHash) {
			const existingUser = await api(req).get(`/users/linkImport/${user.importHash}`);
			Object.assign(user, existingUser);
		}
		return res.render('registration/registration-parent', {
			title: 'Registrierung - Eltern',
			hideMenu: true,
			user,
			CONSENT_WITHOUT_PARENTS_MIN_AGE_YEARS,
			invalid,
		});
	});

router.get(['/registration/:classOrSchoolId/bystudent', '/registration/:classOrSchoolId/bystudent/:sso/:accountId'],
	async (req, res, next) => {
		if (!RegExp('^[0-9a-fA-F]{24}$').test(req.params.classOrSchoolId)) {
			if (req.params.sso && !RegExp('^[0-9a-fA-F]{24}$').test(req.params.accountId)) {
				return res.sendStatus(400);
			}
		}

		const user = {};
		user.importHash = req.query.importHash;
		user.classOrSchoolId = req.params.classOrSchoolId;
		user.sso = req.params.sso === 'sso';
		user.account = req.params.accountId || '';

		invalid = await checkValidRegistration(req);

		await resetThemeForPrivacyDocuments(req, res);

		if (user.importHash) {
			const existingUser = await api(req).get(`/users/linkImport/${user.importHash}`);
			Object.assign(user, existingUser);
		}

		return res.render('registration/registration-student', {
			title: 'Registrierung - Schüler*',
			hideMenu: true,
			user,
			CONSENT_WITHOUT_PARENTS_MIN_AGE_YEARS,
			invalid,
		});
	});

router.get(['/registration/:classOrSchoolId/:byRole'], async (req, res, next) => {
	if (!RegExp('^[0-9a-fA-F]{24}$').test(req.params.classOrSchoolId)) {
		if (req.params.sso && !RegExp('^[0-9a-fA-F]{24}$').test(req.params.accountId)) {
			return res.sendStatus(400);
		}
	}

	const user = {};
	user.importHash = req.query.importHash || req.query.id; // req.query.id is deprecated
	user.classOrSchoolId = req.params.classOrSchoolId;

	invalid = await checkValidRegistration(req);

	await resetThemeForPrivacyDocuments(req, res);

	if (user.importHash) {
		const existingUser = await api(req).get(`/users/linkImport/${user.importHash}`);
		Object.assign(user, existingUser);
	}

	let roleText;
	if (req.params.byRole === 'byemployee') {
		roleText = 'Lehrer*/Admins*';
	} else {
		delete user.firstName;
		delete user.lastName;
		roleText = 'Experte*';
	}

	return res.render('registration/registration-employee', {
		title: `Registrierung - ${roleText}`,
		hideMenu: true,
		user,
		invalid,
	});
});

router.get(
	['/registration/:classOrSchoolId', '/registration/:classOrSchoolId/:sso/:accountId'],
	async (req, res, next) => {
		if (!RegExp('^[0-9a-fA-F]{24}$').test(req.params.classOrSchoolId)) {
			if (req.params.sso && !RegExp('^[0-9a-fA-F]{24}$').test(req.params.accountId)) {
				return res.sendStatus(400);
			}
		}

		invalid = await checkValidRegistration(req);

		await resetThemeForPrivacyDocuments(req, res);

		return res.render('registration/registration', {
			title: 'Herzlich willkommen bei der Registrierung',
			hideMenu: true,
			importHash: req.query.importHash || req.query.id, // req.query.id is deprecated
			classOrSchoolId: req.params.classOrSchoolId,
			sso: req.params.sso === 'sso',
			account: req.params.accountId || '',
			CONSENT_WITHOUT_PARENTS_MIN_AGE_YEARS,
			invalid,
		});
	},
);

module.exports = router;
<commit_msg>Update controllers/registration.js<commit_after>const express = require('express');

const router = express.Router();
const api = require('../api');

const { CONSENT_WITHOUT_PARENTS_MIN_AGE_YEARS } = require('../config/consent');
const setTheme = require('../helpers/theme');

let invalid = false;

const resetThemeForPrivacyDocuments = async (req, res) => {
	res.locals.currentSchoolData = await api(req).get(`registrationSchool/${req.params.classOrSchoolId}`);
	setTheme(res);
};

const checkValidRegistration = async (req) => {
	if (req.query.importHash) {
		const existingUser = await api(req).get(`/users/linkImport/${req.query.importHash}`);
		if (!existingUser.userId) {
			return true;
		}
	}
	return false;
};

/*
 * Warnings for users who wan't to use the old register version if not teacher
 */
router.get(['/register', '/register/*'], (req, res, next) => res.render('registration/deprecated_warning'));

/*
 * EzD Dataprivacy Routes
 */
router.post('/registration/pincreation', (req, res, next) => {
	if (req.body && req.body.email) {
		return api(req).post('/registrationPins/', {
			json: {
				email: req.body.email,
				mailTextForRole: req.body.mailTextForRole,
			},
		}).then((result) => {
			res.sendStatus((result || {}).status || 200);
		}).catch(err => res.status(500).send(err));
	}
	return res.sendStatus(500);
});

router.post(['/registration/submit', '/registration/submit/:sso/:accountId'], (req, res, next) => {
	// normalize form data
	req.body.roles = Array.isArray(req.body.roles) ? req.body.roles : [req.body.roles];

	return api(req)
		.post('/registration/', {
			json: req.body,
		})
		.then((response) => {
			const eMailAdresses = [response.user.email];
			if (response.parent) {
				eMailAdresses.push(response.parent.email);
			}
			eMailAdresses.forEach((eMailAdress) => {
				let passwordText = '';
				let studentInfotext = '';
				if (req.body.roles.includes('student')) {
					passwordText = `Startpasswort: ${req.body.password_1}`;
					studentInfotext = `Für Schüler: Nach dem ersten Login musst du ein persönliches Passwort festlegen.
Wenn du zwischen 14 und ${CONSENT_WITHOUT_PARENTS_MIN_AGE_YEARS} Jahre alt bist,
bestätige bitte zusätzlich die Einverständniserklärung,
damit du die ${res.locals.theme.short_title} nutzen kannst.`;
				}
				return api(req).post('/mails/', {
					json: {
						email: eMailAdress,
						subject: `Willkommen in der ${res.locals.theme.title}!`,
						headers: {},
						content: {
							text: `Hallo ${response.user.firstName}
mit folgenden Anmeldedaten kannst du dich in der ${res.locals.theme.title} einloggen:
Adresse: ${req.headers.origin || process.env.HOST}
E-Mail: ${response.user.email}
${passwordText}
${studentInfotext}
Viel Spaß und einen guten Start wünscht dir dein
${res.locals.theme.short_title}-Team`,
						},
					},
				});
			});
		})
		.then(() => {
			if (req.params.sso) {
				res.cookie(
					'jwt',
					req.cookies.jwt,
					{
						expires: new Date(Date.now() - 100000),
						httpOnly: false,
						hostOnly: true,
						secure: process.env.NODE_ENV === 'production',
					},
				);
			}
		})
		.then(() => {
			res.sendStatus(200);
		})
		.catch((err) => {
			let message = 'Hoppla, ein unbekannter Fehler ist aufgetreten. Bitte versuche es erneut.'
			const customMessage = (err.error || {}).message || err.message;
			if (customMessage) { message = customMessage; }
			if (err && err.code) {
				if (err.code === 'ESOCKETTIMEDOUT') {
					message = 'Leider konnte deine Registrierung nicht abgeschlossen werden (Timeout). Bitte versuche es erneut.'
				}
			}
			return res.status(500).send(message);
		});
});

router.get(['/registration/:classOrSchoolId/byparent', '/registration/:classOrSchoolId/byparent/:sso/:accountId'],
	async (req, res, next) => {
		if (!RegExp('^[0-9a-fA-F]{24}$').test(req.params.classOrSchoolId)) {
			if (req.params.sso && !RegExp('^[0-9a-fA-F]{24}$').test(req.params.accountId)) {
				return res.sendStatus(400);
			}
		}

		const user = {};
		user.importHash = req.query.importHash;
		user.classOrSchoolId = req.params.classOrSchoolId;
		user.sso = req.params.sso === 'sso';
		user.account = req.params.accountId || '';

		invalid = await checkValidRegistration(req);

		await resetThemeForPrivacyDocuments(req, res);

		if (user.importHash) {
			const existingUser = await api(req).get(`/users/linkImport/${user.importHash}`);
			Object.assign(user, existingUser);
		}
		return res.render('registration/registration-parent', {
			title: 'Registrierung - Eltern',
			hideMenu: true,
			user,
			CONSENT_WITHOUT_PARENTS_MIN_AGE_YEARS,
			invalid,
		});
	});

router.get(['/registration/:classOrSchoolId/bystudent', '/registration/:classOrSchoolId/bystudent/:sso/:accountId'],
	async (req, res, next) => {
		if (!RegExp('^[0-9a-fA-F]{24}$').test(req.params.classOrSchoolId)) {
			if (req.params.sso && !RegExp('^[0-9a-fA-F]{24}$').test(req.params.accountId)) {
				return res.sendStatus(400);
			}
		}

		const user = {};
		user.importHash = req.query.importHash;
		user.classOrSchoolId = req.params.classOrSchoolId;
		user.sso = req.params.sso === 'sso';
		user.account = req.params.accountId || '';

		invalid = await checkValidRegistration(req);

		await resetThemeForPrivacyDocuments(req, res);

		if (user.importHash) {
			const existingUser = await api(req).get(`/users/linkImport/${user.importHash}`);
			Object.assign(user, existingUser);
		}

		return res.render('registration/registration-student', {
			title: 'Registrierung - Schüler*',
			hideMenu: true,
			user,
			CONSENT_WITHOUT_PARENTS_MIN_AGE_YEARS,
			invalid,
		});
	});

router.get(['/registration/:classOrSchoolId/:byRole'], async (req, res, next) => {
	if (!RegExp('^[0-9a-fA-F]{24}$').test(req.params.classOrSchoolId)) {
		if (req.params.sso && !RegExp('^[0-9a-fA-F]{24}$').test(req.params.accountId)) {
			return res.sendStatus(400);
		}
	}

	const user = {};
	user.importHash = req.query.importHash || req.query.id; // req.query.id is deprecated
	user.classOrSchoolId = req.params.classOrSchoolId;

	invalid = await checkValidRegistration(req);

	await resetThemeForPrivacyDocuments(req, res);

	if (user.importHash) {
		const existingUser = await api(req).get(`/users/linkImport/${user.importHash}`);
		Object.assign(user, existingUser);
	}

	let roleText;
	if (req.params.byRole === 'byemployee') {
		roleText = 'Lehrer*/Admins*';
	} else {
		delete user.firstName;
		delete user.lastName;
		roleText = 'Experte*';
	}

	return res.render('registration/registration-employee', {
		title: `Registrierung - ${roleText}`,
		hideMenu: true,
		user,
		invalid,
	});
});

router.get(
	['/registration/:classOrSchoolId', '/registration/:classOrSchoolId/:sso/:accountId'],
	async (req, res, next) => {
		if (!RegExp('^[0-9a-fA-F]{24}$').test(req.params.classOrSchoolId)) {
			if (req.params.sso && !RegExp('^[0-9a-fA-F]{24}$').test(req.params.accountId)) {
				return res.sendStatus(400);
			}
		}

		invalid = await checkValidRegistration(req);

		await resetThemeForPrivacyDocuments(req, res);

		return res.render('registration/registration', {
			title: 'Herzlich willkommen bei der Registrierung',
			hideMenu: true,
			importHash: req.query.importHash || req.query.id, // req.query.id is deprecated
			classOrSchoolId: req.params.classOrSchoolId,
			sso: req.params.sso === 'sso',
			account: req.params.accountId || '',
			CONSENT_WITHOUT_PARENTS_MIN_AGE_YEARS,
			invalid,
		});
	},
);

module.exports = router;
<|endoftext|>


<commit_before>var e = module.exports = {};

e.init = () => {
    e.category = bu.CommandType.ADMIN;
};

e.requireCtx = require;

e.isCommand = true;
e.hidden = false;
e.usage = 'settings [keys|help|set <key>]';
e.info = 'Gets or sets the settings for the current guild. Visit https://blargbot.xyz/commands/settings for key documentation.';
e.longinfo = '
Gets or sets the settings for the current guild. For key documentation, go here.
';

e.execute = async function(msg, words) {
    if (words.length == 1) {
        //do settings shit
        let storedGuild = await bu.getGuild(msg.guild.id);
        let settings = storedGuild.settings;
        let channels = storedGuild.channels;

        var nsfw = [];
        var blacklisted = [];
        var i;
        for (let channel in channels) {
            if (channels[channel].nsfw) nsfw.push(channel);
            if (channels[channel].blacklisted) blacklisted.push(channel);
        }
        var prefix = settings.prefix ?
            settings.prefix : 'Not Set';
        var nsfwMessage = 'None Set';
        if (nsfw.length > 0) {
            nsfwMessage = '';
            for (i = 0; i < nsfw.length; i++) {
                let channel = bot.getChannel(nsfw[i]);
                if (channel)
                    nsfwMessage += `${channel.name} (${nsfw[i]})\n                - `;
            }
            nsfwMessage = nsfwMessage.substring(0, nsfwMessage.length - 19);
        }
        var blacklistMessage = 'None Set';
        if (blacklisted.length > 0) {
            blacklistMessage = '';
            for (i = 0; i < blacklisted.length; i++) {
                let channel = bot.getChannel(blacklisted[i]);
                if (channel)
                    blacklistMessage += `${channel.name} (${blacklisted[i]})\n                - `;
            }
            blacklistMessage = blacklistMessage.substring(0, blacklistMessage.length - 19);
        }
        var greeting = settings.greeting ?
            settings.greeting : 'Not Set';
        var farewell = settings.farewell ?
            settings.farewell : 'Not Set';
        var modlogChannel;
        if (settings.modlog) {
            let channel = bot.getChannel(settings.modlog);
            if (channel)
                modlogChannel = `${channel.name} (${settings.modlog})`;
            else
                modlogChannel = `Channel Not Found (${settings.modlog})`;
        } else {
            modlogChannel = 'Not Set';
        }
        var deleteNotif = settings.deletenotif != 0 ? true : false;
        var cahNsfw = settings.cahnsfw && settings.cahnsfw != 0 ? true : false;
        var mutedRole = settings.mutedrole ? settings.mutedrole : 'Not Set';
        var tableFlip = settings.tableflip && settings.tableflip != 0 ? true : false;
        var parsedAntiMention;
        if (settings.antimention) {
            parsedAntiMention = parseInt(settings.antimention);
            if (parsedAntiMention == 0 || isNaN(parsedAntiMention)) {
                parsedAntiMention = 'Disabled';
            }
        } else {
            parsedAntiMention = 'Disabled';
        }
        var antiMention = parsedAntiMention;
        let permOverride = settings.permoverride && settings.permoverride != 0 ? true : false;
        let dmHelp = settings.dmhelp && settings.dmhelp != 0 ? true : false;
        let makeLogs = settings.makelogs && settings.makelogs != 0 ? true : false;

        let staffPerms = settings.staffperms || bu.defaultStaff;
        let kickPerms = settings.kickoverride || 0;
        let banPerms = settings.banoverride || 0;
        let greetChan = settings.greetchan ? bot.getChannel(settings.greetchan) : 'Default';
        if (greetChan && greetChan != 'Default') greetChan = greetChan.name;
        else greetChan = 'Undefined';
        let farewellChan = settings.farewellchan ? bot.getChannel(settings.farewellchan) : 'Default';
        if (farewellChan && farewellChan != 'Default') farewellChan = farewellChan.name;
        else farewellChan = 'Undefined';
        let kickAt = settings.kickat || 'Disabled';
        let banAt = settings.banat || 'Disabled';
        var message = `\`\`\`prolog
Settings For ${msg.channel.guild.name}

-- General --
          Prefix : ${prefix}
     CAH is NSFW : ${cahNsfw}
         DM Help : ${dmHelp}

-- Messages --
        Greeting : ${greeting}
        Farewell : ${farewell}
      Tableflips : ${tableFlip}

-- Channels --
Farewell Channel : ${farewellChan}
Greeting Channel : ${greetChan}
   NSFW Channels : ${nsfwMessage}
  Modlog Channel : ${modlogChannel}
     Blacklisted : ${blacklistMessage}

-- Moderation --
       Chat Logs : ${makeLogs}
    Anti-Mention : ${antiMention}
      Muted Role : ${mutedRole}
   Track Deletes : ${deleteNotif}

-- Permissions --
   Perm Override : ${permOverride}
     Staff Perms : ${staffPerms}
   Kick Override : ${kickPerms}
    Ban Override : ${banPerms}

-- Warnings --
         Kick At : ${kickAt}
          Ban At : ${banAt}
\`\`\``;
        bu.send(msg, message);
    } else {
        words.shift();
        var key;
        switch (words[0].toLowerCase()) {
            case 'keys':
                let message = '\nYou can use \`settings set <key> [value]\` to set the following settings. All settings are case insensitive.\n';
                for (key in bu.settings) {
                    message += ' - **' + key.toUpperCase() + '** (' + bu.settings[key].type + ')\n';
                }
                bu.send(msg, message);
                break;
            case 'help':
                bu.send(msg, e.info);
                break;
            case 'set':
                words.shift();
            default:
                if (words.length > 0) {
                    key = words.shift();
                    let value = words.join(' ');
                    if (bu.settings[key]) {
                        let res = await bu.guildSettings.set(msg.channel.guild.id, key, value, bu.settings[key].type);
                        if (res == true)
                            bu.send(msg, ':ok_hand:');
                        else {
                            bu.send(msg, `Failed to set: ${res}`);
                        };
                    } else {
                        bu.send(msg, 'Invalid key!');
                    }
                }
                break;
        }
    }
};

bu.settings = {
    makelogs: {
        name: 'Make Chatlogs',
        desc: `Whether to record chat logs or not.`,
        type: 'bool'
    },
    cahnsfw: {
        name: 'Is CAH NSFW',
        desc: `Whether 'cah' can only be done in nsfw channels or not.`,
        type: 'bool'
    },
    deletenotif: {
        name: 'Delete Notifications',
        desc: `If enabled, notifies you if a user deleted their command.`,
        type: 'bool'
    },
    greeting: {
        name: 'Greeting Message',
        desc: `What to say to new users when they join. You can also use the <code>greet</code> command`,
        type: 'string'
    },
    farewell: {
        name: 'Farewell Message',
        desc: `What to say when a user leaves. You can also use the <code>farewell</code> command`,
        type: 'string'
    },
    prefix: {
        name: 'Custom Prefix',
        desc: `The custom command prefix. You can also use the <code>setprefix</code> command`,
        type: 'string'
    },
    modlog: {
        name: 'Modlog Channel',
        desc: `The id of the modlog channel. You can also use the <code>modlog</code> command`,
        type: 'string'
    },
    mutedrole: {
        name: 'Muted Role',
        desc: `The id of the muted role.`,
        type: 'string'
    },
    tableflip: {
        name: 'Tableflips',
        desc: `Whether the bot should respond to tableflips/unflips.`,
        type: 'bool'
    },
    antimention: {
        name: 'Anti-Mention',
        desc: `The number of unique mentions required to warrant a ban (for anti-mention spam). Set to '0' to disable. Recommended: 25`,
        type: 'int'
    },
    dmhelp: {
        name: 'DM Help',
        desc: `Whether or not to dm help messages or output them in channels`,
        type: 'bool'
    },
    permoverride: {
        name: 'Permission Override',
        desc: `Whether or not specific permissions override role requirement`,
        type: 'bool'
    },
    staffperms: {
        name: 'Staff Permissions',
        desc: `The numeric value of permissions that designate a staff member. If a user has any of the permissions and permoverride is enabled, allows them to execute any command regardless of role. See here for a permission calculator.`,
        type: 'int'
    },
    kickoverride: {
        name: 'Kick Override',
        desc: `Same as staffperms, but allows users to use the kick command regardless of permissions`,
        type: 'int'
    },
    banoverride: {
        name: 'Ban Override',
        desc: `Same as staffperms, but allows users to use the ban/hackban/unban commands regardless of permissions`,
        type: 'int'
    },
    banat: {
        name: 'Ban At',
        desc: 'The number of warnings before a ban. Set to 0 or below to disable.',
        type: 'int'
    },
    kickat: {
        name: 'Kick At',
        desc: 'The number of warnings before a kick. Set to 0 or below to disable.',
        type: 'int'
    }
};<commit_msg>make keys case-insensitive<commit_after>var e = module.exports = {};

e.init = () => {
    e.category = bu.CommandType.ADMIN;
};

e.requireCtx = require;

e.isCommand = true;
e.hidden = false;
e.usage = 'settings [keys|help|set <key>]';
e.info = 'Gets or sets the settings for the current guild. Visit https://blargbot.xyz/commands/settings for key documentation.';
e.longinfo = '
Gets or sets the settings for the current guild. For key documentation, go here.
';

e.execute = async function(msg, words) {
    if (words.length == 1) {
        //do settings shit
        let storedGuild = await bu.getGuild(msg.guild.id);
        let settings = storedGuild.settings;
        let channels = storedGuild.channels;

        var nsfw = [];
        var blacklisted = [];
        var i;
        for (let channel in channels) {
            if (channels[channel].nsfw) nsfw.push(channel);
            if (channels[channel].blacklisted) blacklisted.push(channel);
        }
        var prefix = settings.prefix ?
            settings.prefix : 'Not Set';
        var nsfwMessage = 'None Set';
        if (nsfw.length > 0) {
            nsfwMessage = '';
            for (i = 0; i < nsfw.length; i++) {
                let channel = bot.getChannel(nsfw[i]);
                if (channel)
                    nsfwMessage += `${channel.name} (${nsfw[i]})\n                - `;
            }
            nsfwMessage = nsfwMessage.substring(0, nsfwMessage.length - 19);
        }
        var blacklistMessage = 'None Set';
        if (blacklisted.length > 0) {
            blacklistMessage = '';
            for (i = 0; i < blacklisted.length; i++) {
                let channel = bot.getChannel(blacklisted[i]);
                if (channel)
                    blacklistMessage += `${channel.name} (${blacklisted[i]})\n                - `;
            }
            blacklistMessage = blacklistMessage.substring(0, blacklistMessage.length - 19);
        }
        var greeting = settings.greeting ?
            settings.greeting : 'Not Set';
        var farewell = settings.farewell ?
            settings.farewell : 'Not Set';
        var modlogChannel;
        if (settings.modlog) {
            let channel = bot.getChannel(settings.modlog);
            if (channel)
                modlogChannel = `${channel.name} (${settings.modlog})`;
            else
                modlogChannel = `Channel Not Found (${settings.modlog})`;
        } else {
            modlogChannel = 'Not Set';
        }
        var deleteNotif = settings.deletenotif != 0 ? true : false;
        var cahNsfw = settings.cahnsfw && settings.cahnsfw != 0 ? true : false;
        var mutedRole = settings.mutedrole ? settings.mutedrole : 'Not Set';
        var tableFlip = settings.tableflip && settings.tableflip != 0 ? true : false;
        var parsedAntiMention;
        if (settings.antimention) {
            parsedAntiMention = parseInt(settings.antimention);
            if (parsedAntiMention == 0 || isNaN(parsedAntiMention)) {
                parsedAntiMention = 'Disabled';
            }
        } else {
            parsedAntiMention = 'Disabled';
        }
        var antiMention = parsedAntiMention;
        let permOverride = settings.permoverride && settings.permoverride != 0 ? true : false;
        let dmHelp = settings.dmhelp && settings.dmhelp != 0 ? true : false;
        let makeLogs = settings.makelogs && settings.makelogs != 0 ? true : false;

        let staffPerms = settings.staffperms || bu.defaultStaff;
        let kickPerms = settings.kickoverride || 0;
        let banPerms = settings.banoverride || 0;
        let greetChan = settings.greetchan ? bot.getChannel(settings.greetchan) : 'Default';
        if (greetChan && greetChan != 'Default') greetChan = greetChan.name;
        else greetChan = 'Undefined';
        let farewellChan = settings.farewellchan ? bot.getChannel(settings.farewellchan) : 'Default';
        if (farewellChan && farewellChan != 'Default') farewellChan = farewellChan.name;
        else farewellChan = 'Undefined';
        let kickAt = settings.kickat || 'Disabled';
        let banAt = settings.banat || 'Disabled';
        var message = `\`\`\`prolog
Settings For ${msg.channel.guild.name}

-- General --
          Prefix : ${prefix}
     CAH is NSFW : ${cahNsfw}
         DM Help : ${dmHelp}

-- Messages --
        Greeting : ${greeting}
        Farewell : ${farewell}
      Tableflips : ${tableFlip}

-- Channels --
Farewell Channel : ${farewellChan}
Greeting Channel : ${greetChan}
   NSFW Channels : ${nsfwMessage}
  Modlog Channel : ${modlogChannel}
     Blacklisted : ${blacklistMessage}

-- Moderation --
       Chat Logs : ${makeLogs}
    Anti-Mention : ${antiMention}
      Muted Role : ${mutedRole}
   Track Deletes : ${deleteNotif}

-- Permissions --
   Perm Override : ${permOverride}
     Staff Perms : ${staffPerms}
   Kick Override : ${kickPerms}
    Ban Override : ${banPerms}

-- Warnings --
         Kick At : ${kickAt}
          Ban At : ${banAt}
\`\`\``;
        bu.send(msg, message);
    } else {
        words.shift();
        var key;
        switch (words[0].toLowerCase()) {
            case 'keys':
                let message = '\nYou can use \`settings set <key> [value]\` to set the following settings. All settings are case insensitive.\n';
                for (key in bu.settings) {
                    message += ' - **' + key.toUpperCase() + '** (' + bu.settings[key].type + ')\n';
                }
                bu.send(msg, message);
                break;
            case 'help':
                bu.send(msg, e.info);
                break;
            case 'set':
                words.shift();
            default:
                if (words.length > 0) {
                    key = words.shift().toLowerCase();
                    let value = words.join(' ');
                    if (bu.settings[key]) {
                        let res = await bu.guildSettings.set(msg.channel.guild.id, key, value, bu.settings[key].type);
                        if (res == true)
                            bu.send(msg, ':ok_hand:');
                        else {
                            bu.send(msg, `Failed to set: ${res}`);
                        };
                    } else {
                        bu.send(msg, 'Invalid key!');
                    }
                }
                break;
        }
    }
};

bu.settings = {
    makelogs: {
        name: 'Make Chatlogs',
        desc: `Whether to record chat logs or not.`,
        type: 'bool'
    },
    cahnsfw: {
        name: 'Is CAH NSFW',
        desc: `Whether 'cah' can only be done in nsfw channels or not.`,
        type: 'bool'
    },
    deletenotif: {
        name: 'Delete Notifications',
        desc: `If enabled, notifies you if a user deleted their command.`,
        type: 'bool'
    },
    greeting: {
        name: 'Greeting Message',
        desc: `What to say to new users when they join. You can also use the <code>greet</code> command`,
        type: 'string'
    },
    farewell: {
        name: 'Farewell Message',
        desc: `What to say when a user leaves. You can also use the <code>farewell</code> command`,
        type: 'string'
    },
    prefix: {
        name: 'Custom Prefix',
        desc: `The custom command prefix. You can also use the <code>setprefix</code> command`,
        type: 'string'
    },
    modlog: {
        name: 'Modlog Channel',
        desc: `The id of the modlog channel. You can also use the <code>modlog</code> command`,
        type: 'string'
    },
    mutedrole: {
        name: 'Muted Role',
        desc: `The id of the muted role.`,
        type: 'string'
    },
    tableflip: {
        name: 'Tableflips',
        desc: `Whether the bot should respond to tableflips/unflips.`,
        type: 'bool'
    },
    antimention: {
        name: 'Anti-Mention',
        desc: `The number of unique mentions required to warrant a ban (for anti-mention spam). Set to '0' to disable. Recommended: 25`,
        type: 'int'
    },
    dmhelp: {
        name: 'DM Help',
        desc: `Whether or not to dm help messages or output them in channels`,
        type: 'bool'
    },
    permoverride: {
        name: 'Permission Override',
        desc: `Whether or not specific permissions override role requirement`,
        type: 'bool'
    },
    staffperms: {
        name: 'Staff Permissions',
        desc: `The numeric value of permissions that designate a staff member. If a user has any of the permissions and permoverride is enabled, allows them to execute any command regardless of role. See here for a permission calculator.`,
        type: 'int'
    },
    kickoverride: {
        name: 'Kick Override',
        desc: `Same as staffperms, but allows users to use the kick command regardless of permissions`,
        type: 'int'
    },
    banoverride: {
        name: 'Ban Override',
        desc: `Same as staffperms, but allows users to use the ban/hackban/unban commands regardless of permissions`,
        type: 'int'
    },
    banat: {
        name: 'Ban At',
        desc: 'The number of warnings before a ban. Set to 0 or below to disable.',
        type: 'int'
    },
    kickat: {
        name: 'Kick At',
        desc: 'The number of warnings before a kick. Set to 0 or below to disable.',
        type: 'int'
    }
};<|endoftext|>


<commit_before>(function() {
  slBarogram = function(placeholder) {
    // Private attributes

    var baro = this;

    var flot = null;

    var active = [];
    var passive = [];
    var enls = [];
    var contests = [];
    var elevations = [];
    var time_highlight = null;

    // Public attributes and functions

    /**
     * @expose
     * Draws the barogram onto the underlying canvas
     */
    baro.draw = function() {
      update();
      flot.setupGrid();
      flot.draw();
    };

    /**
     * @expose
     * Clears the active traces from the barogram
     */
    baro.clearActiveTraces = function() {
      active = [];
    };

    /**
     * @expose
     * Sets the active traces for the barogram
     */
    baro.setActiveTraces = function(data) {
      active = data;
    };

    /**
     * @expose
     * Clears the passive traces from the barogram
     */
    baro.clearPassiveTraces = function() {
      passive = [];
    };

    /**
     * @expose
     * Sets the passive traces for the barogram
     */
    baro.setPassiveTraces = function(data) {
      passive = data;
    };

    /**
     * @expose
     * Clears the ENL data
     */
    baro.clearENLData = function() {
      enls = [];
    };

    /**
     * @expose
     * Sets the ENL data
     */
    baro.setENLData = function(data) {
      enls = data;
    };

    /**
     * @expose
     * Clears the contest markers
     */
    baro.clearContests = function() {
      contests = [];
    };

    /**
     * @expose
     * Sets the contest markers
     */
    baro.setContests = function(data) {
      contests = data;
    };

    /**
     * @expose
     * Clears the elevation data
     */
    baro.clearElevations = function() {
      elevations = [];
    };

    /**
     * @expose
     * Sets the elevation data
     */
    baro.setElevations = function(data) {
      elevations = data;
    };

    /**
     * @expose
     * Clears the crosshair from the barogram
     */
    baro.clearTime = function() {
      baro.setTime(null);
    };

    /**
     * @expose
     * Set the crosshair to the given time
     *
     * @param {?number} time If null the crosshair is removed,
     *   if -1 the crosshair is moved to the end of the barogram,
     *   else the crosshair is moved to the given time.
     */
    baro.setTime = function(time) {
      if (time === null)
        flot.clearCrosshair();
      else if (time == -1)
        flot.lockCrosshair({x: 999999999});
      else
        flot.lockCrosshair({x: global_time * 1000});
    };

    /**
     * @expose
     * Clears the time interval limits from the barogram
     */
    baro.clearTimeInterval = function() {
      var opt = flot.getOptions();
      opt.xaxes[0].min = opt.xaxes[0].max = null;
    };

    /**
     * @expose
     * Sets the time interval that should be shown on the barogram
     *
     * @param {number} start The earliest time that should be shown.
     * @param {number} end The latest time that should be shown.
     */
    baro.setTimeInterval = function(start, end) {
      var opt = flot.getOptions();
      opt.xaxes[0].min = start * 1000;
      opt.xaxes[0].max = end * 1000;
    };

    /**
     * @expose
     * Clears the highlight of a certain time interval from the barogram
     */
    baro.clearTimeHighlight = function() {
      time_highlight = null;
    };

    /**
     * @expose
     * Highlights a certain time interval on the barogram
     *
     * @param {number} start The earliest time that should be highlighted.
     * @param {number} end The latest time that should be highlighted.
     */
    baro.setTimeHighlight = function(start, end) {
      time_highlight = {
        start: start,
        end: end
      };
    };

    // Initialization

    setupFlot();
    attachEventHandlers();

    function setupFlot() {
      flot = $.plot(placeholder, [], {
        grid: {
          borderWidth: 0,
          hoverable: true,
          autoHighlight: false,
          margin: 5
        },
        xaxis: {
          mode: 'time',
          timeformat: '%H:%M'
        },
        yaxes: [
          {
            min: 0,
            tickFormatter: slUnits.addAltitudeUnit
          },
          {
            show: false,
            min: 0,
            max: 1000
          }
        ],
        crosshair: {
          mode: 'x'
        }
      });
    }

    function attachEventHandlers() {
      placeholder.on('plothover', function(event, pos) {
        $(baro).trigger('barohover', [pos.x / 1000.]);
      }).on('mouseout', function(event) {
        $(baro).trigger('mouseout');
      });
    }

    function update() {
      var data = [];
      addActiveTraces(data);
      addPassiveTraces(data);
      addENLData(data);
      addContests(data);
      addElevations(data);
      updateTimeHighlight();

      flot.setData(data);
    }

    function addActiveTraces(data) {
      var active_length = active.length;
      for (var i = 0; i < active_length; ++i) {
        var trace = active[i];

        data.push({
          data: trace.data,
          color: trace.color
        });
      }
    }

    function addPassiveTraces(data) {
      var passive_length = passive.length;
      for (var i = 0; i < passive_length; ++i) {
        var trace = passive[i];

        var color = $.color.parse(trace.color).add('a', -0.6).toString();

        data.push({
          data: trace.data,
          color: color,
          shadowSize: 0,
          lines: {
            lineWidth: 1
          }
        });
      }
    }

    function addENLData(data) {
      var enls_length = enls.length;
      for (var i = 0; i < enls_length; ++i) {
        var enl = enls[i];

        data.push({
          data: enl.data,
          color: enl.color,
          lines: {
            lineWidth: 0,
            fill: 0.2
          },
          yaxis: 2
        });
      }
    }

    /**
     * Adds the current contest markers to the data array
     *
     * @param {Array} data The data array that will be passed to flot.
     */
    function addContests(data) {
      // Skip the function if there are no contest markers
      if (contests === null)
        return;

      // Iterate through the contests
      var contests_length = contests.length;
      for (var i = 0; i < contests_length; ++i) {
        var contest = contests[i];

        var times = contest.times;
        var times_length = times.length;
        if (times_length < 1)
          continue;

        var color = contest.color;

        // Add the turnpoint markers to the markings array
        var markings = [];
        for (var j = 0; j < times_length; ++j) {
          var time = times[j] * 1000;

          markings.push({
            position: time
          });
        }

        // Add the chart series for this contest to the data array
        data.push({
          marks: {
            show: true,
            lineWidth: 1,
            toothSize: 6,
            color: color,
            fillColor: color
          },
          data: [],
          markdata: markings
        });
      }
    }

    function addElevations(data) {
      data.push({
        data: elevations,
        color: 'rgb(235, 155, 98)',
        lines: {
          lineWidth: 0,
          fill: 0.8
        }
      });
    }

    /**
     * Adds the time highlight area to the flot options if available
     */
    function updateTimeHighlight() {
      // There is no flot.setOptions(), so we modify them in-place.
      var options = flot.getOptions();

      // Clear the markings if there is no time highlight
      if (time_highlight === null) {
        options.grid.markings = [];
        return;
      }

      // Add time highlight as flot markings
      options.grid.markings = [{
        color: '#fff083',
        xaxis: {
          from: time_highlight.start * 1000,
          to: time_highlight.end * 1000
        }
      }];
    }
  };
})();
<commit_msg>baro.js: Move elevation data to the background<commit_after>(function() {
  slBarogram = function(placeholder) {
    // Private attributes

    var baro = this;

    var flot = null;

    var active = [];
    var passive = [];
    var enls = [];
    var contests = [];
    var elevations = [];
    var time_highlight = null;

    // Public attributes and functions

    /**
     * @expose
     * Draws the barogram onto the underlying canvas
     */
    baro.draw = function() {
      update();
      flot.setupGrid();
      flot.draw();
    };

    /**
     * @expose
     * Clears the active traces from the barogram
     */
    baro.clearActiveTraces = function() {
      active = [];
    };

    /**
     * @expose
     * Sets the active traces for the barogram
     */
    baro.setActiveTraces = function(data) {
      active = data;
    };

    /**
     * @expose
     * Clears the passive traces from the barogram
     */
    baro.clearPassiveTraces = function() {
      passive = [];
    };

    /**
     * @expose
     * Sets the passive traces for the barogram
     */
    baro.setPassiveTraces = function(data) {
      passive = data;
    };

    /**
     * @expose
     * Clears the ENL data
     */
    baro.clearENLData = function() {
      enls = [];
    };

    /**
     * @expose
     * Sets the ENL data
     */
    baro.setENLData = function(data) {
      enls = data;
    };

    /**
     * @expose
     * Clears the contest markers
     */
    baro.clearContests = function() {
      contests = [];
    };

    /**
     * @expose
     * Sets the contest markers
     */
    baro.setContests = function(data) {
      contests = data;
    };

    /**
     * @expose
     * Clears the elevation data
     */
    baro.clearElevations = function() {
      elevations = [];
    };

    /**
     * @expose
     * Sets the elevation data
     */
    baro.setElevations = function(data) {
      elevations = data;
    };

    /**
     * @expose
     * Clears the crosshair from the barogram
     */
    baro.clearTime = function() {
      baro.setTime(null);
    };

    /**
     * @expose
     * Set the crosshair to the given time
     *
     * @param {?number} time If null the crosshair is removed,
     *   if -1 the crosshair is moved to the end of the barogram,
     *   else the crosshair is moved to the given time.
     */
    baro.setTime = function(time) {
      if (time === null)
        flot.clearCrosshair();
      else if (time == -1)
        flot.lockCrosshair({x: 999999999});
      else
        flot.lockCrosshair({x: global_time * 1000});
    };

    /**
     * @expose
     * Clears the time interval limits from the barogram
     */
    baro.clearTimeInterval = function() {
      var opt = flot.getOptions();
      opt.xaxes[0].min = opt.xaxes[0].max = null;
    };

    /**
     * @expose
     * Sets the time interval that should be shown on the barogram
     *
     * @param {number} start The earliest time that should be shown.
     * @param {number} end The latest time that should be shown.
     */
    baro.setTimeInterval = function(start, end) {
      var opt = flot.getOptions();
      opt.xaxes[0].min = start * 1000;
      opt.xaxes[0].max = end * 1000;
    };

    /**
     * @expose
     * Clears the highlight of a certain time interval from the barogram
     */
    baro.clearTimeHighlight = function() {
      time_highlight = null;
    };

    /**
     * @expose
     * Highlights a certain time interval on the barogram
     *
     * @param {number} start The earliest time that should be highlighted.
     * @param {number} end The latest time that should be highlighted.
     */
    baro.setTimeHighlight = function(start, end) {
      time_highlight = {
        start: start,
        end: end
      };
    };

    // Initialization

    setupFlot();
    attachEventHandlers();

    function setupFlot() {
      flot = $.plot(placeholder, [], {
        grid: {
          borderWidth: 0,
          hoverable: true,
          autoHighlight: false,
          margin: 5
        },
        xaxis: {
          mode: 'time',
          timeformat: '%H:%M'
        },
        yaxes: [
          {
            min: 0,
            tickFormatter: slUnits.addAltitudeUnit
          },
          {
            show: false,
            min: 0,
            max: 1000
          }
        ],
        crosshair: {
          mode: 'x'
        }
      });
    }

    function attachEventHandlers() {
      placeholder.on('plothover', function(event, pos) {
        $(baro).trigger('barohover', [pos.x / 1000.]);
      }).on('mouseout', function(event) {
        $(baro).trigger('mouseout');
      });
    }

    function update() {
      var data = [];
      addElevations(data);
      addActiveTraces(data);
      addPassiveTraces(data);
      addENLData(data);
      addContests(data);
      updateTimeHighlight();

      flot.setData(data);
    }

    function addActiveTraces(data) {
      var active_length = active.length;
      for (var i = 0; i < active_length; ++i) {
        var trace = active[i];

        data.push({
          data: trace.data,
          color: trace.color
        });
      }
    }

    function addPassiveTraces(data) {
      var passive_length = passive.length;
      for (var i = 0; i < passive_length; ++i) {
        var trace = passive[i];

        var color = $.color.parse(trace.color).add('a', -0.6).toString();

        data.push({
          data: trace.data,
          color: color,
          shadowSize: 0,
          lines: {
            lineWidth: 1
          }
        });
      }
    }

    function addENLData(data) {
      var enls_length = enls.length;
      for (var i = 0; i < enls_length; ++i) {
        var enl = enls[i];

        data.push({
          data: enl.data,
          color: enl.color,
          lines: {
            lineWidth: 0,
            fill: 0.2
          },
          yaxis: 2
        });
      }
    }

    /**
     * Adds the current contest markers to the data array
     *
     * @param {Array} data The data array that will be passed to flot.
     */
    function addContests(data) {
      // Skip the function if there are no contest markers
      if (contests === null)
        return;

      // Iterate through the contests
      var contests_length = contests.length;
      for (var i = 0; i < contests_length; ++i) {
        var contest = contests[i];

        var times = contest.times;
        var times_length = times.length;
        if (times_length < 1)
          continue;

        var color = contest.color;

        // Add the turnpoint markers to the markings array
        var markings = [];
        for (var j = 0; j < times_length; ++j) {
          var time = times[j] * 1000;

          markings.push({
            position: time
          });
        }

        // Add the chart series for this contest to the data array
        data.push({
          marks: {
            show: true,
            lineWidth: 1,
            toothSize: 6,
            color: color,
            fillColor: color
          },
          data: [],
          markdata: markings
        });
      }
    }

    function addElevations(data) {
      data.push({
        data: elevations,
        color: 'rgb(235, 155, 98)',
        lines: {
          lineWidth: 0,
          fill: 0.8
        }
      });
    }

    /**
     * Adds the time highlight area to the flot options if available
     */
    function updateTimeHighlight() {
      // There is no flot.setOptions(), so we modify them in-place.
      var options = flot.getOptions();

      // Clear the markings if there is no time highlight
      if (time_highlight === null) {
        options.grid.markings = [];
        return;
      }

      // Add time highlight as flot markings
      options.grid.markings = [{
        color: '#fff083',
        xaxis: {
          from: time_highlight.start * 1000,
          to: time_highlight.end * 1000
        }
      }];
    }
  };
})();
<|endoftext|>