<commit_before>var twilio = require('twilio'),
    constants = require('./../../constants'),
    client = require('twilio')(constants.twilio_sid, constants.auth_token),
    restler = require('restler'),
    colors = require('colors');

exports.help = function(request, response, next){
  console.log('[TEXT] SMS detected:'.green, request.body.Body.green);
  console.log('[TEXT] From:'.green,request.body.From.green);
  console.log('[TEXT] Body:'.green,request.body.Body.green);

  console.log('[TEXT] \'cmds\''.green);

  var tokens = request.body.Body.split(" ");

  if (tokens[0].toLowerCase() == 'cmds'){
    var body = 'Commands:\n'
        + 'cmds || Returns a list of available commands.\n'
        + 'reddit <subreddit> <amount> || Returns <amount> titles from <subreddit> subreddit. (Use \'front\' for homepage results)\n'
        + 'google <query> <amount> || Returns <amount> results from google search of <query>.\n'
        + 'TODO || Add more commands.';

    client.messages.create({
      to: request.body.From,
      from: constants.from_phone,
      body: body,
    });
  } else {
    next();
  }
}

exports.reddit = function(request, response, next){
  console.log('[TEXT] \'reddit\''.green);

  var tokens = request.body.Body.split(" ");
  if (tokens[0].toLowerCase() == 'reddit'){
    var subreddit = tokens[1];
    var amount = tokens[2];
    console.log('[DEBUG] Reddit', amount, 'results for', subreddit);

    if (tokens[1] == 'front'){
      restler.get('http://reddit.com/.json').on('complete', function(reddit) {
        for(var i=0; i<amount; i++) {
          client.messages.create({
            to: request.body.From,
            from: constants.from_phone,
            body: reddit.data.children[i].data.title,
          });
        }
      });
    }else{
      restler.get('http://reddit.com/' + subreddit + '/.json').on('complete', function(reddit) {
        for(var i=0; i<amount; i++) {
          client.messages.create({
            to: request.body.From,
            from: constants.from_phone,
            body: reddit.data.children[i].data.title,
          });
        }
      });
    }
  } else {
    next();
  }
}

exports.google = function(request, response, next){
  console.log('[TEXT] \'google\''.green);

  var tokens = request.body.Body.split(" ");
  if (tokens[0].toLowerCase() == 'google'){
    var query = tokens.slice(1, -1).join(' ');
    var amount = tokens[tokens.length - 1];
    console.log('[DEBUG] Google', amount, 'results for', query);
    var body = 'Google ' + amount + ' results for ' + query;

    client.messages.create({
      to: request.body.From,
      from: constants.from_phone,
      body: body,
    });
  } else {
    next();
  }
}

exports.invalid = function(request, response){
  console.log('[TEXT] \'invalid\'');
  var body = 'Invalid input: ' + request.body.Body + '.\nPlease type \'cmds\' to get list of available commands.'
  client.messages.create({
    to: request.body.From,
    from: constants.from_phone,
    body: body,
  });
}
<commit_msg>reddit - changed from one large sms to one small per title<commit_after>var twilio = require('twilio'),
    constants = require('./../../constants'),
    client = require('twilio')(constants.twilio_sid, constants.auth_token),
    restler = require('restler'),
    colors = require('colors');

exports.help = function(request, response, next){
  console.log('[TEXT] SMS detected:'.green, request.body.Body.green);
  console.log('[TEXT] From:'.green,request.body.From.green);
  console.log('[TEXT] Body:'.green,request.body.Body.green);

  console.log('[TEXT] \'cmds\''.green);

  var tokens = request.body.Body.split(" ");

  if (tokens[0].toLowerCase() == 'cmds'){
    var body = 'Commands:\n'
        + 'cmds || Returns a list of available commands.\n'
        + 'reddit <subreddit> <amount> || Returns <amount> titles from <subreddit> subreddit. (Use \'front\' for homepage results)\n'
        + 'google <query> <amount> || Returns <amount> results from google search of <query>.\n'
        + 'TODO || Add more commands.';

    client.messages.create({
      to: request.body.From,
      from: constants.from_phone,
      body: body,
    });
  } else {
    next();
  }
}

exports.reddit = function(request, response, next){
  console.log('[TEXT] \'reddit\''.green);

  var tokens = request.body.Body.split(" ");
  if (tokens[0].toLowerCase() == 'reddit'){
    var subreddit = tokens[1];
    var amount = tokens[2];

    if (tokens[1] == 'front'){
      restler.get('http://reddit.com/.json').on('complete', function(reddit) {
        for(var i=0; i<amount; i++) {
          client.messages.create({
            to: request.body.From,
            from: constants.from_phone,
            body: reddit.data.children[i].data.title,
          });
        }
      });
    }else{
      restler.get('http://reddit.com/r/' + subreddit + '/.json').on('complete', function(reddit) {
        for(var i=0; i<amount; i++) {
          client.messages.create({
            to: request.body.From,
            from: constants.from_phone,
            body: reddit.data.children[i].data.title,
          });
        }
      });
    }
  } else {
    next();
  }
}

exports.google = function(request, response, next){
  console.log('[TEXT] \'google\''.green);

  var tokens = request.body.Body.split(" ");
  if (tokens[0].toLowerCase() == 'google'){
    var query = tokens.slice(1, -1).join(' ');
    var amount = tokens[tokens.length - 1];
    console.log('[DEBUG] Google', amount, 'results for', query);
    var body = 'Google ' + amount + ' results for ' + query;

    client.messages.create({
      to: request.body.From,
      from: constants.from_phone,
      body: body,
    });
  } else {
    next();
  }
}

exports.invalid = function(request, response){
  console.log('[TEXT] \'invalid\'');
  var body = 'Invalid input: ' + request.body.Body + '.\nPlease type \'cmds\' to get list of available commands.'
  client.messages.create({
    to: request.body.From,
    from: constants.from_phone,
    body: body,
  });
}
<|endoftext|>


<commit_before>var fs = Npm.require('fs'),
    currentDir = fs.realpathSync('./'),
    tmpDir = currentDir + '/tmp~/',
    saveDir = Meteor.settings.saveDir;

if (!fs.existsSync(Meteor.settings.buildDir)) {
    throw new Error('error in buildDir');
}

if (!saveDir
    || !fs.existsSync(saveDir)) {
    fs.mkdirSync(tmpDir);
    saveDir = tmpDir;
    console.warn("saveDir " + Meteor.settings.saveDir + " in settings doesn't exists, application will use this path instead: " + saveDir);
}

Meteor.startup(function serverOnStartup() {
    // init build collection
    if (!BuildRunning.find().count()) {
        BuildRunning.insert({running: 0});
    }

    if (!BuildNeeded.find().count()) {
        BuildNeeded.insert({needed: 0});
    }

    (function initDb() {
        // create default satis file
        if (!fs.existsSync(Meteor.settings.satisJson)) {
            console.warn("your satis (" + Meteor.settings.satisJson + ") file doesn't exists, a sample one is going to be created.");
            fs.writeFileSync(Meteor.settings.satisJson, Assets.getText('satis.default.json'));
        }

        var buf = fs.readFileSync(Meteor.settings.satisJson),
            json = JSON.parse(buf.toString());

        if (!Informations.find().count()) {
            var dataInfo = {
                title: json.name ? json.name : Meteor.settings.public.informations.title,
                homepage: json.homepage ? json.homepage : Meteor.settings.public.informations.homepage,
                description: json.description ? json.description : Meteor.settings.public.informations.description
            };

            if (json.config
                && json.config['github-oauth']) {
                // @TODO foreach on this node to insert it in Informations
                var keys = _.keys(json.config['github-oauth']),
                    config = [];
                _.each(keys, function initConfigWithJsonContent(key) {
                    config.push({
                        name: key,
                        token: json.config['github-oauth'][key]
                    });
                });

                dataInfo.config = {};
                dataInfo.config['github-oauth'] = config;
            }

            Informations.insert(dataInfo);

            console.log('Informations section provisionned title/homepage/description/config.github-oauth datas');
        }

        if (json.repositories
            && !Repositories.find().count()) {
            _.each(json.repositories, function initRepositoriesWithJsonContent(repo) {
                Repositories.insert(repo);
            });

            console.log('Repositories section provisionned with ' + _.size(json.repositories) + ' repo');
        }

        if (json.require
            && !Packages.find().count()) {
            var keys = _.keys(json.require);
            _.each(keys, function initPackagesWithJsonContent(key) {
                var dataPackage = {
                    name: key,
                    version: json.require[key]
                };
                Packages.insert(dataPackage);
            });

            console.log('Require section provisionned with ' + _.size(json.require) + ' packages');
        }
    })();

    // restore build running and launch a build
    var build = BuildRunning.findOne();
    if (build.running !== 0) {
        BuildRunning.update({
            _id: build._id
        }, {
            $set: {
                running: 0,
                endDate: new Date()
            }
        });

        Meteor.call('build');
    }
});

Meteor.methods({
    "generate": function methodsGenerate() {
        SSR.compileTemplate('satisJson', Assets.getText('satis.json'));

        var json = SSR.render('satisJson', {

            title: function ssrTitle() {
                var tt = Informations.findOne() ? Informations.findOne().title : Meteor.settings.public.informations.title;

                return tt;
            },

            description: function ssrDescription() {
                var ds = Informations.findOne() ? Informations.findOne().description : Meteor.settings.public.informations.description;

                return ds;
            },

            homepage: function ssrHomepage() {
                var hp = Informations.findOne() ? Informations.findOne().homepage : Meteor.settings.public.informations.homepage;

                return hp;
            },

            configGithubOauth: function ssrConfigGithubOauth() {
                /*
                 * create a fake collection with a new property: isNotLast that will allow to manage
                 * the last ","
                 */
                var config = new Meteor.Collection(null),
                    infos = Informations.findOne(),
                    total = infos && infos.config && _.has(infos.config, 'github-oauth') ? _.size(infos.config['github-oauth']) : 0,
                    counter = 0;

                if (total) {
                    var keys = _.keys(infos.config['github-oauth']);
                    _.each(keys, function ssrConfigEachOAuth(key) {
                        var item = infos.config['github-oauth'][key];
                        counter++;
                        _.extend(item, {isNotLast: (counter < total)});
                        config.insert(item);
                    });
                }

                return config.find();
            },

            repositories: function ssrRepositories() {
                /*
                 * create a fake collection with a new property: isNotLast that will allow to manage
                 * the last ","
                 */
                var repos = new Meteor.Collection(null),
                    total = Repositories.find({}).count(),
                    counter = 0;

                Repositories.find({}, {sort: {url: 1}}).forEach(function ssrEachRepositories(item) {
                    counter++;
                    _.extend(item, {isNotLast: (counter < total)});
                    repos.insert(item);
                });

                return repos.find();
            },

            packages: function ssrPackages() {
                /*
                 * create a fake collection with a new property: isNotLast that will allow to manage
                 * the last ","
                 */
                var packages = new Meteor.Collection(null),
                    total = Packages.find({}).count(),
                    counter = 0;

                Packages.find({}, {sort: {name: 1}}).forEach(function ssrEachPackages(item) {
                    counter++;
                    _.extend(item, {isNotLast: (counter < total)});
                    packages.insert(item);
                });

                return packages.find();
            },

            hasPackages: function ssrHasPackages() {
                return Packages.find().count();
            },

            archive: function ssrArchive() {
                var hp = Informations.findOne(),
                    archive = hp && hp.archive ? hp.archive : null;

                _.extend(archive, {
                    skipDev: (archive.skipDev ? "true" : "false"),
                    requireDeps: (archive.requireDeps ? "true" : "false"),
                    requireDevDeps: (archive.requireDevDeps ? "true" : "false")
                });

                return archive;
            },

            hasArchive: function ssrHasArchive() {
                return !!this.archive();
            }
        });

        fs.writeFileSync(saveDir + '/satis.json', json);

        // launch build only if no job running
        var job = BuildRunning.findOne();
        if (job.running === 0) {
            Meteor.call('build');
        }
    },

    "build": function methodsBuild(retries) {
        var modifiers = {},
            buildRunning = BuildRunning.findOne({}, {_id: true}),
            buildNeeded = BuildNeeded.findOne({}, {_id: true}),
            phpCmd = 'php ' + Meteor.settings.satisBinary + ' build ' + saveDir + '/satis.json' + ' ' + Meteor.settings.buildDir,
            // phpCmd = 'php ' + Meteor.settings.satisBinary + ' build ' + Meteor.settings.satisJson + ' ' + Meteor.settings.buildDir,
            childProcess = Npm.require('child_process'),
            exec = Meteor.wrapAsync(childProcess.exec);

        // launch buildRunning only if no job running, ask to retry
        var job = BuildRunning.findOne();
        if (job.running !== 0) {
            var retry = new Retry({
                baseTimeout: 1000, //starting from 100ms and starting
                maxTimeout: 1000 //max timeout will be 1 sec
            }),
                retries = retries && _.isNumber(retries) ? retries : 0,
                buildAgain = function buildAgain() {
                    retries++;
                    Meteor.call('buildRunning', retries, function methodBuildAgain(err, res) {
                        if (!err) {
                            console.info('Build succeed');
                            return;
                        }

                        if (err.code == 501) {
                            console.error('Build error, no retry');
                            return;
                        }

                        if(retries < 100) {
                            console.log('retrying because %s', err.message);
                            retry.retryLater(retries, buildAgain);
                        } else {
                            console.log('failed after maximum retries: ', retries);
                        }
                    });
                };

            if (!retries || !_.isNumber(retries)) {
                buildAgain();
            }

            throw new Meteor.Error("A job is already running", 501);
        }

        BuildRunning.update({
            _id: buildRunning._id
        }, {
            $set: {
                running: 1,
                startDate: new Date()
            }
        });

        try {
            console.log(phpCmd);
            var res = exec(phpCmd);

            BuildNeeded.update({
                _id: buildNeeded._id
            }, {
                needed: 0,
                endDate: new Date()
            });
        } catch (e) {
            console.error('exec failed (cmd: %s)', phpCmd);
            console.warn('oups start');
            console.error(e);
            console.warn('oups end');

            var error = e;
        }

        var setData = {
            running: 0,
            endDate: new Date()
        },
            unsetData = {};

        if (error) {
            _.extend(setData, {error: error});
        } else {
            _.extend(modifiers, {$unset: {error: ""}});
        }

        _.extend(modifiers, {$set: setData});

        BuildRunning.update({
            _id: buildRunning._id
        }, modifiers);

        // @TODO check res to alert user if everything is ok or if an error happened
    }
});
<commit_msg>add skip-errors<commit_after>var fs = Npm.require('fs'),
    currentDir = fs.realpathSync('./'),
    tmpDir = currentDir + '/tmp~/',
    saveDir = Meteor.settings.saveDir;

if (!fs.existsSync(Meteor.settings.buildDir)) {
    throw new Error('error in buildDir');
}

if (!saveDir
    || !fs.existsSync(saveDir)) {
    fs.mkdirSync(tmpDir);
    saveDir = tmpDir;
    console.warn("saveDir " + Meteor.settings.saveDir + " in settings doesn't exists, application will use this path instead: " + saveDir);
}

Meteor.startup(function serverOnStartup() {
    // init build collection
    if (!BuildRunning.find().count()) {
        BuildRunning.insert({running: 0});
    }

    if (!BuildNeeded.find().count()) {
        BuildNeeded.insert({needed: 0});
    }

    (function initDb() {
        // create default satis file
        if (!fs.existsSync(Meteor.settings.satisJson)) {
            console.warn("your satis (" + Meteor.settings.satisJson + ") file doesn't exists, a sample one is going to be created.");
            fs.writeFileSync(Meteor.settings.satisJson, Assets.getText('satis.default.json'));
        }

        var buf = fs.readFileSync(Meteor.settings.satisJson),
            json = JSON.parse(buf.toString());

        if (!Informations.find().count()) {
            var dataInfo = {
                title: json.name ? json.name : Meteor.settings.public.informations.title,
                homepage: json.homepage ? json.homepage : Meteor.settings.public.informations.homepage,
                description: json.description ? json.description : Meteor.settings.public.informations.description
            };

            if (json.config
                && json.config['github-oauth']) {
                // @TODO foreach on this node to insert it in Informations
                var keys = _.keys(json.config['github-oauth']),
                    config = [];
                _.each(keys, function initConfigWithJsonContent(key) {
                    config.push({
                        name: key,
                        token: json.config['github-oauth'][key]
                    });
                });

                dataInfo.config = {};
                dataInfo.config['github-oauth'] = config;
            }

            Informations.insert(dataInfo);

            console.log('Informations section provisionned title/homepage/description/config.github-oauth datas');
        }

        if (json.repositories
            && !Repositories.find().count()) {
            _.each(json.repositories, function initRepositoriesWithJsonContent(repo) {
                Repositories.insert(repo);
            });

            console.log('Repositories section provisionned with ' + _.size(json.repositories) + ' repo');
        }

        if (json.require
            && !Packages.find().count()) {
            var keys = _.keys(json.require);
            _.each(keys, function initPackagesWithJsonContent(key) {
                var dataPackage = {
                    name: key,
                    version: json.require[key]
                };
                Packages.insert(dataPackage);
            });

            console.log('Require section provisionned with ' + _.size(json.require) + ' packages');
        }
    })();

    // restore build running and launch a build
    var build = BuildRunning.findOne();
    if (build.running !== 0) {
        BuildRunning.update({
            _id: build._id
        }, {
            $set: {
                running: 0,
                endDate: new Date()
            }
        });

        Meteor.call('build');
    }
});

Meteor.methods({
    "generate": function methodsGenerate() {
        SSR.compileTemplate('satisJson', Assets.getText('satis.json'));

        var json = SSR.render('satisJson', {

            title: function ssrTitle() {
                var tt = Informations.findOne() ? Informations.findOne().title : Meteor.settings.public.informations.title;

                return tt;
            },

            description: function ssrDescription() {
                var ds = Informations.findOne() ? Informations.findOne().description : Meteor.settings.public.informations.description;

                return ds;
            },

            homepage: function ssrHomepage() {
                var hp = Informations.findOne() ? Informations.findOne().homepage : Meteor.settings.public.informations.homepage;

                return hp;
            },

            configGithubOauth: function ssrConfigGithubOauth() {
                /*
                 * create a fake collection with a new property: isNotLast that will allow to manage
                 * the last ","
                 */
                var config = new Meteor.Collection(null),
                    infos = Informations.findOne(),
                    total = infos && infos.config && _.has(infos.config, 'github-oauth') ? _.size(infos.config['github-oauth']) : 0,
                    counter = 0;

                if (total) {
                    var keys = _.keys(infos.config['github-oauth']);
                    _.each(keys, function ssrConfigEachOAuth(key) {
                        var item = infos.config['github-oauth'][key];
                        counter++;
                        _.extend(item, {isNotLast: (counter < total)});
                        config.insert(item);
                    });
                }

                return config.find();
            },

            repositories: function ssrRepositories() {
                /*
                 * create a fake collection with a new property: isNotLast that will allow to manage
                 * the last ","
                 */
                var repos = new Meteor.Collection(null),
                    total = Repositories.find({}).count(),
                    counter = 0;

                Repositories.find({}, {sort: {url: 1}}).forEach(function ssrEachRepositories(item) {
                    counter++;
                    _.extend(item, {isNotLast: (counter < total)});
                    repos.insert(item);
                });

                return repos.find();
            },

            packages: function ssrPackages() {
                /*
                 * create a fake collection with a new property: isNotLast that will allow to manage
                 * the last ","
                 */
                var packages = new Meteor.Collection(null),
                    total = Packages.find({}).count(),
                    counter = 0;

                Packages.find({}, {sort: {name: 1}}).forEach(function ssrEachPackages(item) {
                    counter++;
                    _.extend(item, {isNotLast: (counter < total)});
                    packages.insert(item);
                });

                return packages.find();
            },

            hasPackages: function ssrHasPackages() {
                return Packages.find().count();
            },

            archive: function ssrArchive() {
                var hp = Informations.findOne(),
                    archive = hp && hp.archive ? hp.archive : null;

                _.extend(archive, {
                    skipDev: (archive.skipDev ? "true" : "false"),
                    requireDeps: (archive.requireDeps ? "true" : "false"),
                    requireDevDeps: (archive.requireDevDeps ? "true" : "false")
                });

                return archive;
            },

            hasArchive: function ssrHasArchive() {
                return !!this.archive();
            }
        });

        fs.writeFileSync(saveDir + '/satis.json', json);

        // launch build only if no job running
        var job = BuildRunning.findOne();
        if (job.running === 0) {
            Meteor.call('build');
        }
    },

    "build": function methodsBuild(retries) {
        var modifiers = {},
            buildRunning = BuildRunning.findOne({}, {_id: true}),
            buildNeeded = BuildNeeded.findOne({}, {_id: true}),
            phpCmd = 'php ' + Meteor.settings.satisBinary + ' build ' + saveDir + '/satis.json' + ' ' + Meteor.settings.buildDir + ' --skip-errors',
            // phpCmd = 'php ' + Meteor.settings.satisBinary + ' build ' + Meteor.settings.satisJson + ' ' + Meteor.settings.buildDir,
            childProcess = Npm.require('child_process'),
            exec = Meteor.wrapAsync(childProcess.exec);

        // launch buildRunning only if no job running, ask to retry
        var job = BuildRunning.findOne();
        if (job.running !== 0) {
            var retry = new Retry({
                baseTimeout: 1000, //starting from 100ms and starting
                maxTimeout: 1000 //max timeout will be 1 sec
            }),
                retries = retries && _.isNumber(retries) ? retries : 0,
                buildAgain = function buildAgain() {
                    retries++;
                    Meteor.call('buildRunning', retries, function methodBuildAgain(err, res) {
                        if (!err) {
                            console.info('Build succeed');
                            return;
                        }

                        if (err.code == 501) {
                            console.error('Build error, no retry');
                            return;
                        }

                        if(retries < 100) {
                            console.log('retrying because %s', err.message);
                            retry.retryLater(retries, buildAgain);
                        } else {
                            console.log('failed after maximum retries: ', retries);
                        }
                    });
                };

            if (!retries || !_.isNumber(retries)) {
                buildAgain();
            }

            throw new Meteor.Error("A job is already running", 501);
        }

        BuildRunning.update({
            _id: buildRunning._id
        }, {
            $set: {
                running: 1,
                startDate: new Date()
            }
        });

        try {
            console.log(phpCmd);
            var res = exec(phpCmd);

            BuildNeeded.update({
                _id: buildNeeded._id
            }, {
                needed: 0,
                endDate: new Date()
            });
        } catch (e) {
            console.error('exec failed (cmd: %s)', phpCmd);
            console.warn('oups start');
            console.error(e);
            console.warn('oups end');

            var error = e;
        }

        var setData = {
            running: 0,
            endDate: new Date()
        },
            unsetData = {};

        if (error) {
            _.extend(setData, {error: error});
        } else {
            _.extend(modifiers, {$unset: {error: ""}});
        }

        _.extend(modifiers, {$set: setData});

        BuildRunning.update({
            _id: buildRunning._id
        }, modifiers);

        // @TODO check res to alert user if everything is ok or if an error happened
    }
});
<|endoftext|>


<commit_before>/**
 * Creates a new pretty test runner.
 * @param {String} product the name of the "product" being tested
 * @class Runs Crucible tests, displaying the results graphically in the browser
 * window.
 * @augments Crucible.Runner
 */
Crucible.PrettyRunner = function PrettyRunner(product) {
	Crucible.Runner.call(this);
	if (product)
		this.product = product;

	for (var name in this._eventListeners) {
		this[name].add(this._eventListeners[name], this);
	}

	this._test_messages = [];

	this.draw();
};

Crucible.PrettyRunner.prototype = new Crucible.Runner();

Crucible.augment(Crucible.PrettyRunner.prototype,
	/** @lends Crucible.PrettyRunner.prototype */
{
	/**
	 * PrettyRunner status.
	 * @type String
	 */
	status: null,

	/**
	 * The product that the PrettyRunner is testing.
	 */
	product: 'the product',

	doneAdding: function done_adding_tasks_to_pretty_runner() {
		var msg;
		this._done_adding = true;

		if (!this.root) {
			Crucible.defer(Crucible.bind(this.doneAdding, this));
			return;
		}

		function start() {
			this.tallies = {pass: 0, fail: 0, error: 0};
			this.run();
		}

		msg = this.addMessage('prompt', "Crucible is ready to test " +
			this.product + ".", {'Start': Crucible.bind(start, this)});
	},

	displayMessage: function pr_display_message(message, buttons) {
		this.addMessage('prompt', message, buttons);
	},

	_getMessage: function _get_message_for_test(test, remove) {
		var i, len, entry, message;
		for (i = 0, len = this._test_messages.length; i < len; ++i) {
			entry = this._test_messages[i];
			if (entry && entry.test == test) {
				message = entry.message;
				if (remove)
					this._test_messages.splice(i, 1);
				return message;
			}
		}

		return null;
	},

	_setMessage: function _set_message_for_test(test, message) {
		var old = this._getMessage(test, true);
		if (old && old.remove)
			old.remove();
		this._test_messages.push({test: test, message: message});
		return message;
	},

	_eventListeners: {
		testStarted: function pr_test_started(test) {
			var msg = this.addMessage('running', 'Testing “' + test.name +
				'”…');
			this._setMessage(test, msg);
		},

		testPassed: function pr_test_succeeded(test) {
			var message = this._getMessage(test);
			message.setType('pass');
			message.setMessage(test.name);
			this.tallies.pass++;
			console.debug('Test passed: ' + test.name);
		},

		testFailed: function pr_test_failed(test, failure) {
			var message = this._getMessage(test);
			message.setType('fail');
			message.setMessage(test.name + ': ' + failure.description);
			if (this.status == 'ok')
				this.setStatus('failure');
			this.tallies.fail++;
			console.debug('Test failed: ' + test.name);
		},

		testError: function pr_test_error(test, error) {
			var message = this._getMessage(test);
			message.setType('error');
			message.setMessage('Test “' + test.name + '” ' +
				'had an error: ' + error.error.toString());
			this.setStatus('error');
			this.tallies.error++;
			console.debug('Test had an error: ' + test.name);
		},

		completed: function pr_run_completed() {
			this.addMessage('done', "Crucible has finished testing "
				+ this.product + ".");
		}
	},

	/**
	 * @type Boolean
	 * @private
	 */
	_drawn: false,

	/**
	 * @type Boolean
	 * @private
	 */
	_done_adding: false,

	/**
	 * @type Object[]
	 * @private
	 */
	_test_messages: null,

	/**
	 * @type Object
	 * @private
	 */
	tallies: null,

	/**
	 * @type String
	 * @private
	 */
	base: null,

	/**
	 * The root runner window.
	 * @type HTMLDivElement
	 * @private
	 */
	root: null,

	/**
	 * The runner window title bar.
	 * @type HTMLDivElement
	 * @private
	 */
	titlebar: null,

	/**
	 * The status icon in the title bar.
	 * @type HTMLImageElement
	 * @private
	 */
	status_icon: null,

	/**
	 * The runner window main body.
	 * @type HTMLDivElement
	 * @private
	 */
	body: null,

	/**
	 * The results table.
	 * @type HTMLTableElement
	 * @private
	 */
	results: null,

	addMessage: function add_message_to_table(type, message, buttons) {
		var doc, row, icon_cell, icon, message_cell, button_cell;
		var mo;
		var runner = this;
		if (!this.results)
			this.createResultTable();

		doc = this.results.ownerDocument;
		row = this.results.insertRow(-1);

		icon_cell = row.insertCell(-1);
		icon_cell.className = 'pr_result_icon';
		icon = document.createElement('IMG');
		icon_cell.appendChild(icon);

		message_cell = row.insertCell(-1);
		message_cell.className = 'pr_result_body';

		mo = {
			setType: function set_pr_message_type(type) {
				var params;
				if (!(params = Crucible.PrettyRunner._type_params[type]))
					throw new Error('Unknown message type "' + type + '".');
				row.className = params.row_class;
				icon.src = runner.base + 'assets/icons/' + params.icon;
			},

			setMessage: function set_pr_message_text(message) {
				message_cell.innerHTML = message;
			},

			setButtons: function set_pr_message_buttons(buttons) {
				var button;
				function click_listener(button) {
					return function (ev) {
						if (typeof(button.pr_action) == 'function')
							button.pr_action.call(null);
						else
							button.pr_action.run(runner);
						mo.remove();
						ev.preventDefault();
					};
				}

				message_cell.colSpan = (buttons) ? 1 : 2;

				if (!buttons && button_cell) {
					button_cell.parentNode.removeChild(button_cell);
					button_cell = null;
				} else if (buttons) {
					if (button_cell) {
						while (button_cell.firstChild)
							button_cell.removeChild(button_cell.firstChild);
					} else {
						button_cell = row.insertCell(-1);
						button_cell.className = 'pr_result_buttons';
					}

					for (var label in buttons) {
						button = doc.createElement('A');
						button.href = '#';
						button.innerHTML = label;
						button.pr_action = buttons[label];
						Crucible.observeEvent(button, 'click',
							click_listener(button));
						button_cell.appendChild(button);
					}
				}
			},

			remove: function remove_pr_message() {
				runner.results.deleteRow(row.rowIndex);
			}
		};

		mo.setType(type);
		mo.setMessage(message);
		mo.setButtons(buttons);

		row.scrollIntoView();
		return mo;
	},

	/**
	 * Sets the status icon.
	 * @private
	 * @return {void}
	 */
	setStatus: function set_pretty_runner_status_icon(status) {
		var base = this.base + 'assets/icons/';
		switch (status) {
			case 'ok':
				this.status_icon.src = base + 'ok.png';
				this.status_icon.alt = 'OK';
				this.status_icon.title = 'No errors.';
				break;
			case 'failure':
				this.status_icon.src = base + 'error.png';
				this.status_icon.alt = 'Failure(s)';
				this.status_icon.title = 'One or more tests have failed.';
				break;
			case 'error':
				this.status_icon.src = base + 'exclamation.png';
				this.status_icon.alt = 'Error(s)';
				this.status_icon.title = 'One or more tests have encountered ' +
					'errors.';
				break;
			default:
				throw new Error('Unknown runner status code "' + status + '".');
		}
		this.status = status;
	},

	/**
	 * Creates the runner interface.
	 * @private
	 * @return {void}
	 */
	draw: function add_pretty_runner_stylesheet() {
		var base;

		if (this._drawn)
			return;

		if (!document.body) {
			Crucible.defer(this.draw, this);
			return;
		}

		this._drawn = true;

		base = this.base = Crucible.determineBase();
		Crucible.addStyleSheet(base + 'assets/css/pretty_runner.css');

		//this.appendUI();
		Crucible.defer(this.appendUI, this);
	},

	/**
	 * Creates the runner UI elements and appends them to the document.
	 * @private
	 * @return {void}
	 */
	appendUI: function append_pretty_runner_ui() {
		if (this.root && this.titlebar && this.status_icon && this.body)
			return; // guard

		this.root = document.createElement('DIV');
		this.root.id = "pretty_runner";

		this.titlebar = document.createElement('DIV');
		this.titlebar.id = "pretty_runner_title";
		this.titlebar.title = 'Click to open.';

		this.status_icon = document.createElement('IMG');
		this.status_icon.className = 'pr_status';
		this.setStatus('ok');
		this.titlebar.appendChild(this.status_icon)
		this.titlebar.appendChild(document.createTextNode("\nCrucible"));
		this.root.appendChild(this.titlebar);

		Crucible.observeEvent(this.titlebar, 'click', Crucible.bind(function() {
			var row;

			this.body.className = (!this.body.className)
				? 'pr_active'
				: '';
			this.titlebar.title = (this.body.className == 'pr_active')
				? 'Click to close.'
				: 'Click to open.';
			if (this.body.className == 'pr_active' && this.results) {
				row = this.results.rows[this.results.rows.length-1];
				Crucible.defer(function() {
					row.scrollIntoView();
				});
			}
		}, this));

		this.body = document.createElement('DIV');
		this.body.id = 'pretty_runner_body';
		this.root.appendChild(this.body);

		document.body.appendChild(this.root);
	},

	/**
	 * Creates the results table.
	 * @private
	 * @return {void}
	 */
	createResultTable: function create_pretty_runner_result_table() {
		this.results = this.root.ownerDocument.createElement('TABLE');
		this.results.id = "pretty_runner_results";
		this.body.appendChild(this.results);
	}
});

Crucible.augment(Crucible.PrettyRunner, {
	_window_loaded: false,
	_pending_runners: [],

	_window_load: function _pretty_runner_onload() {
		var pending, i;

		Crucible.PrettyRunner._window_loaded = true;

		pending = Crucible.PrettyRunner._pending_runners;
		Crucible.PrettyRunner._pending_runners = [];
		for (i = 0; i < pending.count; i++) {
			pending[i].draw();
		}
	},

	_type_params: {
		'prompt': {
			row_class: 'pr_message',
			icon: 'bullet_go.png'
		},
		'running': {
			row_class: 'pr_running',
			icon: 'bullet_yellow.png'
		},
		'pass': {
			row_class: 'pr_passed',
			icon: 'tick.png'
		},
		'fail': {
			row_class: 'pr_failed',
			icon: 'cross.png'
		},
		'error': {
			row_class: 'pr_error',
			icon: 'exclamation.png'
		},
		'done': {
			row_class: 'pr_done',
			icon: 'flag_blue.png'
		}
	}
});

Crucible.observeEvent(window, 'load', Crucible.PrettyRunner._window_load);
<commit_msg>Removed Firebug logging calls.<commit_after>/**
 * Creates a new pretty test runner.
 * @param {String} product the name of the "product" being tested
 * @class Runs Crucible tests, displaying the results graphically in the browser
 * window.
 * @augments Crucible.Runner
 */
Crucible.PrettyRunner = function PrettyRunner(product) {
	Crucible.Runner.call(this);
	if (product)
		this.product = product;

	for (var name in this._eventListeners) {
		this[name].add(this._eventListeners[name], this);
	}

	this._test_messages = [];

	this.draw();
};

Crucible.PrettyRunner.prototype = new Crucible.Runner();

Crucible.augment(Crucible.PrettyRunner.prototype,
	/** @lends Crucible.PrettyRunner.prototype */
{
	/**
	 * PrettyRunner status.
	 * @type String
	 */
	status: null,

	/**
	 * The product that the PrettyRunner is testing.
	 */
	product: 'the product',

	doneAdding: function done_adding_tasks_to_pretty_runner() {
		var msg;
		this._done_adding = true;

		if (!this.root) {
			Crucible.defer(Crucible.bind(this.doneAdding, this));
			return;
		}

		function start() {
			this.tallies = {pass: 0, fail: 0, error: 0};
			this.run();
		}

		msg = this.addMessage('prompt', "Crucible is ready to test " +
			this.product + ".", {'Start': Crucible.bind(start, this)});
	},

	displayMessage: function pr_display_message(message, buttons) {
		this.addMessage('prompt', message, buttons);
	},

	_getMessage: function _get_message_for_test(test, remove) {
		var i, len, entry, message;
		for (i = 0, len = this._test_messages.length; i < len; ++i) {
			entry = this._test_messages[i];
			if (entry && entry.test == test) {
				message = entry.message;
				if (remove)
					this._test_messages.splice(i, 1);
				return message;
			}
		}

		return null;
	},

	_setMessage: function _set_message_for_test(test, message) {
		var old = this._getMessage(test, true);
		if (old && old.remove)
			old.remove();
		this._test_messages.push({test: test, message: message});
		return message;
	},

	_eventListeners: {
		testStarted: function pr_test_started(test) {
			var msg = this.addMessage('running', 'Testing “' + test.name +
				'”…');
			this._setMessage(test, msg);
		},

		testPassed: function pr_test_succeeded(test) {
			var message = this._getMessage(test);
			message.setType('pass');
			message.setMessage(test.name);
			this.tallies.pass++;
		},

		testFailed: function pr_test_failed(test, failure) {
			var message = this._getMessage(test);
			message.setType('fail');
			message.setMessage(test.name + ': ' + failure.description);
			if (this.status == 'ok')
				this.setStatus('failure');
			this.tallies.fail++;
		},

		testError: function pr_test_error(test, error) {
			var message = this._getMessage(test);
			message.setType('error');
			message.setMessage('Test “' + test.name + '” ' +
				'had an error: ' + error.error.toString());
			this.setStatus('error');
			this.tallies.error++;
		},

		completed: function pr_run_completed() {
			this.addMessage('done', "Crucible has finished testing "
				+ this.product + ".");
		}
	},

	/**
	 * @type Boolean
	 * @private
	 */
	_drawn: false,

	/**
	 * @type Boolean
	 * @private
	 */
	_done_adding: false,

	/**
	 * @type Object[]
	 * @private
	 */
	_test_messages: null,

	/**
	 * @type Object
	 * @private
	 */
	tallies: null,

	/**
	 * @type String
	 * @private
	 */
	base: null,

	/**
	 * The root runner window.
	 * @type HTMLDivElement
	 * @private
	 */
	root: null,

	/**
	 * The runner window title bar.
	 * @type HTMLDivElement
	 * @private
	 */
	titlebar: null,

	/**
	 * The status icon in the title bar.
	 * @type HTMLImageElement
	 * @private
	 */
	status_icon: null,

	/**
	 * The runner window main body.
	 * @type HTMLDivElement
	 * @private
	 */
	body: null,

	/**
	 * The results table.
	 * @type HTMLTableElement
	 * @private
	 */
	results: null,

	addMessage: function add_message_to_table(type, message, buttons) {
		var doc, row, icon_cell, icon, message_cell, button_cell;
		var mo;
		var runner = this;
		if (!this.results)
			this.createResultTable();

		doc = this.results.ownerDocument;
		row = this.results.insertRow(-1);

		icon_cell = row.insertCell(-1);
		icon_cell.className = 'pr_result_icon';
		icon = document.createElement('IMG');
		icon_cell.appendChild(icon);

		message_cell = row.insertCell(-1);
		message_cell.className = 'pr_result_body';

		mo = {
			setType: function set_pr_message_type(type) {
				var params;
				if (!(params = Crucible.PrettyRunner._type_params[type]))
					throw new Error('Unknown message type "' + type + '".');
				row.className = params.row_class;
				icon.src = runner.base + 'assets/icons/' + params.icon;
			},

			setMessage: function set_pr_message_text(message) {
				message_cell.innerHTML = message;
			},

			setButtons: function set_pr_message_buttons(buttons) {
				var button;
				function click_listener(button) {
					return function (ev) {
						if (typeof(button.pr_action) == 'function')
							button.pr_action.call(null);
						else
							button.pr_action.run(runner);
						mo.remove();
						ev.preventDefault();
					};
				}

				message_cell.colSpan = (buttons) ? 1 : 2;

				if (!buttons && button_cell) {
					button_cell.parentNode.removeChild(button_cell);
					button_cell = null;
				} else if (buttons) {
					if (button_cell) {
						while (button_cell.firstChild)
							button_cell.removeChild(button_cell.firstChild);
					} else {
						button_cell = row.insertCell(-1);
						button_cell.className = 'pr_result_buttons';
					}

					for (var label in buttons) {
						button = doc.createElement('A');
						button.href = '#';
						button.innerHTML = label;
						button.pr_action = buttons[label];
						Crucible.observeEvent(button, 'click',
							click_listener(button));
						button_cell.appendChild(button);
					}
				}
			},

			remove: function remove_pr_message() {
				runner.results.deleteRow(row.rowIndex);
			}
		};

		mo.setType(type);
		mo.setMessage(message);
		mo.setButtons(buttons);

		row.scrollIntoView();
		return mo;
	},

	/**
	 * Sets the status icon.
	 * @private
	 * @return {void}
	 */
	setStatus: function set_pretty_runner_status_icon(status) {
		var base = this.base + 'assets/icons/';
		switch (status) {
			case 'ok':
				this.status_icon.src = base + 'ok.png';
				this.status_icon.alt = 'OK';
				this.status_icon.title = 'No errors.';
				break;
			case 'failure':
				this.status_icon.src = base + 'error.png';
				this.status_icon.alt = 'Failure(s)';
				this.status_icon.title = 'One or more tests have failed.';
				break;
			case 'error':
				this.status_icon.src = base + 'exclamation.png';
				this.status_icon.alt = 'Error(s)';
				this.status_icon.title = 'One or more tests have encountered ' +
					'errors.';
				break;
			default:
				throw new Error('Unknown runner status code "' + status + '".');
		}
		this.status = status;
	},

	/**
	 * Creates the runner interface.
	 * @private
	 * @return {void}
	 */
	draw: function add_pretty_runner_stylesheet() {
		var base;

		if (this._drawn)
			return;

		if (!document.body) {
			Crucible.defer(this.draw, this);
			return;
		}

		this._drawn = true;

		base = this.base = Crucible.determineBase();
		Crucible.addStyleSheet(base + 'assets/css/pretty_runner.css');

		//this.appendUI();
		Crucible.defer(this.appendUI, this);
	},

	/**
	 * Creates the runner UI elements and appends them to the document.
	 * @private
	 * @return {void}
	 */
	appendUI: function append_pretty_runner_ui() {
		if (this.root && this.titlebar && this.status_icon && this.body)
			return; // guard

		this.root = document.createElement('DIV');
		this.root.id = "pretty_runner";

		this.titlebar = document.createElement('DIV');
		this.titlebar.id = "pretty_runner_title";
		this.titlebar.title = 'Click to open.';

		this.status_icon = document.createElement('IMG');
		this.status_icon.className = 'pr_status';
		this.setStatus('ok');
		this.titlebar.appendChild(this.status_icon)
		this.titlebar.appendChild(document.createTextNode("\nCrucible"));
		this.root.appendChild(this.titlebar);

		Crucible.observeEvent(this.titlebar, 'click', Crucible.bind(function() {
			var row;

			this.body.className = (!this.body.className)
				? 'pr_active'
				: '';
			this.titlebar.title = (this.body.className == 'pr_active')
				? 'Click to close.'
				: 'Click to open.';
			if (this.body.className == 'pr_active' && this.results) {
				row = this.results.rows[this.results.rows.length-1];
				Crucible.defer(function() {
					row.scrollIntoView();
				});
			}
		}, this));

		this.body = document.createElement('DIV');
		this.body.id = 'pretty_runner_body';
		this.root.appendChild(this.body);

		document.body.appendChild(this.root);
	},

	/**
	 * Creates the results table.
	 * @private
	 * @return {void}
	 */
	createResultTable: function create_pretty_runner_result_table() {
		this.results = this.root.ownerDocument.createElement('TABLE');
		this.results.id = "pretty_runner_results";
		this.body.appendChild(this.results);
	}
});

Crucible.augment(Crucible.PrettyRunner, {
	_window_loaded: false,
	_pending_runners: [],

	_window_load: function _pretty_runner_onload() {
		var pending, i;

		Crucible.PrettyRunner._window_loaded = true;

		pending = Crucible.PrettyRunner._pending_runners;
		Crucible.PrettyRunner._pending_runners = [];
		for (i = 0; i < pending.count; i++) {
			pending[i].draw();
		}
	},

	_type_params: {
		'prompt': {
			row_class: 'pr_message',
			icon: 'bullet_go.png'
		},
		'running': {
			row_class: 'pr_running',
			icon: 'bullet_yellow.png'
		},
		'pass': {
			row_class: 'pr_passed',
			icon: 'tick.png'
		},
		'fail': {
			row_class: 'pr_failed',
			icon: 'cross.png'
		},
		'error': {
			row_class: 'pr_error',
			icon: 'exclamation.png'
		},
		'done': {
			row_class: 'pr_done',
			icon: 'flag_blue.png'
		}
	}
});

Crucible.observeEvent(window, 'load', Crucible.PrettyRunner._window_load);
<|endoftext|>


<commit_before>var express = require('express');
var bodyParser = require('body-parser');
var http = require('http');

var api = require('./controller/api');
var socket = require('./controller/socket');

var app = express();

var server = http.createServer(app);

//parser json
app.use(bodyParser.json());

//allowed cors - cross domain
app.use(api.cors);

//routes api
app.get('/api/users', api.getUsers);

app.post('/api/user', api.addUser);

app.delete('/api/user/:id', api.deleteUser);

//web socket
var io = require('socket.io').listen(server);

io.sockets.on('connection', socket);

//start server
server.listen(8080, function() {
	console.log('Server wss is up! port: http://localhost:8080');
});<commit_msg>remove codes from api<commit_after>var express = require('express');
var http = require('http');

var api = require('./controller/api');
var socket = require('./controller/socket');

var app = express();

var server = http.createServer(app);

//web socket
var io = require('socket.io').listen(server);

io.sockets.on('connection', socket);

//start server
server.listen(8080, function() {
	console.log('Server wss is up! port: http://localhost:8080');
});<|endoftext|>


<commit_before>/* 'van.js' (vanguard), because I load this module in advance of all others
 * Ubiquitious functional-style support functions
 * no dependencies
 */

var van = {};

/* Currying functions */
/* Example uses found in example/curring.js */

van.fixN = fixN = function(f,a,n){
  n=n||0;
  return function(b){
    args=Array.prototype.slice.call(arguments); // more general now
    args.splice(n,0,a);
    return f.apply(null,args);
  };
};

van.die = die = function(r){
  return Math.floor(Math.random()*r);
};

van.nullArray = nullArray = function(n){
  var temp = [];
  while(n-- > 0)temp.push(null);
  return temp;
};

van.fix1 = fix1 = function(f,a){
  return function(b){
    return f(a,b);
  };
};

van.fix2 = fix2 = function(f,b){
  return function(a){
    return f(a,b);
  };
};

van.negate = negate = function(p){
  return function(x){
    return !p(x);
  };
};

/*
 * When we want to chain functions into a new function, we use 'compose'
 */

van.compose = compose = function(f,g){
  return function(x){
    return g(f(x));
  };
};

/*
 * we commonly need to sum an array.
 * conveniently, the functional way of summing also demonstrates a useful technique.
 */

van.sum = sum = function(A){
  return A.reduce(function(a,b){
    return a+b;
  });
};

/*
var expter = function(a,b){return Math.pow(a,b);};
console.log([fix2(expter,2),fix1(expter,3),fix1(expter,2)]
    .reduce(compose)(2));
*/

/*
 * In its most common form, Reduce continually applies a binary function to a list
 * until nothing remains.
 * by reducing an array of functions with compose,
 * we can chain an arbitrarily long series of functions into one.
 */

/*
console.log(compose(
  function(x){return x*3;},
  function(x){return x*4;})(5)
);
*/

// These sequential arrays are getting repetitive
// never leave home without a range function.
// FYI, I like my range functions to be inclusive
// I took some shortcuts making this a unary/binary function
// if its arguments are equal, it will default the first to 0
// deal with it.

van.range = range = function(a,b){
  var temp=[];
  b = b || a;
  if(a===b)a=0;
  while(a<=b)temp.push(a++);
  return temp;
};

van.carte = carte = function(f,A,B){
  return A.map(function(a){
    return B.map(fix1(f,a));
  });
};

van.carteSquare = carteSquare = function(f,A){
  return A.map(function(a,i,z){
    return z.map(fix1(f,a));
  });
};

van.flatten = flatten = function(AA){
  return AA.reduce(function(A,B){
    return A.concat(B);
  });
};

/* A few basic membership handlers */

van.exists = exists = function(A,e){
  return A.indexOf(e);
};

van.vals = vals = function(O){
  return Object.keys(O).map(function(k){
    return O[k];
  });
};

/*
console.log(van.vals({a:"0",b:"1",c:2}));
*/

van.keys = keys = function(O){
  return Object.keys(O);
};

van.is = is = function(a,b){
  return a === b;
};

/* Standard Deviation and other statistical measures */

van.stdDev = stdDev = function(A){
  var S = sum(A),
  L = A.length;
  mean = S/L;
  var variance = sum(A.map(function(x){
    return Math.pow(x-mean,2);
  }))/A.length;
  return Math.pow(variance,0.5);
};

/*
console.log(stdDev([1,2,2,1]));
*/

/* Scheduling */

van.schedule = schedule = function(f,t,n){
  n = n || -1;
  n -= 1;
  if(n===0){
    setTimeout(function(){
      f(n);
    },t);
  }else{
    setTimeout(function(){
      f(n);
      schedule(f,t,n);
    },t);
  }
};

/*
schedule(function(x){
  console.log(x);
},1000,5);
*/

// dat parsimony
if(typeof module!=="undefined"&&module.exports)module.exports=van;
<commit_msg>moved examples from the lib into standalone scripts<commit_after>/* 'van.js' (vanguard), because I load this module in advance of all others
 * Ubiquitious functional-style support functions
 * no dependencies
 */

var van = {};

/* Currying functions */
/* Example uses found in example/curring.js */

van.fixN = fixN = function(f,a,n){
  n=n||0;
  return function(b){
    args=Array.prototype.slice.call(arguments); // more general now
    args.splice(n,0,a);
    return f.apply(null,args);
  };
};

van.die = die = function(r){
  return Math.floor(Math.random()*r);
};

van.nullArray = nullArray = function(n){
  var temp = [];
  while(n-- > 0)temp.push(null);
  return temp;
};

van.fix1 = fix1 = function(f,a){
  return function(b){
    return f(a,b);
  };
};

van.fix2 = fix2 = function(f,b){
  return function(a){
    return f(a,b);
  };
};

/* Example usage in example/arrays.js */

van.negate = negate = function(p){
  return function(x){
    return !p(x);
  };
};

/* Example usage found in example/compose.js */

van.compose = compose = function(f,g){
  return function(x){
    return g(f(x));
  };
};

van.sum = sum = function(A){
  return A.reduce(function(a,b){
    return a+b;
  });
};

van.range = range = function(a,b){
  var temp=[];
  b = b || a;
  if(a===b)a=0; // beware, if a and b are equal, it indexes from 0
    // maybe that's not what you expect
  while(a<=b)temp.push(a++);
  return temp;
};

van.carte = carte = function(f,A,B){
  return A.map(function(a){
    return B.map(fix1(f,a));
  });
};

van.carteSquare = carteSquare = function(f,A){
  return A.map(function(a,i,z){
    return z.map(fix1(f,a));
  });
};

van.flatten = flatten = function(AA){
  return AA.reduce(function(A,B){
    return A.concat(B);
  });
};

/* A few basic membership handlers */

van.exists = exists = function(A,e){
  return A.indexOf(e);
};

van.vals = vals = function(O){
  return Object.keys(O).map(function(k){
    return O[k];
  });
};

/*
console.log(van.vals({a:"0",b:"1",c:2}));
*/

van.keys = keys = function(O){
  return Object.keys(O);
};

van.is = is = function(a,b){
  return a === b;
};

/* Standard Deviation and other statistical measures */

van.stdDev = stdDev = function(A){
  var S = sum(A),
  L = A.length;
  mean = S/L;
  var variance = sum(A.map(function(x){
    return Math.pow(x-mean,2);
  }))/A.length;
  return Math.pow(variance,0.5);
};

/*
console.log(stdDev([1,2,2,1]));
*/

/* Scheduling */

van.schedule = schedule = function(f,t,n){
  n = n || -1;
  n -= 1;
  if(n===0){
    setTimeout(function(){
      f(n);
    },t);
  }else{
    setTimeout(function(){
      f(n);
      schedule(f,t,n);
    },t);
  }
};

// dat parsimony
if(typeof module!=="undefined"&&module.exports)module.exports=van;
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015-2016, Salesforce.com, Inc.
 * All rights reserved.
 * Licensed under the MIT license.
 * For full license text, see LICENSE.md file in the repo root or
 * https://opensource.org/licenses/MIT
 */

'use strict';

let jQuery = require('jquery');
window.jQuery = jQuery;
require('bootstrap-webpack');
let _ = require('lodash');
//delete window._;
let queryString = require('querystring');
let getParams = queryString.parse(window.location.search.slice(1));

let compiler = require('runway-compiler/lib/compiler.js');
window.compiler = compiler;
let GlobalEnvironment = require('runway-compiler/lib/environment.js').GlobalEnvironment;
let preludeText = require('runway-compiler/lib/prelude.model');

let Controller = require('./controller.js').Controller;
let Highlight = require('./highlight.js');
let makeBrowserRequire = require('./browserrequire.js');
let WorkerClient = require('./workerclient.js');

let AboutView = require('./about.js');
let ExecutionView = require('./executionview.jsx');
let REPLView = require('./repl.jsx');
let RuleControls = require('./rulecontrols.jsx');
let StateDump = require('./statedump.jsx');
let TimelineView = require('./timeline.jsx').TimelineView;

let workerClient = new WorkerClient();

let pageLoaded = new Promise((resolve, reject) => {
  jQuery(window).load(resolve);
});

let basename = 'counter/counter';
if ('model' in getParams) {
  basename = getParams['model'];
}

pageLoaded.then(() => {
  jQuery('.page-header h2 small').text(`${basename}.model`);
});

let browserRequire = makeBrowserRequire('models/');

Promise.all([
  browserRequire(`./${basename}.model`),
  browserRequire(`./${basename}.js`)
    .catch(err => {
      console.log(`Failed to get JS file over HTTP: ${err}`);
      return browserRequire(`./${basename}.jsx`);
    })
    .catch(err => {
      console.log(`Failed to get view file over HTTP: ${err}`);
      return null;
    }),
  pageLoaded,
]).then((results) => {
  let input = results[0];

  let useClock = getParams['clock'] && true;
  let clockUnits;
  if (useClock) {
    if (['us', 'ms', 's'].indexOf(getParams['clock']) >= 0) {
      clockUnits = getParams['clock'];
    } else {
      clockUnits = 'ms';
    }
  }

  let prelude = compiler.loadPrelude(preludeText, {
    clock: useClock,
  });
  let env = new GlobalEnvironment(prelude.env);
  let module;
  try {
    module = compiler.load(input, env);
    window.module = module;
    let context = {
      clock: 0,
    };
    module.ast.execute(context);
  } catch ( e ) {
    jQuery('#error').text(e);
    throw e;
  }
  let controller = new Controller(module);
  controller.clockUnits = clockUnits;

  workerClient.load(preludeText, input, useClock);

  controller.errorHandler = (msg, e) => {
    console.log(msg);
    jQuery('#error').text(msg);
    throw e;
  };
  controller.resetHandler = () => {
    jQuery('#error').text('');
  };
  window.controller = controller;
  controller.addView(StateDump.HTMLStateView);
  controller.addView(ExecutionView);
  controller.addView(REPLView);
  controller.mountTab(elem => elem.appendChild(Highlight(input.getText())),
    'modelcode', 'Model Code');
  controller.addView(AboutView);

  controller.views.push(
    new RuleControls(controller, jQuery('#rulecontrols')[0], module));
  controller.views.push(
    new TimelineView(controller, jQuery('#timeline')[0], module));

  controller.workspace.invariantError.sub(msg => {
    jQuery('#error').text(msg);
  });
  controller.workspace.update.sub(changes => {
    if (controller.workspace.cursor.getEvent().passedInvariants === false) {
      controller.workspace.checkInvariants();
    }
  });

  let userView = results[1];
  if (userView !== null) {
    userView = new userView(controller, jQuery('#view #user')[0], module);
    Promise.resolve(userView).then(v => {
      if (v.name === undefined) {
        v.name = 'User';
      }
      controller.views.push(v);

      let viewWrapper = jQuery('#viewwrapper');
      let smallSide = v.bigView ? 1000 : 100;
      let resize = () => {
        let viewElem = jQuery('#view');
        let width = viewWrapper.width();
        let height = viewWrapper.height();
        console.log(`resize to ${width}, ${height}`);
        viewElem.width(width);
        viewElem.height(height);
        if (width < height) {
          height = height / width * smallSide;
          width = smallSide;
        } else {
          width = width / height * smallSide;
          height = smallSide;
        }
        // viewElem.attr('viewBox', ...) sets viewbox (lowercase) instead
        viewElem[0].setAttribute('viewBox',
          `0 0 ${width} ${height}`);
        v.update(['layout']);
      };
      resize();
      viewWrapper.mouseup(resize);
    });
  }
  jQuery('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
    controller._updateViews();
  });

  let playbackId = undefined;
  let playbackStart = 0;

  let usefulWorkerId = undefined;
  let nextWorkerId = 1;
  let deadlockEvent = undefined;
  let startSimulating = () => {
    let cursor = controller.workspace.cursor.execution.last();
    let startEvent = cursor.getEvent();
    if (usefulWorkerId === undefined &&
        (startEvent.clock < controller.workspace.clock + 1e5 ||
         jQuery('#simulate')[0].checked) &&
        startEvent !== deadlockEvent) {
      let thisWorkerId = nextWorkerId;
      nextWorkerId += 1;
      usefulWorkerId = thisWorkerId;
      workerClient.simulate(startEvent).then(result => {
        let newEvents = result.events;
        if (usefulWorkerId === thisWorkerId) {
          usefulWorkerId = undefined;
          if (newEvents.length === 0) {
            deadlockEvent = startEvent;
          } else {
            deadlockEvent = undefined;
          }
        }
        controller.workspace._output = result.output;
        if (newEvents.length > 0) {
          newEvents.forEach(event => {
            cursor = cursor.addEvent(event);
          });
          controller._updateViews(['execution']);
          startSimulating();
        }
      });
    }
  };
  jQuery('#simulate').change(startSimulating);

  controller.workspace.forked.sub(execution => {
    usefulWorkerId = undefined;
    startSimulating();
  });

  // 'playbackSpeed' is the "x" of slowdown.
  // For asynchronous models without clocks, steps are executed every 10ms of
  // simulation time.
  window.playbackSpeed = getParams['speed'] || 100;
  jQuery('body > div')
    .addClass('paused');
  let toggleAnimate = () => {
    if (jQuery('#playback')[0].checked) {
      jQuery('body > div')
        .addClass('playback')
        .removeClass('paused');
    } else {
      jQuery('body > div')
        .addClass('paused')
        .removeClass('playback');
    }
    let stop = () => {
      window.cancelAnimationFrame(playbackId);
      playbackId = undefined;
    };
    if (playbackId === undefined) {
      let draw = when => {
        playbackId = undefined;
        let elapsed = (when - playbackStart);
        playbackStart = when;
        //console.log('elapsed:', elapsed, 'ms');
        if (elapsed > 500) { // probably had another tab open
          console.log(`Too much time elapsed between animation ` +
            `frames: ${elapsed} ms`);
          elapsed = 0;
        }
        controller.workspace.advanceClock(elapsed * 1000 / window.playbackSpeed);
        let maxGen = controller.workspace.cursor.execution.last().getEvent().clock;
        if (controller.workspace.clock >= maxGen) {
          controller.workspace.setClock(maxGen);
        }
        startSimulating();
        playbackId = window.requestAnimationFrame(draw);
      };
      draw(playbackStart);
    } else {
      stop();
    }
  };
  jQuery('#playback').change(toggleAnimate);
  let mapPlaybackSpeed = fn => {
    window.playbackSpeed = _.clamp(fn(window.playbackSpeed), .1, 5000000);
    console.log(`replay speed set to ${window.playbackSpeed}x slowdown`);
  };
  jQuery('#slower').click(() => mapPlaybackSpeed(s => s * 2));
  jQuery('#faster').click(() => mapPlaybackSpeed(s => s / 2));
});
<commit_msg>web.js: refactor<commit_after>/*
 * Copyright (c) 2015-2016, Salesforce.com, Inc.
 * All rights reserved.
 * Licensed under the MIT license.
 * For full license text, see LICENSE.md file in the repo root or
 * https://opensource.org/licenses/MIT
 */

'use strict';

let jQuery = require('jquery');
window.jQuery = jQuery;
require('bootstrap-webpack');
let _ = require('lodash');
//delete window._;
let queryString = require('querystring');
let getParams = queryString.parse(window.location.search.slice(1));

let compiler = require('runway-compiler/lib/compiler.js');
window.compiler = compiler;
let GlobalEnvironment = require('runway-compiler/lib/environment.js').GlobalEnvironment;
let preludeText = require('runway-compiler/lib/prelude.model');
let PubSub = require('runway-compiler/lib/pubsub.js');

let Controller = require('./controller.js').Controller;
let Highlight = require('./highlight.js');
let makeBrowserRequire = require('./browserrequire.js');
let WorkerClient = require('./workerclient.js');

let AboutView = require('./about.js');
let ExecutionView = require('./executionview.jsx');
let REPLView = require('./repl.jsx');
let RuleControls = require('./rulecontrols.jsx');
let StateDump = require('./statedump.jsx');
let TimelineView = require('./timeline.jsx').TimelineView;

let workerClient = new WorkerClient();

let pageLoaded = new Promise((resolve, reject) => {
  jQuery(window).load(resolve);
});

let createController = function(input, clockUnits) {
  let prelude = compiler.loadPrelude(preludeText, {
    clock: clockUnits !== undefined,
  });
  let env = new GlobalEnvironment(prelude.env);
  let module;
  try {
    module = compiler.load(input, env);
    window.module = module;
    let context = {
      clock: 0,
    };
    module.ast.execute(context);
  } catch ( e ) {
    jQuery('#error').text(e);
    throw e;
  }
  let controller = new Controller(module);
  controller.input = input;
  controller.clockUnits = clockUnits;

  controller.workspace.update.sub(changes => {
    if (controller.workspace.cursor.getEvent().passedInvariants === false) {
      controller.workspace.checkInvariants();
    }
  });

  workerClient.load(preludeText, input, clockUnits !== undefined);
  return controller;
};

let setUpDefaultViews = controller => {
  controller.views.push(
    new RuleControls(controller, jQuery('#rulecontrols')[0], controller.workspace.module));
  controller.views.push(
    new TimelineView(controller, jQuery('#timeline')[0], controller.workspace.module));
  controller.addView(StateDump.HTMLStateView);
  controller.addView(ExecutionView);
  controller.addView(REPLView);
  controller.mountTab(elem => elem.appendChild(Highlight(controller.input.getText())),
    'modelcode', 'Model Code');
  controller.addView(AboutView);
};

let setUpResizing = view => {
  let viewWrapper = jQuery('#viewwrapper');
  let smallSide = view.bigView ? 1000 : 100;
  let resize = () => {
    let viewElem = jQuery('#view');
    let width = viewWrapper.width();
    let height = viewWrapper.height();
    console.log(`resize to ${width}, ${height}`);
    viewElem.width(width);
    viewElem.height(height);
    if (width < height) {
      height = height / width * smallSide;
      width = smallSide;
    } else {
      width = width / height * smallSide;
      height = smallSide;
    }
    // viewElem.attr('viewBox', ...) sets viewbox (lowercase) instead
    viewElem[0].setAttribute('viewBox',
      `0 0 ${width} ${height}`);
    view.update(['layout']);
  };
  resize();
  viewWrapper.mouseup(resize);
};

class Playback {
  constructor() {
    // Publishes the number of ticks to advance by.
    this.tick = new PubSub();

    // 'speed' is the "x" of slowdown.
    // For asynchronous models without clocks, steps are executed every 10ms of
    // simulation time.
    this.speed = getParams['speed'] || 100;

    // When animating, this is the ID returned by
    // window.requestAnimationFrame(). Otherwise undefined.
    this.animationId = undefined;

    // The last time draw was called, in ms.
    // Used to determine how much time has elapsed.
    this.playbackStart = 0;

    pageLoaded.then(() => this.initPage());
  }

  initPage() {
    let map = fn => {
      this.speed = _.clamp(fn(this.speed), .1, 5000000);
      console.log(`replay speed set to ${this.speed}x slowdown`);
    };
    jQuery('#slower').click(() => map(s => s * 2));
    jQuery('#faster').click(() => map(s => s / 2));

    jQuery('body > div')
      .addClass('paused');

    jQuery('#playback').change(() => {
      if (jQuery('#playback')[0].checked) {
        this.start();
      } else {
        this.stop();
      }
    });
  }

  stop() {
    window.cancelAnimationFrame(this.animationId);
    this.animationId = undefined;
    pageLoaded.then(() => {
      jQuery('#playback')[0].checked = false;
      jQuery('body > div')
        .addClass('paused')
        .removeClass('playback');
    });
  }

  onAnimationFrame(when) {
    this.animationId = undefined;
    let elapsed = (when - this.playbackStart);
    this.playbackStart = when;
    //console.log('elapsed:', elapsed, 'ms');
    if (elapsed > 500) { // probably had another tab open
      console.log(`Too much time elapsed between animation ` +
        `frames: ${elapsed} ms`);
    } else {
      this.tick.pub(elapsed * 1000 / this.speed);
    }
    this.animationId = window.requestAnimationFrame(
      when => this.onAnimationFrame(when));
  }

  start() {
    if (this.animationId !== undefined) {
      return;
    }
    this.animationId = window.requestAnimationFrame(
      when => this.onAnimationFrame(when));
    pageLoaded.then(() => {
      jQuery('#playback')[0].checked = true;
      jQuery('body > div')
        .addClass('playback')
        .removeClass('paused');
    });
  }

  animating() {
    return this.animationId !== undefined;
  }
}
let playback = new Playback();

let makeCounter = next => {
  return () => {
    let r = next;
    next += 1;
    return r;
  };
};

class WorkerSimulation {
  constructor(controller) {
    this.controller = controller;

    // Used to match up simulation requests and replies.
    this.allocateWorkerId = makeCounter(1);
    // The ID of a simulation request that we think will generate events to
    // append to the current execution. Otherwise undefined.
    // TODO: is it possible to compare cursors instead? Would be clearer.
    this.usefulWorkerId = undefined;
    // If defined, this event is known to not have any successors, so don't
    // bother trying to run the simulator on it again.
    this.deadlockEvent = undefined;

    this.controller.workspace.forked.sub(execution => {
      this.usefulWorkerId = undefined;
      this.startSimulating();
    });

    pageLoaded.then(() => {
      jQuery('#simulate').change(() => this.startSimulating());
    });
  }

  startSimulating() {
    let cursor = this.controller.workspace.cursor.execution.last();
    let startEvent = cursor.getEvent();
    if (this.usefulWorkerId === undefined &&
        (startEvent.clock < this.controller.workspace.clock + 1e5 ||
         jQuery('#simulate')[0].checked) &&
        startEvent !== this.deadlockEvent) {
      let thisWorkerId = this.allocateWorkerId();
      this.usefulWorkerId = thisWorkerId;
      workerClient.simulate(startEvent).then(result => {
        let newEvents = result.events;
        if (this.usefulWorkerId === thisWorkerId) {
          this.usefulWorkerId = undefined;
          if (newEvents.length === 0) {
            this.deadlockEvent = startEvent;
          } else {
            this.deadlockEvent = undefined;
          }
        }
        this.controller.workspace._output = result.output;
        if (newEvents.length > 0) {
          newEvents.forEach(event => {
            cursor = cursor.addEvent(event);
          });
          this.controller._updateViews(['execution']);
          this.startSimulating();
        }
      });
    }
  }
}

let loadModel = basename => {
  pageLoaded.then(() => {
    jQuery('.page-header h2 small').text(`${basename}.model`);
  });

  let browserRequire = makeBrowserRequire('models/');

  let clockUnits;
  if (getParams['clock']) {
    if (['us', 'ms', 's'].indexOf(getParams['clock']) >= 0) {
      clockUnits = getParams['clock'];
    } else {
      clockUnits = 'ms';
    }
  }

  let specPromise = browserRequire(`./${basename}.model`);
  let viewPromise = browserRequire(`./${basename}.js`)
    .catch(err => {
      console.log(`Failed to get JS file over HTTP: ${err}`);
      return browserRequire(`./${basename}.jsx`);
    })
    .catch(err => {
      console.log(`Failed to get view file over HTTP: ${err}`);
      return null;
    });

  specPromise
    .then(input => createController(input, clockUnits))
    .then(controller => {
      window.controller = controller;
      let workerSimulation = new WorkerSimulation(controller);
      playback.tick.sub(ticks => {
        controller.workspace.advanceClock(ticks);
        let maxGen = controller.workspace.cursor.execution.last().getEvent().clock;
        if (controller.workspace.clock >= maxGen) {
          controller.workspace.setClock(maxGen);
        }
        workerSimulation.startSimulating();
      });

      pageLoaded.then(() => {
        controller.workspace.invariantError.sub(msg => {
          jQuery('#error').text(msg);
        });
        setUpDefaultViews(controller);
        jQuery('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
          controller._updateViews();
        });

        viewPromise
          .then(userView =>
            new userView(controller,
              jQuery('#view #user')[0],
              controller.workspace.module))
          .then(userView => {
            if (userView.name === undefined) {
              userView.name = 'User';
            }
            controller.views.push(userView);
            setUpResizing(userView);
          }); // view loaded
      }); // page loaded

    }); // spec loaded
}; // loadModel()

let basename = 'counter/counter';
if ('model' in getParams) {
  basename = getParams['model'];
}
loadModel(basename);
<|endoftext|>


<commit_before>'use strict';

var passport = require.main.require('passport');
var passportTotp = require('passport-totp').Strategy;
var loggedIn = require.main.require('connect-ensure-login');

var db = require.main.require('./src/database');
var nconf = require.main.require('nconf');
var async = require.main.require('async');
var user = require.main.require('./src/user');
var notifications = require.main.require('./src/notifications');
var utils = require.main.require('./src/utils');
var translator = require.main.require('./public/src/modules/translator');
var routeHelpers = require.main.require('./src/controllers/helpers');
var SocketPlugins = require.main.require('./src/socket.io/plugins');

var plugin = {};

plugin.init = function (params, callback) {
	var router = params.router;
	var hostMiddleware = params.middleware;
	var hostHelpers = require.main.require('./src/routes/helpers');
	var controllers = require('./lib/controllers');
	var middlewares = require('./lib/middlewares');

	// ACP
	router.get('/admin/plugins/2factor', hostMiddleware.admin.buildHeader, controllers.renderAdminPage);
	router.get('/api/admin/plugins/2factor', controllers.renderAdminPage);

	// UCP
	hostHelpers.setupPageRoute(router, '/user/:userslug/2factor', hostMiddleware, [hostMiddleware.requireUser, hostMiddleware.exposeUid], controllers.renderSettings);

	// 2fa Login
	router.get('/login/2fa', hostMiddleware.buildHeader, loggedIn.ensureLoggedIn(), controllers.renderLogin);
	router.get('/api/login/2fa', loggedIn.ensureLoggedIn(), controllers.renderLogin);
	router.post('/login/2fa', loggedIn.ensureLoggedIn(), controllers.processLogin, function (req, res) {
		req.session.tfa = true;
		res.redirect(nconf.get('relative_path') + (req.query.next || '/'));
	});

	// 2fa backups codes
	router.get('/login/2fa/backup', hostMiddleware.buildHeader, loggedIn.ensureLoggedIn(), controllers.renderBackup);
	router.get('/api/login/2fa/backup', loggedIn.ensureLoggedIn(), controllers.renderBackup);
	router.post('/login/2fa/backup', loggedIn.ensureLoggedIn(), controllers.processBackup, function (req, res) {
		req.session.tfa = true;
		res.redirect(nconf.get('relative_path') + (req.query.next || '/'));
	});
	router.put('/login/2fa/backup', hostMiddleware.requireUser, middlewares.requireSecondFactor, hostMiddleware.applyCSRF, controllers.generateBackupCodes);

	// Websockets
	SocketPlugins['2factor'] = require('./websockets');

	// Login Strategy
	passport.use(new passportTotp(
		function (user, done) {
			plugin.get(user.uid, function (err, key) {
				if (err) { return done(err); }
				return done(null, key, 30);
			});
		}
	));

	callback();
};

plugin.addAdminNavigation = function (header, callback) {
	translator.translate('[[2factor:title]]', function (title) {
		header.plugins.push({
			route: '/plugins/2factor',
			icon: 'fa-lock',
			name: title,
		});

		callback(null, header);
	});
};

plugin.addProfileItem = function (data, callback) {
	translator.translate('[[2factor:title]]', function (title) {
		data.links.push({
			id: '2factor',
			route: '2factor',
			icon: 'fa-lock',
			name: title,
			visibility: {
				self: true,
				other: false,
				moderator: false,
				globalMod: false,
				admin: false,
			},
		});

		callback(null, data);
	});
};

plugin.get = function (uid, callback) {
	db.getObjectField('2factor:uid:key', uid, callback);
};

plugin.save = function (uid, key, callback) {
	db.setObjectField('2factor:uid:key', uid, key, callback);
};

plugin.hasKey = function (uid, callback) {
	db.isObjectField('2factor:uid:key', uid, callback);
};

plugin.generateBackupCodes = function (uid, callback) {
	var set = '2factor:uid:' + uid + ':backupCodes';
	var codes = [];
	var code;

	for (var x = 0; x < 5; x++) {
		code = utils.generateUUID().replace('-', '').slice(0, 10);
		codes.push(code);
	}

	async.series([
		async.apply(db.delete, set),		// Invalidate all old codes
		async.apply(db.setAdd, set, codes),	// Save new codes
		function (next) {
			notifications.create({
				bodyShort: '[[2factor:notification.backupCode.generated]]',
				bodyLong: '',
				nid: '2factor.backupCode.generated-' + uid + '-' + Date.now(),
				from: uid,
				path: '/',
			}, function (err, notification) {
				if (!err && notification) {
					notifications.push(notification, [uid], next);
				}
			});
		},
	], function (err) {
		callback(err, codes);
	});
};

plugin.useBackupCode = function (code, uid, callback) {
	var set = '2factor:uid:' + uid + ':backupCodes';

	async.waterfall([
		async.apply(db.isSetMember, set, code),
		function (valid, next) {
			if (valid) {
				// Invalidate this backup code
				db.setRemove(set, code, function (err) {
					next(err, valid);
				});

				notifications.create({
					bodyShort: '[[2factor:notification.backupCode.used]]',
					bodyLong: '',
					nid: '2factor.backupCode.used-' + uid + '-' + Date.now(),
					from: uid,
					path: '/',
				}, function (err, notification) {
					if (!err && notification) {
						notifications.push(notification, [uid]);
					}
				});
			} else {
				next(null, valid);
			}
		},
	], callback);
};

plugin.disassociate = function (uid, callback) {
	async.parallel([
		async.apply(db.deleteObjectField, '2factor:uid:key', uid),
		async.apply(db.delete, '2factor:uid:' + uid + ':backupCodes'),
	], callback);
};

plugin.check = function (req, res, next) {
	if (!req.user || req.session.tfa === true) {
		return next();
	}

	plugin.hasKey(req.user.uid, function (err, hasKey) {
		if (err) {
			return next(err);
		}

		if (hasKey) {
			// Account has TFA, redirect to login
			return routeHelpers.redirect(res, '/login/2fa?next=' + (req.url ? req.url.replace('/api', '') : '/'));
		}

		// No TFA setup
		return next();
	});
};

plugin.checkSocket = function (data, callback) {
	if (!data.socket.uid || data.req.session.tfa === true) {
		return callback();
	}

	plugin.hasKey(data.socket.uid, function (err, hasKey) {
		if (err) {
			return callback(err);
		}

		if (hasKey) {
			return callback(new Error('[[2factor:second-factor-required]]'));
		}

		// No TFA setup
		return callback();
	});
};

plugin.clearSession = function (data, callback) {
	if (data.req.session) {
		delete data.req.session.tfa;
	}

	setImmediate(callback);
};

plugin.getUsers = function (callback) {
	async.waterfall([
		async.apply(db.getObjectKeys, '2factor:uid:key'),
		function (uids, next) {
			user.getUsersFields(uids, ['username', 'userslug', 'picture'], next);
		},
	], callback);
};

plugin.updateTitle = function (data, callback) {
	translator.translate('[[2factor:title]]', function (title) {
		if (data.templateData.url.match(/user\/.+\/2factor/)) {
			data.templateData.title = title;
		}
		callback(null, data);
	});
};

module.exports = plugin;
<commit_msg>fix: reference to diff file<commit_after>'use strict';

var passport = require.main.require('passport');
var passportTotp = require('passport-totp').Strategy;
var loggedIn = require.main.require('connect-ensure-login');

var db = require.main.require('./src/database');
var nconf = require.main.require('nconf');
var async = require.main.require('async');
var user = require.main.require('./src/user');
var notifications = require.main.require('./src/notifications');
var utils = require.main.require('./src/utils');
var translator = require.main.require('./src/translator');
var routeHelpers = require.main.require('./src/controllers/helpers');
var SocketPlugins = require.main.require('./src/socket.io/plugins');

var plugin = {};

plugin.init = function (params, callback) {
	var router = params.router;
	var hostMiddleware = params.middleware;
	var hostHelpers = require.main.require('./src/routes/helpers');
	var controllers = require('./lib/controllers');
	var middlewares = require('./lib/middlewares');

	// ACP
	router.get('/admin/plugins/2factor', hostMiddleware.admin.buildHeader, controllers.renderAdminPage);
	router.get('/api/admin/plugins/2factor', controllers.renderAdminPage);

	// UCP
	hostHelpers.setupPageRoute(router, '/user/:userslug/2factor', hostMiddleware, [hostMiddleware.requireUser, hostMiddleware.exposeUid], controllers.renderSettings);

	// 2fa Login
	router.get('/login/2fa', hostMiddleware.buildHeader, loggedIn.ensureLoggedIn(), controllers.renderLogin);
	router.get('/api/login/2fa', loggedIn.ensureLoggedIn(), controllers.renderLogin);
	router.post('/login/2fa', loggedIn.ensureLoggedIn(), controllers.processLogin, function (req, res) {
		req.session.tfa = true;
		res.redirect(nconf.get('relative_path') + (req.query.next || '/'));
	});

	// 2fa backups codes
	router.get('/login/2fa/backup', hostMiddleware.buildHeader, loggedIn.ensureLoggedIn(), controllers.renderBackup);
	router.get('/api/login/2fa/backup', loggedIn.ensureLoggedIn(), controllers.renderBackup);
	router.post('/login/2fa/backup', loggedIn.ensureLoggedIn(), controllers.processBackup, function (req, res) {
		req.session.tfa = true;
		res.redirect(nconf.get('relative_path') + (req.query.next || '/'));
	});
	router.put('/login/2fa/backup', hostMiddleware.requireUser, middlewares.requireSecondFactor, hostMiddleware.applyCSRF, controllers.generateBackupCodes);

	// Websockets
	SocketPlugins['2factor'] = require('./websockets');

	// Login Strategy
	passport.use(new passportTotp(
		function (user, done) {
			plugin.get(user.uid, function (err, key) {
				if (err) { return done(err); }
				return done(null, key, 30);
			});
		}
	));

	callback();
};

plugin.addAdminNavigation = function (header, callback) {
	translator.translate('[[2factor:title]]', function (title) {
		header.plugins.push({
			route: '/plugins/2factor',
			icon: 'fa-lock',
			name: title,
		});

		callback(null, header);
	});
};

plugin.addProfileItem = function (data, callback) {
	translator.translate('[[2factor:title]]', function (title) {
		data.links.push({
			id: '2factor',
			route: '2factor',
			icon: 'fa-lock',
			name: title,
			visibility: {
				self: true,
				other: false,
				moderator: false,
				globalMod: false,
				admin: false,
			},
		});

		callback(null, data);
	});
};

plugin.get = function (uid, callback) {
	db.getObjectField('2factor:uid:key', uid, callback);
};

plugin.save = function (uid, key, callback) {
	db.setObjectField('2factor:uid:key', uid, key, callback);
};

plugin.hasKey = function (uid, callback) {
	db.isObjectField('2factor:uid:key', uid, callback);
};

plugin.generateBackupCodes = function (uid, callback) {
	var set = '2factor:uid:' + uid + ':backupCodes';
	var codes = [];
	var code;

	for (var x = 0; x < 5; x++) {
		code = utils.generateUUID().replace('-', '').slice(0, 10);
		codes.push(code);
	}

	async.series([
		async.apply(db.delete, set),		// Invalidate all old codes
		async.apply(db.setAdd, set, codes),	// Save new codes
		function (next) {
			notifications.create({
				bodyShort: '[[2factor:notification.backupCode.generated]]',
				bodyLong: '',
				nid: '2factor.backupCode.generated-' + uid + '-' + Date.now(),
				from: uid,
				path: '/',
			}, function (err, notification) {
				if (!err && notification) {
					notifications.push(notification, [uid], next);
				}
			});
		},
	], function (err) {
		callback(err, codes);
	});
};

plugin.useBackupCode = function (code, uid, callback) {
	var set = '2factor:uid:' + uid + ':backupCodes';

	async.waterfall([
		async.apply(db.isSetMember, set, code),
		function (valid, next) {
			if (valid) {
				// Invalidate this backup code
				db.setRemove(set, code, function (err) {
					next(err, valid);
				});

				notifications.create({
					bodyShort: '[[2factor:notification.backupCode.used]]',
					bodyLong: '',
					nid: '2factor.backupCode.used-' + uid + '-' + Date.now(),
					from: uid,
					path: '/',
				}, function (err, notification) {
					if (!err && notification) {
						notifications.push(notification, [uid]);
					}
				});
			} else {
				next(null, valid);
			}
		},
	], callback);
};

plugin.disassociate = function (uid, callback) {
	async.parallel([
		async.apply(db.deleteObjectField, '2factor:uid:key', uid),
		async.apply(db.delete, '2factor:uid:' + uid + ':backupCodes'),
	], callback);
};

plugin.check = function (req, res, next) {
	if (!req.user || req.session.tfa === true) {
		return next();
	}

	plugin.hasKey(req.user.uid, function (err, hasKey) {
		if (err) {
			return next(err);
		}

		if (hasKey) {
			// Account has TFA, redirect to login
			return routeHelpers.redirect(res, '/login/2fa?next=' + (req.url ? req.url.replace('/api', '') : '/'));
		}

		// No TFA setup
		return next();
	});
};

plugin.checkSocket = function (data, callback) {
	if (!data.socket.uid || data.req.session.tfa === true) {
		return callback();
	}

	plugin.hasKey(data.socket.uid, function (err, hasKey) {
		if (err) {
			return callback(err);
		}

		if (hasKey) {
			return callback(new Error('[[2factor:second-factor-required]]'));
		}

		// No TFA setup
		return callback();
	});
};

plugin.clearSession = function (data, callback) {
	if (data.req.session) {
		delete data.req.session.tfa;
	}

	setImmediate(callback);
};

plugin.getUsers = function (callback) {
	async.waterfall([
		async.apply(db.getObjectKeys, '2factor:uid:key'),
		function (uids, next) {
			user.getUsersFields(uids, ['username', 'userslug', 'picture'], next);
		},
	], callback);
};

plugin.updateTitle = function (data, callback) {
	translator.translate('[[2factor:title]]', function (title) {
		if (data.templateData.url.match(/user\/.+\/2factor/)) {
			data.templateData.title = title;
		}
		callback(null, data);
	});
};

module.exports = plugin;
<|endoftext|>


<commit_before>/* @flow */
import React from 'react';
import { GoogleMap } from 'react-google-maps';
import ScriptjsLoader from 'react-google-maps/lib/async/ScriptjsLoader';
import { latLon } from '../../../types/map';

type Props = {
  spanFullPage: ?boolean,
  defaultCenter: latLon,
};

/** @class Map */
function Map(props : Props) {
  const containerElement = (

  );

  const googleMapElement = (
    <GoogleMap
      defaultZoom={15}
      defaultCenter={props.defaultCenter}
    />
  );

  return (


<commit_before>(function(module) {
	"use strict";

	var SoundCloud = {},
		embed = '';

	SoundCloud.parse = function(postContent, callback) {
		// modified from http://stackoverflow.com/questions/7168987/
		postContent = postContent.replace(/<\/a>/g, embed);
		callback(null, postContent);
	};

	module.exports = SoundCloud;
}(module));
<commit_msg>change temp<commit_after>(function(module) {
	"use strict";

	var SoundCloud = {},
		embed = '';

	SoundCloud.parse = function(postContent, callback) {
		// modified from http://stackoverflow.com/questions/7168987/
		postContent = postContent.replace(/.+<\/a>/g, embed);
		callback(null, postContent);
	};

	module.exports = SoundCloud;
}(module));
<|endoftext|>