<commit_before>// -----------
//   Globals
// -----------

var LATENCY = 500;

function basicEventChecker(type, object, flag, extra) {
    object[flag] = false;
    window.addEventListener(type, function handler(c) {
        window.removeEventListener(type, handler, false);
        object[flag] = true;
        if (extra)
            extra();
    }, false);
}

// --------------
//   Test Suite
// --------------

context('Basics', function() {
    should('have public methods', function() {
        ok(window.openDataCache !== undefined, "window.openDataCache exists");
    });

    should('have constants', function() {
        ok(typeof DataCache.IDLE === 'number', "DataCache.IDLE exists");
        ok(typeof DataCache.READY === 'number', "DataCache.IDLE exists");
        ok(typeof DataCache.OBSOLETE === 'number', "DataCache.IDLE exists");
    });
});

context('Resolving Absolute URLs', function() {
    var resolve = DataCache.resolveAbsoluteFromBase;
    var location = { href: 'http://example.com/foo/bar.txt', host: 'example.com' }

    should('resolve properly', function() {

        // Already Full
        ok(resolve(location, 'http://example.com/foo/bar.txt') === '/foo/bar.txt');
        ok(resolve(location, 'http://example.com/foo/bar/baz.txt') === '/foo/bar/baz.txt');

        // Absolute, from host
        ok(resolve(location, '/foo/bar.txt') === '/foo/bar.txt');
        ok(resolve(location, '/foo/bar/baz.txt') === '/foo/bar/baz.txt');

        // Relative from Current Directory
        ok(resolve(location, 'foo/bar.txt') === '/foo/foo/bar.txt');
        ok(resolve(location, 'foo/bar/baz.txt') === '/foo/foo/bar/baz.txt');

        // Relative with tricks
        ok(resolve(location, 'foo/../bar.txt') === '/foo/bar.txt');
        ok(resolve(location, 'foo/../bar/baz.txt') === '/foo/bar/baz.txt');
        ok(resolve(location, 'a/b/c/../../d/../../bar/baz.txt') === '/foo/bar/baz.txt');

        // Absolute + Relative attempt to go above host
        ok(resolve(location, '../../../bar.txt') === '/bar.txt');
        ok(resolve(location, '/../../../bar.txt') === '/bar.txt');

        // Strips the #hash fragment
        ok(resolve(location, 'foo/../bar.txt#hash') === '/foo/bar.txt');
        ok(resolve(location, 'http://example.com/foo/bar.txt#hash') === '/foo/bar.txt');

    });
});

context('Parsing Headers', function() {
    var parse = CacheTransaction.prototype.parseHeaders;
    var headersText = [
        'Date: Sun, 06 Dec 2009 05:19:04 GMT',     // typical data
        'Content-Encoding: gzip',                  // typical data
        'Content-Length: 3447',                    // typical data
        'Content-Type: text/html; charset=UTF-8',  // typical data
        'Cache-Control: private, max-age=0',       // typical data
        'X-Xss-Protection:   0',                   // ignore left pad after colon
        '  Server: gws',                           // ignore left pad
        '  ',                                      // ignore blank line
        'Expires: -2',                             // gets overwritten later on
        'Expires: -1'
    ].join("\n");

    should('create a nice object', function() {
        var obj = parse(headersText);
        ok(obj['Cache-Control'] === "private, max-age=0");
        ok(obj['Content-Encoding'] === "gzip");
        ok(obj['Content-Length'] === "3447");
        ok(obj['Content-Type'] === "text/html; charset=UTF-8");
        ok(obj['Date'] === "Sun, 06 Dec 2009 05:19:04 GMT");
        ok(obj['Expires'] === "-1");
        ok(obj['Server'] === "gws");
        ok(obj['X-Xss-Protection'] === "0");
    });
});

// Testing private code
context('DataCacheGroup/Host', function() {
    var cache = window.openDataCache();
    var version = cache.version;
    var group = cache.group;

    should('have window as the host', function() {
        equals(group.host.realHost, window, "window is host");
    });

    should('return most current for relativeCache', function() {
        var newCache = group.create();
        var newVersion = newCache.version;

        ok(cache.group === newCache.group, "Same Group");
        ok(version < newVersion, "Version are in the proper order");

        ok(group.effectiveCache !== newCache, "Effective is not Newest");
        ok(group.relevantCache  === newCache, "Relevant is Newest");
        group.remove(newCache);
        ok(group.effectiveCache === cache, "Effective is newest");
        ok(group.relevantCache  === cache, "Relevant is newest");
    });

    should('not be not be obsolete', function() {
        equals(group.obsolete, false, "Not obsolete");
    });
});

context('DataCache', function() {
    should('be the same', function() {
        ok(window.openDataCache() === window.openDataCache(), 'Same returned');
    });
});

context('Offline Transaction', function() {
    var flags = {};
    var eventCache = null;

    should('trigger off-line-updating event', function() {
        stop();
        basicEventChecker('off-line-updating', flags, 'firedOfflineUpdating', function(c) {
            eventCache = c;
        });

        var cache = window.openDataCache();
        cache.offlineTransaction(function(tx) {
            flags.callbackFlag = true;
        });

        setTimeout(function() {
            ok(flags.firedOfflineUpdating, "did fire");
            ok(flags.callbackFlag, "did fire");
            ok(eventCache !== cache, "new cache");
            start();
        }); // no latency needed, these are all queued setTimeout's
    });
});

context('Offline Capture', function() {
    var body = 'Hello, World!';
    var uri = 'blah.html';

    should('capture and manage a resource', function() {
        stop();

        var flags = {};
        basicEventChecker('captured', flags, 'firedCapturedEvent');

        var cache = window.openDataCache();
        cache.offlineTransaction(function(tx) {
            tx.capture(uri, body, 'text/plain', ['GET']);
        });

        function verify() {
            cache.swapCache();
            var item = window.openDataCache().getItem(uri);
            ok(item.body === body, "proper data");
            ok(item.readyState === CacheItem.CACHED);
        }

        setTimeout(function() {
            ok(flags.firedCapturedEvent);
            verify();
            start();
        });
    });

    should('capture and release a resource', function() {
        stop();
        var txCache = null;

        var flags = {};
        basicEventChecker('captured', flags, 'firedCapturedEvent');
        basicEventChecker('released', flags, 'firedReleasedEvent');

        var cache = window.openDataCache();
        cache.offlineTransaction(function(tx) {
            tx.capture(uri, body, 'text/plain', ['GET']);
            tx.release(uri);
            txCache = tx.cache;
        });

        setTimeout(function() {
            ok(flags.firedCapturedEvent, 'did fire');
            ok(flags.firedReleasedEvent, 'did fire');
            ok(txCache.getItem(uri).readyState === CacheItem.GONE, 'no longer stored');
            start();
        });
    });
});

context('Online Transaction', function() {
    var uri = 'data.txt';
    var body = 'Hello, World!';
    var asyncData = null;
    var syncData = null;

    should('work asynchronously', function() {
        stop();

        var flags = {}
        basicEventChecker('updating', flags, 'firedUpdatingEvent');
        basicEventChecker('fetching', flags, 'firedFetchingEvent');

        var cache = window.openDataCache();
        var txCache = null;
        cache.transaction(function(tx) {
            tx.capture(uri);
            txCache = tx.cache;
        });

        setTimeout(function() {
            ok(flags.firedUpdatingEvent);
            ok(flags.firedFetchingEvent);
            ok(txCache.getItem(uri).body === body);
            start();
        }, LATENCY);
    });

    should('work synchronously', function() {
        stop();

        var flags = {}
        basicEventChecker('updating', flags, 'firedUpdatingEvent');
        basicEventChecker('fetching', flags, 'firedFetchingEvent');

        var cache = window.openDataCache();
        var tx = cache.transactionSync();
        tx.capture(uri);

        setTimeout(function() {
            ok(flags.firedUpdatingEvent);
            ok(flags.firedFetchingEvent);
            ok(!tx.offline);
            ok(tx.cache.getItem(uri).body === body);
            ok(tx.cache.getItem(uri).readyState === CacheItem.CACHED);
            start();
        }, LATENCY);
    });

    should('have the same resources as the last online', function() {
        var cache = window.openDataCache();
        var tx = cache.transactionSync();
        ok(tx.cache.getItem(uri).body === body);
    });

    should('release a resource', function() {
        stop();

        var flags = {};
        basicEventChecker('released', flags, 'firedReleasedEvent');

        var cache = window.openDataCache();
        var tx = cache.transactionSync();
        tx.release(uri);

        setTimeout(function() {
            ok(flags.firedReleasedEvent, 'did fire');
            ok(tx.cache.getItem(uri).readyState === CacheItem.GONE);
            start();
        });
    });

    should('be aborted', function() {
       stop();

       var flags = {};
       basicEventChecker('error', flags, 'firedErrorEvent');

       var cache = window.openDataCache();
       var tx = cache.transactionSync();
       tx.abort();

       setTimeout(function() {
           ok(flags.firedErrorEvent, 'did fire');
           ok(tx.status === CacheTransaction.ABORTED);
           start();
       });
    });
});

context('Online Transaction with 4xx or 5xx error', function() {
    var uri = 'code.php?code=500';
    should('fire error event', function() {
        stop();

        var flags = {};
        basicEventChecker('error', flags, 'firedErrorEvent');

        var cache = window.openDataCache();
        cache.transaction(function(tx) {
            tx.capture(uri);
        });

        setTimeout(function() {
            ok(flags.firedErrorEvent, "did fire");
            start();
        }, LATENCY);
    });
});

context('Online Transaction with 401', function() {
    var uri = 'code.php?code=401';
    var cache = window.openDataCache();

    should('make fire obsolete event and make obsolete', function() {
        stop();

        var flags = {};
        basicEventChecker('obsolete', flags, 'firedObsoleteEvent');

        cache.transaction(function(tx) {
            tx.capture(uri);
        });

        setTimeout(function() {
            ok(flags.firedObsoleteEvent, "did fire");
            ok(cache.group.status === DataCache.OBSOLETE, "group became obsolete");
            start();
        }, LATENCY);
    });
});
<commit_msg>Tested errorCallback in online transaction<commit_after>// -----------
//   Globals
// -----------

var LATENCY = 500;

function basicEventChecker(type, object, flag, extra) {
    object[flag] = false;
    window.addEventListener(type, function handler(c) {
        window.removeEventListener(type, handler, false);
        object[flag] = true;
        if (extra)
            extra();
    }, false);
}

// --------------
//   Test Suite
// --------------

context('Basics', function() {
    should('have public methods', function() {
        ok(window.openDataCache !== undefined, "window.openDataCache exists");
    });

    should('have constants', function() {
        ok(typeof DataCache.IDLE === 'number', "DataCache.IDLE exists");
        ok(typeof DataCache.READY === 'number', "DataCache.IDLE exists");
        ok(typeof DataCache.OBSOLETE === 'number', "DataCache.IDLE exists");
    });
});

context('Resolving Absolute URLs', function() {
    var resolve = DataCache.resolveAbsoluteFromBase;
    var location = { href: 'http://example.com/foo/bar.txt', host: 'example.com' }

    should('resolve properly', function() {

        // Already Full
        ok(resolve(location, 'http://example.com/foo/bar.txt') === '/foo/bar.txt');
        ok(resolve(location, 'http://example.com/foo/bar/baz.txt') === '/foo/bar/baz.txt');

        // Absolute, from host
        ok(resolve(location, '/foo/bar.txt') === '/foo/bar.txt');
        ok(resolve(location, '/foo/bar/baz.txt') === '/foo/bar/baz.txt');

        // Relative from Current Directory
        ok(resolve(location, 'foo/bar.txt') === '/foo/foo/bar.txt');
        ok(resolve(location, 'foo/bar/baz.txt') === '/foo/foo/bar/baz.txt');

        // Relative with tricks
        ok(resolve(location, 'foo/../bar.txt') === '/foo/bar.txt');
        ok(resolve(location, 'foo/../bar/baz.txt') === '/foo/bar/baz.txt');
        ok(resolve(location, 'a/b/c/../../d/../../bar/baz.txt') === '/foo/bar/baz.txt');

        // Absolute + Relative attempt to go above host
        ok(resolve(location, '../../../bar.txt') === '/bar.txt');
        ok(resolve(location, '/../../../bar.txt') === '/bar.txt');

        // Strips the #hash fragment
        ok(resolve(location, 'foo/../bar.txt#hash') === '/foo/bar.txt');
        ok(resolve(location, 'http://example.com/foo/bar.txt#hash') === '/foo/bar.txt');

    });
});

context('Parsing Headers', function() {
    var parse = CacheTransaction.prototype.parseHeaders;
    var headersText = [
        'Date: Sun, 06 Dec 2009 05:19:04 GMT',     // typical data
        'Content-Encoding: gzip',                  // typical data
        'Content-Length: 3447',                    // typical data
        'Content-Type: text/html; charset=UTF-8',  // typical data
        'Cache-Control: private, max-age=0',       // typical data
        'X-Xss-Protection:   0',                   // ignore left pad after colon
        '  Server: gws',                           // ignore left pad
        '  ',                                      // ignore blank line
        'Expires: -2',                             // gets overwritten later on
        'Expires: -1'
    ].join("\n");

    should('create a nice object', function() {
        var obj = parse(headersText);
        ok(obj['Cache-Control'] === "private, max-age=0");
        ok(obj['Content-Encoding'] === "gzip");
        ok(obj['Content-Length'] === "3447");
        ok(obj['Content-Type'] === "text/html; charset=UTF-8");
        ok(obj['Date'] === "Sun, 06 Dec 2009 05:19:04 GMT");
        ok(obj['Expires'] === "-1");
        ok(obj['Server'] === "gws");
        ok(obj['X-Xss-Protection'] === "0");
    });
});

// Testing private code
context('DataCacheGroup/Host', function() {
    var cache = window.openDataCache();
    var version = cache.version;
    var group = cache.group;

    should('have window as the host', function() {
        equals(group.host.realHost, window, "window is host");
    });

    should('return most current for relativeCache', function() {
        var newCache = group.create();
        var newVersion = newCache.version;

        ok(cache.group === newCache.group, "Same Group");
        ok(version < newVersion, "Version are in the proper order");

        ok(group.effectiveCache !== newCache, "Effective is not Newest");
        ok(group.relevantCache  === newCache, "Relevant is Newest");
        group.remove(newCache);
        ok(group.effectiveCache === cache, "Effective is newest");
        ok(group.relevantCache  === cache, "Relevant is newest");
    });

    should('not be not be obsolete', function() {
        equals(group.obsolete, false, "Not obsolete");
    });
});

context('DataCache', function() {
    should('be the same', function() {
        ok(window.openDataCache() === window.openDataCache(), 'Same returned');
    });
});

context('Offline Transaction', function() {
    var flags = {};
    var eventCache = null;

    should('trigger off-line-updating event', function() {
        stop();
        basicEventChecker('off-line-updating', flags, 'firedOfflineUpdating', function(c) {
            eventCache = c;
        });

        var cache = window.openDataCache();
        cache.offlineTransaction(function(tx) {
            flags.callbackFlag = true;
        });

        setTimeout(function() {
            ok(flags.firedOfflineUpdating, "did fire");
            ok(flags.callbackFlag, "did fire");
            ok(eventCache !== cache, "new cache");
            start();
        }); // no latency needed, these are all queued setTimeout's
    });
});

context('Offline Capture', function() {
    var body = 'Hello, World!';
    var uri = 'blah.html';

    should('capture and manage a resource', function() {
        stop();

        var flags = {};
        basicEventChecker('captured', flags, 'firedCapturedEvent');

        var cache = window.openDataCache();
        cache.offlineTransaction(function(tx) {
            tx.capture(uri, body, 'text/plain', ['GET']);
        });

        function verify() {
            cache.swapCache();
            var item = window.openDataCache().getItem(uri);
            ok(item.body === body, "proper data");
            ok(item.readyState === CacheItem.CACHED);
        }

        setTimeout(function() {
            ok(flags.firedCapturedEvent);
            verify();
            start();
        });
    });

    should('capture and release a resource', function() {
        stop();
        var txCache = null;

        var flags = {};
        basicEventChecker('captured', flags, 'firedCapturedEvent');
        basicEventChecker('released', flags, 'firedReleasedEvent');

        var cache = window.openDataCache();
        cache.offlineTransaction(function(tx) {
            tx.capture(uri, body, 'text/plain', ['GET']);
            tx.release(uri);
            txCache = tx.cache;
        });

        setTimeout(function() {
            ok(flags.firedCapturedEvent, 'did fire');
            ok(flags.firedReleasedEvent, 'did fire');
            ok(txCache.getItem(uri).readyState === CacheItem.GONE, 'no longer stored');
            start();
        });
    });
});

context('Online Transaction', function() {
    var uri = 'data.txt';
    var body = 'Hello, World!';

    should('work asynchronously', function() {
        stop();

        var flags = {}
        basicEventChecker('updating', flags, 'firedUpdatingEvent');
        basicEventChecker('fetching', flags, 'firedFetchingEvent');

        var cache = window.openDataCache();
        var txCache = null;
        cache.transaction(function(tx) {
            tx.capture(uri);
            txCache = tx.cache;
        });

        setTimeout(function() {
            ok(flags.firedUpdatingEvent);
            ok(flags.firedFetchingEvent);
            ok(txCache.getItem(uri).body === body);
            start();
        }, LATENCY);
    });

    should('work synchronously', function() {
        stop();

        var flags = {}
        basicEventChecker('updating', flags, 'firedUpdatingEvent');
        basicEventChecker('fetching', flags, 'firedFetchingEvent');

        var cache = window.openDataCache();
        var tx = cache.transactionSync();
        tx.capture(uri);

        setTimeout(function() {
            ok(flags.firedUpdatingEvent);
            ok(flags.firedFetchingEvent);
            ok(!tx.offline);
            ok(tx.cache.getItem(uri).body === body);
            ok(tx.cache.getItem(uri).readyState === CacheItem.CACHED);
            start();
        }, LATENCY);
    });

    should('have the same resources as the last online', function() {
        var cache = window.openDataCache();
        var tx = cache.transactionSync();
        ok(tx.cache.getItem(uri).body === body);
    });

    should('release a resource', function() {
        stop();

        var flags = {};
        basicEventChecker('released', flags, 'firedReleasedEvent');

        var cache = window.openDataCache();
        var tx = cache.transactionSync();
        tx.release(uri);

        setTimeout(function() {
            ok(flags.firedReleasedEvent, 'did fire');
            ok(tx.cache.getItem(uri).readyState === CacheItem.GONE);
            start();
        });
    });

    should('be aborted', function() {
       stop();

       var flags = {};
       basicEventChecker('error', flags, 'firedErrorEvent');

       var cache = window.openDataCache();
       var tx = cache.transactionSync();
       tx.abort();

       setTimeout(function() {
           ok(flags.firedErrorEvent, 'did fire');
           ok(tx.status === CacheTransaction.ABORTED);
           start();
       });
    });

    should('trigger errorCallback', function() {
        stop();

        var calledErrorCallback = false;
        var cache = window.openDataCache();
        cache.transaction(
            function() { THISWILLCAUSEANERROR; },
            function() { calledErrorCallback = true; }
        );

        setTimeout(function() {
            ok(calledErrorCallback, 'did fire errorCallback');
            start();
        }, LATENCY);
    });
});

context('Online Transaction with 4xx or 5xx error', function() {
    var uri = 'code.php?code=500';
    should('fire error event', function() {
        stop();

        var flags = {};
        basicEventChecker('error', flags, 'firedErrorEvent');

        var cache = window.openDataCache();
        cache.transaction(function(tx) {
            tx.capture(uri);
        });

        setTimeout(function() {
            ok(flags.firedErrorEvent, "did fire");
            start();
        }, LATENCY);
    });
});

context('Online Transaction with 401', function() {
    var uri = 'code.php?code=401';
    var cache = window.openDataCache();

    should('make fire obsolete event and make obsolete', function() {
        stop();

        var flags = {};
        basicEventChecker('obsolete', flags, 'firedObsoleteEvent');

        cache.transaction(function(tx) {
            tx.capture(uri);
        });

        setTimeout(function() {
            ok(flags.firedObsoleteEvent, "did fire");
            ok(cache.group.status === DataCache.OBSOLETE, "group became obsolete");
            start();
        }, LATENCY);
    });
});
<|endoftext|>


<commit_before>var config = require('./config/config'),
mongoose = require('./config/mongoose'),
Bot = require('node-telegram-bot');
var db = mongoose();

var parseRollString = function(rollStr){
	console.log(rollStr);
	if(rollStr.indexOf('d') === -1){
		return false;
	}
	var splitStr = rollStr.split('d');
	// console.log(splitStr);
	var firstPart = splitStr[0];
	var secondPart = rollStr.substring(firstPart.length + 1);

	times = parseInt(firstPart);

	if(times === NaN || times <= 0 || times > 100){
		return false;
	}
	//no more than 100 due to abuse considerations
	//firstInt is a positive integer at this point
	console.log("times: " + times);

	var dice = NaN;
	var modifier = NaN;
	if(rollStr.indexOf('+') > 0 ){
		splitStr = secondPart.split('+');
		if(splitStr.length > 2){
			return false;
		}
		dice = parseInt(splitStr[0]);
		modifier = parseInt(splitStr[1]);
	} else if (rollStr.indexOf('-') > 0 ){
		splitStr = secondPart.split('-');
		if(splitStr.length > 2){
			return false;
		}
		dice = parseInt(splitStr[0]);
		modifier = -1 * parseInt(splitStr[1]);
	} else {
		dice = parseInt(secondPart);
		modifier = 0;
	}

	if(dice === NaN || modifier === NaN){
		return false;
	}

	rollValues = {
		"times" : times,
		"dice" : dice,
		"modifier" : modifier
	};

	console.log(rollValues);

	return rollValues;

};

var calculateRoll = function(roll){
	var sum = 0;
	for (var i = 0; i < roll.times; i++) {
		sum += Math.floor(Math.random() * roll.dice) + 1;
	};
	sum += roll.modifier;
	return sum;
}

var bot = new Bot({
	token: config.token
})
.on('message', function (message) {
	console.log(message);
	var User = db.model('User');
	var Roll = db.model('Roll');

	if(message.hasOwnProperty("text"))
	{
		splitStr = message.text.split(" ");

		if(splitStr.length === 1)
		{
			if(splitStr[0] === "/register")
			{
				console.log("entered /register")
				var userRegisterCallback = function(err,user){
					// var User = db.model('User');
					if(err)
					{
						console.log("error at /register, User.findOne");
						console.log(err);
						bot.sendMessage({"chat_id" : message.chat.id , "text" : err},function(nodifiedPromise){});
						return
					}
					if(user === null)
					{
						User.create({"id": message.from.id}, function(err){
							console.log("error at /register, User.findOne, User.create");
							console.log(err);
							bot.sendMessage({"chat_id" : message.chat.id , "text" : err},function(nodifiedPromise){});
							return
						});
						console.log('added new user');
						bot.sendMessage({"chat_id" : message.chat.id , "text" : "User " + message.from.username + " is registered"},function(nodifiedPromise){});
					} else {
						bot.sendMessage({"chat_id" : message.chat.id , "text" : "User " + message.from.username + " was already registered"},function(nodifiedPromise){});
					}
				};
				userRegisterCallback.message = message;
				User.findOne({"id": message.from.id}, userRegisterCallback);
			}
			else if (splitStr[0] === "/help")
			{
				bot.sendMessage({"chat_id" : message.chat.id , "text" : "/register - register to start using the bot and save your custom rolls | usage: \"/register\"\n/qroll - quick roll without saving a custom roll | usage: \"/qroll 1d4+1\"\n/save - save a custom roll | usage \"/save magicmissile 1d4+1\"\n/roll - roll a previously saved custom roll | usage: \"/roll magicmissile\""});
			}
			else if (splitStr[0] === "/show")
			{
				var userCallback = function(err,user)
				{
					if(err)
					{
						console.log(err);
						bot.sendMessage({"chat_id" : message.chat.id , "text" : err.toString()},function(nodifiedPromise){});
						return
					}
					if(user === null)
					{
						bot.sendMessage({"chat_id" : message.chat.id , "text" : "Please register first by typing \"/register\" (without the quotes)"});
					} else
					{
					//found user, now display rolls
						var rollCallback = function(err,rolls)
						{
							if(err)
							{
								console.log(err);
								bot.sendMessage({"chat_id" : message.chat.id , "text" : err.toString()},function(nodifiedPromise){});
								return
							}
							if(rolls === null)
							{
								bot.sendMessage({"chat_id" : message.chat.id , "reply_to_message_id" : message.message_id ,"text" : "No saved rolls found. Please save a roll first with \"/save <roll name> <integer>d<integer>{+,-}<integer>\", for example: \"/save magicmissile 1d4+1\""},function(nodifiedPromise){});
							}
							else
							{
								console.log('found rolls');
								var msgText = 'Saved rolls for ' + message.from.username + '\n';
								rolls.forEach(function(val,ind,arr){
									var modifierSign = '+';
									if(val.modifier < 0) modifierSign = '';
									msgText += val.name + " | " + val.times + "d" + val.dice +  modifierSign + val.modifier + '\n';
								});
								bot.sendMessage({"chat_id" : message.chat.id , "reply_to_message_id" : message.message_id ,"text" : msgText },function(nodifiedPromise){});
							}
						}
						rollCallback.message = message;
						Roll.find({"id": message.from.id},rollCallback);
					}
				}
				userCallback.message = message;
				User.findOne({"id": message.from.id}, userCallback);
			}
		}
		else if (splitStr.length === 2)
		{
			if(splitStr[0] === "/roll")
			{
				var key = splitStr[1];
				var userCallback = function(err,user){
					if(err)
					{
						console.log(err);
						bot.sendMessage({"chat_id" : message.chat.id , "text" : err.toString()},function(nodifiedPromise){});
						return
					}
					if(user === null)
					{
						bot.sendMessage({"chat_id" : message.chat.id , "text" : "Please register first by typing \"/register\" (without the quotes)"});
					} else
					{
						//found user, now find roll if exists
						var rollCallback = function(err,roll){
							if(err)
							{
								console.log(err);
								bot.sendMessage({"chat_id" : message.chat.id , "text" : err.toString()},function(nodifiedPromise){});
								return
							}
							if(roll === null)
							{
								bot.sendMessage({"chat_id" : message.chat.id , "reply_to_message_id" : message.message_id ,"text" : "Unsaved custom roll. Please save first with \"/save <roll name> <integer>d<integer>{+,-}<integer>\", for example: \"/save magicmissile 1d4+1\""},function(nodifiedPromise){});
							} else
							{
								var newRoll = {};
								newRoll.times = roll.times;
								newRoll.dice = roll.dice;
								newRoll.modifier = roll.modifier;
								result = calculateRoll(newRoll);
								bot.sendMessage({"chat_id" : message.chat.id , "reply_to_message_id" : message.message_id ,"text" : message.from.username + " | " + key + " | " + result },function(nodifiedPromise){});
							}

						}
						rollCallback.message = message;
						rollCallback.key = key;
						Roll.findOne({"id": message.from.id , "name" : key},rollCallback);
				}
			};
			userCallback.message = message;
			userCallback.key = key;
			User.findOne({"id": message.from.id}, userCallback);
			}
			else if(splitStr[0] === "/qroll")
			{
				var roll = parseRollString(splitStr[1]);
				if(roll === false){
					bot.sendMessage({"chat_id" : message.chat.id , "reply_to_message_id" : message.message_id ,"text" : "Invalid roll format or unsaved custom roll. The expected format is \"/qroll <integer>d<integer>{+,-}<integer>\", for example: \"/qroll 2d12+4\""},function(nodifiedPromise){});
					return
				}
				var result = calculateRoll(roll);
				bot.sendMessage({"chat_id" : message.chat.id , "reply_to_message_id" : message.message_id ,"text" : message.from.username + " | " + splitStr[1] + " | " + result },function(nodifiedPromise){});
			}
			// else
			// {
			// 	bot.sendMessage({"chat_id" : message.chat.id , "text" : "Unknown request. Try /help for options"});
			// }
		}
		else if (splitStr.length === 3)
		{
			if(splitStr[0] === "/save")
			{
			var key = splitStr[1];
			var roll = parseRollString(splitStr[2]);

			if(roll === false)
			{
				bot.sendMessage({"chat_id" : message.chat.id , "reply_to_message_id" : message.message_id ,"text" : "Invalid save format. The expected format is \"/save <roll name> <integer>d<integer>{+,-}<integer>\", for example: \"/save magicmissile 1d4+1\""},function(nodifiedPromise){});
				return
			}

			var saveCallback = function(err,user){
				// var User = db.model('User');
				if(err)
				{
					console.log(err);
					bot.sendMessage({"chat_id" : message.chat.id , "text" : "Unknown error" },function(nodifiedPromise){});
					return
				}
				if(user === null)
				{
					bot.sendMessage({"chat_id" : message.chat.id , "text" : "Please register first by typing \"/register\" (without the quotes)"});
				}
				else
				{
					if(roll === false)
					{
						bot.sendMessage({"chat_id" : message.chat.id , "reply_to_message_id" : message.message_id ,"text" : "Invalid roll format. The expected format is \"<integer>d<integer>{+,-}<integer>\", for example: \"2d12+4\""},function(nodifiedPromise){});
					}
					else
					{
						// user = user.toObject();
						// console.log(typeof(user.rolls));
						// console.log('user before adding roll');
						// console.log(user);
						// user.rolls[key.toString()] = roll;
						// console.log('user after adding roll');
						// console.log(user);

						// var rollArray = new Array();
						// rollArray[key] = roll;
						// console.log(rollArray);

						Roll.update({"id": user.id, "name": key}, {$set: {"dice": roll.dice, "times": roll.times, "modifier": roll.modifier}}, {"upsert": true, "new": true}, function(err,result){
							console.log(result);
							console.log('recorded roll');
							bot.sendMessage({"chat_id" : message.chat.id , "reply_to_message_id" : message.message_id ,"text" : message.from.username + " | " + key + " | saved"},function(nodifiedPromise){});
						});
					}
				}
			};
			saveCallback.message = message;
			saveCallback.roll = roll;
			saveCallback.key = key;
			// saveCallback.rollString = splitStr[2];
			User.findOne({"id": message.from.id}, saveCallback);

			}
			else if(splitStr[0] === "/roll")
			{
				console.log('rolling n times');
				var nTimes = parseInt(splitStr[0]);
				if( nTimes > 0)
				{
					console.log('rolling ' + key + ' ' + nTimes);
					if(nTimes > 100)
					{
						bot.sendMessage({"chat_id" : message.chat.id , "text" : "I can repeat the roll to a maximum of 100 times at a time. Please try a smaller number."},function(nodifiedPromise){});
						return
					}
					var key = splitStr[1];
					var userCallback = function(err,user){
						if(err)
						{
							console.log(err);
							bot.sendMessage({"chat_id" : message.chat.id , "text" : err.toString()},function(nodifiedPromise){});
							return
						}
						if(user === null)
						{
							bot.sendMessage({"chat_id" : message.chat.id , "text" : "Please register first by typing \"/register\" (without the quotes)"});
						} else
						{
							//found user, now find roll if exists
							var rollCallback = function(err,roll){
								if(err)
								{
									console.log(err);
									bot.sendMessage({"chat_id" : message.chat.id , "text" : err.toString()},function(nodifiedPromise){});
									return
								}
								if(roll === null)
								{
									bot.sendMessage({"chat_id" : message.chat.id , "reply_to_message_id" : message.message_id ,"text" : "Unsaved custom roll. Please save first with \"/save <roll name> <integer>d<integer>{+,-}<integer>\", for example: \"/save magicmissile 1d4+1\""},function(nodifiedPromise){});
								} else
								{
									var newRoll = {};
									newRoll.times = roll.times;
									newRoll.dice = roll.dice;
									newRoll.modifier = roll.modifier;
									var msgText = 'Rolling ' + key + ' ' + nTimes + ' for ' + message.from.username + '\n';
									var sum = 0;
									for (var i = 0; i < nTimes; i++) {
										var rollResult = calculateRoll(newRoll);
										msgText += rollResult + " | ";
										sum += rollResult;
									};
									msgText += '\n' + 'Sum of rolls: ' + sum;
									bot.sendMessage({"chat_id" : message.chat.id , "reply_to_message_id" : message.message_id ,"text" : msgText},function(nodifiedPromise){});
								}
							};
							rollCallback.message = message;
							rollCallback.key = key;
							Roll.findOne({"id": message.from.id , "name" : key},rollCallback);
						}
					};
					userCallback.message = message;
					userCallback.key = key;
					User.findOne({"id": message.from.id}, userCallback);
				}
				else
				{
					//TODO: wrong roll ntimes syntax
				}

			}
			// else
			// {
			// 	bot.sendMessage({"chat_id" : message.chat.id , "text" : "Unknown request. Try /help for options"});
			// }
		}
	}
}).start();<commit_msg>debugging: repeat saved roll n times<commit_after>var config = require('./config/config'),
mongoose = require('./config/mongoose'),
Bot = require('node-telegram-bot');
var db = mongoose();

var parseRollString = function(rollStr){
	console.log(rollStr);
	if(rollStr.indexOf('d') === -1){
		return false;
	}
	var splitStr = rollStr.split('d');
	// console.log(splitStr);
	var firstPart = splitStr[0];
	var secondPart = rollStr.substring(firstPart.length + 1);

	times = parseInt(firstPart);

	if(times === NaN || times <= 0 || times > 100){
		return false;
	}
	//no more than 100 due to abuse considerations
	//firstInt is a positive integer at this point
	console.log("times: " + times);

	var dice = NaN;
	var modifier = NaN;
	if(rollStr.indexOf('+') > 0 ){
		splitStr = secondPart.split('+');
		if(splitStr.length > 2){
			return false;
		}
		dice = parseInt(splitStr[0]);
		modifier = parseInt(splitStr[1]);
	} else if (rollStr.indexOf('-') > 0 ){
		splitStr = secondPart.split('-');
		if(splitStr.length > 2){
			return false;
		}
		dice = parseInt(splitStr[0]);
		modifier = -1 * parseInt(splitStr[1]);
	} else {
		dice = parseInt(secondPart);
		modifier = 0;
	}

	if(dice === NaN || modifier === NaN){
		return false;
	}

	rollValues = {
		"times" : times,
		"dice" : dice,
		"modifier" : modifier
	};

	console.log(rollValues);

	return rollValues;

};

var calculateRoll = function(roll){
	var sum = 0;
	for (var i = 0; i < roll.times; i++) {
		sum += Math.floor(Math.random() * roll.dice) + 1;
	};
	sum += roll.modifier;
	return sum;
}

var bot = new Bot({
	token: config.token
})
.on('message', function (message) {
	console.log(message);
	var User = db.model('User');
	var Roll = db.model('Roll');

	if(message.hasOwnProperty("text"))
	{
		splitStr = message.text.split(" ");

		if(splitStr.length === 1)
		{
			if(splitStr[0] === "/register")
			{
				console.log("entered /register")
				var userRegisterCallback = function(err,user){
					// var User = db.model('User');
					if(err)
					{
						console.log("error at /register, User.findOne");
						console.log(err);
						bot.sendMessage({"chat_id" : message.chat.id , "text" : err},function(nodifiedPromise){});
						return
					}
					if(user === null)
					{
						User.create({"id": message.from.id}, function(err){
							console.log("error at /register, User.findOne, User.create");
							console.log(err);
							bot.sendMessage({"chat_id" : message.chat.id , "text" : err},function(nodifiedPromise){});
							return
						});
						console.log('added new user');
						bot.sendMessage({"chat_id" : message.chat.id , "text" : "User " + message.from.username + " is registered"},function(nodifiedPromise){});
					} else {
						bot.sendMessage({"chat_id" : message.chat.id , "text" : "User " + message.from.username + " was already registered"},function(nodifiedPromise){});
					}
				};
				userRegisterCallback.message = message;
				User.findOne({"id": message.from.id}, userRegisterCallback);
			}
			else if (splitStr[0] === "/help")
			{
				bot.sendMessage({"chat_id" : message.chat.id , "text" : "/register - register to start using the bot and save your custom rolls | usage: \"/register\"\n/qroll - quick roll without saving a custom roll | usage: \"/qroll 1d4+1\"\n/save - save a custom roll | usage \"/save magicmissile 1d4+1\"\n/roll - roll a previously saved custom roll | usage: \"/roll magicmissile\""});
			}
			else if (splitStr[0] === "/show")
			{
				var userCallback = function(err,user)
				{
					if(err)
					{
						console.log(err);
						bot.sendMessage({"chat_id" : message.chat.id , "text" : err.toString()},function(nodifiedPromise){});
						return
					}
					if(user === null)
					{
						bot.sendMessage({"chat_id" : message.chat.id , "text" : "Please register first by typing \"/register\" (without the quotes)"});
					} else
					{
					//found user, now display rolls
						var rollCallback = function(err,rolls)
						{
							if(err)
							{
								console.log(err);
								bot.sendMessage({"chat_id" : message.chat.id , "text" : err.toString()},function(nodifiedPromise){});
								return
							}
							if(rolls === null)
							{
								bot.sendMessage({"chat_id" : message.chat.id , "reply_to_message_id" : message.message_id ,"text" : "No saved rolls found. Please save a roll first with \"/save <roll name> <integer>d<integer>{+,-}<integer>\", for example: \"/save magicmissile 1d4+1\""},function(nodifiedPromise){});
							}
							else
							{
								console.log('found rolls');
								var msgText = 'Saved rolls for ' + message.from.username + '\n';
								rolls.forEach(function(val,ind,arr){
									var modifierSign = '+';
									if(val.modifier < 0) modifierSign = '';
									msgText += val.name + " | " + val.times + "d" + val.dice +  modifierSign + val.modifier + '\n';
								});
								bot.sendMessage({"chat_id" : message.chat.id , "reply_to_message_id" : message.message_id ,"text" : msgText },function(nodifiedPromise){});
							}
						}
						rollCallback.message = message;
						Roll.find({"id": message.from.id},rollCallback);
					}
				}
				userCallback.message = message;
				User.findOne({"id": message.from.id}, userCallback);
			}
		}
		else if (splitStr.length === 2)
		{
			if(splitStr[0] === "/roll")
			{
				var key = splitStr[1];
				var userCallback = function(err,user){
					if(err)
					{
						console.log(err);
						bot.sendMessage({"chat_id" : message.chat.id , "text" : err.toString()},function(nodifiedPromise){});
						return
					}
					if(user === null)
					{
						bot.sendMessage({"chat_id" : message.chat.id , "text" : "Please register first by typing \"/register\" (without the quotes)"});
					} else
					{
						//found user, now find roll if exists
						var rollCallback = function(err,roll){
							if(err)
							{
								console.log(err);
								bot.sendMessage({"chat_id" : message.chat.id , "text" : err.toString()},function(nodifiedPromise){});
								return
							}
							if(roll === null)
							{
								bot.sendMessage({"chat_id" : message.chat.id , "reply_to_message_id" : message.message_id ,"text" : "Unsaved custom roll. Please save first with \"/save <roll name> <integer>d<integer>{+,-}<integer>\", for example: \"/save magicmissile 1d4+1\""},function(nodifiedPromise){});
							} else
							{
								var newRoll = {};
								newRoll.times = roll.times;
								newRoll.dice = roll.dice;
								newRoll.modifier = roll.modifier;
								result = calculateRoll(newRoll);
								bot.sendMessage({"chat_id" : message.chat.id , "reply_to_message_id" : message.message_id ,"text" : message.from.username + " | " + key + " | " + result },function(nodifiedPromise){});
							}

						}
						rollCallback.message = message;
						rollCallback.key = key;
						Roll.findOne({"id": message.from.id , "name" : key},rollCallback);
				}
			};
			userCallback.message = message;
			userCallback.key = key;
			User.findOne({"id": message.from.id}, userCallback);
			}
			else if(splitStr[0] === "/qroll")
			{
				var roll = parseRollString(splitStr[1]);
				if(roll === false){
					bot.sendMessage({"chat_id" : message.chat.id , "reply_to_message_id" : message.message_id ,"text" : "Invalid roll format or unsaved custom roll. The expected format is \"/qroll <integer>d<integer>{+,-}<integer>\", for example: \"/qroll 2d12+4\""},function(nodifiedPromise){});
					return
				}
				var result = calculateRoll(roll);
				bot.sendMessage({"chat_id" : message.chat.id , "reply_to_message_id" : message.message_id ,"text" : message.from.username + " | " + splitStr[1] + " | " + result },function(nodifiedPromise){});
			}
			// else
			// {
			// 	bot.sendMessage({"chat_id" : message.chat.id , "text" : "Unknown request. Try /help for options"});
			// }
		}
		else if (splitStr.length === 3)
		{
			if(splitStr[0] === "/save")
			{
				var key = splitStr[1];
				var roll = parseRollString(splitStr[2]);

				if(roll === false)
				{
					bot.sendMessage({"chat_id" : message.chat.id , "reply_to_message_id" : message.message_id ,"text" : "Invalid save format. The expected format is \"/save <roll name> <integer>d<integer>{+,-}<integer>\", for example: \"/save magicmissile 1d4+1\""},function(nodifiedPromise){});
					return
				}

				var saveCallback = function(err,user){
					// var User = db.model('User');
					if(err)
					{
						console.log(err);
						bot.sendMessage({"chat_id" : message.chat.id , "text" : "Unknown error" },function(nodifiedPromise){});
						return
					}
					if(user === null)
					{
						bot.sendMessage({"chat_id" : message.chat.id , "text" : "Please register first by typing \"/register\" (without the quotes)"});
					}
					else
					{
						if(roll === false)
						{
							bot.sendMessage({"chat_id" : message.chat.id , "reply_to_message_id" : message.message_id ,"text" : "Invalid roll format. The expected format is \"<integer>d<integer>{+,-}<integer>\", for example: \"2d12+4\""},function(nodifiedPromise){});
						}
						else
						{
							// user = user.toObject();
							// console.log(typeof(user.rolls));
							// console.log('user before adding roll');
							// console.log(user);
							// user.rolls[key.toString()] = roll;
							// console.log('user after adding roll');
							// console.log(user);

							// var rollArray = new Array();
							// rollArray[key] = roll;
							// console.log(rollArray);

							Roll.update({"id": user.id, "name": key}, {$set: {"dice": roll.dice, "times": roll.times, "modifier": roll.modifier}}, {"upsert": true, "new": true}, function(err,result){
								console.log(result);
								console.log('recorded roll');
								bot.sendMessage({"chat_id" : message.chat.id , "reply_to_message_id" : message.message_id ,"text" : message.from.username + " | " + key + " | saved"},function(nodifiedPromise){});
							});
						}
					}
				};
				saveCallback.message = message;
				saveCallback.roll = roll;
				saveCallback.key = key;
				// saveCallback.rollString = splitStr[2];
				User.findOne({"id": message.from.id}, saveCallback);
			}
			else if(splitStr[0] === "/roll")
			{
				console.log('rolling n times');
				var key = splitStr[1];
				var nTimes = parseInt(splitStr[0]);
				if( nTimes > 0)
				{
					console.log('rolling ' + key + ' ' + nTimes);
					if(nTimes > 100)
					{
						bot.sendMessage({"chat_id" : message.chat.id , "text" : "I can repeat the roll to a maximum of 100 times at a time. Please try a smaller number."},function(nodifiedPromise){});
						return
					}
					var key = splitStr[1];
					var userCallback = function(err,user){
						if(err)
						{
							console.log(err);
							bot.sendMessage({"chat_id" : message.chat.id , "text" : err.toString()},function(nodifiedPromise){});
							return
						}
						if(user === null)
						{
							bot.sendMessage({"chat_id" : message.chat.id , "text" : "Please register first by typing \"/register\" (without the quotes)"});
						} else
						{
							//found user, now find roll if exists
							var rollCallback = function(err,roll){
								if(err)
								{
									console.log(err);
									bot.sendMessage({"chat_id" : message.chat.id , "text" : err.toString()},function(nodifiedPromise){});
									return
								}
								if(roll === null)
								{
									bot.sendMessage({"chat_id" : message.chat.id , "reply_to_message_id" : message.message_id ,"text" : "Unsaved custom roll. Please save first with \"/save <roll name> <integer>d<integer>{+,-}<integer>\", for example: \"/save magicmissile 1d4+1\""},function(nodifiedPromise){});
								} else
								{
									var newRoll = {};
									newRoll.times = roll.times;
									newRoll.dice = roll.dice;
									newRoll.modifier = roll.modifier;
									var msgText = 'Rolling ' + key + ' ' + nTimes + ' for ' + message.from.username + '\n';
									var sum = 0;
									for (var i = 0; i < nTimes; i++) {
										var rollResult = calculateRoll(newRoll);
										msgText += rollResult + " | ";
										sum += rollResult;
									};
									msgText += '\n' + 'Sum of rolls: ' + sum;
									bot.sendMessage({"chat_id" : message.chat.id , "reply_to_message_id" : message.message_id ,"text" : msgText},function(nodifiedPromise){});
								}
							};
							rollCallback.message = message;
							rollCallback.key = key;
							Roll.findOne({"id": message.from.id , "name" : key},rollCallback);
						}
					};
					userCallback.message = message;
					userCallback.key = key;
					User.findOne({"id": message.from.id}, userCallback);
				}
				else
				{
					//TODO: wrong roll ntimes syntax
				}

			}
			// else
			// {
			// 	bot.sendMessage({"chat_id" : message.chat.id , "text" : "Unknown request. Try /help for options"});
			// }
		}
	}
}).start();<|endoftext|>


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

var setHelper = {
  concat: (a, b) => new Set(_.concat(Array.from(a), Array.from(b))),
  difference: (a, b) => new Set(_.difference(Array.from(a), Array.from(b))),
  keys: (object) => new Set(_.keys(object)),
  map: (set, callback) => new Set(Array.from(set).map(callback))
}

class ValidationError extends Error {
  constructor (optionErrors) {
    super()
    this.name = 'ValidationError'
    this.optionErrors = optionErrors
  }

  mapOptionErrors (callback) {
    return Array.from(setHelper.map(this.optionErrors, callback))
  }

  toJSON () {
    return {
      errors: this.mapOptionErrors((e) => e.toJSON())
    }
  }

  toText () {
    return this.mapOptionErrors((e) => e.toText()).join('\n')
  }
}

class OptionError extends Error {
  constructor (option) {
    super()
    this.name = 'OptionError'
    this.option = option
  }

  toJSON () {
    return {
      name: this.name,
      option: this.option
    }
  }
}

class InvalidOptionError extends OptionError {
  constructor (option) {
    super(option)
    this.name = 'InvalidOptionError'
  }

  toText () {
    return `Error: Invalid option "${this.option}"`
  }
}

class MissingOptionError extends OptionError {
  constructor (option) {
    super(option)
    this.name = 'MissingOptionError'
  }

  toText () {
    return `Error: Missing required option "${this.option}"`
  }
}

class Command {
  constructor (core, options) {
    this.core = core
    this.options = options
    this.requiredOptionNames = setHelper.keys(_.pickBy(this.options, 'required'))
    this.optionNames = setHelper.keys(this.options)
  }

  static createErrors (OptionErrorClass, optionNames) {
    return new Set(Array.from(optionNames).map((optionName) => new OptionErrorClass(optionName)))
  }

  run (options) {
    var optionErrors = this.validate(setHelper.keys(options))
    if (optionErrors.size) throw new ValidationError(optionErrors)

    return String(this.core(_.mapValues(options, String)))
  }

  validate (optionNames) {
    if (!this.options) return new Set()

    var missingOptions = setHelper.difference(this.requiredOptionNames, optionNames)
    var invalidOptions = setHelper.difference(optionNames, this.optionNames)

    return setHelper.concat(
      Command.createErrors(MissingOptionError, missingOptions),
      Command.createErrors(InvalidOptionError, invalidOptions)
    )
  }
}

class Runner {
  constructor (commandOrCore, options) {
    if (commandOrCore instanceof Command) {
      this.command = commandOrCore
    } else {
      this.command = new Command(commandOrCore, options)
    }
  }
}

class API extends Runner {
  constructor (command) {
    super(command)

    this.server = http.createServer((req, res) => {
      try {
        var body = `${this.command.run(API.options(req))}\n`
        res.setHeader('content-type', 'text/plain')
        res.writeHead(200)
      } catch (e) {
        res.setHeader('content-type', 'application/json')

        if (e instanceof ValidationError) {
          body = JSON.stringify(e.toJSON())
          res.writeHead(403)
        } else {
          body = null
          res.writeHead(500)
        }
      } finally {
        res.end(body)
      }
    })
  }

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

  static options (req) {
    var query = url.parse(req.url, true).query

    // Force the result to extend Object.prototype for testing
    return Object.assign({}, query)
  }

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

class CLI extends Runner {
  static formatOptions (options) {
    return _.chain(options)
      .map((option, name) => `  --${_.padEnd(name, 19)}${option.description}`)
      .join('\n')
      .value()
  }

  help () {
    var programName = path.basename(process.argv[1], '.js')
    var helpOption = { help: { description: 'output usage information' } }
    var options = this.command.options
    var required = _.pickBy(options, (option) => option.required)
    var optional = _.pickBy(options, (option) => !option.required)
    optional = _.extend(helpOption, optional)

    return [
      `Usage: ${programName} <required> [optional]`,
      'Required:',
      CLI.formatOptions(required),
      'Optional:',
      CLI.formatOptions(optional)
    ].join('\n\n')
  }

  static options () {
    var args = minimist(process.argv.slice(2))
    return _.omit(args, '_')
  }

  run () {
    var options = CLI.options()
    try {
      console.log(options.help ? this.help() : this.command.run(options))
    } catch (e) {
      if (e instanceof ValidationError) {
        console.error(e.toText())
        console.log()
        console.log(this.help())
      } else {
        throw e
      }
    }
  }
}

module.exports = { setHelper, OptionError, InvalidOptionError, MissingOptionError, ValidationError, Command, Runner, API, CLI }
<commit_msg>Use ES6 method syntax for setHelper<commit_after>'use strict'
var _ = require('lodash')
var http = require('http')
var minimist = require('minimist')
var path = require('path')
var url = require('url')

var setHelper = {
  concat (a, b) {
    return new Set(_.concat(Array.from(a), Array.from(b)))
  },

  difference (a, b) {
    return new Set(_.difference(Array.from(a), Array.from(b)))
  },

  keys (object) {
    return new Set(_.keys(object))
  },

  map (set, callback) {
    return new Set(Array.from(set).map(callback))
  }
}

class ValidationError extends Error {
  constructor (optionErrors) {
    super()
    this.name = 'ValidationError'
    this.optionErrors = optionErrors
  }

  mapOptionErrors (callback) {
    return Array.from(setHelper.map(this.optionErrors, callback))
  }

  toJSON () {
    return {
      errors: this.mapOptionErrors((e) => e.toJSON())
    }
  }

  toText () {
    return this.mapOptionErrors((e) => e.toText()).join('\n')
  }
}

class OptionError extends Error {
  constructor (option) {
    super()
    this.name = 'OptionError'
    this.option = option
  }

  toJSON () {
    return {
      name: this.name,
      option: this.option
    }
  }
}

class InvalidOptionError extends OptionError {
  constructor (option) {
    super(option)
    this.name = 'InvalidOptionError'
  }

  toText () {
    return `Error: Invalid option "${this.option}"`
  }
}

class MissingOptionError extends OptionError {
  constructor (option) {
    super(option)
    this.name = 'MissingOptionError'
  }

  toText () {
    return `Error: Missing required option "${this.option}"`
  }
}

class Command {
  constructor (core, options) {
    this.core = core
    this.options = options
    this.requiredOptionNames = setHelper.keys(_.pickBy(this.options, 'required'))
    this.optionNames = setHelper.keys(this.options)
  }

  static createErrors (OptionErrorClass, optionNames) {
    return new Set(Array.from(optionNames).map((optionName) => new OptionErrorClass(optionName)))
  }

  run (options) {
    var optionErrors = this.validate(setHelper.keys(options))
    if (optionErrors.size) throw new ValidationError(optionErrors)

    return String(this.core(_.mapValues(options, String)))
  }

  validate (optionNames) {
    if (!this.options) return new Set()

    var missingOptions = setHelper.difference(this.requiredOptionNames, optionNames)
    var invalidOptions = setHelper.difference(optionNames, this.optionNames)

    return setHelper.concat(
      Command.createErrors(MissingOptionError, missingOptions),
      Command.createErrors(InvalidOptionError, invalidOptions)
    )
  }
}

class Runner {
  constructor (commandOrCore, options) {
    if (commandOrCore instanceof Command) {
      this.command = commandOrCore
    } else {
      this.command = new Command(commandOrCore, options)
    }
  }
}

class API extends Runner {
  constructor (command) {
    super(command)

    this.server = http.createServer((req, res) => {
      try {
        var body = `${this.command.run(API.options(req))}\n`
        res.setHeader('content-type', 'text/plain')
        res.writeHead(200)
      } catch (e) {
        res.setHeader('content-type', 'application/json')

        if (e instanceof ValidationError) {
          body = JSON.stringify(e.toJSON())
          res.writeHead(403)
        } else {
          body = null
          res.writeHead(500)
        }
      } finally {
        res.end(body)
      }
    })
  }

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

  static options (req) {
    var query = url.parse(req.url, true).query

    // Force the result to extend Object.prototype for testing
    return Object.assign({}, query)
  }

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

class CLI extends Runner {
  static formatOptions (options) {
    return _.chain(options)
      .map((option, name) => `  --${_.padEnd(name, 19)}${option.description}`)
      .join('\n')
      .value()
  }

  help () {
    var programName = path.basename(process.argv[1], '.js')
    var helpOption = { help: { description: 'output usage information' } }
    var options = this.command.options
    var required = _.pickBy(options, (option) => option.required)
    var optional = _.pickBy(options, (option) => !option.required)
    optional = _.extend(helpOption, optional)

    return [
      `Usage: ${programName} <required> [optional]`,
      'Required:',
      CLI.formatOptions(required),
      'Optional:',
      CLI.formatOptions(optional)
    ].join('\n\n')
  }

  static options () {
    var args = minimist(process.argv.slice(2))
    return _.omit(args, '_')
  }

  run () {
    var options = CLI.options()
    try {
      console.log(options.help ? this.help() : this.command.run(options))
    } catch (e) {
      if (e instanceof ValidationError) {
        console.error(e.toText())
        console.log()
        console.log(this.help())
      } else {
        throw e
      }
    }
  }
}

module.exports = { setHelper, OptionError, InvalidOptionError, MissingOptionError, ValidationError, Command, Runner, API, CLI }
<|endoftext|>


<commit_before>var cssLintTree = require('broccoli-csslint');

'use strict';

module.exports = {
  name: 'ember-cli-csslint'
};
<commit_msg>Register csslinting to the app registry<commit_after>var cssLintTree = require('broccoli-csslint');

'use strict';

module.exports = {
  name: 'ember-cli-csslint',

  included: function(app) {
    this._super.included(app);

    app.registry.add('styles', {
      name: 'ember-cli-csslint',
      ext: 'css',
      toTree: function(tree) {
        return cssLintTree(tree, {});
      }
    });
  }
};
<|endoftext|>


<commit_before>//
'use strict';
var Canvas = require('drawille');
var _ = require('lodash');
require('colors');

var width = process.stdout.getWindowSize()[0] * 2;
var height = process.stdout.getWindowSize()[1] * 4;
var canvas = new Canvas(width, height);

Number.prototype.mod = function(n) {
    return ((this%n)+n)%n;
};

// re-used from baudio
function mergeArgs (opts, args) {
    Object.keys(opts || {}).forEach(function (key) {
        args[key] = opts[key];
    });

    return Object.keys(args).reduce(function (acc, key) {
        var dash = key.length === 1 ? '-' : '--';
        return acc.concat(dash + key, args[key]);
    }, []);
}

var oscillate = module.exports =  function(b, options) {

    options  = _.defaults(options || {}, {
        framesPerSecond: 20,
        windowSize: 1000
    });

    //
    // pipe from baudio -> boscillate -> sox
    //
    //
    var Transform = require('stream').Transform;
    var ts = new Transform();
    var v = 0;
    var windowSize = options.windowSize;
    var points = Array.apply(null, new Array(windowSize)).map(Number.prototype.valueOf,0);
    ts._transform = function (chunk, encoding, done) {
        for (var i = 0; i < chunk.length; i += 2) {
            v++;
            var n = chunk.readInt16LE(i);
            points[v % windowSize] = n;
        }
        this.push(chunk);
        done();
    };

    function draw() {
        canvas.clear();
        var offset = v % windowSize;
        for(var i=0; i<points.length; i++) {
            var point = points[i];
            var index = (i - offset).mod(windowSize);
            canvas.set(width - width * (index / windowSize), height / 2 + point / 1000);
        }
        console.log(canvas.frame().green);
    }

    b.play = function (opts) {
        var ps = this._spawn('play', mergeArgs(opts, {
            'c': 1,
            'r': this.rate,
            't': 's16'
        }).concat('-', '-q'));
        this.pipe(ts).pipe(ps.stdin);
        // draw in the interval to avoid mucking
        // up the pipes
        setInterval(draw, 1 / options.framesPerSecond * 1000);
        return ps;
    };

    return b;
};

<commit_msg>move req statement to the top<commit_after>//
'use strict';
var Canvas = require('drawille');
var Transform = require('stream').Transform;
var _ = require('lodash');
require('colors');

var width = process.stdout.getWindowSize()[0] * 2;
var height = process.stdout.getWindowSize()[1] * 4;
var canvas = new Canvas(width, height);

Number.prototype.mod = function(n) {
    return ((this%n)+n)%n;
};

// re-used from baudio
function mergeArgs (opts, args) {
    Object.keys(opts || {}).forEach(function (key) {
        args[key] = opts[key];
    });

    return Object.keys(args).reduce(function (acc, key) {
        var dash = key.length === 1 ? '-' : '--';
        return acc.concat(dash + key, args[key]);
    }, []);
}

var oscillate = module.exports =  function(b, options) {

    options  = _.defaults(options || {}, {
        framesPerSecond: 20,
        windowSize: 1000
    });

    //
    // pipe from baudio -> boscillate -> sox
    //
    //

    var ts = new Transform();
    var v = 0;
    var windowSize = options.windowSize;
    var points = Array.apply(null, new Array(windowSize)).map(Number.prototype.valueOf,0);
    ts._transform = function (chunk, encoding, done) {
        for (var i = 0; i < chunk.length; i += 2) {
            v++;
            var n = chunk.readInt16LE(i);
            points[v % windowSize] = n;
        }
        this.push(chunk);
        done();
    };

    function draw() {
        canvas.clear();
        var offset = v % windowSize;
        for(var i=0; i<points.length; i++) {
            var point = points[i];
            var index = (i - offset).mod(windowSize);
            canvas.set(width - width * (index / windowSize), height / 2 + point / 1000);
        }
        console.log(canvas.frame().green);
    }

    b.play = function (opts) {
        var ps = this._spawn('play', mergeArgs(opts, {
            'c': 1,
            'r': this.rate,
            't': 's16'
        }).concat('-', '-q'));
        this.pipe(ts).pipe(ps.stdin);
        // draw in the interval to avoid mucking
        // up the pipes
        setInterval(draw, 1 / options.framesPerSecond * 1000);
        return ps;
    };

    return b;
};

<|endoftext|>


<commit_before>'use strict';

var argv = require('minimist')(process.argv.slice(2), {
  alias: {
    b: ['database', 'db'],
    s: ['db-size', 'size'],
    d: ['duration'],
    o: ['options'],
    l: ['db-list', 'list']
  },
  default: {
    s: 5000,
    d: 5
  }
});

if (argv.list) {
  var path    = require('path');
  var fs      = require('fs');
  var plugDir = path.join(__dirname, 'plug');

  fs.readdir(plugDir, function (err, items) {
    if (err) { throw err; }

    (function list() {
      var item = items.pop();
      if (!item) { return; }

      fs.stat(path.join(plugDir, item), function (err, stat) {
        if (err) { console.error(err); }
        if (stat && stat.isDirectory()) { console.log(item); }
        list();
      });
    })();
  });
  return;
}

if (!argv.db) {
  console.error('No database provided');
  process.exit(1);
}

var faker = require('faker');
var db    = require('./plug/' + argv.db + '/index.js');

var id = 0;

function generate(callback) {
  var inserted  = 0;
  var errors    = 0;

  (function insert() {
    if (id >= argv.size) {
      return callback(null, {
        inserted: inserted,
        errors: errors
      });
    }

    db.insert('identifier' + id++, {
      firstname: faker.name.firstName(),
      lastname: faker.name.lastName(),
      zipcode: faker.address.zipCode(),
      city: faker.address.city(),
      country: faker.address.country()
    }, function (err) {
      if (err) { errors++; }
      else     { inserted++; }

      setImmediate(insert);
    });
  })();
};

function bench(callback) {
  var stop        = false;
  var nbQueries   = 0;
  var nbErrors    = 0;
  var maxTime     = 0;
  var minTime     = Infinity;
  var averageTime = 0;
  var maxMemory   = 0;
  var minMemory   = Infinity;

  (function query() {
    var id = 'identifier' + (Math.floor(Math.random() * argv.size));
    var startTime = process.hrtime();

    var memoryUsage = process.memoryUsage().rss;
    minMemory = Math.min(minMemory, memoryUsage);
    maxMemory = Math.max(maxMemory, memoryUsage);

    db.get(id, function (err, entry) {
      var elapsed = process.hrtime(startTime);
      elapsed = elapsed[0] * 1e9 + elapsed[1];

      minTime = Math.min(minTime, elapsed);
      maxTime = Math.max(maxTime, elapsed);
      averageTime = averageTime ? (averageTime + elapsed) / 2 : elapsed;

      if (err) { nbErrors++; }
      else     { nbQueries++ }

      if (stop) {
        callback(null, {
          queries: nbQueries,
          errors: nbErrors,
          time: {
            min: Math.round(minTime / 1e3) / 1e3,
            max: Math.round(maxTime / 1e3) / 1e3,
            average: Math.round(averageTime / 1e3) / 1e3
          },
          memory: {
            min: Math.round(minMemory / 1024 / 1024 * 100) / 100,
            max: Math.round(maxMemory / 1024 / 1024 * 100) / 100
          }
        });
      } else {
        setImmediate(query);
      }
    });
  })();

  setTimeout(function() { stop = true; }, argv.duration * 1000);
};

console.log('[ %s ]', db.name);
console.log('Initializing database...');
db.init(argv.options ? JSON.parse(argv.options) : {}, function (err) {
  if (err) { throw err; }

  var startTime = process.hrtime();
  console.log('Generating dataset...');

  generate(function (err, res) {

    var elapsed = process.hrtime(startTime);
    elapsed = (elapsed[0] * 1e9 + elapsed[1]) / 1e6;

    var genMin = Math.floor(elapsed / 60000).toString();
    var genSec = Math.floor(elapsed / 1000 % 60000).toString();
    if (genMin.length == 1) { genMin = '0' + genMin; }
    if (genSec.length == 1) { genSec = '0' + genSec; }

    startTime = process.hrtime();
    console.log('Starting bench');

    bench(function (err, result) {

      elapsed = process.hrtime(startTime);
      elapsed = (elapsed[0] * 1e9 + elapsed[1]) / 1e6;
      var benchMin = Math.floor(elapsed / 60000).toString();
      var benchSec = Math.floor(elapsed / 1000 % 60000).toString();
      if (benchMin.length == 1) { benchMin = '0' + benchMin; }
      if (benchSec.length == 1) { benchSec = '0' + benchSec; }

      console.log('Bench finished in %d minutes and %d seconds\n', benchMin, benchSec);

      var queriesPerSecond = Math.round(result.queries / argv.duration);

      console.log('Dataset');
      console.log('  Inserted: \t%d', res.inserted);
      console.log('  Failed: \t%d', res.errors);
      console.log('  Time: \t%s:%s', genMin, genSec);

      console.log('Queries');
      console.log('  Successful: \t%d (%d per second)', result.queries, queriesPerSecond);
      console.log('  Failed: \t%d', result.errors);

      console.log('Queries time')
      console.log('  Minimum: \t%d ms', result.time.min);
      console.log('  Maximum: \t%d ms', result.time.max);
      console.log('  Average: \t%d ms', result.time.average);

      console.log('Memory usage')
      console.log('  Minimum: \t%d MiB', result.memory.min);
      console.log('  Maximum: \t%d MiB', result.memory.max);
    });
  });
});<commit_msg>add not found and fix times<commit_after>'use strict';

var argv = require('minimist')(process.argv.slice(2), {
  alias: {
    b: ['database', 'db'],
    s: ['db-size', 'size'],
    d: ['duration'],
    o: ['options'],
    l: ['db-list', 'list']
  },
  default: {
    s: 5000,
    d: 5
  }
});

if (argv.list) {
  var path    = require('path');
  var fs      = require('fs');
  var plugDir = path.join(__dirname, 'plug');

  fs.readdir(plugDir, function (err, items) {
    if (err) { throw err; }

    (function list() {
      var item = items.pop();
      if (!item) { return; }

      fs.stat(path.join(plugDir, item), function (err, stat) {
        if (err) { console.error(err); }
        if (stat && stat.isDirectory()) { console.log(item); }
        list();
      });
    })();
  });
  return;
}

if (!argv.db) {
  console.error('No database provided');
  process.exit(1);
}

var faker = require('faker');
var db    = require('./plug/' + argv.db + '/index.js');

var id = 0;

function generate(callback) {
  var inserted  = 0;
  var errors    = 0;

  (function insert() {
    if (id >= argv.size) {
      return callback(null, {
        inserted: inserted,
        errors: errors
      });
    }

    db.insert('identifier' + id++, {
      firstname: faker.name.firstName(),
      lastname: faker.name.lastName(),
      zipcode: faker.address.zipCode(),
      city: faker.address.city(),
      country: faker.address.country()
    }, function (err) {
      if (err) { errors++; }
      else     { inserted++; }

      setImmediate(insert);
    });
  })();
};

function bench(callback) {
  var stop        = false;
  var nbQueries   = 0;
  var nbNotFound  = 0;
  var nbErrors    = 0;
  var maxTime     = 0;
  var minTime     = Infinity;
  var averageTime = 0;
  var maxMemory   = 0;
  var minMemory   = Infinity;

  (function query() {
    var id = 'identifier' + (Math.floor(Math.random() * argv.size));
    var startTime = process.hrtime();

    var memoryUsage = process.memoryUsage().rss;
    minMemory = Math.min(minMemory, memoryUsage);
    maxMemory = Math.max(maxMemory, memoryUsage);

    db.get(id, function (err, entry) {
      var elapsed = process.hrtime(startTime);
      elapsed = elapsed[0] * 1e9 + elapsed[1];

      minTime = Math.min(minTime, elapsed);
      maxTime = Math.max(maxTime, elapsed);
      averageTime = averageTime ? (averageTime + elapsed) / 2 : elapsed;

      if (err) {
        nbErrors++; }
      else {
        nbQueries++
        if (!entry) { nbNotFound++; }
      }

      if (stop) {
        callback(null, {
          queries: nbQueries,
          errors: nbErrors,
          notFound: nbNotFound,
          time: {
            min: Math.round(minTime / 1e3) / 1e3,
            max: Math.round(maxTime / 1e3) / 1e3,
            average: Math.round(averageTime / 1e3) / 1e3
          },
          memory: {
            min: Math.round(minMemory / 1024 / 1024 * 100) / 100,
            max: Math.round(maxMemory / 1024 / 1024 * 100) / 100
          }
        });
      } else {
        setImmediate(query);
      }
    });
  })();

  setTimeout(function() { stop = true; }, argv.duration * 1000);
};

console.log('[ %s ]', db.name);
console.log('Initializing database...');
db.init(argv.options ? JSON.parse(argv.options) : {}, function (err) {
  if (err) { throw err; }

  var startTime = process.hrtime();
  console.log('Generating dataset...');

  generate(function (err, res) {

    var elapsed = process.hrtime(startTime);
    elapsed = (elapsed[0] * 1e9 + elapsed[1]) / 1e6;

    var genMin = Math.floor(elapsed / 60000).toString();
    var genSec = Math.floor(elapsed % 60000 / 1000).toString();
    if (genMin.length == 1) { genMin = '0' + genMin; }
    if (genSec.length == 1) { genSec = '0' + genSec; }

    startTime = process.hrtime();
    console.log('Starting bench');

    bench(function (err, result) {

      elapsed = process.hrtime(startTime);
      elapsed = (elapsed[0] * 1e9 + elapsed[1]) / 1e6;
      var benchMin = Math.floor(elapsed / 60000).toString();
      var benchSec = Math.floor(elapsed % 60000 / 1000).toString();
      if (benchMin.length == 1) { benchMin = '0' + benchMin; }
      if (benchSec.length == 1) { benchSec = '0' + benchSec; }

      console.log('Bench finished in %d minutes and %d seconds\n', benchMin, benchSec);

      var queriesPerSecond = Math.round(result.queries / argv.duration);

      console.log('Dataset');
      console.log('  Inserted: \t%d', res.inserted);
      console.log('  Failed: \t%d', res.errors);
      console.log('  Time: \t%s:%s', genMin, genSec);

      console.log('Queries');
      console.log('  Performed: \t%d (%d per second)', result.queries, queriesPerSecond);
      console.log('  Not found: \t%d', result.notFound);
      console.log('  Failed: \t%d', result.errors);

      console.log('Queries time')
      console.log('  Minimum: \t%d ms', result.time.min);
      console.log('  Maximum: \t%d ms', result.time.max);
      console.log('  Average: \t%d ms', result.time.average);

      console.log('Memory usage')
      console.log('  Minimum: \t%d MiB', result.memory.min);
      console.log('  Maximum: \t%d MiB', result.memory.max);
    });
  });
});<|endoftext|>


<commit_before>
var Query   = require("./query")
  , Utils   = require("../../utils")

module.exports = (function() {
  var ConnectorManager = function(sequelize, config) {
    var pgModule = config.dialectModulePath || 'pg'

    this.sequelize = sequelize
    this.client         = null
    this.config         = config || {}
    this.config.port    = this.config.port || 5432
    this.pooling        = (!!this.config.pool && (this.config.pool.maxConnections > 0))
    this.pg             = this.config.native ? require(pgModule).native : require(pgModule)
    this.poolIdentifier = null
    // Better support for BigInts
    // https://github.com/brianc/node-postgres/issues/166#issuecomment-9514935
    this.pg.types.setTypeParser(20, String);

    // set pooling parameters if specified
    if (this.pooling) {
      this.pg.defaults.poolSize           = this.config.pool.maxConnections || 10
      this.pg.defaults.poolIdleTimeout    = this.config.pool.maxIdleTime    || 30000
      this.pg.defaults.reapIntervalMillis = this.config.pool.reapInterval   || 1000
    }

    this.disconnectTimeoutId = null
    this.pendingQueries = 0
    this.clientDrained = true
    this.maxConcurrentQueries = (this.config.maxConcurrentQueries || 50)

    this.onProcessExit = function () {
      this.disconnect()
    }.bind(this);

    process.on('exit', this.onProcessExit)
  }
  Utils._.extend(ConnectorManager.prototype, require("../connector-manager").prototype)

  ConnectorManager.prototype.endQuery = function() {
    var self = this

    self.pendingQueries--

    if (!self.pooling && self.pendingQueries === 0) {
      setTimeout(function() {
        self.pendingQueries === 0 && self.disconnect.call(self)
      }, 100)
    }
  }

  ConnectorManager.prototype.query = function(sql, callee, options) {
    var self = this

    self.pendingQueries++
    self.clientDrained = false

    return new Utils.CustomEventEmitter(function(emitter) {
      self.connect()
      .on('error', function(err) {
        emitter.emit('error', err)
      })
      .on('success', function(done) {
        var query = new Query(self.client, self.sequelize, callee, options || {})

        return query.run(sql)
          .complete(function(err) {
            self.endQuery.call(self)
            done && done(err) })
          .proxy(emitter)
      })
    }).run()
  }

  ConnectorManager.prototype.afterTransactionSetup = function(callback) {
    this.setTimezone(this.client, 'UTC', callback)
  }

  ConnectorManager.prototype.connect = function(callback) {
    var self = this
    var emitter = new (require('events').EventEmitter)()

    // in case database is slow to connect, prevent orphaning the client
    // TODO: We really need some sort of queue/flush/drain mechanism
    if (this.isConnecting && !this.pooling && this.client === null) {
      emitter.emit('success', null)
      return emitter
    }

    this.isConnecting = true
    this.isConnected  = false

    var uri = this.sequelize.getQueryInterface().QueryGenerator.databaseConnectionUri(this.config)

    var connectCallback = function(err, client, done) {
      self.isConnecting = false

      if (!!err) {
        // release the pool immediately, very important.
        done && done(err)
        self.client = null

        if (err.code) {
          switch(err.code) {
          case 'ECONNREFUSED':
            emitter.emit('error', new Error("Failed to authenticate for PostgresSQL. Please double check your settings."))
            break
          case 'ENOTFOUND':
          case 'EHOSTUNREACH':
          case 'EINVAL':
            emitter.emit('error', new Error("Failed to find PostgresSQL server. Please double check your settings."))
            break
          default:
            emitter.emit('error', err)
            break
          }
        } else {
          emitter.emit('error', new Error(err.message))
        }
      } else if (client) {
        var timezoneCallback = function() {
          self.isConnected = true
          self.client = client
          emitter.emit('success', done)
        }

        if (self.config.keepDefaultTimezone) {
          Utils.tick(timezoneCallback)
        } else {
          self.setTimezone(client, 'UTC', timezoneCallback)
        }
      } else if (self.config.native) {
        self.setTimezone(self.client, 'UTC', function() {
          self.isConnected = true
          emitter.emit('success', done)
        })
      } else {
        done && done()
        self.client = null
        emitter.emit('success')
      }
    }

    if (this.pooling) {
      // acquire client from pool
      this.pg.connect(uri, connectCallback)
    } else {
      if (!!this.client) {
        connectCallback(null, this.client)
      } else {
        //create one-off client

        var responded = false

        this.client = new this.pg.Client(uri)
        this.client.connect(function(err, client, done) {
          responded = true
          connectCallback(err, client || self.client, done)
        })

        // If we didn't ever hear from the client.connect() callback the connection timedout, node-postgres does not treat this as an error since no active query was ever emitted
        this.client.on('end', function () {
          if (!responded) {
            connectCallback(new Error('Connection timed out'))
          }
        })

        // Closes a client correctly even if we have backed up queries
        // https://github.com/brianc/node-postgres/pull/346
        this.client.on('drain', function() {
          self.clientDrained = true
        })
      }
    }

    return emitter
  }

  ConnectorManager.prototype.setTimezone = function(client, timezone, callback) {
    client.query("SET TIME ZONE '" + (timezone || "UTC") + "'").on('end', callback)
  }

  ConnectorManager.prototype.disconnect = function() {
    if (this.poolIdentifier) {
      this.poolIdentifier.destroyAllNow()
    }

    if (this.client) {
      if (this.clientDrained) {
        this.client.end()
      }
      this.client = null
    }

    this.isConnecting = false
    this.isConnected  = false
  }

  return ConnectorManager
})()
<commit_msg>Remove unused variable from pg connector manager. Closes #1140<commit_after>
var Query   = require("./query")
  , Utils   = require("../../utils")

module.exports = (function() {
  var ConnectorManager = function(sequelize, config) {
    var pgModule = config.dialectModulePath || 'pg'

    this.sequelize = sequelize
    this.client         = null
    this.config         = config || {}
    this.config.port    = this.config.port || 5432
    this.pooling        = (!!this.config.pool && (this.config.pool.maxConnections > 0))
    this.pg             = this.config.native ? require(pgModule).native : require(pgModule)
    // Better support for BigInts
    // https://github.com/brianc/node-postgres/issues/166#issuecomment-9514935
    this.pg.types.setTypeParser(20, String);

    // set pooling parameters if specified
    if (this.pooling) {
      this.pg.defaults.poolSize           = this.config.pool.maxConnections || 10
      this.pg.defaults.poolIdleTimeout    = this.config.pool.maxIdleTime    || 30000
      this.pg.defaults.reapIntervalMillis = this.config.pool.reapInterval   || 1000
    }

    this.disconnectTimeoutId = null
    this.pendingQueries = 0
    this.clientDrained = true
    this.maxConcurrentQueries = (this.config.maxConcurrentQueries || 50)

    this.onProcessExit = function () {
      this.disconnect()
    }.bind(this);

    process.on('exit', this.onProcessExit)
  }
  Utils._.extend(ConnectorManager.prototype, require("../connector-manager").prototype)

  ConnectorManager.prototype.endQuery = function() {
    var self = this

    self.pendingQueries--

    if (!self.pooling && self.pendingQueries === 0) {
      setTimeout(function() {
        self.pendingQueries === 0 && self.disconnect.call(self)
      }, 100)
    }
  }

  ConnectorManager.prototype.query = function(sql, callee, options) {
    var self = this

    self.pendingQueries++
    self.clientDrained = false

    return new Utils.CustomEventEmitter(function(emitter) {
      self.connect()
      .on('error', function(err) {
        emitter.emit('error', err)
      })
      .on('success', function(done) {
        var query = new Query(self.client, self.sequelize, callee, options || {})

        return query.run(sql)
          .complete(function(err) {
            self.endQuery.call(self)
            done && done(err) })
          .proxy(emitter)
      })
    }).run()
  }

  ConnectorManager.prototype.afterTransactionSetup = function(callback) {
    this.setTimezone(this.client, 'UTC', callback)
  }

  ConnectorManager.prototype.connect = function(callback) {
    var self = this
    var emitter = new (require('events').EventEmitter)()

    // in case database is slow to connect, prevent orphaning the client
    // TODO: We really need some sort of queue/flush/drain mechanism
    if (this.isConnecting && !this.pooling && this.client === null) {
      emitter.emit('success', null)
      return emitter
    }

    this.isConnecting = true
    this.isConnected  = false

    var uri = this.sequelize.getQueryInterface().QueryGenerator.databaseConnectionUri(this.config)

    var connectCallback = function(err, client, done) {
      self.isConnecting = false

      if (!!err) {
        // release the pool immediately, very important.
        done && done(err)
        self.client = null

        if (err.code) {
          switch(err.code) {
          case 'ECONNREFUSED':
            emitter.emit('error', new Error("Failed to authenticate for PostgresSQL. Please double check your settings."))
            break
          case 'ENOTFOUND':
          case 'EHOSTUNREACH':
          case 'EINVAL':
            emitter.emit('error', new Error("Failed to find PostgresSQL server. Please double check your settings."))
            break
          default:
            emitter.emit('error', err)
            break
          }
        } else {
          emitter.emit('error', new Error(err.message))
        }
      } else if (client) {
        var timezoneCallback = function() {
          self.isConnected = true
          self.client = client
          emitter.emit('success', done)
        }

        if (self.config.keepDefaultTimezone) {
          Utils.tick(timezoneCallback)
        } else {
          self.setTimezone(client, 'UTC', timezoneCallback)
        }
      } else if (self.config.native) {
        self.setTimezone(self.client, 'UTC', function() {
          self.isConnected = true
          emitter.emit('success', done)
        })
      } else {
        done && done()
        self.client = null
        emitter.emit('success')
      }
    }

    if (this.pooling) {
      // acquire client from pool
      this.pg.connect(uri, connectCallback)
    } else {
      if (!!this.client) {
        connectCallback(null, this.client)
      } else {
        //create one-off client

        var responded = false

        this.client = new this.pg.Client(uri)
        this.client.connect(function(err, client, done) {
          responded = true
          connectCallback(err, client || self.client, done)
        })

        // If we didn't ever hear from the client.connect() callback the connection timedout, node-postgres does not treat this as an error since no active query was ever emitted
        this.client.on('end', function () {
          if (!responded) {
            connectCallback(new Error('Connection timed out'))
          }
        })

        // Closes a client correctly even if we have backed up queries
        // https://github.com/brianc/node-postgres/pull/346
        this.client.on('drain', function() {
          self.clientDrained = true
        })
      }
    }

    return emitter
  }

  ConnectorManager.prototype.setTimezone = function(client, timezone, callback) {
    client.query("SET TIME ZONE '" + (timezone || "UTC") + "'").on('end', callback)
  }

  ConnectorManager.prototype.disconnect = function() {
    if (this.client) {
      if (this.clientDrained) {
        this.client.end()
      }
      this.client = null
    }

    this.isConnecting = false
    this.isConnected  = false
  }

  return ConnectorManager
})()
<|endoftext|>


<commit_before>var Botkit = require('botkit')

var token = process.env.SLACK_TOKEN

var controller = Botkit.slackbot({
  // reconnect to Slack RTM when connection goes bad
  retry: Infinity,
  debug: false
})

// Assume single team mode if we have a SLACK_TOKEN
if (token) {
  console.log('Starting in single-team mode')
  controller.spawn({
    token: token
  }).startRTM(function (err, bot, payload) {
    if (err) {
      throw new Error(err)
    }

    console.log('Connected to Slack RTM')
  })
// Otherwise assume multi-team mode - setup beep boop resourcer connection
} else {
  console.log('Starting in Beep Boop multi-team mode')
  require('beepboop-botkit').start(controller, { debug: true })
}

controller.on('bot_channel_join', function (bot, message) {
  bot.reply(message, "I'm here!")
})

controller.hears('.*', ['mention'], function (bot, message) {
  bot.reply(message, 'You really do care about me. :heart:')
})

controller.hears('help', ['direct_message', 'direct_mention'], function (bot, message) {
  var help = 'I will respond to the following messages: \n' +
      '`bot hi` for a simple message.\n' +
      '`bot attachment` to see a Slack attachment message.\n' +
      '`@<your bot\'s name>` to demonstrate detecting a mention.\n' +
      '`bot help` to see this again.'
  bot.reply(message, help)
})

controller.hears(['attachment'], ['direct_message', 'direct_mention'], function (bot, message) {
  var text = 'Beep Beep Boop is a ridiculously simple hosting platform for your Slackbots.'
  var attachments = [{
    fallback: text,
    pretext: 'We bring bots to life. :sunglasses: :thumbsup:',
    title: 'Host, deploy and share your bot in seconds.',
    image_url: 'https://storage.googleapis.com/beepboophq/_assets/bot-1.22f6fb.png',
    title_link: 'https://beepboophq.com/',
    text: text,
    color: '#7CD197'
  }]

  bot.reply(message, {
    attachments: attachments
  }, function (err, resp) {
    console.log(err, resp)
  })
})

controller.hears(['.*play|game|Hi|Hello|Salut|Bonjour.*'], 'direct_message,direct_mention,mention', function(bot, message) {
  bot.api.reactions.add({
    timestamp: message.ts,
    channel: message.channel,
    name: 'robot_face',
  }, function(err, res) {
    if (err) {
      bot.botkit.log('Failed to add emoji reaction :(', err);
    }
  })

  controller.storage.users.get(message.user, function(err, user) {
    if (user && user.name) {
      bot.reply(message, 'Hey what\'s up ' + user.name + '!! Do you wanna play ?');
    } else {
      bot.reply(message, 'Hey what\'s up. Do you wanna play ?');
    }
    bot.reply(message, {
      attachments:[
        {
          "text": "You'll have to find out the capital city of a random country motherfucker mouhahaha.",
          "fallback": "Oh what a loser you are !!",
          "callback_id": "cc_game",
          "color": "#3AA3E3",
          "attachment_type": "default",
          "actions": [
            {
              "name":"yes",
              "text": "YES",
              "style": "primary",
              "type": "button",
              "value": "yes"
            },
            {
              "name":"no",
              "text": "NO",
              "style": "default",
              "type": "button",
              "value": "no"
            }
          ]
        }
      ]
    })
  })
})

controller.hears('.*', ['direct_message', 'direct_mention'], function (bot, message) {
  bot.reply(message, 'Sorry <@' + message.user + '>, I don\'t understand. \n')
})
<commit_msg>quiz command added<commit_after>var Botkit = require('botkit')

var token = process.env.SLACK_TOKEN

var controller = Botkit.slackbot({
  // reconnect to Slack RTM when connection goes bad
  retry: Infinity,
  debug: false
})

// Assume single team mode if we have a SLACK_TOKEN
if (token) {
  console.log('Starting in single-team mode')
  controller.spawn({
    token: token
  }).startRTM(function (err, bot, payload) {
    if (err) {
      throw new Error(err)
    }

    console.log('Connected to Slack RTM')
  })
// Otherwise assume multi-team mode - setup beep boop resourcer connection
} else {
  console.log('Starting in Beep Boop multi-team mode')
  require('beepboop-botkit').start(controller, { debug: true })
}

controller.on('bot_channel_join', function (bot, message) {
  bot.reply(message, "I'm here!")
})

controller.hears('.*', ['mention'], function (bot, message) {
  bot.reply(message, 'You really do care about me. :heart:')
})

controller.hears('help', ['direct_message', 'direct_mention'], function (bot, message) {
  var help = 'I will respond to the following messages: \n' +
      '`bot hi` for a simple message.\n' +
      '`bot attachment` to see a Slack attachment message.\n' +
      '`@<your bot\'s name>` to demonstrate detecting a mention.\n' +
      '`bot help` to see this again.'
  bot.reply(message, help)
})

controller.hears(['attachment'], ['direct_message', 'direct_mention'], function (bot, message) {
  var text = 'Beep Beep Boop is a ridiculously simple hosting platform for your Slackbots.'
  var attachments = [{
    fallback: text,
    pretext: 'We bring bots to life. :sunglasses: :thumbsup:',
    title: 'Host, deploy and share your bot in seconds.',
    image_url: 'https://storage.googleapis.com/beepboophq/_assets/bot-1.22f6fb.png',
    title_link: 'https://beepboophq.com/',
    text: text,
    color: '#7CD197'
  }]

  bot.reply(message, {
    attachments: attachments
  }, function (err, resp) {
    console.log(err, resp)
  })
})

controller.hears(['/quiz|.*play|game|Hi|Hello|Salut|Bonjour.*'], 'direct_message,direct_mention,mention', function(bot, message) {
  bot.api.reactions.add({
    timestamp: message.ts,
    channel: message.channel,
    name: 'robot_face',
  }, function(err, res) {
    if (err) {
      bot.botkit.log('Failed to add emoji reaction :(', err);
    }
  })

  controller.storage.users.get(message.user, function(err, user) {
    if (user && user.name) {
      bot.reply(message, 'Hey what\'s up ' + user.name + '!! Do you wanna play ?');
    } else {
      bot.reply(message, 'Hey what\'s up. Do you wanna play ?');
    }
    bot.reply(message, {
      attachments:[
        {
          "text": "You'll have to find out the capital city of a random country motherfucker mouhahaha.",
          "fallback": "Oh what a loser you are !!",
          "callback_id": "cc_game",
          "color": "#3AA3E3",
          "attachment_type": "default",
          "actions": [
            {
              "name":"yes",
              "text": "YES",
              "style": "primary",
              "type": "button",
              "value": "yes"
            },
            {
              "name":"no",
              "text": "NO",
              "style": "default",
              "type": "button",
              "value": "no"
            }
          ]
        }
      ]
    })
  })
})

controller.hears('.*', ['direct_message', 'direct_mention'], function (bot, message) {
  bot.reply(message, 'Sorry <@' + message.user + '>, I don\'t understand. \n')
})
<|endoftext|>