<commit_before>
if (!_)
	throw {name:'RequiresException', message:'Requires underscore.js'};

	// Helper function to walk recursively through two objects, together.
	// - callback: function(a,b,key,path)
	var pairWalkRec = function pairWalkRec(a,b,path,callback)
	{
		if (typeof b === 'undefined')
			return;

		for (var p in a)
		{
			path.push(p);
			callback(a,b,p,path);

			pairWalkRec(a[p],b[p],path,callback);
			path.pop();
		}
	};

	var pairWalk = function(a,b,callback)
	{
		for (var p in a)
		{
			pairWalkRec(a,b,[],callback);
		}
	}
// Perhaps the '.__' prefix can be changed to a random string, unique per
// page load.

Model = (function()
{
	// NOTE: These can be individual per Handle.  Why did I do it this way?
	var listeners = {};

	var special = {
		delete:{}
	};

	var modelId = _.uniqueId();

	// NOTE: Playing around with another private var.
	var onEvent = function(handle,eventName,func,args)
	{
		listeners[handle.__id][eventName].push({func:func,args:args});
	};

	var offEvent = function(handle,eventName,func)
	{
		var events = listeners[handle.__id][eventName]
		var funcs = events.map(function(a){return a.func});

		var index = funcs.indexOf(func);

		console.log(index,funcs);

		if (index >= 0)
			listeners[handle.__id][eventName].splice(index,1);

		return index >= 0;
	};

	function Handle(ob)
	{
		makeHandle(this,ob);
	}

	// NOTE: I want these Handle objects to remain *independent* of Model
	//   instances, though...  Will think through, later.
	function makeHandle(handle,ob)
	{
		var self = handle;
		var handle = handle;

		// ob effectively holds a mirror copy of... everthing.  There's a reason I'm
		// using it, and testing has revealed that reason as valid.  But exactly what
		// is that reason...?  Was it the leaf node Handles?
		ob = (typeof ob === 'object' ?
				(Array.isArray(ob) ? ob.slice() : _.extend({},ob)): ob)

		// Assign immutable id.
		Object.defineProperty(handle,'__id',{
			enumerable:false,
			configurable:false,
			writable:false,
			value:modelId+'_'+_.uniqueId()
		});

		// Add listeners entry, with arrays of event callbacks.
		//
		// NOTE: In the event that the listeners object is moved to a private,
		//   per-Handle var, this... will likely not change much, now that I
		//   think about it.
		listeners[handle.__id] = {change:[],delete:[],all:[]};

		// Assign add-event-listener function.
		Object.defineProperty(handle,'$on',{
			enumerable:false,
			configurable:false,
			value:function(eventName,func,args)
			{ onEvent(self,eventName,func,args); }
		});

		// Assign remove-event-listener function.
		Object.defineProperty(handle,'$off',{
			enumerable:false,
			configurable:false,
			value:function(eventName,func)
			{
				return offEvent(self,eventName,func);
			}
		});

		// Assign basic JSON-object export function.
		Object.defineProperty(handle,'$',{
			enumerable:false,
			configurable:false,
			get:function()
			{
				if (typeof ob !== 'object')
					return ob;

				var ret = (Array.isArray(ob) ? [] : {});
				for (var p in ob)
					ret[p] = ob[p].$;
				return ret;
			}
		});

		if (typeof ob !== 'object')
		{
			// NOTE: Looks like defining properties on Number/String/Boolean is
			//   considered acting on primitives, and is not permitted.  Guess
			//   creating unique literal value Handles won't be possible.

			Object.defineProperty(handle,'valueOf',{
				enumerable:false,
				conifgurable:false,
				writable:false,
				value:function()
				{ console.log('val?',ob); return ob; }
			});
		}

		if (typeof ob === 'object')
		for (var p in ob)
		{
			//ob[p] = (typeof ob[p] === 'object' ? new Handle(ob[p]) : ob[p]);
			//ob[p] = new Handle(ob[p]);
			ob[p] = new Handle(ob[p]);
			Object.defineProperty(ob[p],'__parent',{
				enumerable:false,
				configurable:false,
				get:function(){return handle}
			});

			// NOTE: Put this here for private access to its parent while
			//   retaining its given property name.
			Object.defineProperty(ob[p],'$delete',{
				enumerable:false,
				configurable:false,
				value:(function(k){return function(){ self[k] = special.delete }})(p)
			});

			Object.defineProperty(handle,p,{
				enumerable:true,
				configurable:true,
				get:(function(k){return function(){return ob[k]}})(p),
				set:(function(k){return function(val)
				{
					var oldHandle = ob[k];
					var newHandle;

					if (val == special.delete)
					{
						// NOTE: Deletion needs to go somewhere more accissible.  Now that
						//   there's a proper $delete method, this ought go somewhere more
						//   sensible.

						listeners[oldHandle.__id].delete.map(function(action)
						{
							action.func(oldHandle.$);
						});

						listeners[oldHandle.__id].all.map(function(action)
						{
							action.func('delete',[oldHandle.$]);
						});

						// NOTE: WAAAAIT!
						//   This must recurse.  It needs to recurse.
						//   Or does it?  What if something else is using these?
						//
						//   You know what?  This is all based on the idea of a unified
						//   object model, meaning there is only *one* root object for
						//   each of these.  Modifying a Handle *should* invalidate all
						//   the Handles below it.
						//*
						for (var x in oldHandle)
							if (oldHandle[x] instanceof Handle)
								oldHandle[x] = special.delete;
						//*/

						// NOTE: There is another concern, however.  In the event that a
						//   Handle is assigned another object structure, creating more
						//   handles, ought paths/values matching between the recursed
						//   deleted old and the new created Handle be applied to the new,
						//   as well?
						//
						//   By values, I mean things held by private Model vars,
						//   like the listeners object.
						//
						//   Ultimately, that depends on whether the object is being
						//   *replaced* or *modified*.  How might we distinguish between
						//   the two?
						//
						//   Maybe... replace = new M.Hanlde({}), modify = {}.
						//   Or visa-versa.  Could work either way.
						//
						//   Save this for a later commit.  Or better yet, make a github
						//   Issue.

						// Remove events from listeners object.
						delete listeners[oldHandle.__id];
						delete ob[k];
						delete self[k];
						return;
					}

					// NOTE: Replace-vs-Modify logic will have to change this, here.
					//newHandle = (val instanceof Handle ? val : new Handle(val));
					if (val instanceof Handle)
					{
						// Replace.
						newHandle = val;
					}
					else if (typeof val === 'object')
					{
						// Modify.
						newHandle = new Handle(val);

						// Recursively transfer listeners.
						//
						// NOTE: Seems to work, but on thinking over it, again, perhaps
						//   passing in a regular object should traverse that regular
						//   object *alone*, and modify oldHandle *without* replacing it,
						//   entirely.  I'll think it over.  For now, it effectively does
						//   already what I made it to do, so all's good.
						pairWalk(oldHandle,newHandle,function(old,newh,key,path)
						{
							console.log('hokay!',key,old[key],newh[key]);

							if (newh[key])
								_.extend(listeners[newh[key].__id],listeners[old[key].__id]);
							delete listeners[old[key].__id];
						});
					}
					else
						newHandle = new Handle(val);
					//newHandle = (val instanceof Handle ? val : new Handle(val));
					ob[k] = newHandle;

					// Modify listeners object.
					// - Copy oldHandle's listeners over to newHandle's.
					// - Remove oldHandle's listeners.
					_.extend(listeners[newHandle.__id],listeners[oldHandle.__id]);
					delete listeners[oldHandle.__id];

					// Run change event listeners.
					listeners[ob[k].__id].change.map(function(action)
					{
						action.func(val,oldHandle.$,action.args);
					});

					// Run 'all' event listeners.
					listeners[ob[k].__id].all.map(function(action)
					{
						action.func('change',[val,oldHandle.$,action.args]);
					});

					// Should events also bubble up...?

					console.log('returning',ob[k]);
					return ob[k];
				}})(p)
			});
		}

		return handle;
	}

	function Model(params)
	{
		var Model = {};

		if (params)
		{

		}

		this.Handle = Handle;

		this.makeHandle = makeHandle;

		/*
		Object.defineProperty(this,'Delete',{
			enumerable:false,
			configurable:false,
			writable:false,
			value:special.delete
		});
		//*/
	};

	return Model;
})();

<commit_msg>#1 Handle get assignment no longer replaces the calling Handle by default, instead overwriting its values, so that outside references to the Handle may still refer to the same object.<commit_after>
if (!_)
	throw {name:'RequiresException', message:'Requires underscore.js'};

	// Helper function to walk recursively through two objects, together.
	// - callback: function(a,b,key,path)
	var pairWalkRec = function pairWalkRec(a,b,path,callback)
	{
		if (typeof b === 'undefined')
			return;

		for (var p in a)
		{
			path.push(p);
			callback(a,b,p,path);

			pairWalkRec(a[p],b[p],path,callback);
			path.pop();
		}
	};

	var pairWalk = function(a,b,callback)
	{
		for (var p in a)
		{
			pairWalkRec(a,b,[],callback);
		}
	}
// Perhaps the '.__' prefix can be changed to a random string, unique per
// page load.

Model = (function()
{
	// NOTE: These can be individual per Handle.  Why did I do it this way?
	var listeners = {};

	var special = {
		delete:{}
	};

	var modelId = _.uniqueId();

	// NOTE: Playing around with another private var.
	var onEvent = function(handle,eventName,func,args)
	{
		listeners[handle.__id][eventName].push({func:func,args:args});
	};

	var offEvent = function(handle,eventName,func)
	{
		var events = listeners[handle.__id][eventName]
		var funcs = events.map(function(a){return a.func});

		var index = funcs.indexOf(func);

		console.log(index,funcs);

		if (index >= 0)
			listeners[handle.__id][eventName].splice(index,1);

		return index >= 0;
	};

	function Handle(ob)
	{
		makeHandle(this,ob);
	}

	// NOTE: I want these Handle objects to remain *independent* of Model
	//   instances, though...  Will think through, later.
	function makeHandle(handle,ob)
	{
		var self = handle;
		var handle = handle;

		// ob effectively holds a mirror copy of... everthing.  There's a reason I'm
		// using it, and testing has revealed that reason as valid.  But exactly what
		// is that reason...?  Was it the leaf node Handles?
		ob = (typeof ob === 'object' ?
				(Array.isArray(ob) ? ob.slice() : _.extend({},ob)): ob)

		// Assign these values only if handle has not yet been instantiated.
		if (!handle.__id)
		{
			// Assign immutable id.
			Object.defineProperty(handle,'__id',{
				enumerable:false,
				configurable:false,
				writable:false,
				value:modelId+'_'+_.uniqueId()
			});

			// Add listeners entry, with arrays of event callbacks.
			//
			// NOTE: In the event that the listeners object is moved to a private,
			//   per-Handle var, this... will likely not change much, now that I
			//   think about it.
			listeners[handle.__id] = {change:[],delete:[],all:[]};

			// Assign add-event-listener function.
			Object.defineProperty(handle,'$on',{
				enumerable:false,
				configurable:false,
				value:function(eventName,func,args)
				{ onEvent(self,eventName,func,args); }
			});

			// Assign remove-event-listener function.
			Object.defineProperty(handle,'$off',{
				enumerable:false,
				configurable:false,
				value:function(eventName,func)
				{ return offEvent(self,eventName,func); }
			});
		}

		// Assign basic JSON-object export function.
		Object.defineProperty(handle,'$',{
			enumerable:false,
			configurable:true,
			get:function()
			{
				if (typeof ob !== 'object')
					return ob;

				var ret = (Array.isArray(ob) ? [] : {});
				for (var p in ob)
					ret[p] = ob[p].$;
				return ret;
			}
		});

		if (typeof ob !== 'object')
		{
			// NOTE: Looks like defining properties on Number/String/Boolean is
			//   considered acting on primitives, and is not permitted.  Guess
			//   creating unique literal value Handles won't be possible.

			Object.defineProperty(handle,'valueOf',{
				enumerable:false,
				configurable:true,
				value:function()
				{ console.log('val?',ob); return ob; }
			});
		}

		if (typeof ob === 'object')
		for (var p in ob)
		{
			//ob[p] = (typeof ob[p] === 'object' ? new Handle(ob[p]) : ob[p]);
			//ob[p] = new Handle(ob[p]);

			console.log('ob[p]',[ob,p,ob[p],ob[p].__id]);
			// NOTE: If going for soft overwrites, this, too, needs to be a call to
			//   makeHandle, rather than new Handle(...).  Unless this is only ever
			//   accessed at creation, and not on assign.  One moment...
			if (handle[p] instanceof Handle)
				ob[p] = makeHandle(handle[p],ob[p]);
			else
				ob[p] = new Handle(ob[p]);

			if (handle[p] != ob[p])
			{
				Object.defineProperty(ob[p],'__parent',{
					enumerable:false,
					configurable:false,
					get:function(){return handle}
				});

				// NOTE: Put this here for private access to its parent while
				//   retaining its given property name.

				Object.defineProperty(ob[p],'$delete',{
					enumerable:false,
					configurable:false,
					value:(function(k){return function(){ self[k] = special.delete }})(p)
				});
			}

			Object.defineProperty(handle,p,{
				enumerable:true,
				configurable:true,
				get:(function(k){return function(){return ob[k]}})(p),
				set:(function(k){return function(val)
				{
					var oldHandle = ob[k];
					var newHandle;

					if (val == special.delete)
					{
						// NOTE: Deletion needs to go somewhere more accissible.  Now that
						//   there's a proper $delete method, this ought go somewhere more
						//   sensible.

						listeners[oldHandle.__id].delete.map(function(action)
						{
							action.func(oldHandle.$);
						});

						listeners[oldHandle.__id].all.map(function(action)
						{
							action.func('delete',[oldHandle.$]);
						});

						// NOTE: WAAAAIT!
						//   This must recurse.  It needs to recurse.
						//   Or does it?  What if something else is using these?
						//
						//   You know what?  This is all based on the idea of a unified
						//   object model, meaning there is only *one* root object for
						//   each of these.  Modifying a Handle *should* invalidate all
						//   the Handles below it.
						//*
						for (var x in oldHandle)
							if (oldHandle[x] instanceof Handle)
								oldHandle[x] = special.delete;
						//*/

						// NOTE: There is another concern, however.  In the event that a
						//   Handle is assigned another object structure, creating more
						//   handles, ought paths/values matching between the recursed
						//   deleted old and the new created Handle be applied to the new,
						//   as well?
						//
						//   By values, I mean things held by private Model vars,
						//   like the listeners object.
						//
						//   Ultimately, that depends on whether the object is being
						//   *replaced* or *modified*.  How might we distinguish between
						//   the two?
						//
						//   Maybe... replace = new M.Hanlde({}), modify = {}.
						//   Or visa-versa.  Could work either way.
						//
						//   Save this for a later commit.  Or better yet, make a github
						//   Issue.

						// Remove events from listeners object.
						delete listeners[oldHandle.__id];
						delete ob[k];
						delete self[k];
						return;
					}

					// Get old value only if it will be necessary later on in calling
					// listeners.
					var oldValue;
					if (listeners[oldHandle.__id].change.length > 0 ||
					    listeners[oldHandle.__id].all.length > 0)
						oldValue = oldHandle.$;

					// NOTE: Replace-vs-Modify logic will have to change this, here.
					//newHandle = (val instanceof Handle ? val : new Handle(val));
					if (val instanceof Handle)
					{
						// Replace.
						//newHandle = val;
						throw {
							name:'BlockingThisForNowException',
							message:'For now, no replacement.'
						};
					}
					else if (typeof val === 'object')
					{
						// Modify.
						//newHandle = new Handle(val);
						newHandle = makeHandle(oldHandle,val);

						/* If not replacing oldHandle, the external data need not
						   be removed.

						// Recursively transfer listeners.
						//
						// NOTE: Seems to work, but on thinking over it, again, perhaps
						//   passing in a regular object should traverse that regular
						//   object *alone*, and modify oldHandle *without* replacing it,
						//   entirely.  I'll think it over.  For now, it effectively does
						//   already what I made it to do, so all's good.
						pairWalk(oldHandle,newHandle,function(old,newh,key,path)
						{
							console.log('hokay!',key,old[key],newh[key]);

							if (newh[key])
								_.extend(listeners[newh[key].__id],listeners[old[key].__id]);
							delete listeners[old[key].__id];
						});
						//*/
					}
					else
						//newHandle = new Handle(val);
						newHandle = makeHandle(oldHandle,val);

					// Modify listeners object.
					// - Copy oldHandle's listeners over to newHandle's.
					// - Remove oldHandle's listeners.
					if (newHandle !== oldHandle)
					{
						_.extend(listeners[newHandle.__id],listeners[oldHandle.__id]);
						delete listeners[oldHandle.__id];
					}

					ob[k] = newHandle;

					if (oldValue)
					{
						// Run change event listeners.
						listeners[ob[k].__id].change.map(function(action)
						{
							action.func(val,oldValue,action.args);
						});

						// Run 'all' event listeners.
						listeners[ob[k].__id].all.map(function(action)
						{
							action.func('change',[val,oldValue,action.args]);
						});
					}

					// Should events also bubble up...?

					console.log('returning',ob[k]);
					return ob[k];
				}})(p)
			});
		}

		return handle;
	}

	function Model(params)
	{
		var Model = {};

		if (params)
		{

		}

		this.Handle = Handle;

		this.makeHandle = makeHandle;

		Object.defineProperty(this,'listeners',{
			enumerable:true,
			configurable:false,
			writable:false,
			value:function()
			{
				var ret = {};
				for (var p in listeners)
				{
					var events = {};
					for (var k in listeners[p])
						events[k] = listeners[p][k].map(function(a){return _.extend({},a)});
					ret[p] = events;
				}
				return ret;
			}
		});
	};

	return Model;
})();

<|endoftext|>


<commit_before>'use strict'

const express = require('express')
const Slapp = require('slapp')
const ConvoStore = require('slapp-convo-beepboop')
const Context = require('slapp-context-beepboop')
const slack = require('slack')

// use `PORT` env var on Beep Boop - default to 3000 locally
var port = process.env.PORT || 3000
var token =process.env.SLACK_VERIFY_TOKEN

var slapp = Slapp({
  // Beep Boop sets the SLACK_VERIFY_TOKEN env var
  verify_token: process.env.SLACK_VERIFY_TOKEN,
  convo_store: ConvoStore(),
  context: Context()
})

var HELP_TEXT = `
I will respond to the following messages:
\`help\` - to see this message.
\`hi\` - to demonstrate a conversation that tracks state.
\`thanks\` - to demonstrate a simple response.
\`<type-any-other-text>\` - to demonstrate a random emoticon response, some of the time :wink:.
\`attachment\` - to see a Slack attachment message.
`

//*********************************************
// Setup different handlers for messages
//*********************************************

// response to the user typing "help"
slapp.message('help', ['mention', 'direct_message'], (msg) => {
  msg.say(HELP_TEXT)
})

slapp.event('team_join', (msg) => {

  slapp.client.im.open({ token: msg.meta.bot_token, user: msg.meta.user_id }, (err, data) => {
    if (err) {
      return console.error(err)
    }
    let channel = data.channel.id

    msg.say({ channel: channel, text: 'Please visite www.neurotechedu.com' })
    msg.say({ channel: channel, text: help })
    })

})
// "Conversation" flow that tracks state - kicks off when user says hi, hello or hey
slapp
  .message('^(hi|hello|hey)$', ['direct_mention', 'direct_message'], (msg, text) => {
    msg
      .say(`${text}, how are you?`)
      // sends next event from user to this route, passing along state
      .route('how-are-you', { greeting: text })
  })
  .route('how-are-you', (msg, state) => {
    var text = (msg.body.event && msg.body.event.text) || ''

    // user may not have typed text as their next action, ask again and re-route
    if (!text) {
      return msg
        .say("Whoops, I'm still waiting to hear how you're doing.")
        .say('How are you?')
        .route('how-are-you', state)
    }

    // add their response to state
    state.status = text

    msg
      .say(`Ok then. What's your favorite color?`)
      .route('color', state)
  })
  .route('color', (msg, state) => {
    var text = (msg.body.event && msg.body.event.text) || ''

    // user may not have typed text as their next action, ask again and re-route
    if (!text) {
      return msg
        .say("I'm eagerly awaiting to hear your favorite color.")
        .route('color', state)
    }

    // add their response to state
    state.color = text

    msg
      .say('Thanks for sharing.')
      .say(`Here's what you've told me so far: \`\`\`${JSON.stringify(state)}\`\`\``)
    // At this point, since we don't route anywhere, the "conversation" is over
  })

// Can use a regex as well
slapp.message(/^(thanks|thank you)/i, ['mention', 'direct_message'], (msg) => {
  // You can provide a list of responses, and a random one will be chosen
  // You can also include slack emoji in your responses
  msg.say([
    "You're welcome :smile:",
    'You bet',
    ':+1: Of course',
    'Anytime :sun_with_face: :full_moon_with_face:'
  ])
})

// demonstrate returning an attachment...
slapp.message('attachment', ['mention', 'direct_message'], (msg) => {
  msg.say({
    text: 'Check out this amazing attachment! :confetti_ball: ',
    attachments: [{
      text: 'Slapp is a robust open source library that sits on top of the Slack APIs',
      title: 'Slapp Library - Open Source',
      image_url: 'https://storage.googleapis.com/beepboophq/_assets/bot-1.22f6fb.png',
      title_link: 'https://beepboophq.com/',
      color: '#7CD197'
    }]
  })
})

// Catch-all for any other responses not handled above
slapp.message('.*', ['direct_mention', 'direct_message'], (msg) => {
  // respond only 40% of the time
  if (Math.random() < 0.4) {
    msg.say([':wave:', ':pray:', ':raised_hands:'])
  }
})

// attach Slapp to express server
var server = slapp.attachToExpress(express())

// start http server
server.listen(port, (err) => {
  if (err) {
    return console.error(err)
  }

  console.log(`Listening on port ${port}`)
})
<commit_msg>event.user<commit_after>'use strict'

const express = require('express')
const Slapp = require('slapp')
const ConvoStore = require('slapp-convo-beepboop')
const Context = require('slapp-context-beepboop')
const slack = require('slack')

// use `PORT` env var on Beep Boop - default to 3000 locally
var port = process.env.PORT || 3000
var token =process.env.SLACK_VERIFY_TOKEN

var slapp = Slapp({
  // Beep Boop sets the SLACK_VERIFY_TOKEN env var
  verify_token: process.env.SLACK_VERIFY_TOKEN,
  convo_store: ConvoStore(),
  context: Context()
})

var HELP_TEXT = `
I will respond to the following messages:
\`help\` - to see this message.
\`hi\` - to demonstrate a conversation that tracks state.
\`thanks\` - to demonstrate a simple response.
\`<type-any-other-text>\` - to demonstrate a random emoticon response, some of the time :wink:.
\`attachment\` - to see a Slack attachment message.
`

//*********************************************
// Setup different handlers for messages
//*********************************************

// response to the user typing "help"
slapp.message('help', ['mention', 'direct_message'], (msg) => {
  msg.say(HELP_TEXT)
})

slapp.event('team_join', (msg) => {

  slapp.client.im.open({ token: msg.meta.bot_token, user: msg.body.event.user }, (err, data) => {
    if (err) {
      return console.error(err)
    }
    let channel = data.channel.id

    msg.say({ channel: channel, text: 'Please visite www.neurotechedu.com' })
    msg.say({ channel: channel, text: help })
    })

})
// "Conversation" flow that tracks state - kicks off when user says hi, hello or hey
slapp
  .message('^(hi|hello|hey)$', ['direct_mention', 'direct_message'], (msg, text) => {
    msg
      .say(`${text}, how are you?`)
      // sends next event from user to this route, passing along state
      .route('how-are-you', { greeting: text })
  })
  .route('how-are-you', (msg, state) => {
    var text = (msg.body.event && msg.body.event.text) || ''

    // user may not have typed text as their next action, ask again and re-route
    if (!text) {
      return msg
        .say("Whoops, I'm still waiting to hear how you're doing.")
        .say('How are you?')
        .route('how-are-you', state)
    }

    // add their response to state
    state.status = text

    msg
      .say(`Ok then. What's your favorite color?`)
      .route('color', state)
  })
  .route('color', (msg, state) => {
    var text = (msg.body.event && msg.body.event.text) || ''

    // user may not have typed text as their next action, ask again and re-route
    if (!text) {
      return msg
        .say("I'm eagerly awaiting to hear your favorite color.")
        .route('color', state)
    }

    // add their response to state
    state.color = text

    msg
      .say('Thanks for sharing.')
      .say(`Here's what you've told me so far: \`\`\`${JSON.stringify(state)}\`\`\``)
    // At this point, since we don't route anywhere, the "conversation" is over
  })

// Can use a regex as well
slapp.message(/^(thanks|thank you)/i, ['mention', 'direct_message'], (msg) => {
  // You can provide a list of responses, and a random one will be chosen
  // You can also include slack emoji in your responses
  msg.say([
    "You're welcome :smile:",
    'You bet',
    ':+1: Of course',
    'Anytime :sun_with_face: :full_moon_with_face:'
  ])
})

// demonstrate returning an attachment...
slapp.message('attachment', ['mention', 'direct_message'], (msg) => {
  msg.say({
    text: 'Check out this amazing attachment! :confetti_ball: ',
    attachments: [{
      text: 'Slapp is a robust open source library that sits on top of the Slack APIs',
      title: 'Slapp Library - Open Source',
      image_url: 'https://storage.googleapis.com/beepboophq/_assets/bot-1.22f6fb.png',
      title_link: 'https://beepboophq.com/',
      color: '#7CD197'
    }]
  })
})

// Catch-all for any other responses not handled above
slapp.message('.*', ['direct_mention', 'direct_message'], (msg) => {
  // respond only 40% of the time
  if (Math.random() < 0.4) {
    msg.say([':wave:', ':pray:', ':raised_hands:'])
  }
})

// attach Slapp to express server
var server = slapp.attachToExpress(express())

// start http server
server.listen(port, (err) => {
  if (err) {
    return console.error(err)
  }

  console.log(`Listening on port ${port}`)
})
<|endoftext|>


<commit_before>var child_process = require('child_process')
var fs = require('fs');
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator
//First cut at libfaketime support

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes",
  "One more time...",
  "Re-commiting last",
  "One more User Story done",
 <commit_msg>Not quite working<commit_after>var child_process = require('child_process')
var fs = require('fs');
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator
//First cut at libfaketime support

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes",
  "One more time...",
  "Re-commiting last",
  "One more User Story done",
  <|endoftext|>


<commit_before>var child_process = require('child_process')
var fs = require('fs');
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator
//First cut at libfaketime support

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who y<commit_msg>Fixed memory parsing error #1337<commit_after>var child_process = require('child_process')
var fs = require('fs');
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator
//First cut at libfaketime support

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who yo<|endoftext|>


<commit_before>'use strict';

var mongoose = require('mongoose'),
  Schema = mongoose.Schema;

/**
 * Post Schema
 */
var PostSchema = new Schema({
  author: { type: String, required: true},
  createDate: { type: Date, default: Date.now() }, // 생성 시간
  updateDate: { type: Date, default: Date.now() } // 수정 시간
}, { collection: 'posts' });

/**
 * Model Methods
 */

module.exports = mongoose.model('Post', PostSchema);<commit_msg>Update posts<commit_after>'use strict';

var mongoose = require('mongoose'),
  Schema = mongoose.Schema;

/**
 * Post Schema
 */
var PostSchema = new Schema({
  subject: { type: String, required: true },
  content: { type: String, required: true },
  author: { type: String, required: true },
  isSecret: { type: Boolean, default: true },
  createDate: { type: Date, default: Date.now() }, // 생성 시간
  updateDate: { type: Date, default: Date.now() } // 수정 시간
}, { collection: 'posts' });

/**
 * Model Methods
 */

module.exports = mongoose.model('Post', PostSchema);<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import * as firebase from 'firebase'
import { FirebaseAuth } from 'react-firebaseui'
import {
  dashboardURL
} from 'navigation/navigation'
import {
  signupPageButtonClick,
  signupPageEmailButtonClick,
  signupPageSocialButtonClick
} from 'analytics/logEvent'

class FirebaseAuthenticationUI extends React.Component {
  componentWillMount () {
    this.configureFirebaseUI()
  }

  componentWillUnmount () {
    this.removeButtonClickListeners()
  }

  socialButtonClicked (e) {
    signupPageButtonClick()
    signupPageSocialButtonClick()
  }

  emailButtonClicked (e) {
    signupPageButtonClick()
    signupPageEmailButtonClick()
  }

  // Poll a few times for an element by classnames
  async getElementByClassNamePolling (classnames) {
    function getElems () {
      return document.getElementsByClassName(classnames)
    }
    function timeout (ms) {
      return new Promise(resolve => setTimeout(resolve, ms))
    }
    var elems = []
    const timesToPoll = 10
    const pollIntervalMs = 100
    var times = 0
    while (times < timesToPoll) {
      elems = getElems()
      if (elems.length) {
        return elems[0]
      }
      // If could not find the elem, continue polling
      times += 1
      await timeout(pollIntervalMs)
    }
    return null
  }

  // TODO: fix this hack after replacing/updating firebaseweb-ui.
  // This callback is called before the sign-in buttons are
  // rendered, so poll for the elements.
  async addButtonClickListeners () {
    // Facebook
    const facebookButton = await this.getElementByClassNamePolling(
      'firebaseui-idp-button firebaseui-idp-facebook')
    if (facebookButton) {
      facebookButton.addEventListener('click', this.socialButtonClicked)
    }

    // Google
    const googleButton = await this.getElementByClassNamePolling(
      'firebaseui-idp-button firebaseui-idp-google')
    if (googleButton) {
      googleButton.addEventListener('click', this.socialButtonClicked)
    }

    // // Twitter
    // const twitterButton = await this.getElementByClassNamePolling(
    //   'firebaseui-idp-button firebaseui-idp-twitter')
    // if (twitterButton) {
    //   twitterButton.addEventListener('click', this.socialButtonClicked)
    // }

    // Email & password
    const emailButton = await this.getElementByClassNamePolling(
      'firebaseui-idp-button firebaseui-idp-password')
    if (emailButton) {
      emailButton.addEventListener('click', this.emailButtonClicked)
    }
  }

  async removeButtonClickListeners () {
    // Facebook
    const facebookButton = await this.getElementByClassNamePolling(
      'firebaseui-idp-button firebaseui-idp-facebook')
    if (facebookButton) {
      facebookButton.removeEventListener('click', this.socialButtonClicked)
    }

    // Google
    const googleButton = await this.getElementByClassNamePolling(
      'firebaseui-idp-button firebaseui-idp-google')
    if (googleButton) {
      googleButton.removeEventListener('click', this.socialButtonClicked)
    }

    // // Twitter
    // const twitterButton = await this.getElementByClassNamePolling(
    //   'firebaseui-idp-button firebaseui-idp-twitter')
    // if (twitterButton) {
    //   twitterButton.removeEventListener('click', this.socialButtonClicked)
    // }

    // Email & password
    const emailButton = await this.getElementByClassNamePolling(
      'firebaseui-idp-button firebaseui-idp-password')
    if (emailButton) {
      emailButton.removeEventListener('click', this.emailButtonClicked)
    }
  }

  configureFirebaseUI () {
    // Configure FirebaseUI.
    // https://github.com/firebase/firebaseui-web#example-with-all-parameters-used
    this.uiConfig = {
      // Either 'popup' or 'redirect'
      signInFlow: 'popup',
      // Redirect path after successful sign in, or a callbacks.signInSuccess function
      signInSuccessUrl: dashboardURL,
      // Auth providers
      // https://github.com/firebase/firebaseui-web#configure-oauth-providers
      signInOptions: [
        {
          provider: firebase.auth.GoogleAuthProvider.PROVIDER_ID,
          scopes: ['https://www.googleapis.com/auth/userinfo.email']
        },
        {
          provider: firebase.auth.FacebookAuthProvider.PROVIDER_ID,
          scopes: ['email']
        },
        {
          provider: firebase.auth.EmailAuthProvider.PROVIDER_ID,
          requireDisplayName: false
        }
      ],
      callbacks: {
        signInSuccess: (currentUser, credential, redirectUrl) => {
          this.props.onSignInSuccess(currentUser, credential, redirectUrl)

          // Do not automatically redirect to the signInSuccessUrl.
          return false
        },
        uiShown: () => {
          this.addButtonClickListeners()
        }
      },
      // Just using the constant rather than importing firebaseui
      // https://github.com/firebase/firebaseui-web#credential-helper
      // https://github.com/firebase/firebaseui-web/blob/bd710448caa34c4a47a2fd578d76be8506d392d8/javascript/widgets/config.js#L83
      credentialHelper: 'none',
      tosUrl: 'https://tab.gladly.io/more/terms'
    }
  }

  render () {
    return (
      <FirebaseAuth uiConfig={this.uiConfig} firebaseAuth={firebase.auth()} />
    )
  }
}

FirebaseAuthenticationUI.propTypes = {
  onSignInSuccess: PropTypes.func.isRequired
}

// https://github.com/facebook/react/issues/6653
FirebaseAuthenticationUI.defaultProps = {
  onSignInSuccess: () => {}
}

export default FirebaseAuthenticationUI
<commit_msg>Try IDP auth redirect instead of popup.<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import * as firebase from 'firebase'
import { FirebaseAuth } from 'react-firebaseui'
import {
  dashboardURL
} from 'navigation/navigation'
import {
  signupPageButtonClick,
  signupPageEmailButtonClick,
  signupPageSocialButtonClick
} from 'analytics/logEvent'

class FirebaseAuthenticationUI extends React.Component {
  componentWillMount () {
    this.configureFirebaseUI()
  }

  componentWillUnmount () {
    this.removeButtonClickListeners()
  }

  socialButtonClicked (e) {
    signupPageButtonClick()
    signupPageSocialButtonClick()
  }

  emailButtonClicked (e) {
    signupPageButtonClick()
    signupPageEmailButtonClick()
  }

  // Poll a few times for an element by classnames
  async getElementByClassNamePolling (classnames) {
    function getElems () {
      return document.getElementsByClassName(classnames)
    }
    function timeout (ms) {
      return new Promise(resolve => setTimeout(resolve, ms))
    }
    var elems = []
    const timesToPoll = 10
    const pollIntervalMs = 100
    var times = 0
    while (times < timesToPoll) {
      elems = getElems()
      if (elems.length) {
        return elems[0]
      }
      // If could not find the elem, continue polling
      times += 1
      await timeout(pollIntervalMs)
    }
    return null
  }

  // TODO: fix this hack after replacing/updating firebaseweb-ui.
  // This callback is called before the sign-in buttons are
  // rendered, so poll for the elements.
  async addButtonClickListeners () {
    // Facebook
    const facebookButton = await this.getElementByClassNamePolling(
      'firebaseui-idp-button firebaseui-idp-facebook')
    if (facebookButton) {
      facebookButton.addEventListener('click', this.socialButtonClicked)
    }

    // Google
    const googleButton = await this.getElementByClassNamePolling(
      'firebaseui-idp-button firebaseui-idp-google')
    if (googleButton) {
      googleButton.addEventListener('click', this.socialButtonClicked)
    }

    // // Twitter
    // const twitterButton = await this.getElementByClassNamePolling(
    //   'firebaseui-idp-button firebaseui-idp-twitter')
    // if (twitterButton) {
    //   twitterButton.addEventListener('click', this.socialButtonClicked)
    // }

    // Email & password
    const emailButton = await this.getElementByClassNamePolling(
      'firebaseui-idp-button firebaseui-idp-password')
    if (emailButton) {
      emailButton.addEventListener('click', this.emailButtonClicked)
    }
  }

  async removeButtonClickListeners () {
    // Facebook
    const facebookButton = await this.getElementByClassNamePolling(
      'firebaseui-idp-button firebaseui-idp-facebook')
    if (facebookButton) {
      facebookButton.removeEventListener('click', this.socialButtonClicked)
    }

    // Google
    const googleButton = await this.getElementByClassNamePolling(
      'firebaseui-idp-button firebaseui-idp-google')
    if (googleButton) {
      googleButton.removeEventListener('click', this.socialButtonClicked)
    }

    // // Twitter
    // const twitterButton = await this.getElementByClassNamePolling(
    //   'firebaseui-idp-button firebaseui-idp-twitter')
    // if (twitterButton) {
    //   twitterButton.removeEventListener('click', this.socialButtonClicked)
    // }

    // Email & password
    const emailButton = await this.getElementByClassNamePolling(
      'firebaseui-idp-button firebaseui-idp-password')
    if (emailButton) {
      emailButton.removeEventListener('click', this.emailButtonClicked)
    }
  }

  configureFirebaseUI () {
    // Configure FirebaseUI.
    // https://github.com/firebase/firebaseui-web#example-with-all-parameters-used
    this.uiConfig = {
      // Either 'popup' or 'redirect'
      signInFlow: 'redirect',
      // Redirect path after successful sign in, or a callbacks.signInSuccess function
      signInSuccessUrl: dashboardURL,
      // Auth providers
      // https://github.com/firebase/firebaseui-web#configure-oauth-providers
      signInOptions: [
        {
          provider: firebase.auth.GoogleAuthProvider.PROVIDER_ID,
          scopes: ['https://www.googleapis.com/auth/userinfo.email']
        },
        {
          provider: firebase.auth.FacebookAuthProvider.PROVIDER_ID,
          scopes: ['email']
        },
        {
          provider: firebase.auth.EmailAuthProvider.PROVIDER_ID,
          requireDisplayName: false
        }
      ],
      callbacks: {
        signInSuccess: (currentUser, credential, redirectUrl) => {
          this.props.onSignInSuccess(currentUser, credential, redirectUrl)

          // Do not automatically redirect to the signInSuccessUrl.
          return false
        },
        uiShown: () => {
          this.addButtonClickListeners()
        }
      },
      // Just using the constant rather than importing firebaseui
      // https://github.com/firebase/firebaseui-web#credential-helper
      // https://github.com/firebase/firebaseui-web/blob/bd710448caa34c4a47a2fd578d76be8506d392d8/javascript/widgets/config.js#L83
      credentialHelper: 'none',
      tosUrl: 'https://tab.gladly.io/more/terms'
    }
  }

  render () {
    return (
      <FirebaseAuth uiConfig={this.uiConfig} firebaseAuth={firebase.auth()} />
    )
  }
}

FirebaseAuthenticationUI.propTypes = {
  onSignInSuccess: PropTypes.func.isRequired
}

// https://github.com/facebook/react/issues/6653
FirebaseAuthenticationUI.defaultProps = {
  onSignInSuccess: () => {}
}

export default FirebaseAuthenticationUI
<|endoftext|>


<commit_before>/* jshint esversion: 6 */
const myConfig = require('./config.json');
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const bodyParser = require('body-parser');
const Discord = require('discord.js');
const bot = new Discord.Client({autoReconnect:true});
app.set('serverPort', myConfig.serverPort);
app.use(bodyParser.urlencoded({
  extended: true
}));
let botInvites = [];
app.use(bodyParser.json());
const prefix = '!'
bot.on('message', message => {
  if (!message.content.startsWith(prefix) || message.author.bot) return;
  const args = message.content.slice(prefix.length).split(' ');
  const command = args.shift().toLowerCase();
  if (command === 'kern') {
    message.channel.sendMessage('https://clips.twitch.tv/MistyNiceBibimbapTheRinger');
  } else if (command === 'kern2') {
    message.channel.sendMessage('https://clips.twitch.tv/SarcasticConcernedHedgehogTebowing');
  } else if (command === 'varcster') {
    message.channel.sendMessage('https://www.twitch.tv/videos/68214198');
  } else if (command === 'zesty') {
    message.channel.sendMessage('https://clips.twitch.tv/SpoopyFreezingWrenOSsloth');
  } else if (command === 'sephyr') {
    message.channel.sendMessage('https://www.youtube.com/watch?v=p9UZnxDVxTY');
  } else if (command === 'dimi') {
    message.channel.sendMessage('https://clips.twitch.tv/PowerfulFancyOcelotAliens');
  } else if (command === 'fire') {
    message.channel.sendMessage('https://youtu.be/V552exgHaWU');
  } else if (command === 'stagger') {
    message.channel.sendMessage('When they nerf stagger \n https://cdn.discordapp.com/attachments/444357789025042432/507587021213007883/image0.jpg');
  } else if (command === 'mrblizzard') {
    message.channel.sendMessage('https://youtu.be/dstyQa9JRgY');
  } else if (command === 'diminudes') {
    message.channel.sendMessage('<https://www.youtube.com/watch?v=dQw4w9WgXcQ>');
  } else if (command === 'seabreeze') {
    message.channel.sendMessage(`PriestBot: How good is Seabreeze for shadow? Is the haste proc worth the lack of secondaries?\n\nIts not awful but its not amazing either. Mostly it doesnt change your gear prioritization. Its worth a tiny bit less than staves with BIS stats at the same ilvl`);
  } else if (command === 'deism') {
    message.channel.sendMessage('https://clips.twitch.tv/BashfulCourageousDootHassaanChop');
  } else if (command === 'bthelight') {
    message.channel.sendMessage('https://www.twitch.tv/videos/127633788');
  } else if (command === 'swampletics') {
    message.channel.sendMessage(`Meet Swampletics, my Morytania locked ultimate ironman. After recently maxing my ultimate ironman I decided to up the ante, and forge my own journey from scratch. No banking, no trading, but this time I can't leave Morytania.\n<https://youtu.be/rk5XuqLrf3U>`)
  } else if (command === 'bobcommands') {
    message.channel.sendMessage(`!kern\n!varcster\n!zesty\n!sephyr\n!dimi\n!fire\n!stagger\n!mrblizzard\n!diminudes\n!seabreeze\n!kern2\n!deism\n!bthelight\n!swampletics\n!bobcommands`);
  }
});

bot.on('ready', () => {
  console.log('I am ready!');
  let guild = bot.guilds.find(val => val.id === myConfig.guildID);
  if (guild.available) {
    guild.fetchInvites()
      .then(invites => {
        for (const invite of invites.array()) {
          if (invite.inviter && invite.inviter.id &&
            invite.inviter.id === myConfig.botID && invite.uses !== null &&
            invite.uses === 0)
            botInvites.push(invite.code);
        }
      })
      .catch(console.error);
  }
});
bot.on('guildMemberAdd', (member) => {
  let guild = bot.guilds.find(val => val.id === myConfig.guildID);
  if (guild.available) {
    guild.fetchInvites()
      .then(invites => {
        for (const invite of invites.array()) {
          for (var i = 0; i < botInvites.length; i++) {
            if (invite.code === botInvites[i] && invite.uses >= 1) {
              createApplicantUser(member, invite, i);
            }
          }
        }
      })
      .catch(console.error);
  }
});

const createApplicantUser = (member, invite, i) => {
  member.addRole(myConfig.applicantRoleID)
    .then((member) => {
      if (invite.channel) {
        invite.channel.overwritePermissions(member, {
         SEND_MESSAGES: true,
         READ_MESSAGES: true,
         EMBED_LINKS: true,
         READ_MESSAGE_HISTORY:true,
         ATTACH_FILES: true
        })
        .then(() => {
          member.setNickname(invite.channel.name)
            .then((applicant) => {
              invite.channel.sendMessage(`${applicant.user} Thanks for applying to revive. You can find your application here please feel free to ask any questions.`);
            })
            .catch(console.error);
        })
        .catch(console.error);
      }
    })
    .catch(console.error);
  invite.delete()
    .then(invite => {
      botInvites.splice(i,1);
    })
    .catch(console.error);
};

app.post('/discord/createGuildApp', (req,res) => {
  const applicationData = {
    name:req.body.name,
    loc:req.body.loc,
    tag:req.body.tag,
    armory:req.body.armory,
    sscombat:req.body.sscombat,
    headset:req.body.headset,
    logs:req.body.logs,
    role:req.body.role,
    awp:req.body.awp,
    prog:req.body.prog,
    left:req.body.left,
    rotation:req.body.rotation,
    resources:req.body.resources,
    hear:req.body.hear,
    crit:req.body.crit,
    sit:req.body.sit,
    schedule:req.body.schedule,
    beta:req.body.beta,
    about:req.body.about,
    joke:req.body.joke
  };
  const applicationText = `**What is your Name, Age and Sex?**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
<${applicationData.name}>\n\n
**Provide the location you will primarily will be playing from and a speedtest.net screenshot from the Chicago server**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
<${applicationData.loc}>\n\n
**What is your Battle.net Tag**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
<${applicationData.tag}>\n\n
**Link to your main characters and alternate character's armory **\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
<${applicationData.armory}>\n\n
**Post a screenshot of your character in combat**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
<${applicationData.sscombat}>\n\n
**Do you have a functioning headset with microphone that you can use in Discord?**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
<${applicationData.headset}>\n\n
**Post your recent warcraft logs**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
<${applicationData.logs}>\n\n
**What role and spec are you applying for**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
<${applicationData.role}>\n\n
**Neck Level **\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
<${applicationData.awp}>\n\n
**List Previous Mythic/Heroic Progression Experiences**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
<${applicationData.prog}>\n\n
**Name your last TWO raiding guilds and the reason for leaving them?**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
<${applicationData.left}>\n\n
**Take us through your opening rotation on a SINGLE TARGET fight. (Healers Ignore this)**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
<${applicationData.rotation}>\n\n
**What resources do you use to improve yourself?**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
<${applicationData.resources}>\n\n
**How did you hear about us?**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
<${applicationData.hear}>\n\n
**How do you handle criticism and adult humor?**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
<${applicationData.crit}>\n\n
**You may be asked to sit on some fights for composition, gear, or general skill level how do you feel about that?**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
<${applicationData.sit}>\n\n
**Do you have any commitments or schedule changes that we should know about?**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
<${applicationData.schedule}>\n\n
**Are you willing to test new content in PTR/Alpha/Beta?**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
<${applicationData.beta}>\n\n
**Tell us a little bit about yourself. The more we know the better!**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
<${applicationData.about}>\n\n
**Tell us a joke**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
<${applicationData.joke}>\n\n`;
  let guild = bot.guilds.find(val => val.id === myConfig.guildID);
  let _this = this;
  if (guild.available) {
    const channel = applicationData.tag.replace('#','-');
    const permissions = [
      { id: '231944378577321984', type: 'role', deny: 0, allow: 3072 },
      { id: '291440686916698112', type: 'role', deny: 0, allow: 3072 },
      { id: '231933464201527298', type: 'role', deny: 1024, allow: 0 },
      {id: '231944387255336960',type: 'role',deny: 8192,allow: 3072 },
      {id: '231944378476658690',type:'role',deny:0,allow:3072},
      {id: '231948453737922580',type: 'role',deny: 8192,allow: 3072 }
    ];
    guild.createChannel(channel, 'text', permissions)
     .then(channel => {
       channel.createInvite({
         temporary: false,
         maxUses: 2
       }).then(invite => {
        botInvites.push(invite.code);
        res.send(invite.url);
       })
       .catch(console.error);
       channel.sendMessage(`@everyone New application please review.`).then(message => {
         channel.sendMessage(applicationText, {split:true})
         .then(message => {
         })
         .catch(console.error);
       }).catch(console.error());
     })
     .catch(console.error);
  }
});

app.get('/discord', (req,res) => {
  res.send("Revive-Discord-Bot");
});

app.get('/discord/callback', (req,res) => {
  //Handle Discord Request URI?
});

bot.login(myConfig.discordKey);

server.listen(app.get('serverPort'));
console.log('Listening on port', app.get('serverPort'));
<commit_msg>fix app thing<commit_after>/* jshint esversion: 6 */
const myConfig = require('./config.json');
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const bodyParser = require('body-parser');
const Discord = require('discord.js');
const bot = new Discord.Client({autoReconnect:true});
app.set('serverPort', myConfig.serverPort);
app.use(bodyParser.urlencoded({
  extended: true
}));
let botInvites = [];
app.use(bodyParser.json());
const prefix = '!'
bot.on('message', message => {
  if (!message.content.startsWith(prefix) || message.author.bot) return;
  const args = message.content.slice(prefix.length).split(' ');
  const command = args.shift().toLowerCase();
  if (command === 'kern') {
    message.channel.sendMessage('https://clips.twitch.tv/MistyNiceBibimbapTheRinger');
  } else if (command === 'kern2') {
    message.channel.sendMessage('https://clips.twitch.tv/SarcasticConcernedHedgehogTebowing');
  } else if (command === 'varcster') {
    message.channel.sendMessage('https://www.twitch.tv/videos/68214198');
  } else if (command === 'zesty') {
    message.channel.sendMessage('https://clips.twitch.tv/SpoopyFreezingWrenOSsloth');
  } else if (command === 'sephyr') {
    message.channel.sendMessage('https://www.youtube.com/watch?v=p9UZnxDVxTY');
  } else if (command === 'dimi') {
    message.channel.sendMessage('https://clips.twitch.tv/PowerfulFancyOcelotAliens');
  } else if (command === 'fire') {
    message.channel.sendMessage('https://youtu.be/V552exgHaWU');
  } else if (command === 'stagger') {
    message.channel.sendMessage('When they nerf stagger \n https://cdn.discordapp.com/attachments/444357789025042432/507587021213007883/image0.jpg');
  } else if (command === 'mrblizzard') {
    message.channel.sendMessage('https://youtu.be/dstyQa9JRgY');
  } else if (command === 'diminudes') {
    message.channel.sendMessage('ಠ_ಠ');
  } else if (command === 'seabreeze') {
    message.channel.sendMessage(`PriestBot: How good is Seabreeze for shadow? Is the haste proc worth the lack of secondaries?\n\nIts not awful but its not amazing either. Mostly it doesnt change your gear prioritization. Its worth a tiny bit less than staves with BIS stats at the same ilvl`);
  } else if (command === 'deism') {
    message.channel.sendMessage('https://clips.twitch.tv/BashfulCourageousDootHassaanChop');
  } else if (command === 'bthelight') {
    message.channel.sendMessage('https://www.twitch.tv/videos/127633788');
  } else if (command === 'swampletics') {
    message.channel.sendMessage(`Meet Swampletics, my Morytania locked ultimate ironman. After recently maxing my ultimate ironman I decided to up the ante, and forge my own journey from scratch. No banking, no trading, but this time I can't leave Morytania.\n<https://youtu.be/rk5XuqLrf3U>`)
  } else if (command === 'bobcommands') {
    message.channel.sendMessage(`!kern\n!varcster\n!zesty\n!sephyr\n!dimi\n!fire\n!stagger\n!mrblizzard\n!diminudes\n!seabreeze\n!kern2\n!deism\n!bthelight\n!swampletics\n!bobcommands`);
  }
});

bot.on('ready', () => {
  console.log('I am ready!');
  let guild = bot.guilds.find(val => val.id === myConfig.guildID);
  if (guild.available) {
    guild.fetchInvites()
      .then(invites => {
        for (const invite of invites.array()) {
          if (invite.inviter && invite.inviter.id &&
            invite.inviter.id === myConfig.botID && invite.uses !== null &&
            invite.uses === 0)
            botInvites.push(invite.code);
        }
      })
      .catch(console.error);
  }
});
bot.on('guildMemberAdd', (member) => {
  let guild = bot.guilds.find(val => val.id === myConfig.guildID);
  if (guild.available) {
    guild.fetchInvites()
      .then(invites => {
        for (const invite of invites.array()) {
          for (var i = 0; i < botInvites.length; i++) {
            if (invite.code === botInvites[i] && invite.uses >= 1) {
              createApplicantUser(member, invite, i);
            }
          }
        }
      })
      .catch(console.error);
  }
});

const createApplicantUser = (member, invite, i) => {
  member.addRole(myConfig.applicantRoleID)
    .then((member) => {
      if (invite.channel) {
        invite.channel.overwritePermissions(member, {
         SEND_MESSAGES: true,
         READ_MESSAGES: true,
         EMBED_LINKS: true,
         READ_MESSAGE_HISTORY:true,
         ATTACH_FILES: true
        })
        .then(() => {
          member.setNickname(invite.channel.name)
            .then((applicant) => {
              invite.channel.sendMessage(`${applicant.user} Thanks for applying to revive. You can find your application here please feel free to ask any questions.`);
            })
            .catch(console.error);
        })
        .catch(console.error);
      }
    })
    .catch(console.error);
  invite.delete()
    .then(invite => {
      botInvites.splice(i,1);
    })
    .catch(console.error);
};

app.post('/discord/createGuildApp', (req,res) => {
  const applicationData = {
    name:req.body.name,
    loc:req.body.loc,
    tag:req.body.tag,
    armory:req.body.armory,
    sscombat:req.body.sscombat,
    headset:req.body.headset,
    logs:req.body.logs,
    role:req.body.role,
    awp:req.body.awp,
    prog:req.body.prog,
    left:req.body.left,
    rotation:req.body.rotation,
    resources:req.body.resources,
    hear:req.body.hear,
    crit:req.body.crit,
    sit:req.body.sit,
    schedule:req.body.schedule,
    beta:req.body.beta,
    about:req.body.about,
    joke:req.body.joke
  };
  const applicationText = `**What is your Name, Age and Sex?**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
${applicationData.name}\n\n
**Provide the location you will primarily will be playing from and a speedtest.net screenshot from the Chicago server**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
<${applicationData.loc}>\n\n
**What is your Battle.net Tag**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
${applicationData.tag}\n\n
**Link to your main characters and alternate character's armory **\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
<${applicationData.armory}>\n\n
**Post a screenshot of your character in combat**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
<${applicationData.sscombat}>\n\n
**Do you have a functioning headset with microphone that you can use in Discord?**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
${applicationData.headset}\n\n
**Post your recent warcraft logs**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
<${applicationData.logs}>\n\n
**What role and spec are you applying for**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
${applicationData.role}\n\n
**Neck Level **\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
${applicationData.awp}\n\n
**List Previous Mythic/Heroic Progression Experiences**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
${applicationData.prog}\n\n
**Name your last TWO raiding guilds and the reason for leaving them?**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
${applicationData.left}\n\n
**Take us through your opening rotation on a SINGLE TARGET fight. (Healers Ignore this)**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
${applicationData.rotation}\n\n
**What resources do you use to improve yourself?**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
${applicationData.resources}\n\n
**How did you hear about us?**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
${applicationData.hear}\n\n
**How do you handle criticism and adult humor?**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
${applicationData.crit}\n\n
**You may be asked to sit on some fights for composition, gear, or general skill level how do you feel about that?**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
${applicationData.sit}\n\n
**Do you have any commitments or schedule changes that we should know about?**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
${applicationData.schedule}\n\n
**Are you willing to test new content in PTR/Alpha/Beta?**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
${applicationData.beta}\n\n
**Tell us a little bit about yourself. The more we know the better!**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
${applicationData.about}\n\n
**Tell us a joke**\n
━━━━━━━━━━━━━━━━━━━━━━━━\n
${applicationData.joke}\n\n`;
  let guild = bot.guilds.find(val => val.id === myConfig.guildID);
  let _this = this;
  if (guild.available) {
    const channel = applicationData.tag.replace('#','-');
    const permissions = [
      { id: '231944378577321984', type: 'role', deny: 0, allow: 3072 },
      { id: '291440686916698112', type: 'role', deny: 0, allow: 3072 },
      { id: '231933464201527298', type: 'role', deny: 1024, allow: 0 },
      {id: '231944387255336960',type: 'role',deny: 8192,allow: 3072 },
      {id: '231944378476658690',type:'role',deny:0,allow:3072},
      {id: '231948453737922580',type: 'role',deny: 8192,allow: 3072 }
    ];
    guild.createChannel(channel, 'text', permissions)
     .then(channel => {
       channel.createInvite({
         temporary: false,
         maxUses: 2
       }).then(invite => {
        botInvites.push(invite.code);
        res.send(invite.url);
       })
       .catch(console.error);
       channel.sendMessage(`@everyone New application please review.`).then(message => {
         channel.sendMessage(applicationText, {split:true})
         .then(message => {
         })
         .catch(console.error);
       }).catch(console.error());
     })
     .catch(console.error);
  }
});

app.get('/discord', (req,res) => {
  res.send("Revive-Discord-Bot");
});

app.get('/discord/callback', (req,res) => {
  //Handle Discord Request URI?
});

bot.login(myConfig.discordKey);

server.listen(app.get('serverPort'));
console.log('Listening on port', app.get('serverPort'));
<|endoftext|>


<commit_before>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300
//Added a comment that achieves no real goal.

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  console.info("Writing from %s to %s, with up to %s seconds between commits", inFile, outFile, max_sleep)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    console.info("Bytes: %s", length)
    try {
      child_process.execFileSync('/usr/bin/git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var message = commit_messages[randomIntFromInterval(0, commit_messages.length - 1)]
    var args = ['commit', outFile, '-m', message]
    for (var counter = 0; counter < length; counter++)
    {
      var message = commit_messages[randomIntFromInterval(0, commit_messages.length - 1)]
      var args = ['commit', outFile, '-m', message]
      fs.writeSync(outFD, data.slice(counter, counter+1), 0, 1)
      sleep(Math.random() * max_sleep)
      child_process.execFileSync('/usr/bin/git', args)
    }
  })
} else {
  console.info("Usage:")
  console.info("node commit.js infile outfile [time in seconds]")
}

function sleep(seconds) {
  var endTime = new Date().getTime() + (seconds * 1000);
  while (new <commit_msg>Fixed memory parsing error #1337<commit_after>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300
//Added a comment that achieves no real goal.

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  console.info("Writing from %s to %s, with up to %s seconds between commits", inFile, outFile, max_sleep)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    console.info("Bytes: %s", length)
    try {
      child_process.execFileSync('/usr/bin/git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var message = commit_messages[randomIntFromInterval(0, commit_messages.length - 1)]
    var args = ['commit', outFile, '-m', message]
    for (var counter = 0; counter < length; counter++)
    {
      var message = commit_messages[randomIntFromInterval(0, commit_messages.length - 1)]
      var args = ['commit', outFile, '-m', message]
      fs.writeSync(outFD, data.slice(counter, counter+1), 0, 1)
      sleep(Math.random() * max_sleep)
      child_process.execFileSync('/usr/bin/git', args)
    }
  })
} else {
  console.info("Usage:")
  console.info("node commit.js infile outfile [time in seconds]")
}

function sleep(seconds) {
  var endTime = new Date().getTime() + (seconds * 1000);
  while (new D<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

/* jshint maxparams:5 */

var assert = require('assert');
var util = require('util');
var fs = require('fs');
var path = require('path');
var setTimeout = require('timers').setTimeout;
var Errors = require('tchannel/errors.js');
var TChannelJSON = require('tchannel/as/json');
var TChannelThrift = require('tchannel/as/thrift');
var TChannelEndpointHandler = require('tchannel/endpoint-handler');

var MAX_RELAY_AD_ATTEMPTS = 2;
var RELAY_AD_RETRY_TIME = 1 * 1000;
var RELAY_AD_TIMEOUT = 500;

var RELAY_TIMEOUT = 500;

var thriftSource = fs.readFileSync(
    path.join(__dirname, 'hyperbahn.thrift'), 'utf8'
);

module.exports = HyperbahnHandler;

// TODO: should be part of Hyperbahn error file
var TypedError = require('error/typed');
var NoPeersAvailable = TypedError({
    type: 'hyperbahn.no-peers-available',
    nameAsThrift: 'noPeersAvailable',
    message: 'no peer available for {serviceName}',
    serviceName: null
});

var InvalidServiceName = TypedError({
    type: 'hyperbahn.invalid-service-name',
    nameAsThrift: 'invalidServiceName',
    message: 'invalid service name: {serviceName}',
    serviceName: null
});

function HyperbahnHandler(options) {
    if (!(this instanceof HyperbahnHandler)) {
        return new HyperbahnHandler(options);
    }

    var self = this;
    TChannelEndpointHandler.call(self, 'hyperbahn');

    assert(options && options.channel, 'channel required');
    assert(options && options.egressNodes, 'egressNodes required');
    assert(options && options.callerName, 'callerName required');

    // TODO support blackList

    self.channel = options.channel;
    self.egressNodes = options.egressNodes;
    self.callerName = options.callerName;

    self.tchannelJSON = TChannelJSON({
        logger: self.channel.logger
    });

    self.tchannelThrift = TChannelThrift({
        channel: self.channel,
        logger: self.channel.logger,
        source: thriftSource
    });

    // TODO replace JSON with real bufrw handlers for this
    self.tchannelJSON.register(self, 'ad', self,
        self.handleAdvertise);
    self.tchannelJSON.register(self, 'relay-ad', self,
        self.handleRelayAdvertise);
    self.tchannelJSON.register(self, 'unad', self,
        self.handleUnadvertise);
    self.tchannelJSON.register(self, 'relay-unad', self,
        self.handleRelayUnadvertise);

    self.tchannelThrift.register(self, 'Hyperbahn::discover', self,
        self.discover);

    self.relayAdTimeout = options.relayAdTimeout ||
        RELAY_AD_TIMEOUT;
    self.relayAdRetryTime = options.relayAdRetryTime ||
        RELAY_AD_RETRY_TIME;
    self.maxRelayAdAttempts = options.maxRelayAdAttempts ||
        MAX_RELAY_AD_ATTEMPTS;

    self.relayTimeout = options.relayTimeout || RELAY_TIMEOUT;
}
util.inherits(HyperbahnHandler, TChannelEndpointHandler);

HyperbahnHandler.prototype.type = 'hyperbahn.advertisement-handler';

/*  req: {
        services: Array<{
            serviceName: String,
            cost: Number
        }>
    }

    res: {
        connectionCount: Number
    }
*/
HyperbahnHandler.prototype.handleAdvertise =
function handleAdvertise(handler, req, arg2, arg3, cb) {
    handler.sendRelays(req, arg2, arg3, 'relay-ad', cb);
};

HyperbahnHandler.prototype.handleUnadvertise =
function handleUnadvertise(handler, req, arg2, arg3, cb) {
    handler.sendRelays(req, arg2, arg3, 'relay-unad', cb);
};

HyperbahnHandler.prototype.sendRelays =
function sendRelays(req, arg2, arg3, endpoint, cb) {
    /*eslint max-statements: [2, 25], max-params: [2, 6]*/
    var self = this;
    var services = arg3.services;

    var servicesByExitNode = {};

    for (var i = 0; i < services.length; i++) {
        var service = services[i];
        service.hostPort = req.connection.remoteName;

        var serviceName = service.serviceName;
        if (serviceName === '') {
            continue;
        }

        var exitNodes = self.egressNodes.exitsFor(serviceName);
        var exitHosts = Object.keys(exitNodes);

        for (var j = 0; j < exitHosts.length; j++) {
            var exitNode = exitHosts[j];

            var relayReq = servicesByExitNode[exitNode];
            if (!relayReq) {
                relayReq = servicesByExitNode[exitNode] = [];
            }

            relayReq.push(service);
        }
    }

    var exitNodeKeys = Object.keys(servicesByExitNode);
    var counter = 1 + exitNodeKeys.length;
    for (var k = 0; k < exitNodeKeys.length; k++) {
        var hostPort = exitNodeKeys[k];
        var exitNodeServices = servicesByExitNode[hostPort];

        self.sendRelay({
            hostPort: hostPort,
            services: exitNodeServices,
            inreq: req,
            endpoint: endpoint
        }, onFinish);
    }

    onFinish();

    // TODO remove blocking on fanout finish. Requires fixing
    // hyperbahn tests upstream
    function onFinish() {
        if (--counter === 0) {
            cb(null, {
                ok: true,
                head: null,
                body: {
                    connectionCount: exitNodeKeys.length
                }
            });
        }
    }
};

HyperbahnHandler.prototype.sendAdvertise =
function sendAdvertise(services, options, callback) {
    var self = this;

    if (typeof options === 'function') {
        callback = options;
        options = {};
    }

    options.serviceName = 'hyperbahn';
    options.trace = false;
    options.hasNoParent = true;
    options.headers = options.headers || {};
    options.headers.cn = self.callerName;

    var req = self.channel.request(options);
    self.tchannelJSON.send(req, 'ad', null, {
        services: services
    }, callback);
};

/*  req: {
        services: Array<{
            serviceName: String,
            hostPort: String,
            cost: Number
        }>
    }

    res: {}
*/
HyperbahnHandler.prototype.handleRelayAdvertise =
function handleRelayAdvertise(handler, req, arg2, arg3, cb) {
    handler.handleRelay('ad', req, arg2, arg3, cb);
};

HyperbahnHandler.prototype.handleRelayUnadvertise =
function handleRelayUnadvertise(handler, req, arg2, arg3, cb) {
    handler.handleRelay('unad', req, arg2, arg3, cb);
};

HyperbahnHandler.prototype.handleRelay =
function handleRelay(endpoint, req, arg2, arg3, cb) {
    var self = this;
    var services = arg3.services;
    var logger = self.channel.logger;

    for (var i = 0; i < services.length; i++) {
        var service = services[i];

        var exitNodes = self.egressNodes
            .exitsFor(service.serviceName);
        var exitHosts = Object.keys(exitNodes);

        var myHost = self.channel.hostPort;
        if (exitHosts.indexOf(myHost) < 0) {
            logger.warn('Non-exit node got relay', {
                endpoint: endpoint,
                service: service,
                myHost: myHost,
                exitHosts: exitHosts
            });
        } else if (endpoint === 'ad') {
            self.advertise(service);
        } else if (endpoint === 'unad') {
            self.unadvertise(service);
        } else {
            logger.error('Unexpected endpoint for relay', {
                endpoint: endpoint,
                service: service
            });
        }
    }

    cb(null, {
        ok: true,
        head: null,
        body: {}
    });
};

HyperbahnHandler.prototype.sendRelay =
function sendRelay(opts, callback) {
    var self = this;

    var attempts = 0;

    tryRequest();

    // TODO: move functions out to methods
    function tryRequest() {
        attempts++;

        self.channel.waitForIdentified({
            host: opts.hostPort
        }, onIdentified);

        function onIdentified(err) {
            if (err) {
                return onResponse(err);
            }

            self.tchannelJSON.send(self.channel.request({
                host: opts.hostPort,
                serviceName: 'hyperbahn',
                trace: false,
                timeout: self.relayAdTimeout,
                headers: {
                    cn: self.callerName
                },
                parent: opts.inreq,
                retryFlags: {
                    never: true
                }
            }), opts.endpoint, null, {
                services: opts.services
            }, onResponse);
        }

        function onResponse(err, response) {
            if (response && response.ok) {
                return callback(null, null);
            }

            var codeName = Errors.classify(err);
            if (attempts <= self.maxRelayAdAttempts && err &&
                (
                    codeName === 'NetworkError' ||
                    codeName === 'Timeout'
                )
            ) {
                setTimeout(tryRequest, self.relayAdRetryTime);
            } else {
                self.logError(err, opts, response);

                callback(null, null);
            }
        }
    }
};

HyperbahnHandler.prototype.logError =
function logError(err, opts, response) {
    var self = this;

    var logger = self.channel.logger;

    var logOptions = {
        exitNode: opts.hostPort,
        services: opts.services,
        responseBody: response && response.body,
        error: err
    };

    var codeName = Errors.classify(err);
    if (codeName === 'NetworkError' ||
        codeName === 'Timeout'
    ) {
        logger.warn('Relay advertise failed with expected err', logOptions);
    } else {
        logger.error('Relay advertise failed with unexpected err', logOptions);
    }
};

HyperbahnHandler.prototype.advertise =
function advertise(service) {
    var self = this;
    self.channel.topChannel.handler.refreshServicePeer(service.serviceName, service.hostPort);
};

HyperbahnHandler.prototype.unadvertise =
function unadvertise(service) {
    var self = this;
    self.channel.topChannel.handler.removeServicePeer(service.serviceName, service.hostPort);
};

function convertHosts(hosts) {
    var res = [];
    for (var i = 0; i < hosts.length; i++) {
        var strs = hosts[i].split(':');
        var obj = {
            port: parseInt(strs[1], 10)
        };
        strs = strs[0].split('.');
        obj.ip = {
            ipv4: parseInt(strs[3], 10) + (parseInt(strs[2], 10) << 8) +
                (parseInt(strs[1], 10) << 16) + (parseInt(strs[0], 10) << 24)
        };

        res.push(obj);
    }

    return res;
}

HyperbahnHandler.prototype.discover =
function discover(handler, req, head, body, cb) {
    var serviceName = body.query.serviceName;
    if (serviceName.length === 0) {
        cb(null, {
            ok: false,
            body: InvalidServiceName({
                serviceName: serviceName
            }),
            typeName: 'invalidServiceName'
        });
        return;
    }

    var exitNodes = handler.egressNodes.exitsFor(serviceName);
    var exitHosts = Object.keys(exitNodes);

    var svcchan = null;
    var myHost = handler.channel.hostPort;
    if (exitHosts.indexOf(myHost) === -1) {
        // Since Hyperbahn is fully connected to service hosts,
        // any exit node suffices.
        svcchan = handler.channel.topChannel.handler.getOrCreateServiceChannel(serviceName);
        handler.tchannelThrift.send(svcchan.request({
            serviceName: 'hyperbahn',
            headers: {
                cn: 'hyperbahn'
            },
            parent: req,
            timeout: 5000,
            timeoutPerAttempt: 500,
            trace: false
        }), 'Hyperbahn::discover', null, body, function handleForward(err, resp) {
            if (err) {
                handler.channel.logger.error('Failed to call discover API on exit node', {
                    error: err,
                    serviceName: serviceName
                });
                return cb(err, null);
            }

            cb(null, resp);
        });
    } else {
        svcchan = handler.channel.topChannel.subChannels[serviceName];
        var hosts = [];
        if (svcchan) {
            hosts = convertHosts(svcchan.peers.keys());
        }
        if (hosts.length === 0) {
            cb(null, {
                ok: false,
                body: NoPeersAvailable({
                    serviceName: serviceName
                }),
                typeName: 'noPeersAvailable'
            });
        } else {
            cb(null, {
                ok: true,
                body: {
                    peers: hosts
                }
            });
        }
    }
};
<commit_msg>handler: use tchannel/errors.isFatal<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

/* jshint maxparams:5 */

var assert = require('assert');
var util = require('util');
var fs = require('fs');
var path = require('path');
var setTimeout = require('timers').setTimeout;
var Errors = require('tchannel/errors.js');
var TChannelJSON = require('tchannel/as/json');
var TChannelThrift = require('tchannel/as/thrift');
var TChannelEndpointHandler = require('tchannel/endpoint-handler');

var MAX_RELAY_AD_ATTEMPTS = 2;
var RELAY_AD_RETRY_TIME = 1 * 1000;
var RELAY_AD_TIMEOUT = 500;

var RELAY_TIMEOUT = 500;

var thriftSource = fs.readFileSync(
    path.join(__dirname, 'hyperbahn.thrift'), 'utf8'
);

module.exports = HyperbahnHandler;

// TODO: should be part of Hyperbahn error file
var TypedError = require('error/typed');
var NoPeersAvailable = TypedError({
    type: 'hyperbahn.no-peers-available',
    nameAsThrift: 'noPeersAvailable',
    message: 'no peer available for {serviceName}',
    serviceName: null
});

var InvalidServiceName = TypedError({
    type: 'hyperbahn.invalid-service-name',
    nameAsThrift: 'invalidServiceName',
    message: 'invalid service name: {serviceName}',
    serviceName: null
});

function HyperbahnHandler(options) {
    if (!(this instanceof HyperbahnHandler)) {
        return new HyperbahnHandler(options);
    }

    var self = this;
    TChannelEndpointHandler.call(self, 'hyperbahn');

    assert(options && options.channel, 'channel required');
    assert(options && options.egressNodes, 'egressNodes required');
    assert(options && options.callerName, 'callerName required');

    // TODO support blackList

    self.channel = options.channel;
    self.egressNodes = options.egressNodes;
    self.callerName = options.callerName;

    self.tchannelJSON = TChannelJSON({
        logger: self.channel.logger
    });

    self.tchannelThrift = TChannelThrift({
        channel: self.channel,
        logger: self.channel.logger,
        source: thriftSource
    });

    // TODO replace JSON with real bufrw handlers for this
    self.tchannelJSON.register(self, 'ad', self,
        self.handleAdvertise);
    self.tchannelJSON.register(self, 'relay-ad', self,
        self.handleRelayAdvertise);
    self.tchannelJSON.register(self, 'unad', self,
        self.handleUnadvertise);
    self.tchannelJSON.register(self, 'relay-unad', self,
        self.handleRelayUnadvertise);

    self.tchannelThrift.register(self, 'Hyperbahn::discover', self,
        self.discover);

    self.relayAdTimeout = options.relayAdTimeout ||
        RELAY_AD_TIMEOUT;
    self.relayAdRetryTime = options.relayAdRetryTime ||
        RELAY_AD_RETRY_TIME;
    self.maxRelayAdAttempts = options.maxRelayAdAttempts ||
        MAX_RELAY_AD_ATTEMPTS;

    self.relayTimeout = options.relayTimeout || RELAY_TIMEOUT;
}
util.inherits(HyperbahnHandler, TChannelEndpointHandler);

HyperbahnHandler.prototype.type = 'hyperbahn.advertisement-handler';

/*  req: {
        services: Array<{
            serviceName: String,
            cost: Number
        }>
    }

    res: {
        connectionCount: Number
    }
*/
HyperbahnHandler.prototype.handleAdvertise =
function handleAdvertise(handler, req, arg2, arg3, cb) {
    handler.sendRelays(req, arg2, arg3, 'relay-ad', cb);
};

HyperbahnHandler.prototype.handleUnadvertise =
function handleUnadvertise(handler, req, arg2, arg3, cb) {
    handler.sendRelays(req, arg2, arg3, 'relay-unad', cb);
};

HyperbahnHandler.prototype.sendRelays =
function sendRelays(req, arg2, arg3, endpoint, cb) {
    /*eslint max-statements: [2, 25], max-params: [2, 6]*/
    var self = this;
    var services = arg3.services;

    var servicesByExitNode = {};

    for (var i = 0; i < services.length; i++) {
        var service = services[i];
        service.hostPort = req.connection.remoteName;

        var serviceName = service.serviceName;
        if (serviceName === '') {
            continue;
        }

        var exitNodes = self.egressNodes.exitsFor(serviceName);
        var exitHosts = Object.keys(exitNodes);

        for (var j = 0; j < exitHosts.length; j++) {
            var exitNode = exitHosts[j];

            var relayReq = servicesByExitNode[exitNode];
            if (!relayReq) {
                relayReq = servicesByExitNode[exitNode] = [];
            }

            relayReq.push(service);
        }
    }

    var exitNodeKeys = Object.keys(servicesByExitNode);
    var counter = 1 + exitNodeKeys.length;
    for (var k = 0; k < exitNodeKeys.length; k++) {
        var hostPort = exitNodeKeys[k];
        var exitNodeServices = servicesByExitNode[hostPort];

        self.sendRelay({
            hostPort: hostPort,
            services: exitNodeServices,
            inreq: req,
            endpoint: endpoint
        }, onFinish);
    }

    onFinish();

    // TODO remove blocking on fanout finish. Requires fixing
    // hyperbahn tests upstream
    function onFinish() {
        if (--counter === 0) {
            cb(null, {
                ok: true,
                head: null,
                body: {
                    connectionCount: exitNodeKeys.length
                }
            });
        }
    }
};

HyperbahnHandler.prototype.sendAdvertise =
function sendAdvertise(services, options, callback) {
    var self = this;

    if (typeof options === 'function') {
        callback = options;
        options = {};
    }

    options.serviceName = 'hyperbahn';
    options.trace = false;
    options.hasNoParent = true;
    options.headers = options.headers || {};
    options.headers.cn = self.callerName;

    var req = self.channel.request(options);
    self.tchannelJSON.send(req, 'ad', null, {
        services: services
    }, callback);
};

/*  req: {
        services: Array<{
            serviceName: String,
            hostPort: String,
            cost: Number
        }>
    }

    res: {}
*/
HyperbahnHandler.prototype.handleRelayAdvertise =
function handleRelayAdvertise(handler, req, arg2, arg3, cb) {
    handler.handleRelay('ad', req, arg2, arg3, cb);
};

HyperbahnHandler.prototype.handleRelayUnadvertise =
function handleRelayUnadvertise(handler, req, arg2, arg3, cb) {
    handler.handleRelay('unad', req, arg2, arg3, cb);
};

HyperbahnHandler.prototype.handleRelay =
function handleRelay(endpoint, req, arg2, arg3, cb) {
    var self = this;
    var services = arg3.services;
    var logger = self.channel.logger;

    for (var i = 0; i < services.length; i++) {
        var service = services[i];

        var exitNodes = self.egressNodes
            .exitsFor(service.serviceName);
        var exitHosts = Object.keys(exitNodes);

        var myHost = self.channel.hostPort;
        if (exitHosts.indexOf(myHost) < 0) {
            logger.warn('Non-exit node got relay', {
                endpoint: endpoint,
                service: service,
                myHost: myHost,
                exitHosts: exitHosts
            });
        } else if (endpoint === 'ad') {
            self.advertise(service);
        } else if (endpoint === 'unad') {
            self.unadvertise(service);
        } else {
            logger.error('Unexpected endpoint for relay', {
                endpoint: endpoint,
                service: service
            });
        }
    }

    cb(null, {
        ok: true,
        head: null,
        body: {}
    });
};

HyperbahnHandler.prototype.sendRelay =
function sendRelay(opts, callback) {
    var self = this;

    var attempts = 0;

    tryRequest();

    // TODO: move functions out to methods
    function tryRequest() {
        attempts++;

        self.channel.waitForIdentified({
            host: opts.hostPort
        }, onIdentified);

        function onIdentified(err) {
            if (err) {
                return onResponse(err);
            }

            self.tchannelJSON.send(self.channel.request({
                host: opts.hostPort,
                serviceName: 'hyperbahn',
                trace: false,
                timeout: self.relayAdTimeout,
                headers: {
                    cn: self.callerName
                },
                parent: opts.inreq,
                retryFlags: {
                    never: true
                }
            }), opts.endpoint, null, {
                services: opts.services
            }, onResponse);
        }

        function onResponse(err, response) {
            if (response && response.ok) {
                return callback(null, null);
            }

            var codeName = Errors.classify(err);
            if (attempts <= self.maxRelayAdAttempts && err &&
                (
                    codeName === 'NetworkError' ||
                    codeName === 'Timeout'
                )
            ) {
                setTimeout(tryRequest, self.relayAdRetryTime);
            } else {
                self.logError(err, opts, response);

                callback(null, null);
            }
        }
    }
};

HyperbahnHandler.prototype.logError =
function logError(err, opts, response) {
    var self = this;

    var logger = self.channel.logger;

    var logOptions = {
        exitNode: opts.hostPort,
        services: opts.services,
        responseBody: response && response.body,
        error: err
    };

    if (Errors.isFatal(err)) {
        logger.error('Relay advertise failed with unexpected err', logOptions);
    } else {
        logger.warn('Relay advertise failed with expected err', logOptions);
    }
};

HyperbahnHandler.prototype.advertise =
function advertise(service) {
    var self = this;
    self.channel.topChannel.handler.refreshServicePeer(service.serviceName, service.hostPort);
};

HyperbahnHandler.prototype.unadvertise =
function unadvertise(service) {
    var self = this;
    self.channel.topChannel.handler.removeServicePeer(service.serviceName, service.hostPort);
};

function convertHosts(hosts) {
    var res = [];
    for (var i = 0; i < hosts.length; i++) {
        var strs = hosts[i].split(':');
        var obj = {
            port: parseInt(strs[1], 10)
        };
        strs = strs[0].split('.');
        obj.ip = {
            ipv4: parseInt(strs[3], 10) + (parseInt(strs[2], 10) << 8) +
                (parseInt(strs[1], 10) << 16) + (parseInt(strs[0], 10) << 24)
        };

        res.push(obj);
    }

    return res;
}

HyperbahnHandler.prototype.discover =
function discover(handler, req, head, body, cb) {
    var serviceName = body.query.serviceName;
    if (serviceName.length === 0) {
        cb(null, {
            ok: false,
            body: InvalidServiceName({
                serviceName: serviceName
            }),
            typeName: 'invalidServiceName'
        });
        return;
    }

    var exitNodes = handler.egressNodes.exitsFor(serviceName);
    var exitHosts = Object.keys(exitNodes);

    var svcchan = null;
    var myHost = handler.channel.hostPort;
    if (exitHosts.indexOf(myHost) === -1) {
        // Since Hyperbahn is fully connected to service hosts,
        // any exit node suffices.
        svcchan = handler.channel.topChannel.handler.getOrCreateServiceChannel(serviceName);
        handler.tchannelThrift.send(svcchan.request({
            serviceName: 'hyperbahn',
            headers: {
                cn: 'hyperbahn'
            },
            parent: req,
            timeout: 5000,
            timeoutPerAttempt: 500,
            trace: false
        }), 'Hyperbahn::discover', null, body, function handleForward(err, resp) {
            if (err) {
                handler.channel.logger.error('Failed to call discover API on exit node', {
                    error: err,
                    serviceName: serviceName
                });
                return cb(err, null);
            }

            cb(null, resp);
        });
    } else {
        svcchan = handler.channel.topChannel.subChannels[serviceName];
        var hosts = [];
        if (svcchan) {
            hosts = convertHosts(svcchan.peers.keys());
        }
        if (hosts.length === 0) {
            cb(null, {
                ok: false,
                body: NoPeersAvailable({
                    serviceName: serviceName
                }),
                typeName: 'noPeersAvailable'
            });
        } else {
            cb(null, {
                ok: true,
                body: {
                    peers: hosts
                }
            });
        }
    }
};
<|endoftext|>


<commit_before>var child_process = require('child_process')
var fs = require('fs');
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator
//First cut at libfaketime support

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes",
  "One more time...",
  "Re-commiting last",
  "One more User Story done",
  "Can work my way through the Kanban",
  "Sprint complete",
  "Well that seemed pretty easy",
  "What do you mean you can't pack up the commit?",
  "Merge in master",
  "Fast-forwarding changes"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (inFile == outFile) {
    console.error("Aborted: infile and outfile must be different")
<commit_msg>Someone poisoned the waterhole!<commit_after>var child_process = require('child_process')
var fs = require('fs');
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator
//First cut at libfaketime support

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes",
  "One more time...",
  "Re-commiting last",
  "One more User Story done",
  "Can work my way through the Kanban",
  "Sprint complete",
  "Well that seemed pretty easy",
  "What do you mean you can't pack up the commit?",
  "Merge in master",
  "Fast-forwarding changes"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (inFile == outFile) {
    console.error("Aborted: infile and outfile must be different")
 <|endoftext|>