<commit_before>(
	function($)
	{
		/**
		* createDistributionsList
		*
		* @class Makes the createDistributionsList() method available to JQuery
		* selectors.
		*
		* @param {hash} options The options for generating the list of distributions.
		*/
		$.fn.createDistributionsList = function(options)
		{
			/***** MAIN *****/
			var container = this;

			// Remove existing rows, in case we're refreshing the container.
			container.find('tbody:last tr.distribution').remove();

			// Parse options and add defaults if needed.
			var settings = $.extend(
				{
					pause_id: 'AUBERTG',
					github_id: 'guillaumeaubert',
					coveralls: true,
					travis_ci: true,
					repositories: {},
					repository_lowercase: false,
					template_row: this.find('tr.template:first')
				},
				options
			);

			retrieve_metacpan_information(container, settings);
		};

		/***** SUPPORTING FUNCTIONS *****/

		/**
		* Retrieve the distribution information from MetaCPAN.
		*
		* @param {JQuery selector} container The container to display the
		* distribution rows in.
		* @param {hash} settings The settings to use for display.
		*/
		function retrieve_metacpan_information(container, settings)
		{
			$.ajax(
				{
					type: 'GET',
					async: true,
					dataType: "json",
					url: "http://api.metacpan.org/v0/release/_search?q=author:"+settings.pause_id+"%20AND%20status:latest&fields=version,distribution,date&size=100&sort=distribution",
					success: function(json)
					{
						if (json.timed_out === 'false')
						{
							alert('MetaCPAN timed out (' + json.timed_out + ')!');
							return;
						}
						if (json.hits.total === 0)
						{
							alert('MetaCPAN returned no distributions for this author!');
							return;
						}

						// Display each distribution.
						json.hits.hits.forEach(
							function(element, index)
							{
								display_distribution(
									container,
									settings,
									index,
									element.fields.distribution,
									element.fields.version,
									element.fields.date
								);
							}
						);

						// Asynchronous population of GitHub data.
						populate_github_information(container, settings);
					},
					error: function(xhr)
					{
						alert('Error: ' + xhr.statusText);
					}
				}
			);
		}

		/**
		* Retrieve the repository information from GitHub and populate where
		* needed.
		*
		* @param {JQuery selector} container The container to display the
		* distribution rows in.
		* @param {hash} settings The settings to use for display.
		*/
		function populate_github_information(container, settings)
		{
			$.ajax(
				{
					type: 'GET',
					async: true,
					dataType: "json",
					url: "https://api.github.com/users/"+settings.github_id+"/repos",
					success: function(json)
					{
						if (json.length === 0)
						{
							alert('GitHub returned no repositories for this username!');
							return;
						}

						// Add GitHub information to the appropriate rows.
						json.forEach(
							function(element, index)
							{
								var distribution = element.name;
								var repository = get_repository(settings, distribution);

								container.find('tr#distribution_'+distribution+' td.github_open_issues').html(
									$('<a>')
										.attr('href', "https://github.com/"+settings.github_id+"/"+repository+"/issues")
										.html(element.open_issues_count)
								);
							}
						);

						// Callback for success, if needed.
						if (settings.on_success)
						{
							settings.on_success(json);
						}
					},
					error: function(xhr)
					{
						alert('Error: ' + xhr.statusText);
					}
				}
			);
		}

		/**
		* Retrieve the name of the repository from the name of the distribution.
		*
		* @param {hash} settings The settings to use for display.
		* @param {string} distribution The name of the distribution.
		*/
		function get_repository(settings, distribution)
		{
			return settings.repositories[distribution]
				? settings.repositories[distribution]
				: settings.repository_lowercase
					? distribution.toLowerCase()
					: distribution;
		}

		/**
		* Display a distribution in the container table.
		*
		* @param {JQuery selector} container The container to display the
		* distribution rows in.
		* @param {hash} settings The settings to use for display.
		* @param {integer} index The index of the distribution retrieved.
		* @param {string} distribution The name of the distribution.
		* @param {string} version The current version of the distribution.
		* @param {string} date The date of the latest release of the distribution.
		*/
		function display_distribution(container, settings, index, distribution, version, date)
		{
			var repository = get_repository(settings, distribution);

			// Gather all the data that we will use to build the table.
			var data =
			{
				'distribution': distribution,
				'version': version,
				'date': date,
				'travis_status_badge':
					settings.travis_ci
						? $('<a>')
							.attr('href', 'https://travis-ci.org/'+settings.github_id+'/'+repository)
							.html(
								$('<img>')
									.attr('src', 'https://travis-ci.org/'+settings.github_id+'/'+repository+'.svg?branch=master')
									.attr('alt', 'Build Status')
							)
						: '',
				'coveralls_badge':
					settings.coveralls
						? $('<a>')
							.attr('href', 'https://coveralls.io/r/'+settings.github_id+'/'+repository+'?branch=master')
							.html(
								$('<img>')
									.attr('src', 'https://coveralls.io/repos/'+settings.github_id+'/'+repository+'/badge.svg?branch=master')
									.attr('alt', 'Coverage Status')
							)
						: '',
				'github': $('<a>')
					.attr('href', 'https://github.com/'+settings.github_id+'/'+repository)
					.html('GitHub'),
				'metacpan': $('<a>')
					.attr('href', 'https://metacpan.org/release/'+distribution)
					.html('MetaCPAN'),
				'cpants': $('<a>')
					.attr('href', 'http://cpants.cpanauthors.org/dist/'+distribution)
					.html('CPANTS')
			};

			// Clone row.
			var tr = settings.template_row.clone();

			// Add information to the row.
			for (var key in data)
			{
				tr.find('.'+key).html(data[key]);
			}
			tr.css('display', '');
			tr.attr('id', 'distribution_'+distribution);
			tr.addClass('distribution');
			tr.removeClass('template');

			// Append the row at the end of the table.
			container.find('tbody:last').append(tr);
		}
	}(jQuery)
);
<commit_msg>Generalize the passing of data to the display function.<commit_after>(
	function($)
	{
		/**
		* createDistributionsList
		*
		* @class Makes the createDistributionsList() method available to JQuery
		* selectors.
		*
		* @param {hash} options The options for generating the list of distributions.
		*/
		$.fn.createDistributionsList = function(options)
		{
			/***** MAIN *****/
			var container = this;

			// Remove existing rows, in case we're refreshing the container.
			container.find('tbody:last tr.distribution').remove();

			// Parse options and add defaults if needed.
			var settings = $.extend(
				{
					pause_id: 'AUBERTG',
					github_id: 'guillaumeaubert',
					coveralls: true,
					travis_ci: true,
					repositories: {},
					repository_lowercase: false,
					template_row: this.find('tr.template:first')
				},
				options
			);

			retrieve_metacpan_information(container, settings);
		};

		/***** SUPPORTING FUNCTIONS *****/

		/**
		* Retrieve the distribution information from MetaCPAN.
		*
		* @param {JQuery selector} container The container to display the
		* distribution rows in.
		* @param {hash} settings The settings to use for display.
		*/
		function retrieve_metacpan_information(container, settings)
		{
			$.ajax(
				{
					type: 'GET',
					async: true,
					dataType: "json",
					url: "http://api.metacpan.org/v0/release/_search?q=author:"+settings.pause_id+"%20AND%20status:latest&fields=version,distribution,date&size=100&sort=distribution",
					success: function(json)
					{
						if (json.timed_out === 'false')
						{
							alert('MetaCPAN timed out (' + json.timed_out + ')!');
							return;
						}
						if (json.hits.total === 0)
						{
							alert('MetaCPAN returned no distributions for this author!');
							return;
						}

						// Display each distribution.
						json.hits.hits.forEach(
							function(element, index)
							{
								display_distribution(
									container,
									settings,
									index,
									element.fields
								);
							}
						);

						// Asynchronous population of GitHub data.
						populate_github_information(container, settings);
					},
					error: function(xhr)
					{
						alert('Error: ' + xhr.statusText);
					}
				}
			);
		}

		/**
		* Retrieve the repository information from GitHub and populate where
		* needed.
		*
		* @param {JQuery selector} container The container to display the
		* distribution rows in.
		* @param {hash} settings The settings to use for display.
		*/
		function populate_github_information(container, settings)
		{
			$.ajax(
				{
					type: 'GET',
					async: true,
					dataType: "json",
					url: "https://api.github.com/users/"+settings.github_id+"/repos",
					success: function(json)
					{
						if (json.length === 0)
						{
							alert('GitHub returned no repositories for this username!');
							return;
						}

						// Add GitHub information to the appropriate rows.
						json.forEach(
							function(element, index)
							{
								var distribution = element.name;
								var repository = get_repository(settings, distribution);

								container.find('tr#distribution_'+distribution+' td.github_open_issues').html(
									$('<a>')
										.attr('href', "https://github.com/"+settings.github_id+"/"+repository+"/issues")
										.html(element.open_issues_count)
								);
							}
						);

						// Callback for success, if needed.
						if (settings.on_success)
						{
							settings.on_success(json);
						}
					},
					error: function(xhr)
					{
						alert('Error: ' + xhr.statusText);
					}
				}
			);
		}

		/**
		* Retrieve the name of the repository from the name of the distribution.
		*
		* @param {hash} settings The settings to use for display.
		* @param {string} distribution The name of the distribution.
		*/
		function get_repository(settings, distribution)
		{
			return settings.repositories[distribution]
				? settings.repositories[distribution]
				: settings.repository_lowercase
					? distribution.toLowerCase()
					: distribution;
		}

		/**
		* Display a distribution in the container table.
		*
		* @param {JQuery selector} container The container to display the
		* distribution rows in.
		* @param {hash} settings The settings to use for display.
		* @param {integer} index The index of the distribution retrieved.
		* @param {string} distribution The name of the distribution.
		* @param {string} version The current version of the distribution.
		* @param {string} date The date of the latest release of the distribution.
		*/
		function display_distribution(container, settings, index, metacpan_data)
		{
			var distribution = metacpan_data.distribution;
			var repository = get_repository(settings, distribution);

			// Gather all the data that we will use to build the table.
			var data =
			{
				'distribution': distribution,
				'version': metacpan_data.version,
				'date': metacpan_data.date,
				'travis_status_badge':
					settings.travis_ci
						? $('<a>')
							.attr('href', 'https://travis-ci.org/'+settings.github_id+'/'+repository)
							.html(
								$('<img>')
									.attr('src', 'https://travis-ci.org/'+settings.github_id+'/'+repository+'.svg?branch=master')
									.attr('alt', 'Build Status')
							)
						: '',
				'coveralls_badge':
					settings.coveralls
						? $('<a>')
							.attr('href', 'https://coveralls.io/r/'+settings.github_id+'/'+repository+'?branch=master')
							.html(
								$('<img>')
									.attr('src', 'https://coveralls.io/repos/'+settings.github_id+'/'+repository+'/badge.svg?branch=master')
									.attr('alt', 'Coverage Status')
							)
						: '',
				'github': $('<a>')
					.attr('href', 'https://github.com/'+settings.github_id+'/'+repository)
					.html('GitHub'),
				'metacpan': $('<a>')
					.attr('href', 'https://metacpan.org/release/'+distribution)
					.html('MetaCPAN'),
				'cpants': $('<a>')
					.attr('href', 'http://cpants.cpanauthors.org/dist/'+distribution)
					.html('CPANTS')
			};

			// Clone row.
			var tr = settings.template_row.clone();

			// Add information to the row.
			for (var key in data)
			{
				tr.find('.'+key).html(data[key]);
			}
			tr.css('display', '');
			tr.attr('id', 'distribution_'+distribution);
			tr.addClass('distribution');
			tr.removeClass('template');

			// Append the row at the end of the table.
			container.find('tbody:last').append(tr);
		}
	}(jQuery)
);
<|endoftext|>


<commit_before>var queue = require('queue-async');
var _ = require('underscore');

function MapConfigNamedLayersAdapter(overviewsApi) {
    this.overviewsApi = overviewsApi;
}

module.exports = MapConfigNamedLayersAdapter;

MapConfigNamedLayersAdapter.prototype.getLayers = function(username, layers, callback) {
  var self = this;

  if (!layers) {
      return callback(null);
  }

  var augmentLayersQueue = queue(layers.length);

  function augmentLayer(layer, done) {
      self.overviewsApi.getOverviewsMetadata(username, layer.options.sql, function(err, metadata){
           if ( !_.isEmpty(metadata) ) {
               layer = _.extend({}, layer, { overviews: metadata });
           }
           done(null, layer);
      });
  }

  function layersAugmentQueueFinish(err, layers) {
    if (err) {
        return callback(err);
    }

    if (!layers || layers.length === 0) {
        return callback(new Error('Missing layers array from layergroup config'));
    }

    return callback(null, layers);
  }

  layers.forEach(function(layer) {
      augmentLayersQueue.defer(augmentLayer, layer);
  });
  augmentLayersQueue.awaitAll(layersAugmentQueueFinish);

};
<commit_msg>Fix: handle error properly when augmented layers with overviews<commit_after>var queue = require('queue-async');
var _ = require('underscore');

function MapConfigNamedLayersAdapter(overviewsApi) {
    this.overviewsApi = overviewsApi;
}

module.exports = MapConfigNamedLayersAdapter;

MapConfigNamedLayersAdapter.prototype.getLayers = function(username, layers, callback) {
  var self = this;

  if (!layers) {
      return callback(null);
  }

  var augmentLayersQueue = queue(layers.length);

  function augmentLayer(layer, done) {
      self.overviewsApi.getOverviewsMetadata(username, layer.options.sql, function(err, metadata){
           if (err) {
               done(err, layer);
           } else {
               if ( !_.isEmpty(metadata) ) {
                   // layer = _.extend({}, layer, { overviews: metadata });
               }
               done(null, layer);
           }
      });
  }

  function layersAugmentQueueFinish(err, layers) {
    if (err) {
        return callback(err);
    }

    if (!layers || layers.length === 0) {
        return callback(new Error('Missing layers array from layergroup config'));
    }

    return callback(null, layers);
  }

  layers.forEach(function(layer) {
      augmentLayersQueue.defer(augmentLayer, layer);
  });
  augmentLayersQueue.awaitAll(layersAugmentQueueFinish);

};
<|endoftext|>


<commit_before>import Slate from 'slate'
import { range } from '../../utility/range'

export function createCell() {
  const textNode = Slate.Raw.deserializeText({
    kind: 'text',
    text: '',
  }, { terse: true })

  return Slate.Block.create({ type: 'td', nodes: [textNode] })
}
export function createRow(columns = 2) {
  return Slate.Block.create({
    type:  'tr',
    nodes: range(1, columns).map(() => createCell()),
  })
}
export function createTable(columns = 2, rows = 2) {
  return Slate.Block.create({
    type:  'table',
    nodes: range(1, rows).map(() => createRow(columns)),
  })
}
<commit_msg>:bug:fix - table cells should be created with a <p> in them, not a text node<commit_after>import Slate from 'slate'
import Paragraph from '../Paragraph'
import { range } from '../../utility/range'

export function createCell() {
  return Slate.Block.create({ type: 'td', nodes: [Paragraph.create()] })
}
export function createRow(columns = 2) {
  return Slate.Block.create({
    type:  'tr',
    nodes: range(1, columns).map(() => createCell()),
  })
}
export function createTable(columns = 2, rows = 2) {
  return Slate.Block.create({
    type:  'table',
    nodes: range(1, rows).map(() => createRow(columns)),
  })
}
<|endoftext|>


<commit_before>/*
	Basic Commands
*/

function setPermission(room, perm, rank) {
	if (!Settings.settings.commands) Settings.settings.commands = {};
	if (!Settings.settings.commands[room]) Settings.settings.commands[room] = {};
	Settings.settings.commands[room][perm] = rank;
	Settings.save();
}

Settings.addPermissions(['say']);

exports.commands = {
	about: 'bot',
	bot: function (arg, by, room, cmd) {
		var text = "I'm a **Pokemon Showdown Bot** written in JavaScript for Node. By: Ecuacion (https://github.com/Ecuacion/Pokemon-Showdown-Node-Bot)";
		if (!this.isRanked('#')) {
			this.pmReply(text);
		} else {
			this.reply(text);
		}
	},

	bottime: 'time',
	time: function (arg, by, room, cmd) {
		var f = new Date();
		var text = "**" + this.trad('time') + ":** " + Tools.addLeftZero(f.getHours(), 2) + ":" + Tools.addLeftZero(f.getMinutes(), 2) + ":" + Tools.addLeftZero(f.getSeconds(), 2);
		if (!this.isRanked('#')) {
			this.pmReply(text);
		} else {
			this.reply(text);
		}
	},

	uptime: function (arg, by, room, cmd) {
		var text = '';
		text += '**Uptime:** ';
		var divisors = [52, 7, 24, 60, 60];
		var units = [this.trad('week'), this.trad('day'), this.trad('hour'), this.trad('minute'), this.trad('second')];
		var buffer = [];
		var uptime = ~~(process.uptime());
		do {
			var divisor = divisors.pop();
			var unit = uptime % divisor;
			buffer.push(unit > 1 ? unit + ' ' + units.pop() + 's' : unit + ' ' + units.pop());
			uptime = ~~(uptime / divisor);
		} while (uptime);

		switch (buffer.length) {
		case 5:
			text += buffer[4] + ', ';
			text += buffer[3] + ', ';
			text += buffer[2] + ', ' + buffer[1] + ', ' + this.trad('and') + ' ' + buffer[0];
			break;
		case 4:
			text += buffer[3] + ', ';
			text += buffer[2] + ', ' + buffer[1] + ', ' + this.trad('and') + ' ' + buffer[0];
			break;
		case 3:
			text += buffer[2] + ', ' + buffer[1] + ', ' + this.trad('and') + ' ' + buffer[0];
			break;
		case 2:
			text += buffer[1] + ' ' + this.trad('and') + ' ' + buffer[0];
			break;
		case 1:
			text += buffer[0];
			break;
		}
		if (!this.isRanked('#')) {
			this.pmReply(text);
		} else {
			this.reply(text);
		}
	},

	seen: function (arg, by, room, cmd) {
		var text = '';
		var name = arg;
		arg = toId(arg);
		if (!arg || arg.length > 18) return this.pmReply(this.trad('inv'));
		if (arg === toId(Bot.status.nickName)) return this.pmReply(this.trad('bot'));
		if (arg === toId(by)) return this.pmReply(this.trad('self'));
		if (Settings.seen[arg]) {
			var dSeen = Settings.seen[arg];
			var lang = Config.language || 'english';
			if (Settings.settings['language'] && Settings.settings['language'][room]) lang = Settings.settings['language'][room];
			text += name + ' ' + this.trad('s1') + ' ' + Tools.getTimeAgo(dSeen.time, lang) + (this.trad('s2') ? (' ' + this.trad('s2')) : '');
			if (dSeen.room) {
				switch (dSeen.action) {
					case 'j':
						text += ', ' + this.trad('j') + ' ' + dSeen.room;
						break;
					case 'l':
						text += ', ' + this.trad('l') + ' ' + dSeen.room;
						break;
					case 'c':
						text += ', ' + this.trad('c') + ' ' + dSeen.room;
						break;
					case 'n':
						text += ', ' + this.trad('n') + ' ' + dSeen.args[0];
						break;
				}
			}
		} else {
			text += this.trad('n1') + ' ' + arg + ' ' + this.trad('n2');
		}
		this.pmReply(text);
	},

	say: function (arg, by, room, cmd) {
		if (!arg) return;
		if (this.roomType !== 'chat') {
			if (this.isRanked('%')) return;
			this.reply(Tools.stripCommands(arg));
		}
		if (!this.can('say')) return;
		this.reply(Tools.stripCommands(arg));
	},

	lang: 'language',
	language: function (arg, by, room, cmd) {
		if (!this.isRanked('#')) return false;
		if (this.roomType !== 'chat') return this.reply(this.trad('notchat'));
		var lang = toId(arg);
		if (!lang.length) return this.reply(this.trad('nolang'));
		if (!Tools.translations[lang]) return this.reply(this.trad('v') + ': ' + Object.keys(Tools.translations).join(', '));
		if (!Settings.settings['language']) Settings.settings['language'] = {};
		Settings.settings['language'][room] = lang;
		Settings.save();
		this.reply(this.trad('l'));
	},

	settings: 'set',
	set: function (arg, by, room, cmd) {
		if (!this.isRanked('#')) return false;
		if (this.roomType !== 'chat') return this.reply(this.trad('notchat'));
		var args = arg.split(",");
		if (args.length < 2) return this.reply(this.trad('u1') + ": " + Config.commandChar + cmd + " " + this.trad('u2'));
		var perm = toId(args[0]);
		var rank = args[1].trim();
		if (!(perm in Settings.permissions)) {
			return this.reply(this.trad('ps') + ": " + Object.keys(Settings.permissions).sort().join(", "));
		}
		if (rank in {'off': 1, 'disable': 1}) {
			setPermission(room, perm, true);
			return this.reply(this.trad('p') + " **" + perm + "** " + this.trad('d'));
		}
		if (rank in {'on': 1, 'all': 1, 'enable': 1}) {
			setPermission(room, perm, ' ');
			return this.reply(this.trad('p') + " **" + perm + "** " + this.trad('a'));
		}
		if (Config.ranks.indexOf(rank) >= 0) {
			setPermission(room, perm, rank);
			return this.reply(this.trad('p') + " **" + perm + "** " + this.trad('r') + ' ' + rank + " " + this.trad('r2'));
		} else {
			return this.reply(this.trad('not1') + " " + rank + " " + this.trad('not2'));
		}
	}
};
<commit_msg>Fix 'say' command permissions<commit_after>/*
	Basic Commands
*/

function setPermission(room, perm, rank) {
	if (!Settings.settings.commands) Settings.settings.commands = {};
	if (!Settings.settings.commands[room]) Settings.settings.commands[room] = {};
	Settings.settings.commands[room][perm] = rank;
	Settings.save();
}

Settings.addPermissions(['say']);

exports.commands = {
	about: 'bot',
	bot: function (arg, by, room, cmd) {
		var text = "I'm a **Pokemon Showdown Bot** written in JavaScript for Node. By: Ecuacion (https://github.com/Ecuacion/Pokemon-Showdown-Node-Bot)";
		if (!this.isRanked('#')) {
			this.pmReply(text);
		} else {
			this.reply(text);
		}
	},

	bottime: 'time',
	time: function (arg, by, room, cmd) {
		var f = new Date();
		var text = "**" + this.trad('time') + ":** " + Tools.addLeftZero(f.getHours(), 2) + ":" + Tools.addLeftZero(f.getMinutes(), 2) + ":" + Tools.addLeftZero(f.getSeconds(), 2);
		if (!this.isRanked('#')) {
			this.pmReply(text);
		} else {
			this.reply(text);
		}
	},

	uptime: function (arg, by, room, cmd) {
		var text = '';
		text += '**Uptime:** ';
		var divisors = [52, 7, 24, 60, 60];
		var units = [this.trad('week'), this.trad('day'), this.trad('hour'), this.trad('minute'), this.trad('second')];
		var buffer = [];
		var uptime = ~~(process.uptime());
		do {
			var divisor = divisors.pop();
			var unit = uptime % divisor;
			buffer.push(unit > 1 ? unit + ' ' + units.pop() + 's' : unit + ' ' + units.pop());
			uptime = ~~(uptime / divisor);
		} while (uptime);

		switch (buffer.length) {
		case 5:
			text += buffer[4] + ', ';
			text += buffer[3] + ', ';
			text += buffer[2] + ', ' + buffer[1] + ', ' + this.trad('and') + ' ' + buffer[0];
			break;
		case 4:
			text += buffer[3] + ', ';
			text += buffer[2] + ', ' + buffer[1] + ', ' + this.trad('and') + ' ' + buffer[0];
			break;
		case 3:
			text += buffer[2] + ', ' + buffer[1] + ', ' + this.trad('and') + ' ' + buffer[0];
			break;
		case 2:
			text += buffer[1] + ' ' + this.trad('and') + ' ' + buffer[0];
			break;
		case 1:
			text += buffer[0];
			break;
		}
		if (!this.isRanked('#')) {
			this.pmReply(text);
		} else {
			this.reply(text);
		}
	},

	seen: function (arg, by, room, cmd) {
		var text = '';
		var name = arg;
		arg = toId(arg);
		if (!arg || arg.length > 18) return this.pmReply(this.trad('inv'));
		if (arg === toId(Bot.status.nickName)) return this.pmReply(this.trad('bot'));
		if (arg === toId(by)) return this.pmReply(this.trad('self'));
		if (Settings.seen[arg]) {
			var dSeen = Settings.seen[arg];
			var lang = Config.language || 'english';
			if (Settings.settings['language'] && Settings.settings['language'][room]) lang = Settings.settings['language'][room];
			text += name + ' ' + this.trad('s1') + ' ' + Tools.getTimeAgo(dSeen.time, lang) + (this.trad('s2') ? (' ' + this.trad('s2')) : '');
			if (dSeen.room) {
				switch (dSeen.action) {
					case 'j':
						text += ', ' + this.trad('j') + ' ' + dSeen.room;
						break;
					case 'l':
						text += ', ' + this.trad('l') + ' ' + dSeen.room;
						break;
					case 'c':
						text += ', ' + this.trad('c') + ' ' + dSeen.room;
						break;
					case 'n':
						text += ', ' + this.trad('n') + ' ' + dSeen.args[0];
						break;
				}
			}
		} else {
			text += this.trad('n1') + ' ' + arg + ' ' + this.trad('n2');
		}
		this.pmReply(text);
	},

	say: function (arg, by, room, cmd) {
		if (!arg) return;
		if (this.roomType !== 'chat') {
			if (!this.isRanked('%')) return;
			this.reply(Tools.stripCommands(arg));
		}
		if (!this.can('say')) return;
		this.reply(Tools.stripCommands(arg));
	},

	lang: 'language',
	language: function (arg, by, room, cmd) {
		if (!this.isRanked('#')) return false;
		if (this.roomType !== 'chat') return this.reply(this.trad('notchat'));
		var lang = toId(arg);
		if (!lang.length) return this.reply(this.trad('nolang'));
		if (!Tools.translations[lang]) return this.reply(this.trad('v') + ': ' + Object.keys(Tools.translations).join(', '));
		if (!Settings.settings['language']) Settings.settings['language'] = {};
		Settings.settings['language'][room] = lang;
		Settings.save();
		this.reply(this.trad('l'));
	},

	settings: 'set',
	set: function (arg, by, room, cmd) {
		if (!this.isRanked('#')) return false;
		if (this.roomType !== 'chat') return this.reply(this.trad('notchat'));
		var args = arg.split(",");
		if (args.length < 2) return this.reply(this.trad('u1') + ": " + Config.commandChar + cmd + " " + this.trad('u2'));
		var perm = toId(args[0]);
		var rank = args[1].trim();
		if (!(perm in Settings.permissions)) {
			return this.reply(this.trad('ps') + ": " + Object.keys(Settings.permissions).sort().join(", "));
		}
		if (rank in {'off': 1, 'disable': 1}) {
			setPermission(room, perm, true);
			return this.reply(this.trad('p') + " **" + perm + "** " + this.trad('d'));
		}
		if (rank in {'on': 1, 'all': 1, 'enable': 1}) {
			setPermission(room, perm, ' ');
			return this.reply(this.trad('p') + " **" + perm + "** " + this.trad('a'));
		}
		if (Config.ranks.indexOf(rank) >= 0) {
			setPermission(room, perm, rank);
			return this.reply(this.trad('p') + " **" + perm + "** " + this.trad('r') + ' ' + rank + " " + this.trad('r2'));
		} else {
			return this.reply(this.trad('not1') + " " + rank + " " + this.trad('not2'));
		}
	}
};
<|endoftext|>


<commit_before>'use strict';

require('posts', function (Posts) {
  var setPostHeat = function () {
    var allArr = Posts.find({
      oldPoints: {
        $gt: 1
      }
    }).fetch();

    console.log('Setting post heat for ' + allArr.length + ' posts');
    _(allArr).forEach(function (post) {
      var now = new Date();
      var secondsAgo = Math.abs(now - (new Date(post.createdAt))) / 1000
      var hoursAgo = secondsAgo / 60 / 60;
      var points = (post.oldPoints - 1);
      var decay = Math.pow(hoursAgo + 2, 1.5);
      Posts.update({
        _id: post._id
      },{
        $set: {
          heat: points / decay
        }
      });
    });
  };

  // run every 6 seconds
  Meteor.setInterval(setPostHeat, 6 * 1000);
});
<commit_msg>Add a semicolon because I'm stupid<commit_after>'use strict';

require('posts', function (Posts) {
  var setPostHeat = function () {
    var allArr = Posts.find({
      oldPoints: {
        $gt: 1
      }
    }).fetch();

    console.log('Setting post heat for ' + allArr.length + ' posts');
    _(allArr).forEach(function (post) {
      var now = new Date();
      var secondsAgo = Math.abs(now - (new Date(post.createdAt))) / 1000;
      var hoursAgo = secondsAgo / 60 / 60;
      var points = (post.oldPoints - 1);
      var decay = Math.pow(hoursAgo + 2, 1.5);
      Posts.update({
        _id: post._id
      },{
        $set: {
          heat: points / decay
        }
      });
    });
  };

  // run every 6 seconds
  Meteor.setInterval(setPostHeat, 6 * 1000);
});
<|endoftext|>


<commit_before>function HandsontableAutoColumnSize() {
  var that = this
    , instance
    , sampleCount = 5; //number of samples to take of each value length

  this.beforeInit = function () {
    this.autoColumnWidths = [];
    this.autoColumnSizeTmp = {
      thead: null,
      theadTh: null,
      theadStyle: null,
      tbody: null,
      tbodyTd: null,
      noRenderer: null,
      noRendererTd: null,
      renderer: null,
      rendererTd: null,
      container: null,
      containerStyle: null
    };
  };

  this.determineColumnWidth = function (col) {
    var tmp = instance.autoColumnSizeTmp
      , d;

    if (!tmp.container) {
      d = document;

      tmp.thead = d.createElement('table');
      tmp.thead.appendChild(d.createElement('thead')).appendChild(d.createElement('tr')).appendChild(d.createElement('th'));
      tmp.theadTh = tmp.thead.getElementsByTagName('th')[0];

      tmp.thead.className = 'htTable';
      tmp.theadStyle = tmp.thead.style;
      tmp.theadStyle.tableLayout = 'auto';
      tmp.theadStyle.width = 'auto';

      tmp.tbody = tmp.thead.cloneNode(false);
      tmp.tbody.appendChild(d.createElement('tbody')).appendChild(d.createElement('tr')).appendChild(d.createElement('td'));
      tmp.tbodyTd = tmp.tbody.getElementsByTagName('td')[0];

      tmp.noRenderer = tmp.tbody.cloneNode(true);
      tmp.noRendererTd = tmp.noRenderer.getElementsByTagName('td')[0];

      tmp.renderer = tmp.tbody.cloneNode(true);
      tmp.rendererTd = tmp.renderer.getElementsByTagName('td')[0];

      tmp.container = d.createElement('div');
      tmp.container.className = instance.rootElement[0].className + ' hidden';
      tmp.containerStyle = tmp.container.style;

      tmp.container.appendChild(tmp.thead);
      tmp.container.appendChild(tmp.tbody);
      tmp.container.appendChild(tmp.noRenderer);
      tmp.container.appendChild(tmp.renderer);

      instance.rootElement[0].parentNode.appendChild(tmp.container);
    }

    tmp.container.className = instance.rootElement[0].className + ' hidden';
    var cls = instance.$table[0].className;
    tmp.thead.className = cls;
    tmp.tbody.className = cls;

    var rows = instance.countRows();
    var samples = {};
    var maxLen = 0;
    for (var r = 0; r < rows; r++) {
      var value = Handsontable.helper.stringify(instance.getDataAtCell(r, col));
      var len = value.length;
      if (len > maxLen) {
        maxLen = len;
      }
      if (!samples[len]) {
        samples[len] = {
          needed: sampleCount,
          strings: []
        };
      }
      if (samples[len].needed) {
        samples[len].strings.push(value);
        samples[len].needed--;
      }
    }

    var settings = instance.getSettings();
    if (settings.colHeaders) {
      instance.view.appendColHeader(col, tmp.theadTh); //TH innerHTML
    }

    var txt = '';
    for (var i in samples) {
      if (samples.hasOwnProperty(i)) {
        for (var j = 0, jlen = samples[i].strings.length; j < jlen; j++) {
          txt += samples[i].strings[j] + '
';
        }
      }
    }
    tmp.tbodyTd.innerHTML = txt; //TD innerHTML

    instance.view.wt.wtDom.empty(tmp.rendererTd);
    instance.view.wt.wtDom.empty(tmp.noRendererTd);

    tmp.containerStyle.display = 'block';

    var width = instance.view.wt.wtDom.outerWidth(tmp.container);

    var cellProperties = instance.getCellMeta(0, col);
    if (cellProperties.renderer) {
      var str = 9999999999;

      tmp.noRendererTd.appendChild(document.createTextNode(str));
      var renderer = Handsontable.helper.getCellMethod('renderer', cellProperties.renderer);
      renderer(instance, tmp.rendererTd, 0, col, instance.colToProp(col), str, cellProperties);

      width += instance.view.wt.wtDom.outerWidth(tmp.renderer) - instance.view.wt.wtDom.outerWidth(tmp.noRenderer); //add renderer overhead to the calculated width
    }

    var maxWidth = instance.view.wt.wtViewport.getViewportWidth() - 2; //2 is some overhead for cell border
    if (width > maxWidth) {
      width = maxWidth;
    }

    tmp.containerStyle.display = 'none';

    return width;
  };

  this.determineColumnsWidth = function () {
    instance = this;
    var settings = this.getSettings();
    if (settings.autoColumnSize || !settings.colWidths) {
      var cols = this.countCols();
      for (var c = 0; c < cols; c++) {
        if (!instance._getColWidthFromSettings(c)) {
          this.autoColumnWidths[c] = that.determineColumnWidth(c);
        }
      }
    }
  };

  this.getColWidth = function (col, response) {
    if (this.autoColumnWidths[col] && this.autoColumnWidths[col] > response.width) {
      response.width = this.autoColumnWidths[col];
    }
  };

  this.afterDestroy = function () {
    instance = this;
    if (instance.autoColumnSizeTmp.container) {
      instance.autoColumnSizeTmp.container.parentNode.removeChild(instance.autoColumnSizeTmp.container);
    }
  };
}
var htAutoColumnSize = new HandsontableAutoColumnSize();

Handsontable.PluginHooks.add('beforeInit', htAutoColumnSize.beforeInit);
Handsontable.PluginHooks.add('beforeRender', htAutoColumnSize.determineColumnsWidth);
Handsontable.PluginHooks.add('afterGetColWidth', htAutoColumnSize.getColWidth);
Handsontable.PluginHooks.add('afterDestroy', htAutoColumnSize.afterDestroy);
<commit_msg>cleanup: remove redundant line<commit_after>function HandsontableAutoColumnSize() {
  var that = this
    , instance
    , sampleCount = 5; //number of samples to take of each value length

  this.beforeInit = function () {
    this.autoColumnWidths = [];
    this.autoColumnSizeTmp = {
      thead: null,
      theadTh: null,
      theadStyle: null,
      tbody: null,
      tbodyTd: null,
      noRenderer: null,
      noRendererTd: null,
      renderer: null,
      rendererTd: null,
      container: null,
      containerStyle: null
    };
  };

  this.determineColumnWidth = function (col) {
    var tmp = instance.autoColumnSizeTmp
      , d;

    if (!tmp.container) {
      d = document;

      tmp.thead = d.createElement('table');
      tmp.thead.appendChild(d.createElement('thead')).appendChild(d.createElement('tr')).appendChild(d.createElement('th'));
      tmp.theadTh = tmp.thead.getElementsByTagName('th')[0];

      tmp.theadStyle = tmp.thead.style;
      tmp.theadStyle.tableLayout = 'auto';
      tmp.theadStyle.width = 'auto';

      tmp.tbody = tmp.thead.cloneNode(false);
      tmp.tbody.appendChild(d.createElement('tbody')).appendChild(d.createElement('tr')).appendChild(d.createElement('td'));
      tmp.tbodyTd = tmp.tbody.getElementsByTagName('td')[0];

      tmp.noRenderer = tmp.tbody.cloneNode(true);
      tmp.noRendererTd = tmp.noRenderer.getElementsByTagName('td')[0];

      tmp.renderer = tmp.tbody.cloneNode(true);
      tmp.rendererTd = tmp.renderer.getElementsByTagName('td')[0];

      tmp.container = d.createElement('div');
      tmp.container.className = instance.rootElement[0].className + ' hidden';
      tmp.containerStyle = tmp.container.style;

      tmp.container.appendChild(tmp.thead);
      tmp.container.appendChild(tmp.tbody);
      tmp.container.appendChild(tmp.noRenderer);
      tmp.container.appendChild(tmp.renderer);

      instance.rootElement[0].parentNode.appendChild(tmp.container);
    }

    tmp.container.className = instance.rootElement[0].className + ' hidden';
    var cls = instance.$table[0].className;
    tmp.thead.className = cls;
    tmp.tbody.className = cls;

    var rows = instance.countRows();
    var samples = {};
    var maxLen = 0;
    for (var r = 0; r < rows; r++) {
      var value = Handsontable.helper.stringify(instance.getDataAtCell(r, col));
      var len = value.length;
      if (len > maxLen) {
        maxLen = len;
      }
      if (!samples[len]) {
        samples[len] = {
          needed: sampleCount,
          strings: []
        };
      }
      if (samples[len].needed) {
        samples[len].strings.push(value);
        samples[len].needed--;
      }
    }

    var settings = instance.getSettings();
    if (settings.colHeaders) {
      instance.view.appendColHeader(col, tmp.theadTh); //TH innerHTML
    }

    var txt = '';
    for (var i in samples) {
      if (samples.hasOwnProperty(i)) {
        for (var j = 0, jlen = samples[i].strings.length; j < jlen; j++) {
          txt += samples[i].strings[j] + '
';
        }
      }
    }
    tmp.tbodyTd.innerHTML = txt; //TD innerHTML

    instance.view.wt.wtDom.empty(tmp.rendererTd);
    instance.view.wt.wtDom.empty(tmp.noRendererTd);

    tmp.containerStyle.display = 'block';

    var width = instance.view.wt.wtDom.outerWidth(tmp.container);

    var cellProperties = instance.getCellMeta(0, col);
    if (cellProperties.renderer) {
      var str = 9999999999;

      tmp.noRendererTd.appendChild(document.createTextNode(str));
      var renderer = Handsontable.helper.getCellMethod('renderer', cellProperties.renderer);
      renderer(instance, tmp.rendererTd, 0, col, instance.colToProp(col), str, cellProperties);

      width += instance.view.wt.wtDom.outerWidth(tmp.renderer) - instance.view.wt.wtDom.outerWidth(tmp.noRenderer); //add renderer overhead to the calculated width
    }

    var maxWidth = instance.view.wt.wtViewport.getViewportWidth() - 2; //2 is some overhead for cell border
    if (width > maxWidth) {
      width = maxWidth;
    }

    tmp.containerStyle.display = 'none';

    return width;
  };

  this.determineColumnsWidth = function () {
    instance = this;
    var settings = this.getSettings();
    if (settings.autoColumnSize || !settings.colWidths) {
      var cols = this.countCols();
      for (var c = 0; c < cols; c++) {
        if (!instance._getColWidthFromSettings(c)) {
          this.autoColumnWidths[c] = that.determineColumnWidth(c);
        }
      }
    }
  };

  this.getColWidth = function (col, response) {
    if (this.autoColumnWidths[col] && this.autoColumnWidths[col] > response.width) {
      response.width = this.autoColumnWidths[col];
    }
  };

  this.afterDestroy = function () {
    instance = this;
    if (instance.autoColumnSizeTmp.container) {
      instance.autoColumnSizeTmp.container.parentNode.removeChild(instance.autoColumnSizeTmp.container);
    }
  };
}
var htAutoColumnSize = new HandsontableAutoColumnSize();

Handsontable.PluginHooks.add('beforeInit', htAutoColumnSize.beforeInit);
Handsontable.PluginHooks.add('beforeRender', htAutoColumnSize.determineColumnsWidth);
Handsontable.PluginHooks.add('afterGetColWidth', htAutoColumnSize.getColWidth);
Handsontable.PluginHooks.add('afterDestroy', htAutoColumnSize.afterDestroy);
<|endoftext|>


<commit_before>var _ = require('lodash');
var async = require('async');
var fs = require('fs');
var github = require('octonode');
var rimraf = require('rimraf');
var path = require('path');
var exec = require('child_process').exec;
var green = '\u001b[42m \u001b[0m';
var red = '\u001b[41m \u001b[0m';

module.exports = {
    name:'clone',
    description:'Gets an list of all repos in your team and runs git clone for each',
    example: 'bosco clone',
    cmd:cmd,
    options: [{
        option: 'clean',
        syntax: ['--clean', 'Remove any repositories in the workspace that are no longer in the github team']
    }]
}

function cmd(bosco, args, next) {

    var repoPattern = bosco.options.repo;
    var repoRegex = new RegExp(repoPattern);
    var team = bosco.getTeam();
    var teamConfig = bosco.config.get('teams:' + team);

    var client = github.client(bosco.config.get('github:authToken'));

    if(!teamConfig) {

        // The user does not have a team, so just treat the repos config
        // as manually edited
        return bosco.error('Looks like you havent linked this workspace to a team?  Try: ' + 'bosco team setup'.green);

    } else {

        bosco.log('Fetching repository list from Github for ' + team.green + ' team ...');
        var more = true, page = 1, repoList = [];
        async.whilst(
            function () { return more; },
            function (callback) {
                getRepos(client, teamConfig, page, function(err, repos, isMore) {
                    if(err) { return callback(err); }
                    repoList = _.union(repoList, repos);
                    if(isMore) {
                        page = page + 1;
                    } else {
                        more = false;
                    }
                    callback();
                });
            },
            function (err) {
                if(err) {
                    return bosco.error(err.message);
                }
                bosco.log('Cloning ' + (repoList.length + '').green + ' repositories from Github for ' + team.green + ' team ...');
                fetch(bosco, team, repoList, repoRegex, args, next);
            }
        );
    }

}

function getRepos(client, teamConfig, page, next) {

    if(teamConfig.isUser) {
        client.get('/user/repos', {per_page: 20, page: page}, function (err, status, body, headers) {
            next(err, _.pluck(body, 'name'), _.contains(headers.link, 'rel="next"'));
        });
    } else {
        client.get('/teams/' + teamConfig.id + '/repos', {per_page: 20, page: page}, function (err, status, body, headers) {
            next(err, _.pluck(body, 'name'), _.contains(headers.link, 'rel="next"'));
        });
    }

}

function fetch(bosco, team, repos, repoRegex, args, next) {

    var orgPath = bosco.getOrgPath();

    var saveRepos = function(cb) {
        bosco.config.set('teams:' + team + ':repos',repos);
        bosco.config.save(cb);
    }

    var checkOrphans = function(cb) {

        fs.readdir(bosco.getOrgPath(), function(err, files) {

            var orphans = _.chain(files)
                            .map(function(file) { return path.join(bosco.getOrgPath(),file) })
                            .filter(function(file) { return fs.statSync(file).isDirectory() && bosco.exists(path.join(file, '.git')) })
                            .map(function(file) { return path.relative(bosco.getOrgPath(), file); })
                            .difference(repos)
                            .value()

            async.map(orphans, function(orphan, cb2) {
                if(bosco.options.clean) {
                    var orphanPath = bosco.getRepoPath(orphan);
                    checkStatus(bosco, orphanPath, function(err, status) {
                        var canDelete = status.indexOf('Your branch is up-to-date') >= 0 && status.indexOf('nothing to commit') >= 0;
                        if(canDelete) {
                            bosco.log('Deleted project ' + orphan.green + ' as it is no longer in the github team and you have no local changes.');
                            rimraf(orphanPath, cb2)
                        } else {
                            bosco.warn('Wont delete project' + orphan.red + ' as you have uncommited or unpushed local changes.');
                            cb2();
                        }
                    });
                } else {
                    bosco.warn('I am concerned that you still have the repo ' + orphan.red + ' as it is no longer in the github team, run "bosco clone --clean" to remove them.');
                    cb2();
                }
            }, cb);

        });

    }

    var getRepos = function(cb) {

        var progressbar = bosco.config.get('progress') == 'bar',
            total = repos.length,
            pullFlag = false;

          var bar = progressbar ? new bosco.progress('Getting repositories [:bar] :percent :etas', {
            complete: green,
              incomplete: red,
            width: 50,
            total: total
        }) : null;

        async.mapLimit(repos, bosco.concurrency.network, function repoGet(repo, repoCb) {

          if(!repo.match(repoRegex)) return repoCb();

          var repoPath = bosco.getRepoPath(repo);
          var repoUrl = bosco.getRepoUrl(repo);

          if(bosco.exists(repoPath)) {
              pullFlag = true;
              if(progressbar) bar.tick();
              repoCb();
          } else {
              clone(bosco,  progressbar, bar, repoUrl, orgPath, repoCb);
          }
        }, function() {
            if(pullFlag) {
                bosco.warn('Some repositories already existed, to pull changes use \'bosco pull\'');
            }
            cb();
        });

    }

    var gitIgnoreRepos = function(cb) {
        // Ensure repo folders are in workspace gitignore
        var gi = [bosco.getWorkspacePath(),'.gitignore'].join('/');
        fs.readFile(gi, function(err, contents) {
            if(err) { cb(err); }
            contents = contents || '';
            var ignore = contents.toString().split('\n');
            var newIgnore = _.union(ignore, repos, ['.DS_Store','node_modules','.bosco/bosco.json','']);
            fs.writeFile(gi, newIgnore.join('\n') + '\n', cb);
        });
    }

    async.series([saveRepos, checkOrphans, getRepos, gitIgnoreRepos], function() {
        bosco.log('Complete');
        if(next) next();
    });

}

function checkStatus(bosco, repoPath, next) {
    exec('git status', {
      cwd: repoPath
    }, function(err, stdout) {
        return next(err, stdout);
    });
}

function clone(bosco, progressbar, bar, repoUrl, orgPath, next) {
    if(!progressbar) bosco.log('Cloning ' + repoUrl.blue + ' into ' + orgPath.blue);
    exec('git clone ' + repoUrl, {
      cwd: orgPath
    }, function(err, stdout, stderr) {
        if(progressbar) bar.tick();
        if(err) {
            if(progressbar) console.log('');
            bosco.error(repoUrl.blue + ' >> ' + stderr);
        } else {
            if(!progressbar && stdout) bosco.log(repoUrl.blue + ' >> ' + stdout);
        }
        next();
    });
}

<commit_msg>Improve clean criteria as per @geophree comments<commit_after>var _ = require('lodash');
var async = require('async');
var fs = require('fs');
var github = require('octonode');
var rimraf = require('rimraf');
var path = require('path');
var exec = require('child_process').exec;
var green = '\u001b[42m \u001b[0m';
var red = '\u001b[41m \u001b[0m';

module.exports = {
    name:'clone',
    description:'Gets an list of all repos in your team and runs git clone for each',
    example: 'bosco clone',
    cmd:cmd,
    options: [{
        option: 'clean',
        syntax: ['--clean', 'Remove any repositories in the workspace that are no longer in the github team']
    }]
}

function cmd(bosco, args, next) {

    var repoPattern = bosco.options.repo;
    var repoRegex = new RegExp(repoPattern);
    var team = bosco.getTeam();
    var teamConfig = bosco.config.get('teams:' + team);

    var client = github.client(bosco.config.get('github:authToken'));

    if(!teamConfig) {

        // The user does not have a team, so just treat the repos config
        // as manually edited
        return bosco.error('Looks like you havent linked this workspace to a team?  Try: ' + 'bosco team setup'.green);

    } else {

        bosco.log('Fetching repository list from Github for ' + team.green + ' team ...');
        var more = true, page = 1, repoList = [];
        async.whilst(
            function () { return more; },
            function (callback) {
                getRepos(client, teamConfig, page, function(err, repos, isMore) {
                    if(err) { return callback(err); }
                    repoList = _.union(repoList, repos);
                    if(isMore) {
                        page = page + 1;
                    } else {
                        more = false;
                    }
                    callback();
                });
            },
            function (err) {
                if(err) {
                    return bosco.error(err.message);
                }
                bosco.log('Cloning ' + (repoList.length + '').green + ' repositories from Github for ' + team.green + ' team ...');
                fetch(bosco, team, repoList, repoRegex, args, next);
            }
        );
    }

}

function getRepos(client, teamConfig, page, next) {

    if(teamConfig.isUser) {
        client.get('/user/repos', {per_page: 20, page: page}, function (err, status, body, headers) {
            next(err, _.pluck(body, 'name'), _.contains(headers.link, 'rel="next"'));
        });
    } else {
        client.get('/teams/' + teamConfig.id + '/repos', {per_page: 20, page: page}, function (err, status, body, headers) {
            next(err, _.pluck(body, 'name'), _.contains(headers.link, 'rel="next"'));
        });
    }

}

function fetch(bosco, team, repos, repoRegex, args, next) {

    var orgPath = bosco.getOrgPath();

    var saveRepos = function(cb) {
        bosco.config.set('teams:' + team + ':repos',repos);
        bosco.config.save(cb);
    }

    var checkOrphans = function(cb) {

        fs.readdir(bosco.getOrgPath(), function(err, files) {

            var orphans = _.chain(files)
                            .map(function(file) { return path.join(bosco.getOrgPath(),file) })
                            .filter(function(file) { return fs.statSync(file).isDirectory() && bosco.exists(path.join(file, '.git')) })
                            .map(function(file) { return path.relative(bosco.getOrgPath(), file); })
                            .difference(repos)
                            .value()

            async.map(orphans, function(orphan, cb2) {
                if(bosco.options.clean) {
                    var orphanPath = bosco.getRepoPath(orphan);
                    checkCanDelete(bosco, orphanPath, function(err, canDelete) {
                        if(canDelete) {
                            bosco.log('Deleted project ' + orphan.green + ' as it is no longer in the github team and you have no local changes.');
                            rimraf(orphanPath, cb2)
                        } else {
                            bosco.warn('Wont delete project' + orphan.red + ' as you have uncommited or unpushed local changes.');
                            cb2();
                        }
                    });
                } else {
                    bosco.warn('I am concerned that you still have the repo ' + orphan.red + ' as it is no longer in the github team, run "bosco clone --clean" to remove them.');
                    cb2();
                }
            }, cb);

        });

    }

    var getRepos = function(cb) {

        var progressbar = bosco.config.get('progress') == 'bar',
            total = repos.length,
            pullFlag = false;

          var bar = progressbar ? new bosco.progress('Getting repositories [:bar] :percent :etas', {
            complete: green,
              incomplete: red,
            width: 50,
            total: total
        }) : null;

        async.mapLimit(repos, bosco.concurrency.network, function repoGet(repo, repoCb) {

          if(!repo.match(repoRegex)) return repoCb();

          var repoPath = bosco.getRepoPath(repo);
          var repoUrl = bosco.getRepoUrl(repo);

          if(bosco.exists(repoPath)) {
              pullFlag = true;
              if(progressbar) bar.tick();
              repoCb();
          } else {
              clone(bosco,  progressbar, bar, repoUrl, orgPath, repoCb);
          }
        }, function() {
            if(pullFlag) {
                bosco.warn('Some repositories already existed, to pull changes use \'bosco pull\'');
            }
            cb();
        });

    }

    var gitIgnoreRepos = function(cb) {
        // Ensure repo folders are in workspace gitignore
        var gi = [bosco.getWorkspacePath(),'.gitignore'].join('/');
        fs.readFile(gi, function(err, contents) {
            if(err) { cb(err); }
            contents = contents || '';
            var ignore = contents.toString().split('\n');
            var newIgnore = _.union(ignore, repos, ['.DS_Store','node_modules','.bosco/bosco.json','']);
            fs.writeFile(gi, newIgnore.join('\n') + '\n', cb);
        });
    }

    async.series([saveRepos, checkOrphans, getRepos, gitIgnoreRepos], function() {
        bosco.log('Complete');
        if(next) next();
    });

}

function checkCanDelete(bosco, repoPath, next) {

    var reducer = function(memo, cmd, cb) {
        exec(cmd, {
            cwd: repoPath
        }, function(err, stdout) {
            return cb(err, memo && !stdout);
        });
    }

    async.reduce([
        'git stash list',
        'git branch --no-merged origin/master',
        'git status --porcelain'
    ], true, reducer, function(err, result) {
        next(err, result)
    });

}

function clone(bosco, progressbar, bar, repoUrl, orgPath, next) {
    if(!progressbar) bosco.log('Cloning ' + repoUrl.blue + ' into ' + orgPath.blue);
    exec('git clone ' + repoUrl, {
      cwd: orgPath
    }, function(err, stdout, stderr) {
        if(progressbar) bar.tick();
        if(err) {
            if(progressbar) console.log('');
            bosco.error(repoUrl.blue + ' >> ' + stderr);
        } else {
            if(!progressbar && stdout) bosco.log(repoUrl.blue + ' >> ' + stdout);
        }
        next();
    });
}

<|endoftext|>


<commit_before>/*
 *  FCKPlugin.js
 *  ------------
 *  This is a generic file which is needed for plugins that are developed
 *  for FCKEditor. With the below statements that toolbar is created and
 *  several options are being activated.
 *
 *  See the online documentation for more information:
 *  http://wiki.fckeditor.net/
 */

// Register the related commands.
FCKCommands.RegisterCommand(
	'tikiimage',
	new FCKDialogCommand(
		'tikiimage',
		FCKConfig.tikiimageDlgTitle,
		FCKConfig.BasePath + 'dialog/fck_image.html',
		400,
		400
	)
);

var otikiimageItem = new FCKToolbarButton( 'tikiimage', FCKConfig.tikiimageBtn, null, null, false, true );
otikiimageItem.IconPath = _TikiRoot + 'pics/icons/page_white_picture.png';

FCKToolbarItems.RegisterItem( 'tikiimage', otikiimageItem );

var FCKTikiImages = new Object() ;

FCKTikiImages.add = function( sSrc, sHeight, sWidth, sLink, sAlign, sDesc, sImalign, sAlt, sUsemap, sClass ) {
	var oImg = FCK.CreateElement( 'IMG' ) ;
	this.SetupImage( oImg, sSrc, sHeight, sWidth, sLink, sAlign, sDesc, sImalign, sAlt, sUsemap, sClass ) ;
}

FCKTikiImages.SetupImage  = function( img, sSrc, sHeight, sWidth, sLink, sAlign, sDesc, sImalign, sAlt, sUsemap, sClass ) {
	img.contentEditable = 'false' ;
	if ( sClass ) img.className = sClass ;
	if ( sHeight ) img.height = sHeight ;
	if ( sWidth ) img.width = sWidth ;
	if ( sAlign ) img.align = sAlign ;
	if ( sAlt ) img.alt = sAlt ;
	img.src = sSrc ;
	img._tikiimage = true ;
	img.onresizestart = function() {
		FCK.EditorWindow.event.returnValue = false ;
		return false ;
	}
}

FCKTikiImages._SetupClickListener = function() {
	FCKTikiImages._ClickListener = function( e ) {
		if ( e.target.tagName == 'IMG' && e.target.src ) {
			FCKSelection.SelectNode( e.target ) ;
		}
	}
	FCK.EditorDocument.addEventListener( 'click', FCKTikiImages._ClickListener, true ) ;
}

FCKTikiImages.OnDoubleClick = function( img ) {
	if ( img.tagName == 'IMG' && img.src ) {
		FCKCommands.GetCommand( 'tikiimage' ).Execute() ;
	}
}

FCK.RegisterDoubleClickHandler( FCKTikiImages.OnDoubleClick, 'IMG' ) ;

FCKTikiImages.Exist = function( name ) {
	var aImg = FCK.EditorDocument.getElementsByTagName( 'IMG' ) ;
	for ( var i = 0 ; i < aImg.length ; i++ ) {
		if ( aImg[i]._tikiimage ) {
			return true ;
		}
	}
}

if ( FCKBrowserInfo.IsIE ) {
	FCKTikiImages.Redraw = function() {
		var aImgs = FCK.EditorDocument.body.innerText.match( /(\{img\s*[^\}]*\})/g ) ;
		if ( !aImgs ) {
			return ;
		}
		var oRange = FCK.EditorDocument.body.createTextRange() ;
		for ( var i = 0 ; i < aImgs.length ; i++ ) {
			if ( oRange.findText( aImgs[i] ) ) {
				var sImg = aImgs[i].match( /{img\s*([^\}]*)\}/ )[0].split(' ') ;
				var sSrc = '' ;
				var sClass  = '' ;
				var sHeight  = '' ;
				var sWidth  = '' ;
				var sAlign  = '' ;
				alert(sImg) ;
				for ( var j = 0 ; j < sImg.length ; j++ ) {
					if ( sImg[j].indexOf( '=' ) != -1 ) {
						var lParam = sImg[j].split('=')[0] ;
						var lValue = sImg[j].split('=')[1] ;
						if ( lParam == 'src') {
							sSrc = lValue ;
						} else if ( lParam == 'height' ) {
							sHeight = lValue ;
						} else if ( lParam == 'width' ) {
							sWidth = lValue ;
						} else if ( lParam == 'align' ) {
							sAlign = lValue ;
						} else if ( lParam == 'class' ) {
							sClass = lValue ;
						}
					}
				}
				if ( sSrc ) {
					var extra = '' ;
					if ( sHeight ) extra = extra + ' height="' + sHeight + '"' ;
					if ( sWidth ) extra = extra + ' width="' + sWidth + '"' ;
					if ( sClass ) extra = extra + ' class="' + sClass + '"' ;
					if ( sAlign ) extra = extra + ' align="' + sAlign + '"' ;
					oRange.pasteHTML( '' );
				}
			}
		}
	}
} else {
	FCKTikiImages.Redraw = function() {
		var oInteractor = FCK.EditorDocument.createTreeWalker( FCK.EditorDocument.body, NodeFilter.SHOW_TEXT, FCKTikiImages._AcceptNode, true ) ;
		var aNodes = new Array() ;
		while ( oNode = oInteractor.nextNode() ) {
			aNodes[ aNodes.length ] = oNode ;
		}
		for ( var n = 0 ; n < aNodes.length ; n++ ) {
			var aPieces = aNodes[n].nodeValue.split( /(\{img\s*[^\}]*\})/ );
			for ( var i = 0 ; i < aPieces.length ; i++ ) {
				if ( aPieces[i].length > 0 ) {
					if ( aPieces[i].indexOf( '{img ' ) == 0 ) {
						var sImg = aPieces[i].match( /\{img\s*([^\}]*)\}/ )[1].split(' ') ;
						var sSrc = '' ;
						var sHeight = '' ;
						var sWidth = '' ;
						var sLink = '' ;
						var sAlign = '' ;
						var sDesc = '' ;
						var sImalign = '' ;
						var sAlt = '' ;
						var sUsemap = '' ;
						var sClass = '' ;
						for ( var j = 0 ; j < sImg.length ; j++ ) {
							if ( sImg[j].indexOf( '=' ) != -1 ) {
							var lParam = sImg[j].split('=')[0] ;
							var lValue = sImg[j].split('=')[1] ;
							if ( lParam == 'src') {
								sSrc = lValue ;
							} else if ( lParam == 'height' ) {
								sHeight = lValue ;
							} else if ( lParam == 'width' ) {
								sWidth = lValue ;
							} else if ( lParam == 'align' ) {
								sAlign = lValue ;
							} else if ( lParam == 'alt' ) {
								sAlt = lValue ;
							} else if ( lParam == 'link' ) {
							} else if ( lParam == 'desc' ) {
							} else if ( lParam == 'imalign' ) {
								sAlign = lValue ;
							} else if ( lParam == 'usemap' ) {
							} else if ( lParam == 'class' ) {
							}
							}
						}
						var oImg = FCK.EditorDocument.createElement( 'img' ) ;
						FCKTikiImages.SetupImage( oImg, sSrc, sHeight, sWidth, sLink, sAlign, sDesc, sImalign, sAlt, sUsemap, sClass ) ;
						aNodes[n].parentNode.insertBefore( oImg, aNodes[n] ) ;
					} else {
						aNodes[n].parentNode.insertBefore( FCK.EditorDocument.createTextNode( aPieces[i] ) , aNodes[n] ) ;
					}
				}
			}
			aNodes[n].parentNode.removeChild( aNodes[n] ) ;
		}
		FCKTikiImages._SetupClickListener() ;
	}
	FCKTikiImages._AcceptNode = function( node ) {
		if ( /\{img\s/.test( node.nodeValue ) ) {
			return NodeFilter.FILTER_ACCEPT ;
		} else {
			return NodeFilter.FILTER_SKIP ;
		}
	}
}

FCK.Events.AttachEvent( 'OnAfterSetHTML', FCKTikiImages.Redraw ) ;

FCKXHtml.TagProcessors['img'] = function( node, htmlNode ) {
	if ( htmlNode.src ) {
		var extra = '' ;
		if ( htmlNode.height ) extra = extra + ' height=' + htmlNode.height ;
		if ( htmlNode.width ) extra = extra + ' width=' + htmlNode.width ;
		if ( htmlNode.align ) {
			if ( htmlNode.align == 'left' || htmlNode.align == 'right' ) {
				extra = extra + ' imalign=' + htmlNode.align ;
			} else {
				extra = extra + ' align=' + htmlNode.align ;
			}
		}
		if ( htmlNode.alt ) extra = extra + ' alt=' + htmlNode.alt ;
		node = FCKXHtml.XML.createTextNode( '{img src=' + htmlNode.src + ' ' + extra + '}' ) ;
	} else {
		FCKXHtml._AppendChildNodes( node, htmlNode, false ) ;
	}
	return node ;
}

<commit_msg>[FIX] wysiwyg: removed debug alert<commit_after>/*
 *  FCKPlugin.js
 *  ------------
 *  This is a generic file which is needed for plugins that are developed
 *  for FCKEditor. With the below statements that toolbar is created and
 *  several options are being activated.
 *
 *  See the online documentation for more information:
 *  http://wiki.fckeditor.net/
 */

// Register the related commands.
FCKCommands.RegisterCommand(
	'tikiimage',
	new FCKDialogCommand(
		'tikiimage',
		FCKConfig.tikiimageDlgTitle,
		FCKConfig.BasePath + 'dialog/fck_image.html',
		400,
		400
	)
);

var otikiimageItem = new FCKToolbarButton( 'tikiimage', FCKConfig.tikiimageBtn, null, null, false, true );
otikiimageItem.IconPath = _TikiRoot + 'pics/icons/page_white_picture.png';

FCKToolbarItems.RegisterItem( 'tikiimage', otikiimageItem );

var FCKTikiImages = new Object() ;

FCKTikiImages.add = function( sSrc, sHeight, sWidth, sLink, sAlign, sDesc, sImalign, sAlt, sUsemap, sClass ) {
	var oImg = FCK.CreateElement( 'IMG' ) ;
	this.SetupImage( oImg, sSrc, sHeight, sWidth, sLink, sAlign, sDesc, sImalign, sAlt, sUsemap, sClass ) ;
}

FCKTikiImages.SetupImage  = function( img, sSrc, sHeight, sWidth, sLink, sAlign, sDesc, sImalign, sAlt, sUsemap, sClass ) {
	img.contentEditable = 'false' ;
	if ( sClass ) img.className = sClass ;
	if ( sHeight ) img.height = sHeight ;
	if ( sWidth ) img.width = sWidth ;
	if ( sAlign ) img.align = sAlign ;
	if ( sAlt ) img.alt = sAlt ;
	img.src = sSrc ;
	img._tikiimage = true ;
	img.onresizestart = function() {
		FCK.EditorWindow.event.returnValue = false ;
		return false ;
	}
}

FCKTikiImages._SetupClickListener = function() {
	FCKTikiImages._ClickListener = function( e ) {
		if ( e.target.tagName == 'IMG' && e.target.src ) {
			FCKSelection.SelectNode( e.target ) ;
		}
	}
	FCK.EditorDocument.addEventListener( 'click', FCKTikiImages._ClickListener, true ) ;
}

FCKTikiImages.OnDoubleClick = function( img ) {
	if ( img.tagName == 'IMG' && img.src ) {
		FCKCommands.GetCommand( 'tikiimage' ).Execute() ;
	}
}

FCK.RegisterDoubleClickHandler( FCKTikiImages.OnDoubleClick, 'IMG' ) ;

FCKTikiImages.Exist = function( name ) {
	var aImg = FCK.EditorDocument.getElementsByTagName( 'IMG' ) ;
	for ( var i = 0 ; i < aImg.length ; i++ ) {
		if ( aImg[i]._tikiimage ) {
			return true ;
		}
	}
}

if ( FCKBrowserInfo.IsIE ) {
	FCKTikiImages.Redraw = function() {
		var aImgs = FCK.EditorDocument.body.innerText.match( /(\{img\s*[^\}]*\})/g ) ;
		if ( !aImgs ) {
			return ;
		}
		var oRange = FCK.EditorDocument.body.createTextRange() ;
		for ( var i = 0 ; i < aImgs.length ; i++ ) {
			if ( oRange.findText( aImgs[i] ) ) {
				var sImg = aImgs[i].match( /{img\s*([^\}]*)\}/ )[0].split(' ') ;
				var sSrc = '' ;
				var sClass  = '' ;
				var sHeight  = '' ;
				var sWidth  = '' ;
				var sAlign  = '' ;
				for ( var j = 0 ; j < sImg.length ; j++ ) {
					if ( sImg[j].indexOf( '=' ) != -1 ) {
						var lParam = sImg[j].split('=')[0] ;
						var lValue = sImg[j].split('=')[1] ;
						if ( lParam == 'src') {
							sSrc = lValue ;
						} else if ( lParam == 'height' ) {
							sHeight = lValue ;
						} else if ( lParam == 'width' ) {
							sWidth = lValue ;
						} else if ( lParam == 'align' ) {
							sAlign = lValue ;
						} else if ( lParam == 'class' ) {
							sClass = lValue ;
						}
					}
				}
				if ( sSrc ) {
					var extra = '' ;
					if ( sHeight ) extra = extra + ' height="' + sHeight + '"' ;
					if ( sWidth ) extra = extra + ' width="' + sWidth + '"' ;
					if ( sClass ) extra = extra + ' class="' + sClass + '"' ;
					if ( sAlign ) extra = extra + ' align="' + sAlign + '"' ;
					oRange.pasteHTML( '' );
				}
			}
		}
	}
} else {
	FCKTikiImages.Redraw = function() {
		var oInteractor = FCK.EditorDocument.createTreeWalker( FCK.EditorDocument.body, NodeFilter.SHOW_TEXT, FCKTikiImages._AcceptNode, true ) ;
		var aNodes = new Array() ;
		while ( oNode = oInteractor.nextNode() ) {
			aNodes[ aNodes.length ] = oNode ;
		}
		for ( var n = 0 ; n < aNodes.length ; n++ ) {
			var aPieces = aNodes[n].nodeValue.split( /(\{img\s*[^\}]*\})/ );
			for ( var i = 0 ; i < aPieces.length ; i++ ) {
				if ( aPieces[i].length > 0 ) {
					if ( aPieces[i].indexOf( '{img ' ) == 0 ) {
						var sImg = aPieces[i].match( /\{img\s*([^\}]*)\}/ )[1].split(' ') ;
						var sSrc = '' ;
						var sHeight = '' ;
						var sWidth = '' ;
						var sLink = '' ;
						var sAlign = '' ;
						var sDesc = '' ;
						var sImalign = '' ;
						var sAlt = '' ;
						var sUsemap = '' ;
						var sClass = '' ;
						for ( var j = 0 ; j < sImg.length ; j++ ) {
							if ( sImg[j].indexOf( '=' ) != -1 ) {
							var lParam = sImg[j].split('=')[0] ;
							var lValue = sImg[j].split('=')[1] ;
							if ( lParam == 'src') {
								sSrc = lValue ;
							} else if ( lParam == 'height' ) {
								sHeight = lValue ;
							} else if ( lParam == 'width' ) {
								sWidth = lValue ;
							} else if ( lParam == 'align' ) {
								sAlign = lValue ;
							} else if ( lParam == 'alt' ) {
								sAlt = lValue ;
							} else if ( lParam == 'link' ) {
							} else if ( lParam == 'desc' ) {
							} else if ( lParam == 'imalign' ) {
								sAlign = lValue ;
							} else if ( lParam == 'usemap' ) {
							} else if ( lParam == 'class' ) {
							}
							}
						}
						var oImg = FCK.EditorDocument.createElement( 'img' ) ;
						FCKTikiImages.SetupImage( oImg, sSrc, sHeight, sWidth, sLink, sAlign, sDesc, sImalign, sAlt, sUsemap, sClass ) ;
						aNodes[n].parentNode.insertBefore( oImg, aNodes[n] ) ;
					} else {
						aNodes[n].parentNode.insertBefore( FCK.EditorDocument.createTextNode( aPieces[i] ) , aNodes[n] ) ;
					}
				}
			}
			aNodes[n].parentNode.removeChild( aNodes[n] ) ;
		}
		FCKTikiImages._SetupClickListener() ;
	}
	FCKTikiImages._AcceptNode = function( node ) {
		if ( /\{img\s/.test( node.nodeValue ) ) {
			return NodeFilter.FILTER_ACCEPT ;
		} else {
			return NodeFilter.FILTER_SKIP ;
		}
	}
}

FCK.Events.AttachEvent( 'OnAfterSetHTML', FCKTikiImages.Redraw ) ;

FCKXHtml.TagProcessors['img'] = function( node, htmlNode ) {
	if ( htmlNode.src ) {
		var extra = '' ;
		if ( htmlNode.height ) extra = extra + ' height=' + htmlNode.height ;
		if ( htmlNode.width ) extra = extra + ' width=' + htmlNode.width ;
		if ( htmlNode.align ) {
			if ( htmlNode.align == 'left' || htmlNode.align == 'right' ) {
				extra = extra + ' imalign=' + htmlNode.align ;
			} else {
				extra = extra + ' align=' + htmlNode.align ;
			}
		}
		if ( htmlNode.alt ) extra = extra + ' alt=' + htmlNode.alt ;
		node = FCKXHtml.XML.createTextNode( '{img src=' + htmlNode.src + ' ' + extra + '}' ) ;
	} else {
		FCKXHtml._AppendChildNodes( node, htmlNode, false ) ;
	}
	return node ;
}

<|endoftext|>


<commit_before>'use strict';

var assign             = require('es5-ext/object/assign')
  , normalizeOptions   = require('es5-ext/object/normalize-options')
  , ensureObject       = require('es5-ext/object/valid-object')
  , deferred           = require('deferred')
  , ensureDatabase     = require('dbjs/valid-dbjs')
  , ensureDriver       = require('dbjs-persistence/ensure-driver')
  , QueryHandler       = require('../../utils/query-handler')
  , timePerPersonPrint = require('./controllers/statistics-time-per-person-print')
  , timePerRolePrint   = require('./controllers/statistics-time-per-role-print')
  , timePerRoleCsv     = require('./controllers/statistics-time-per-role-csv')
  , getBaseRoutes      = require('./authenticated');

var getProcessingTimesByStepProcessor =
	require('../statistics/get-processing-times-by-step-processor');
var getFilesApprovedByDateAndService =
	require('../statistics/get-files-approved-by-date-and-service');
var getFilesPendingByStepAndService =
	require('../statistics/get-files-pending-by-step-and-service');
var getQueryHandlerConf = require('../../routes/utils/get-statistics-time-query-handler-conf');

module.exports = function (data) {
	var options = normalizeOptions(ensureObject(data))
	  , queryConf, processingStepsMeta, db;

	ensureDriver(options.driver);
	db = ensureDatabase(options.db);
	processingStepsMeta = options.processingStepsMeta;
	queryConf = getQueryHandlerConf({
		db: db,
		processingStepsMeta: processingStepsMeta,
		// Eventual system specific query conf
		queryConf: options.queryConf
	});

	timePerPersonPrint = timePerPersonPrint(assign(options));
	timePerRolePrint   = timePerRolePrint(assign(options));
	timePerRoleCsv     = timePerRoleCsv(assign(options));

	var queryHandler = new QueryHandler(queryConf);

	return assign({
		'get-processing-time-data': function (query) {
			return queryHandler.resolve(query)(function (query) {
				return getProcessingTimesByStepProcessor(assign(options, { query: query }));
			});
		},
		'get-time-per-person-print': {
			headers: timePerPersonPrint.headers,
			controller: function (query) {
				return queryHandler.resolve(query)(function (query) {
					return timePerPersonPrint.controller({ query: query });
				});
			}
		},
		'get-time-per-role-print': {
			headers: timePerRolePrint.headers,
			controller: function (query) {
				return queryHandler.resolve(query)(function (query) {
					return timePerRolePrint.controller({ query: query });
				});
			}
		},
		'get-time-per-role-csv': {
			headers: timePerRoleCsv.headers,
			controller: function (query) {
				return queryHandler.resolve(query)(function (query) {
					return timePerRoleCsv.controller({ query: query });
				});
			}
		},
		'get-dashboard-data': function (query) {
			var today = new Date();
			return queryHandler.resolve(query)(function (query) {
				var finalResult = {};
				return deferred(
					getProcessingTimesByStepProcessor(assign(options,
						{ query: query }))(function (result) {
						assign(finalResult, result);
					}),
					getFilesApprovedByDateAndService(query)(function (filesApproved) {
						assign(finalResult, { filesApprovedByDay: filesApproved });
					}),
					getFilesPendingByStepAndService(query.dateTo ||
						new db.Date(today.getUTCFullYear(), today.getUTCMonth(),
							today.getUTCDate()), processingStepsMeta)(function (pendingFiles) {
						assign(finalResult, { pendingFiles: pendingFiles });
					})
				)(finalResult);
			});
		}
	}, getBaseRoutes());
};
<commit_msg>-- whitespace<commit_after>'use strict';

var assign             = require('es5-ext/object/assign')
  , normalizeOptions   = require('es5-ext/object/normalize-options')
  , ensureObject       = require('es5-ext/object/valid-object')
  , deferred           = require('deferred')
  , ensureDatabase     = require('dbjs/valid-dbjs')
  , ensureDriver       = require('dbjs-persistence/ensure-driver')
  , QueryHandler       = require('../../utils/query-handler')
  , timePerPersonPrint = require('./controllers/statistics-time-per-person-print')
  , timePerRolePrint   = require('./controllers/statistics-time-per-role-print')
  , timePerRoleCsv     = require('./controllers/statistics-time-per-role-csv')
  , getBaseRoutes      = require('./authenticated');

var getProcessingTimesByStepProcessor =
	require('../statistics/get-processing-times-by-step-processor');
var getFilesApprovedByDateAndService =
	require('../statistics/get-files-approved-by-date-and-service');
var getFilesPendingByStepAndService =
	require('../statistics/get-files-pending-by-step-and-service');
var getQueryHandlerConf = require('../../routes/utils/get-statistics-time-query-handler-conf');

module.exports = function (data) {
	var options = normalizeOptions(ensureObject(data))
	  , queryConf, processingStepsMeta, db;

	ensureDriver(options.driver);
	db = ensureDatabase(options.db);
	processingStepsMeta = options.processingStepsMeta;
	queryConf = getQueryHandlerConf({
		db: db,
		processingStepsMeta: processingStepsMeta,
		// Eventual system specific query conf
		queryConf: options.queryConf
	});

	timePerPersonPrint = timePerPersonPrint(assign(options));
	timePerRolePrint = timePerRolePrint(assign(options));
	timePerRoleCsv = timePerRoleCsv(assign(options));

	var queryHandler = new QueryHandler(queryConf);

	return assign({
		'get-processing-time-data': function (query) {
			return queryHandler.resolve(query)(function (query) {
				return getProcessingTimesByStepProcessor(assign(options, { query: query }));
			});
		},
		'get-time-per-person-print': {
			headers: timePerPersonPrint.headers,
			controller: function (query) {
				return queryHandler.resolve(query)(function (query) {
					return timePerPersonPrint.controller({ query: query });
				});
			}
		},
		'get-time-per-role-print': {
			headers: timePerRolePrint.headers,
			controller: function (query) {
				return queryHandler.resolve(query)(function (query) {
					return timePerRolePrint.controller({ query: query });
				});
			}
		},
		'get-time-per-role-csv': {
			headers: timePerRoleCsv.headers,
			controller: function (query) {
				return queryHandler.resolve(query)(function (query) {
					return timePerRoleCsv.controller({ query: query });
				});
			}
		},
		'get-dashboard-data': function (query) {
			var today = new Date();
			return queryHandler.resolve(query)(function (query) {
				var finalResult = {};
				return deferred(
					getProcessingTimesByStepProcessor(assign(options,
						{ query: query }))(function (result) {
						assign(finalResult, result);
					}),
					getFilesApprovedByDateAndService(query)(function (filesApproved) {
						assign(finalResult, { filesApprovedByDay: filesApproved });
					}),
					getFilesPendingByStepAndService(query.dateTo ||
						new db.Date(today.getUTCFullYear(), today.getUTCMonth(),
							today.getUTCDate()), processingStepsMeta)(function (pendingFiles) {
						assign(finalResult, { pendingFiles: pendingFiles });
					})
				)(finalResult);
			});
		}
	}, getBaseRoutes());
};
<|endoftext|>


<commit_before>let kuro
let _msg
let _table = 'radio'

exports.init = function(bot){
	kuro = bot

	// Create the table where we will be storing this module's data
	bot.db.schema.createTableIfNotExists(_table, function (table) {
		table.increments()
		table.string('token')
	}).then(function () {
		bot.db.table(_table).then(function(row){
			if(row.length > 0) return

			// Populate it
			bot.db.table(_table).insert({
				token: ''
			}).then(function() {})
		})
	}).catch(function(error) { kuro.error(error) })

}

exports.run = function(msg, args) {

	_msg = msg

	let newargs  = []
	for(let i = 1; i < args.length; i++)
		newargs.push(args[i])

	if(args[0] === 'token') return this.token(newargs)
	if(args[0] === 'search') return this.search(newargs)
	if(args[0] === 'request') return this.request(newargs)
}

exports.token = function(args) {
	if(args === undefined || args === '') return kuro.edit(_msg, 'You need to provide a token.')
	kuro.db.table(_table).where('id', 1).update({
		token: args[0]
	}).then(function(){
		return kuro.edit(_msg, 'Token saved.')
	}).catch(function(error) { kuro.error(error) })
}

exports.search = function(args) {

	kuro.db.table(_table).where('id', 1).then(function(row){
		if(row[0].token === '') return kuro.edit(_msg, 'Invalid token')

		require('axios')({
			method: 'post',
			url: 'https://listen.moe/api/songs/search',
			data: {
				query: args[0]
			},
			headers: {'authorization': kuro.utils.conf().radiotoken}
		}).then((response) => {
			if(response.data === undefined) return kuro.edit(_msg, '**Error:**')
			if(response.data.success === false) return kuro.edit(_msg, '**Error:**\n' + response.data.message)

			let message = ''
			let count = 0
			for(let song of response.data.songs){
				if(count < 10){
					count++

					if(song.id.toString().length < 4){
						for(let i = song.id.toString().length; i < 4; i++){
							song.id = song.id + ' '
						}
					}

					message = message + `${song.id} | ${song.artist} - ${song.title}` + '\n'
				}
			}

			kuro.edit(_msg, '\`\`\`' + message + '\`\`\`', 10000)

		})
		.catch(function (error) {
			kuro.error(error)
			_msg.edit('**Error:**\n' + error)
		})

	})

}

exports.request = function(args) {

	require('axios')({
		method: 'post',
		url: 'https://listen.moe/api/songs/request',
		data: { song: args[0] },
		headers: {'authorization': kuro.config.radiotoken}
	}).then((response) => {
		if(response.data === undefined) return kuro.edit(_msg, '**Error:**')
		if(response.data.success === false) return kuro.edit(_msg, '**Error:**\n' + response.data.message)

		kuro.edit(_msg, 'Request placed successfully.')
	}).catch(function (error) {
		kuro.error(error)
		_msg.edit('**Error:**\n' + error)
	})

}<commit_msg>possible radio fix<commit_after>let kuro
let _msg
let _table = 'radio'
let _token

exports.init = function(bot){
	kuro = bot

	// Create the table where we will be storing this module's data
	bot.db.schema.createTableIfNotExists(_table, function (table) {
		table.increments()
		table.string('token')
	}).then(function () {
		bot.db.table(_table).then(function(row){
			if(row.length > 0){
				_token = row[0].token
				return
			}

			// Populate it
			bot.db.table(_table).insert({
				token: ''
			}).then(function(){

			})
		})
	}).catch(function(error) { kuro.error(error) })

}

exports.run = function(msg, args) {

	_msg = msg

	let newargs  = []
	for(let i = 1; i < args.length; i++)
		newargs.push(args[i])

	if(args[0] === 'token') return this.token(newargs)
	if(args[0] === 'search') return this.search(newargs)
	if(args[0] === 'request') return this.request(newargs)
}

exports.token = function(args) {
	if(args === undefined || args === '') return kuro.edit(_msg, 'You need to provide a token.')
	kuro.db.table(_table).where('id', 1).update({
		token: args[0]
	}).then(function(){
		_token = args[0]
		return kuro.edit(_msg, 'Token saved.')
	}).catch(function(error) { kuro.error(error) })
}

exports.search = function(args) {

	kuro.db.table(_table).where('id', 1).then(function(row){
		if(row[0].token === '') return kuro.edit(_msg, 'Invalid token')

		require('axios')({
			method: 'post',
			url: 'https://listen.moe/api/songs/search',
			data: {
				query: args[0]
			},
			headers: {'authorization': kuro.config.radiotoken}
		}).then((response) => {
			if(response.data === undefined) return kuro.edit(_msg, '**Error:**')
			if(response.data.success === false) return kuro.edit(_msg, '**Error:**\n' + response.data.message)

			let message = ''
			let count = 0
			for(let song of response.data.songs){
				if(count < 10){
					count++

					if(song.id.toString().length < 4){
						for(let i = song.id.toString().length; i < 4; i++){
							song.id = song.id + ' '
						}
					}

					message = message + `${song.id} | ${song.artist} - ${song.title}` + '\n'
				}
			}

			kuro.edit(_msg, '\`\`\`' + message + '\`\`\`', 10000)

		})
		.catch(function (error) {
			kuro.error(error)
			_msg.edit('**Error:**\n' + error)
		})

	})

}

exports.request = function(args) {

	require('axios')({
		method: 'post',
		url: 'https://listen.moe/api/songs/request',
		data: { song: args[0] },
		headers: {'authorization': kuro.config.radiotoken}
	}).then((response) => {
		if(response.data === undefined) return kuro.edit(_msg, '**Error:**')
		if(response.data.success === false) return kuro.edit(_msg, '**Error:**\n' + response.data.message)

		kuro.edit(_msg, 'Request placed successfully.')
	}).catch(function (error) {
		kuro.error(error)
		_msg.edit('**Error:**\n' + error)
	})

}<|endoftext|>


<commit_before>"use strict";

var request = require('request');
var cheerio = require('cheerio');
var sessionator = require('../managers/sessionator');
var mango = require('../managers/mango');

exports.update_user = function(user) {
    var sessions = sessionator.get_sessions();

    exports.get_max_rank(user.steam_id, function(max_rank) {
        if (max_rank != null) {

            mango.get().then(function(db) {
                var users = db.collection('users');
                users.updateOne({user_id: user.user_id}, {$set: {rl_max_rank: max_rank}}).then(function() {
                    db.close();
                });
            });

            for (var s in sessions) {
                var username = sessions[s].profile.username && sessions[s].profile.username.toLowerCase();
                if (username == user.username) {
                    sessions[s].profile.rocket_league_rank = max_rank;
                }
            }
        }
    });
};

exports.update_all = function() {
    var sessions = sessionator.get_sessions();

    mango.get().then(function(db) {
        var users_collection = db.collection('users');
        users_collection.find({}).toArray(function(err, users) {

            users.forEach(function(user) {
                exports.get_max_rank(user.steam_id, function(max_rank) {
                    if (max_rank != null) {
                        users_collection.updateOne({user_id: user.user_id}, {$set: {rl_max_rank: max_rank}});

                        for (var s in sessions) {
                            var username = sessions[s].profile.username && sessions[s].profile.username.toLowerCase();
                            if (username == user.username) {
                                sessions[s].profile.rocket_league_rank = max_rank;
                            }
                        }
                    }
                });
            });

            db.close();
        });
    });
};

exports.get_max_rank = function(profile_id, callback) {
    if (!profile_id) {
        return;
    }

    request('http://rocketleague.tracker.network/profile/steam/' + profile_id, function(error, response, body) {
        if (!error && response.statusCode == 200) {
            var $ = cheerio.load(body);

            var $table = $(".stats-panel .table-striped").first();
            var $heh = $table.find('img');
            var max_rank = 0;
            var found_rank = false;

            $heh.each(function() {
                var $woboy = $(this);
                var raw_rank = $woboy.attr('src');

                var matches = raw_rank.match(/(\d+).png/);
                if (matches.length >= 2) {
                    var rank = matches[1];
                    found_rank = true;
                    max_rank = Math.max(max_rank, rank);
                }
            });

            if (found_rank) {
                callback(max_rank);
            }
            else {
                callback(null);
            }

        }
        else {
            callback(null);
        }
    });
};
<commit_msg>Heh heh<commit_after>"use strict";

var request = require('request');
var cheerio = require('cheerio');
var sessionator = require('../managers/sessionator');
var mango = require('../managers/mango');

exports.update_user = function(user) {
    var sessions = sessionator.get_sessions();

    exports.get_max_rank(user.steam_id, function(max_rank) {
        if (max_rank != null) {

            mango.get().then(function(db) {
                var users = db.collection('users');
                users.updateOne({user_id: user.user_id}, {$set: {rl_max_rank: max_rank}}).then(function() {
                    db.close();
                });
            });

            for (var s in sessions) {
                var username = sessions[s].profile.username && sessions[s].profile.username.toLowerCase();
                if (username == user.username) {
                    sessions[s].profile.rocket_league_rank = max_rank;
                }
            }
        }
    });
};

exports.update_all = function() {
    var sessions = sessionator.get_sessions();

    mango.get().then(function(db) {
        var users_collection = db.collection('users');
        users_collection.find({}).toArray(function(err, users) {

            users.forEach(function(user) {
                exports.get_max_rank(user.steam_id, function(max_rank) {
                    if (max_rank != null) {
                        users_collection.updateOne({user_id: user.user_id}, {$set: {rl_max_rank: max_rank}});

                        for (var s in sessions) {
                            var username = sessions[s].profile.username && sessions[s].profile.username.toLowerCase();
                            if (username == user.username) {
                                sessions[s].profile.rocket_league_rank = max_rank;
                            }
                        }
                    }
                });
            });

            // TODO close db after all updates complete...
        });
    });
};

exports.get_max_rank = function(profile_id, callback) {
    if (!profile_id) {
        return;
    }

    request('http://rocketleague.tracker.network/profile/steam/' + profile_id, function(error, response, body) {
        if (!error && response.statusCode == 200) {
            var $ = cheerio.load(body);

            var $table = $(".stats-panel .table-striped").first();
            var $heh = $table.find('img');
            var max_rank = 0;
            var found_rank = false;

            $heh.each(function() {
                var $woboy = $(this);
                var raw_rank = $woboy.attr('src');

                var matches = raw_rank.match(/(\d+).png/);
                if (matches.length >= 2) {
                    var rank = matches[1];
                    found_rank = true;
                    max_rank = Math.max(max_rank, rank);
                }
            });

            if (found_rank) {
                callback(max_rank);
            }
            else {
                callback(null);
            }

        }
        else {
            callback(null);
        }
    });
};
<|endoftext|>


<commit_before>module.exports.DEFAULT_CONFIG_STRUCTURE = {
  host: 'localhost',
  port: 1080,
  servers: [{
    enabled: false,
    remarks: 'Default Server',
    transport: 'tcp',
    host: 'example.com',
    port: 23333,
    key: '',
    presets: [{
      name: 'ss-base',
      params: {}
    }]
  }],
  timeout: 600,
  profile: false,
  watch: false,
  log_level: 'info',
  bypass: [
    '127.0.0.1', '::1', '<local>',
    'localhost', '127.*', '10.*',
    '172.16.*', '172.17.*', '172.18.*',
    '172.19.*', '172.20.*', '172.21.*',
    '172.22.*', '172.23.*', '172.24.*',
    '172.25.*', '172.26.*', '172.27.*',
    '172.28.*', '172.29.*', '172.30.*',
    '172.31.*', '172.32.*', '192.168.*'
  ],
  pac: 'http://localhost:1090/proxy.pac',
  pac_status: 0,
  app_status: 0
};<commit_msg>fix(defs): remove "::1" bypass<commit_after>module.exports.DEFAULT_CONFIG_STRUCTURE = {
  host: 'localhost',
  port: 1080,
  servers: [{
    enabled: false,
    remarks: 'Default Server',
    transport: 'tcp',
    host: 'example.com',
    port: 23333,
    key: '',
    presets: [{
      name: 'ss-base',
      params: {}
    }]
  }],
  timeout: 600,
  profile: false,
  watch: false,
  log_level: 'info',
  bypass: [
    '127.0.0.1', '<local>',
    'localhost', '127.*', '10.*',
    '172.16.*', '172.17.*', '172.18.*',
    '172.19.*', '172.20.*', '172.21.*',
    '172.22.*', '172.23.*', '172.24.*',
    '172.25.*', '172.26.*', '172.27.*',
    '172.28.*', '172.29.*', '172.30.*',
    '172.31.*', '172.32.*', '192.168.*'
  ],
  pac: 'http://localhost:1090/proxy.pac',
  pac_status: 0,
  app_status: 0
};<|endoftext|>


<commit_before>var dbConnect = require("../utility.js").dbConnect;
var post = require("../slack.js").post;

module.exports = {
	synopsis: "tally {category} [{member}[++|--]]",
	description: "keep a tally (see: 'tally help')",
	pattern: /^tally\s+(pivot\s+)?(?:(help)|(list)|(?:(\S+)(?:\s+([^\s+-]*)\s*(\+\+|--|\+=\s*\d+|-=\s*\d+)?)?))\s*/i,
	reply: function(m, context, callback) {
		match = { pivot: !!m[1], help: !!m[2], list: !!m[3], command: m[6] };
		match.category = match.pivot ? m[5] : m[4];
		match.member = match.pivot ? m[4] : m[5];
		match.item = match.pivot ? "member" : "category";

		dbConnect(function(db) {
			db.run("CREATE TABLE IF NOT EXISTS tally" +
				"(category TEXT, member TEXT, count INT, PRIMARY KEY (category, member))", function(error) {
				if (error) console.error("Error creating tally table in database: " + JSON.stringify(error));
				else if (match.help) {
					post(["Tally command:",
						"`tally {category} [{member} [++|--|+= n|-= n]]`",
						"'tally list' lists all categories",
						"'tally pivot ...' swaps categories and members",
					].join("\n"),
					context, callback);
				}
				else if (match.list) {
					console.log(match.item);
					db.all("SELECT " + match.item + " FROM tally GROUP BY " + match.item, function(error, rows) {
						if (error) console.error("Error reading tally list: " + JSON.stringify(error));
						else if (rows.length) {
							var result = ["Tally " + match.item + " list:"].concat(rows.map(function(r) { return r[match.item] })).join("\n* ");
							post(result, context, callback);
						}
						else post("No " + match.item + " to list.", context, callback);
					});
				}
				else {
					db.all("SELECT * FROM tally WHERE category LIKE ? AND member LIKE ?", match.category || "%", match.member || "%", function(error, rows) {
						var postTally = function(rows) {
							var result = "";
							for (var i = 0; i < rows.length; i++) {
								result += "\n* " + (match.pivot ? rows[i].category : rows[i].member) + ": " + rows[i].count;
							}
							post("Tally for " + match.item + " '" + match[match.item] + "':" + result, context, callback);
						};

						if (error) console.error("Error reading tally: " + JSON.stringify(error));
						else if (match.command) {
							var count = rows.length ? rows[0].count : 0;
							eval("count" + match.command);
							db.run("DELETE FROM tally WHERE category LIKE ? AND member LIKE ?", match.category, match.member, function(error) {
								if (error) console.error("Error deleting tally: " + JSON.stringify(error));
								else if (count) {
									db.run("INSERT INTO tally VALUES (?, ?, ?)", match.category, match.member, count, function(error) {
										if (error) {
											console.error("Error updating tally: " + JSON.stringify(error));
										}
										else postTally([{category: match.category, member: match.member, count: count}]);
									});
								}
								else postTally([{category: match.category, member: match.member, count: count}]);
							});
						}
						else postTally(rows);
					});
				}
			});
		});
	}
};
<commit_msg>remove unnecessary console.log<commit_after>var dbConnect = require("../utility.js").dbConnect;
var post = require("../slack.js").post;

module.exports = {
	synopsis: "tally {category} [{member}[++|--]]",
	description: "keep a tally (see: 'tally help')",
	pattern: /^tally\s+(pivot\s+)?(?:(help)|(list)|(?:(\S+)(?:\s+([^\s+-]*)\s*(\+\+|--|\+=\s*\d+|-=\s*\d+)?)?))\s*/i,
	reply: function(m, context, callback) {
		match = { pivot: !!m[1], help: !!m[2], list: !!m[3], command: m[6] };
		match.category = match.pivot ? m[5] : m[4];
		match.member = match.pivot ? m[4] : m[5];
		match.item = match.pivot ? "member" : "category";

		dbConnect(function(db) {
			db.run("CREATE TABLE IF NOT EXISTS tally" +
				"(category TEXT, member TEXT, count INT, PRIMARY KEY (category, member))", function(error) {
				if (error) console.error("Error creating tally table in database: " + JSON.stringify(error));
				else if (match.help) {
					post(["Tally command:",
						"`tally {category} [{member} [++|--|+= n|-= n]]`",
						"'tally list' lists all categories",
						"'tally pivot ...' swaps categories and members",
					].join("\n"),
					context, callback);
				}
				else if (match.list) {
					db.all("SELECT " + match.item + " FROM tally GROUP BY " + match.item, function(error, rows) {
						if (error) console.error("Error reading tally list: " + JSON.stringify(error));
						else if (rows.length) {
							var result = ["Tally " + match.item + " list:"].concat(rows.map(function(r) { return r[match.item] })).join("\n* ");
							post(result, context, callback);
						}
						else post("No " + match.item + " to list.", context, callback);
					});
				}
				else {
					db.all("SELECT * FROM tally WHERE category LIKE ? AND member LIKE ?", match.category || "%", match.member || "%", function(error, rows) {
						var postTally = function(rows) {
							var result = "";
							for (var i = 0; i < rows.length; i++) {
								result += "\n* " + (match.pivot ? rows[i].category : rows[i].member) + ": " + rows[i].count;
							}
							post("Tally for " + match.item + " '" + match[match.item] + "':" + result, context, callback);
						};

						if (error) console.error("Error reading tally: " + JSON.stringify(error));
						else if (match.command) {
							var count = rows.length ? rows[0].count : 0;
							eval("count" + match.command);
							db.run("DELETE FROM tally WHERE category LIKE ? AND member LIKE ?", match.category, match.member, function(error) {
								if (error) console.error("Error deleting tally: " + JSON.stringify(error));
								else if (count) {
									db.run("INSERT INTO tally VALUES (?, ?, ?)", match.category, match.member, count, function(error) {
										if (error) {
											console.error("Error updating tally: " + JSON.stringify(error));
										}
										else postTally([{category: match.category, member: match.member, count: count}]);
									});
								}
								else postTally([{category: match.category, member: match.member, count: count}]);
							});
						}
						else postTally(rows);
					});
				}
			});
		});
	}
};
<|endoftext|>


<commit_before>const Player = require('../classes/player');
const YtSong = require('../classes/ytsong');
const ScSong = require('../classes/scsong');
const util = require('./meta/util');

let players = {};

bot.registerCommand('join', (msg, args) => {
    let server = msg.member.guild.id;

    if(!msg.member.voiceState.channelID) return 'You\'re not in a voice channel';
    if(players[server]) return 'I\'m already in a voice channel'; //TODO: Allow the bot to change voice channels

    bot.joinVoiceChannel(msg.member.voiceState.channelID)
    .then(conn => {
        console.log(conn);
        players[server] = new Player(conn, msg.channel);
    })
    .catch(err => {
        console.log(`Error joining voice channel: ${err.stack}`);
        return 'There was an error joining your voice channel';
    });
}, {
    description: 'Make me join your voice channel',
    fullDescription: 'The bot will attempt to join your voice channel'
});

bot.registerCommand('skip', (msg, args) => {
    let server = msg.member.guild.id;

    if(!msg.member.voiceState.channelID) return 'You\'re not in a voice channel';
    if(!players[server]) return 'I\'m not in a voice channel';

    players[server].skip();
}, {
    description: 'Skip the current song',
    fullDescription: 'Skips to the next song or stops playing if the queue is empty'
});

bot.registerCommand('play', (msg, args) => {
    if(args.length === 0) return 'Please supply some form of song';

    let server = msg.member.guild.id;

    if(!msg.member.voiceState.channelID) return 'You\'re not in a voice channel';
    if(!players[server]) return 'I\'m not in a voice channel';

    let type = util.getSource(args.join(' '));
    if(!type) return 'You didn\'t supply a valid song';

    util.getLink(args.join(' '), type === 'query').then(link => {
        let song = {};
        if(type === 'sc') {
            song = new ScSong(link, msg.member.nick || msg.member.user.username, 'sc');
        } else {
            song = new YtSong(link, msg.member.nick || msg.member.user.username, 'yt');
        }

        song.getInfo().then(song => {
            players[server].addSong(song);
        })
        .catch(err => {
            console.log(`Error getting song: ${err.stack}`);
            bot.createMessage(msg.channel.id, 'There was an error adding your song to the queue');
        });
    })
    .catch(err => {
        console.log(`Error querying youtube for song: ${err.stack}`);
        bot.createMessage(msg.channel.id, `I wasn't able to find any information on your song`);
    });

}, {
    description: 'Make me play a song',
    fullDescription: 'The bot will attempt to join your voice channel',
    usage: '<youtube url> or <soundcloud url> or <youtube search>'
});
<commit_msg>remove print, add message to skip command<commit_after>const Player = require('../classes/player');
const YtSong = require('../classes/ytsong');
const ScSong = require('../classes/scsong');
const util = require('./meta/util');

let players = {};

bot.registerCommand('join', (msg, args) => {
    let server = msg.member.guild.id;

    if(!msg.member.voiceState.channelID) return 'You\'re not in a voice channel';
    if(players[server]) return 'I\'m already in a voice channel'; //TODO: Allow the bot to change voice channels

    bot.joinVoiceChannel(msg.member.voiceState.channelID)
    .then(conn => {
        players[server] = new Player(conn, msg.channel);
    })
    .catch(err => {
        console.log(`Error joining voice channel: ${err.stack}`);
        return 'There was an error joining your voice channel';
    });
}, {
    description: 'Make me join your voice channel',
    fullDescription: 'The bot will attempt to join your voice channel'
});

bot.registerCommand('skip', (msg, args) => {
    let server = msg.member.guild.id;

    if(!msg.member.voiceState.channelID) return 'You\'re not in a voice channel';
    if(!players[server]) return 'I\'m not in a voice channel';

    players[server].skip();
    return 'Song was skipped';
}, {
    description: 'Skip the current song',
    fullDescription: 'Skips to the next song or stops playing if the queue is empty'
});

bot.registerCommand('play', (msg, args) => {
    if(args.length === 0) return 'Please supply some form of song';

    let server = msg.member.guild.id;

    if(!msg.member.voiceState.channelID) return 'You\'re not in a voice channel';
    if(!players[server]) return 'I\'m not in a voice channel';

    let type = util.getSource(args.join(' '));
    if(!type) return 'You didn\'t supply a valid song';

    util.getLink(args.join(' '), type === 'query').then(link => {
        let song = {};
        if(type === 'sc') {
            song = new ScSong(link, msg.member.nick || msg.member.user.username, 'sc');
        } else {
            song = new YtSong(link, msg.member.nick || msg.member.user.username, 'yt');
        }

        song.getInfo().then(song => {
            players[server].addSong(song);
        })
        .catch(err => {
            console.log(`Error getting song: ${err.stack}`);
            bot.createMessage(msg.channel.id, 'There was an error adding your song to the queue');
        });
    })
    .catch(err => {
        console.log(`Error querying youtube for song: ${err.stack}`);
        bot.createMessage(msg.channel.id, `I wasn't able to find any information on your song`);
    });

}, {
    description: 'Make me play a song',
    fullDescription: 'The bot will attempt to join your voice channel',
    usage: '<youtube url> or <soundcloud url> or <youtube search>'
});
<|endoftext|>