<commit_before>var _ = require('lodash');
var request = require('request');
var CronJob = require('cron').CronJob;
var constants = require('./constants.js');

module.exports = function(
  logger,
  app,
  retriesBeforeDelete,
  triggerDB,
  routerHost
) {

    this.logger = logger;
    this.app = app;
    this.retriesBeforeDelete = retriesBeforeDelete;
    this.triggerDB = triggerDB;
    this.routerHost = routerHost;

    // this is the default trigger fire limit (in the event that is was not set during trigger creation)
    this.defaultTriggerFireLimit = constants.DEFAULT_TRIGGER_COUNT;

    // Log HTTP Requests
    app.use(function(req, res, next) {
        if (req.url.indexOf('/alarmtriggers') === 0) {
            logger.info('HttpRequest', req.method, req.url);
        }
        next();
    });

    this.module = 'utils';
    this.triggers = {};

    var that = this;

    this.createTrigger = function(newTrigger) {

        var method = 'createTrigger';

        try {
            var triggerIdentifier = that.getTriggerIdentifier(newTrigger.apikey, newTrigger.namespace, newTrigger.name);
            var cronHandle;

            return new Promise(function(resolve, reject) {

                // to avoid multiple cron jobs for the same trigger we will only create a cron job if
                // the trigger is not already in the list of identified triggers
                if (!(triggerIdentifier in that.triggers)) {
                    cronHandle = new CronJob(newTrigger.cron,
                        function onTick() {
                            var triggerHandle = that.triggers[triggerIdentifier];
                            if (triggerHandle && (triggerHandle.maxTriggers === -1 || triggerHandle.triggersLeft > 0)) {
                                that.fireTrigger(newTrigger.namespace, newTrigger.name, newTrigger.payload, newTrigger.apikey);
                            }
                        }
                    );
                    logger.info(method, triggerIdentifier, 'starting cron job');
                    cronHandle.start();

                    that.triggers[triggerIdentifier] = {
                        cron: newTrigger.cron,
                        cronHandle: cronHandle,
                        triggersLeft: newTrigger.maxTriggers,
                        maxTriggers: newTrigger.maxTriggers,
                        apikey: newTrigger.apikey,
                        name: newTrigger.name,
                        namespace: newTrigger.namespace
                    };
                }
                else {
                    logger.info(method, triggerIdentifier, 'already exists');
                }
                resolve(triggerIdentifier);
            });

        } catch (err) {
            return Promise.reject(err);
        }
    };

    this.fireTrigger = function (namespace, name, payload, apikey) {
        var method = 'fireTrigger';
        var triggerIdentifier = that.getTriggerIdentifier(apikey, namespace, name);
        var routerHost = process.env.ROUTER_HOST;
        var host = "https://" + routerHost + ":443";
        // https://github.com/openwhisk/openwhisk-alarms-trigger/issues/9
        // resolved this in create.js by validating apikey and failing with a useful message if it is
        // not present
        var keyParts = apikey.split(':');
        var triggerHandle = that.triggers[triggerIdentifier];

        request({
            method: 'POST',
            uri: host + '/api/v1/namespaces/' + namespace + '/triggers/' + name,
            json: payload,
            auth: {
                user: keyParts[0],
                pass: keyParts[1]
            }
        }, function(err, res, body) {
            if (triggerHandle) {
                logger.info(method, 'done http request, STATUS', res ? res.statusCode : res);
                if (err || res.statusCode >= 400) {
                    logger.error(method, 'there was an error invoking', triggerIdentifier, res ? res.statusCode : res, err, body);
                    if (!err && [408, 429, 500, 503].indexOf(res.statusCode) === -1) {
                        //delete dead triggers
                        that.deleteTrigger(triggerHandle.namespace, triggerHandle.name, triggerHandle.apikey);
                    }
                } else {
                    // only manage trigger fires if they are not infinite
                    if (triggerHandle.maxTriggers !== -1) {
                        triggerHandle.triggersLeft--;
                    }
                    logger.info(method, 'fired', triggerIdentifier, 'with body', body, triggerHandle.triggersLeft, 'triggers left');
                }

                if (triggerHandle.triggersLeft === 0) {
                    logger.info('onTick', 'no more triggers left, deleting');
                    that.deleteTrigger(triggerHandle.namespace, triggerHandle.name, triggerHandle.apikey);
                }
            }
            else {
                logger.info(method, 'trigger', triggerIdentifier, 'was deleted between invocations');
            }
        });
    };

    this.deleteTrigger = function (namespace, name, apikey) {

        var method = 'deleteTrigger';

        var triggerIdentifier = that.getTriggerIdentifier(apikey, namespace, name);
        if (that.triggers[triggerIdentifier]) {
            if (that.triggers[triggerIdentifier].cronHandle) {
                that.triggers[triggerIdentifier].cronHandle.stop();
            }
            delete that.triggers[triggerIdentifier];

            logger.info(method, 'trigger', triggerIdentifier, 'successfully deleted');

            that.deleteTriggerFromDB(triggerIdentifier);
            return true;
        }
        else {
            logger.info(method, 'trigger', triggerIdentifier, 'could not be found');
            return false;
        }
    };

    this.deleteTriggerFromDB = function (triggerIdentifier) {

        var method = 'deleteTriggerFromDB';

        that.triggerDB.get(triggerIdentifier, function (err, body) {
            if (!err) {
                that.triggerDB.destroy(body._id, body._rev, function (err) {
                    if (err) {
                        logger.error(method, 'there was an error while deleting', triggerIdentifier, 'from database');
                    }
                    else {
                        logger.info(method, 'trigger', triggerIdentifier, 'successfully deleted from database');
                    }
                });
            }
            else {
                logger.error(method, 'there was an error while deleting', triggerIdentifier, 'from database');
            }
        });
    };

    this.getTriggerIdentifier = function (apikey, namespace, name) {
        return apikey + '/' + namespace + '/' + name;
    };

    this.initAllTriggers = function () {
        var method = 'initAllTriggers';
        logger.info(method, 'resetting system from last state');
        that.triggerDB.view('filters', 'only_triggers', {include_docs: true}, function(err, body) {
            if (!err) {
                body.rows.forEach(function(trigger) {
                    //check if trigger still exists in whisk db
                    var namespace = trigger.doc.namespace;
                    var name = trigger.doc.name;
                    var apikey = trigger.doc.apikey;
                    var triggerIdentifier = that.getTriggerIdentifier(apikey, namespace, name);
                    logger.info(method, 'Checking if trigger', triggerIdentifier, 'still exists');

                    var host = 'https://' + routerHost +':'+ 443;
                    var triggerURL = host + '/api/v1/namespaces/' + namespace + '/triggers/' + name;
                    var auth = apikey.split(':');

                    request({
                        method: 'get',
                        url: triggerURL,
                        auth: {
                            user: auth[0],
                            pass: auth[1]
                        }
                    }, function(error, response, body) {
                        //delete from database if trigger no longer exists (404)
                        if (!error && response.statusCode === 404) {
                            logger.info(method, 'trigger', triggerIdentifier, 'could not be found');
                            that.deleteTriggerFromDB(triggerIdentifier);
                        }
                        else {
                            that.createTrigger(trigger.doc)
                            .then(triggerIdentifier => {
                                logger.info(method, triggerIdentifier, 'created successfully');
                            })
                            .catch(err => {
                                logger.error(method, err);
                                that.deleteTriggerFromDB(triggerIdentifier);
                            });
                        }
                    });
                });
            }
            else {
                logger.error(method, 'could not get latest state from database');
            }
        });
    };

    this.sendError = function (method, code, message, res) {
        logger.warn(method, message);
        res.status(code).json({error: message});
    };

    this.authorize = function(req, res, next) {
        if (!req.headers.authorization) {
            return that.sendError(400, 'Malformed request, authentication header expected', res);
        }

        var parts = req.headers.authorization.split(' ');
        if (parts[0].toLowerCase() !== 'basic' || !parts[1]) {
            return that.sendError(400, 'Malformed request, basic authentication expected', res);
        }

        var auth = new Buffer(parts[1], 'base64').toString();
        auth = auth.match(/^([^:]*):(.*)$/);
        if (!auth) {
            return that.sendError(400, 'Malformed request, authentication invalid', res);
        }

        req.user = {
            uuid: auth[1],
            key: auth[2]
        };

        next();
    };

};
<commit_msg>include trigger name with post response status code (#46)<commit_after>var _ = require('lodash');
var request = require('request');
var CronJob = require('cron').CronJob;
var constants = require('./constants.js');

module.exports = function(
  logger,
  app,
  retriesBeforeDelete,
  triggerDB,
  routerHost
) {

    this.logger = logger;
    this.app = app;
    this.retriesBeforeDelete = retriesBeforeDelete;
    this.triggerDB = triggerDB;
    this.routerHost = routerHost;

    // this is the default trigger fire limit (in the event that is was not set during trigger creation)
    this.defaultTriggerFireLimit = constants.DEFAULT_TRIGGER_COUNT;

    // Log HTTP Requests
    app.use(function(req, res, next) {
        if (req.url.indexOf('/alarmtriggers') === 0) {
            logger.info('HttpRequest', req.method, req.url);
        }
        next();
    });

    this.module = 'utils';
    this.triggers = {};

    var that = this;

    this.createTrigger = function(newTrigger) {

        var method = 'createTrigger';

        try {
            var triggerIdentifier = that.getTriggerIdentifier(newTrigger.apikey, newTrigger.namespace, newTrigger.name);
            var cronHandle;

            return new Promise(function(resolve, reject) {

                // to avoid multiple cron jobs for the same trigger we will only create a cron job if
                // the trigger is not already in the list of identified triggers
                if (!(triggerIdentifier in that.triggers)) {
                    cronHandle = new CronJob(newTrigger.cron,
                        function onTick() {
                            var triggerHandle = that.triggers[triggerIdentifier];
                            if (triggerHandle && (triggerHandle.maxTriggers === -1 || triggerHandle.triggersLeft > 0)) {
                                that.fireTrigger(newTrigger.namespace, newTrigger.name, newTrigger.payload, newTrigger.apikey);
                            }
                        }
                    );
                    logger.info(method, triggerIdentifier, 'starting cron job');
                    cronHandle.start();

                    that.triggers[triggerIdentifier] = {
                        cron: newTrigger.cron,
                        cronHandle: cronHandle,
                        triggersLeft: newTrigger.maxTriggers,
                        maxTriggers: newTrigger.maxTriggers,
                        apikey: newTrigger.apikey,
                        name: newTrigger.name,
                        namespace: newTrigger.namespace
                    };
                }
                else {
                    logger.info(method, triggerIdentifier, 'already exists');
                }
                resolve(triggerIdentifier);
            });

        } catch (err) {
            return Promise.reject(err);
        }
    };

    this.fireTrigger = function (namespace, name, payload, apikey) {
        var method = 'fireTrigger';
        var triggerIdentifier = that.getTriggerIdentifier(apikey, namespace, name);
        var routerHost = process.env.ROUTER_HOST;
        var host = "https://" + routerHost + ":443";
        // https://github.com/openwhisk/openwhisk-alarms-trigger/issues/9
        // resolved this in create.js by validating apikey and failing with a useful message if it is
        // not present
        var keyParts = apikey.split(':');
        var triggerHandle = that.triggers[triggerIdentifier];

        request({
            method: 'POST',
            uri: host + '/api/v1/namespaces/' + namespace + '/triggers/' + name,
            json: payload,
            auth: {
                user: keyParts[0],
                pass: keyParts[1]
            }
        }, function(err, res, body) {
            if (triggerHandle) {
                logger.info(method, triggerIdentifier, 'http post request, STATUS:', res ? res.statusCode : res);
                if (err || res.statusCode >= 400) {
                    logger.error(method, 'there was an error invoking', triggerIdentifier, res ? res.statusCode : res, err, body);
                    if (!err && [408, 429, 500, 503].indexOf(res.statusCode) === -1) {
                        //delete dead triggers
                        that.deleteTrigger(triggerHandle.namespace, triggerHandle.name, triggerHandle.apikey);
                    }
                } else {
                    // only manage trigger fires if they are not infinite
                    if (triggerHandle.maxTriggers !== -1) {
                        triggerHandle.triggersLeft--;
                    }
                    logger.info(method, 'fired', triggerIdentifier, 'with body', body, triggerHandle.triggersLeft, 'triggers left');
                }

                if (triggerHandle.triggersLeft === 0) {
                    logger.info('onTick', 'no more triggers left, deleting');
                    that.deleteTrigger(triggerHandle.namespace, triggerHandle.name, triggerHandle.apikey);
                }
            }
            else {
                logger.info(method, 'trigger', triggerIdentifier, 'was deleted between invocations');
            }
        });
    };

    this.deleteTrigger = function (namespace, name, apikey) {

        var method = 'deleteTrigger';

        var triggerIdentifier = that.getTriggerIdentifier(apikey, namespace, name);
        if (that.triggers[triggerIdentifier]) {
            if (that.triggers[triggerIdentifier].cronHandle) {
                that.triggers[triggerIdentifier].cronHandle.stop();
            }
            delete that.triggers[triggerIdentifier];

            logger.info(method, 'trigger', triggerIdentifier, 'successfully deleted');

            that.deleteTriggerFromDB(triggerIdentifier);
            return true;
        }
        else {
            logger.info(method, 'trigger', triggerIdentifier, 'could not be found');
            return false;
        }
    };

    this.deleteTriggerFromDB = function (triggerIdentifier) {

        var method = 'deleteTriggerFromDB';

        that.triggerDB.get(triggerIdentifier, function (err, body) {
            if (!err) {
                that.triggerDB.destroy(body._id, body._rev, function (err) {
                    if (err) {
                        logger.error(method, 'there was an error while deleting', triggerIdentifier, 'from database');
                    }
                    else {
                        logger.info(method, 'trigger', triggerIdentifier, 'successfully deleted from database');
                    }
                });
            }
            else {
                logger.error(method, 'there was an error while deleting', triggerIdentifier, 'from database');
            }
        });
    };

    this.getTriggerIdentifier = function (apikey, namespace, name) {
        return apikey + '/' + namespace + '/' + name;
    };

    this.initAllTriggers = function () {
        var method = 'initAllTriggers';
        logger.info(method, 'resetting system from last state');
        that.triggerDB.view('filters', 'only_triggers', {include_docs: true}, function(err, body) {
            if (!err) {
                body.rows.forEach(function(trigger) {
                    //check if trigger still exists in whisk db
                    var namespace = trigger.doc.namespace;
                    var name = trigger.doc.name;
                    var apikey = trigger.doc.apikey;
                    var triggerIdentifier = that.getTriggerIdentifier(apikey, namespace, name);
                    logger.info(method, 'Checking if trigger', triggerIdentifier, 'still exists');

                    var host = 'https://' + routerHost +':'+ 443;
                    var triggerURL = host + '/api/v1/namespaces/' + namespace + '/triggers/' + name;
                    var auth = apikey.split(':');

                    request({
                        method: 'get',
                        url: triggerURL,
                        auth: {
                            user: auth[0],
                            pass: auth[1]
                        }
                    }, function(error, response, body) {
                        //delete from database if trigger no longer exists (404)
                        if (!error && response.statusCode === 404) {
                            logger.info(method, 'trigger', triggerIdentifier, 'could not be found');
                            that.deleteTriggerFromDB(triggerIdentifier);
                        }
                        else {
                            that.createTrigger(trigger.doc)
                            .then(triggerIdentifier => {
                                logger.info(method, triggerIdentifier, 'created successfully');
                            })
                            .catch(err => {
                                logger.error(method, err);
                                that.deleteTriggerFromDB(triggerIdentifier);
                            });
                        }
                    });
                });
            }
            else {
                logger.error(method, 'could not get latest state from database');
            }
        });
    };

    this.sendError = function (method, code, message, res) {
        logger.warn(method, message);
        res.status(code).json({error: message});
    };

    this.authorize = function(req, res, next) {
        if (!req.headers.authorization) {
            return that.sendError(400, 'Malformed request, authentication header expected', res);
        }

        var parts = req.headers.authorization.split(' ');
        if (parts[0].toLowerCase() !== 'basic' || !parts[1]) {
            return that.sendError(400, 'Malformed request, basic authentication expected', res);
        }

        var auth = new Buffer(parts[1], 'base64').toString();
        auth = auth.match(/^([^:]*):(.*)$/);
        if (!auth) {
            return that.sendError(400, 'Malformed request, authentication invalid', res);
        }

        req.user = {
            uuid: auth[1],
            key: auth[2]
        };

        next();
    };

};
<|endoftext|>


<commit_before>'use strict';

/* ******************************************************************** */
/* TASK SPECIFIC IMPORTS */
const packagejson = require('../../../package.json');
const moment = require('moment');
const md5 = require('md5');
/*/********************************************************************///
/*///*/

/* ******************************************************************** */
/* TASK DEBUG */
module.exports = (gulp, plugins) => {
    const buildTimestamp = moment();
    const buildNumber = buildTimestamp.format('YYYYMMDDHHmmss');
    const machine = `${plugins.os.platform()}:${plugins.os.type()}:${plugins.os.hostname()}`;

    return () => {
        return gulp.src(`${plugins.config.paths.src.config}/config.${plugins.config.env.name}.json`)
            .pipe(plugins.rename('config.json'))
            .pipe(plugins.jsoneditor(json => {
                json.app.name = _getProjectName();
                json.app.version = _getProjectVersion();
                json.app.build.number = buildNumber;
                json.app.build.timestamp = buildTimestamp.format();
                json.app.build.commit = _getCommitHash();
                json.app.build.environment.id = plugins.config.env.id;
                json.app.build.environment.name = plugins.config.env.name;
                json.app.build.environment.machine = {};
                json.app.build.environment.machine.id = machine;
                json.app.build.environment.machine.number = md5(machine);
                return json;
        }, {
            'indent_char': '\t',
            'indent_size': 1
        }))
        .pipe(gulp.dest(plugins.config.paths.dest.config));
    };
};

function _getCommitHash() {
    try {
        return childProcess.execSync('git rev-parse HEAD').toString().trim();
    } catch(err) {
        return -1;
    }
}
function _getProjectName() {
    if(packagejson === undefined) {
        throw new Error('No package.json defined');
    }
    if(packagejson['name'] === undefined) {
        throw new Error('No \'name\' property found inside package.json');
    }
    return packagejson.name;
}
function _getProjectVersion() {
    if(packagejson === undefined) {
        throw new Error('No package.json defined');
    }
    if(packagejson['version'] === undefined) {
        throw new Error('No \'name\' property found inside package.json');
    }
    return packagejson.version;
}
/*/********************************************************************///
/*///*/<commit_msg>fixed commit number<commit_after>'use strict';

/* ******************************************************************** */
/* TASK SPECIFIC IMPORTS */
const packagejson = require('../../../package.json');
const moment = require('moment');
const md5 = require('md5');
const childProcess = require('child_process');
/*/********************************************************************///
/*///*/

/* ******************************************************************** */
/* TASK DEBUG */
module.exports = (gulp, plugins) => {
    const buildTimestamp = moment();
    const buildNumber = buildTimestamp.format('YYYYMMDDHHmmss');
    const machine = `${plugins.os.platform()}:${plugins.os.type()}:${plugins.os.hostname()}`;

    return () => {
        return gulp.src(`${plugins.config.paths.src.config}/config.${plugins.config.env.name}.json`)
            .pipe(plugins.rename('config.json'))
            .pipe(plugins.jsoneditor(json => {
                json.app.name = _getProjectName();
                json.app.version = _getProjectVersion();
                json.app.build.number = buildNumber;
                json.app.build.timestamp = buildTimestamp.format();
                json.app.build.commit = _getCommitHash();
                json.app.build.environment.id = plugins.config.env.id;
                json.app.build.environment.name = plugins.config.env.name;
                json.app.build.environment.machine = {};
                json.app.build.environment.machine.id = machine;
                json.app.build.environment.machine.number = md5(machine);
                return json;
            }, {
                    'indent_char': '\t',
                    'indent_size': 1
                }))
            .pipe(gulp.dest(plugins.config.paths.dest.config));
    };
};

function _getCommitHash() {
    try {
        return childProcess.execSync('git rev-parse HEAD').toString().trim();
    } catch (err) {
        return -1;
    }
}
function _getProjectName() {
    if (packagejson === undefined) {
        throw new Error('No package.json defined');
    }
    if (packagejson['name'] === undefined) {
        throw new Error('No \'name\' property found inside package.json');
    }
    return packagejson.name;
}
function _getProjectVersion() {
    if (packagejson === undefined) {
        throw new Error('No package.json defined');
    }
    if (packagejson['version'] === undefined) {
        throw new Error('No \'name\' property found inside package.json');
    }
    return packagejson.version;
}
/*/********************************************************************///
/*///*/<|endoftext|>


<commit_before>// Types of events:
// 1 = Sosialt
// 2 = Bedriftspresentasjon
// 3 = Kurs
// 4 = Utflukt
// 5 = Ekskursjon
// 6 = Internt
// 7 = Annet

var API_KEY = "derp",
    API_BASE_URL = "http://localhost";

function dateFormatter (date, format) {

    if (typeof date === 'string') {

        var format = (typeof format === 'string' ? format : 'dag DD.MM.YYYY (HH:MM:SS)'),
            dager = ["Man", "Tirs", "Ons", "Tors", "Fre", "Lør", "Søn"],
            d = new Date(date.replace(/-/g, '/').replace(/T/g, ' ').replace(/Z/g, '')),
            formatted = format.replace(new RegExp("da[gy]", "ig"), dager[d.getDay()]);

        for(var i = 5; i > 0; i--) {
            formatted = formatted.replace(new RegExp("(^|\\W)y{" + i + ",}($|\\W)", "ig"), "$1" + digits(d.getFullYear(), i) + "$2")
                                 .replace(new RegExp("(^|\\W)m{" + i + ",}($|\\W)", "ig"), "$1" + digits(d.getMonth()+1, i) + "$2")
                                 .replace(new RegExp("(^|\\W)d{" + i + ",}($|\\W)", "ig"), "$1" + digits(d.getDate(), i) + "$2")
                                 .replace(new RegExp("(^|\\W)h{" + i + ",}($|\\W)", "ig"), "$1" + digits(d.getHours(), i) + "$2")
                                 .replace(new RegExp("(^|\\W)m{" + i + ",}($|\\W)", "ig"), "$1" + digits(d.getMinutes(), i) + "$2")
                                 .replace(new RegExp("(^|\\W)s{" + i + ",}($|\\W)", "ig"), "$1" + digits(d.getSeconds(), i) + "$2");
        }

        return formatted;
    }

    return '';
}

function digits (number, places) {
    var places = (typeof places === 'number' ? places : 2);

    return (Array(places).join("0") + number).slice(-(places));
}

var sortBy = {
    date: {
        asc: function (user1, user2) {
            var time1 = user1.timestamp,
                time2 = user2.timestamp;

            if (time1 > time2) return 1;
            if (time1 < time2) return -1;

            return 0;
        },
        desc: function (user2, user1) {
            var time1 = user1.timestamp,
                time2 = user2.timestamp;

            if (time1 > time2) return 1;
            if (time1 < time2) return -1;

            return 0;
        }
    },
    username: {
        asc: function (user1, user2) {
            var time1 = user1.user.first_name.toLowerCase(),
                time2 = user2.user.first_name.toLowerCase();

            if (time1 > time2) return 1;
            if (time1 < time2) return -1;

            return 0;
        },
        desc: function (user2, user1) {
            var time1 = user1.user.first_name.toLowerCase(),
                time2 = user2.user.first_name.toLowerCase();

            if (time1 > time2) return 1;
            if (time1 < time2) return -1;

            return 0;
        }
    }
}

var UserList = React.createClass({
    getInitialState: function () {
        return {
            data: [],
            selectedIndex: null
        };
    },

    render: function () {

        if (this.props.users.length > 0) {
            var List = (
                    this.props.users.map(function (user, index) {
                    return (

                            { [user.user.first_name, user.user.last_name].join(" ") }
                            { user.user.username }
                            { dateFormatter(user.timestamp, 'day DD/MM/YY (HH:MM:SS)') }

                    );
                }, this)
            );

            return (

{ this.props.title }

                                Navn
                                Brukernavn

{ List }

            );
        } else {
            return (

{ this.props.empty }

            );
        }
    }
});

var UserLists = React.createClass({
    getInitialState: function () {
        return {
            data: [],
            selectedIndex: null,
            sortedBy: "username",
            sort: "asc"
        };
    },

    componentDidMount: function () {
        this.request = $.get("js/data.json", function (data) {
            var events = data.events.filter(function (event) {
                return (event.attendance_event != null)
            }).map(function (event) {

                if (event.attendance_event.waitlist) {
                    event.attendance_event.listed = event.attendance_event.users.slice(0, event.attendance_event.max_capacity)
                    event.attendance_event.registered = event.attendance_event.listed.filter(function (user) {
                        return user.attended;
                    });
                    event.attendance_event.listed = event.attendance_event.listed.filter(function (user) {
                        return !user.attended;
                    });
                    event.attendance_event.waiting = event.attendance_event.users.slice(event.attendance_event.max_capacity);
                }

                event.attendance_event.registered = event.attendance_event.registered.sort(sortBy.username.asc);
                event.attendance_event.listed = event.attendance_event.listed.sort(sortBy.username.asc);
                event.attendance_event.waiting = event.attendance_event.waiting.sort(sortBy.username.asc);

                //event.attendance_event.listed = event.attendance_event.listed.

                return event;
            });

            document.querySelector('#title').innerHTML = events[0].title;

            if (this.isMounted()) {
                this.setState({
                    data: events,
                    selectedIndex: 0
                });
            }
        }.bind(this));
    },

    componentWillUnmount: function () {
        this.request.abort();
    },

    handleClick: function (i) {
        document.querySelector('#title').innerHTML = this.state.data[i].title;

        this.setState({
            selectedIndex: i
        });
    },

    handleSort: function (func) {
        this.setState({
            sort: (this.state.sort === "asc" ? "desc" : "asc"),
            sortBy: func,
            data: this.state.data.map(function (event) {
                event.attendance_event.users = event.attendance_event.users.sort(sortBy[func][(this.state.sort === "asc" ? "desc" : "asc")])

                return event;
            }, this)
        });
    },

    render: function () {
        var eventNames = this.state.data.map(function (event, index) {
            return <button className="event-name btn" onClick={this.handleClick.bind(this, index)} listItem={index} key={index}>{event.title}</button>
        }, this);

        var usersRegistered = [],
            usersListed = [],
            usersWaiting = [];

        if (typeof this.state.selectedIndex === "number") {
            usersRegistered = this.state.data[this.state.selectedIndex].attendance_event.registered;
            usersListed = this.state.data[this.state.selectedIndex].attendance_event.listed;
            usersWaiting = this.state.data[this.state.selectedIndex].attendance_event.waiting;
        }

        return (

{ eventNames }

                <button className="btn" onClick={ this.handleSort.bind(this, "username") }>Sorter etter navn</button>
                <button className="btn" onClick={ this.handleSort.bind(this, "date") }>Sorter etter dato</button>
                <UserList title={ (usersListed.length > 0 ? usersRegistered.length + " har møtt" : "Alle har møtt!") } users={ usersRegistered } />
                <UserList title={ (usersRegistered.length > 0 ? usersListed.length + " har ikke møtt" : "Ingen har møtt") } users={ usersListed } />
                <UserList title="Venteliste" empty="Ingen på venteliste" users={ usersWaiting } />

        );
    }
});

ReactDOM.render(
    <UserLists />,
    document.querySelector('#options')
);
<commit_msg>Buttons now has an on-state when selected<commit_after>// Types of events:
// 1 = Sosialt
// 2 = Bedriftspresentasjon
// 3 = Kurs
// 4 = Utflukt
// 5 = Ekskursjon
// 6 = Internt
// 7 = Annet

var API_KEY = "derp",
    API_BASE_URL = "http://localhost";

function dateFormatter (date, format) {

    if (typeof date === 'string') {

        var format = (typeof format === 'string' ? format : 'dag DD.MM.YYYY (HH:MM:SS)'),
            dager = ["Man", "Tirs", "Ons", "Tors", "Fre", "Lør", "Søn"],
            d = new Date(date.replace(/-/g, '/').replace(/T/g, ' ').replace(/Z/g, '')),
            formatted = format.replace(new RegExp("da[gy]", "ig"), dager[d.getDay()]);

        for(var i = 5; i > 0; i--) {
            formatted = formatted.replace(new RegExp("(^|\\W)y{" + i + ",}($|\\W)", "ig"), "$1" + digits(d.getFullYear(), i) + "$2")
                                 .replace(new RegExp("(^|\\W)m{" + i + ",}($|\\W)", "ig"), "$1" + digits(d.getMonth()+1, i) + "$2")
                                 .replace(new RegExp("(^|\\W)d{" + i + ",}($|\\W)", "ig"), "$1" + digits(d.getDate(), i) + "$2")
                                 .replace(new RegExp("(^|\\W)h{" + i + ",}($|\\W)", "ig"), "$1" + digits(d.getHours(), i) + "$2")
                                 .replace(new RegExp("(^|\\W)m{" + i + ",}($|\\W)", "ig"), "$1" + digits(d.getMinutes(), i) + "$2")
                                 .replace(new RegExp("(^|\\W)s{" + i + ",}($|\\W)", "ig"), "$1" + digits(d.getSeconds(), i) + "$2");
        }

        return formatted;
    }

    return '';
}

function digits (number, places) {
    var places = (typeof places === 'number' ? places : 2);

    return (Array(places).join("0") + number).slice(-(places));
}

var sortBy = {
    date: {
        asc: function (user1, user2) {
            var time1 = user1.timestamp,
                time2 = user2.timestamp;

            if (time1 > time2) return 1;
            if (time1 < time2) return -1;

            return 0;
        },
        desc: function (user2, user1) {
            var time1 = user1.timestamp,
                time2 = user2.timestamp;

            if (time1 > time2) return 1;
            if (time1 < time2) return -1;

            return 0;
        }
    },
    username: {
        asc: function (user1, user2) {
            var time1 = user1.user.first_name.toLowerCase(),
                time2 = user2.user.first_name.toLowerCase();

            if (time1 > time2) return 1;
            if (time1 < time2) return -1;

            return 0;
        },
        desc: function (user2, user1) {
            var time1 = user1.user.first_name.toLowerCase(),
                time2 = user2.user.first_name.toLowerCase();

            if (time1 > time2) return 1;
            if (time1 < time2) return -1;

            return 0;
        }
    }
}

var UserList = React.createClass({
    getInitialState: function () {
        return {
            data: [],
            selectedIndex: null
        };
    },

    render: function () {

        if (this.props.users.length > 0) {
            var List = (
                    this.props.users.map(function (user, index) {
                    return (

                            { [user.user.first_name, user.user.last_name].join(" ") }
                            { user.user.username }
                            { dateFormatter(user.timestamp, 'day DD/MM/YY (HH:MM:SS)') }

                    );
                }, this)
            );

            return (

{ this.props.title }

                                Navn
                                Brukernavn

{ List }

            );
        } else {
            return (

{ this.props.empty }

            );
        }
    }
});

var UserLists = React.createClass({
    getInitialState: function () {
        return {
            data: [],
            selectedIndex: null,
            sortedBy: "username",
            sort: "asc"
        };
    },

    componentDidMount: function () {
        this.request = $.get("js/data.json", function (data) {
            var events = data.events.filter(function (event) {
                return (event.attendance_event != null)
            }).map(function (event) {

                if (event.attendance_event.waitlist) {
                    event.attendance_event.listed = event.attendance_event.users.slice(0, event.attendance_event.max_capacity)
                    event.attendance_event.registered = event.attendance_event.listed.filter(function (user) {
                        return user.attended;
                    });
                    event.attendance_event.listed = event.attendance_event.listed.filter(function (user) {
                        return !user.attended;
                    });
                    event.attendance_event.waiting = event.attendance_event.users.slice(event.attendance_event.max_capacity);
                }

                event.attendance_event.registered = event.attendance_event.registered.sort(sortBy.username.asc);
                event.attendance_event.listed = event.attendance_event.listed.sort(sortBy.username.asc);
                event.attendance_event.waiting = event.attendance_event.waiting.sort(sortBy.username.asc);

                //event.attendance_event.listed = event.attendance_event.listed.

                return event;
            });

            document.querySelector('#title').innerHTML = events[0].title;

            if (this.isMounted()) {
                this.setState({
                    data: events,
                    selectedIndex: 0
                });
            }
        }.bind(this));
    },

    componentWillUnmount: function () {
        this.request.abort();
    },

    handleClick: function (i) {
        document.querySelector('#title').innerHTML = this.state.data[i].title;

        this.setState({
            selectedIndex: i
        });
    },

    handleSort: function (func) {
        this.setState({
            sort: (this.state.sort === "asc" ? "desc" : "asc"),
            sortedBy: func,
            data: this.state.data.map(function (event) {
                event.attendance_event.users = event.attendance_event.users.sort(sortBy[func][(this.state.sort === "asc" ? "desc" : "asc")])

                return event;
            }, this)
        });
    },

    render: function () {
        var eventNames = this.state.data.map(function (event, index) {
            return <button className={ "btn" + (this.state.selectedIndex === index ? " btn-default" : "") } onClick={this.handleClick.bind(this, index)} listItem={index} key={index}>{event.title}</button>
        }, this);

        var usersRegistered = [],
            usersListed = [],
            usersWaiting = [];

        if (typeof this.state.selectedIndex === "number") {
            usersRegistered = this.state.data[this.state.selectedIndex].attendance_event.registered;
            usersListed = this.state.data[this.state.selectedIndex].attendance_event.listed;
            usersWaiting = this.state.data[this.state.selectedIndex].attendance_event.waiting;
        }

        return (

{ eventNames }

                <button className={ "btn" + (this.state.sortedBy === "username" ? " btn-default" : "") } onClick={ this.handleSort.bind(this, "username") }>Sorter etter navn</button>
                <button className={ "btn" + (this.state.sortedBy === "date" ? " btn-default" : "") } onClick={ this.handleSort.bind(this, "date") }>Sorter etter dato</button>
                <UserList title={ (usersListed.length > 0 ? usersRegistered.length + " har møtt" : "Alle har møtt!") } users={ usersRegistered } />
                <UserList title={ (usersRegistered.length > 0 ? usersListed.length + " har ikke møtt" : "Ingen har møtt") } users={ usersListed } />
                <UserList title="Venteliste" empty="Ingen på venteliste" users={ usersWaiting } />

        );
    }
});

ReactDOM.render(
    <UserLists />,
    document.querySelector('#options')
);
<|endoftext|>


<commit_before>/*global
	DATA_POWERTIP:true
	DATA_POWERTIPJQ:true
	DATA_POWERTIPTARGET:true
	session:true
	Collision:true
	isSvgElement:true
	initTracking:true
	trackMouse:true
	isMouseOver:true
	getTooltipContent:true
	getViewportCollisions:true
	countFlags:true*/
$(function() {
	'use strict';

	module('Utility Functions');

	test('isSvgElement', function() {
		var div = $('
'),
			rect = $(document.createElementNS('http://www.w3.org/2000/svg', 'rect'));

		strictEqual(isSvgElement(rect), true, 'rect is an SVG element');
		strictEqual(isSvgElement(div), false, 'div is not an SVG element');
	});

	test('initTracking', function() {
		session.currentX = 1;
		session.currentY = 1;

		initTracking();

		$(document).trigger($.Event('mousemove', { pageX: 2, pageY: 3 }));

		strictEqual(session.currentX, 2, 'currentX updated with correct value on mousemove');
		strictEqual(session.currentY, 3, 'currentY updated with correct value on mousemove');
	});

	test('trackMouse', function() {
		session.currentX = 1;
		session.currentY = 1;

		trackMouse($.Event('mousemove', { pageX: 4, pageY: 5 }));

		strictEqual(session.currentX, 4, 'currentX updated with correct value on mousemove');
		strictEqual(session.currentY, 5, 'currentY updated with correct value on mousemove');
	});

	test('isMouseOver', function() {
		var div = $('
')
			.css({
				position: 'absolute',
				top: '10px',
				left: '30px',
				width: '50px',
				height: '20px'
			})
			.appendTo('body');

		session.currentX = 30;
		session.currentY = 10;
		ok(isMouseOver(div), 'top/left hover detected');

		session.currentX = 55;
		session.currentY = 15;
		ok(isMouseOver(div), 'center hover detected');

		session.currentX = 80;
		session.currentY = 30;
		ok(isMouseOver(div), 'bottom/right hover detected');

		session.currentX = 9;
		session.currentY = 29;
		ok(!isMouseOver(div), 'no hover detected');

		session.currentX = 81;
		session.currentY = 31;
		ok(!isMouseOver(div), 'no hover detected');

		div.remove();
	});

	test('getTooltipContent', function() {
		var powertip = $('
').data(DATA_POWERTIP, 'powertip'),
			powertipFunc = $('
').data(DATA_POWERTIP, function() { return 'powertipFunc'; }),
			jqObject = $('
powertipjq
'),
			powertipjq = $('
').data(DATA_POWERTIPJQ, jqObject),
			powertipjqFunc = $('
').data(DATA_POWERTIPJQ, function() { return jqObject; }),
			powertiptarget = $('
').data(DATA_POWERTIPTARGET, 'tiptargettest'),
			targetDiv = $('
').attr('id', 'tiptargettest').text('tiptargettest');

		// add powertiptarget to body
		targetDiv.appendTo($('body'));

		strictEqual(getTooltipContent(powertip), 'powertip', 'data-powertip text parsed');
		strictEqual(getTooltipContent(powertipFunc), 'powertipFunc', 'data-powertip function parsed');
		strictEqual(getTooltipContent(powertipjq).find('b').text(), 'powertipjq', 'data-powertipjq object parsed');
		strictEqual(getTooltipContent(powertipjqFunc).find('b').text(), 'powertipjq', 'data-powertipjq function parsed');
		strictEqual(getTooltipContent(powertiptarget), 'tiptargettest', 'data-powertiptarget reference parsed');

		// remove target test div
		targetDiv.remove();
	});

	test('countFlags', function() {
		var zero = Collision.none,
			one = Collision.top,
			two = Collision.top | Collision.left,
			three = Collision.top | Collision.left | Collision.right,
			four = Collision.top | Collision.left | Collision.right | Collision.bottom;

		strictEqual(countFlags(zero), 0, 'Found zero flags.');
		strictEqual(countFlags(one), 1, 'Found one flag.');
		strictEqual(countFlags(two), 2, 'Found two flags.');
		strictEqual(countFlags(three), 3, 'Found three flags.');
		strictEqual(countFlags(four), 4, 'Found four flags.');
	});

	test('getViewportCollisions', function() {
		var windowWidth = $(window).width(),
			windowHeight = $(window).height(),
			none, right, bottom, bottomRight, top, left, topLeft;

		function doTests() {
			ok(none === Collision.none, 'no collisions detected');
			ok(countFlags(right) === 1 && (right & Collision.right) === Collision.right, 'right collision detected');
			ok(countFlags(bottom) === 1 && (bottom & Collision.bottom) === Collision.bottom, 'bottom collision detected');
			ok(countFlags(bottomRight) === 2 && (bottomRight & Collision.bottom) === Collision.bottom && (bottomRight & Collision.right) === Collision.right, 'bottom right collision detected');
			ok(countFlags(top) === 1 && (top & Collision.top) === Collision.top, 'top collision detected');
			ok(countFlags(left) === 1 && (left & Collision.left) === Collision.left, 'left collision detected');
			ok(countFlags(topLeft) === 2 && (topLeft & Collision.top) === Collision.top && (topLeft & Collision.left) === Collision.left, 'top left collision detected');
		}

		// need to make sure initTracking() has been invoked to populate the
		// viewport dimensions cache
		initTracking();

		// top/left placement
		none = getViewportCollisions({ top: 0, left: 0 }, 200, 100);
		right = getViewportCollisions({ top: 0, left: windowWidth - 199 }, 200, 100);
		bottom = getViewportCollisions({ top: windowHeight - 99, left: 0 }, 200, 100);
		bottomRight = getViewportCollisions({ top: windowHeight - 99, left: windowWidth - 199 }, 200, 100);
		top = getViewportCollisions({ top: -1, left: 0 }, 200, 100);
		left = getViewportCollisions({ top: 0, left: -1 }, 200, 100);
		topLeft = getViewportCollisions({ top: -1, left: -1 }, 200, 100);

		doTests();

		// top/right placement
		none = getViewportCollisions({ top: 0, right: 0 }, 200, 100);
		right = getViewportCollisions({ top: 0, right: -1 }, 200, 100);
		bottom = getViewportCollisions({ top: windowHeight - 99, right: 0 }, 200, 100);
		bottomRight = getViewportCollisions({ top: windowHeight - 99, right: -1 }, 200, 100);
		top = getViewportCollisions({ top: -1, right: 0 }, 200, 100);
		left = getViewportCollisions({ top: 0, right: windowWidth - 199 }, 200, 100);
		topLeft = getViewportCollisions({ top: -1, right: windowWidth - 199 }, 200, 100);

		doTests();
	});

});
<commit_msg>Split getViewportCollisions() test assertions.<commit_after>/*global
	DATA_POWERTIP:true
	DATA_POWERTIPJQ:true
	DATA_POWERTIPTARGET:true
	session:true
	Collision:true
	isSvgElement:true
	initTracking:true
	trackMouse:true
	isMouseOver:true
	getTooltipContent:true
	getViewportCollisions:true
	countFlags:true*/
$(function() {
	'use strict';

	module('Utility Functions');

	test('isSvgElement', function() {
		var div = $('
'),
			rect = $(document.createElementNS('http://www.w3.org/2000/svg', 'rect'));

		strictEqual(isSvgElement(rect), true, 'rect is an SVG element');
		strictEqual(isSvgElement(div), false, 'div is not an SVG element');
	});

	test('initTracking', function() {
		session.currentX = 1;
		session.currentY = 1;

		initTracking();

		$(document).trigger($.Event('mousemove', { pageX: 2, pageY: 3 }));

		strictEqual(session.currentX, 2, 'currentX updated with correct value on mousemove');
		strictEqual(session.currentY, 3, 'currentY updated with correct value on mousemove');
	});

	test('trackMouse', function() {
		session.currentX = 1;
		session.currentY = 1;

		trackMouse($.Event('mousemove', { pageX: 4, pageY: 5 }));

		strictEqual(session.currentX, 4, 'currentX updated with correct value on mousemove');
		strictEqual(session.currentY, 5, 'currentY updated with correct value on mousemove');
	});

	test('isMouseOver', function() {
		var div = $('
')
			.css({
				position: 'absolute',
				top: '10px',
				left: '30px',
				width: '50px',
				height: '20px'
			})
			.appendTo('body');

		session.currentX = 30;
		session.currentY = 10;
		ok(isMouseOver(div), 'top/left hover detected');

		session.currentX = 55;
		session.currentY = 15;
		ok(isMouseOver(div), 'center hover detected');

		session.currentX = 80;
		session.currentY = 30;
		ok(isMouseOver(div), 'bottom/right hover detected');

		session.currentX = 9;
		session.currentY = 29;
		ok(!isMouseOver(div), 'no hover detected');

		session.currentX = 81;
		session.currentY = 31;
		ok(!isMouseOver(div), 'no hover detected');

		div.remove();
	});

	test('getTooltipContent', function() {
		var powertip = $('
').data(DATA_POWERTIP, 'powertip'),
			powertipFunc = $('
').data(DATA_POWERTIP, function() { return 'powertipFunc'; }),
			jqObject = $('
powertipjq
'),
			powertipjq = $('
').data(DATA_POWERTIPJQ, jqObject),
			powertipjqFunc = $('
').data(DATA_POWERTIPJQ, function() { return jqObject; }),
			powertiptarget = $('
').data(DATA_POWERTIPTARGET, 'tiptargettest'),
			targetDiv = $('
').attr('id', 'tiptargettest').text('tiptargettest');

		// add powertiptarget to body
		targetDiv.appendTo($('body'));

		strictEqual(getTooltipContent(powertip), 'powertip', 'data-powertip text parsed');
		strictEqual(getTooltipContent(powertipFunc), 'powertipFunc', 'data-powertip function parsed');
		strictEqual(getTooltipContent(powertipjq).find('b').text(), 'powertipjq', 'data-powertipjq object parsed');
		strictEqual(getTooltipContent(powertipjqFunc).find('b').text(), 'powertipjq', 'data-powertipjq function parsed');
		strictEqual(getTooltipContent(powertiptarget), 'tiptargettest', 'data-powertiptarget reference parsed');

		// remove target test div
		targetDiv.remove();
	});

	test('countFlags', function() {
		var zero = Collision.none,
			one = Collision.top,
			two = Collision.top | Collision.left,
			three = Collision.top | Collision.left | Collision.right,
			four = Collision.top | Collision.left | Collision.right | Collision.bottom;

		strictEqual(countFlags(zero), 0, 'Found zero flags.');
		strictEqual(countFlags(one), 1, 'Found one flag.');
		strictEqual(countFlags(two), 2, 'Found two flags.');
		strictEqual(countFlags(three), 3, 'Found three flags.');
		strictEqual(countFlags(four), 4, 'Found four flags.');
	});

	test('getViewportCollisions', function() {
		var windowWidth = $(window).width(),
			windowHeight = $(window).height(),
			none, right, bottom, bottomRight, top, left, topLeft;

		function doTests() {
			strictEqual(none, Collision.none, 'no collisions detected');
			strictEqual(countFlags(right), 1, 'exactly one collision detected for right test');
			strictEqual(right & Collision.right, Collision.right, 'right collision detected for right test');
			strictEqual(countFlags(bottom), 1, 'exactly one collision detected for bottom test');
			strictEqual(bottom & Collision.bottom, Collision.bottom, 'bottom collision detected for bottom test');
			strictEqual(countFlags(bottomRight), 2, 'exactly two collisions detected for bottom-right test');
			strictEqual(bottomRight & Collision.bottom, Collision.bottom, 'bottom collision detected for bottom-right test');
			strictEqual(bottomRight & Collision.right, Collision.right, 'right collision detected for bottom-right test');
			strictEqual(countFlags(top), 1, 'exactly one collision detected for top test');
			strictEqual(top & Collision.top, Collision.top, 'top collision detected for top test');
			strictEqual(countFlags(left), 1, 'exactly one collision detected for left test');
			strictEqual(left & Collision.left, Collision.left, 'left collision detected for left test');
			strictEqual(countFlags(topLeft), 2, 'exactly two collisions detected for top-left test');
			strictEqual(topLeft & Collision.top, Collision.top, 'top collision detected for top-left test');
			strictEqual(topLeft & Collision.left, Collision.left, 'left collision detected for top-left test');
		}

		// need to make sure initTracking() has been invoked to populate the
		// viewport dimensions cache
		initTracking();

		// top/left placement
		none = getViewportCollisions({ top: 0, left: 0 }, 200, 100);
		right = getViewportCollisions({ top: 0, left: windowWidth - 199 }, 200, 100);
		bottom = getViewportCollisions({ top: windowHeight - 99, left: 0 }, 200, 100);
		bottomRight = getViewportCollisions({ top: windowHeight - 99, left: windowWidth - 199 }, 200, 100);
		top = getViewportCollisions({ top: -1, left: 0 }, 200, 100);
		left = getViewportCollisions({ top: 0, left: -1 }, 200, 100);
		topLeft = getViewportCollisions({ top: -1, left: -1 }, 200, 100);

		doTests();

		// top/right placement
		none = getViewportCollisions({ top: 0, right: 0 }, 200, 100);
		right = getViewportCollisions({ top: 0, right: -1 }, 200, 100);
		bottom = getViewportCollisions({ top: windowHeight - 99, right: 0 }, 200, 100);
		bottomRight = getViewportCollisions({ top: windowHeight - 99, right: -1 }, 200, 100);
		top = getViewportCollisions({ top: -1, right: 0 }, 200, 100);
		left = getViewportCollisions({ top: 0, right: windowWidth - 199 }, 200, 100);
		topLeft = getViewportCollisions({ top: -1, right: windowWidth - 199 }, 200, 100);

		doTests();
	});

});
<|endoftext|>


<commit_before>// ==ClosureCompiler==
// @output_file_name gee.min.js
// @compilation_level ADVANCED_OPTIMIZATIONS
// ==/ClosureCompiler==
window['GEE'] = function(params) {

	if ( !params ) {
		params = {};
	}

	// Do we support canvas?
	if ( !document.createElement('canvas').getContext ) {
		if ( params.fallback ) {
			params.fallback();
		}
		return;
	}

	var _this = this,
	_keysDown = {},
	_privateParts =
	{
		'ctx':		    undefined,
		'domElement':   undefined,
		'width':	    undefined,
		'height':	    undefined,
		'desiredFrameTime':    1E3/60,
		'frameCount':   0,
		'key':	        undefined,
		'keyCode':      undefined,
		'mouseX':       0,
		'mouseY':       0,
		'pmouseX':	    undefined,
		'pmouseY':	    undefined,
		'mousePressed': false
	},
	_actualFrameTime = undefined,
	d; // shorthand for the dom element

	var getOffset = function() {
		var obj = d;
		var x = 0, y = 0;
		while (obj) {
			y += obj.offsetTop;
			x += obj.offsetLeft;
			obj = obj.offsetParent;
		}
		offset = { x:x, y:y };
	};
	// Default parameters

	if ( !params['context'] ) {
		params['context'] = '2d';
	}

	if ( !params['width'] ) {
		params['width'] = 500;
	}

	if ( !params['height'] ) {
		params['height'] = 500;
	}

	// Create domElement, grab context

	d = _privateParts['domElement'] = document.createElement('canvas');
	_privateParts['ctx'] = d.getContext( params['context'] );

	// Are we capable of this context?

	if ( _privateParts['ctx'] == null) {
		if ( params.fallback ) {
			params.fallback();
		}
		return;
	}

	// Set up width and height setters / listeners
	var getter = function(n) {
		Object.defineProperty(_this, n, {get: function() {
				return _privateParts[n];
			}});
	};
	if ( params['fullscreen'] ) {

		var onResize = function() {
			getOffset();
			_privateParts['width'] = d['width'] = window.innerWidth;
			_privateParts['height'] = d['height'] = window.innerHeight;
		};
		window.addEventListener( 'resize', onResize, false );
		onResize();

		if ( !params['container'] ) {
			params['container'] = document['body'];
		}
		document.body.style.margin = '0px';
		document.body.style.padding = '0px';
		document.body.style.overflow = 'hidden';

		getter('width');
		getter('height');
	} else {
		getOffset();
		Object.defineProperty(_this,"width", {get : function() {
				return _privateParts['width']
			}, set : function(v) {
				_privateParts['width'] = d['width'] = v;
			}});
		Object.defineProperty(_this,"height", {get : function() {
				return _privateParts['height']
			}, set : function(v) {
				_privateParts['height'] = d['height'] = v;
			}});
		_this['width'] = params['width'];
		_this['height'] = params['height'];
	}

	// Put it where we talked about (if we talked about it).
	if ( params['container'] ) {
		params['container'].appendChild(d);
		getOffset();
	}

	// Would love to reduce this to params.
	getter('ctx');
	getter('frameCount');
	getter('key');
	getter('keyCode');
	getter('mouseX');
	getter('mouseY');
	getter('pmouseX');
	getter('pmouseY');
	getter('mousePressed');

	var n = function() {
	};
	// TODO: Ensure data type
	_this['loop'] = true;

	// TODO: Ensure data type
	_this['keyup'] = n;
	_this['keydown'] = n;
	_this['draw'] = n;
	_this['mousedown'] = n;
	_this['mouseup'] = n;
	_this['mousemove'] = n;
	_this['mousedrag'] = n;

	// Custom Getters & Setters
	Object.defineProperty(_this, 'frameRate', {
		get: function() {
			return 1E3/_actualFrameTime;
		},
		set : function(v) {
			_privateParts['desiredFrameTime'] = k/v;
		}
	});

	Object.defineProperty(_this, 'frameTime', {
		get: function() {
			return _actualFrameTime;
		},
		set : function(v) {
			_privateParts['desiredFrameTime'] = v;
		}
	});

	Object.defineProperty(_this, 'keyPressed', {
		get: function() {
			for (var i in _keysDown) {
				if (_keysDown[i]) {
					return true;
				}
			}
			return false;
		}
	});
	// Listeners

	d.addEventListener('mouseenter', function(e) {
		getOffset();
	}, false);
	var fireMouseMove = function(e) {
		_this['mousemove']();
	};
	var updateMousePosition = function(e) {
		var x = e.pageX - offset.x;
		var y = e.pageY - offset.y;
		if (_privateParts['pmouseX'] == undefined) {
			_privateParts['pmouseX'] = x;
			_privateParts['pmouseY'] = y;
		} else {
			_privateParts['pmouseX'] = _privateParts['mouseX'];
			_privateParts['pmouseY'] = _privateParts['mouseY'];
		}
		_privateParts['mouseX'] = x;
		_privateParts['mouseY'] = y;
	}
	d.addEventListener('mousemove', updateMousePosition, false);
	d.addEventListener('mousemove', fireMouseMove, false);

	d.addEventListener('mousedown', function() {
		_privateParts['mousePressed'] = true;
		_this['mousedown']();
		d.addEventListener('mousemove', _this['mousedrag'], false);
		d.removeEventListener('mousemove', fireMouseMove, false);
	}, false);
	d.addEventListener('mouseup', function() {
		_privateParts['mousePressed'] = false;
		_this['mouseup']();
		d['removeEventListener']('mousemove', _this['mousedrag'], false);
		d.addEventListener('mousemove', fireMouseMove, false);
	}, false);
	window.addEventListener('keydown', function(e) {
		var kc = e.keyCode;
		_privateParts['key'] = String.fromCharCode(kc); // Kinda busted.
		_privateParts['keyCode'] = kc;
		_keysDown[kc] = true;
		_this['keydown']();
	}, false);
	window.addEventListener('keyup', function(e) {
		var kc = e.keyCode;
		_privateParts['key'] = String.fromCharCode(kc); // Kinda busted.
		_privateParts['keyCode'] = kc;
		_keysDown[kc] = false;
		_this['keyup']();
	}, false);
	// Internal loop.

	var requestAnimationFrame = (function() {
		return  window.requestAnimationFrame       ||
		window.webkitRequestAnimationFrame ||
		window.mozRequestAnimationFrame    ||
		window.oRequestAnimationFrame      ||
		window.msRequestAnimationFrame     ||
		function (callback) {
			window.setTimeout(callback, _actualFrameTime);
		};

	})();
	_idraw = function() {

		if ( _this['loop'] ) {
			requestAnimationFrame( _idraw );
		}

		_privateParts['frameCount']++;
		var prev = new Date().getTime();

		_this['draw']();

		var delta = new Date().getTime() - prev;

		if (delta > _privateParts['desiredFrameTime']) {
			_actualFrameTime = delta;
		} else {
			_actualFrameTime = _privateParts['desiredFrameTime'];
		}

	};
	_idraw();

}<commit_msg>Delete gee.js<commit_after><|endoftext|>


<commit_before>var mapzen = mapzen || {};
mapzen.whosonfirst = mapzen.whosonfirst || {};

mapzen.whosonfirst.spelunker = (function(){

	var self = {

	    // this is invoked by by mapzen.whosonfirst.spelunker.init.js
	    // which is running code (20160202/thisisaaronland)

	    'init': function(){
		mapzen.whosonfirst.config.init();
	    },

	    'abs_root_url': function(){
		var body = document.body;
		return body.getAttribute("data-abs-root-url");
	    },

	    'draw_list': function(classname){

		var locs = document.getElementsByClassName(classname);
			var count = locs.length;

			var swlat = undefined;
			var swlon = undefined;
			var nelat = undefined;
			var nelon = undefined;

			var features = [];

			for (var i=0; i < count; i++){

				var loc = locs[i];
				var lat = loc.getAttribute("data-latitude");
				var lon = loc.getAttribute("data-longitude");
				var id = loc.getAttribute("data-id");

				var anchor = loc.getElementsByTagName("a");
				anchor = anchor[0];
				var name = anchor.textContent;

				if ((! swlat) || (lat < swlat)){
					swlat = lat;
				}

				if ((! swlon) || (lat < swlon)){
					swlon = lon;
				}

				if ((! nelat) || (lat > nelat)){
					nelat = lat;
				}

				if ((! nelon) || (lat < nelon)){
					nelon = lon;
				}

				var geom = { 'type': 'Point', 'coordinates': [ lon, lat ] };
				var props = { 'lflt:label_text': name, 'wof:id': id };

				var feature = {'type': 'Feature', 'geometry': geom, 'properties': props, 'id': id };
				features.push(feature);
			}

		console.log(swlat);
		console.log(swlon);
		console.log(nelat);
		console.log(nelon);

			var geojson = { 'type': 'FeatureCollection', 'features': features };

			var map = mapzen.whosonfirst.leaflet.tangram.map_with_bbox('map', swlat, swlon, nelat, nelon);

			var style = mapzen.whosonfirst.leaflet.styles.search_centroid();
			var handler = mapzen.whosonfirst.leaflet.handlers.point(style);

			var oneach = function(feature, layer){
				layer.on('click', function(e){
					var props = feature['properties'];
					var id = props['wof:id'];
					id = encodeURIComponent(id);
					var root = mapzen.whosonfirst.spelunker.abs_root_url();
					var url = root + "id/" + id + "/";
					location.href = url;
				});
			};

			var layer = L.geoJson(geojson, {
				'style': style,
				'pointToLayer': handler,
				'onEachFeature': oneach,
			});

			layer.addTo(map);
		},

		'draw_names': function(cls){

			var locs = document.getElementsByClassName(cls);
			var count = locs.length;

			for (var i=0; i < count; i++){

				var loc = locs[i];
				var id = loc.getAttribute("data-value");

				if (! id){
					continue;
				}

				var url = mapzen.whosonfirst.data.id2abspath(id);

				var cb = function(feature){
					var props = feature['properties'];
					var name = props['wof:name'];
					var id = props['wof:id'];

					var cls_id = cls + "_" + id;

					mapzen.whosonfirst.log.info("assign name for ID " + id + " to be " + name + " for " + cls_id);

					var els = document.getElementsByClassName(cls_id);
					var count_els = els.length;

					for (var j=0; j < count_els; j++){
						var el = els[j];
						el.innerHTML = mapzen.whosonfirst.php.htmlspecialchars(name) + " " + mapzen.whosonfirst.php.htmlspecialchars(id) + "";
					}
				};

				mapzen.whosonfirst.net.fetch(url, cb);
			}
		},

	};

	return self;
})();
<commit_msg>debug<commit_after>var mapzen = mapzen || {};
mapzen.whosonfirst = mapzen.whosonfirst || {};

mapzen.whosonfirst.spelunker = (function(){

	var self = {

	    // this is invoked by by mapzen.whosonfirst.spelunker.init.js
	    // which is running code (20160202/thisisaaronland)

	    'init': function(){
		mapzen.whosonfirst.config.init();
	    },

	    'abs_root_url': function(){
		var body = document.body;
		return body.getAttribute("data-abs-root-url");
	    },

	    'draw_list': function(classname){

		var locs = document.getElementsByClassName(classname);
			var count = locs.length;

			var swlat = undefined;
			var swlon = undefined;
			var nelat = undefined;
			var nelon = undefined;

			var features = [];

			for (var i=0; i < count; i++){

				var loc = locs[i];
				var lat = loc.getAttribute("data-latitude");
				var lon = loc.getAttribute("data-longitude");
				var id = loc.getAttribute("data-id");

				var anchor = loc.getElementsByTagName("a");
				anchor = anchor[0];
				var name = anchor.textContent;

				if ((! swlat) || (lat < swlat)){
					swlat = lat;
				}

				if ((! swlon) || (lat < swlon)){
					swlon = lon;
				}

				if ((! nelat) || (lat > nelat)){
					nelat = lat;
				}

				if ((! nelon) || (lat < nelon)){
					nelon = lon;
				}

				var geom = { 'type': 'Point', 'coordinates': [ lon, lat ] };
				var props = { 'lflt:label_text': name, 'wof:id': id };

				var feature = {'type': 'Feature', 'geometry': geom, 'properties': props, 'id': id };
				features.push(feature);
			}

			if (swlat == 0.0 and swlon == 0.0. and nelat == 0.0 and nelon == 0.0){
			    console.log("NULL ISLAND!");
			}

			var geojson = { 'type': 'FeatureCollection', 'features': features };

			var map = mapzen.whosonfirst.leaflet.tangram.map_with_bbox('map', swlat, swlon, nelat, nelon);

			var style = mapzen.whosonfirst.leaflet.styles.search_centroid();
			var handler = mapzen.whosonfirst.leaflet.handlers.point(style);

			var oneach = function(feature, layer){
				layer.on('click', function(e){
					var props = feature['properties'];
					var id = props['wof:id'];
					id = encodeURIComponent(id);
					var root = mapzen.whosonfirst.spelunker.abs_root_url();
					var url = root + "id/" + id + "/";
					location.href = url;
				});
			};

			var layer = L.geoJson(geojson, {
				'style': style,
				'pointToLayer': handler,
				'onEachFeature': oneach,
			});

			layer.addTo(map);
		},

		'draw_names': function(cls){

			var locs = document.getElementsByClassName(cls);
			var count = locs.length;

			for (var i=0; i < count; i++){

				var loc = locs[i];
				var id = loc.getAttribute("data-value");

				if (! id){
					continue;
				}

				var url = mapzen.whosonfirst.data.id2abspath(id);

				var cb = function(feature){
					var props = feature['properties'];
					var name = props['wof:name'];
					var id = props['wof:id'];

					var cls_id = cls + "_" + id;

					mapzen.whosonfirst.log.info("assign name for ID " + id + " to be " + name + " for " + cls_id);

					var els = document.getElementsByClassName(cls_id);
					var count_els = els.length;

					for (var j=0; j < count_els; j++){
						var el = els[j];
						el.innerHTML = mapzen.whosonfirst.php.htmlspecialchars(name) + " " + mapzen.whosonfirst.php.htmlspecialchars(id) + "";
					}
				};

				mapzen.whosonfirst.net.fetch(url, cb);
			}
		},

	};

	return self;
})();
<|endoftext|>


<commit_before>import buildcss from '../utils/buildcss';

const prod = done => buildcss('prod')(done);

prod.displayName = 'prod';
prod.description = 'Build flexboxgrid CSS';
prod.flags = { '--debug': 'Build debug CSS' };
prod.flags = { '--split': 'Split flexboxgrid into individual breakpoints' };

export default prod;
<commit_msg>Fixed prod debug flag<commit_after>import buildcss from '../utils/buildcss';

const prod = done => buildcss('prod')(done);

prod.displayName = 'prod';
prod.description = 'Build flexboxgrid CSS';
prod.flags = {
	'--split': 'Split flexboxgrid into individual breakpoints',
	'--debug': 'Build debug CSS',
};

export default prod;
<|endoftext|>


<commit_before>(function () {

    // Implement routing based on riot.route

    app(function (api) {

        // Add a delegated event listener to the root element defined by the app init.
        // This listens to all clicks and triggers riot.route(TO) only if the target
        // element has "data-goto" attribute beginning with "#/".
        api.args.root.addEventListener("click", function (e) {

            var target = e.target;

            while(typeof target.dataset.goto === "undefined") {
                target = target.parentNode;
            }

            var goto = target.dataset.goto;

            if (goto && goto.indexOf("#/") === 0) {
                e.preventDefault();
                riot.route(goto);
            } else if (goto && goto === "back") {
                api.pushhistory = false;
                riot.route("#/" + api.history.pop());
            }

            // Memory cleanup
            goto = target = null;

        }, false);

        // Next, listen to riot.route(fn), which will trigger the things we need to do
        // to actually perform what happens when a new page is called. For now, we just
        // do api.trigger("load:" + url)
        riot.route(function (path) {
            api.load(path.substr(2));
            api.pushhistory = true;
        });

        /**
         * Before load hook for views
         */
        api.on("before:load", function (next) {
            var prev = $("#" + api.view.split("/")[0]);
            next = $("#" + next.split("/")[0]);

            prev && prev.classList.remove("active-view");
            next && next.classList.add("active-view");

            // Memory cleanup
            prev = next = null;
        });

    });

})();
<commit_msg>Check if target.dataset is set in route call<commit_after>(function () {

    // Implement routing based on riot.route

    app(function (api) {

        // Add a delegated event listener to the root element defined by the app init.
        // This listens to all clicks and triggers riot.route(TO) only if the target
        // element has "data-goto" attribute beginning with "#/".
        api.args.root.addEventListener("click", function (e) {

            var target = e.target;

            while(target.dataset && typeof target.dataset.goto === "undefined") {
                target = target.parentNode;
            }

            var goto = target.dataset && target.dataset.goto;

            if (goto && goto.indexOf("#/") === 0) {
                e.preventDefault();
                riot.route(goto);
            } else if (goto && goto === "back") {
                api.pushhistory = false;
                riot.route("#/" + api.history.pop());
            }

            // Memory cleanup
            goto = target = null;

        }, false);

        // Next, listen to riot.route(fn), which will trigger the things we need to do
        // to actually perform what happens when a new page is called. For now, we just
        // do api.trigger("load:" + url)
        riot.route(function (path) {
            api.load(path.substr(2));
            api.pushhistory = true;
        });

        /**
         * Before load hook for views
         */
        api.on("before:load", function (next) {
            var prev = $("#" + api.view.split("/")[0]);
            next = $("#" + next.split("/")[0]);

            prev && prev.classList.remove("active-view");
            next && next.classList.add("active-view");

            // Memory cleanup
            prev = next = null;
        });

    });

})();
<|endoftext|>


<commit_before>
/*================================================================
This plugin allows you to control your viewing experience directly from your mouse while watching on your computer browser. See below for a list of all supported mouse commands.

Right button click - Toggle Play / Pause
Wheel click - Toggle Full-screen toggle
Wheel scrolling - Volume Up / Down
Wheel scrolling with holding left button - Subtitles Bigger / Lower (this settings is remembered in cookie)
Wheel scrolling with holding right button - Rewind / Forward

================================================================*/

// ==UserScript==
// @name         netflix-hot-mouse
// @version      0.9
// @description  tool increasing UX while using mouse in netflix web app
// @author       Michał Najman (https://github.com/michalnajman)
// @include      https://*netflix.com*
// @grant        none
// ==/UserScript==

(function netflixHotMouse() {
    "use strict";

    // get jQuery for DOM manipulation
    let script = document.createElement("script");
    script.src = "https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js";
    script.type = "text/javascript";
    script.onload = function onload() {

        $(document).ready(function onDocumentReady() {

            /////////////////////////////////////////////////////////////////////////////////
            // HELPER FUNCTIONS
            /////////////////////////////////////////////////////////////////////////////////

            let helper = {
                createCookie: function(name, value) {

                    let date = new Date();
                    date.setTime(date.getTime() + (365 * 24 * 60 * 60 * 1000));
                    let expires = "; expires=" + date.toGMTString();

                    document.cookie = name + "=" + value + expires + "; path=/";
                },

                getCookie: function(name) {
                    let nameEq = name + "=";
                    let ca = document.cookie.split(";");
                    for (let i = 0; i < ca.length; i++) {
                        let c = ca[i];
                        while (c.charAt(0) === " ") c = c.substring(1, c.length);
                        if (c.indexOf(nameEq) === 0) return c.substring(nameEq.length, c.length);
                    }
                    return null;
                },

                addHeadStyle: function(style) {
                    $("head").append(`<style type='text/css'>${style}</style>`);
                },

                log: function(key, value) {
                    console.log(`[netflix-hot-mouse] ${key}: ${value}`);
                },

                triggerKeyDownEvent: function(k) {

                    let oEvent = document.createEvent("KeyboardEvent");

                    // Chromium Hack
                    Object.defineProperty(oEvent, "keyCode", {
                        get: function() {
                            return this.keyCodeVal;
                        }
                    });
                    Object.defineProperty(oEvent, "which", {
                        get: function() {
                            return this.keyCodeVal;
                        }
                    });

                    if (oEvent.initKeyboardEvent) {
                        oEvent.initKeyboardEvent("keydown", true, true, document.defaultView, false, false, false, false, k, k);
                    } else {
                        oEvent.initKeyEvent("keydown", true, true, document.defaultView, false, false, false, false, k, 0);
                    }

                    oEvent.keyCodeVal = k;

                    if (oEvent.keyCode !== k) {
                        console.log("keyCode mismatch " + oEvent.keyCode + "(" + oEvent.which + ")");
                    }

                    document.dispatchEvent(oEvent);
                }
            };

            /////////////////////////////////////////////////////////////////////////////////
            // EVENT HANDLERS
            /////////////////////////////////////////////////////////////////////////////////

            function createHandlers({ onMouseRightButtonClick, onMouseWheel, onMouseWheelButtonClick } = {}) {

                let ignoreRightButtonMouseUp = false,
                    pressedMouseButtonIndex = null;

                $(window).on("mousedown", e => {

                    pressedMouseButtonIndex = null;
                    if (e.which === 1) {
                        pressedMouseButtonIndex = 1;
                    } else if (e.which === 2) {
                        onMouseWheelButtonClick();
                    } else if (e.which === 3) {
                        pressedMouseButtonIndex = 3;
                    }
                }).on("mouseup", e => {

                    if (!ignoreRightButtonMouseUp && e.which === 3) {
                        onMouseRightButtonClick();
                    }

                    pressedMouseButtonIndex = 0;
                    ignoreRightButtonMouseUp = false;

                }).on("mousewheel DOMMouseScroll", e => {

                    let originalDeltaY = e.originalEvent.wheelDeltaY,
                        detail = e.originalEvent.detail,
                        deltaY = e.deltaY,
                        direction = (originalDeltaY < 0 || detail > 0 || deltaY < 0) ? -1 : 1;

                    ignoreRightButtonMouseUp = true;

                    onMouseWheel(direction, pressedMouseButtonIndex);
                    return false;
                });
            }

            /////////////////////////////////////////////////////////////////////////////////
            // MAIN LOGIC
            /////////////////////////////////////////////////////////////////////////////////

            function createLogic({ fontChangeQuantum }) {

                function playToggle() {
                    $(".icon-player-pause, .icon-player-play").trigger("click");
                    helper.log("Play/pause", "toggled");
                }

                function changeSubtitlesSize(direction) {

                    let cookieName = "subtitles-size",
                        cookieSubtitlesSize = parseInt(helper.getCookie(cookieName)) || 32; // default value

                    cookieSubtitlesSize += (direction * fontChangeQuantum);

                    if (cookieSubtitlesSize < 0) {
                        cookieSubtitlesSize = 0;
                    }

                    helper.createCookie(cookieName, cookieSubtitlesSize);
                    helper.addHeadStyle(`.player-timedtext span { font-size : ${cookieSubtitlesSize}px !important; }`);
                    helper.log("Subtitles", cookieSubtitlesSize);
                }

                function changeVolume(direction) {

                    direction > 0 ?
                        helper.triggerKeyDownEvent(38) : // up
                        helper.triggerKeyDownEvent(40); // down

                    helper.log("Volume", `direction: ${direction}`);
                }

                function fullscreenToggle() {
                    $(".icon-player-full-screen, .icon-player-windowed-screen").trigger("click");
                    helper.log("Fullscreen", "toggled");
                }

                function moveVideo(direction) {

                    direction > 0 ?
                        helper.triggerKeyDownEvent(39) : // forward
                        helper.triggerKeyDownEvent(37); // backward

                    helper.log("Scroll video", `direction: ${direction}`);
                }

                function init() {
                    changeSubtitlesSize(0);

                    return {
                        fullscreenToggle,
                        playToggle,
                        moveVideo,
                        changeSubtitlesSize,
                        changeVolume
                    };
                }

                return {
                    init
                };
            }

            /////////////////////////////////////////////////////////////////////////////////
            // CONSTRUCTOR
            /////////////////////////////////////////////////////////////////////////////////
            (function initialize() {

                let logic = createLogic({
                    fontChangeQuantum: 4
                }).init();

                helper.log("Initialized", "done");

                createHandlers({
                    onMouseRightButtonClick: () => { logic.playToggle(); },
                    onMouseWheel: (direction, pressedMouseButtonIndex) => {
                        switch (pressedMouseButtonIndex) {
                        case 1:
                            logic.changeSubtitlesSize(direction);
                            return;
                        case 3:
                            logic.moveVideo(direction);
                            logic.playToggle();
                            return;
                        default:
                            logic.changeVolume(direction);
                        }
                    },
                    onMouseWheelButtonClick: () => { logic.fullscreenToggle(); }
                });
            }());
        });
    };

    document.getElementsByTagName("head")[0].appendChild(script);

})();
<commit_msg>Delete index.js<commit_after><|endoftext|>


<commit_before>app.directive('inputBox', function ($rootScope, $stateParams, bunkerData, emoticons, keycode) {
	return {
		template: `

					<form class="col-md-10 no-gutter">
						<textarea rows="1" class="form-control"></textarea>
						<button type="submit" class="btn btn-success visible-xs">Send</button>
						<upload-button></upload-button>
					</form>

		`,
		link: function (scope, elem) {
			var searchingFor, searchTerm, matches, suggestedTerm, matchingEmoticons, matchingUsers, matchIndex, hidden;

			var editingMessage;

			var inputBox = $('textarea', elem);
			var container = $('.message-input', elem);
			var send = container.find('button[type="submit"]');
			var popup = $('.message-popup', elem);
			resetMatchSearch();
			resetMessageEditing();

			// anchors are the special keys which define an emoticon or user
			var anchors = {
				'emoticons': ':',
				'users': '@'
			};

			// handlers are triggered when a specific key is pressed
			var handlers = {
				'enter': enter,
				'backspace': backspace,
				'esc': reset,
				'tab': tab,
				'space': space,
				'up': up,
				'down': down,
				';': emoticon,
				'2': user,

				// ignore these keystrokes
				'command': _.noop,
				'alt': _.noop,
				'ctrl': _.noop,
				'shift': _.noop
			};

			// search functions which are triggered when an anchor is used
			var searchers = {
				'emoticons': searchForEmoticons,
				'users': searchForUsers,
				null: _.noop
			};

			// the functions to render the html in the popup
			var render = {
				'emoticons': renderEmoticons,
				'users': renderUsers
			};

			// events

			// every key press in the text area
			inputBox.keydown(e => {
				// gets a human readable keyboard value
				var key = keycode(e);

				var handler = handlers[key];
				if (handler) {
					handler(e);
				}
				else {
					bunkerData.broadcastTyping($rootScope.roomId);
				}

				if (searchingFor) {
					searchers[searchingFor](key);
					var html = render[searchingFor]();
					popup.html(html);

					if (hidden) {
						popup.show();
						popup.on("click", "li", popupClick);
					}
				}
			});

			// Change the text if commanded to do so
			scope.$on('inputText', function (evt, text) {
				var val = inputBox.val();
				var append = val.length ? ' ' : ''; // start with a space if message already started
				append += text + ' ';
				val += append;
				inputBox.val(val);
				inputBox.focus();
			});

			$rootScope.$on('roomIdChanged', () => {
				resetMatchSearch();
				resetMessageEditing();
				inputBox.focus();
			});
			$rootScope.$on('bunkerDataLoaded', () => inputBox.focus());

			// the send button needs to be attached to the enter handler
			send.on("click", enter);

			function popupClick(e) {
				e.stopPropagation();
				e.preventDefault();

				if (!searchingFor) return;

				var item = $(e.currentTarget);
				var value = item.data('value');
				replaceMatch(searchTerm, value);
				selectItem();
				inputBox.focus();
			}

			function reset() {
				if (searchingFor)return resetMatchSearch();
				resetMessageEditing();
			}

			function resetMatchSearch() {
				searchingFor = null;
				searchTerm = "";
				matches = null;
				suggestedTerm = null;
				matchingEmoticons = null;
				matchingUsers = null;
				matchIndex = -1;
				hidden = true;
				popup.unbind("click");
				popup.html('');
				popup.hide();
			}

			function resetMessageEditing() {
				editingMessage = null;
				container.removeClass('edit-mode');
			}

			function selectItem() {
				if (searchingFor == 'emoticons') {
					inputBox.val(inputBox.val() + ':');
				}

				inputBox.val(inputBox.val() + ' ');

				resetMatchSearch();
			}

			function enter(e) {
				e.preventDefault();

				if (editingMessage) {
					editMessage()
				}
				else if (suggestedTerm) {
					selectItem();
				}
				else if (e.shiftKey && bunkerData.userSettings.multilineShiftEnter) {
					inputBox.val(inputBox.val() + '\n');
				}
				else {
					submitMessage();
				}

				reset();
			}

			function editMessage() {
				var text = inputBox.val();
				if (!/\S/.test(text)) return;

				editingMessage.text = text;
				editingMessage.edited = true;
				inputBox.val('');
				bunkerData.editMessage(editingMessage);
			}

			function submitMessage() {
				var text = inputBox.val();
				if (!/\S/.test(text)) return;

				inputBox.val('');

				if (/^\/clear/i.test(text)) {
					// Special command to clear all messages or message from a user
					var nickMatches = /\/clear\s+(.+)/i.exec(text);
					var nick;
					if(nickMatches && nickMatches.length === 2) {
						nick = nickMatches[1].trim();
					}
					bunkerData.clearMessagesFromNick($stateParams.roomId, nick);
				}
				else {
					// Default
					bunkerData.createMessage($stateParams.roomId, text);
				}
			}

			function backspace(e) {
				if (!searchTerm.length) {
					return resetMatchSearch();
				}

				if (suggestedTerm) {
					replaceMatch(suggestedTerm, searchTerm);
					suggestedTerm = null;
					matchIndex = -1;
					e.preventDefault();
					return;
				}

				searchTerm = searchTerm.slice(0, -1);
			}

			function tab(e) {
				e.preventDefault();
				if (!searchingFor) return;

				var oldSuggestion = suggestedTerm || searchTerm;
				suggestedTerm = getNextMatch(e.shiftKey);

				if (!suggestedTerm) return;
				replaceMatch(oldSuggestion, suggestedTerm);
			}

			function space(e) {
				if (suggestedTerm) {
					e.preventDefault();
					return selectItem();
				}

				if (searchingFor == 'emoticons') {
					return resetMatchSearch();
				}
			}

			function up(e) {
				e.preventDefault();
				var messages = getMessages();

				if (!editingMessage) {
					editingMessage = _.last(messages);
				}
				else {
					var currentIndex = _.findIndex(messages, {_id: editingMessage._id});
					console.log(currentIndex);
					if (currentIndex == 0) return;
					editingMessage = messages[currentIndex - 1];
				}

				container.addClass('edit-mode');
				inputBox.val(editingMessage.text);
			}

			function down(e) {
				if (!editingMessage) return resetMessageEditing();

				var messages = getMessages();
				var currentIndex = _.findIndex(messages, {_id: editingMessage._id});
				editingMessage = messages[currentIndex + 1];

				// no more messages
				if (!editingMessage) {
					inputBox.val('');
					return resetMessageEditing();
				}

				inputBox.val(editingMessage.text);
			}

			function getMessages() {
				var currentRoom = bunkerData.getRoom($rootScope.roomId);
				return currentRoom.$messages.filter(message => {
					return message.author && message.author._id == bunkerData.user._id;
				});
			}

			function replaceMatch(oldText, newText) {
				var anchor = anchors[searchingFor];
				var oldSuggestion = `${anchor}${oldText}${anchor}`;

				var suggestionSearch = anchor + newText;

				var currentText = inputBox.val();
				var currentSearch = new RegExp(`${oldSuggestion}*$`);
				currentText = currentText.replace(currentSearch, suggestionSearch);

				inputBox.val(currentText);
			}

			function getNextMatch(shiftKey) {
				matchIndex += shiftKey ? -1 : 1;

				if (matchIndex >= matches.length) {
					matchIndex = 0;
				}

				if (matchIndex < 0) {
					matchIndex = matches.length - 1;
				}

				return matches[matchIndex];
			}

			function emoticon(e) {
				if (!e.shiftKey) return;
				if (searchingFor == 'emoticons') return resetMatchSearch();
				searchingFor = 'emoticons';
			}

			function searchForEmoticons(key) {
				// only allow single letters/numbers/underscores on search term
				var singleLetterNumber = /^[\w\d\_]{1}$/g;
				if (singleLetterNumber.test(key)) {
					searchTerm += key;
				}

				matchingEmoticons = _.filter(emoticons.imageEmoticons, emoticon => emoticon.name.indexOf(searchTerm) == 0);
				matches = _.map(matchingEmoticons, 'name');
			}

			function renderEmoticons() {
				return `

						${_.map(matchingEmoticons, emoticon => `

									:${emoticon.name}:

						`).join('')}

				`
			}

			function user(e) {
				if (!e.shiftKey) return;
				if (searchingFor == 'users') return resetMatchSearch();
				searchingFor = 'users';
			}

			function searchForUsers(key) {
				// only allow single letters/numbers/underscores on search term
				var singleLetterNumber = /^[\w\s\-\.]{1}$/g;
				if (singleLetterNumber.test(key)) {
					searchTerm += key;
				}

				// since the @ key is actually shift + 2, when the search term is this, ignore it
				// since it is the start of looking for a specific user: eg @Jason == 2Jason
				if (searchTerm == '2') {
					searchTerm = '';
				}

				var currentRoom = bunkerData.getRoom($rootScope.roomId);
				var users = _.map(currentRoom.$members, 'user');
				var activeUsers = _.filter(users, user => moment().diff(user.lastConnected, 'days') < 45);

				matchingUsers = _.filter(activeUsers, user => user.nick.toLowerCase().indexOf(searchTerm) == 0);
				matches = _.map(matchingUsers, 'nick');
			}

			function renderUsers() {
				return `

						${_.map(matchingUsers, user => `

									${user.nick}

						`).join('')}

				`
			}
		}
	}
});
<commit_msg>fixed user popup thing<commit_after>app.directive('inputBox', function ($rootScope, $stateParams, bunkerData, emoticons, keycode) {
	return {
		template: `

					<form class="col-md-10 no-gutter">
						<textarea rows="1" class="form-control"></textarea>
						<button type="submit" class="btn btn-success visible-xs">Send</button>
						<upload-button></upload-button>
					</form>

		`,
		link: function (scope, elem) {
			var searchingFor, searchTerm, matches, suggestedTerm, matchingEmoticons, matchingUsers, matchIndex, hidden;

			var editingMessage;

			var inputBox = $('textarea', elem);
			var container = $('.message-input', elem);
			var send = container.find('button[type="submit"]');
			var popup = $('.message-popup', elem);
			resetMatchSearch();
			resetMessageEditing();

			// anchors are the special keys which define an emoticon or user
			var anchors = {
				'emoticons': ':',
				'users': '@'
			};

			// handlers are triggered when a specific key is pressed
			var handlers = {
				'enter': enter,
				'backspace': backspace,
				'esc': reset,
				'tab': tab,
				'space': space,
				'up': up,
				'down': down,
				';': emoticon,
				'2': user,

				// ignore these keystrokes
				'command': _.noop,
				'alt': _.noop,
				'ctrl': _.noop,
				'shift': _.noop
			};

			// search functions which are triggered when an anchor is used
			var searchers = {
				'emoticons': searchForEmoticons,
				'users': searchForUsers,
				null: _.noop
			};

			// the functions to render the html in the popup
			var render = {
				'emoticons': renderEmoticons,
				'users': renderUsers
			};

			// events

			// every key press in the text area
			inputBox.keydown(e => {
				// gets a human readable keyboard value
				var key = keycode(e);

				var handler = handlers[key];
				if (handler) {
					handler(e);
				}
				else {
					bunkerData.broadcastTyping($rootScope.roomId);
				}

				if (searchingFor) {
					searchers[searchingFor](key);
					var html = render[searchingFor]();
					popup.html(html);

					if (hidden) {
						popup.show();
						popup.on("click", "li", popupClick);
					}
				}
			});

			// Change the text if commanded to do so
			scope.$on('inputText', function (evt, text) {
				var val = inputBox.val();
				var append = val.length ? ' ' : ''; // start with a space if message already started
				append += text + ' ';
				val += append;
				inputBox.val(val);
				inputBox.focus();
			});

			$rootScope.$on('roomIdChanged', () => {
				resetMatchSearch();
				resetMessageEditing();
				inputBox.focus();
			});
			$rootScope.$on('bunkerDataLoaded', () => inputBox.focus());

			// the send button needs to be attached to the enter handler
			send.on("click", enter);

			function popupClick(e) {
				e.stopPropagation();
				e.preventDefault();

				if (!searchingFor) return;

				var item = $(e.currentTarget);
				var value = item.data('value');
				replaceMatch(searchTerm, value);
				selectItem();
				inputBox.focus();
			}

			function reset() {
				if (searchingFor)return resetMatchSearch();
				resetMessageEditing();
			}

			function resetMatchSearch() {
				searchingFor = null;
				searchTerm = "";
				matches = null;
				suggestedTerm = null;
				matchingEmoticons = null;
				matchingUsers = null;
				matchIndex = -1;
				hidden = true;
				popup.unbind("click");
				popup.html('');
				popup.hide();
			}

			function resetMessageEditing() {
				editingMessage = null;
				container.removeClass('edit-mode');
			}

			function selectItem() {
				if (searchingFor == 'emoticons') {
					inputBox.val(inputBox.val() + ':');
				}

				inputBox.val(inputBox.val() + ' ');

				resetMatchSearch();
			}

			function enter(e) {
				e.preventDefault();

				if (editingMessage) {
					editMessage()
				}
				else if (suggestedTerm) {
					selectItem();
				}
				else if (e.shiftKey && bunkerData.userSettings.multilineShiftEnter) {
					inputBox.val(inputBox.val() + '\n');
				}
				else {
					submitMessage();
				}

				reset();
			}

			function editMessage() {
				var text = inputBox.val();
				if (!/\S/.test(text)) return;

				editingMessage.text = text;
				editingMessage.edited = true;
				inputBox.val('');
				bunkerData.editMessage(editingMessage);
			}

			function submitMessage() {
				var text = inputBox.val();
				if (!/\S/.test(text)) return;

				inputBox.val('');

				if (/^\/clear/i.test(text)) {
					// Special command to clear all messages or message from a user
					var nickMatches = /\/clear\s+(.+)/i.exec(text);
					var nick;
					if(nickMatches && nickMatches.length === 2) {
						nick = nickMatches[1].trim();
					}
					bunkerData.clearMessagesFromNick($stateParams.roomId, nick);
				}
				else {
					// Default
					bunkerData.createMessage($stateParams.roomId, text);
				}
			}

			function backspace(e) {
				if (!searchTerm.length) {
					return resetMatchSearch();
				}

				if (suggestedTerm) {
					replaceMatch(suggestedTerm, searchTerm);
					suggestedTerm = null;
					matchIndex = -1;
					e.preventDefault();
					return;
				}

				searchTerm = searchTerm.slice(0, -1);
			}

			function tab(e) {
				e.preventDefault();
				if (!searchingFor) return;

				var oldSuggestion = suggestedTerm || searchTerm;
				suggestedTerm = getNextMatch(e.shiftKey);

				if (!suggestedTerm) return;
				replaceMatch(oldSuggestion, suggestedTerm);
			}

			function space(e) {
				if (suggestedTerm) {
					e.preventDefault();
					return selectItem();
				}

				if (searchingFor == 'emoticons') {
					return resetMatchSearch();
				}
			}

			function up(e) {
				e.preventDefault();
				var messages = getMessages();

				if (!editingMessage) {
					editingMessage = _.last(messages);
				}
				else {
					var currentIndex = _.findIndex(messages, {_id: editingMessage._id});
					console.log(currentIndex);
					if (currentIndex == 0) return;
					editingMessage = messages[currentIndex - 1];
				}

				container.addClass('edit-mode');
				inputBox.val(editingMessage.text);
			}

			function down(e) {
				if (!editingMessage) return resetMessageEditing();

				var messages = getMessages();
				var currentIndex = _.findIndex(messages, {_id: editingMessage._id});
				editingMessage = messages[currentIndex + 1];

				// no more messages
				if (!editingMessage) {
					inputBox.val('');
					return resetMessageEditing();
				}

				inputBox.val(editingMessage.text);
			}

			function getMessages() {
				var currentRoom = bunkerData.getRoom($rootScope.roomId);
				return currentRoom.$messages.filter(message => {
					return message.author && message.author._id == bunkerData.user._id;
				});
			}

			function replaceMatch(oldText, newText) {
				var anchor = anchors[searchingFor];
				var oldSuggestion = `${anchor}${oldText}${anchor}`;

				var suggestionSearch = anchor + newText;

				var currentText = inputBox.val();
				var currentSearch = new RegExp(`${oldSuggestion}*$`);
				currentText = currentText.replace(currentSearch, suggestionSearch);

				inputBox.val(currentText);
			}

			function getNextMatch(shiftKey) {
				matchIndex += shiftKey ? -1 : 1;

				if (matchIndex >= matches.length) {
					matchIndex = 0;
				}

				if (matchIndex < 0) {
					matchIndex = matches.length - 1;
				}

				return matches[matchIndex];
			}

			function emoticon(e) {
				if (!e.shiftKey) return;
				if (searchingFor == 'emoticons') return resetMatchSearch();
				searchingFor = 'emoticons';
			}

			function searchForEmoticons(key) {
				// only allow single letters/numbers/underscores on search term
				var singleLetterNumber = /^[\w\d\_]{1}$/g;
				if (singleLetterNumber.test(key)) {
					searchTerm += key;
				}

				matchingEmoticons = _.filter(emoticons.imageEmoticons, emoticon => emoticon.name.indexOf(searchTerm) == 0);
				matches = _.map(matchingEmoticons, 'name');
			}

			function renderEmoticons() {
				return `

						${_.map(matchingEmoticons, emoticon => `

									:${emoticon.name}:

						`).join('')}

				`
			}

			function user(e) {
				if (!e.shiftKey) return;
				if (searchingFor == 'users') return resetMatchSearch();
				searchingFor = 'users';
			}

			function searchForUsers(key) {
				// only allow single letters/numbers/underscores on search term
				var singleLetterNumber = /^[\w\s\-\.]{1}$/g;
				if (singleLetterNumber.test(key)) {
					searchTerm += key;
				}

				// since the @ key is actually shift + 2, when the search term is this, ignore it
				// since it is the start of looking for a specific user: eg @Jason == 2Jason
				if (searchTerm == '2') {
					searchTerm = '';
				}

				var currentRoom = bunkerData.getRoom($rootScope.roomId);
				var users = _.map(currentRoom.$members, 'user');
				var activeUsers = _.filter(users, user => moment().diff(user.lastConnected, 'days') < 45);

				matchingUsers = _.filter(activeUsers, user => user.nick.toLowerCase().indexOf(searchTerm) == 0);
				matches = _.map(matchingUsers, 'nick');
			}

			function renderUsers() {
				return `

						${_.map(matchingUsers, user => `

									${user.nick}

						`).join('')}

				`
			}
		}
	}
});
<|endoftext|>