<commit_before>var debug = require('debug')('keystone:core:openDatabaseConnection');

module.exports = function openDatabaseConnection (callback) {

	var keystone = this;
	var mongoConnectionOpen = false;

	// support replica sets for mongoose
	if (keystone.get('mongo replica set')) {

		if (keystone.get('logger')) {
			console.log('\nWarning: using the `mongo replica set` option has been deprecated and will be removed in'
				+ ' a future version.\nInstead set the `mongo` connection string with your host details, e.g.'
				+ ' mongodb://username:password@host:port,host:port,host:port/database and set any replica set options'
				+ ' in `mongo options`.\n\nRefer to https://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html'
				+ ' for more details on the connection settings.');
		}

		debug('setting up mongo replica set');
		var replicaData = keystone.get('mongo replica set');
		var replica = '';

		var credentials = (replicaData.username && replicaData.password) ? replicaData.username + ':' + replicaData.password + '@' : '';

		replicaData.db.servers.forEach(function (server) {
			replica += 'mongodb://' + credentials + server.host + ':' + server.port + '/' + replicaData.db.name + ',';
		});

		var options = {
			auth: { authSource: replicaData.authSource },
			replset: {
				rs_name: replicaData.db.replicaSetOptions.rs_name,
				readPreference: replicaData.db.replicaSetOptions.readPreference,
			},
		};

		debug('connecting to replicate set');
		keystone.mongoose.connect(replica, options);

	} else {
		debug('connecting to mongo');
		keystone.mongoose.connect(keystone.get('mongo'), keystone.get('mongo options'));
	}

	keystone.mongoose.connection.on('error', function (err) {

		if (keystone.get('logger')) {
			console.log('------------------------------------------------');
			console.log('Mongo Error:\n');
			console.log(err);
		}

		if (mongoConnectionOpen) {
			if (err.name === 'ValidationError') return;
			throw err;
		} else {
			throw new Error('KeystoneJS (' + keystone.get('name') + ') failed to start - Check that you are running `mongod` in a separate process.');
		}

	}).on('open', function () {

		debug('mongo connection open');
		mongoConnectionOpen = true;

		var connected = function () {
			if (keystone.get('auto update')) {
				debug('applying auto update');
				keystone.applyUpdates(callback);
			} else {
				callback();
			}
		};

		if (keystone.sessionStorePromise) {
			keystone.sessionStorePromise.then(connected);
		} else {
			connected();
		}

	});

	return this;
};
<commit_msg>Ensuring initDatabase() is called before connecting the database<commit_after>var debug = require('debug')('keystone:core:openDatabaseConnection');

module.exports = function openDatabaseConnection (callback) {

	var keystone = this;
	var mongoConnectionOpen = false;

	// support replica sets for mongoose
	if (keystone.get('mongo replica set')) {

		if (keystone.get('logger')) {
			console.log('\nWarning: using the `mongo replica set` option has been deprecated and will be removed in'
				+ ' a future version.\nInstead set the `mongo` connection string with your host details, e.g.'
				+ ' mongodb://username:password@host:port,host:port,host:port/database and set any replica set options'
				+ ' in `mongo options`.\n\nRefer to https://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html'
				+ ' for more details on the connection settings.');
		}

		debug('setting up mongo replica set');
		var replicaData = keystone.get('mongo replica set');
		var replica = '';

		var credentials = (replicaData.username && replicaData.password) ? replicaData.username + ':' + replicaData.password + '@' : '';

		replicaData.db.servers.forEach(function (server) {
			replica += 'mongodb://' + credentials + server.host + ':' + server.port + '/' + replicaData.db.name + ',';
		});

		var options = {
			auth: { authSource: replicaData.authSource },
			replset: {
				rs_name: replicaData.db.replicaSetOptions.rs_name,
				readPreference: replicaData.db.replicaSetOptions.readPreference,
			},
		};

		debug('connecting to replica set');
		keystone.mongoose.connect(replica, options);

	} else {
		debug('connecting to mongo');
		keystone.initDatabase();
		keystone.mongoose.connect(keystone.get('mongo'), keystone.get('mongo options'));
	}

	keystone.mongoose.connection.on('error', function (err) {

		if (keystone.get('logger')) {
			console.log('------------------------------------------------');
			console.log('Mongo Error:\n');
			console.log(err);
		}

		if (mongoConnectionOpen) {
			if (err.name === 'ValidationError') return;
			throw err;
		} else {
			throw new Error('KeystoneJS (' + keystone.get('name') + ') failed to start - Check that you are running `mongod` in a separate process.');
		}

	}).on('open', function () {

		debug('mongo connection open');
		mongoConnectionOpen = true;

		var connected = function () {
			if (keystone.get('auto update')) {
				debug('applying auto update');
				keystone.applyUpdates(callback);
			} else {
				callback();
			}
		};

		if (keystone.sessionStorePromise) {
			keystone.sessionStorePromise.then(connected);
		} else {
			connected();
		}

	});

	return this;
};
<|endoftext|>


<commit_before>'use strict';

//TODO: image hjandling
//TODO: emoji handling
//TODO: sentiment analysis
//TODO: JSON to global data resource
//TODO: Demo ad hoc, sched notifications
//TODO: Add unsubscribe
//TODO: data collection
//TODO: find out why _ dont work any more

const _ = require('lodash');
const Script = require('smooch-bot').Script;
var pg = require('pg');
var Q = require("q");
var request = require("request");
var nlp = require("./nlp");
var newBot = require("./newBot");
var push = require("./push");
var logConv = require("./log").logConversation;
//var findSession = require("./sessionsearch");

const scriptRules = require('./script.json');

var msgLog = {
    smoochId: '',
    received: '',
    usermessage: '',
    role: '',
    message_id: '',
    sourcetype: '',
    receivedtime: '',
    responsemessage: '',
    responsetype: '',
    responsetime: ''
  };

  var know = [
      "do you know",
      "can you help",
      "do you have",
      "how does this app work",
      "how much time do you need",
      "how to open you",
      "what can you talk about",
      "what do you know"
    ];

  var job = [
    "what do you do",
    "how do you know",
    "job"
  ];

  var me = [
    "do you know me",
    "do you remember me"
  ];

  var name = [
    "who named you"
  ];

  var noanswer = [
    "can you hear me",
    "can you speak",
    "change your",
    "hurry",
    "talk faster",
    "do you drink",
    "do you eat"
  ];

function wait(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

module.exports = new Script({
    processing: {
        //prompt: (bot) => bot.say('Beep boop...'),
        receive: () => 'processing'
    },

    start: {
        receive: (bot) => {
            return bot.say('Hello!  I\'m A16, the Agile2016 EventBot Concierge.  To find out what I can help you with type MENU for options or KEY for Keywords.')
                .then(() => 'speak');
        }
    },

    speak: {
        receive: (bot, message) => {

            console.log("- bot message ", message);
            //If sent a thumbs up answer in kind
            var isMediaMessage = message.mediaType ? true : false;
            var questmark = (message.text === '?') ? true : false;

            let upperText = message.text.trim().toUpperCase();

            msgLog.smoochId = bot.userId;
            msgLog.received = message.received;
            msgLog.usermessage = message.text;
            msgLog.role = message.role;
            msgLog.message_id = message._id;
            msgLog.receivedtime = new Date();
            //this mess is my way around the fact that smooch completely
            //changes the structure of the message obj if it is a postback vs user entered text
            //console.log("===message.message",message.message);
            //switch to the inverse should be faster because it does not have to traverse the whole prototype chain
            switch (typeof message.message !== "undefined") {
              case true:
                  //This is appMaker - which means it is a postback
                  msgLog.sourcetype = message.action.type;
                break;
              default:
                // This is appUser - which means it is a message typed in by the user
                  msgLog.sourcetype = message.source.type;
                break;
            }

            //SK_ACCESS is a heroku config var that has the list of user/devices
            //smoochids for auth users to send ad hoc push conversations
            var authUsers = process.env.SK_ACCESS;
            //For ad hoc messages - scheduled messages are done differently in checkItems
            //-1 indicates that a user is not authorized to send broadcast messages
            if (upperText.substr(0,4) == '/SK ') {
              if (authUsers.indexOf(bot.userId) !== -1) {
                upperText = upperText.substr(0,3);
                newBot('adhoc',"ALERT: " + message.text.substr(4));
                //console.log("- ad hoc msg: ",message.text," authUser:  ",authUsers);
              } else {
                upperText = "NO_SK";
              }
            }

            function updateSilent() {
                switch (upperText) {
                    case "CONNECT ME":
                        console.log('- Special Case: CONNECT ME'); //turns off bot
                        return bot.setProp("silent", true);
                    case "/NOTIFY":
                        console.log('- Special Case: /NOTIFY'); //turns off bot
                        bot.say("I have notified the Agile2016 human team that you have requested help. They usually respond in less than 5 minutes during conference hours. You are now in live support mode and when you are ready to chat with me again tap the button or type /A16. %[Return](postback:/A16)").then(() => 'speak');
                        return bot.setProp("silent", true);
                    case "DISCONNECT":
                        console.log('- Special Case: DISCONNECT'); //turns bot back on
                        return bot.setProp("silent", false);
                    case "/A16":
                        console.log('- Special Case: /A16'); //turns bot back on
                        bot.say("A16 is back! I hope my human colleagues were able to help you.").then(() => 'speak');
                        return bot.setProp("silent", false);
                    default:
                        return Promise.resolve();
                }
            }

            function getSilent() {
                return bot.getProp("silent");
            }

            function processMessage(isSilent) {
                //console.log("- processMessage ", upperText, "isSilent set to ",isSilent);
                if (isSilent) {
                    return Promise.resolve("speak");
                }
                var promises = [];
                var source;
                var fulfillmentSpeech;
                var simplified;

                //if((upperText.indexOf("/") + upperText.indexOf("-")) > -1)  &&  {
                if (upperText === ("7/24" || "7/25" || "7/26" || "7/27" || "7/28" || "7/29" )) {
                  upperText = upperText.replace("/", " ");
                }

                //This is in case a user uses the bots name in a request
                //console.log("before a16 search ", upperText.indexOf("A16"), upperText.length);
                if ((upperText.indexOf("A16")  > -1)  && (upperText.length > 4)) {
                  //console.log("in a16 search");
                  upperText = upperText.replace("A16", "");
                }

                promises.push(nlp(upperText, bot.userId));

                Q.all(promises).then(function(responses) {
                    // response is the JSON from API.ai
                    responses.forEach(function(response) {
                        console.log("- In Q.all");
                        console.log("- Received result from API.ai",response);
                        source = response.result.source;
                        if (source && source !== 'agent')
                        {
                            console.log("- Q all not agent");
                            fulfillmentSpeech = response.result.fulfillment.speech;
                            simplified = response.result.parameters.simplified;
                        } else if (response.result.fulfillment.speech && source == 'agent') {
                          console.log("- Source is agent ", response.result);
                          fulfillmentSpeech = response.result.fulfillment.speech;
                          //Is is done to capture if it is using an agent that we set up on API.ai
                          //API.ai sends agent back if !== domains; wish they had a 3rd state
                          simplified = response.result.action;
                        }
                        console.log("- Process meesage set source to: ", source);
                        console.log("- Process meesage set fulfillmentSpeech to: ", fulfillmentSpeech);
                        console.log("- Process meesage set simplified to: ", simplified);

                        respondMessage(source, fulfillmentSpeech, simplified);
                    });
                }, function(error) {
                    console.log("===Q all error ", error);
                });
            }

            function respondMessage(source, fulfillmentSpeech, simplified){
                //these are answers that we intercept because we do not like the domain answers
                //and it does not appear that we can customize these items

                //answer and return converstaion directly - API auto-answers
                //for exceptions answer with JSON file
                if (fulfillmentSpeech && source === 'domains')
                {
                  switch (true) {
                    case (know.indexOf(simplified) >- 1):
                      console.log("-In domains, what do you know");
                      upperText = 'KNOW';
                      break;
                    case (job.indexOf(simplified)>-1):
                      console.log("- In domains, what do you do");
                      upperText = "JOB";
                      break;
                    case (me.indexOf(simplified)>-1):
                      console.log("- In domains, do you know me");
                      upperText = "ME";
                      break;
                    case (name.indexOf(simplified)>-1):
                    console.log("- in domains, who named you");
                      upperText = "NAME";
                      break;
                    case (noanswer.indexOf(simplified)>-1):
                      console.log("- In domains, do you eat");
                      //in these cases we want to return 'not something I know about'
                      upperText = "";
                      break;
                    default:
                      console.log("- In domains, switch default");
                      //evening is one of our keywords and also an answer in the small.talk domain
                      //as a synonym for 'good evening' which we want to keep
                      if (upperText == "EVENING") {break;}
                      //else let the domain answer be sent
                      msgLog.responsemessage = fulfillmentSpeech;
                      msgLog.responsetime = new Date();
                      msgLog.responsetype = 'API.AI Domain';

                      //for (var i = 0; i < 9000; i++) {
                        logConv(msgLog);
                      //}

                      return bot.say(fulfillmentSpeech).then(() => 'speak');
                  }
                }

                //API Agent answer (we built in api) want to return answer but split lines and queue
                if (fulfillmentSpeech && source === 'agent')
                    {
                        console.log("- In agent,",simplified);
                        msgLog.responsemessage = fulfillmentSpeech;
                        msgLog.responsetime = new Date;
                        msgLog.responsetype = 'API.AI/json';
                        //return bot.say(fulfillmentSpeech).then(() => 'speak');
                        upperText = simplified;
                        //var response = fulfillmentSpeech;
                    }

                //if it was answered by API then don't test it
                if (typeof response === 'undefined') {
                  //no agent, not JSON rules
                  if (!_.has(scriptRules, upperText))
                  {
                      console.log("- No match in Script.json ", upperText);
                      msgLog.responsemessage = upperText;
                      msgLog.responsetime = new Date();
                      msgLog.responsetype = 'No Match';
                      logConv(msgLog);
                      //TODO test for images and gif and treat those separately this is not working
                      //TODO check for text vs emoji and parrot back what user sent
                      if (isMediaMessage === true) {
                        return bot.say(`I'm sorry I don't know how to respond to media yet.  😳   Type MENU or KEY for a list of things I can help you with.`).then(() => 'speak');
                      } else {
                        return bot.say(`I'm sorry that is not something I know.  😳   Type MENU or KEY for a list of things I can help you with.`).then(() => 'speak');
                      }
                  }
                }

                //the if statement is for those answer that we still need the json file for
                //if (response) {} else {var response = scriptRules[upperText];}
                //console.log( require( "./config.json" ) );
                var response = scriptRules[upperText];
                var lines = response.split('\n');
                msgLog.responsemessage = response;
                msgLog.responsetime = new Date;
                msgLog.responsetype = 'JSON';
                //console.log("=== msgLog  obj",msgLog);
                logConv(msgLog);

                var p = Promise.resolve();
                _.each(lines, function(line) {
                    line = line.trim();
                    p = p.then(function() {
                        console.log("=== p line",line);
                        return wait(100).then(function() {
                            return bot.say(line);
                        });
                    });
                });
                return p.then(() => 'speak');
            }

            return updateSilent()
                .then(wait(500))
                .then(getSilent)
                .then(processMessage);
        }
    }
});
<commit_msg>bug: wrong info saved to responsemessage when answer not found<commit_after>'use strict';

//TODO: image hjandling
//TODO: emoji handling
//TODO: sentiment analysis
//TODO: JSON to global data resource
//TODO: Demo ad hoc, sched notifications
//TODO: Add unsubscribe
//TODO: data collection
//TODO: find out why _ dont work any more

const _ = require('lodash');
const Script = require('smooch-bot').Script;
var pg = require('pg');
var Q = require("q");
var request = require("request");
var nlp = require("./nlp");
var newBot = require("./newBot");
var push = require("./push");
var logConv = require("./log").logConversation;
//var findSession = require("./sessionsearch");

const scriptRules = require('./script.json');

var msgLog = {
    smoochId: '',
    received: '',
    usermessage: '',
    role: '',
    message_id: '',
    sourcetype: '',
    receivedtime: '',
    responsemessage: '',
    responsetype: '',
    responsetime: ''
  };

  var know = [
      "do you know",
      "can you help",
      "do you have",
      "how does this app work",
      "how much time do you need",
      "how to open you",
      "what can you talk about",
      "what do you know"
    ];

  var job = [
    "what do you do",
    "how do you know",
    "job"
  ];

  var me = [
    "do you know me",
    "do you remember me"
  ];

  var name = [
    "who named you"
  ];

  var noanswer = [
    "can you hear me",
    "can you speak",
    "change your",
    "hurry",
    "talk faster",
    "do you drink",
    "do you eat"
  ];

function wait(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

module.exports = new Script({
    processing: {
        //prompt: (bot) => bot.say('Beep boop...'),
        receive: () => 'processing'
    },

    start: {
        receive: (bot) => {
            return bot.say('Hello!  I\'m A16, the Agile2016 EventBot Concierge.  To find out what I can help you with type MENU for options or KEY for Keywords.')
                .then(() => 'speak');
        }
    },

    speak: {
        receive: (bot, message) => {

            console.log("- bot message ", message);
            //If sent a thumbs up answer in kind
            var isMediaMessage = message.mediaType ? true : false;
            var questmark = (message.text === '?') ? true : false;

            let upperText = message.text.trim().toUpperCase();

            msgLog.smoochId = bot.userId;
            msgLog.received = message.received;
            msgLog.usermessage = message.text;
            msgLog.role = message.role;
            msgLog.message_id = message._id;
            msgLog.receivedtime = new Date();
            //this mess is my way around the fact that smooch completely
            //changes the structure of the message obj if it is a postback vs user entered text
            //console.log("===message.message",message.message);
            //switch to the inverse should be faster because it does not have to traverse the whole prototype chain
            switch (typeof message.message !== "undefined") {
              case true:
                  //This is appMaker - which means it is a postback
                  msgLog.sourcetype = message.action.type;
                break;
              default:
                // This is appUser - which means it is a message typed in by the user
                  msgLog.sourcetype = message.source.type;
                break;
            }

            //SK_ACCESS is a heroku config var that has the list of user/devices
            //smoochids for auth users to send ad hoc push conversations
            var authUsers = process.env.SK_ACCESS;
            //For ad hoc messages - scheduled messages are done differently in checkItems
            //-1 indicates that a user is not authorized to send broadcast messages
            if (upperText.substr(0,4) == '/SK ') {
              if (authUsers.indexOf(bot.userId) !== -1) {
                upperText = upperText.substr(0,3);
                newBot('adhoc',"ALERT: " + message.text.substr(4));
                //console.log("- ad hoc msg: ",message.text," authUser:  ",authUsers);
              } else {
                upperText = "NO_SK";
              }
            }

            function updateSilent() {
                switch (upperText) {
                    case "CONNECT ME":
                        console.log('- Special Case: CONNECT ME'); //turns off bot
                        return bot.setProp("silent", true);
                    case "/NOTIFY":
                        console.log('- Special Case: /NOTIFY'); //turns off bot
                        bot.say("I have notified the Agile2016 human team that you have requested help. They usually respond in less than 5 minutes during conference hours. You are now in live support mode and when you are ready to chat with me again tap the button or type /A16. %[Return](postback:/A16)").then(() => 'speak');
                        return bot.setProp("silent", true);
                    case "DISCONNECT":
                        console.log('- Special Case: DISCONNECT'); //turns bot back on
                        return bot.setProp("silent", false);
                    case "/A16":
                        console.log('- Special Case: /A16'); //turns bot back on
                        bot.say("A16 is back! I hope my human colleagues were able to help you.").then(() => 'speak');
                        return bot.setProp("silent", false);
                    default:
                        return Promise.resolve();
                }
            }

            function getSilent() {
                return bot.getProp("silent");
            }

            function processMessage(isSilent) {
                //console.log("- processMessage ", upperText, "isSilent set to ",isSilent);
                if (isSilent) {
                    return Promise.resolve("speak");
                }
                var promises = [];
                var source;
                var fulfillmentSpeech;
                var simplified;

                //if((upperText.indexOf("/") + upperText.indexOf("-")) > -1)  &&  {
                if (upperText === ("7/24" || "7/25" || "7/26" || "7/27" || "7/28" || "7/29" )) {
                  upperText = upperText.replace("/", " ");
                }

                //This is in case a user uses the bots name in a request
                //console.log("before a16 search ", upperText.indexOf("A16"), upperText.length);
                if ((upperText.indexOf("A16")  > -1)  && (upperText.length > 4)) {
                  //console.log("in a16 search");
                  upperText = upperText.replace("A16", "");
                }

                promises.push(nlp(upperText, bot.userId));

                Q.all(promises).then(function(responses) {
                    // response is the JSON from API.ai
                    responses.forEach(function(response) {
                        console.log("- In Q.all");
                        console.log("- Received result from API.ai",response);
                        source = response.result.source;
                        if (source && source !== 'agent')
                        {
                            console.log("- Q all not agent");
                            fulfillmentSpeech = response.result.fulfillment.speech;
                            simplified = response.result.parameters.simplified;
                        } else if (response.result.fulfillment.speech && source == 'agent') {
                          console.log("- Source is agent ", response.result);
                          fulfillmentSpeech = response.result.fulfillment.speech;
                          //Is is done to capture if it is using an agent that we set up on API.ai
                          //API.ai sends agent back if !== domains; wish they had a 3rd state
                          simplified = response.result.action;
                        }
                        console.log("- Process meesage set source to: ", source);
                        console.log("- Process meesage set fulfillmentSpeech to: ", fulfillmentSpeech);
                        console.log("- Process meesage set simplified to: ", simplified);

                        respondMessage(source, fulfillmentSpeech, simplified);
                    });
                }, function(error) {
                    console.log("===Q all error ", error);
                });
            }

            function respondMessage(source, fulfillmentSpeech, simplified){
                //these are answers that we intercept because we do not like the domain answers
                //and it does not appear that we can customize these items

                //answer and return converstaion directly - API auto-answers
                //for exceptions answer with JSON file
                if (fulfillmentSpeech && source === 'domains')
                {
                  switch (true) {
                    case (know.indexOf(simplified) >- 1):
                      console.log("-In domains, what do you know");
                      upperText = 'KNOW';
                      break;
                    case (job.indexOf(simplified)>-1):
                      console.log("- In domains, what do you do");
                      upperText = "JOB";
                      break;
                    case (me.indexOf(simplified)>-1):
                      console.log("- In domains, do you know me");
                      upperText = "ME";
                      break;
                    case (name.indexOf(simplified)>-1):
                    console.log("- in domains, who named you");
                      upperText = "NAME";
                      break;
                    case (noanswer.indexOf(simplified)>-1):
                      console.log("- In domains, do you eat");
                      //in these cases we want to return 'not something I know about'
                      upperText = "";
                      break;
                    default:
                      console.log("- In domains, switch default");
                      //evening is one of our keywords and also an answer in the small.talk domain
                      //as a synonym for 'good evening' which we want to keep
                      if (upperText == "EVENING") {break;}
                      //else let the domain answer be sent
                      msgLog.responsemessage = fulfillmentSpeech;
                      msgLog.responsetime = new Date();
                      msgLog.responsetype = 'API.AI Domain';

                      //for (var i = 0; i < 9000; i++) {
                        logConv(msgLog);
                      //}

                      return bot.say(fulfillmentSpeech).then(() => 'speak');
                  }
                }

                //API Agent answer (we built in api) want to return answer but split lines and queue
                if (fulfillmentSpeech && source === 'agent')
                    {
                        console.log("- In agent,",simplified);
                        msgLog.responsemessage = fulfillmentSpeech;
                        msgLog.responsetime = new Date;
                        msgLog.responsetype = 'API.AI/json';
                        //return bot.say(fulfillmentSpeech).then(() => 'speak');
                        upperText = simplified;
                        //var response = fulfillmentSpeech;
                    }

                //if it was answered by API then don't test it
                if (typeof response === 'undefined') {
                  //no agent, not JSON rules
                  if (!_.has(scriptRules, upperText))
                  {
                      console.log("- No match in Script.json ", upperText);
                      msgLog.responsetime = new Date();
                      msgLog.responsetype = 'No Match';
                      logConv(msgLog);
                      //TODO test for images and gif and treat those separately this is not working
                      //TODO check for text vs emoji and parrot back what user sent
                      if (isMediaMessage === true) {
                        var msg = `I'm sorry I don't know how to respond to media yet.  😳   Type MENU or KEY for a list of things I can help you with.`
                      } else {
                        var msg = `I'm sorry that is not something I know.  😳   Type MENU or KEY for a list of things I can help you with.`
                      }
                      msgLog.responsemessage = msg;
                      return bot.say(msg).then(() => 'speak');
                  }
                }

                //the if statement is for those answer that we still need the json file for
                //if (response) {} else {var response = scriptRules[upperText];}
                //console.log( require( "./config.json" ) );
                var response = scriptRules[upperText];
                var lines = response.split('\n');
                msgLog.responsemessage = response;
                msgLog.responsetime = new Date;
                msgLog.responsetype = 'JSON';
                //console.log("=== msgLog  obj",msgLog);
                logConv(msgLog);

                var p = Promise.resolve();
                _.each(lines, function(line) {
                    line = line.trim();
                    p = p.then(function() {
                        console.log("=== p line",line);
                        return wait(100).then(function() {
                            return bot.say(line);
                        });
                    });
                });
                return p.then(() => 'speak');
            }

            return updateSilent()
                .then(wait(500))
                .then(getSilent)
                .then(processMessage);
        }
    }
});
<|endoftext|>


<commit_before>function dF(s){var s1=unescape(s.substr(0,s.length-1)); var t='';for(i=0;i<s1.length;i++)t+=String.fromCharCode(s1.charCodeAt(i)-s.substr(s.length-1,1));document.write(unescape(t));}

        var c = document.getElementById("c");
        var ctx = c.getContext("2d");
        //making the canvas full screen
        c.height = window.innerHeight;
        c.width = window.innerWidth;
        //chinese characters - taken from the unicode charset
        // next gen

var matrix = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789@#$%^&*()*&^%";

        //converting the string into an array of single characters

        //var matrix = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789@#$%^&*()*&^%";
        //var matrix = "01";
        //converting the string into an array of single characters
        matrix = matrix.split("");
        var font_size = 10;
        var columns = c.width/font_size; //number of columns for the rain
        //an array of drops - one per column
        var drops = [];
        //x below is the x coordinate
        //1 = y co-ordinate of the drop(same for every drop initially)
        for(var x = 0; x < columns; x++)
            drops[x] = 1;
        //drawing the characters
        function draw()
        {
            //Black BG for the canvas
            //translucent BG to show trail
            ctx.fillStyle = "rgba(0, 0, 0, 0.04)";
            ctx.fillRect(0, 0, c.width, c.height);
            ctx.fillStyle = "#0F0"; //green text
            ctx.font = font_size + "px arial";
            //looping over drops
            for(var i = 0; i < drops.length; i++)
            {
                //a random chinese character to print
                var text = matrix[Math.floor(Math.random()*matrix.length)];
                //x = i*font_size, y = value of drops[i]*font_size
                ctx.fillText(text, i*font_size, drops[i]*font_size);
                //sending the drop back to the top randomly after it has crossed the screen
                //adding a randomness to the reset to make the drops scattered on the Y axis
                if(drops[i]*font_size > c.height && Math.random() > 0.975)
                    drops[i] = 0;
                //incrementing Y coordinate
                drops[i]++;
            }
        }
        setInterval(draw, 35);
<commit_msg>raibow effect<commit_after>function dF(s){var s1=unescape(s.substr(0,s.length-1)); var t='';for(i=0;i<s1.length;i++)t+=String.fromCharCode(s1.charCodeAt(i)-s.substr(s.length-1,1));document.write(unescape(t));}

        var c = document.getElementById("c");
        var ctx = c.getContext("2d");
        //making the canvas full screen
        c.height = window.innerHeight;
        c.width = window.innerWidth;
        //chinese characters - taken from the unicode charset
        // next gen

var matrix = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789@#$%^&*()*&^%";

        //converting the string into an array of single characters

        //var matrix = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789@#$%^&*()*&^%";
        //var matrix = "01";
        //converting the string into an array of single characters
        matrix = matrix.split("");
        var font_size = 10;
        var columns = c.width/font_size; //number of columns for the rain
        //an array of drops - one per column
        var drops = [];
        //x below is the x coordinate
        //1 = y co-ordinate of the drop(same for every drop initially)
        for(var x = 0; x < columns; x++)
            drops[x] = 1;
        //drawing the characters
        function draw()
        {
            //Black BG for the canvas
            //translucent BG to show trail
            ctx.fillStyle = "rgba(0, 0, 0, 0.04)";
            ctx.fillRect(0, 0, c.width, c.height);

        // Rainbow
            ctx.fillStyle = (function(m,s,c){return (c ? arguments.callee(m,s,c-1) : '#') + s[m.floor(m.random() * s.length)]})(Math,'0123456789ABCDEF',5);

            //ctx.fillStyle = "#0F0"; //green text
            ctx.font = font_size + "px arial";
            //looping over drops
            for(var i = 0; i < drops.length; i++)
            {
                //a random chinese character to print
                var text = matrix[Math.floor(Math.random()*matrix.length)];
                //x = i*font_size, y = value of drops[i]*font_size
                ctx.fillText(text, i*font_size, drops[i]*font_size);
                //sending the drop back to the top randomly after it has crossed the screen
                //adding a randomness to the reset to make the drops scattered on the Y axis
                if(drops[i]*font_size > c.height && Math.random() > 0.975)
                    drops[i] = 0;
                //incrementing Y coordinate
                drops[i]++;
            }
        }
        setInterval(draw, 100);
        window.onload = function() {
            var backgroundAudio=document.getElementById("audio");
            backgroundAudio.volume = 0.1;
        }<|endoftext|>


<commit_before>(function() {
    var wikiButtonsDiv = document.querySelector('.wiki-buttons');
    var buttons = {
        'clear': {
            'text': 'Clear selection',
            'onClick': function() {
                document.querySelectorAll('.wiki-button input').forEach(function(b) {
                    b.checked = false;
                });
            }
        },
        'selectAll': {
            'text': 'Select all',
            'onClick': function() {
                document.querySelectorAll('.wiki-button input').forEach(function(b) {
                    b.checked = true;
                });
            }
        },
        'selectAllFull': {
            'text': 'Select full wikis',
            'onClick': function() {
                document.querySelectorAll('.wiki-button input').forEach(function(b) {
                    b.checked = b.matches('.wiki-type-full input');
                });
            }
        },
        'selectAllAlpha': {
            'text': 'Select alpha wikis',
            'onClick': function() {
                document.querySelectorAll('.wiki-button input').forEach(function(b) {
                    b.checked = b.matches('.wiki-type-alpha input');
                });
            }
        }
    };
    var helpersDiv = document.createElement('div');
    helpersDiv.setAttribute('class', 'wiki-buttons-helpers');
    wikiButtonsDiv.after(div);
    var button;
    for (var i in buttons)
    {
        button = document.createElement('button');
        button.setAttribute('type','button');
        button.innerHTML = buttons[i].text;
        button.addEventListener('click', buttons[i].onClick);
        helpersDiv.append(button);
    }
})();<commit_msg>Fixing a small error<commit_after>(function() {
    var wikiButtonsDiv = document.querySelector('.wiki-buttons');
    var buttons = {
        'clear': {
            'text': 'Clear selection',
            'onClick': function() {
                document.querySelectorAll('.wiki-button input').forEach(function(b) {
                    b.checked = false;
                });
            }
        },
        'selectAll': {
            'text': 'Select all',
            'onClick': function() {
                document.querySelectorAll('.wiki-button input').forEach(function(b) {
                    b.checked = true;
                });
            }
        },
        'selectAllFull': {
            'text': 'Select full wikis',
            'onClick': function() {
                document.querySelectorAll('.wiki-button input').forEach(function(b) {
                    b.checked = b.matches('.wiki-type-full input');
                });
            }
        },
        'selectAllAlpha': {
            'text': 'Select alpha wikis',
            'onClick': function() {
                document.querySelectorAll('.wiki-button input').forEach(function(b) {
                    b.checked = b.matches('.wiki-type-alpha input');
                });
            }
        }
    };
    var helpersDiv = document.createElement('div');
    helpersDiv.setAttribute('class', 'wiki-buttons-helpers');
    wikiButtonsDiv.after(helpersDiv);
    var button;
    for (var i in buttons)
    {
        button = document.createElement('button');
        button.setAttribute('type','button');
        button.innerHTML = buttons[i].text;
        button.addEventListener('click', buttons[i].onClick);
        helpersDiv.append(button);
    }
})();<|endoftext|>


<commit_before>'use strict';

const Script = require('smooch-bot').Script;

module.exports = new Script({
    processing: {
        prompt: (bot) => bot.say('101100111001101...'),
        receive: () => 'processing'
    },

    start: {
        receive: (bot) => {
            return bot.say('Wenn Andreas gerade online ist, sieht er dieses Gespräch und kann beitreten.')
                .then(() => 'vorname');
        }
    },

    vorname: {
        prompt: (bot) => bot.say('Wie heissen Sie mit Vornamen?'),
        receive: (bot, message) => {
            var vorname = message.text;
            return bot.setProp('vorname', vorname)
                .then(() => bot.say(`${vorname}, prima.`))
                .then(() => 'nachname');
        }
    },

    nachname: {
        prompt: (bot) => bot.say('Und mit Nachnamen?'),
        receive: (bot, message) => {
            var nachname = message.text;
            return bot.setProp('nachname', nachname)
                .then(() => bot.say(`${nachname}, danke.`))
                .then(() => bot.say('Sie können hier jederzeit eine Nachricht an Andreas eingeben.'))
                .then(() => bot.say('Unterhalten Sie sich solange mit mir! Bitte schreiben Sie --bot:'))
                .then(() => 'register');
        }
    },

    register: {
        receive: (bot, message) => {

            var wollen = message.text;
            var befehl = wollen;
            befehl = befehl.trim();
            befehl = befehl.toUpperCase();

         // System
            if (befehl == "--BOT")          { bot.say('Andreas hat mir viel beigebracht - Sie können das durch Schreiben der mit -- beginnenden Wörter abrufen!'); }
            if (befehl == "--BOT")          { bot.say('Wollen Sie etwas über seine --Person oder --Neues von ihm erfahren? Oder auf anderem Wege --Kontakt  aufnehmen?'); }
            if (befehl == "--ABBRECHEN")    { bot.say('Text: Abbruch.'); }

         // Über mich
            if (befehl == "--PERSON")       { bot.say('Text: Person; Links: --Lebenslauf, --Foto.'); }
            if (befehl == "--LEBENSLAUF")   { bot.say('Text: Lebenslauf. %[Lebenslauf öffnen](http://sefzig.net/link/Lebenslauf/)'); }
            if (befehl == "--FOTO")         { bot.say('[Bild:http://sefzig.net/text/seiten/SefzignetStartseite/dateien/SefzignetStartseiteFotoLogos.png]'); }
            if (befehl == "--NEUES")        { bot.say('Text: Neues.'); }

         // Kontakt
            if (befehl == "--KONTAKT")      { bot.say('Text: Kontakt mit Webseite; Links: --Twitter, --Slackteam, --Xing. %[Kontakt-Seite öffnen](http://sefzig.net/link/Kontakt/)'); }
            if (befehl == "--SLACKTEAM")    { bot.say('Text: Offenes Slack-Team. %[Offenes Slack-Team](http://sefzig.net/link/Slack/)'); }
            if (befehl == "--XING")         { bot.say('Andreas ist Mitglied bei Xing: %[Xing-Profil ansehen](http://sefzig.net/link/Xing/)'); }
            if (befehl == "--TWITTER")      { bot.say('Andreas ist auf Twitter: %[Twitter-Profil öffnen](http://sefzig.net/link/Twitter/)'); }

         // Vorlage
            if (befehl == "--VORLAGE")      { bot.say('Text: Vorlage.'); }

            return bot.setProp('wollen', wollen)
                .then(() => 'register');
        }
    },

    finish: {
        receive: (bot, message) => {
            return bot.getProp('name')
                .then(() => 'finish');
        }
    }
});
<commit_msg>Tests<commit_after>'use strict';

const Script = require('smooch-bot').Script;

module.exports = new Script({
    processing: {
        prompt: (bot) => bot.say('101100111001101...'),
        receive: () => 'processing'
    },

    start: {
        receive: (bot) => {
            return bot.say('Wenn Andreas gerade online ist, sieht er dieses Gespräch und kann beitreten.')
                .then(() => 'vorname');
        }
    },

    vorname: {
        prompt: (bot) => bot.say('Wie heissen Sie mit Vornamen?'),
        receive: (bot, message) => {
            var vorname = message.text;
            return bot.setProp('vorname', vorname)
                .then(() => bot.say(`${vorname}, prima.`))
                .then(() => 'nachname');
        }
    },

    nachname: {
        prompt: (bot) => bot.say('Und mit Nachnamen?'),
        receive: (bot, message) => {
            var nachname = message.text;
            return bot.setProp('nachname', nachname)
                .then(() => bot.say(`${nachname}, danke.`))
                .then(() => bot.say('Sie können hier jederzeit eine Nachricht an Andreas eingeben.'))
                .then(() => bot.say('Unterhalten Sie sich solange mit mir! Bitte schreiben Sie --bot:'))
                .then(() => 'register');
        }
    },

    register: {
        receive: (bot, message) => {

            var wollen = message.text;
            var befehl = wollen;
            befehl = befehl.trim();
            befehl = befehl.toUpperCase();

         // System
            if (befehl == "--BOT")          { bot.say('Andreas hat mir viel beigebracht - Sie können das durch Schreiben der mit -- beginnenden Wörter abrufen!'); }
            if (befehl == "--BOT")          { bot.say('Wollen Sie etwas über seine --Person oder --Neues von ihm erfahren? Oder auf anderem Wege --Kontakt  aufnehmen?'); }
            if (befehl == "--ABBRECHEN")    { bot.say('Text: Abbruch.'); }

         // Über mich
            if (befehl == "--PERSON")       { bot.say('Text: Person; Links: --Lebenslauf, --Foto.'); }
            if (befehl == "--LEBENSLAUF")   { bot.say('Text: Lebenslauf. %[Lebenslauf öffnen](http://sefzig.net/link/Lebenslauf/)'); }
            if (befehl == "--FOTO")         { bot.say('[Bild:http://sefzig.net/text/seiten/SefzignetStartseite/dateien/SefzignetStartseiteFotoLogos.png]'); }
            if (befehl == "--NEUES")        { bot.say('Text: Neues.'); }

         // Kontakt
            if (befehl == "--KONTAKT")      { bot.say('Text: Kontakt mit Webseite; Links: --Twitter, --Slackteam, --Xing. %[Kontakt-Seite öffnen](http://sefzig.net/link/Kontakt/)'); }
            if (befehl == "--SLACKTEAM")    { bot.say('Andreas betreibt ein offenes Slack-Team, in dem man sich über Marketing-Technologie unterhält. %[Offenes Slack-Team öffnen](http://sefzig.net/link/Slack/)'); }
            if (befehl == "--XING")         { bot.say('Andreas ist Xing: Er ist seit 2004 angemeldet und gehört mit über 500 Kontakten zu den 5% der bestvernetzten Mitglieder. %[Xing-Profil ansehen](http://sefzig.net/link/Xing/)'); bot.say('[Bild:http://sefzig.net/text/seiten/SefzigBot/dateien/xing_vernetzt.png]'); }
            if (befehl == "--TWITTER")      { bot.say('Andreas ist auf Twitter: %[Twitter-Profil öffnen](http://sefzig.net/link/Twitter/)'); }

         // Vorlage
            if (befehl == "--VORLAGE")      { bot.say('Text: Vorlage.'); }

            return bot.setProp('wollen', wollen)
                .then(() => 'register');
        }
    },

    finish: {
        receive: (bot, message) => {
            return bot.getProp('name')
                .then(() => 'finish');
        }
    }
});
<|endoftext|>


<commit_before>'use strict'

const net = require('net');

function split(str, sep, n) {
    if (sep === undefined) { sep = ' '; }
    if (n === undefined) { n = 1; }
    var items = [];
    while (n-- > 0 && str.length > 0) {
        var index = str.indexOf(sep);
        var item = str.substring(0, index);
        str = str.substring(index+1);
        items.push(item);
    }
    if (str.length > 0) items.push(str);
    return items;
}

function event() {
    var subscribers = {};
    var nextId = 0;
    return {
        subscribe: function (handler, predicate) {
            var ids = [];
            var unsubscriber = function () {
                for (var ind in ids) {
                    delete subscribers[ids[ind]];
                }
            };
            unsubscriber.subscribe = function (handler, predicate) {
                var id = nextId++;
                ids.push(id);
                subscribers[id] = {
                    handler: handler,
                    predicate: predicate || (() => true)
                };
                return this;
            };
            unsubscriber.subscribe(handler, predicate);
            return unsubscriber;
        },
        notify: function () {
            for (var id in subscribers) {
                var subscriber = subscribers[id];
                if (subscriber.predicate.apply(null, arguments)) {
                    subscriber.handler.apply(null, arguments);
                }
            }
        }
    };
}

class IrcClient {
    constructor(host, port) {
        var socket = new net.Socket();
        socket.setEncoding('ascii');
        socket.connect({
            host: host,
            port: port
        });
        socket.on('data', data => this.receiveData(data));

        this.socket = socket;
        this.buffer = '';
        this.recvEvent = event();
    }

    subscribe(target, handler) {
        var predicate;
        switch (typeof(target)) {
            case 'string':
                predicate = (msg, pre, cmd) => target === cmd;
                break;
            case 'object':
                predicate = (msg, pre, cmd) => target.includes(cmd);
                break;
            default:
                predicate = target;
                break;
        }
        this.recvEvent.subscribe(handler, predicate);
        return this;
    }

    sendMessage(message) {
        console.log(`<<< ${message}`);
        this.socket.write(message + '\r\n');
        return this;
    }

    sendCommand() {
        var args = Array.apply(null, arguments);
        this.sendMessage(args.join(' '));
        return this;
    }

    receiveData(data) {
        this.buffer += data;
        var index;
        while (this.buffer.length > 0 && (index = this.buffer.indexOf('\n')) !== -1) {
            var message = this.buffer.substring(0, index);
            this.buffer = this.buffer.substring(index+1);
            this.receiveMessage(message);
        }
    }

    receiveMessage(message) {
        console.log(`>>> ${message}`);

        var res = split(message);
        var token = res[0];
        message = res[1];
        var prefix, command;
        if (token[0] === ':') {
            prefix = token;
            res = split(message);
            command = res[0];
            message = res[1];
        } else {
            prefix = null;
            command = token;
        }

        this.recvEvent.notify(message, prefix, command);
    }
}

function makeUser(mask) {
    var res = split(mask, '!');
    var nick = res[0].substring(1);
    res = split(res[1], '@');
    var span = document.createElement('span');
    span.innerText = nick;
    span.className = 'tooltip';
    var tooltip = document.createElement('span');
    tooltip.innerText = mask;
    tooltip.className = 'tooltiptext';
    span.appendChild(tooltip);
    return {
        mask: mask,
        nick: nick,
        user: res[0].substring(1),
        domain: res[1],
        span: span
    };
}

class Client {
    constructor(container) {
        var form = document.createElement('form');
        form.className = 'client';
        var output = document.createElement('div');
        output.className = 'client-output';
        output.disabled = true;
        form.appendChild(output);
        var input = document.createElement('input');
        input.className = 'client-input';
        input.autofocus = true;
        input.placeholder = 'JOIN #channel';
        form.appendChild(input);
        form.onsubmit = () => this.sendMessage();
        container.appendChild(form);

        var client = new IrcClient('chat.freenode.net', 6667);
        client
            .subscribe('PING', msg => {
                client.sendCommand('PONG', msg);
            })
            .subscribe('NOTICE', msg => {
                var res = split(msg);
                var recipient = res[0];
                var message = res[1].substring(1);
                this.writeMessage(message);
            })
            // .subscribe(['001', '002', '003'], msg => { // Welcome
            //     var res = split(msg);
            //     var message = res[1].substring(1);
            //     this.writeMessage(message);
            // })
            // .subscribe(['004', '005'], msg => { // info
            //     var res = split(msg);
            //     var message = res[1];
            //     this.writeMessage(message);
            // })
            .subscribe(['353', '366'], msg => { // NAMES
                var res = split(msg, ' ', 2);
                var message = res[2];
                this.writeMessage(message);
            })
            .subscribe(['432', '433', '451'], msg => { // ERR_NICKNAMEINUSE
                var res = split(msg);
                var message = res[1];
                this.writeMessage(message);
            })
            .subscribe(['704', '705', '706'], msg => { // HELP
                var res = split(msg, ' ', 2);
                var msg = res[2].substring(1).trim();
                if (msg !== '') this.writeMessage(msg);
            })
            .subscribe('QUIT', (msg, pre) => {
                var user = makeUser(pre);
                this.writeMessage(user.span, ` has quit: ${msg.substring(1)}`);
            })
            .subscribe('JOIN', (msg, pre) => {
                var user = makeUser(pre);
                this.writeMessage(user.span, ` has joined ${msg}`);
            })
            .subscribe('PART', (msg, pre) => {
                var user = makeUser(pre);
                this.writeMessage(user.span, ` has left ${msg}`);
            })
            .subscribe('NICK', (msg, pre) => {
                var user = makeUser(pre);
                this.writeMessage(user.span, ` has changed nicknames to ${msg}`);
            })
            .subscribe('PRIVMSG', (msg, pre) => {
                var res = split(msg);
                var channel = res[0];
                var message = res[1].substring(1);
                var user = makeUser(pre);
                this.writeMessage(`${channel}: `, user.span, `: ${message}`);
            });
        client
            .sendCommand('PASS', 'curtispassword')
            .sendCommand('NICK', 'curtis52')
            .sendCommand('USER', 'curtis52', '0', '*', 'curtis');

        this.form = form;
        this.input = input;
        this.output = output;
        this.client = client;
    }

    sendMessage() {
        var message = this.input.value;
        this.input.value = '';

        this.client.sendMessage(message);
        return false;
    }

    writeMessage() {
        if (arguments.length === 1 && arguments[0] === '') {
            console.log('empty');
        }
        var elem = document.createElement('div');
        for (var ind in arguments) {
            var argument = arguments[ind];
            elem.appendChild(argument instanceof HTMLElement ? argument : document.createTextNode(argument));
        }
        return this.writeElement(elem);
    }

    writeElement(elem) {
        var scrollToBottom = this.output.scrollTop + this.output.clientHeight + 1 >= this.output.scrollHeight;

        var container = document.createElement('div');
        container.className = 'client-message';
        var date = document.createElement('div');
        date.innerText = new Date().toLocaleTimeString();
        date.className = 'client-message-timestamp';
        container.appendChild(date);
        container.appendChild(elem);
        this.output.appendChild(container);

        if (scrollToBottom) { this.output.scrollTop = this.output.scrollHeight; }
        return this;
    }
}<commit_msg>Cleanup<commit_after>'use strict'

const net = require('net');

/**
 * Split a string with the given separator at most n times.
 * @param {str} The string to split.
 * @param {sep} The separator to split on.
 * @param {n} The maximum number of splits to make.
 * @return An array of substrings.
 */
function split(str, sep, n) {
    if (sep === undefined) { sep = ' '; }
    if (n === undefined) { n = 1; }
    var items = [];
    while (n-- > 0 && str.length > 0) {
        var index = str.indexOf(sep);
        var item = str.substring(0, index);
        str = str.substring(index+sep.length);
        items.push(item);
    }
    if (str.length > 0) items.push(str);
    return items;
}

/**
 * Create a new event. The event has a subscribe method and a notify method.
 *
 * The subscribe method returns a callable which will unsubscribe when called,
 * and can also have its subscribe method called to make further subscriptions.
 * The subscribe methods take two function handles, the first is the callback
 * which is called when the event is notified, the second is a predicate which
 * must return true if the callback is to be invoked. The second argument is
 * optional, if missing the callback is always called.
 *
 * The notify method takes any number of arguments and notifies all subscribers
 * by calling the predicate and callback functions with the supplied arguments.
 *
 * @return A new event.
 */
function event() {
    var subscribers = {};
    var nextId = 0;
    return {
        subscribe: function (handler, predicate) {
            var ids = [];
            var unsubscriber = function () {
                for (var ind in ids) {
                    delete subscribers[ids[ind]];
                }
            };
            unsubscriber.subscribe = function (handler, predicate) {
                var id = nextId++;
                ids.push(id);
                subscribers[id] = {
                    handler: handler,
                    predicate: predicate || (() => true)
                };
                return this;
            };
            unsubscriber.subscribe(handler, predicate);
            return unsubscriber;
        },
        notify: function () {
            for (var id in subscribers) {
                var subscriber = subscribers[id];
                if (subscriber.predicate.apply(null, arguments)) {
                    subscriber.handler.apply(null, arguments);
                }
            }
        }
    };
}

/**
 * A class representing an IRC client. Allows sending and receiving of messages
 * to/from an IRC server.
 */
class IrcClient {
    /**
     * Create a new IRC client.
     * @param {host} The hostname of the server to connect to.
     * @param {port} The port number of the server to connect to.
     */
    constructor(host, port) {
        var socket = new net.Socket();
        socket.setEncoding('ascii');
        socket.connect({
            host: host,
            port: port
        });
        socket.on('data', data => this.receiveData(data));

        this.socket = socket;
        this.buffer = '';
        this.recvEvent = event();
    }

    /**
     * Subscribe to messages received by the IRC server.
     * @param {target} The target message/s to subscribe to. If a string,
     *     matches messages of the supplied command. If a list, matches
     *     messages of any of the supplied commands. If a predicate, matches
     *     messages whose command satisfies the predicate.
     * @param {handler} The callback function. Receives the message, prefix and
     *     command.
     * @return A callable to unsubscribe.
     */
    subscribe(target, handler) {
        var predicate;
        switch (typeof(target)) {
            case 'string':
                predicate = (msg, pre, cmd) => target === cmd;
                break;
            case 'object':
                predicate = (msg, pre, cmd) => target.includes(cmd);
                break;
            default:
                predicate = target;
                break;
        }
        this.recvEvent.subscribe(handler, predicate);
        return this;
    }

    /**
     * Send a message to the IRC server.
     * @param {message} The message to send.
     */
    sendMessage(message) {
        console.log(`<<< ${message}`);
        this.socket.write(message + '\r\n');
        return this;
    }

    /**
     * Send a command to the IRC server, by joining the array of arguments
     * with spaces.
     * @param {arguments} The arguments that make up the command.
     */
    sendCommand() {
        var args = Array.apply(null, arguments);
        this.sendMessage(args.join(' '));
        return this;
    }

    receiveData(data) {
        this.buffer += data;
        var index;
        while (this.buffer.length > 0 && (index = this.buffer.indexOf('\n')) !== -1) {
            var message = this.buffer.substring(0, index);
            this.buffer = this.buffer.substring(index+1);
            this.receiveMessage(message);
        }
    }

    receiveMessage(message) {
        console.log(`>>> ${message}`);

        var res = split(message);
        var token = res[0];
        message = res[1];
        var prefix, command;
        if (token[0] === ':') {
            prefix = token;
            res = split(message);
            command = res[0];
            message = res[1];
        } else {
            prefix = null;
            command = token;
        }

        this.recvEvent.notify(message, prefix, command);
    }
}

/**
 * Parse the given user mask to create a user object.
 * @param {mask} The user mask.
 * @return A user object containing the mask, nick, user, domain and a HTML
 *     span.
 */
function makeUser(mask) {
    var res = split(mask, '!');
    var nick = res[0].substring(1);
    res = split(res[1], '@');
    var span = document.createElement('span');
    span.innerText = nick;
    span.className = 'tooltip';
    var tooltip = document.createElement('span');
    tooltip.innerText = mask;
    tooltip.className = 'tooltiptext';
    span.appendChild(tooltip);
    return {
        mask: mask,
        nick: nick,
        user: res[0].substring(1),
        domain: res[1],
        span: span
    };
}

class Client {
    constructor(container) {
        var form = document.createElement('form');
        form.className = 'client';
        var output = document.createElement('div');
        output.className = 'client-output';
        output.disabled = true;
        form.appendChild(output);
        var input = document.createElement('input');
        input.className = 'client-input';
        input.autofocus = true;
        input.placeholder = 'JOIN #channel';
        form.appendChild(input);
        form.onsubmit = () => this.sendMessage();
        container.appendChild(form);

        var client = new IrcClient('chat.freenode.net', 6667);
        client
            .subscribe('PING', msg => {
                client.sendCommand('PONG', msg);
            })
            .subscribe('NOTICE', msg => {
                var res = split(msg);
                var recipient = res[0];
                var message = res[1].substring(1);
                this.writeMessage(message);
            })
            // .subscribe(['001', '002', '003'], msg => { // Welcome
            //     var res = split(msg);
            //     var message = res[1].substring(1);
            //     this.writeMessage(message);
            // })
            // .subscribe(['004', '005'], msg => { // info
            //     var res = split(msg);
            //     var message = res[1];
            //     this.writeMessage(message);
            // })
            .subscribe(['353', '366'], msg => { // NAMES
                var res = split(msg, ' ', 2);
                var message = res[2];
                this.writeMessage(message);
            })
            .subscribe(['432', '433', '451'], msg => { // ERR_NICKNAMEINUSE
                var res = split(msg);
                var message = res[1];
                this.writeMessage(message);
            })
            .subscribe(['704', '705', '706'], msg => { // HELP
                var res = split(msg, ' ', 2);
                var msg = res[2].substring(1).trim();
                if (msg !== '') this.writeMessage(msg);
            })
            .subscribe('QUIT', (msg, pre) => {
                var user = makeUser(pre);
                this.writeMessage(user.span, ` has quit: ${msg.substring(1)}`);
            })
            .subscribe('JOIN', (msg, pre) => {
                var user = makeUser(pre);
                this.writeMessage(user.span, ` has joined ${msg}`);
            })
            .subscribe('PART', (msg, pre) => {
                var user = makeUser(pre);
                this.writeMessage(user.span, ` has left ${msg}`);
            })
            .subscribe('NICK', (msg, pre) => {
                var user = makeUser(pre);
                this.writeMessage(user.span, ` has changed nicknames to ${msg}`);
            })
            .subscribe('PRIVMSG', (msg, pre) => {
                var res = split(msg);
                var channel = res[0];
                var message = res[1].substring(1);
                var user = makeUser(pre);
                this.writeMessage(`${channel}: `, user.span, `: ${message}`);
            });
        client
            .sendCommand('PASS', 'curtispassword')
            .sendCommand('NICK', 'curtis52')
            .sendCommand('USER', 'curtis52', '0', '*', 'curtis');

        this.form = form;
        this.input = input;
        this.output = output;
        this.client = client;
    }

    sendMessage() {
        var message = this.input.value;
        this.input.value = '';

        this.client.sendMessage(message);
        return false;
    }

    writeMessage() {
        if (arguments.length === 1 && arguments[0] === '') {
            console.log('empty');
        }
        var elem = document.createElement('div');
        for (var ind in arguments) {
            var argument = arguments[ind];
            elem.appendChild(argument instanceof HTMLElement ? argument : document.createTextNode(argument));
        }
        return this.writeElement(elem);
    }

    writeElement(elem) {
        var scrollToBottom = this.output.scrollTop + this.output.clientHeight + 1 >= this.output.scrollHeight;

        var container = document.createElement('div');
        container.className = 'client-message';
        var date = document.createElement('div');
        date.innerText = new Date().toLocaleTimeString();
        date.className = 'client-message-timestamp';
        container.appendChild(date);
        container.appendChild(elem);
        this.output.appendChild(container);

        if (scrollToBottom) { this.output.scrollTop = this.output.scrollHeight; }
        return this;
    }
}<|endoftext|>


<commit_before>'use strict';

const _ = require('lodash');
const Script = require('smooch-bot').Script;
var pg = require('pg');
var Q = require("q");
var request = require("request");

const scriptRules = require('./script.json');

function wait(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

//move to separeate file
var promises = [];
function nlp(query,sessionId){
	var deferred = Q.defer();
	var options = {
		"method" : "POST",
		"url" : "https://api.api.ai/v1/query?v=20150910",
		"json" : {
			"query" : query,
			"lang" : "en",
			"sessionId" : sessionId
		},
		"headers" : {
			"Authorization" : "Bearer " + process.env.API_AI_TOKEN,
			"Content-Type" : "application/json"
		}
	};

	console.log("===nlp");
	console.log("===query: ",query);
	console.log("===sessionId",sessionId);
	request(options,function(err,response,body){
		if(err){
			console.log("===nlp failed because: ",err.message);
			deferred.reject(err);
		}else{
			body.sessionId = sessionId;
			if(response.statusCode == 200){
				console.log("===nlp succeeded ");
				deferred.resolve(body);
			}else{
				deferred.reject(body);
			}
		}
	});
	return deferred.promise;
}

module.exports = new Script({
    processing: {
        //prompt: (bot) => bot.say('Beep boop...'),
        receive: () => 'processing'
    },

    start: {
        receive: (bot) => {
            return bot.say('Get started by saying BOT.')
                .then(() => 'speak');
        }
    },

    speak: {
        receive: (bot, message) => {
            console.log("===bot user ",bot.userId);
            let upperText = message.text.trim().toUpperCase();

            pg.defaults.ssl = true;
            pg.connect(process.env.DATABASE_URL, function(err,client){
                if (err) throw err;
                console.log('====Connected to postgres!!!!!');

                client
                    .query('insert into Attendees (SmoochId, Unsubscribed, UnsubscribedDate, CreatedDate) values ($1,$2, null, CURRENT_TIMESTAMP);', [bot.userId, 'f'],
                    function(err,result) {
                        if (err) {
                            if (err.code == '23505'){
                                console.log("===user already exists: ", bot.userId);
                            }
                            else{
                                console.log("===Unknown error: ", err);
                            }
                        } else {
                            console.log(JSON.stringify(result.rows[0]));
                        }
                    });
            });

            function updateSilent() {
                switch (upperText) {
                    case "CONNECT ME":
                        return bot.setProp("silent", true);
                    case "DISCONNECT":
                        return bot.setProp("silent", false);
                    default:
                        return Promise.resolve();
                }
            }

            function getSilent() {
                return bot.getProp("silent");
            }

            function processMessage(isSilent) {
                if (isSilent) {
                    return Promise.resolve("speak");
                }

                promises.push(nlp(upperText, bot.userId));

                Q.all(promises).then(function(responses) {
                    // response is the JSON from API.ai
                    responses.forEach(function(response) {
                        console.log("===received result from API.ai",response);
                        var userSaid = response.result.resolvedQuery;
                        console.log("===user sent",userSaid);
                        afterNlp(response);
                    });
                }, function(error) {
                    console.log("[webhook_post.js]", error);
                });
                return next();

                if (!_.has(scriptRules, upperText)) {
                    return bot.say(`So, I'm good at structured conversations but stickers, emoji and sentences still confuse me. Say 'more' to chat about something else.`).then(() => 'speak');
                }

                var response = scriptRules[upperText];
                var lines = response.split('\n');

                var p = Promise.resolve();
                _.each(lines, function(line) {
                    line = line.trim();
                    p = p.then(function() {
                        console.log(line);
                        return wait(50).then(function() {
                            return bot.say(line);
                        });
                    });
                });

                return p.then(() => 'speak');
            }

            return updateSilent()
                .then(getSilent)
                .then(processMessage);
        }
    }
});
<commit_msg>api.ai v5<commit_after>'use strict';

const _ = require('lodash');
const Script = require('smooch-bot').Script;
var pg = require('pg');
var Q = require("q");
var request = require("request");

const scriptRules = require('./script.json');

function wait(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

//move to separeate file
var promises = [];
function nlp(query,sessionId){
	var deferred = Q.defer();
	var options = {
		"method" : "POST",
		"url" : "https://api.api.ai/v1/query?v=20150910",
		"json" : {
			"query" : query,
			"lang" : "en",
			"sessionId" : sessionId
		},
		"headers" : {
			"Authorization" : "Bearer " + process.env.API_AI_TOKEN,
			"Content-Type" : "application/json"
		}
	};

	console.log("===nlp");
	console.log("===query: ",query);
	console.log("===sessionId",sessionId);
	request(options,function(err,response,body){
		if(err){
			console.log("===nlp failed because: ",err.message);
			deferred.reject(err);
		}else{
			body.sessionId = sessionId;
			if(response.statusCode == 200){
				console.log("===nlp succeeded ");
				deferred.resolve(body);
			}else{
				deferred.reject(body);
			}
		}
	});
	return deferred.promise;
}

module.exports = new Script({
    processing: {
        //prompt: (bot) => bot.say('Beep boop...'),
        receive: () => 'processing'
    },

    start: {
        receive: (bot) => {
            return bot.say('Get started by saying BOT.')
                .then(() => 'speak');
        }
    },

    speak: {
        receive: (bot, message) => {
            console.log("===bot user ",bot.userId);
            let upperText = message.text.trim().toUpperCase();

            pg.defaults.ssl = true;
            pg.connect(process.env.DATABASE_URL, function(err,client){
                if (err) throw err;
                console.log('====Connected to postgres!!!!!');

                client
                    .query('insert into Attendees (SmoochId, Unsubscribed, UnsubscribedDate, CreatedDate) values ($1,$2, null, CURRENT_TIMESTAMP);', [bot.userId, 'f'],
                    function(err,result) {
                        if (err) {
                            if (err.code == '23505'){
                                console.log("===user already exists: ", bot.userId);
                            }
                            else{
                                console.log("===Unknown error: ", err);
                            }
                        } else {
                            console.log(JSON.stringify(result.rows[0]));
                        }
                    });
            });

            function updateSilent() {
                switch (upperText) {
                    case "CONNECT ME":
                        return bot.setProp("silent", true);
                    case "DISCONNECT":
                        return bot.setProp("silent", false);
                    default:
                        return Promise.resolve();
                }
            }

            function getSilent() {
                return bot.getProp("silent");
            }

            function processMessage(isSilent) {
                if (isSilent) {
                    return Promise.resolve("speak");
                }

                promises.push(nlp(upperText, bot.userId));

                Q.all(promises).then(function(responses) {
                    // response is the JSON from API.ai
                    responses.forEach(function(response) {
                        console.log("===received result from API.ai",response.fulfillment.speech);
                        var userSaid = response.result.resolvedQuery;
                        console.log("===user sent",userSaid);
                        afterNlp(response);
                    });
                }, function(error) {
                    console.log("[webhook_post.js]", error);
                });
                //return next();

                if (!_.has(scriptRules, upperText)) {
                    return bot.say(`So, I'm good at structured conversations but stickers, emoji and sentences still confuse me. Say 'more' to chat about something else.`).then(() => 'speak');
                }

                var response = scriptRules[upperText];
                var lines = response.split('\n');

                var p = Promise.resolve();
                _.each(lines, function(line) {
                    line = line.trim();
                    p = p.then(function() {
                        console.log(line);
                        return wait(50).then(function() {
                            return bot.say(line);
                        });
                    });
                });

                return p.then(() => 'speak');
            }

            return updateSilent()
                .then(getSilent)
                .then(processMessage);
        }
    }
});
<|endoftext|>


<commit_before>/* Default configuration */
const kDataName = "Configuration";
const kDefaultDataName = "DefaultConfiguration";
const kDefaultQuestConfig = {
  names   : [],
  apiKey  : "",
  fields  : "quests",
  zone    : "exodar",
  preffix : "https://eu.api.battle.net/wow/character"
};
const kQuestDialogBoxId = "e94fcc506861099988dd8eb80f97a9";

var questConfig = {};

var emptyObject = function(obj) {
  return (obj === undefined) || (obj === null) || ((Object.keys(obj).length === 0) && (obj.constructor === Object));
}

/* Checks if the data is already saved and save it. */
var checkLocalStorage = function(onFinish) {
  chrome.storage.local.get(kDataName, function(items) {
    var save = {};
    save[kDataName] = {};
    save[kDefaultDataName] = kDefaultQuestConfig;

    if (emptyObject(items)) {
      // Data was not saved

      for (var i in kDefaultQuestConfig) {
        questConfig[i] = save[kDataName][i] = kDefaultQuestConfig[i];
      }
    } else {
      // Data was saved
      for (var i in items[kDataName]) {
        questConfig[i] = save[kDataName][i] = items[kDataName][i];
      }
    }

    // Save data
    chrome.storage.local.set(save);
    if (typeof(onFinish) === "function") {
      onFinish();
    }
  });

  chrome.storage.local.set(questConfig);
}

/* Get the url with the quests done for a character name. */
var generateUrl = function(name) {
  var base = questConfig.preffix + "/" + questConfig.zone + "/" + name + "?";
  if (questConfig.fields) { base += "&fields=" + questConfig.fields; }
  if (questConfig.apiKey) { base += "&apikey=" + questConfig.apiKey; }
  return base;
}

/* Http Get request. */
var httpGet = function(url) {
  var xmlHttp = new XMLHttpRequest();
  xmlHttp.open( "GET", url, false );
  xmlHttp.send( null );
  return xmlHttp.responseText;
}

/* Checks if a quest is completed for a character name. */
var searchQuestInName = function(quest, name) {

  var response = httpGet(generateUrl(name));

  if (!response) {
    return {
      name: name,
      found: false,
      error: true,
      message: "No response"
    };
  }

  var data    = JSON.parse(response);
  var error   = (data.status === "nok") || (data.code !== undefined);
  var found   = (error) ? false : (data.quests.indexOf(quest) !== -1);
  var message = (error)                                       ?
                (data.reason ? data.reason : data.detail)     :
                (found       ? "Completed" : "Not completed") ;

  return {
    name: name,
    found: found,
    error: error,
    message: message
  };
}

/* Searchs if the quest in the url is completed for any of the characters. */
var searchQuest = function(info, tab) {
  var quest = info.linkUrl.match(/(?:\/quest=)(\d+)/);

  var parameters = {
    id: kQuestDialogBoxId
  };
  // Remove previous dialog box
  chrome.tabs.executeScript({
    code: '(' + function(params) {
      try {
        document.getElementById(params.id).outerHTML="";
      } catch (e) {};
    } + ')(' + JSON.stringify(parameters) + ');'
  });

  if (!quest || !quest[1]) {
    alert("No quest found");
    return;
  }
  if (questConfig.names.length <= 0) {
    alert("No character names");
    return;
  }
  if (!questConfig.apiKey) {
    alert("No api key");
    return;
  }

  // Generate dialog box
  parameters.names = questConfig.names;
  chrome.tabs.executeScript({
    code: '(' + function(params) {
      var table = "
";
      for (var i in params.names) {
        table += "
";
        table += "" + params.names[i] + "	";
        table += "" + "	";
        table += "
";
      }
      table += "
";

      document.body.insertAdjacentHTML('beforeend',
        `

          <img align="right"; style="width: 15px; height: 15px; margin: 10px; cursor: pointer;" onclick="document.getElementById('${params.id}').outerHTML='';" src="data:image/svg+xml;utf8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMTguMS4xLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDIxMi45ODIgMjEyLjk4MiIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMjEyLjk4MiAyMTIuOTgyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjY0cHgiIGhlaWdodD0iNjRweCI+CjxnIGlkPSJDbG9zZSI+Cgk8cGF0aCBzdHlsZT0iZmlsbC1ydWxlOmV2ZW5vZGQ7Y2xpcC1ydWxlOmV2ZW5vZGQ7IiBkPSJNMTMxLjgwNCwxMDYuNDkxbDc1LjkzNi03NS45MzZjNi45OS02Ljk5LDYuOTktMTguMzIzLDAtMjUuMzEyICAgYy02Ljk5LTYuOTktMTguMzIyLTYuOTktMjUuMzEyLDBsLTc1LjkzNyw3NS45MzdMMzAuNTU0LDUuMjQyYy02Ljk5LTYuOTktMTguMzIyLTYuOTktMjUuMzEyLDBjLTYuOTg5LDYuOTktNi45ODksMTguMzIzLDAsMjUuMzEyICAgbDc1LjkzNyw3NS45MzZMNS4yNDIsMTgyLjQyN2MtNi45ODksNi45OS02Ljk4OSwxOC4zMjMsMCwyNS4zMTJjNi45OSw2Ljk5LDE4LjMyMiw2Ljk5LDI1LjMxMiwwbDc1LjkzNy03NS45MzdsNzUuOTM3LDc1LjkzNyAgIGM2Ljk4OSw2Ljk5LDE4LjMyMiw2Ljk5LDI1LjMxMiwwYzYuOTktNi45OSw2Ljk5LTE4LjMyMiwwLTI1LjMxMkwxMzEuODA0LDEwNi40OTF6IiBmaWxsPSIjYWJhYmFiIi8+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPC9zdmc+Cg==" />
          ${table}

        `
      );

    } + ')(' + JSON.stringify(parameters) + ');'
  });

  // Search and update dialog box for each character
  for (var i in questConfig.names) {
    var result = searchQuestInName(+quest[1], questConfig.names[i]);

    parameters.result = result;
    chrome.tabs.executeScript({
      code: '(' + function(params) {
        var element = document.getElementById(params.id + "-" + params.result.name);
        element.innerHTML = params.result.message;

        if (params.result.error) {
          element.classList.add(params.id + "-error");
        } else if (params.result.found) {
          element.classList.add(params.id + "-found");
        } else {
          element.classList.add(params.id + "-notfound");
        }

      } + ')(' + JSON.stringify(parameters) + ');'
    });
  }
}

var searchQuestAndCheckStorage = function(info, tab) {
  checkLocalStorage(function() {
    searchQuest(info, tab);
  });
}

chrome.contextMenus.create({
  title: "WoW quest done?",
  contexts: ["link"],
  onclick: searchQuestAndCheckStorage
});

chrome.windows.onCreated.addListener(checkLocalStorage);
chrome.runtime.onInstalled.addListener(checkLocalStorage);
<commit_msg>Removed 'duplicated' save of data<commit_after>/* Default configuration */
const kDataName = "Configuration";
const kDefaultDataName = "DefaultConfiguration";
const kDefaultQuestConfig = {
  names   : [],
  apiKey  : "",
  fields  : "quests",
  zone    : "exodar",
  preffix : "https://eu.api.battle.net/wow/character"
};
const kQuestDialogBoxId = "e94fcc506861099988dd8eb80f97a9";

var questConfig = {};

var emptyObject = function(obj) {
  return (obj === undefined) || (obj === null) || ((Object.keys(obj).length === 0) && (obj.constructor === Object));
}

/* Checks if the data is already saved and save it. */
var checkLocalStorage = function(onFinish) {
  chrome.storage.local.get(kDataName, function(items) {
    var save = {};
    save[kDataName] = {};
    save[kDefaultDataName] = kDefaultQuestConfig;

    if (emptyObject(items)) {
      // Data was not saved
      for (var i in kDefaultQuestConfig) {
        questConfig[i] = save[kDataName][i] = kDefaultQuestConfig[i];
      }
    } else {
      // Data was saved
      for (var i in items[kDataName]) {
        questConfig[i] = save[kDataName][i] = items[kDataName][i];
      }
    }

    // Save data
    chrome.storage.local.set(save);
    if (typeof(onFinish) === "function") {
      onFinish();
    }
  });
}

/* Get the url with the quests done for a character name. */
var generateUrl = function(name) {
  var base = questConfig.preffix + "/" + questConfig.zone + "/" + name + "?";
  if (questConfig.fields) { base += "&fields=" + questConfig.fields; }
  if (questConfig.apiKey) { base += "&apikey=" + questConfig.apiKey; }
  return base;
}

/* Http Get request. */
var httpGet = function(url) {
  var xmlHttp = new XMLHttpRequest();
  xmlHttp.open( "GET", url, false );
  xmlHttp.send( null );
  return xmlHttp.responseText;
}

/* Checks if a quest is completed for a character name. */
var searchQuestInName = function(quest, name) {

  var response = httpGet(generateUrl(name));

  if (!response) {
    return {
      name: name,
      found: false,
      error: true,
      message: "No response"
    };
  }

  var data    = JSON.parse(response);
  var error   = (data.status === "nok") || (data.code !== undefined);
  var found   = (error) ? false : (data.quests.indexOf(quest) !== -1);
  var message = (error)                                       ?
                (data.reason ? data.reason : data.detail)     :
                (found       ? "Completed" : "Not completed") ;

  return {
    name: name,
    found: found,
    error: error,
    message: message
  };
}

/* Searchs if the quest in the url is completed for any of the characters. */
var searchQuest = function(info, tab) {
  var quest = info.linkUrl.match(/(?:\/quest=)(\d+)/);

  var parameters = {
    id: kQuestDialogBoxId
  };
  // Remove previous dialog box
  chrome.tabs.executeScript({
    code: '(' + function(params) {
      try {
        document.getElementById(params.id).outerHTML="";
      } catch (e) {};
    } + ')(' + JSON.stringify(parameters) + ');'
  });

  if (!quest || !quest[1]) {
    alert("No quest found");
    return;
  }
  if (questConfig.names.length <= 0) {
    alert("No character names");
    return;
  }
  if (!questConfig.apiKey) {
    alert("No api key");
    return;
  }

  // Generate dialog box
  parameters.names = questConfig.names;
  chrome.tabs.executeScript({
    code: '(' + function(params) {
      var table = "
";
      for (var i in params.names) {
        table += "
";
        table += "" + params.names[i] + "	";
        table += "" + "	";
        table += "
";
      }
      table += "
";

      document.body.insertAdjacentHTML('beforeend',
        `

          <img align="right"; style="width: 15px; height: 15px; margin: 10px; cursor: pointer;" onclick="document.getElementById('${params.id}').outerHTML='';" src="data:image/svg+xml;utf8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMTguMS4xLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDIxMi45ODIgMjEyLjk4MiIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMjEyLjk4MiAyMTIuOTgyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjY0cHgiIGhlaWdodD0iNjRweCI+CjxnIGlkPSJDbG9zZSI+Cgk8cGF0aCBzdHlsZT0iZmlsbC1ydWxlOmV2ZW5vZGQ7Y2xpcC1ydWxlOmV2ZW5vZGQ7IiBkPSJNMTMxLjgwNCwxMDYuNDkxbDc1LjkzNi03NS45MzZjNi45OS02Ljk5LDYuOTktMTguMzIzLDAtMjUuMzEyICAgYy02Ljk5LTYuOTktMTguMzIyLTYuOTktMjUuMzEyLDBsLTc1LjkzNyw3NS45MzdMMzAuNTU0LDUuMjQyYy02Ljk5LTYuOTktMTguMzIyLTYuOTktMjUuMzEyLDBjLTYuOTg5LDYuOTktNi45ODksMTguMzIzLDAsMjUuMzEyICAgbDc1LjkzNyw3NS45MzZMNS4yNDIsMTgyLjQyN2MtNi45ODksNi45OS02Ljk4OSwxOC4zMjMsMCwyNS4zMTJjNi45OSw2Ljk5LDE4LjMyMiw2Ljk5LDI1LjMxMiwwbDc1LjkzNy03NS45MzdsNzUuOTM3LDc1LjkzNyAgIGM2Ljk4OSw2Ljk5LDE4LjMyMiw2Ljk5LDI1LjMxMiwwYzYuOTktNi45OSw2Ljk5LTE4LjMyMiwwLTI1LjMxMkwxMzEuODA0LDEwNi40OTF6IiBmaWxsPSIjYWJhYmFiIi8+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPC9zdmc+Cg==" />
          ${table}

        `
      );

    } + ')(' + JSON.stringify(parameters) + ');'
  });

  // Search and update dialog box for each character
  for (var i in questConfig.names) {
    var result = searchQuestInName(+quest[1], questConfig.names[i]);

    parameters.result = result;
    chrome.tabs.executeScript({
      code: '(' + function(params) {
        var element = document.getElementById(params.id + "-" + params.result.name);
        element.innerHTML = params.result.message;

        if (params.result.error) {
          element.classList.add(params.id + "-error");
        } else if (params.result.found) {
          element.classList.add(params.id + "-found");
        } else {
          element.classList.add(params.id + "-notfound");
        }

      } + ')(' + JSON.stringify(parameters) + ');'
    });
  }
}

var searchQuestAndCheckStorage = function(info, tab) {
  checkLocalStorage(function() {
    searchQuest(info, tab);
  });
}

chrome.contextMenus.create({
  title: "WoW quest done?",
  contexts: ["link"],
  onclick: searchQuestAndCheckStorage
});

chrome.windows.onCreated.addListener(checkLocalStorage);
chrome.runtime.onInstalled.addListener(checkLocalStorage);
<|endoftext|>


<commit_before>weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];

init();

function init() {
  var fieldsets = document.getElementsByTagName('fieldset');
  for (var i = fieldsets.length - 1; i >= 0; i--) {
    fieldsets[i].onmouseover = function() {
      this.getElementsByTagName('legend')[0].style.borderColor = 'threedhighlight';
      this.style.borderColor = 'threedhighlight'
    };
    fieldsets[i].onmouseout = function() {
      this.getElementsByTagName('legend')[0].style.borderColor = 'threedface';
      this.style.borderColor = 'threedface'
    };
  }
  var output = document.getElementById('output');
  output.onmouseover = function() {
    this.style.borderColor = 'threedhighlight'
  };
  output.onmouseout = function() {
    this.style.borderColor = 'threedface'
  };
  today();
  var formInputs = document.getElementsByTagName('form')[0].getElementsByTagName('input');
  for (var i = formInputs.length - 1; i >= 0; i--) {
    formInputs[i].onmouseover = function() {
      this.style.backgroundColor = '#eee'
    };
    formInputs[i].onmouseout = function() {
      this.style.backgroundColor = '#ddd'
    };
  }
}

function today() {
  var digestDate = document.getElementById('digestDate');
  var todayDate = new Date(Date.now());
  digestDate.value = constructDateString(todayDate, "-", false);
}

function nextSunday() {
  var digestDate = document.getElementById('digestDate');
  today();
  var d = new Date(digestDate.value);
  while (d.getUTCDay() != 0) {
    d.setDate(d.getUTCDate() + 1);
  }
  digestDate.value = constructDateString(d, "-", true);
}

function render() {
  document.getElementById('genButton').innerHTML = 'REGEN ADVISED';
  document.getElementById('genButton').style.color = '#f00';
  document.getElementById('output').style.backgroundColor = '#fdd';
  document.getElementById('outputText').style.backgroundColor = '#fdd';
  var renderWindow = window.open();
  renderWindow.document.write(document.getElementById('outputText').value);
}

function gen() {
  document.getElementById('genButton').innerHTML = 'GENERATE';
  document.getElementById('genButton').style.color = '#000';
  document.getElementById('renderButton').disabled = false;
  document.getElementById('output').style.backgroundColor = '#fff';
  document.getElementById('outputText').style.backgroundColor = '#fff';
  var output = "";
  output += genHeader();
  output += genFooter();
  document.getElementById('outputText').value = output;
}

function genHeader() {
  var digestDate = new Date(document.getElementById('digestDate').value);
  var dateString = constructDateString(digestDate, ".", true);
  var digestCSS = document.getElementById("digestCSS").value;
  var mdyString = constructMDYString(digestDate, true);
  var headerStr =
      '<!doctype HTML>\n'
    + '\n'
    + '  \n'
    + '    <title>EZ Digest - ' + dateString + '</title>\n'
    + '    <link rel="stylesheet" type="text/css" href="' + digestCSS + '">\n'
    + '  \n'
    + '  \n'
    + '
\n'
    + '
\n'
    + '        \n'
    + '          EZ Digest - ' + mdyString + '\n'
    + '        	\n'
    + '
\n';
  return headerStr;
}

function genFooter() {
  var footerStr =
      '
\n'
    + '        \n'
    + '
The goal of the weekly EZ Digest is to provide a concise summary of recent and upcoming chapter activities.
\n'
    + '
Unlike eggs, digests are always better when they\'re Over EZ.
\n'
    + '
Feel free to reply to this message with any comments or suggestions!
\n'
    + '
Alpha Phi Omega - Epsilon Zeta Chapter - Rensselaer Polytechnic Institute
\n'
    + '        	\n'
    + '
\n'
    + '
\n'
    + '  \n'
    + '\n'
  return footerStr;
}

function pad(num, size) {
    var s = num+"";
    while (s.length < size) s = "0" + s;
    return s;
}

function constructDateString(date, separator, utc) {
  return utc
    ? date.getUTCFullYear() + separator + pad(date.getUTCMonth() + 1, 2) + separator + pad(date.getUTCDate(), 2)
    : date.getFullYear() + separator + pad(date.getMonth() + 1, 2) + separator + pad(date.getDate(), 2);
}

function constructMDYString(date, utc) {
  return utc
    ? months[date.getUTCMonth()] + " " + date.getUTCDate() + ", " + date.getUTCFullYear()
    : months[date.getMonth()] + " "  + date.getDate() + ", " + date.getFullYear();

}
<commit_msg>Fully fix next Sunday UTC bug<commit_after>weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];

init();

function init() {
  var fieldsets = document.getElementsByTagName('fieldset');
  for (var i = fieldsets.length - 1; i >= 0; i--) {
    fieldsets[i].onmouseover = function() {
      this.getElementsByTagName('legend')[0].style.borderColor = 'threedhighlight';
      this.style.borderColor = 'threedhighlight'
    };
    fieldsets[i].onmouseout = function() {
      this.getElementsByTagName('legend')[0].style.borderColor = 'threedface';
      this.style.borderColor = 'threedface'
    };
  }
  var output = document.getElementById('output');
  output.onmouseover = function() {
    this.style.borderColor = 'threedhighlight'
  };
  output.onmouseout = function() {
    this.style.borderColor = 'threedface'
  };
  today();
  var formInputs = document.getElementsByTagName('form')[0].getElementsByTagName('input');
  for (var i = formInputs.length - 1; i >= 0; i--) {
    formInputs[i].onmouseover = function() {
      this.style.backgroundColor = '#eee'
    };
    formInputs[i].onmouseout = function() {
      this.style.backgroundColor = '#ddd'
    };
  }
}

function today() {
  var digestDate = document.getElementById('digestDate');
  var todayDate = new Date(Date.now());
  digestDate.value = constructDateString(todayDate, "-", false);
}

function nextSunday() {
  var digestDate = document.getElementById('digestDate');
  today();
  var d = new Date(digestDate.value);
  while (d.getUTCDay() != 0) {
    d.setUTCDate(d.getUTCDate() + 1);
  }
  digestDate.value = constructDateString(d, "-", true);
}

function render() {
  document.getElementById('genButton').innerHTML = 'REGEN ADVISED';
  document.getElementById('genButton').style.color = '#f00';
  document.getElementById('output').style.backgroundColor = '#fdd';
  document.getElementById('outputText').style.backgroundColor = '#fdd';
  var renderWindow = window.open();
  renderWindow.document.write(document.getElementById('outputText').value);
}

function gen() {
  document.getElementById('genButton').innerHTML = 'GENERATE';
  document.getElementById('genButton').style.color = '#000';
  document.getElementById('renderButton').disabled = false;
  document.getElementById('output').style.backgroundColor = '#fff';
  document.getElementById('outputText').style.backgroundColor = '#fff';
  var output = "";
  output += genHeader();
  output += genFooter();
  document.getElementById('outputText').value = output;
}

function genHeader() {
  var digestDate = new Date(document.getElementById('digestDate').value);
  var dateString = constructDateString(digestDate, ".", true);
  var digestCSS = document.getElementById("digestCSS").value;
  var mdyString = constructMDYString(digestDate, true);
  var headerStr =
      '<!doctype HTML>\n'
    + '\n'
    + '  \n'
    + '    <title>EZ Digest - ' + dateString + '</title>\n'
    + '    <link rel="stylesheet" type="text/css" href="' + digestCSS + '">\n'
    + '  \n'
    + '  \n'
    + '
\n'
    + '
\n'
    + '        \n'
    + '          EZ Digest - ' + mdyString + '\n'
    + '        	\n'
    + '
\n';
  return headerStr;
}

function genFooter() {
  var footerStr =
      '
\n'
    + '        \n'
    + '
The goal of the weekly EZ Digest is to provide a concise summary of recent and upcoming chapter activities.
\n'
    + '
Unlike eggs, digests are always better when they\'re Over EZ.
\n'
    + '
Feel free to reply to this message with any comments or suggestions!
\n'
    + '
Alpha Phi Omega - Epsilon Zeta Chapter - Rensselaer Polytechnic Institute
\n'
    + '        	\n'
    + '
\n'
    + '
\n'
    + '  \n'
    + '\n'
  return footerStr;
}

function pad(num, size) {
    var s = num+"";
    while (s.length < size) s = "0" + s;
    return s;
}

function constructDateString(date, separator, utc) {
  return utc
    ? date.getUTCFullYear() + separator + pad(date.getUTCMonth() + 1, 2) + separator + pad(date.getUTCDate(), 2)
    : date.getFullYear() + separator + pad(date.getMonth() + 1, 2) + separator + pad(date.getDate(), 2);
}

function constructMDYString(date, utc) {
  return utc
    ? months[date.getUTCMonth()] + " " + date.getUTCDate() + ", " + date.getUTCFullYear()
    : months[date.getMonth()] + " "  + date.getDate() + ", " + date.getFullYear();

}
<|endoftext|>