<commit_before>/*! @license
 * Karma Local WebDriver Launcher
 * Copyright 2022 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @fileoverview
 *
 * Launches local web browsers using WebDriver, to enable screenshots and other
 * advanced tests to be executed in-browser.  If you don't need WebDriver to
 * enable some test scenario in Karma, you can just use typical local browser
 * launchers.
 *
 * Supports Chrome, Firefox, and Safari.
 */

const os = require('os');
const url = require('url');
const wd = require('wd');

// Map nodejs OS names to Selenium platform names.
const PLATFORM_MAP = {
  'darwin': 'Mac',
  'win32': 'Windows',
  'linux': 'Linux',
};

const LocalWebDriverBase =
    function(browserName, driverCommand, baseBrowserDecorator, logger) {
  baseBrowserDecorator(this);

  this.browserName = browserName;

  this.DEFAULT_CMD = {
    linux: driverCommand,
    darwin: driverCommand,
    win32: driverCommand,
  };

  this.ENV_CMD = driverCommand.toUpperCase() + '_PATH';

  const config = {
    protocol: 'http:',
    hostname: '127.0.0.1',
    port: Math.floor((Math.random() * 1000)) + 4000,
    pathname: '/'
  };

  const webDriver = url.format(config);
  this.name = `${this.browserName} via WebDriver at ` + webDriver;

  const log = logger.create(this.name);
  log.debug('config:', JSON.stringify(config));

  // These names ("browser" and "spec") are needed for compatibility with
  // karma-webdriver-launcher.
  this.browser = wd.remote(config);
  this.spec = {
    browserName: this.browserName.toLowerCase(),
    platform: PLATFORM_MAP[os.platform()],
  };

  this.browser.on('status', (info) => {
    log.debug('Status: ' + info);
  });

  this.browser.on('command', (eventType, command, response) => {
    log.debug('[command] ' + eventType + ' ' + command + ' ' + (response || ''));
  });

  this.browser.on('http', (meth, path, data) => {
    log.debug('[http] ' + meth + ' ' + path + ' ' + (data || ''));
  });

  this._getOptions = () => ['-p', config.port.toString()];

  this.on('start', (url) => {
    this.browser.init(this.spec, (error) => {
      if (error) {
        log.error(`Could not connect to ${this.browserName} WebDriver`);
        log.error(error);
      } else {
        log.debug(`Connected to ${this.browserName} WebDriver`);
        log.debug('Connecting to ' + url);
        this.browser.get(url);
      }
    });
  });

  // The base decorators will listen for the 'kill' event to close the process
  // for the driver.  Once that happens, we can no longer stop the webdriver
  // connection and close the open browser window.  There is no way to register
  // a listener ahead of the base class's, so to shut down the browser
  // properly, we need to reimplement all the methods that could trigger a
  // 'kill' event.
  this.kill = async () => {
    this.state = 'BEING_KILLED';
    await this.stopWebdriver_();
  };

  this.forceKill = async () => {
    this.state = 'BEING_FORCE_KILLED';
    await this.stopWebdriver_();
  };

  const originalStart = this.start;
  let previousUrl = null;

  this.start = (url) => {
    previousUrl = url;
    originalStart.call(this, url);
  };

  this.restart = async () => {
    if (this.state == 'BEING_FORCE_KILLED') {
      return;
    }

    this.state = 'RESTARTING';
    await this.stopWebDriver();

    if (this.state != 'BEING_FORCE_KILLED') {
      log.debug(`Restarting ${this.name}`)
      this.start(previousUrl);
    }
  };

  this.stopWebdriver_ = async () => {
    if (this.browser) {
      await new Promise(resolve => this.browser.quit(resolve));
    }

    // Now that the driver connection and browser are closed, emit the signal
    // that shuts down the driver executable.
    await this.emitAsync('kill');

    this.state = 'FINISHED';
  };
}

const LocalWebDriverChrome = function(baseBrowserDecorator, logger) {
  LocalWebDriverBase.call(this,
      'Chrome', 'chromedriver', baseBrowserDecorator, logger);
};

const LocalWebDriverFirefox = function(baseBrowserDecorator, logger) {
  LocalWebDriverBase.call(this,
      'Firefox', 'geckodriver', baseBrowserDecorator, logger);
};

const LocalWebDriverSafari = function(baseBrowserDecorator, logger) {
  LocalWebDriverBase.call(this,
      'Safari', 'safaridriver', baseBrowserDecorator, logger);
};

LocalWebDriverChrome.$inject = ['baseBrowserDecorator', 'logger'];
LocalWebDriverFirefox.$inject = ['baseBrowserDecorator', 'logger'];
LocalWebDriverSafari.$inject = ['baseBrowserDecorator', 'logger'];

module.exports = {
  'launcher:Chrome': ['type', LocalWebDriverChrome],
  'launcher:Firefox': ['type', LocalWebDriverFirefox],
};

// Safari is only supported on Mac.
if (os.platform() == 'darwin') {
  module.exports['launcher:Safari'] = ['type', LocalWebDriverSafari];
}
<commit_msg>fix: Fix chromedriver arguments<commit_after>/*! @license
 * Karma Local WebDriver Launcher
 * Copyright 2022 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @fileoverview
 *
 * Launches local web browsers using WebDriver, to enable screenshots and other
 * advanced tests to be executed in-browser.  If you don't need WebDriver to
 * enable some test scenario in Karma, you can just use typical local browser
 * launchers.
 *
 * Supports Chrome, Firefox, and Safari.
 */

const os = require('os');
const url = require('url');
const wd = require('wd');

// Map nodejs OS names to Selenium platform names.
const PLATFORM_MAP = {
  'darwin': 'Mac',
  'win32': 'Windows',
  'linux': 'Linux',
};

const LocalWebDriverBase = function(
    browserName, driverCommand, argsFromPort, baseBrowserDecorator, logger) {
  baseBrowserDecorator(this);

  this.browserName = browserName;

  this.DEFAULT_CMD = {
    linux: driverCommand,
    darwin: driverCommand,
    win32: driverCommand,
  };

  const port = Math.floor((Math.random() * 1000)) + 4000;

  // Called by the base class to get arguments to pass to the driver command.
  this._getOptions = () => argsFromPort(port.toString());

  this.ENV_CMD = driverCommand.toUpperCase() + '_PATH';

  const config = {
    protocol: 'http:',
    hostname: '127.0.0.1',
    port,
    pathname: '/'
  };

  const webDriver = url.format(config);
  this.name = `${this.browserName} via WebDriver at ` + webDriver;

  const log = logger.create(this.name);
  log.debug('config:', JSON.stringify(config));

  // These names ("browser" and "spec") are needed for compatibility with
  // karma-webdriver-launcher.
  this.browser = wd.remote(config);
  this.spec = {
    browserName: this.browserName.toLowerCase(),
    platform: PLATFORM_MAP[os.platform()],
  };

  this.browser.on('status', (info) => {
    log.debug('Status: ' + info);
  });

  this.browser.on('command', (eventType, command, response) => {
    log.debug('[command] ' + eventType + ' ' + command + ' ' + (response || ''));
  });

  this.browser.on('http', (meth, path, data) => {
    log.debug('[http] ' + meth + ' ' + path + ' ' + (data || ''));
  });

  this.on('start', (url) => {
    this.browser.init(this.spec, (error) => {
      if (error) {
        log.error(`Could not connect to ${this.browserName} WebDriver`);
        log.error(error);
      } else {
        log.debug(`Connected to ${this.browserName} WebDriver`);
        log.debug('Connecting to ' + url);
        this.browser.get(url);
      }
    });
  });

  // The base decorators will listen for the 'kill' event to close the process
  // for the driver.  Once that happens, we can no longer stop the webdriver
  // connection and close the open browser window.  There is no way to register
  // a listener ahead of the base class's, so to shut down the browser
  // properly, we need to reimplement all the methods that could trigger a
  // 'kill' event.
  this.kill = async () => {
    this.state = 'BEING_KILLED';
    await this.stopWebdriver_();
  };

  this.forceKill = async () => {
    this.state = 'BEING_FORCE_KILLED';
    await this.stopWebdriver_();
  };

  const originalStart = this.start;
  let previousUrl = null;

  this.start = (url) => {
    previousUrl = url;
    originalStart.call(this, url);
  };

  this.restart = async () => {
    if (this.state == 'BEING_FORCE_KILLED') {
      return;
    }

    this.state = 'RESTARTING';
    await this.stopWebDriver();

    if (this.state != 'BEING_FORCE_KILLED') {
      log.debug(`Restarting ${this.name}`)
      this.start(previousUrl);
    }
  };

  this.stopWebdriver_ = async () => {
    if (this.browser) {
      await new Promise(resolve => this.browser.quit(resolve));
    }

    // Now that the driver connection and browser are closed, emit the signal
    // that shuts down the driver executable.
    await this.emitAsync('kill');

    this.state = 'FINISHED';
  };
}

const LocalWebDriverChrome = function(baseBrowserDecorator, logger) {
  LocalWebDriverBase.call(this,
      'Chrome', 'chromedriver', (port) => ['--port=' + port],
      baseBrowserDecorator, logger);
};

// TODO: Add Chrome on android?

const LocalWebDriverFirefox = function(baseBrowserDecorator, logger) {
  LocalWebDriverBase.call(this,
      'Firefox', 'geckodriver', (port) => ['-p', port],
      baseBrowserDecorator, logger);
};

const LocalWebDriverSafari = function(baseBrowserDecorator, logger) {
  LocalWebDriverBase.call(this,
      'Safari', '/usr/bin/safaridriver', (port) => ['-p', port],
      baseBrowserDecorator, logger);
};

// TODO: Add MS Edge

LocalWebDriverChrome.$inject = ['baseBrowserDecorator', 'logger'];
LocalWebDriverFirefox.$inject = ['baseBrowserDecorator', 'logger'];
LocalWebDriverSafari.$inject = ['baseBrowserDecorator', 'logger'];

module.exports = {
  'launcher:Chrome': ['type', LocalWebDriverChrome],
  'launcher:Firefox': ['type', LocalWebDriverFirefox],
};

// Safari is only supported on Mac.
if (os.platform() == 'darwin') {
  module.exports['launcher:Safari'] = ['type', LocalWebDriverSafari];
}
<|endoftext|>


<commit_before>'use strict';

const bunyan = require('bunyan');
const createCWStream = require('bunyan-cloudwatch');

let loggerInstance = null;

class BunyanCWLogger {

  constructor(logGroup, streamName, arn) {
    this.arn = arn;
    this.logGroup = logGroup;
    this.streamName = streamName;
  }

  static getInstance() {
    if (!loggerInstance || loggerInstance === null) {
      throw new Error('Logger is not initialized');
    }
    return loggerInstance;
  }

  build() {
    this._validateInput();
    this._populateProperties();
    this._createCWStream();
    this._createBunyanLogger();
    this._setLoggerInstance();
    BunyanCWLogger._addEndMethod();
  }

  _setLoggerInstance() {
    loggerInstance = this.bunyanLogger;
  }

  _createBunyanLogger() {
    this.bunyanLogger = bunyan.createLogger({
      name: this.name,
      hostname: this.hostname,
      src: true,
      level: this.logLevel,
      node_env: process.env.NODE_ENV,
      serializers: {
        err: err => ({
          name: err.name,
          cause: err.message,
        }),
      },
      streams: [{ stream: this.cwStream, type: 'raw' },
        { stream: process.stdout, level: this.logLevel },
      ],
    });
  }

  _createCWStream() {
    this.cwStream = createCWStream({
      logGroupName: this.logGroup,
      logStreamName: this.streamName,
      cloudWatchLogsOptions: {
        region: this.region,
      },
    });
  }

  _populateProperties() {
    const arnArray = this.arn.split(':');
    this.hostname = (arnArray[7] || 'none');
    this.name = arnArray[6];
    this.region = arnArray[3];

    this.logLevel = bunyan.DEBUG;
    if (process.env.NODE_ENV === 'prod') {
      this.logLevel = bunyan.INFO;
    }
  }

  _validateInput() {
    if (!this.arn) {
      throw Error('Unable to setup logger. No arn was supplied');
    }
    const arnArray = this.arn.split(':');
    if (arnArray.length < 7) {
      throw Error('Invalid ARN');
    }
    if (!arnArray[6] || arnArray[6].length === 0) {
      throw Error('ARN is missing function name');
    }
    if (!arnArray[3] || arnArray[3].length === 0) {
      throw Error('ARN is missing region name');
    }
    if (!this.logGroup || this.logGroup.length === 0) {
      throw Error('logGroup is missing');
    }
    if (!this.streamName || this.streamName.length === 0) {
      throw Error('streamName is missing');
    }
  }

  static _addEndMethod() {
    if (!loggerInstance || loggerInstance === null) {
      throw new Error('Logger instance is not configured');
    }

    loggerInstance.end = (callback) => {
      setInterval(() => {
        if (!loggerInstance.streams[0].stream.writeQueued) {
          loggerInstance = null;
          callback();
        }
      }, 10);
    };
  }
}

module.exports = BunyanCWLogger;
<commit_msg>Bug fix.<commit_after>'use strict';

const bunyan = require('bunyan');
const createCWStream = require('bunyan-cloudwatch');

let loggerInstance = null;

class BunyanCWLogger {

  constructor(logGroup, streamName, arn) {
    this.arn = arn;
    this.logGroup = logGroup;
    this.streamName = streamName;
  }

  static getInstance() {
    if (!loggerInstance || loggerInstance === null) {
      throw new Error('Logger is not initialized');
    }
    return loggerInstance;
  }

  build() {
    this._validateInput();
    this._populateProperties();
    this._createCWStream();
    this._createBunyanLogger();
    this._setLoggerInstance();
    BunyanCWLogger._addEndMethod();
  }

  _setLoggerInstance() {
    loggerInstance = this.bunyanLogger;
  }

  _createBunyanLogger() {
    this.bunyanLogger = bunyan.createLogger({
      name: this.name,
      hostname: this.hostname,
      src: true,
      level: this.logLevel,
      node_env: process.env.NODE_ENV,
      serializers: {
        err: err => ({
          name: err.name,
          cause: err.message,
        }),
      },
      streams: [{ stream: this.cwStream, type: 'raw' },
        { stream: process.stdout, level: this.logLevel },
      ],
    });
  }

  _createCWStream() {
    this.cwStream = createCWStream({
      logGroupName: this.logGroup,
      logStreamName: this.streamName,
      cloudWatchLogsOptions: {
        region: this.region,
      },
    });
  }

  _populateProperties() {
    const arnArray = this.arn.split(':');
    this.hostname = (arnArray[7] || 'none');
    this.name = arnArray[6];
    this.region = arnArray[3];

    this.logLevel = bunyan.DEBUG;
    if (process.env.NODE_ENV === 'prod') {
      this.logLevel = bunyan.INFO;
    }
  }

  _validateInput() {
    if (!this.arn) {
      throw Error('Unable to setup logger. No arn was supplied');
    }
    const arnArray = this.arn.split(':');
    if (arnArray.length < 7) {
      throw Error('Invalid ARN');
    }
    if (!arnArray[6] || arnArray[6].length === 0) {
      throw Error('ARN is missing function name');
    }
    if (!arnArray[3] || arnArray[3].length === 0) {
      throw Error('ARN is missing region name');
    }
    if (!this.logGroup || this.logGroup.length === 0) {
      throw Error('logGroup is missing');
    }
    if (!this.streamName || this.streamName.length === 0) {
      throw Error('streamName is missing');
    }
  }

  static _addEndMethod() {
    if (!loggerInstance || loggerInstance === null) {
      throw new Error('Logger instance is not configured');
    }

    loggerInstance.end = (callback) => {
      setInterval(() => {
        if (loggerInstance && !loggerInstance.streams[0].stream.writeQueued) {
          loggerInstance = null;
          callback();
        }
      }, 10);
    };
  }
}

module.exports = BunyanCWLogger;
<|endoftext|>


<commit_before>try {
	var Config = require('./config.json');
} catch (e){
	Config.debug = false;
	Config.respondToInvalid = false;
}

try {
	var AuthDetails = require('./auth.json');
} catch (e){
	console.log("Please create an auth.json file with account email and password"+e.stack);
	process.exit();
}

try {
	var Discord = require("discord.js");
} catch (e){
	console.log("Please run npm install discord.js"+e.stack);
	process.exit();
}

try {
	var d20 = require('d20');
} catch (e){
	console.log("Please run npm install d20"+e.stack);
}

var commands = {
	"dam": {
		usage: "",
		description: "returns image/gif",
		process: function(bot, msg) {
			var rand = Math.floor(Math.random() * 2) + 1;
			var result;
			if (rand == 1)
				result = 'https://i.imgur.com/7lZwLKc.jpg';
			else
				result = 'https://i.imgur.com/VQLGJOL.gif';
			bot.sendMessage(msg.channel, result);
		}
	},
	"happy": {
		usage: "",
		description: "returns image/gif",
		process: function(bot, msg) {
			var rand = Math.floor(Math.random() * 2) + 1;
			var result;
			if (rand == 1)
			  result = 'https://i.imgur.com/gbXzYXp.gif';
			else
			  result = 'https://i.imgur.com/OxwIC0O.gif';
			bot.sendMessage(msg.channel, result);
		}
	},
	"horse": {
		usage: "",
		description: "returns horse gif",
		process: function(bot, msg) {
			var result = 'https://i.giphy.com/S4mOmgmpBQAXm.gif';
			bot.sendMessage(msg.channel, result);
		}
	},
	"img": {
		usage: "<search term>",
		description: "searches imgur based on keyword",
		process: function(bot, msg, suffix) {
			var key = AuthDetails;
			var Imgur = require('imgur-search');

			var term = suffix;
			if(!term) {
				bot.sendMessage(msg.channel, "No Search Term");
				return;
			}
			new Imgur(key.imgur_key).search(term).then(function(result) {
				if (result.length == 0 || result == undefined) {
					bot.sendMessage(msg.channel, "You suck at searching");
				} else {
					var img = result[Math.floor(Math.random() * result.length)];
					bot.sendMessage(msg.channel, img.link);
				}
			});
		}
	},
	"why": {
		usage: "",
		description: "returns gif",
		process: function(bot, msg) {
			var result = 'https://media.giphy.com/media/1M9fmo1WAFVK0/giphy.gif';
			bot.sendMessage(msg.channel, result);
		}
	},
	"roll": {
		usage: "[#d#]",
		description: "dice roller, with single command giving a d20, otherwise rolling specified combo",
		process: function(bot, msg, suffix) {
			if(!suffix) {
				bot.sendMessage(msg.channel, msg.author + " rolled: " + d20.roll(20));
			} else {
				var result;
				try {
					result = d20.roll(suffix);
				} catch (e){
					bot.sendMessage(msg.channel, msg.author + " Could not roll " + suffix);
					return;
				}
				if (!isNaN(result) && result != 'NaN')
					bot.sendMessage(msg.channel, msg.author + " rolled: " + d20.verboseRoll(suffix));
				else
					bot.sendMessage(msg.channel, msg.author + " Not a valid number");
			}
		}
	},
	"rolloff": {
		usage: "",
		description: "Roll off against the bot (D20)",
		process: function(bot, msg) {
			var roll_bot;
			var roll_usr;

			bot.sendMessage(msg.channel, "A CHALLENGER APPROACHES!")
			roll_bot = d20.roll(20);
			roll_usr = d20.roll(20);

			if (roll_bot > roll_usr)
				bot.sendMessage(msg.channel, "MUAHAHAHA. My " + roll_bot + " p4wned your " + roll_usr + ". Get rekt.")
			else if (roll_usr > roll_bot)
				bot.sendMessage(msg.channel, "Lucky roll... My " + roll_bot + " can't beat your " + roll_usr + ".")
			else
				bot.sendMessage(msg.channel, "Tie? TIE!? Let's call that a win for me...")
		}
	},
	"blown": {
		usage: "",
		description: "returns gif",
		process: function(bot, msg) {
			var result;
			var rand = Math.floor(Math.random() * 6);
			var gifs = [	'https://i.imgur.com/YGsTG5o.gif',
					'https://i.imgur.com/pBTk7MC.gif',
					'https://i.imgur.com/rfFWukr.gif',
					'https://media.giphy.com/media/OK27wINdQS5YQ/giphy.gif',
					'https://i.imgur.com/l4bJmRE.gif',
					'https://i.imgur.com/3WB3L.gif',
					'https://giphy.com/gifs/cheezburger-robots-screaming-NfEQd1ge1kP04']

			bot.sendMessage(msg.channel, gifs[rand]);
		}
	},
	"weekend": {
		usage: "",
		description: "returns days until weekend",
		process: function(bot, msg) {
			var date = new Date();
			var day = date.getDay();
			var result = ["TGIF!", "1 Day left", "2 Days left", "3 Days left", "4 Days left"];
			var temp = 5 - day;

			if (day == 6){
				bot.sendMessage(msg.channel, "IT'S THE WEEKEND!");
			} else if (day == 0) {
				bot.sendMessage(msg.channel, "Last day, Enjoy it!");
			} else {
				bot.sendMessage(msg.channel, result[temp]);
			}
		}
	}
};

var bot = new Discord.Client();

bot.on("ready", function () {
	console.log("Ready to start. Channels: " + bot.channels.length);
});

bot.on('disconnected', function() {
	console.log('Disconnected.');
	process.exit(1);
});

bot.on("message", function (msg) {
	if(msg.author.id != bot.user.id && msg.content[0] === '!'){
		var cmdTxt = msg.content.split(" ")[0].substring(1);
        	var suffix = msg.content.substring(cmdTxt.length+2);
		var cmd = commands[cmdTxt];

        	if(cmdTxt === "help"){
			var info = "Available Commands: ";
			for(var cmd in commands) {
				info += "!" + cmd;
				var usage = commands[cmd].usage;
				if(usage){
					info += " " + usage + "; ";
				}
				else
					info += "; ";
			}
			bot.sendMessage(msg.author,info);
        	} else if(cmd) {
			try{
				cmd.process(bot,msg,suffix);
			} catch(e){
				if(Config.debug){
					bot.sendMessage(msg.channel, "command " + cmdTxt + " failed :(\n" + e.stack);
				}
			}
		} else {
			bot.sendMessage(msg.author, " Invalid command, Sucka!  Maybe you need some !help");
		}
	} else if (msg.author != bot.user && msg.isMentioned(bot.user)) {
		bot.sendMessage(msg.channel,msg.author + ", you called?");
    	}
});

exports.addCommand = function(commandName, commandObject){
    try {
        commands[commandName] = commandObject;
    } catch(err){
        console.log(err);
    }
}
exports.commandCount = function(){
    return Object.keys(commands).length;
}

bot.login(AuthDetails.email, AuthDetails.password);
<commit_msg>fixing new command<commit_after>try {
	var Config = require('./config.json');
} catch (e){
	Config.debug = false;
	Config.respondToInvalid = false;
}

try {
	var AuthDetails = require('./auth.json');
} catch (e){
	console.log("Please create an auth.json file with account email and password"+e.stack);
	process.exit();
}

try {
	var Discord = require("discord.js");
} catch (e){
	console.log("Please run npm install discord.js"+e.stack);
	process.exit();
}

try {
	var d20 = require('d20');
} catch (e){
	console.log("Please run npm install d20"+e.stack);
}

var commands = {
	"dam": {
		usage: "",
		description: "returns image/gif",
		process: function(bot, msg) {
			var rand = Math.floor(Math.random() * 2) + 1;
			var result;
			if (rand == 1)
				result = 'https://i.imgur.com/7lZwLKc.jpg';
			else
				result = 'https://i.imgur.com/VQLGJOL.gif';
			bot.sendMessage(msg.channel, result);
		}
	},
	"happy": {
		usage: "",
		description: "returns image/gif",
		process: function(bot, msg) {
			var rand = Math.floor(Math.random() * 2) + 1;
			var result;
			if (rand == 1)
			  result = 'https://i.imgur.com/gbXzYXp.gif';
			else
			  result = 'https://i.imgur.com/OxwIC0O.gif';
			bot.sendMessage(msg.channel, result);
		}
	},
	"horse": {
		usage: "",
		description: "returns horse gif",
		process: function(bot, msg) {
			var result = 'https://i.giphy.com/S4mOmgmpBQAXm.gif';
			bot.sendMessage(msg.channel, result);
		}
	},
	"img": {
		usage: "<search term>",
		description: "searches imgur based on keyword",
		process: function(bot, msg, suffix) {
			var key = AuthDetails;
			var Imgur = require('imgur-search');

			var term = suffix;
			if(!term) {
				bot.sendMessage(msg.channel, "No Search Term");
				return;
			}
			new Imgur(key.imgur_key).search(term).then(function(result) {
				if (result.length == 0 || result == undefined) {
					bot.sendMessage(msg.channel, "You suck at searching");
				} else {
					var img = result[Math.floor(Math.random() * result.length)];
					bot.sendMessage(msg.channel, img.link);
				}
			});
		}
	},
	"why": {
		usage: "",
		description: "returns gif",
		process: function(bot, msg) {
			var result = 'https://media.giphy.com/media/1M9fmo1WAFVK0/giphy.gif';
			bot.sendMessage(msg.channel, result);
		}
	},
	"roll": {
		usage: "[#d#]",
		description: "dice roller, with single command giving a d20, otherwise rolling specified combo",
		process: function(bot, msg, suffix) {
			if(!suffix) {
				bot.sendMessage(msg.channel, msg.author + " rolled: " + d20.roll(20));
			} else {
				var result;
				try {
					result = d20.roll(suffix);
				} catch (e){
					bot.sendMessage(msg.channel, msg.author + " Could not roll " + suffix);
					return;
				}
				if (!isNaN(result) && result != 'NaN')
					bot.sendMessage(msg.channel, msg.author + " rolled: " + d20.verboseRoll(suffix));
				else
					bot.sendMessage(msg.channel, msg.author + " Not a valid number");
			}
		}
	},
	"rolloff": {
		usage: "",
		description: "Roll off against the bot (D20)",
		process: function(bot, msg) {
			var roll_bot;
			var roll_usr;

			roll_bot = d20.roll(20);
			roll_usr = d20.roll(20);
			bot.sendMessage(msg.channel, "A CHALLENGER APPROACHES!");

			if (roll_bot > roll_usr)
				bot.sendMessage(msg.channel, "MUAHAHAHA. My " + roll_bot + " p4wned your " + roll_usr + ". Get rekt.");
			else if (roll_usr > roll_bot)
				bot.sendMessage(msg.channel, "Lucky roll... My " + roll_bot + " can't beat your " + roll_usr + ".");
			else
				bot.sendMessage(msg.channel, "Tie? TIE!? Let's call that a win for me...");
		}
	},
	"blown": {
		usage: "",
		description: "returns gif",
		process: function(bot, msg) {
			var result;
			var rand = Math.floor(Math.random() * 6);
			var gifs = [	'https://i.imgur.com/YGsTG5o.gif',
					'https://i.imgur.com/pBTk7MC.gif',
					'https://i.imgur.com/rfFWukr.gif',
					'https://media.giphy.com/media/OK27wINdQS5YQ/giphy.gif',
					'https://i.imgur.com/l4bJmRE.gif',
					'https://i.imgur.com/3WB3L.gif',
					'https://giphy.com/gifs/cheezburger-robots-screaming-NfEQd1ge1kP04']

			bot.sendMessage(msg.channel, gifs[rand]);
		}
	},
	"weekend": {
		usage: "",
		description: "returns days until weekend",
		process: function(bot, msg) {
			var date = new Date();
			var day = date.getDay();
			var result = ["TGIF!", "1 Day left", "2 Days left", "3 Days left", "4 Days left"];
			var temp = 5 - day;

			if (day == 6){
				bot.sendMessage(msg.channel, "IT'S THE WEEKEND!");
			} else if (day == 0) {
				bot.sendMessage(msg.channel, "Last day, Enjoy it!");
			} else {
				bot.sendMessage(msg.channel, result[temp]);
			}
		}
	}
};

var bot = new Discord.Client();

bot.on("ready", function () {
	console.log("Ready to start. Channels: " + bot.channels.length);
});

bot.on('disconnected', function() {
	console.log('Disconnected.');
	process.exit(1);
});

bot.on("message", function (msg) {
	if(msg.author.id != bot.user.id && msg.content[0] === '!'){
		var cmdTxt = msg.content.split(" ")[0].substring(1);
        	var suffix = msg.content.substring(cmdTxt.length+2);
		var cmd = commands[cmdTxt];

        	if(cmdTxt === "help"){
			var info = "Available Commands: ";
			for(var cmd in commands) {
				info += "!" + cmd;
				var usage = commands[cmd].usage;
				if(usage){
					info += " " + usage + "; ";
				}
				else
					info += "; ";
			}
			bot.sendMessage(msg.author,info);
        	} else if(cmd) {
			try{
				cmd.process(bot,msg,suffix);
			} catch(e){
				if(Config.debug){
					bot.sendMessage(msg.channel, "command " + cmdTxt + " failed :(\n" + e.stack);
				}
			}
		} else {
			bot.sendMessage(msg.author, " Invalid command, Sucka!  Maybe you need some !help");
		}
	} else if (msg.author != bot.user && msg.isMentioned(bot.user)) {
		bot.sendMessage(msg.channel,msg.author + ", you called?");
    	}
});

exports.addCommand = function(commandName, commandObject){
    try {
        commands[commandName] = commandObject;
    } catch(err){
        console.log(err);
    }
}
exports.commandCount = function(){
    return Object.keys(commands).length;
}

bot.login(AuthDetails.email, AuthDetails.password);
<|endoftext|>


<commit_before>var chalk = require('chalk');
var moment = require('moment');
var keypress = require('keypress');

keypress(process.stdin);
process.stdin.setRawMode(true);
process.stdin.resume();

process.stdin.on('keypress', (ch, key) => {
    if(key && key.ctrl && key.name === 'c'){
        process.stdin.pause();
        process.exit(1);
    }

    if(game.status <= Status.READY) start(); else if(game.status === Status.STARTED) switch(ch){
        case 'e': toggleFlag(cursor); break;
        case 'q': uncoverField(cursor); break;

        case 'w': cursor.w(); break;
        case 'd': cursor.d(); break;
        case 's': cursor.s(); break;
        case 'a': cursor.a(); break;

        default: if(key) switch(key.name){
            case 'up':    cursor.w(); break;
            case 'right': cursor.d(); break;
            case 'down':  cursor.s(); break;
            case 'left':  cursor.a(); break;
            default: return;
        }
    }

    printAll();
});

const FieldType = {
    GROUND: 0,
    BLANK: 1,
    MINE: 2
};

const Border = {
    TOP: '▄', BOTTOM: '▀', CENTER: '█', LEFT: '▐', RIGHT: '▌',
    COLOR: chalk.yellow,
    SELECTION_COLOR: chalk.yellow.bold
};

var consoleWidth = () => process.stdout.columns;
var consoleHeight = () => process.stdout.rows;

var fieldWidth = Math.min(2048, consoleWidth() - 2);
var fieldHeight = Math.min(2048, consoleHeight() - 3);

var fields = Array.apply(null, Array(fieldWidth)).map((v, x) => Array.apply(null, Array(fieldHeight)).map((v, y) => ({
    x: x, y: y,
    type: FieldType.GROUND,
    flagged: false
})));

var flatFields = () => fields.reduce((a, b) => a.concat(b));

var cursor = {
    x: Math.floor(fieldWidth / 2),
    y: Math.floor(fieldHeight / 2),
    w: () => cursor.y = Math.max(0, cursor.y - 1),
    d: () => cursor.x = Math.min(fieldWidth - 1, cursor.x + 1),
    s: () => cursor.y = Math.min(fieldHeight - 1, cursor.y + 1),
    a: () => cursor.x = Math.max(0, cursor.x - 1)
};

const Status = {
    READY: 0,
    STARTED: 1,
    FAILED: 2,
    SUCCEEDED: 3
};

var game = {
    status: Status.READY,
    startedTime: null,
    finishedTime: null,

    flagCount: 0,
    mineCount: Math.floor((fieldWidth * fieldHeight) / 25),
    mineInstalled: false,
};

var vectorToField = (x, y) => {
    if(x && x.hasOwnProperty('x')){
        y = x.y; x = x.x;
    }

    return (fields[x] && fields[x][y]) || null;
};

var toggleFlag = (x, y) => {
    var field = vectorToField(x, y); if(!field) return;
    if(field.type === FieldType.BLANK) return;

    if(field.flagged = !field.flagged) game.flagCount++; else game.flagCount--;
    if(game.flagCount === game.mineCount && flatFields().filter(field => field.flagged).every(field => field.type === FieldType.MINE)) return finish(true);

    printAll();
};

var mineCount = (x, y) => {
    var field = vectorToField(x, y); if(!field) return;

    var xx, yy, count = 0;
    for(var i = -1; i <= 1; i++) for(var j = -1; j <= 1; j++) if((i !== 0 || j !== 0) && (xx = field.x + i) >= 0 && (yy = field.y + j) >= 0 && xx < fieldWidth && yy < fieldHeight && fields[xx][yy].type === FieldType.MINE) count++;
    return count;
};

var uncoverField = (x, y) => {
    var field = vectorToField(x, y); if(!field || field.flagged) return;
    if(!game.mineInstalled){
        game.mineInstalled = true;

        var exception = {}; exception[field.x + ':' + field.y] = true;
        randomVectorArray(game.mineCount, exception).forEach((vector) => fields[vector[0]][vector[1]].type = FieldType.MINE);
    }

    switch(field.type){
        case FieldType.MINE:
            finish(false);
            break;

        case FieldType.GROUND:
            field.type = FieldType.BLANK;

            uncoverGround(field.x, field.y - 1); //w
            uncoverGround(field.x + 1, field.y); //d
            uncoverGround(field.x, field.y + 1); //s
            uncoverGround(field.x - 1, field.y); //a
            break;

        default: return;
    }
};

var uncoverGround = (x, y) => {
    var queue = [vectorToField(x, y)];
    var check = {};

    while(queue.length > 0){
        var field = queue.shift();
        if(!field || field.type !== FieldType.GROUND) continue;

        var key = field.x + ':' + field.y;
        if(check[key]) continue; check[key] = true;

        if(mineCount(field) !== 0) continue;
        field.type = FieldType.BLANK;

        queue.push(vectorToField(field.x, field.y - 1)); //w
        queue.push(vectorToField(field.x + 1, field.y)); //d
        queue.push(vectorToField(field.x, field.y + 1)); //s
        queue.push(vectorToField(field.x - 1, field.y)); //a
    }
};

var buffer = '';

var write = (text) => buffer += text;
var flush = () => {
    process.stdout.write(buffer);
    buffer = '';
};

var clear = () => write('\033c');
var newLine = () => write('\n');

var repeat = (theChalk, text, count) => {
    for(var i = 0; i < count; i++) theChalk ? write(theChalk(text)) : write(text);
};

var capitalize = (str) => str && str.charAt(0).toUpperCase() + str.slice(1);

var random = (min, max) => {
    if(max === undefined){
        max = min; min = 0;
    }

    return min + Math.floor(Math.random() * (max - min));
};

var randomVectorArray = (count, exception) => {
    var check = {};
    var vectors = [];

    while(vectors.length < count){
        var vector = [random(fieldWidth), random(fieldHeight)]; var key = vector.join(':');
        if(!check[key] && !exception[key]){
            check[key] = true;
            vectors.push(vector);
        }
    }
    return vectors;
};

const Title = {
    COLOR: chalk.yellow.bold
};

var printTitle = (text, align) => {
    var spaces = consoleWidth() - text.length;

    switch(align){
        case 'left':
            write(Title.COLOR(text));
            repeat(Title.COLOR, ' ', spaces);
            break;

        default:
        case 'center':
            var leftSpaces = Math.floor(spaces / 2);
            repeat(Title.COLOR, ' ', leftSpaces);
            write(Title.COLOR(text));
            repeat(Title.COLOR, ' ', spaces - leftSpaces);
            break;

        case 'right':
            repeat(Title.COLOR, ' ', spaces);
            write(Title.COLOR(text));
            break;
    }

    newLine();
};

var blankColor = (count) => {
    if(count >= 7) return 'red';
    if(count >= 5) return 'blue';
    if(count >= 3) return 'yellow';
    else return 'black';
};

var getFieldString = (x, y) => {
    var field = fields[x][y];
    var output = {
        background: 'white', foreground: 'black', text: ' ', special: null
    };

    if(field.flagged){
        output.text = 'X';
        output.background = 'cyan';
    }

    else switch(field.type){
        case FieldType.GROUND:
        case FieldType.MINE:
            output.text = '?';
            output.background = 'black';
            break;

        case FieldType.BLANK:
            var count = mineCount(x, y);
            output.foreground = blankColor(count);
            if(count > 0) output.text = Math.min(count, 9).toString(10);
            break;
    }

    if(cursor.x === x && cursor.y === y) output.background = 'green';

    if(game.status > Status.STARTED && field.type === FieldType.MINE){
        output.text = '!';
        output.foreground = 'white';
        output.special = 'bold';

        if(!field.flagged) output.background = 'red';
    }

    var theChalk = chalk['bg' + capitalize(output.background)][output.foreground];
    if(output.special) theChalk = theChalk[output.special];

    return theChalk(output.text);
};

var getElapsedTime = (now) => moment.utc((now || moment()).diff(game.startedTime)).format("HH:mm:ss");

var printAll = (title) => {
    clear();
    var marginTop = Math.round((consoleHeight() - fieldHeight - 3) / 2);
    var marginLeft = Math.round((consoleWidth() - fieldWidth - 2) / 2);

    repeat(null, '\n', marginTop);

    switch(game.status){
        case Status.READY:
            printTitle("Press any key to start...");
            break;

        case Status.STARTED:
            var title = getElapsedTime() + ' | ' + game.flagCount + '/' + game.mineCount;
            var cursorText = ' | (' + cursor.x + ', ' + cursor.y + ')';
            printTitle((title.length + cursorText.length) < consoleWidth() ? title + cursorText : title);
            break;

        case Status.FAILED:
            printTitle(getElapsedTime(game.finishedTime) + " | Failed");
            break;

        case Status.SUCCEEDED:
            printTitle(getElapsedTime(game.finishedTime) + " | Succeeded");
            break;
    }

    repeat(null, ' ', marginLeft);
    repeat(Border.COLOR, Border.TOP, cursor.x + 1);
    write(Border.SELECTION_COLOR(Border.TOP));
    repeat(Border.COLOR, Border.TOP, fieldWidth - cursor.x);
    newLine();

    for(var y = 0; y < fieldHeight; y++){
        var border = (y === cursor.y ? Border.SELECTION_COLOR : Border.COLOR)(Border.CENTER);
        repeat(null, ' ', marginLeft); write(border); for(var x = 0; x < fieldWidth; x++) write(getFieldString(x, y)); write(border); newLine();
    }

    repeat(null, ' ', marginLeft); repeat(Border.COLOR, Border.BOTTOM, cursor.x + 1);
    write(Border.SELECTION_COLOR(Border.BOTTOM));
    repeat(Border.COLOR, Border.BOTTOM, fieldWidth - cursor.x);

    flush();
};

var printer = null;

var start = () => {
    if(game.status > Status.READY) return;

    game.status = Status.STARTED;
    game.startedTime = moment();

    printAll();
};

var finish = (succeeded) => {
    if(game.status > Status.STARTED) return;

    game.status = succeeded ? Status.SUCCEEDED : Status.FAILED;
    game.finishedTime = moment();

    printAll();
    setTimeout(() => process.exit(0), 3000);
};

game.status = Status.READY; printAll();
printer = setInterval(printAll, 200);
<commit_msg>Added level option<commit_after>var chalk = require('chalk');
var moment = require('moment');
var keypress = require('keypress');

keypress(process.stdin);
process.stdin.setRawMode(true);
process.stdin.resume();

process.stdin.on('keypress', (ch, key) => {
    if(key && key.ctrl && key.name === 'c'){
        process.stdin.pause();
        process.exit(1);
    }

    if(game.status <= Status.READY) start(); else if(game.status === Status.STARTED) switch(ch){
        case 'e': toggleFlag(cursor); break;
        case 'q': uncoverField(cursor); break;

        case 'w': cursor.w(); break;
        case 'd': cursor.d(); break;
        case 's': cursor.s(); break;
        case 'a': cursor.a(); break;

        default: if(key) switch(key.name){
            case 'up':    cursor.w(); break;
            case 'right': cursor.d(); break;
            case 'down':  cursor.s(); break;
            case 'left':  cursor.a(); break;
            default: return;
        }
    }

    printAll();
});

const FieldType = {
    GROUND: 0,
    BLANK: 1,
    MINE: 2
};

const Border = {
    TOP: '▄', BOTTOM: '▀', CENTER: '█', LEFT: '▐', RIGHT: '▌',
    COLOR: chalk.yellow,
    SELECTION_COLOR: chalk.yellow.bold
};

var consoleWidth = () => process.stdout.columns;
var consoleHeight = () => process.stdout.rows;

var fieldWidth = Math.min(2048, consoleWidth() - 2);
var fieldHeight = Math.min(2048, consoleHeight() - 3);

var fields = Array.apply(null, Array(fieldWidth)).map((v, x) => Array.apply(null, Array(fieldHeight)).map((v, y) => ({
    x: x, y: y,
    type: FieldType.GROUND,
    flagged: false
})));

var flatFields = () => fields.reduce((a, b) => a.concat(b));

var cursor = {
    x: Math.floor(fieldWidth / 2),
    y: Math.floor(fieldHeight / 2),
    w: () => cursor.y = Math.max(0, cursor.y - 1),
    d: () => cursor.x = Math.min(fieldWidth - 1, cursor.x + 1),
    s: () => cursor.y = Math.min(fieldHeight - 1, cursor.y + 1),
    a: () => cursor.x = Math.max(0, cursor.x - 1)
};

const Status = {
    READY: 0,
    STARTED: 1,
    FAILED: 2,
    SUCCEEDED: 3
};

var game = {
    status: Status.READY,
    startedTime: null,
    finishedTime: null,

    flagCount: 0,
    mineCount: Math.floor((fieldWidth * fieldHeight) / 100 * Math.min(95, parseFloat(process.argv[2]) || 15)),
    mineInstalled: false,
};

var vectorToField = (x, y) => {
    if(x && x.hasOwnProperty('x')){
        y = x.y; x = x.x;
    }

    return (fields[x] && fields[x][y]) || null;
};

var toggleFlag = (x, y) => {
    var field = vectorToField(x, y); if(!field) return;
    if(field.type === FieldType.BLANK) return;

    if(field.flagged = !field.flagged) game.flagCount++; else game.flagCount--;
    if(game.flagCount === game.mineCount && flatFields().filter(field => field.flagged).every(field => field.type === FieldType.MINE)) return finish(true);

    printAll();
};

var mineCount = (x, y) => {
    var field = vectorToField(x, y); if(!field) return;

    var xx, yy, count = 0;
    for(var i = -1; i <= 1; i++) for(var j = -1; j <= 1; j++) if((i !== 0 || j !== 0) && (xx = field.x + i) >= 0 && (yy = field.y + j) >= 0 && xx < fieldWidth && yy < fieldHeight && fields[xx][yy].type === FieldType.MINE) count++;
    return count;
};

var uncoverField = (x, y) => {
    var field = vectorToField(x, y); if(!field || field.flagged) return;
    if(!game.mineInstalled){
        game.mineInstalled = true;

        var exception = {}; exception[field.x + ':' + field.y] = true;
        randomVectorArray(game.mineCount, exception).forEach((vector) => fields[vector[0]][vector[1]].type = FieldType.MINE);
    }

    switch(field.type){
        case FieldType.MINE:
            finish(false);
            break;

        case FieldType.GROUND:
            field.type = FieldType.BLANK;

            uncoverGround(field.x, field.y - 1); //w
            uncoverGround(field.x + 1, field.y); //d
            uncoverGround(field.x, field.y + 1); //s
            uncoverGround(field.x - 1, field.y); //a
            break;

        default: return;
    }
};

var uncoverGround = (x, y) => {
    var queue = [vectorToField(x, y)];
    var check = {};

    while(queue.length > 0){
        var field = queue.shift();
        if(!field || field.type !== FieldType.GROUND) continue;

        var key = field.x + ':' + field.y;
        if(check[key]) continue; check[key] = true;

        if(mineCount(field) !== 0) continue;
        field.type = FieldType.BLANK;

        queue.push(vectorToField(field.x, field.y - 1)); //w
        queue.push(vectorToField(field.x + 1, field.y)); //d
        queue.push(vectorToField(field.x, field.y + 1)); //s
        queue.push(vectorToField(field.x - 1, field.y)); //a
    }
};

var buffer = '';

var write = (text) => buffer += text;
var flush = () => {
    process.stdout.write(buffer);
    buffer = '';
};

var clear = () => write('\033c');
var newLine = () => write('\n');

var repeat = (theChalk, text, count) => {
    for(var i = 0; i < count; i++) theChalk ? write(theChalk(text)) : write(text);
};

var capitalize = (str) => str && str.charAt(0).toUpperCase() + str.slice(1);

var random = (min, max) => {
    if(max === undefined){
        max = min; min = 0;
    }

    return min + Math.floor(Math.random() * (max - min));
};

var randomVectorArray = (count, exception) => {
    var check = {};
    var vectors = [];

    while(vectors.length < count){
        var vector = [random(fieldWidth), random(fieldHeight)]; var key = vector.join(':');
        if(!check[key] && !exception[key]){
            check[key] = true;
            vectors.push(vector);
        }
    }
    return vectors;
};

const Title = {
    COLOR: chalk.yellow.bold
};

var printTitle = (text, align) => {
    var spaces = consoleWidth() - text.length;

    switch(align){
        case 'left':
            write(Title.COLOR(text));
            repeat(Title.COLOR, ' ', spaces);
            break;

        default:
        case 'center':
            var leftSpaces = Math.floor(spaces / 2);
            repeat(Title.COLOR, ' ', leftSpaces);
            write(Title.COLOR(text));
            repeat(Title.COLOR, ' ', spaces - leftSpaces);
            break;

        case 'right':
            repeat(Title.COLOR, ' ', spaces);
            write(Title.COLOR(text));
            break;
    }

    newLine();
};

var blankColor = (count) => {
    if(count >= 7) return 'red';
    if(count >= 5) return 'blue';
    if(count >= 3) return 'yellow';
    else return 'black';
};

var getFieldString = (x, y) => {
    var field = fields[x][y];
    var output = {
        background: 'white', foreground: 'black', text: ' ', special: null
    };

    if(field.flagged){
        output.text = 'X';
        output.background = 'cyan';
    }

    else switch(field.type){
        case FieldType.GROUND:
        case FieldType.MINE:
            output.text = '?';
            output.background = 'black';
            break;

        case FieldType.BLANK:
            var count = mineCount(x, y);
            output.foreground = blankColor(count);
            if(count > 0) output.text = Math.min(count, 9).toString(10);
            break;
    }

    if(cursor.x === x && cursor.y === y) output.background = 'green';

    if(game.status > Status.STARTED && field.type === FieldType.MINE){
        output.text = '!';
        output.foreground = 'white';
        output.special = 'bold';

        if(!field.flagged) output.background = 'red';
    }

    var theChalk = chalk['bg' + capitalize(output.background)][output.foreground];
    if(output.special) theChalk = theChalk[output.special];

    return theChalk(output.text);
};

var getElapsedTime = (now) => moment.utc((now || moment()).diff(game.startedTime)).format("HH:mm:ss");

var printAll = (title) => {
    clear();
    var marginTop = Math.round((consoleHeight() - fieldHeight - 3) / 2);
    var marginLeft = Math.round((consoleWidth() - fieldWidth - 2) / 2);

    repeat(null, '\n', marginTop);

    switch(game.status){
        case Status.READY:
            printTitle("Press any key to start...");
            break;

        case Status.STARTED:
            var title = getElapsedTime() + ' | ' + game.flagCount + '/' + game.mineCount;
            var cursorText = ' | (' + cursor.x + ', ' + cursor.y + ')';
            printTitle((title.length + cursorText.length) < consoleWidth() ? title + cursorText : title);
            break;

        case Status.FAILED:
            printTitle(getElapsedTime(game.finishedTime) + " | Failed");
            break;

        case Status.SUCCEEDED:
            printTitle(getElapsedTime(game.finishedTime) + " | Succeeded");
            break;
    }

    repeat(null, ' ', marginLeft);
    repeat(Border.COLOR, Border.TOP, cursor.x + 1);
    write(Border.SELECTION_COLOR(Border.TOP));
    repeat(Border.COLOR, Border.TOP, fieldWidth - cursor.x);
    newLine();

    for(var y = 0; y < fieldHeight; y++){
        var border = (y === cursor.y ? Border.SELECTION_COLOR : Border.COLOR)(Border.CENTER);
        repeat(null, ' ', marginLeft); write(border); for(var x = 0; x < fieldWidth; x++) write(getFieldString(x, y)); write(border); newLine();
    }

    repeat(null, ' ', marginLeft); repeat(Border.COLOR, Border.BOTTOM, cursor.x + 1);
    write(Border.SELECTION_COLOR(Border.BOTTOM));
    repeat(Border.COLOR, Border.BOTTOM, fieldWidth - cursor.x);

    flush();
};

var printer = null;

var start = () => {
    if(game.status > Status.READY) return;

    game.status = Status.STARTED;
    game.startedTime = moment();

    printAll();
};

var finish = (succeeded) => {
    if(game.status > Status.STARTED) return;

    game.status = succeeded ? Status.SUCCEEDED : Status.FAILED;
    game.finishedTime = moment();

    printAll();
    setTimeout(() => process.exit(0), 3000);
};

game.status = Status.READY; printAll();
printer = setInterval(printAll, 200);
<|endoftext|>


<commit_before>'use strict'

module.exports = tempest
tempest.compile = compile
tempest.render = render

function tempest (s) {
  for (var i = 0, p = [], e = [], f, l, o = '{{', c = '}}';;) {
    f = s.indexOf(o)
    if (f < 0) break
    p[i] = s.slice(0, f)
    l = s.indexOf(c, f)
    e[i++] = s.slice(f + 2, l)
    s = s.slice(l + 2)
  }
  p[i] = s
  return [p, e]
}

function compile (t, d) {
  for (var i = 0, s = '', p = t[0], e = t[1], l = e.length; i < l; s += p[i] + (d[e[i++]] || ''));
  return s + p[i]
}

function render (s, d) {
  return compile(tempest(s), d)
}
<commit_msg>Don't slice to iterate<commit_after>'use strict'

module.exports = tempest
tempest.compile = compile
tempest.render = render

function tempest (s) {
  for (var i = 0, t = 0, p = [], e = [], f, l, o = '{{', c = '}}';;) {
    f = s.indexOf(o, t)
    if (f < 0) break
    p[i] = s.slice(t, f)
    l = s.indexOf(c, f)
    e[i++] = s.slice(f + 2, l)
    t = l + 2
  }
  p[i] = s.slice(t)
  return [p, e]
}

function compile (t, d) {
  for (var i = 0, s = '', p = t[0], e = t[1], l = e.length; i < l; s += p[i] + (d[e[i++]] || ''));
  return s + p[i]
}

function render (s, d) {
  return compile(tempest(s), d)
}
<|endoftext|>


<commit_before>/**
 * Dependencies
 */
const url = require('url')
const HttpProxy = require('http-proxy')
const pathMatch = require('path-match')

/**
 * Constants
 */

const proxy = HttpProxy.createProxyServer()
const route = pathMatch({
  // path-to-regexp options
  sensitive: false,
  strict: false,
  end: false
})

let eventRegistered = false

/**
 * Koa Http Proxy Middleware
 */
module.exports = (context, options) => (ctx, next) => {
  // create a match function
  const match = route(context)
  if (!match(ctx.path)) return next()

  let opts = Object.assign({}, options)
  if (typeof options === 'function') {
    const params = match(ctx.path)
    opts = options.call(options, params)
  }
  // object-rest-spread is still in stage-3
  // https://github.com/tc39/proposal-object-rest-spread
  const { logs, rewrite, events } = opts

  const httpProxyOpts = Object.keys(opts)
    .filter(n => ['logs', 'rewrite', 'events'].indexOf(n) < 0)
    .reduce((prev, cur) => {
      prev[cur] = opts[cur]
      return prev
    }, {})

  return new Promise((resolve, reject) => {
    ctx.req.oldPath = ctx.req.url

    if (typeof rewrite === 'function') {
      ctx.req.url = rewrite(ctx.req.url)
    }

    if (logs) logger(ctx, opts.target)

    if (events && typeof events === 'object' && !eventRegistered) {
      Object.entries(events).forEach(([event, handler]) => {
        proxy.on(event, handler)
      })
      eventRegistered = true
    }

    proxy.web(ctx.req, ctx.res, httpProxyOpts, e => {
      const status = {
        ECONNREFUSED: 503,
        ETIMEOUT: 504
      }[e.code]
      if (status) ctx.status = status
      resolve()
    })
  })
}

module.exports.proxy = proxy

function logger (ctx, target) {
  console.log('%s - %s %s proxy to -> %s', new Date().toISOString(), ctx.req.method, ctx.req.oldPath, url.resolve(target, ctx.req.url))
}
<commit_msg>Let the promise be solved correctly<commit_after>/**
 * Dependencies
 */
const url = require('url')
const HttpProxy = require('http-proxy')
const pathMatch = require('path-match')

/**
 * Constants
 */

const proxy = HttpProxy.createProxyServer()
const route = pathMatch({
  // path-to-regexp options
  sensitive: false,
  strict: false,
  end: false
})

let eventRegistered = false

/**
 * Koa Http Proxy Middleware
 */
module.exports = (context, options) => (ctx, next) => {
  // create a match function
  const match = route(context)
  if (!match(ctx.path)) return next()

  let opts = Object.assign({}, options)
  if (typeof options === 'function') {
    const params = match(ctx.path)
    opts = options.call(options, params)
  }
  // object-rest-spread is still in stage-3
  // https://github.com/tc39/proposal-object-rest-spread
  const { logs, rewrite, events } = opts

  const httpProxyOpts = Object.keys(opts)
    .filter(n => ['logs', 'rewrite', 'events'].indexOf(n) < 0)
    .reduce((prev, cur) => {
      prev[cur] = opts[cur]
      return prev
    }, {})

  return new Promise((resolve, reject) => {
    ctx.req.oldPath = ctx.req.url

    if (typeof rewrite === 'function') {
      ctx.req.url = rewrite(ctx.req.url)
    }

    if (logs) logger(ctx, opts.target)

    if (events && typeof events === 'object' && !eventRegistered) {
      Object.entries(events).forEach(([event, handler]) => {
        proxy.on(event, handler)
      })
      eventRegistered = true
    }
    // Let the promise be solved correctly after the proxy.web.
    // The solution comes from https://github.com/nodejitsu/node-http-proxy/issues/951#issuecomment-179904134
    ctx.res.on('close', () => {
      reject(new Error(`Http response closed while proxying ${ctx.req.oldPath}`));
    });
    ctx.res.on('finish', () => resolve());

    proxy.web(ctx.req, ctx.res, httpProxyOpts, e => {
      const status = {
        ECONNREFUSED: 503,
        ETIMEOUT: 504
      }[e.code]
      if (status) ctx.status = status
      resolve()
    })
  })
}

module.exports.proxy = proxy

function logger (ctx, target) {
  console.log('%s - %s %s proxy to -> %s', new Date().toISOString(), ctx.req.method, ctx.req.oldPath, url.resolve(target, ctx.req.url))
}
<|endoftext|>


<commit_before>/* jshint node: true */
'use strict';

var EventEmitter = require('events').EventEmitter;
var rtc = require('rtc');
var debug = rtc.logger('rtc-quickconnect');
var signaller = require('rtc-signaller');
var defaults = require('cog/defaults');
var extend = require('cog/extend');
var reTrailingSlash = /\/$/;
var CHANNEL_HEARTBEAT = '__heartbeat';

/**
  # rtc-quickconnect

  This is a high level helper module designed to help you get up
  an running with WebRTC really, really quickly.  By using this module you
  are trading off some flexibility, so if you need a more flexible
  configuration you should drill down into lower level components of the
  [rtc.io](http://www.rtc.io) suite.  In particular you should check out
  [rtc](https://github.com/rtc-io/rtc).

  ## Example Usage

  In the simplest case you simply call quickconnect with a single string
  argument which tells quickconnect which server to use for signaling:

  <<< examples/simple.js

  ## Example Usage (using data channels)

  When working with WebRTC data channels, you can call the `createDataChannel`
  function helper that is attached to the object returned from the
  `quickconnect` call.  The `createDataChannel` function signature matches
  the signature of the `RTCPeerConnection` `createDataChannel` function.

  At the minimum it requires a label for the channel, but you can also pass
  through a dictionary of options that can be used to fine tune the
  data channel behaviour.  For more information on these options, I'd
  recommend having a quick look at the WebRTC spec:

  http://dev.w3.org/2011/webrtc/editor/webrtc.html#dictionary-rtcdatachannelinit-members

  If in doubt, I'd recommend not passing through options.

  <<< examples/datachannel.js

  __NOTE:__ Data channel interoperability has been tested between Chrome 32
  and Firefox 26, which both make use of SCTP data channels.

  __NOTE:__ The current stable version of Chrome is 31, so interoperability
  with Firefox right now will be hard to achieve.

  ## Example Usage (using captured media)

  Another example is displayed below, and this example demonstrates how
  to use `rtc-quickconnect` to create a simple video conferencing application:

  <<< examples/conference.js

  ## Regarding Signalling and a Signalling Server

  Signaling is an important part of setting up a WebRTC connection and for
  our examples we use our own test instance of the
  [rtc-switchboard](https://github.com/rtc-io/rtc-switchboard). For your
  testing and development you are more than welcome to use this also, but
  just be aware that we use this for our testing so it may go up and down
  a little.  If you need something more stable, why not consider deploying
  an instance of the switchboard yourself - it's pretty easy :)

  ## Reference

  ```
  quickconnect(signalhost, opts?) => rtc-sigaller instance (+ helpers)
  ```

  ### Valid Quick Connect Options

  The options provided to the `rtc-quickconnect` module function influence the
  behaviour of some of the underlying components used from the rtc.io suite.

  Listed below are some of the commonly used options:

  - `ns` (default: '')

    An optional namespace for your signalling room.  While quickconnect
    will generate a unique hash for the room, this can be made to be more
    unique by providing a namespace.  Using a namespace means two demos
    that have generated the same hash but use a different namespace will be
    in different rooms.

  - `room` (default: null) _added 0.6_

    Rather than use the internal hash generation
    (plus optional namespace) for room name generation, simply use this room
    name instead.  __NOTE:__ Use of the `room` option takes precendence over
    `ns`.

  - `debug` (default: false)

  Write rtc.io suite debug output to the browser console.

  #### Options for Peer Connection Creation

  Options that are passed onto the
  [rtc.createConnection](https://github.com/rtc-io/rtc#createconnectionopts-constraints)
  function:

  - `constraints`

    Used to provide specific constraints when creating a new
    peer connection.

  #### Options for P2P negotiation

  Under the hood, quickconnect uses the
  [rtc/couple](https://github.com/rtc-io/rtc#rtccouple) logic, and the options
  passed to quickconnect are also passed onto this function.

**/
module.exports = function(signalhost, opts) {
  var hash = location.hash.slice(1);
  var signaller = require('rtc-signaller')(signalhost);

  // init configurable vars
  var ns = (opts || {}).ns || '';
  var room = (opts || {}).room;
  var debugging = (opts || {}).debug;
  var disableHeartbeat = (opts || {}).disableHeartbeat;
  var heartbeatInterval = (opts || {}).heartbeatInterval || 1000;
  var profile = {};

  // collect the local streams
  var localStreams = [];

  // create the peers registry
  var peers = {};

  // create the known data channels registry
  var channels = {};

  function gotPeerChannel(channel, pc, data) {
    // create the channelOpen function
    var emitChannelOpen = signaller.emit.bind(
      signaller,
      channel.label + ':open',
      channel,
      data.id,
      data,
      pc
    );

    debug('channel ' + channel.label + ' discovered for peer: ' + data.id, channel);
    if (channel.readyState === 'open') {
      return emitChannelOpen();
    }

    channel.onopen = emitChannelOpen;
  }

  function initHeartbeat(channel, pc, data) {
    var hbTimeoutTimer;
    var hbTimer;

    function timeoutConnection() {
      console.log('connection with ' + data.id + ' timed out');

      // trigger a peer disconnect event
      signaller.emit('peer:disconnect', data.id);

      // trigger close events for each of the channels
      Object.keys(channels).forEach(function(channel) {
        signaller.emit(channel + ':close');
      });

      // clear the peer reference
      peers[data.id] = undefined;

      // stop trying to send heartbeat messages
      clearInterval(hbTimer);
    }

    debug('created heartbeat channel for peer: ' + data.id);

    // start monitoring using the heartbeat channel to keep tabs on our
    // peers availability
    channel.onmessage = function(evt) {
      // console.log('received hearbeat message: ' + evt.data)
      if (evt.data === '!HB') {
        clearTimeout(hbTimeoutTimer);
        hbTimeoutTimer = setTimeout(timeoutConnection, heartbeatInterval * 2);
      }
    };

    hbTimer  = setInterval(function() {
      // if the channel is no longer open, then abort
      if (channel.readyState !== 'open') {
        return clearInterval(hbTimer);
      }

      channel.send('!HB');
    }, heartbeatInterval);
  }

  // if the room is not defined, then generate the room name
  if (! room) {
    // if the hash is not assigned, then create a random hash value
    if (! hash) {
      hash = location.hash = '' + (Math.pow(2, 53) * Math.random());
    }

    room = ns + '#' + hash;
  }

  if (debugging) {
    rtc.logger.enable.apply(rtc.logger, Array.isArray(debug) ? debugging : ['*']);
  }

  signaller.on('peer:announce', function(data) {
    var pc;
    var monitor;

    // if the room is not a match, abort
    if (data.room !== room) {
      return;
    }

    // create a peer connection
    pc = peers[data.id] = rtc.createConnection(opts, (opts || {}).constraints);

    // add the local streams
    localStreams.forEach(function(stream) {
      pc.addStream(stream);
    });

    // add the data channels
    // do this differently based on whether the connection is a
    // master or a slave connection
    if (signaller.isMaster(data.id)) {
      debug('is master, creating data channels: ', Object.keys(channels));

      // unless the heartbeat is disabled then create a heartbeat datachannel
      if (! disableHeartbeat) {
        initHeartbeat(pc.createDataChannel(CHANNEL_HEARTBEAT), pc, data);
      }

      // create the channels
      Object.keys(channels).forEach(function(label) {
        gotPeerChannel(pc.createDataChannel(label, channels[label]), pc, data);
      });
    }
    else {
      pc.ondatachannel = function(evt) {
        var channel = evt && evt.channel;

        // if we have no channel, abort
        if (! channel) {
          return;
        }

        // if the channel is the heartbeat, then init the heartbeat
        if (channel.label === CHANNEL_HEARTBEAT) {
          initHeartbeat(channel, pc, data);
        }
        // otherwise, if this is a known channel, initialise it
        else if (channels[channel.label] !== undefined) {
          gotPeerChannel(channel, pc, data);
        }
      };
    }

    // couple the connections
    monitor = rtc.couple(pc, data.id, signaller, opts);

    // emit the peer event as per <= rtc-quickconnect@0.7
    signaller.emit('peer', pc, data.id, data, monitor);

    // once active, trigger the peer connect event
    monitor.once('active', function() {
      signaller.emit('peer:connect', pc, data.id, data);
    });

    // if we are the master connnection, create the offer
    // NOTE: this only really for the sake of politeness, as rtc couple
    // implementation handles the slave attempting to create an offer
    if (signaller.isMaster(data.id)) {
      monitor.createOffer();
    }
  });

  // announce ourselves to our new friend
  setTimeout(function() {
    var data = extend({}, profile, { room: room });

    // announce and emit the local announce event
    signaller.announce(data);
    signaller.emit('local:announce', data);
  }, 0);

  /**
    ### Quickconnect Broadcast and Data Channel Helper Functions

    The following are functions that are patched into the `rtc-signaller`
    instance that make working with and creating functional WebRTC applications
    a lot simpler.

  **/

  /**
    #### broadcast(stream)

    Add the stream to the set of local streams that we will broadcast
    to other peers.

  **/
  signaller.broadcast = function(stream) {
    localStreams.push(stream);
    return signaller;
  };

  /**
    #### close()

    The `close` function provides a convenient way of closing all associated
    peer connections.
  **/
  signaller.close = function() {
    Object.keys(peers).forEach(function(id) {
      if (peers[id]) {
        peers[id].close();
      }
    });

    // reset the peer references
    peers = {};
  };

  /**
    #### createDataChannel(label, config)

    Request that a data channel with the specified `label` is created on
    the peer connection.  When the data channel is open and available, an
    event will be triggered using the label of the data channel.

    For example, if a new data channel was requested using the following
    call:

    ```js
    var qc = quickconnect('http://rtc.io/switchboard').createDataChannel('test');
    ```

    Then when the data channel is ready for use, a `test:open` event would
    be emitted by `qc`.

  **/
  signaller.createDataChannel = function(label, opts) {
    // save the data channel opts in the local channels dictionary
    channels[label] = opts || null;
    return signaller;
  };

  /**
    #### profile(data)

    Update the profile data with the attached information, so when
    the signaller announces it includes this data in addition to any
    room and id information.

  **/
  signaller.profile = function(data) {
    extend(profile, data);
    return signaller;
  };

  // pass the signaller on
  return signaller;
};<commit_msg>Ensure to start the heartbeat disconnection timer when heartbeat channel is detected<commit_after>/* jshint node: true */
'use strict';

var EventEmitter = require('events').EventEmitter;
var rtc = require('rtc');
var debug = rtc.logger('rtc-quickconnect');
var signaller = require('rtc-signaller');
var defaults = require('cog/defaults');
var extend = require('cog/extend');
var reTrailingSlash = /\/$/;
var CHANNEL_HEARTBEAT = '__heartbeat';

/**
  # rtc-quickconnect

  This is a high level helper module designed to help you get up
  an running with WebRTC really, really quickly.  By using this module you
  are trading off some flexibility, so if you need a more flexible
  configuration you should drill down into lower level components of the
  [rtc.io](http://www.rtc.io) suite.  In particular you should check out
  [rtc](https://github.com/rtc-io/rtc).

  ## Example Usage

  In the simplest case you simply call quickconnect with a single string
  argument which tells quickconnect which server to use for signaling:

  <<< examples/simple.js

  ## Example Usage (using data channels)

  When working with WebRTC data channels, you can call the `createDataChannel`
  function helper that is attached to the object returned from the
  `quickconnect` call.  The `createDataChannel` function signature matches
  the signature of the `RTCPeerConnection` `createDataChannel` function.

  At the minimum it requires a label for the channel, but you can also pass
  through a dictionary of options that can be used to fine tune the
  data channel behaviour.  For more information on these options, I'd
  recommend having a quick look at the WebRTC spec:

  http://dev.w3.org/2011/webrtc/editor/webrtc.html#dictionary-rtcdatachannelinit-members

  If in doubt, I'd recommend not passing through options.

  <<< examples/datachannel.js

  __NOTE:__ Data channel interoperability has been tested between Chrome 32
  and Firefox 26, which both make use of SCTP data channels.

  __NOTE:__ The current stable version of Chrome is 31, so interoperability
  with Firefox right now will be hard to achieve.

  ## Example Usage (using captured media)

  Another example is displayed below, and this example demonstrates how
  to use `rtc-quickconnect` to create a simple video conferencing application:

  <<< examples/conference.js

  ## Regarding Signalling and a Signalling Server

  Signaling is an important part of setting up a WebRTC connection and for
  our examples we use our own test instance of the
  [rtc-switchboard](https://github.com/rtc-io/rtc-switchboard). For your
  testing and development you are more than welcome to use this also, but
  just be aware that we use this for our testing so it may go up and down
  a little.  If you need something more stable, why not consider deploying
  an instance of the switchboard yourself - it's pretty easy :)

  ## Reference

  ```
  quickconnect(signalhost, opts?) => rtc-sigaller instance (+ helpers)
  ```

  ### Valid Quick Connect Options

  The options provided to the `rtc-quickconnect` module function influence the
  behaviour of some of the underlying components used from the rtc.io suite.

  Listed below are some of the commonly used options:

  - `ns` (default: '')

    An optional namespace for your signalling room.  While quickconnect
    will generate a unique hash for the room, this can be made to be more
    unique by providing a namespace.  Using a namespace means two demos
    that have generated the same hash but use a different namespace will be
    in different rooms.

  - `room` (default: null) _added 0.6_

    Rather than use the internal hash generation
    (plus optional namespace) for room name generation, simply use this room
    name instead.  __NOTE:__ Use of the `room` option takes precendence over
    `ns`.

  - `debug` (default: false)

  Write rtc.io suite debug output to the browser console.

  #### Options for Peer Connection Creation

  Options that are passed onto the
  [rtc.createConnection](https://github.com/rtc-io/rtc#createconnectionopts-constraints)
  function:

  - `constraints`

    Used to provide specific constraints when creating a new
    peer connection.

  #### Options for P2P negotiation

  Under the hood, quickconnect uses the
  [rtc/couple](https://github.com/rtc-io/rtc#rtccouple) logic, and the options
  passed to quickconnect are also passed onto this function.

**/
module.exports = function(signalhost, opts) {
  var hash = location.hash.slice(1);
  var signaller = require('rtc-signaller')(signalhost);

  // init configurable vars
  var ns = (opts || {}).ns || '';
  var room = (opts || {}).room;
  var debugging = (opts || {}).debug;
  var disableHeartbeat = (opts || {}).disableHeartbeat;
  var heartbeatInterval = (opts || {}).heartbeatInterval || 1000;
  var profile = {};

  // collect the local streams
  var localStreams = [];

  // create the peers registry
  var peers = {};

  // create the known data channels registry
  var channels = {};

  function gotPeerChannel(channel, pc, data) {
    // create the channelOpen function
    var emitChannelOpen = signaller.emit.bind(
      signaller,
      channel.label + ':open',
      channel,
      data.id,
      data,
      pc
    );

    debug('channel ' + channel.label + ' discovered for peer: ' + data.id, channel);
    if (channel.readyState === 'open') {
      return emitChannelOpen();
    }

    channel.onopen = emitChannelOpen;
  }

  function initHeartbeat(channel, pc, data) {
    var hbTimeoutTimer;
    var hbTimer;

    function timeoutConnection() {
      console.log('connection with ' + data.id + ' timed out');

      // trigger a peer disconnect event
      signaller.emit('peer:disconnect', data.id);

      // trigger close events for each of the channels
      Object.keys(channels).forEach(function(channel) {
        signaller.emit(channel + ':close');
      });

      // clear the peer reference
      peers[data.id] = undefined;

      // stop trying to send heartbeat messages
      clearInterval(hbTimer);
    }

    debug('created heartbeat channel for peer: ' + data.id);

    // start monitoring using the heartbeat channel to keep tabs on our
    // peers availability
    channel.onmessage = function(evt) {
      // console.log('received hearbeat message: ' + evt.data)
      if (evt.data === '!HB') {
        clearTimeout(hbTimeoutTimer);
        hbTimeoutTimer = setTimeout(timeoutConnection, heartbeatInterval * 2);
      }
    };

    hbTimer  = setInterval(function() {
      // if the channel is no longer open, then abort
      if (channel.readyState !== 'open') {
        return clearInterval(hbTimer);
      }

      channel.send('!HB');
    }, heartbeatInterval);

    // start the heartbeat timer
    hbTimeoutTimer = setTimeout(timeoutConnection, heartbeatInterval * 2);
  }

  // if the room is not defined, then generate the room name
  if (! room) {
    // if the hash is not assigned, then create a random hash value
    if (! hash) {
      hash = location.hash = '' + (Math.pow(2, 53) * Math.random());
    }

    room = ns + '#' + hash;
  }

  if (debugging) {
    rtc.logger.enable.apply(rtc.logger, Array.isArray(debug) ? debugging : ['*']);
  }

  signaller.on('peer:announce', function(data) {
    var pc;
    var monitor;

    // if the room is not a match, abort
    if (data.room !== room) {
      return;
    }

    // create a peer connection
    pc = peers[data.id] = rtc.createConnection(opts, (opts || {}).constraints);

    // add the local streams
    localStreams.forEach(function(stream) {
      pc.addStream(stream);
    });

    // add the data channels
    // do this differently based on whether the connection is a
    // master or a slave connection
    if (signaller.isMaster(data.id)) {
      debug('is master, creating data channels: ', Object.keys(channels));

      // unless the heartbeat is disabled then create a heartbeat datachannel
      if (! disableHeartbeat) {
        initHeartbeat(pc.createDataChannel(CHANNEL_HEARTBEAT), pc, data);
      }

      // create the channels
      Object.keys(channels).forEach(function(label) {
        gotPeerChannel(pc.createDataChannel(label, channels[label]), pc, data);
      });
    }
    else {
      pc.ondatachannel = function(evt) {
        var channel = evt && evt.channel;

        // if we have no channel, abort
        if (! channel) {
          return;
        }

        // if the channel is the heartbeat, then init the heartbeat
        if (channel.label === CHANNEL_HEARTBEAT) {
          initHeartbeat(channel, pc, data);
        }
        // otherwise, if this is a known channel, initialise it
        else if (channels[channel.label] !== undefined) {
          gotPeerChannel(channel, pc, data);
        }
      };
    }

    // couple the connections
    monitor = rtc.couple(pc, data.id, signaller, opts);

    // emit the peer event as per <= rtc-quickconnect@0.7
    signaller.emit('peer', pc, data.id, data, monitor);

    // once active, trigger the peer connect event
    monitor.once('active', function() {
      signaller.emit('peer:connect', pc, data.id, data);
    });

    // if we are the master connnection, create the offer
    // NOTE: this only really for the sake of politeness, as rtc couple
    // implementation handles the slave attempting to create an offer
    if (signaller.isMaster(data.id)) {
      monitor.createOffer();
    }
  });

  // announce ourselves to our new friend
  setTimeout(function() {
    var data = extend({}, profile, { room: room });

    // announce and emit the local announce event
    signaller.announce(data);
    signaller.emit('local:announce', data);
  }, 0);

  /**
    ### Quickconnect Broadcast and Data Channel Helper Functions

    The following are functions that are patched into the `rtc-signaller`
    instance that make working with and creating functional WebRTC applications
    a lot simpler.

  **/

  /**
    #### broadcast(stream)

    Add the stream to the set of local streams that we will broadcast
    to other peers.

  **/
  signaller.broadcast = function(stream) {
    localStreams.push(stream);
    return signaller;
  };

  /**
    #### close()

    The `close` function provides a convenient way of closing all associated
    peer connections.
  **/
  signaller.close = function() {
    Object.keys(peers).forEach(function(id) {
      if (peers[id]) {
        peers[id].close();
      }
    });

    // reset the peer references
    peers = {};
  };

  /**
    #### createDataChannel(label, config)

    Request that a data channel with the specified `label` is created on
    the peer connection.  When the data channel is open and available, an
    event will be triggered using the label of the data channel.

    For example, if a new data channel was requested using the following
    call:

    ```js
    var qc = quickconnect('http://rtc.io/switchboard').createDataChannel('test');
    ```

    Then when the data channel is ready for use, a `test:open` event would
    be emitted by `qc`.

  **/
  signaller.createDataChannel = function(label, opts) {
    // save the data channel opts in the local channels dictionary
    channels[label] = opts || null;
    return signaller;
  };

  /**
    #### profile(data)

    Update the profile data with the attached information, so when
    the signaller announces it includes this data in addition to any
    room and id information.

  **/
  signaller.profile = function(data) {
    extend(profile, data);
    return signaller;
  };

  // pass the signaller on
  return signaller;
};<|endoftext|>


<commit_before>require('pkginfo')(module, 'version'); // jshint ignore:line
var fs = require('fs');
var path = require('path');

exports.dataType = require('db-migrate-shared').dataType;

function loadPluginList () {
  var plugins = JSON.parse(
    fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf-8')
  );
  var targets = [];

  plugins = Object.assign(plugins.dependencies, plugins.devDependencies);

  for (var plugin in plugins) {
    if (plugin.startsWith('db-migrate-plugin')) targets.push(plugin);
  }

  return targets;
}

function loadPlugins () {
  var plugins = loadPluginList();
  var i = 0;
  var length = plugins.length;
  var hooks = {};

  for (; i < length; ++i) {
    var plugin = require(path.join(process.cwd(), 'node_modules', plugins[i]));

    if (
      typeof plugin.name !== 'string' ||
      !plugin.hooks ||
      !plugin.loadPlugin
    ) {
      continue;
    }

    plugin.hooks.map(function (hook) {
      hooks[hook] = hooks[hook] || [];
      hooks[hook].push(plugin);
    });
  }

  return hooks;
}

module.exports.getInstance = function (isModule, options, callback) {
  delete require.cache[require.resolve('./api.js')];
  delete require.cache[require.resolve('optimist')];
  var Mod = require('./api.js');
  var plugins = {};

  try {
    if (!options || !options.noPlugins) plugins = loadPlugins();
  } catch (ex) {}

  if (options && options.plugins) {
    plugins = Object.assign(plugins, options.plugins);
  }

  return new Mod(plugins, isModule, options, callback);
};
<commit_msg>fix: Added warning on plugin loading failure<commit_after>require('pkginfo')(module, 'version'); // jshint ignore:line
var fs = require('fs');
var path = require('path');
var log = require('db-migrate-shared').log;

exports.dataType = require('db-migrate-shared').dataType;

function loadPluginList () {
  var plugins = JSON.parse(
    fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf-8')
  );
  var targets = [];

  plugins = Object.assign(plugins.dependencies, plugins.devDependencies);

  for (var plugin in plugins) {
    if (plugin.startsWith('db-migrate-plugin')) targets.push(plugin);
  }

  return targets;
}

function loadPlugins () {
  var plugins = loadPluginList();
  var i = 0;
  var length = plugins.length;
  var hooks = {};

  for (; i < length; ++i) {
    var plugin = require(path.join(process.cwd(), 'node_modules', plugins[i]));

    if (
      typeof plugin.name !== 'string' ||
      !plugin.hooks ||
      !plugin.loadPlugin
    ) {
      continue;
    }

    plugin.hooks.map(function (hook) {
      hooks[hook] = hooks[hook] || [];
      hooks[hook].push(plugin);
    });
  }

  return hooks;
}

module.exports.getInstance = function (isModule, options, callback) {
  delete require.cache[require.resolve('./api.js')];
  delete require.cache[require.resolve('optimist')];
  var Mod = require('./api.js');
  var plugins = {};

  try {
    if (!options || !options.noPlugins) plugins = loadPlugins();
  } catch (ex) {
    log.warn(ex);
  }

  if (options && options.plugins) {
    plugins = Object.assign(plugins, options.plugins);
  }

  return new Mod(plugins, isModule, options, callback);
};
<|endoftext|>


<commit_before>'use strict'
var http = require('http')
var minimist = require('minimist')
var url = require('url')

class ValidationError extends Error {
}

class Command {
  run (options) {
    var optionNames = Object.keys(options)
    if (!this.validate(optionNames)) throw new ValidationError()

    return String(this.core(this.convertOptions(options)))
  }

  convertOptions (options) {
    return Object.keys(options).reduce((memo, key) => {
      memo[key] = String(options[key])
      return memo
    }, {})
  }

  validate (optionNames) {
    if (Array.isArray(this.requiredOptions)) {
      return this.requiredOptions.every(requiredOption =>
        optionNames.indexOf(requiredOption) > -1
      )
    } else {
      return true
    }
  }
}

class Runner {
  constructor (command) {
    this.command = command
  }
}

class CLI extends Runner {
  options () {
    var args = minimist(process.argv.slice(2))

    var options = Object.assign({}, args)
    delete options._
    return Command.prototype.convertOptions(options)
  }

  run () {
    console.log(this.command.run(this.options()))
  }
}

class Server extends Runner {
  constructor (command) {
    super(command)
    this.server = http.createServer(this.callback.bind(this))
  }

  options (req) {
    return url.parse(req.url, true).query
  }

  callback (req, res) {
    res.setHeader('content-type', 'text/plain')
    res.writeHead(200)
    res.end(`${this.command.run(this.options(req))}\n`)
  }

  close () {
    this.server.close()
  }

  run () {
    this.server.listen(3000)
  }
}

module.exports = { ValidationError, Command, Runner, CLI, Server }
<commit_msg>Refactor Command#validate()<commit_after>'use strict'
var http = require('http')
var minimist = require('minimist')
var url = require('url')

class ValidationError extends Error {
}

class Command {
  isSubset (subset, superset) {
    return subset.every(item => superset.indexOf(item) > -1)
  }

  run (options) {
    var optionNames = Object.keys(options)
    if (!this.validate(optionNames)) throw new ValidationError()

    return String(this.core(this.convertOptions(options)))
  }

  convertOptions (options) {
    return Object.keys(options).reduce((memo, key) => {
      memo[key] = String(options[key])
      return memo
    }, {})
  }

  validate (optionNames) {
    return !Array.isArray(this.requiredOptions) ||
             this.isSubset(this.requiredOptions, optionNames)
  }
}

class Runner {
  constructor (command) {
    this.command = command
  }
}

class CLI extends Runner {
  options () {
    var args = minimist(process.argv.slice(2))

    var options = Object.assign({}, args)
    delete options._
    return Command.prototype.convertOptions(options)
  }

  run () {
    console.log(this.command.run(this.options()))
  }
}

class Server extends Runner {
  constructor (command) {
    super(command)
    this.server = http.createServer(this.callback.bind(this))
  }

  options (req) {
    return url.parse(req.url, true).query
  }

  callback (req, res) {
    res.setHeader('content-type', 'text/plain')
    res.writeHead(200)
    res.end(`${this.command.run(this.options(req))}\n`)
  }

  close () {
    this.server.close()
  }

  run () {
    this.server.listen(3000)
  }
}

module.exports = { ValidationError, Command, Runner, CLI, Server }
<|endoftext|>


<commit_before>
/**
 * Module exports.
 */

module.exports = PCRE;

/**
 * Returns a JavaScript RegExp instance from the given PCRE-compatible string.
 * Flags may be passed in after the final delimiter in the `format` string.
 *
 * An empty array may be passsed in as the second argument, which will be
 * populated with the "named capture group" names as Strings in the Array,
 * once the RegExp has been returned.
 *
 * @param {String} pattern - PCRE regexp string to compile to a JS RegExp
 * @param {Array} [namedCaptures] - optional empty array, which will be populated with the named captures extracted from the PCRE regexp
 * @return {RegExp} returns a JavaScript RegExp instance from the given `pattern` and optionally `flags`
 * @public
 */

function PCRE (pattern, namedCaptures) {
  pattern = String(pattern || '').trim();
  var originalPattern = pattern;
  var delim;
  var flags = '';

  // A delimiter can be any non-alphanumeric, non-backslash,
  // non-whitespace character.
  var hasDelim = /^[^a-zA-Z\\\s]/.test(pattern);
  if (hasDelim) {
    delim = pattern[0];
    var lastDelimIndex = pattern.lastIndexOf(delim);

    // pull out the flags in the pattern
    flags += pattern.substring(lastDelimIndex + 1);

    // strip the delims from the pattern
    pattern = pattern.substring(1, lastDelimIndex);
  }

  // populate namedCaptures array and removed named captures from the `pattern`
  pattern = pattern.replace(/\(\?P<([^\>]+)>([^\)]+)\)/g, function (capture, name, regexp) {
    if (namedCaptures) namedCaptures.push(name);
    return '(' + regexp + ')';
  });

  // TODO: convert PCRE-only flags to JS
  // TODO: handle lots more stuff....
  // http://www.php.net/manual/en/reference.pcre.pattern.syntax.php

  var regexp = new RegExp(pattern, flags);

  regexp.delimiter = delim;
  regexp.pcrePattern = originalPattern;
  regexp.pcreFlags = flags;

  return regexp;
}
<commit_msg>index: attempt to handle nested groups<commit_after>
/**
 * Module exports.
 */

module.exports = PCRE;

/**
 * Returns a JavaScript RegExp instance from the given PCRE-compatible string.
 * Flags may be passed in after the final delimiter in the `format` string.
 *
 * An empty array may be passsed in as the second argument, which will be
 * populated with the "named capture group" names as Strings in the Array,
 * once the RegExp has been returned.
 *
 * @param {String} pattern - PCRE regexp string to compile to a JS RegExp
 * @param {Array} [namedCaptures] - optional empty array, which will be populated with the named captures extracted from the PCRE regexp
 * @return {RegExp} returns a JavaScript RegExp instance from the given `pattern` and optionally `flags`
 * @public
 */

function PCRE (pattern, namedCaptures) {
  pattern = String(pattern || '').trim();
  var originalPattern = pattern;
  var delim;
  var flags = '';

  // A delimiter can be any non-alphanumeric, non-backslash,
  // non-whitespace character.
  var hasDelim = /^[^a-zA-Z\\\s]/.test(pattern);
  if (hasDelim) {
    delim = pattern[0];
    var lastDelimIndex = pattern.lastIndexOf(delim);

    // pull out the flags in the pattern
    flags += pattern.substring(lastDelimIndex + 1);

    // strip the delims from the pattern
    pattern = pattern.substring(1, lastDelimIndex);
  }

  // populate namedCaptures array and removed named captures from the `pattern`
  var numGroups = 0;
  pattern = replaceCaptureGroups(pattern, function (group) {
    if ('(?P' === group.substring(0, 3)) {
      // PCRE-style "named capture"
      var match = /^\(\?P<([^\>]+)>([^\)]+)\)$/.exec(group);
      if (namedCaptures) namedCaptures[numGroups] = match[1];
      numGroups++;
      return '(' + match[2] + ')';
    } else if ('(?:' === group.substring(0, 3)) {
      // non-capture group, leave untouched
      return group;
    } else {
      // regular capture, leave untouched
      numGroups++;
      return group;
    }
  });

  // TODO: convert PCRE-only flags to JS
  // TODO: handle lots more stuff....
  // http://www.php.net/manual/en/reference.pcre.pattern.syntax.php

  var regexp = new RegExp(pattern, flags);

  regexp.delimiter = delim;
  regexp.pcrePattern = originalPattern;
  regexp.pcreFlags = flags;

  return regexp;
}

/**
 * Invokes `fn` for each "capture group" encountered in the PCRE `pattern`,
 * and inserts the returned value into the pattern instead of the capture
 * group itself.
 *
 * @private
 */

function replaceCaptureGroups (pattern, fn) {
  var start;
  var depth = 0;
  var escaped = false;

  for (var i = 0; i < pattern.length; i++) {
    var cur = pattern[i];
    if (escaped) {
      // skip this letter, it's been escaped
      escaped = false;
      continue;
    }
    switch (cur) {
      case '(':
        // we're only interested in groups when the depth reaches 0
        if (0 === depth) {
          start = i;
        }
        depth++;
        break;
      case ')':
        if (depth > 0) {
          depth--;

          // we're only interested in groups when the depth reaches 0
          if (0 === depth) {
            var end = i + 1;
            var l = start === 0 ? '' : pattern.substring(0, start);
            var r = pattern.substring(end);
            var v = String(fn(pattern.substring(start, end)));
            pattern = l + v + r;
            i = start;
          }
        }
        break;
      case '\\':
        escaped = true;
        break;
      default:
        // any other letter
        break;
    }
  }
  return pattern;
}
<|endoftext|>


<commit_before>var flatten = require('flatten')
var featureCollection = require('turf-featurecollection')
var point = require('turf-point')

module.exports = function(fc){
  if(fc.type === 'FeatureCollection'){
    for(var i in fc.features){
      var coordinates
      switch(fc.features[i].geometry.type){
        case 'Point':
          coordinates = [fc.features[i].geometry.coordinates]
          break
        case 'LineString':
          coordinates = fc.features[i].geometry.coordinates
          break
        case 'Polygon':
          coordinates = fc.features[i].geometry.coordinates
          coordinates = flatCoords(coordinates)
          break
        case 'MultiPoint':
          coordinates = fc.features[i].geometry.coordinates
          break
        case 'MultiLineString':
          coordinates = fc.features[i].geometry.coordinates
          coordinates = flatCoords(coordinates)
          break
        case 'MultiPolygon':
          coordinates = fc.features[i].geometry.coordinates
          coordinates = flatCoords(coordinates)
          break
      }
      if(!fc.features[i].geometry && fc.features[i].properties){
        return new Error('Unknown Geometry Type')
      }

      for(var n in coordinates){
        if(xmin > coordinates[n][0]){
          xmin = coordinates[n][0]
        }
        if(ymin > coordinates[n][1]){
          ymin = coordinates[n][1]
        }
        if(xmax < coordinates[n][0]){
          xmax = coordinates[n][0]
        }
        if(ymax < coordinates[n][1]){
          ymax = coordinates[n][1]
        }
      }
    }
    var bbox = [xmin, ymin, xmax, ymax]
    return bbox
  }
  else{
    var coordinates
    var geometry
    if(fc.type === 'Feature'){
      geometry = fc.geometry
    }
    else{
      geometry = fc
    }
    switch(geometry.type){
      case 'Point':
        coordinates = [geometry.coordinates]
        break
      case 'LineString':
        coordinates = geometry.coordinates
        break
      case 'Polygon':
        coordinates = geometry.coordinates
        coordinates = flatCoords(coordinates)
        break
      case 'MultiPoint':
        coordinates = geometry.coordinates
        break
      case 'MultiLineString':
        coordinates = geometry.coordinates
        coordinates = flatCoords(coordinates)
        break
      case 'MultiPolygon':
        coordinates = geometry.coordinates
        coordinates = flatCoords(coordinates)
        break
    }
    if(!geometry){
      return new Error('No Geometry Found')
    }

    var exploded = featureCollection([])

    coordinates.forEach(function(coords){
      exploded.features.push(point(coords[0], coords[1]))
    })

    return exploded
  }
}

function flatCoords(coords){
  var newCoords = []
  coords = flatten(coords)
  coords.forEach(function(c, i){
    if(i % 2 == 0) // if is even
    newCoords.push([c, coords[i+1]])
  })
  return newCoords
}<commit_msg>fixed for alt path<commit_after>var flatten = require('flatten')
var featureCollection = require('turf-featurecollection')
var point = require('turf-point')

module.exports = function(fc){
  if(fc.type === 'FeatureCollection'){
    for(var i in fc.features){
      var coordinates
      switch(fc.features[i].geometry.type){
        case 'Point':
          coordinates = [fc.features[i].geometry.coordinates]
          break
        case 'LineString':
          coordinates = fc.features[i].geometry.coordinates
          break
        case 'Polygon':
          coordinates = fc.features[i].geometry.coordinates
          coordinates = flatCoords(coordinates)
          break
        case 'MultiPoint':
          coordinates = fc.features[i].geometry.coordinates
          break
        case 'MultiLineString':
          coordinates = fc.features[i].geometry.coordinates
          coordinates = flatCoords(coordinates)
          break
        case 'MultiPolygon':
          coordinates = fc.features[i].geometry.coordinates
          coordinates = flatCoords(coordinates)
          break
      }
      if(!fc.features[i].geometry && fc.features[i].properties){
        return new Error('Unknown Geometry Type')
      }
    }

    var exploded = featureCollection([])

    coordinates.forEach(function(coords){
      exploded.features.push(point(coords[0], coords[1]))
    })

    return exploded
  }
  else{
    var coordinates
    var geometry
    if(fc.type === 'Feature'){
      geometry = fc.geometry
    }
    else{
      geometry = fc
    }
    switch(geometry.type){
      case 'Point':
        coordinates = [geometry.coordinates]
        break
      case 'LineString':
        coordinates = geometry.coordinates
        break
      case 'Polygon':
        coordinates = geometry.coordinates
        coordinates = flatCoords(coordinates)
        break
      case 'MultiPoint':
        coordinates = geometry.coordinates
        break
      case 'MultiLineString':
        coordinates = geometry.coordinates
        coordinates = flatCoords(coordinates)
        break
      case 'MultiPolygon':
        coordinates = geometry.coordinates
        coordinates = flatCoords(coordinates)
        break
    }
    if(!geometry){
      return new Error('No Geometry Found')
    }

    var exploded = featureCollection([])

    coordinates.forEach(function(coords){
      exploded.features.push(point(coords[0], coords[1]))
    })

    return exploded
  }
}

function flatCoords(coords){
  var newCoords = []
  coords = flatten(coords)
  coords.forEach(function(c, i){
    if(i % 2 == 0) // if is even
    newCoords.push([c, coords[i+1]])
  })
  return newCoords
}<|endoftext|>


<commit_before>module.exports = function oneliner(str) {
  return str.replace(/[\r\n\t ]+/g, ' ');
};
<commit_msg>Support calling oneliner with raw string<commit_after>module.exports = function oneliner(str) {
  return (str.raw? str.raw[0] : str).replace(/[\r\n\t ]+/g, ' ');
};
<|endoftext|>