<commit_before>var KrakenClient = require('kraken-api');
var nodemailer = require("nodemailer");
var async = require('async');
var fs = require('fs');
var crypto = require('crypto');
var config = require('./config.js');
var errors = require('./errors.js');
var smtpTransport = nodemailer.createTransport("SMTP", config.smtp);
var registry = [];
var registryMap = {};

/**
 * Map of email tokens to confirm the addition or deletion of subscriptions.
 */
var confirmMap = {};
var TOKEN_ADD = 'add';
var TOKEN_REMOVE = 'remove';

exports.TOKEN_ADD = TOKEN_ADD;
exports.TOKEN_REMOVE = TOKEN_REMOVE;

/**
 * Confirms a request to delete or add a subscription.
 * @param token
 * @param callback
 */
exports.confirm = function(token, callback) {
    if (!confirmMap.hasOwnProperty(token)) {
        if (typeof callback == 'function') {
            callback(new Error("Sorry. We could not find this token."));
        }
        return;
    }
    var data = confirmMap[token];
    delete(confirmMap[token]);
    save(function(error) {
        if (error) {
            console.log("Error while removing token: " + error.message);
        }

        if (data.type == TOKEN_ADD) {
            addClient(data.mail, data.key, data.secret, function(error) {
                callback(error, data);
            });
        } else if (data.type == TOKEN_REMOVE) {
            removeClient(data.mail, data.key, function(error) {
                callback(error, data);
            });
        } else {
            callback(new Error("Invalid token data. Please contact support."));
        }
    });
};

/**
 * Initiates the process of adding a subscription.
 *
 * Sends an email to the mail address with a link to confirm.
 *
 * The client will be added after this confirmation.
 *
 * @param mail
 * @param key
 * @param secret
 * @param callback
 */
exports.addRequest = function(mail, key, secret, callback) {
    var id = hash(mail + key);
    if (registryMap.hasOwnProperty(id)) {
        callback(new Error('This API key exists already.'));
        return;
    }

    var token = hash(mail + key + secret + Date.now());
    confirmMap[token] = {
        type: TOKEN_ADD,
        mail: mail,
        key: key,
        secret: secret,
        date: Date.now()
    };
    save(function() {
        sendmail(mail, 'Please confirm your Kraken Notifier subscription by visiting this location: ' + config.url + "/confirm?token=" + token + "\n\n"
         + "If you did not enter your mail address at Kraken Notifier please ignore this email.", 'Welcome to Kraken Notifier', callback);
    });
};

/**
 * Initiates the process of removing a subscription.
 *
 * Sends an email to the mail address with a link to confirm.
 *
 * The client will be removed after this confirmation.
 *
 * @param mail
 * @param key
 * @param callback
 */
exports.removeRequest = function(mail, key, callback) {
    var found = false;
    if (!key) {
        // Look if we have this mail address in the storage.
        for (var i = 0; i < registry.length; i++) {
            if(registry[i].mail === mail) {
                found = true;
            }
        }
    } else if (registryMap.hasOwnProperty(hash(mail + key))) {
        found = true;
    }

    if (found === false) {
        if (!key) {
            callback(new errors.FieldError('mail', "This mail address doesn't exist in storage."));
        } else {
            callback(new errors.FieldError('key', "This key and email combination doesn't exist in storage."));
        }
        return;
    }

    var token = hash(mail + key + Date.now());
    confirmMap[token] = {
        type: TOKEN_REMOVE,
        mail: mail,
        key: key,
        date: Date.now()
    };

    var message = 'Please confirm the deletion of all Kraken Notifier subscriptions by visiting this location: ' + config.url + "/confirm?token=" + token + "\n\n"
        + "If you did not request a deletion at Kraken Notifier please ignore this email.";
    if (key) {
        message = 'Please confirm the deletion of Kraken Notifier notification for the key ' + key + ' by visiting this location: ' + config.url + "/confirm?token=" + token + "\n\n"
            + "If you did not request a deletion at Kraken Notifier please ignore this email.";
    }

    save(function() {
        sendmail(mail, message, 'Confirm Kraken Notifier removal request', callback);
    });
};

exports.start = function() {
    var storage = config.storageFile;
    fs.exists(storage, function(exists) {
        if (exists === true) {
            var data = require(storage);
            if (data && data.registry) {
                registry = data.registry;
            }
            if (data && data.token) {
                confirmMap = data.token;
            }
            for (var i = 0; i < registry.length; i++) {
                var id = hash(registry[i].mail + registry[i].key);
                registryMap[id] = i;
            }
            console.log("Init complete. Going to check now.");
        } else {
            console.log("Storagefile not found. Creating an empty one.");
            // Creating the file for the first time.
            save();
        }

        check();
    });
};

/**
 * Adds a client to the registry.
 *
 * @param mail
 * @param key
 * @param secret
 * @param callback
 */
function addClient (mail, key, secret, callback) {
    var id = hash(mail + key);
    if (registryMap.hasOwnProperty(id)) {
        callback(new Error('This API key exists already.'));
        return;
    } else {
        registryMap[id] = registry.length;
        registry.push({
            mail: mail,
            key: key,
            secret: secret
        });
    }
    save(function(error) {
        if (typeof callback != 'function') {
            return;
        }
        if (error) {
            callback(error);
        } else {
            callback(null);
        }
    });
}

/**
 * Removes a client from the registry.
 *
 * @param mail
 * @param key
 * @param callback {function}
 */
function removeClient(mail, key, callback) {
    var id;
    console.log("Removing mail " + mail + ", key " + key);
    if (!key) {
        // Delete all subscriptions of this mail address
        var i = registry.length;
        var found = false;
        while (i--) {
            if(registry[i].mail === mail) {
                id = hash(mail + registry[i].key);
                delete(registryMap[id]);
                registry.splice(i, 1);
                found = true;
            }
        }
        if (found === false) {
            callback(new errors.FieldError('mail', 'This mail address doesn\'t exist in storage.'));
            return;
        }
    } else {
        id = hash(mail + key);
        if (registryMap.hasOwnProperty(id)) {
            registry.splice(registryMap[id], 1);
            delete(registryMap[id]);
        } else {
            callback(new errors.FieldError('key', 'This combination of key and mail doesn\'t exist in storage.'));
            return;
        }
    }
    save(function(error) {
        if (typeof callback != 'function') {
            return;
        }
        if (error) {
            callback(error);
        } else {
            callback(null);
        }
    });
}

function hash(data) {
    var shasum = crypto.createHash('sha1');
    shasum.update(data);
    return shasum.digest('hex');
}

function check() {

    console.log("checking");

    var queue = [];
    registry.forEach(function(client) {
        queue.push(function(next) {
            var kraken = new KrakenClient(client.key, client.secret);
            kraken.api('Balance', null, function(error, data) {
                if(data === null || error && client.lastResult != 'error') {
                    client.lastResult = 'error';
                    console.log("api error: ", error);
                    if (error == 'EAPI:Invalid nonce') {
                        // Invalid nonce errors get usually fixed with the next request.
                    } else if (error == 'EAPI:Invalid key') {
                        sendmail(client.mail, 'Your API key is not valid. Please create another subscription with a valid key if you want to receive further notification.\n\nKey: ' + client.key, 'You key is invalid', function () {
                            // Delete the invalid client.
                            removeClient(client.mail, client.key, next);
                            console.log("client removed because of an invalid key: " + client.mail + ", " + client.key);
                        });
                    } else if (error == 'EGeneral:Permission denied') {
                        sendmail(client.mail, 'Your API key doesn\'t have the necessary permissions. Please add the permission "Query Funds" to your key and create a new subscription.\n\nKey: ' + client.key, 'You key doesn\'t have enough permissions', function () {
                            // Delete the invalid client.
                            removeClient(client.mail, client.key, next);
                            console.log("client removed because of missing permissions key: " + client.mail + ", " + client.key);
                        });
                    } else {
                        console.log("Unhandled error: " + error);
                        sendmail(client.mail, 'The Kraken api is not reachable currently. You will receive the next email once the api becomes accessible again.', 'Kraken connection issues', next);
                    }
                } else {
                    var stringified = JSON.stringify(data.result);
                    if (client.lastResult != stringified) {
                        client.lastResult = stringified;
                        sendmail(client.mail, stringified, 'Kraken Balance updated', next);
                    } else {
                        next();
                    }
                }
            });
        });
    });

    async.series(queue, function(errors, results) {
        // TODO error handling.
        // TODO: check if save is really necessary.
        save(function(error) {
            // TODO error handling
            setTimeout(check, config.interval);
        });
    });
}

function save(callback) {
    var data = {
        registry: registry,
        token: confirmMap
    };
    fs.writeFile(config.storageFile, "module.exports = " + JSON.stringify(data) + ";", function(err) {
        if(err) {
            console.log('error while saving', err);
            if (typeof callback == 'function') {
                callback(err);
            }
        } else {
            console.log('storage save successful. Serving ' + registry.length + " clients currently.");
            if (typeof callback == 'function') {
                callback();
            }
        }
    });
}

function sendmail(to, message, subject, callback) {
    var mailOptions = config.mailOptions;
    mailOptions.text = message;
    mailOptions.subject = subject;
    mailOptions.to = to;
    smtpTransport.sendMail(mailOptions, function(error, response){
        if (error){
            if (typeof callback == 'function') {
                callback(error);
            }
        } else {
            if (typeof callback == 'function') {
                callback();
            }
        }
    });
}
<commit_msg>Truncate keys in emails for security.<commit_after>var KrakenClient = require('kraken-api');
var nodemailer = require("nodemailer");
var async = require('async');
var fs = require('fs');
var crypto = require('crypto');
var config = require('./config.js');
var errors = require('./errors.js');
var smtpTransport = nodemailer.createTransport("SMTP", config.smtp);
var registry = [];
var registryMap = {};

/**
 * Map of email tokens to confirm the addition or deletion of subscriptions.
 */
var confirmMap = {};
var TOKEN_ADD = 'add';
var TOKEN_REMOVE = 'remove';

exports.TOKEN_ADD = TOKEN_ADD;
exports.TOKEN_REMOVE = TOKEN_REMOVE;

/**
 * Confirms a request to delete or add a subscription.
 * @param token
 * @param callback
 */
exports.confirm = function(token, callback) {
    if (!confirmMap.hasOwnProperty(token)) {
        if (typeof callback == 'function') {
            callback(new Error("Sorry. We could not find this token."));
        }
        return;
    }
    var data = confirmMap[token];
    delete(confirmMap[token]);
    save(function(error) {
        if (error) {
            console.log("Error while removing token: " + error.message);
        }

        if (data.type == TOKEN_ADD) {
            addClient(data.mail, data.key, data.secret, function(error) {
                callback(error, data);
            });
        } else if (data.type == TOKEN_REMOVE) {
            removeClient(data.mail, data.key, function(error) {
                callback(error, data);
            });
        } else {
            callback(new Error("Invalid token data. Please contact support."));
        }
    });
};

/**
 * Initiates the process of adding a subscription.
 *
 * Sends an email to the mail address with a link to confirm.
 *
 * The client will be added after this confirmation.
 *
 * @param mail
 * @param key
 * @param secret
 * @param callback
 */
exports.addRequest = function(mail, key, secret, callback) {
    var id = hash(mail + key);
    if (registryMap.hasOwnProperty(id)) {
        callback(new Error('This API key exists already.'));
        return;
    }

    var token = hash(mail + key + secret + Date.now());
    confirmMap[token] = {
        type: TOKEN_ADD,
        mail: mail,
        key: key,
        secret: secret,
        date: Date.now()
    };
    save(function() {
        sendmail(mail, 'Please confirm your Kraken Notifier subscription by visiting this location: ' + config.url + "/confirm?token=" + token + "\n\n"
         + "If you did not enter your mail address at Kraken Notifier please ignore this email.", 'Welcome to Kraken Notifier', callback);
    });
};

/**
 * Initiates the process of removing a subscription.
 *
 * Sends an email to the mail address with a link to confirm.
 *
 * The client will be removed after this confirmation.
 *
 * @param mail
 * @param key
 * @param callback
 */
exports.removeRequest = function(mail, key, callback) {
    var found = false;
    if (!key) {
        // Look if we have this mail address in the storage.
        for (var i = 0; i < registry.length; i++) {
            if(registry[i].mail === mail) {
                found = true;
            }
        }
    } else if (registryMap.hasOwnProperty(hash(mail + key))) {
        found = true;
    }

    if (found === false) {
        if (!key) {
            callback(new errors.FieldError('mail', "This mail address doesn't exist in storage."));
        } else {
            callback(new errors.FieldError('key', "This key and email combination doesn't exist in storage."));
        }
        return;
    }

    var token = hash(mail + key + Date.now());
    confirmMap[token] = {
        type: TOKEN_REMOVE,
        mail: mail,
        key: key,
        date: Date.now()
    };

    var message = 'Please confirm the deletion of all Kraken Notifier subscriptions by visiting this location: ' + config.url + "/confirm?token=" + token + "\n\n"
        + "If you did not request a deletion at Kraken Notifier please ignore this email.";
    if (key) {
        message = 'Please confirm the deletion of Kraken Notifier notification for the key ' + key + ' by visiting this location: ' + config.url + "/confirm?token=" + token + "\n\n"
            + "If you did not request a deletion at Kraken Notifier please ignore this email.";
    }

    save(function() {
        sendmail(mail, message, 'Confirm Kraken Notifier removal request', callback);
    });
};

exports.start = function() {
    var storage = config.storageFile;
    fs.exists(storage, function(exists) {
        if (exists === true) {
            var data = require(storage);
            if (data && data.registry) {
                registry = data.registry;
            }
            if (data && data.token) {
                confirmMap = data.token;
            }
            for (var i = 0; i < registry.length; i++) {
                var id = hash(registry[i].mail + registry[i].key);
                registryMap[id] = i;
            }
            console.log("Init complete. Going to check now.");
        } else {
            console.log("Storagefile not found. Creating an empty one.");
            // Creating the file for the first time.
            save();
        }

        check();
    });
};

/**
 * Adds a client to the registry.
 *
 * @param mail
 * @param key
 * @param secret
 * @param callback
 */
function addClient (mail, key, secret, callback) {
    var id = hash(mail + key);
    if (registryMap.hasOwnProperty(id)) {
        callback(new Error('This API key exists already.'));
        return;
    } else {
        registryMap[id] = registry.length;
        registry.push({
            mail: mail,
            key: key,
            secret: secret
        });
    }
    save(function(error) {
        if (typeof callback != 'function') {
            return;
        }
        if (error) {
            callback(error);
        } else {
            callback(null);
        }
    });
}

/**
 * Removes a client from the registry.
 *
 * @param mail
 * @param key
 * @param callback {function}
 */
function removeClient(mail, key, callback) {
    var id;
    console.log("Removing mail " + mail + ", key " + key);
    if (!key) {
        // Delete all subscriptions of this mail address
        var i = registry.length;
        var found = false;
        while (i--) {
            if(registry[i].mail === mail) {
                id = hash(mail + registry[i].key);
                delete(registryMap[id]);
                registry.splice(i, 1);
                found = true;
            }
        }
        if (found === false) {
            callback(new errors.FieldError('mail', 'This mail address doesn\'t exist in storage.'));
            return;
        }
    } else {
        id = hash(mail + key);
        if (registryMap.hasOwnProperty(id)) {
            registry.splice(registryMap[id], 1);
            delete(registryMap[id]);
        } else {
            callback(new errors.FieldError('key', 'This combination of key and mail doesn\'t exist in storage.'));
            return;
        }
    }
    save(function(error) {
        if (typeof callback != 'function') {
            return;
        }
        if (error) {
            callback(error);
        } else {
            callback(null);
        }
    });
}

function hash(data) {
    var shasum = crypto.createHash('sha1');
    shasum.update(data);
    return shasum.digest('hex');
}

function check() {

    console.log("checking");

    var queue = [];
    registry.forEach(function(client) {
        queue.push(function(next) {
            var kraken = new KrakenClient(client.key, client.secret);
            kraken.api('Balance', null, function(error, data) {
                if(data === null || error && client.lastResult != 'error') {
                    client.lastResult = 'error';
                    console.log("api error: ", error);
                    if (error == 'EAPI:Invalid nonce') {
                        // Invalid nonce errors get usually fixed with the next request.
                    } else if (error == 'EAPI:Invalid key') {
                        sendmail(client.mail, 'Your API key is not valid. Please create another subscription with a valid key if you want to receive further notification.\n\nKey: ' + truncateKey(client.key), 'You key is invalid', function () {
                            // Delete the invalid client.
                            removeClient(client.mail, client.key, next);
                            console.log("client removed because of an invalid key: " + client.mail + ", " + client.key);
                        });
                    } else if (error == 'EGeneral:Permission denied') {
                        sendmail(client.mail, 'Your API key doesn\'t have the necessary permissions. Please add the permission "Query Funds" to your key and create a new subscription.\n\nKey: ' + truncateKey(client.key), 'You key doesn\'t have enough permissions', function () {
                            // Delete the invalid client.
                            removeClient(client.mail, client.key, next);
                            console.log("client removed because of missing permissions key: " + client.mail + ", " + truncateKey(client.key));
                        });
                    } else {
                        console.log("Unhandled error: " + error);
                        sendmail(client.mail, 'The Kraken api is not reachable currently. You will receive the next email once the api becomes accessible again.', 'Kraken connection issues', next);
                    }
                } else {
                    var stringified = JSON.stringify(data.result);
                    if (client.lastResult != stringified) {
                        client.lastResult = stringified;
                        sendmail(client.mail, stringified, 'Kraken Balance updated', next);
                    } else {
                        next();
                    }
                }
            });
        });
    });

    async.series(queue, function(errors, results) {
        // TODO error handling.
        // TODO: check if save is really necessary.
        save(function(error) {
            // TODO error handling
            setTimeout(check, config.interval);
        });
    });
}

function save(callback) {
    var data = {
        registry: registry,
        token: confirmMap
    };
    fs.writeFile(config.storageFile, "module.exports = " + JSON.stringify(data) + ";", function(err) {
        if(err) {
            console.log('error while saving', err);
            if (typeof callback == 'function') {
                callback(err);
            }
        } else {
            console.log('storage save successful. Serving ' + registry.length + " clients currently.");
            if (typeof callback == 'function') {
                callback();
            }
        }
    });
}

function truncateKey(key) {
    if (key && key.length > 0) {
        return key.substr(0, 10) + "… (truncated for security reasons)";
    }
    return key;
}

function sendmail(to, message, subject, callback) {
    var mailOptions = config.mailOptions;
    mailOptions.text = message;
    mailOptions.subject = subject;
    mailOptions.to = to;
    smtpTransport.sendMail(mailOptions, function(error, response){
        if (error){
            if (typeof callback == 'function') {
                callback(error);
            }
        } else {
            if (typeof callback == 'function') {
                callback();
            }
        }
    });
}
<|endoftext|>


<commit_before>$(document).ready(function () {
	var rotationMultiplier = 3.6;
	// For each div that its id ends with "circle", do the following.
	$( "div[id$='circle']" ).each(function() {
		// Save all of its classes in an array.
		var classList = $( this ).attr('class').split(/\s+/);
		// Iterate over the array
		for (var i = 0; i < classList.length; i++) {
		   /* If there's about a percentage class, take the actual percentage and apply the
				css transformations in all occurences of the specified percentage class,
				even for the divs without an id ending with "circle" */
		   if (classList[i].match("^p")) {
			var rotationPercentage = classList[i].substring(1, classList[i].length);
			var rotationDegrees = rotationMultiplier*rotationPercentage;
			$('.c100.p'+rotationPercentage+ ' .bar').css({
			  '-webkit-transform' : 'rotate(' + rotationDegrees + 'deg)',
			  '-moz-transform'    : 'rotate(' + rotationDegrees + 'deg)',
			  '-ms-transform'     : 'rotate(' + rotationDegrees + 'deg)',
			  '-o-transform'      : 'rotate(' + rotationDegrees + 'deg)',
			  'transform'         : 'rotate(' + rotationDegrees + 'deg)'
			});
		   }
		}
	});
});<commit_msg>Replace $ with jQuery for noConflict mode<commit_after>jQuery(document).ready(function () {
	var rotationMultiplier = 3.6;
	// For each div that its id ends with "circle", do the following.
	jQuery( "div[id$='circle']" ).each(function() {
		// Save all of its classes in an array.
		var classList = jQuery( this ).attr('class').split(/\s+/);
		// Iterate over the array
		for (var i = 0; i < classList.length; i++) {
		   /* If there's about a percentage class, take the actual percentage and apply the
				css transformations in all occurences of the specified percentage class,
				even for the divs without an id ending with "circle" */
		   if (classList[i].match("^p")) {
			var rotationPercentage = classList[i].substring(1, classList[i].length);
			var rotationDegrees = rotationMultiplier*rotationPercentage;
			jQuery('.c100.p'+rotationPercentage+ ' .bar').css({
			  '-webkit-transform' : 'rotate(' + rotationDegrees + 'deg)',
			  '-moz-transform'    : 'rotate(' + rotationDegrees + 'deg)',
			  '-ms-transform'     : 'rotate(' + rotationDegrees + 'deg)',
			  '-o-transform'      : 'rotate(' + rotationDegrees + 'deg)',
			  'transform'         : 'rotate(' + rotationDegrees + 'deg)'
			});
		   }
		}
	});
});
<|endoftext|>


<commit_before>const botUtil = require('../util/botUtil');
const CommandHandler = require('../util/msgUtil');
const Permissions = require('discordie').Permissions;
const logger = require(botUtil.getPlugin('logger'));

const config = require('../config');
const userIds = require('../userIds');

const ballQuotes = require(botUtil.getQuotes('8ball'));
const leaveQuotes = require(botUtil.getQuotes('disconnect'));
const docLinks = require(botUtil.getQuotes('docs'));
const commands = require(botUtil.getQuotes('commands'));

/**
 * Primary message listener
 * @param  {IMessage} msg Message object to be used
 * @param  {Discordie} client Bot client object
 */
function respond (msg, client) {
	const msgText = msg.content;
	const sender = msg.member || msg.author; // IUser as a substitute for DMs
	const msgChannel = msg.channel;
	const msgGuild = msg.guild;

	const botUser = msg.isPrivate ? client.User : client.User.memberOf(msgGuild);

	const sendMessage = (s, e) => msgChannel.sendMessage(s, false, e);
	const sendEmbed = (e) => sendMessage('', e);

	const command = msgText.slice(config.prefix.length);
	const handler = new CommandHandler(command);

	const addCommand = (c, f) => handler.addCommand(c, f);
	const addCommandResponse = (c, r) => addCommand(c, () => sendMessage(r));
	const addCommandSentence = (c, f) => handler.addCommandSentence(c, f);
	const addCommandArgs = (c, f) => handler.addCommandArgs(c, f);

	const codeL = s => botUtil.codeL(s);
	const rInAr = ar => botUtil.rInAr(ar);
	const senderIsOwner = botUtil.senderIsOwner(msg);

	addCommand('dc', () => {
		if (!senderIsOwner) return;

		setTimeout(() => {
			sendMessage(rInAr(leaveQuotes)).then(() => {
				logger.logToBoth('[System] System Disconnected (command)');
				client.disconnect();
				// process.exit();
			});
		}, 2000);
	});

	addCommandResponse('connections', codeL(client.User.username) + ' is connected to ' + codeL(client.Guilds.length) + ' servers.');
	addCommandSentence('docs', a => {
		if (docLinks.hasOwnProperty(a)) sendMessage(docLinks[a]);
		else sendMessage('I don\'t have a link for ' + codeL(a));
	});

	function showHelp (a) {
		let help;
		if (a === 'music') {
			help = [
				'```ini',
				'[Music Commands]', '',
				...[
					'join',
					'leave',
					'm q | add [Search term | YouTube URL]',
					'm rm | remove [number in queue]',
					'm sh | shuffle',
					'm p | play',
					'm s | skip',
					'm re | repeat [\'one\' | \'all\' | \'off\']',
					'stop',
					'clear',
					'list'
				].map(a => config.prefix + a),
				'```'
			].join('\n');
		} else {
			help = [
				'```ini',
				'[General Commands]', '',
				...['help/cmds/?',
					'connections',
					'docs',
					// 'invite (bot invite)',
					'roll <optional: max number>',
					'8ball <yes/no question, always ends with a question mark>',
					'prune <\'all\' or user mention> <amount>',
					'time',
					'elwiki'
				].map(a => config.prefix + a),
				'', 'do \'' + config.prefix + '? music\' for music commands',
				'```'
			].join('\n');
		}
		sendMessage(help);
	}

	['help', 'cmds', '?'].forEach(s => addCommandSentence(s, showHelp));

	addCommand('invite', () => {
		const inviteLink = `https://discordapp.com/oauth2/authorize?&client_id=${userIds.eve}&scope=bot&permissions=34611200`;
		/**
		 * Required perms
		 *
		 * Manage Messages: for prune
		 * Connect: To join voice ¯\_(ツ)_/¯
		 * Use Voice Activity: to stream sick beats
		 */
		// if (msg.channel.isDM || msg.channel.isGroupDM) return sendMessage(inviteLink);
		sender.openDM().then((dmChannel, err) => {
			if (err) return console.log(err);
			dmChannel.sendMessage(inviteLink);
		});
	});

	// This is where the fun starts
	addCommandSentence('8ball', a => {
		if (/\?$/.test(a)) {
			sendEmbed({
				color: 0xFFB2C5,
				author: {
					name: (sender.nickname || sender.name),
					icon_url: sender.avatarURL
				},
				title: a,
				description: 'Answer: ' + rInAr(ballQuotes)
			});
		} else sendMessage('Use a question mark.');
	});

	addCommandSentence('eval', a => {
		if (!senderIsOwner || a === 'e.message.content' || a === 'msgText') return;
		let result;
		return new Promise(resolve => {
			result = eval(a);
			resolve('Success');
		}).catch(e => {
			// sendMessage('\u{1F52B}'); // Peestol
			console.log(e);
			sendMessage('It didn\'t work.');
		}).then(v => {
			if (v === 'Success') {
				if (typeof result === 'string' || typeof result === 'number' || typeof result === 'boolean') sendMessage(result);
				else if (Array.isArray(result)) sendMessage(result.join(', '));
				// else sendMessage('\u{1F44C}'); // Ok hand sign
			}
		});
	});

	function fetchMoreMessages (channel, left) {
		const before = channel.messages[0];
		return channel.fetchMessages(Math.min(left, 100), before)
			.then(e => onFetch(e, channel, left));
	}

	function onFetch (e, channel, left) {
		if (!e.messages.length) return Promise.resolve();
		left -= e.messages.length;
		if (left <= 0) return Promise.resolve();
		return fetchMoreMessages(channel, left);
	}

	function fetchMoreSpecificMessages (channel, user, left) {
		const before = channel.messages.filter(m => m.author.id === user.id)[0];
		return channel.fetchMessages(100, before)
			.then(e => onFetchUser(e, channel, user, left));
	}

	function onFetchUser (e, channel, user, left) {
		if (!e.messages.length) return Promise.resolve();
		left -= e.messages.filter(m => m.author.id === user.id).length;
		if (left <= 0) return Promise.resolve();
		return fetchMoreSpecificMessages(channel, user, left);
	}

	function deleteMessages (msgs, channel) {
		return client.Messages.deleteMessages(msgs, channel).then(() => {
			client.Messages.purgeChannelCache(channel);
		});
	}

	addCommandSentence('prune', a => {
		// Sender can't delete or pin messages
		if (!sender.can(Permissions.Text.MANAGE_MESSAGES, msgGuild)) return sendMessage('No.');
		// Bot can't delete or pin messages
		if (!botUser.can(Permissions.Text.MANAGE_MESSAGES, msgGuild)) return sendMessage('I don\'t have permission.');
		const mention = a.split(' ')[0];
		const amount = parseInt(a.split(' ')[1]);

		let allMsgs = false;

		let messages = client.Messages.forChannel(msgChannel).filter(m => !m.deleted);
		if (msg.mentions.length) messages = messages.filter(m => m.author.id === msg.mentions[0].id);
		else if (mention === 'all') allMsgs = true;
		else return sendMessage('Has to be `all` or a user mention.');

		if (amount > messages.length) {
			if (allMsgs) {
				const difference = amount - messages.length;
				fetchMoreMessages(msgChannel, difference).then(() => {
					messages = client.Messages.forChannel(msgChannel).filter(m => !m.deleted);
					deleteMessages(messages.slice(-amount), msgChannel);
				});
			} else {
				fetchMoreSpecificMessages(msgChannel, msg.mentions[0], amount).then(() => {
					messages = client.Messages.forChannel(msgChannel).filter(m => !m.deleted && m.author.id === msg.mentions[0].id);
					deleteMessages(messages.slice(-amount), msgChannel);
				});
			}
		} else deleteMessages(messages.slice(-amount), msgChannel);
	});

	addCommandSentence('roll', a => {
		sendMessage(Math.ceil(Math.random() * (a || 100)));
	});

	// TODO: add timezone argument, otherwise EST
	addCommand('time', () => {
		const currentTime = new Date(Date.now()).toLocaleTimeString('en-US', {hour12: true});
		const timeShort = currentTime.replace(/([\d]+:[\d]{2})(:[\d]{2})(.*)/, '$1$3');
		sendMessage(`It's ${codeL(timeShort)} EST.`);
	});

	addCommandArgs('elwiki', a => {
		const pageName = a.map(w => w[0].toUpperCase() + w.slice(1)).join('_');
		sendMessage('http://elwiki.net/w/' + pageName);
	});
}

exports.respond = respond;
// module.exports = respond;
<commit_msg>Um.. oops<commit_after>const botUtil = require('../util/botUtil');
const CommandHandler = require('../util/msgUtil');
const Permissions = require('discordie').Permissions;
const logger = require(botUtil.getPlugin('logger'));

const config = require('../config');
const userIds = require('../userIds');

const ballQuotes = require(botUtil.getQuotes('8ball'));
const leaveQuotes = require(botUtil.getQuotes('disconnect'));
const docLinks = require(botUtil.getQuotes('docs'));
const commands = require(botUtil.getQuotes('commands'));

/**
 * Primary message listener
 * @param  {IMessage} msg Message object to be used
 * @param  {Discordie} client Bot client object
 */
function respond (msg, client) {
	const msgText = msg.content;
	const sender = msg.member || msg.author; // IUser as a substitute for DMs
	const msgChannel = msg.channel;
	const msgGuild = msg.guild;

	const botUser = msg.isPrivate ? client.User : client.User.memberOf(msgGuild);

	const sendMessage = (s, e) => msgChannel.sendMessage(s, false, e);
	const sendEmbed = (e) => sendMessage('', e);

	const command = msgText.slice(config.prefix.length);
	const handler = new CommandHandler(command);

	if (!msgText.startsWith(config.prefix)) return;

	const addCommand = (c, f) => handler.addCommand(c, f);
	const addCommandResponse = (c, r) => addCommand(c, () => sendMessage(r));
	const addCommandSentence = (c, f) => handler.addCommandSentence(c, f);
	const addCommandArgs = (c, f) => handler.addCommandArgs(c, f);

	const codeL = s => botUtil.codeL(s);
	const rInAr = ar => botUtil.rInAr(ar);
	const senderIsOwner = botUtil.senderIsOwner(msg);

	addCommand('dc', () => {
		if (!senderIsOwner) return;

		setTimeout(() => {
			sendMessage(rInAr(leaveQuotes)).then(() => {
				logger.logToBoth('[System] System Disconnected (command)');
				client.disconnect();
				// process.exit();
			});
		}, 2000);
	});

	addCommandResponse('connections', codeL(client.User.username) + ' is connected to ' + codeL(client.Guilds.length) + ' servers.');
	addCommandSentence('docs', a => {
		if (docLinks.hasOwnProperty(a)) sendMessage(docLinks[a]);
		else sendMessage('I don\'t have a link for ' + codeL(a));
	});

	function showHelp (a) {
		let help;
		if (a === 'music') {
			help = [
				'```ini',
				'[Music Commands]', '',
				...[
					'join',
					'leave',
					'm q | add [Search term | YouTube URL]',
					'm rm | remove [number in queue]',
					'm sh | shuffle',
					'm p | play',
					'm s | skip',
					'm re | repeat [\'one\' | \'all\' | \'off\']',
					'stop',
					'clear',
					'list'
				].map(a => config.prefix + a),
				'```'
			].join('\n');
		} else {
			help = [
				'```ini',
				'[General Commands]', '',
				...['help/cmds/?',
					'connections',
					'docs',
					// 'invite (bot invite)',
					'roll <optional: max number>',
					'8ball <yes/no question, always ends with a question mark>',
					'prune <\'all\' or user mention> <amount>',
					'time',
					'elwiki'
				].map(a => config.prefix + a),
				'', 'do \'' + config.prefix + '? music\' for music commands',
				'```'
			].join('\n');
		}
		sendMessage(help);
	}

	['help', 'cmds', '?'].forEach(s => addCommandSentence(s, showHelp));

	addCommand('invite', () => {
		const inviteLink = `https://discordapp.com/oauth2/authorize?&client_id=${userIds.eve}&scope=bot&permissions=34611200`;
		/**
		 * Required perms
		 *
		 * Manage Messages: for prune
		 * Connect: To join voice ¯\_(ツ)_/¯
		 * Use Voice Activity: to stream sick beats
		 */
		// if (msg.channel.isDM || msg.channel.isGroupDM) return sendMessage(inviteLink);
		sender.openDM().then((dmChannel, err) => {
			if (err) return console.log(err);
			dmChannel.sendMessage(inviteLink);
		});
	});

	// This is where the fun starts
	addCommandSentence('8ball', a => {
		if (/\?$/.test(a)) {
			sendEmbed({
				color: 0xFFB2C5,
				author: {
					name: (sender.nickname || sender.name),
					icon_url: sender.avatarURL
				},
				title: a,
				description: 'Answer: ' + rInAr(ballQuotes)
			});
		} else sendMessage('Use a question mark.');
	});

	addCommandSentence('eval', a => {
		if (!senderIsOwner || a === 'e.message.content' || a === 'msgText') return;
		let result;
		return new Promise(resolve => {
			result = eval(a);
			resolve('Success');
		}).catch(e => {
			// sendMessage('\u{1F52B}'); // Peestol
			console.log(e);
			sendMessage('It didn\'t work.');
		}).then(v => {
			if (v === 'Success') {
				if (typeof result === 'string' || typeof result === 'number' || typeof result === 'boolean') sendMessage(result);
				else if (Array.isArray(result)) sendMessage(result.join(', '));
				// else sendMessage('\u{1F44C}'); // Ok hand sign
			}
		});
	});

	function fetchMoreMessages (channel, left) {
		const before = channel.messages[0];
		return channel.fetchMessages(Math.min(left, 100), before)
			.then(e => onFetch(e, channel, left));
	}

	function onFetch (e, channel, left) {
		if (!e.messages.length) return Promise.resolve();
		left -= e.messages.length;
		if (left <= 0) return Promise.resolve();
		return fetchMoreMessages(channel, left);
	}

	function fetchMoreSpecificMessages (channel, user, left) {
		const before = channel.messages.filter(m => m.author.id === user.id)[0];
		return channel.fetchMessages(100, before)
			.then(e => onFetchUser(e, channel, user, left));
	}

	function onFetchUser (e, channel, user, left) {
		if (!e.messages.length) return Promise.resolve();
		left -= e.messages.filter(m => m.author.id === user.id).length;
		if (left <= 0) return Promise.resolve();
		return fetchMoreSpecificMessages(channel, user, left);
	}

	function deleteMessages (msgs, channel) {
		return client.Messages.deleteMessages(msgs, channel).then(() => {
			client.Messages.purgeChannelCache(channel);
		});
	}

	addCommandSentence('prune', a => {
		// Sender can't delete or pin messages
		if (!sender.can(Permissions.Text.MANAGE_MESSAGES, msgGuild)) return sendMessage('No.');
		// Bot can't delete or pin messages
		if (!botUser.can(Permissions.Text.MANAGE_MESSAGES, msgGuild)) return sendMessage('I don\'t have permission.');
		const mention = a.split(' ')[0];
		const amount = parseInt(a.split(' ')[1]);

		let allMsgs = false;

		let messages = client.Messages.forChannel(msgChannel).filter(m => !m.deleted);
		if (msg.mentions.length) messages = messages.filter(m => m.author.id === msg.mentions[0].id);
		else if (mention === 'all') allMsgs = true;
		else return sendMessage('Has to be `all` or a user mention.');

		if (amount > messages.length) {
			if (allMsgs) {
				const difference = amount - messages.length;
				fetchMoreMessages(msgChannel, difference).then(() => {
					messages = client.Messages.forChannel(msgChannel).filter(m => !m.deleted);
					deleteMessages(messages.slice(-amount), msgChannel);
				});
			} else {
				fetchMoreSpecificMessages(msgChannel, msg.mentions[0], amount).then(() => {
					messages = client.Messages.forChannel(msgChannel).filter(m => !m.deleted && m.author.id === msg.mentions[0].id);
					deleteMessages(messages.slice(-amount), msgChannel);
				});
			}
		} else deleteMessages(messages.slice(-amount), msgChannel);
	});

	addCommandSentence('roll', a => {
		sendMessage(Math.ceil(Math.random() * (a || 100)));
	});

	// TODO: add timezone argument, otherwise EST
	addCommand('time', () => {
		const currentTime = new Date(Date.now()).toLocaleTimeString('en-US', {hour12: true});
		const timeShort = currentTime.replace(/([\d]+:[\d]{2})(:[\d]{2})(.*)/, '$1$3');
		sendMessage(`It's ${codeL(timeShort)} EST.`);
	});

	addCommandArgs('elwiki', a => {
		const pageName = a.map(w => w[0].toUpperCase() + w.slice(1)).join('_');
		sendMessage('http://elwiki.net/w/' + pageName);
	});
}

exports.respond = respond;
// module.exports = respond;
<|endoftext|>


<commit_before>(function () {
    function Pixelator(imageData) {
        if (!validateProps(imageData, Object, 'width', 'number', 'height', 'number', 'data', Uint8ClampedArray)) {
            throw new TypeError('The first argument passed into the Pixelator constructor was not a valid ImageData object.');
        }

        this.width = imageData.width;
        this.height = imageData.height;
        this.pixelCollection = new RGBAPixelCollection(imageData);
        this.rawImageData = imageData;
    }

    Pixelator.prototype.pixelate = function (sectionWidth, sectionHeight) {
        var sections = this.getAllSections(sectionWidth, sectionHeight),
            canvas = document.createElement('canvas'),
            ctx = canvas.getContext('2d'),
            i = sections.length;

        while (i--) {
            var section = sections[i],
                average = Pixelator.getAverageColor(section);

            ctx.fillStyle = 'rgba(' + average.r + ',' + average.g + ',' + average.b + ',' average.a + ')';
            ctx.fillRect(section.x, section.y, section.width, section.height);
        }

        return ctx;
    };

    Pixelator.prototype.getAllSections = function (sectionWidth, sectionHeight) {
        var sections = [],

            rightEdgeSectionWidth = this.width % sectionWidth,
            bottomEdgeSectionHeight = this.height % sectionHeight,

            rightEdgeSectionX = this.width - rightEdgeSectionWidth,
            bottomEdgeSectionY = this.height - bottomEdgeSectionHeight;

        function addAllSectionsForRow(y, height) {
            sections.push(new Section(rightEdgeSectionX, y, rightEdgeSectionWidth, height));

            var x = rightEdgeSectionX - sectionWidth;

            while (x >= 0) {
                sections.push(new Section(x, y, sectionWidth, height));

                x -= sectionWidth;
            }
        }

        addAllSectionsForRow(bottomEdgeSectionY, bottomEdgeSectionHeight);

        var y = bottomEdgeSectionY - sectionHeight;

        while (y >= 0) {
            addAllSectionsForRow(y, sectionHeight);

            y -= sectionHeight;
        }

        return sections;
    };

    Pixelator.prototype.getAverageColor = function (section) {
        var pixels = this.pixelCollection,
            indices = pixels.getIndicesInRect(section.x, section.y, section.width, section.height),

            sumColor = {r: 0, g: 0, b: 0, a: 0},
            avgColor = {},

            len = indices.length,
            i = len;

        while (i--) {
            var pixel = pixels[indices[i]];

            sumColor.r += pixel.r;
            sumColor.g += pixel.g;
            sumColor.b += pixel.b;
            sumColor.a += pixel.a;
        }

        avgColor.r = sumColor.r / len;
        avgColor.g = sumColor.g / len;
        avgColor.b = sumColor.b / len;
        avgColor.a = sumColor.a / len;

        return avgColor;
    };

    Pixelator.prototype.filters_ = [];

    /** RGBAPixelCollection class. **/

    function RGBAPixelCollection (imageData) {
        if (!validateProps(imageData, Object, 'width', 'number', 'height', 'number')) {
            throw new TypeError('The first argument passed into the RGBAPixelCollection constructor was not a valid ImageData object.');
        }

        this.width = imageData.width;
        this.height = imageData.height;
        this.pixels = [];

        var data = imageData.data;

        if (data instanceof Uint8ClampedArray) {
            this.raw = imageData;

            for (var i = 0; i < data.length; i+= 4) {
                this.pixels.push(new RGBAColor(data[i], data[i + 1], data[i + 2], data[i + 3]));
            }
        } else {
            var size = this.width * this.height;

            for (var i = 0; i < size; i++) {
                this.pixels.push(new RGBAColor(0, 0, 0, 255));
            }

            this.raw = this.toSimpleImageData();
        }
    }

    RGBAPixelCollection.prototype.getIndicesInRect = function (startX, startY, rectWidth, rectHeight) {
        var indices = [],
            endX = startX + rectWidth - 1,
            endY = startY + rectHeight - 1,
            collectionWidth = this.width;

        for (var row = startY; row <= endY; row++) {
            for (var rowCell = startX; rowCell = endX; rowCell++) {
                indices.push(row * collectionWidth + rowCell);
            }
        }

        return indices;
    };

    RGBAPixelCollection.prototype.setPixelByIndex = function (index, color) {
        if (!(index in this.pixels)) {
            throw new RangeError('The index argument (' + JSON.stringify(index) + ') is not a valid index.');
        }

        if (!(color instanceof Object && 'r' in color && 'g' in color && 'b' in color && 'a' in color)) {
            throw new TypeError('The color argument (' + JSON.stringify(color) + ') is not a valid color.');
        }

        var pixel = this.pixels[index];

        pixel.r = color.r;
        pixel.g = color.g;
        pixel.b = color.b;
        pixel.a = color.a;

        return pixel;
    };

    /*
    RGBAPixelCollection.prototype.clone = function () {
        return new RGBAPixelCollection(this.raw);
    };
    */

    RGBAPixelCollection.prototype.toSimpleImageData = function () {
        var imageData = {width: this.width, height: this.height},
            pixels = this.pixels,
            data = new Uint8ClampedArray(this.width * this.height);

        for (var i = 0; i < pixels.length; i+= 4) {
            var currentPixel = pixels[i];

            data[i] = currentPixel.r;
            data[i + 1] = currentPixel.g;
            data[i + 2] = currentPixel.b;
            data[i + 3] = currentPixel.a;
        }

        imageData.data = data;

        return imageData;
    };

    /*
    RGBAPixelCollection.prototype.toImage = function () {
        var canvas = document.createElement('canvas'),
            ctx = canvas.getContext('2d'),

            image = document.createElement('img'),

            pixels = this.pixels,
            size = pixels.length,

            width = this.width,
            height = this.height;

        canvas.width = width;
        canvas.height = height;

        for (var i = 0; i < size; i++) {
            var pixel = pixels[i];

            ctx.fillStyle = 'rgba(' + pixel.r + ',' + pixel.g + ',' + pixel.b + ',' + pixel.a + ')';
            ctx.fillRect(i % width, Math.floor(i / width), 1, 1);
        }

        image.src = canvas.toDataURL();

        return image;
    };

    RGBAPixelCollection.prototype.toDataURL = function () {
        var canvas = document.createElement('canvas'),
            ctx = canvas.getContext('2d'),

            pixels = this.pixels,
            size = pixels.length,

            width = this.width,
            height = this.height;

        canvas.width = width;
        canvas.height = height;

        for (var i = 0; i < size; i++) {
            var pixel = pixels[i];

            ctx.fillStyle = 'rgba(' + pixel.r + ',' + pixel.g + ',' + pixel.b + ',' + pixel.a + ')';
            ctx.fillRect(i % width, Math.floor(i / width), 1, 1);
        }

        return canvas.toDataURL();
    };
    */

    /** RGBAColor class. **/

    function RGBAColor(red, green, blue, alpha) {
        this.r = red & 255;
        this.g = green & 255;
        this.b = blue &  255;
        this.a = alpha & 255;
    }

    RGBA.prototype = {
        r: 0,
        g: 0,
        b: 0,
        a: 255
    };

    /** Section class. **/

    function Section(x, y, w, h) {
        this.x = x;
        this.y = y;
        this.width = w;
        this.height = h;
    }

    /** Miscellaneous utilities. **/

    function validateProps(obj, constructor) {
        if (!(obj instanceof Object) || typeof constructor !== 'function' || !(obj instanceof constructor)) {
            return false;
        }

        var numOfArgs = arguments.length;

        for (var i = 2; i < numOfArgs; i += 2) {
            var prop = obj[arguments[i]],
                propType = arguments[i + 1],
                propTypeType = typeof propType;

            if (
                (propTypeType === 'function' && !(prop instanceof propType)) ||
                (propTypeType === 'string' && typeof prop !== propType) ||
                (propTypeType !== 'function' && propTypeType !== 'string')
            ) {
                return false;
            }
        }

        return true;
    }

    function multiValueTypeCheck(type) {
        var typeType = typeof type,
            i = arguments.length;

        if (typeType === 'function') {
            while (--i) { // Skip first argument (which is the type argument).
                if (!(arguments[i] instanceof type)) {
                    return false;
                }
            }
        } else if (typeType === 'string') {
            while (--i) {
                if (typeof arguments[i] !== type) {
                    return false;
                }
            }
        } else return true;
    }

    window['Pixelator'] = Pixelator;
})();
<commit_msg>Update pixelator.js<commit_after>(function () {
    function Pixelator(imageData) {
        if (!validateProps(imageData, Object, 'width', 'number', 'height', 'number', 'data', Uint8ClampedArray)) {
            throw new TypeError('The first argument passed into the Pixelator constructor was not a valid ImageData object.');
        }

        this.width = imageData.width;
        this.height = imageData.height;
        this.pixelCollection = new RGBAPixelCollection(imageData);
        this.rawImageData = imageData;
    }

    Pixelator.prototype.pixelate = function (sectionWidth, sectionHeight) {
        var sections = this.getAllSections(sectionWidth, sectionHeight),
            canvas = document.createElement('canvas'),
            ctx = canvas.getContext('2d'),
            i = sections.length;

        while (i--) {
            var section = sections[i],
                average = Pixelator.getAverageColor(section);

            ctx.fillStyle = 'rgba(' + average.r + ',' + average.g + ',' + average.b + ',' average.a + ')';
            ctx.fillRect(section.x, section.y, section.width, section.height);
        }

        return ctx;
    };

    Pixelator.prototype.getAllSections = function (sectionWidth, sectionHeight) {
        var sections = [],

            rightEdgeSectionWidth = this.width % sectionWidth,
            bottomEdgeSectionHeight = this.height % sectionHeight,

            rightEdgeSectionX = this.width - rightEdgeSectionWidth,
            bottomEdgeSectionY = this.height - bottomEdgeSectionHeight;

        function addAllSectionsForRow(y, height) {
            sections.push(new Section(rightEdgeSectionX, y, rightEdgeSectionWidth, height));

            var x = rightEdgeSectionX - sectionWidth;

            while (x >= 0) {
                sections.push(new Section(x, y, sectionWidth, height));

                x -= sectionWidth;
            }
        }

        addAllSectionsForRow(bottomEdgeSectionY, bottomEdgeSectionHeight);

        var y = bottomEdgeSectionY - sectionHeight;

        while (y >= 0) {
            addAllSectionsForRow(y, sectionHeight);

            y -= sectionHeight;
        }

        return sections;
    };

    Pixelator.prototype.getAverageColor = function (section) {
        var pixels = this.pixelCollection,
            indices = pixels.getIndicesInRect(section.x, section.y, section.width, section.height),

            sumColor = {r: 0, g: 0, b: 0, a: 0},
            avgColor = {},

            len = indices.length,
            i = len;

        while (i--) {
            var pixel = pixels[indices[i]];

            sumColor.r += pixel.r;
            sumColor.g += pixel.g;
            sumColor.b += pixel.b;
            sumColor.a += pixel.a;
        }

        avgColor.r = sumColor.r / len;
        avgColor.g = sumColor.g / len;
        avgColor.b = sumColor.b / len;
        avgColor.a = sumColor.a / len;

        return avgColor;
    };

    Pixelator.prototype.filters_ = [];

    /** RGBAPixelCollection class. **/

    function RGBAPixelCollection (imageData) {
        if (!validateProps(imageData, Object, 'width', 'number', 'height', 'number')) {
            throw new TypeError('The first argument passed into the RGBAPixelCollection constructor was not a valid ImageData object.');
        }

        this.width = imageData.width;
        this.height = imageData.height;
        this.pixels = [];

        var data = imageData.data;

        if (data instanceof Uint8ClampedArray) {
            this.raw = imageData;

            for (var i = 0; i < data.length; i+= 4) {
                this.pixels.push(new RGBAColor(data[i], data[i + 1], data[i + 2], data[i + 3]));
            }
        } else {
            var size = this.width * this.height;

            for (var i = 0; i < size; i++) {
                this.pixels.push(new RGBAColor(0, 0, 0, 255));
            }

            this.raw = this.toSimpleImageData();
        }
    }

    RGBAPixelCollection.prototype.getIndicesInRect = function (startX, startY, rectWidth, rectHeight) {
        var indices = [],
            endX = startX + rectWidth - 1,
            endY = startY + rectHeight - 1,
            collectionWidth = this.width;

        for (var row = startY; row <= endY; row++) {
            for (var rowCell = startX; rowCell = endX; rowCell++) {
                indices.push(row * collectionWidth + rowCell);
            }
        }

        return indices;
    };

    /*
    RGBAPixelCollection.prototype.setPixelByIndex = function (index, color) {
        if (!(index in this.pixels)) {
            throw new RangeError('The index argument (' + JSON.stringify(index) + ') is not a valid index.');
        }

        if (!(color instanceof Object && 'r' in color && 'g' in color && 'b' in color && 'a' in color)) {
            throw new TypeError('The color argument (' + JSON.stringify(color) + ') is not a valid color.');
        }

        var pixel = this.pixels[index];

        pixel.r = color.r;
        pixel.g = color.g;
        pixel.b = color.b;
        pixel.a = color.a;

        return pixel;
    };
    */

    /*
    RGBAPixelCollection.prototype.clone = function () {
        return new RGBAPixelCollection(this.raw);
    };
    */

    /*
    RGBAPixelCollection.prototype.toSimpleImageData = function () {
        var imageData = {width: this.width, height: this.height},
            pixels = this.pixels,
            data = new Uint8ClampedArray(this.width * this.height);

        for (var i = 0; i < pixels.length; i+= 4) {
            var currentPixel = pixels[i];

            data[i] = currentPixel.r;
            data[i + 1] = currentPixel.g;
            data[i + 2] = currentPixel.b;
            data[i + 3] = currentPixel.a;
        }

        imageData.data = data;

        return imageData;
    };
    */

    /*
    RGBAPixelCollection.prototype.toImage = function () {
        var canvas = document.createElement('canvas'),
            ctx = canvas.getContext('2d'),

            image = document.createElement('img'),

            pixels = this.pixels,
            size = pixels.length,

            width = this.width,
            height = this.height;

        canvas.width = width;
        canvas.height = height;

        for (var i = 0; i < size; i++) {
            var pixel = pixels[i];

            ctx.fillStyle = 'rgba(' + pixel.r + ',' + pixel.g + ',' + pixel.b + ',' + pixel.a + ')';
            ctx.fillRect(i % width, Math.floor(i / width), 1, 1);
        }

        image.src = canvas.toDataURL();

        return image;
    };

    RGBAPixelCollection.prototype.toDataURL = function () {
        var canvas = document.createElement('canvas'),
            ctx = canvas.getContext('2d'),

            pixels = this.pixels,
            size = pixels.length,

            width = this.width,
            height = this.height;

        canvas.width = width;
        canvas.height = height;

        for (var i = 0; i < size; i++) {
            var pixel = pixels[i];

            ctx.fillStyle = 'rgba(' + pixel.r + ',' + pixel.g + ',' + pixel.b + ',' + pixel.a + ')';
            ctx.fillRect(i % width, Math.floor(i / width), 1, 1);
        }

        return canvas.toDataURL();
    };
    */

    /** RGBAColor class. **/

    function RGBAColor(red, green, blue, alpha) {
        this.r = red & 255;
        this.g = green & 255;
        this.b = blue &  255;
        this.a = alpha & 255;
    }

    RGBA.prototype = {
        r: 0,
        g: 0,
        b: 0,
        a: 255
    };

    /** Section class. **/

    function Section(x, y, w, h) {
        this.x = x;
        this.y = y;
        this.width = w;
        this.height = h;
    }

    /** Miscellaneous utilities. **/

    function validateProps(obj, constructor) {
        if (!(obj instanceof Object) || typeof constructor !== 'function' || !(obj instanceof constructor)) {
            return false;
        }

        var numOfArgs = arguments.length;

        for (var i = 2; i < numOfArgs; i += 2) {
            var prop = obj[arguments[i]],
                propType = arguments[i + 1],
                propTypeType = typeof propType;

            if (
                (propTypeType === 'function' && !(prop instanceof propType)) ||
                (propTypeType === 'string' && typeof prop !== propType) ||
                (propTypeType !== 'function' && propTypeType !== 'string')
            ) {
                return false;
            }
        }

        return true;
    }

    function multiValueTypeCheck(type) {
        var typeType = typeof type,
            i = arguments.length;

        if (typeType === 'function') {
            while (--i) { // Skip first argument (which is the type argument).
                if (!(arguments[i] instanceof type)) {
                    return false;
                }
            }
        } else if (typeType === 'string') {
            while (--i) {
                if (typeof arguments[i] !== type) {
                    return false;
                }
            }
        } else return true;
    }

    window['Pixelator'] = Pixelator;
})();
<|endoftext|>


<commit_before>// setup restify
var restify = require('restify');
var server = restify.createServer();
server.use(restify.bodyParser());

// setup default mongoose db connection
var mongoose = require('mongoose');

// will hold mongo connections <host:port, con>,
var connectionMap = {};

function createConnection(host) {
  var uri = 'mongodb://' + host + '/ingestion_batch_job';

  var con = mongoose.createConnection(uri);

  // define _id in Schema otherwise mongoose does not return it
  var schema = new mongoose.Schema({
    _id: String
  });

  // create model object for newBatchJob
  // Mongoose#model(name, [schema], [collection], [skipInit])
  var Error = con.model('Error', schema, 'error');
  var NewBatchJob = con.model('NewBatchJob', schema, 'newBatchJob');
  var BatchJobStage = con.model('BatchJobStage', schema, 'batchJobStage');
  var StagedEntities = con.model('StagedEntities', schema, 'stagedEntities');

  // map of our model vars for generic route lookup
  var routeMap = {
    'error': { 'model': Error, 'allQuery': findAll, 'jobJoinQuery': findJoinBatchJobId },
    'job': { 'model': NewBatchJob, 'allQuery':  findAll },
    'jobids': { 'model': NewBatchJob, 'allQuery':  findAllIds },
    'stage': { 'model': BatchJobStage, 'allQuery':  findAll, 'jobJoinQuery': findJoinJobId  },
    'stagedentities': { 'model': StagedEntities, 'allQuery':  findAll, 'jobJoinQuery': findJoinJobId  }
  };

  var mapObj = { 'routeMap': routeMap };
  connectionMap[host] = mapObj;
}

function getOrCreateConnection(host) {
  var con = connectionMap[host];
  if (con == null) {
    createConnection(host);
    con = connectionMap[host];
  }
  return con;
}

function findAll(model, res) {
  model.find({}, function (err,docs) {
    //console.log('docs: %s', docs);
    res.send(docs);
  });
}

function findAllIds(model, res) {
  model.find({}, '_id jobStartTimestamp', function (err,docs) {
    //console.log('docs: %s', docs);
    res.send(docs);
  });
}

function findJoinJobId(model, docId, res) {
  model.find({ 'jobId': docId }, function (err,joinDoc) {
    //console.log('jobId(%s) join doc: %s', docId, joinDoc);
    res.send(joinDoc);
  });
}

function findJoinBatchJobId(model, docId, res) {
  model.find({ 'batchJobId': docId}, function (err,joinDoc) {
    //console.log('batchJobId(%s) join doc: %s', docId, joinDoc);
    res.send(joinDoc);
  });
}

function findById(model, docId, res) {
  model.findById(docId, function (err,doc) {
    //console.log('doc: %s', doc);
    res.send(doc);
  });
}

function genericFind(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "X-Requested-With");
  console.log('GET request: %s', req);

  // get mongo host:port from request headers, defaulting to localhost:27017
  // X-Api-Version because there is some problem with custom headers and jquery/restify
  var mongo = req.header('X-Api-Version', 'localhost:27017');
  console.log('Request: %s/%s/%s/%s', mongo, req.params[0], req.params[1], req.params[2]);

  var routeMap = getOrCreateConnection(mongo).routeMap;

  if (routeMap[req.params[0]] != null) {

    var firstModel = routeMap[req.params[0]].model;

    if (req.params[1] == null) {
      // find all query (only one param)
      routeMap[req.params[0]].allQuery(firstModel, res);

    } else {
      var reqId = req.params[1];

      if (req.params[2] == null) {
        // find by _id query (params: /resource/id)
        findById(firstModel, reqId, res);

      } else {
        var joinResource = req.params[2];

        // join first resource with second (params: /resource1/id/resource2)
        if (routeMap[joinResource] != null) {
          console.log('attempting to join with: %s using id %s', joinResource, reqId);

          var secondModel = routeMap[joinResource].model;

          // lookup a defined join function to use - can't provide the id field of the query as a variable for some reason
          routeMap[joinResource].jobJoinQuery(secondModel, reqId, res);

        } else {
          console.log('unregistered model requested in join: %s', joinResource);
          res.send(404);
        }
      }
    }
  } else {
    console.log('unregistered model requested: %s', req.params[2]);
    res.send(404);
  }
}

// Set up our routes and start the server
server.get(/^\/([a-zA-Z0-9_\.~-]+)\/(.*)\/(.*)/, genericFind);
server.get(/^\/([a-zA-Z0-9_\.~-]+)\/(.*)/, genericFind);
server.get(/^\/([a-zA-Z0-9_\.~-]+)/, genericFind);

server.listen(8080, function() {
  console.log('%s jobReport server started and listening at %s', server.name, server.url);
});

process.on('uncaughtException', function(err) {
  console.log('uncaught exception: ' + err);
});<commit_msg>sot job ids query by jobStartTimestamp ASC<commit_after>// setup restify
var restify = require('restify');
var server = restify.createServer();
server.use(restify.bodyParser());

// setup default mongoose db connection
var mongoose = require('mongoose');

// will hold mongo connections <host:port, con>,
var connectionMap = {};

function createConnection(host) {
  var uri = 'mongodb://' + host + '/ingestion_batch_job';

  var con = mongoose.createConnection(uri);

  // define _id in Schema otherwise mongoose does not return it
  var schema = new mongoose.Schema({
    _id: String
  });

  // create model object for newBatchJob
  // Mongoose#model(name, [schema], [collection], [skipInit])
  var Error = con.model('Error', schema, 'error');
  var NewBatchJob = con.model('NewBatchJob', schema, 'newBatchJob');
  var BatchJobStage = con.model('BatchJobStage', schema, 'batchJobStage');
  var StagedEntities = con.model('StagedEntities', schema, 'stagedEntities');

  // map of our model vars for generic route lookup
  var routeMap = {
    'error': { 'model': Error, 'allQuery': findAll, 'jobJoinQuery': findJoinBatchJobId },
    'job': { 'model': NewBatchJob, 'allQuery':  findAll },
    'jobids': { 'model': NewBatchJob, 'allQuery':  findAllIds },
    'stage': { 'model': BatchJobStage, 'allQuery':  findAll, 'jobJoinQuery': findJoinJobId  },
    'stagedentities': { 'model': StagedEntities, 'allQuery':  findAll, 'jobJoinQuery': findJoinJobId  }
  };

  var mapObj = { 'routeMap': routeMap };
  connectionMap[host] = mapObj;
}

function getOrCreateConnection(host) {
  var con = connectionMap[host];
  if (con == null) {
    createConnection(host);
    con = connectionMap[host];
  }
  return con;
}

function findAll(model, res) {
  model.find({}, function (err,docs) {
    //console.log('docs: %s', docs);
    res.send(docs);
  });
}

function findAllIds(model, res) {
  model.find(
    {},
    '_id jobStartTimestamp',
    { sort:{ jobStartTimestamp: -1 }},
    function (err,docs) {
      //console.log('docs: %s', docs);
      res.send(docs);
    }
  );
}

function findJoinJobId(model, docId, res) {
  model.find({ 'jobId': docId }, function (err,joinDoc) {
    //console.log('jobId(%s) join doc: %s', docId, joinDoc);
    res.send(joinDoc);
  });
}

function findJoinBatchJobId(model, docId, res) {
  model.find({ 'batchJobId': docId}, function (err,joinDoc) {
    //console.log('batchJobId(%s) join doc: %s', docId, joinDoc);
    res.send(joinDoc);
  });
}

function findById(model, docId, res) {
  model.findById(docId, function (err,doc) {
    //console.log('doc: %s', doc);
    res.send(doc);
  });
}

function genericFind(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "X-Requested-With");
  console.log('GET request: %s', req);

  // get mongo host:port from request headers, defaulting to localhost:27017
  // X-Api-Version because there is some problem with custom headers and jquery/restify
  var mongo = req.header('X-Api-Version', 'localhost:27017');
  console.log('Request: %s/%s/%s/%s', mongo, req.params[0], req.params[1], req.params[2]);

  var routeMap = getOrCreateConnection(mongo).routeMap;

  if (routeMap[req.params[0]] != null) {

    var firstModel = routeMap[req.params[0]].model;

    if (req.params[1] == null) {
      // find all query (only one param)
      routeMap[req.params[0]].allQuery(firstModel, res);

    } else {
      var reqId = req.params[1];

      if (req.params[2] == null) {
        // find by _id query (params: /resource/id)
        findById(firstModel, reqId, res);

      } else {
        var joinResource = req.params[2];

        // join first resource with second (params: /resource1/id/resource2)
        if (routeMap[joinResource] != null) {
          console.log('attempting to join with: %s using id %s', joinResource, reqId);

          var secondModel = routeMap[joinResource].model;

          // lookup a defined join function to use - can't provide the id field of the query as a variable for some reason
          routeMap[joinResource].jobJoinQuery(secondModel, reqId, res);

        } else {
          console.log('unregistered model requested in join: %s', joinResource);
          res.send(404);
        }
      }
    }
  } else {
    console.log('unregistered model requested: %s', req.params[2]);
    res.send(404);
  }
}

// Set up our routes and start the server
server.get(/^\/([a-zA-Z0-9_\.~-]+)\/(.*)\/(.*)/, genericFind);
server.get(/^\/([a-zA-Z0-9_\.~-]+)\/(.*)/, genericFind);
server.get(/^\/([a-zA-Z0-9_\.~-]+)/, genericFind);

server.listen(8080, function() {
  console.log('%s jobReport server started and listening at %s', server.name, server.url);
});

process.on('uncaughtException', function(err) {
  console.log('uncaught exception: ' + err);
});<|endoftext|>


<commit_before>// Title: Tigra Calendar
// URL: http://www.softcomplex.com/products/tigra_calendar/
// Version: 3.3 (American date format)
// Date: 09/01/2005 (mm/dd/yyyy)
// Note: Permission given to use this script in ANY kind of applications if
//    header lines are left unchanged.
// Note: Script consists of two files: calendar?.js and calendar.html

// if two digit year input dates after this year considered 20 century.
var NUM_CENTYEAR = 30;
// is time input control required by default
var BUL_TIMECOMPONENT = false;
// are year scrolling buttons required by default
var BUL_YEARSCROLL = true;

var calendars = [];
var RE_NUM = /^\-?\d+$/;

function calendar2(obj_target) {

	// assigning methods
	this.gen_date = cal_gen_date2;
	this.gen_time = cal_gen_time2;
	this.gen_tsmp = cal_gen_tsmp2;
	this.prs_date = cal_prs_date2;
	this.prs_time = cal_prs_time2;
	this.prs_tsmp = cal_prs_tsmp2;
	this.popup    = cal_popup2;

	// validate input parameters
	if (!obj_target)
		return cal_error("Error calling the calendar: no target control specified");
	if (obj_target.value == null)
		return cal_error("Error calling the calendar: parameter specified is not valid target control");
	this.target = obj_target;
	this.time_comp = BUL_TIMECOMPONENT;
	this.year_scroll = BUL_YEARSCROLL;
	this.context='/';

	// register in global collections
	this.id = calendars.length;
	calendars[this.id] = this;
}

function cal_popup2 (str_datetime) {
	if (str_datetime) {
		this.dt_current = this.prs_tsmp(str_datetime);
	}
	else {
		this.dt_current = this.prs_tsmp(this.target.value);
		this.dt_selected = this.dt_current;
	}
	if (!this.dt_current) return;

	var obj_calwindow = window.open(
		this.context +
		'/html/calendar.html?datetime=' + this.dt_current.valueOf()+ '&id=' + this.id,
		'Calendar', 'width=200,height='+(this.time_comp ? 215 : 190)+
		',status=no,resizable=no,top=200,left=200,dependent=yes,alwaysRaised=yes'
	);
	obj_calwindow.opener = window;
	obj_calwindow.focus();
}

// timestamp generating function
function cal_gen_tsmp2 (dt_datetime) {
	return(this.gen_date(dt_datetime) + ' ' + this.gen_time(dt_datetime));
}

// date generating function
function cal_gen_date2 (dt_datetime) {
	return (
		(dt_datetime.getMonth() < 9 ? '0' : '') + (dt_datetime.getMonth() + 1) + "/"
		+ (dt_datetime.getDate() < 10 ? '0' : '') + dt_datetime.getDate() + "/"
		+ dt_datetime.getFullYear()
	);
}
// time generating function
function cal_gen_time2 (dt_datetime) {
	return (
		(dt_datetime.getHours() < 10 ? '0' : '') + dt_datetime.getHours() + ":"
		+ (dt_datetime.getMinutes() < 10 ? '0' : '') + (dt_datetime.getMinutes()) + ":"
		+ (dt_datetime.getSeconds() < 10 ? '0' : '') + (dt_datetime.getSeconds())
	);
}

// timestamp parsing function
function cal_prs_tsmp2 (str_datetime) {
	// if no parameter specified return current timestamp
	if (!str_datetime)
		return (new Date());

	// if positive integer treat as milliseconds from epoch
	if (RE_NUM.exec(str_datetime))
		return new Date(str_datetime);

	// else treat as date in string format
	var arr_datetime = str_datetime.split(' ');
	return this.prs_time(arr_datetime[1], this.prs_date(arr_datetime[0]));
}

// date parsing function
function cal_prs_date2 (str_date) {

	var arr_date = str_date.split('/');

	if (arr_date.length != 3) return alert ("Invalid date format: '" + str_date + "'.\nFormat accepted is dd-mm-yyyy.");
	if (!arr_date[1]) return alert ("Invalid date format: '" + str_date + "'.\nNo day of month value can be found.");
	if (!RE_NUM.exec(arr_date[1])) return alert ("Invalid day of month value: '" + arr_date[1] + "'.\nAllowed values are unsigned integers.");
	if (!arr_date[0]) return alert ("Invalid date format: '" + str_date + "'.\nNo month value can be found.");
	if (!RE_NUM.exec(arr_date[0])) return alert ("Invalid month value: '" + arr_date[0] + "'.\nAllowed values are unsigned integers.");
	if (!arr_date[2]) return alert ("Invalid date format: '" + str_date + "'.\nNo year value can be found.");
	if (!RE_NUM.exec(arr_date[2])) return alert ("Invalid year value: '" + arr_date[2] + "'.\nAllowed values are unsigned integers.");

	var dt_date = new Date();
	dt_date.setDate(1);

	if (arr_date[0] < 1 || arr_date[0] > 12) return alert ("Invalid month value: '" + arr_date[0] + "'.\nAllowed range is 01-12.");
	dt_date.setMonth(arr_date[0]-1);

	if (arr_date[2] < 100) arr_date[2] = Number(arr_date[2]) + (arr_date[2] < NUM_CENTYEAR ? 2000 : 1900);
	dt_date.setFullYear(arr_date[2]);

	var dt_numdays = new Date(arr_date[2], arr_date[0], 0);
	dt_date.setDate(arr_date[1]);
	if (dt_date.getMonth() != (arr_date[0]-1)) return alert ("Invalid day of month value: '" + arr_date[1] + "'.\nAllowed range is 01-"+dt_numdays.getDate()+".");

	return (dt_date)
}

// time parsing function
function cal_prs_time2 (str_time, dt_date) {

	if (!dt_date) return null;
	var arr_time = String(str_time ? str_time : '').split(':');

	if (!arr_time[0]) dt_date.setHours(0);
	else if (RE_NUM.exec(arr_time[0]))
		if (arr_time[0] < 24) dt_date.setHours(arr_time[0]);
		else return cal_error ("Invalid hours value: '" + arr_time[0] + "'.\nAllowed range is 00-23.");
	else return cal_error ("Invalid hours value: '" + arr_time[0] + "'.\nAllowed values are unsigned integers.");

	if (!arr_time[1]) dt_date.setMinutes(0);
	else if (RE_NUM.exec(arr_time[1]))
		if (arr_time[1] < 60) dt_date.setMinutes(arr_time[1]);
		else return cal_error ("Invalid minutes value: '" + arr_time[1] + "'.\nAllowed range is 00-59.");
	else return cal_error ("Invalid minutes value: '" + arr_time[1] + "'.\nAllowed values are unsigned integers.");

	if (!arr_time[2]) dt_date.setSeconds(0);
	else if (RE_NUM.exec(arr_time[2]))
		if (arr_time[2] < 60) dt_date.setSeconds(arr_time[2]);
		else return cal_error ("Invalid seconds value: '" + arr_time[2] + "'.\nAllowed range is 00-59.");
	else return cal_error ("Invalid seconds value: '" + arr_time[2] + "'.\nAllowed values are unsigned integers.");

	dt_date.setMilliseconds(0);
	return dt_date;
}

function cal_error (str_message) {
	alert (str_message);
	return null;
}
<commit_msg>added ;<commit_after>// Title: Tigra Calendar
// URL: http://www.softcomplex.com/products/tigra_calendar/
// Version: 3.3 (American date format)
// Date: 09/01/2005 (mm/dd/yyyy)
// Note: Permission given to use this script in ANY kind of applications if
//    header lines are left unchanged.
// Note: Script consists of two files: calendar?.js and calendar.html

// if two digit year input dates after this year considered 20 century.
var NUM_CENTYEAR = 30;
// is time input control required by default
var BUL_TIMECOMPONENT = false;
// are year scrolling buttons required by default
var BUL_YEARSCROLL = true;

var calendars = [];
var RE_NUM = /^\-?\d+$/;

function calendar2(obj_target) {

	// assigning methods
	this.gen_date = cal_gen_date2;
	this.gen_time = cal_gen_time2;
	this.gen_tsmp = cal_gen_tsmp2;
	this.prs_date = cal_prs_date2;
	this.prs_time = cal_prs_time2;
	this.prs_tsmp = cal_prs_tsmp2;
	this.popup    = cal_popup2;

	// validate input parameters
	if (!obj_target)
		return cal_error("Error calling the calendar: no target control specified");
	if (obj_target.value == null)
		return cal_error("Error calling the calendar: parameter specified is not valid target control");
	this.target = obj_target;
	this.time_comp = BUL_TIMECOMPONENT;
	this.year_scroll = BUL_YEARSCROLL;
	this.context='/';

	// register in global collections
	this.id = calendars.length;
	calendars[this.id] = this;
}

function cal_popup2 (str_datetime) {
	if (str_datetime) {
		this.dt_current = this.prs_tsmp(str_datetime);
	}
	else {
		this.dt_current = this.prs_tsmp(this.target.value);
		this.dt_selected = this.dt_current;
	}
	if (!this.dt_current) return;

	var obj_calwindow = window.open(
		this.context +
		'/html/calendar.html?datetime=' + this.dt_current.valueOf()+ '&id=' + this.id,
		'Calendar', 'width=200,height='+(this.time_comp ? 215 : 190)+
		',status=no,resizable=no,top=200,left=200,dependent=yes,alwaysRaised=yes'
	);
	obj_calwindow.opener = window;
	obj_calwindow.focus();
}

// timestamp generating function
function cal_gen_tsmp2 (dt_datetime) {
	return(this.gen_date(dt_datetime) + ' ' + this.gen_time(dt_datetime));
}

// date generating function
function cal_gen_date2 (dt_datetime) {
	return (
		(dt_datetime.getMonth() < 9 ? '0' : '') + (dt_datetime.getMonth() + 1) + "/"
		+ (dt_datetime.getDate() < 10 ? '0' : '') + dt_datetime.getDate() + "/"
		+ dt_datetime.getFullYear()
	);
}
// time generating function
function cal_gen_time2 (dt_datetime) {
	return (
		(dt_datetime.getHours() < 10 ? '0' : '') + dt_datetime.getHours() + ":"
		+ (dt_datetime.getMinutes() < 10 ? '0' : '') + (dt_datetime.getMinutes()) + ":"
		+ (dt_datetime.getSeconds() < 10 ? '0' : '') + (dt_datetime.getSeconds())
	);
}

// timestamp parsing function
function cal_prs_tsmp2 (str_datetime) {
	// if no parameter specified return current timestamp
	if (!str_datetime)
		return (new Date());

	// if positive integer treat as milliseconds from epoch
	if (RE_NUM.exec(str_datetime))
		return new Date(str_datetime);

	// else treat as date in string format
	var arr_datetime = str_datetime.split(' ');
	return this.prs_time(arr_datetime[1], this.prs_date(arr_datetime[0]));
}

// date parsing function
function cal_prs_date2 (str_date) {

	var arr_date = str_date.split('/');

	if (arr_date.length != 3) return alert ("Invalid date format: '" + str_date + "'.\nFormat accepted is dd-mm-yyyy.");
	if (!arr_date[1]) return alert ("Invalid date format: '" + str_date + "'.\nNo day of month value can be found.");
	if (!RE_NUM.exec(arr_date[1])) return alert ("Invalid day of month value: '" + arr_date[1] + "'.\nAllowed values are unsigned integers.");
	if (!arr_date[0]) return alert ("Invalid date format: '" + str_date + "'.\nNo month value can be found.");
	if (!RE_NUM.exec(arr_date[0])) return alert ("Invalid month value: '" + arr_date[0] + "'.\nAllowed values are unsigned integers.");
	if (!arr_date[2]) return alert ("Invalid date format: '" + str_date + "'.\nNo year value can be found.");
	if (!RE_NUM.exec(arr_date[2])) return alert ("Invalid year value: '" + arr_date[2] + "'.\nAllowed values are unsigned integers.");

	var dt_date = new Date();
	dt_date.setDate(1);

	if (arr_date[0] < 1 || arr_date[0] > 12) return alert ("Invalid month value: '" + arr_date[0] + "'.\nAllowed range is 01-12.");
	dt_date.setMonth(arr_date[0]-1);

	if (arr_date[2] < 100) arr_date[2] = Number(arr_date[2]) + (arr_date[2] < NUM_CENTYEAR ? 2000 : 1900);
	dt_date.setFullYear(arr_date[2]);

	var dt_numdays = new Date(arr_date[2], arr_date[0], 0);
	dt_date.setDate(arr_date[1]);
	if (dt_date.getMonth() != (arr_date[0]-1)) return alert ("Invalid day of month value: '" + arr_date[1] + "'.\nAllowed range is 01-"+dt_numdays.getDate()+".");

	return (dt_date);
}

// time parsing function
function cal_prs_time2 (str_time, dt_date) {

	if (!dt_date) return null;
	var arr_time = String(str_time ? str_time : '').split(':');

	if (!arr_time[0]) dt_date.setHours(0);
	else if (RE_NUM.exec(arr_time[0]))
		if (arr_time[0] < 24) dt_date.setHours(arr_time[0]);
		else return cal_error ("Invalid hours value: '" + arr_time[0] + "'.\nAllowed range is 00-23.");
	else return cal_error ("Invalid hours value: '" + arr_time[0] + "'.\nAllowed values are unsigned integers.");

	if (!arr_time[1]) dt_date.setMinutes(0);
	else if (RE_NUM.exec(arr_time[1]))
		if (arr_time[1] < 60) dt_date.setMinutes(arr_time[1]);
		else return cal_error ("Invalid minutes value: '" + arr_time[1] + "'.\nAllowed range is 00-59.");
	else return cal_error ("Invalid minutes value: '" + arr_time[1] + "'.\nAllowed values are unsigned integers.");

	if (!arr_time[2]) dt_date.setSeconds(0);
	else if (RE_NUM.exec(arr_time[2]))
		if (arr_time[2] < 60) dt_date.setSeconds(arr_time[2]);
		else return cal_error ("Invalid seconds value: '" + arr_time[2] + "'.\nAllowed range is 00-59.");
	else return cal_error ("Invalid seconds value: '" + arr_time[2] + "'.\nAllowed values are unsigned integers.");

	dt_date.setMilliseconds(0);
	return dt_date;
}

function cal_error (str_message) {
	alert (str_message);
	return null;
}
<|endoftext|>