<commit_before>$(document).ready(function(){
	var success = $('#success');
	var error = $('#error');
	success.hide();
	error.hide();
	$('#unapprovedTitle').click(function(){$('#unapprovedTable').toggle()});
	$('#approvedTitle').click(function(){$('#approvedTable').toggle()});
	$('#usedTitle').click(function(){$('#usedTable').toggle()});
	$('table').hide(); //hide all tables by default.

	$.ajaxSetup({
		xhrFields: {
			withCredentials: true
		}
	});
	var post = function(url,data) {
		$.ajax({
			type: 'POST',
			url: url,
			data: data,
			complete: displayResult,
			dataType: 'application/json'
		});
	}
	var showError = function(err) {
		error.innerHTML = err ||"Error!";
		error.show();
		setTimeout(function(){error.hide()},5000);
	}
	var displayResult = function(data) {
		if(!data || !data.responseText){
			showError();
			return;
		}
		var data = JSON.parse(data.responseText);
		if(data.error) {
			displayError(data.error);
			return;
		}
		success.innerHTML = 'Success!';
		success.show();
		setTimeout(function(){success.hide()},5000);
		if(data.keys) {
			document.getElementById('usedBody').innerHTML="";
			document.getElementById('approvedBody').innerHTML="";
			document.getElementById('unapprovedBody').innerHTML="";
			for(var key in data.keys.used) {
				addRow(data.keys.used[key]);
			}
			for(var key in data.keys.approved) {
				addRow(data.keys.approved[key]);
			}
			for(var key in data.keys.unapproved) {
				addRow(data.keys.unapproved[key]);
			}
		}
	}
	var addKey = function(event){
		post("addkey",{
			game: $('#game').val(),
			secretname: $('#secretname').val(),
			key: $('#key').val(),
			obfuscatedkey: $('#obfuscatedkey').val(),
			donor: $('#donor').val(),
			message: $('#message').val()
		});
	}
	var delKey = function(time){
		post("delkey",{
			time:time
		});
	}
	var approveKey = function(time){
		post("approvekey",{
			time:time
		});
	}
	var dropKey = function(time,public){
		post("dropkey",{
			time:time,
			public:public?true:false
		});
	}
	var getKeys = function(){
		post("getkeys");
	}
	$('#sendButton')    .click(addKey);
	getKeys();

	var addRow = function(data) {
		var row = document.createElement('tr');
		row.id=data.addedtime;

		var controls = document.createElement('td');
		if(!data.approvedtime) {
			var approve = document.createElement('a');
			$(approve).click(function(){
				approveKey(data.addedtime);
			});
			approve.innerHTML = "&#10004";
			approve.className = "approveButton";
			approve.href="#";
			approve.title = "Move key from unapproved to approved list";
			controls.appendChild(approve);
			controls.appendChild(document.createTextNode(" "));
		}
		if(!data.usedby) {
			var publicCont = document.createElement('span');
			publicCont.className="publicCheckContainer";
			publicCont.title = "If this box is checked, the key will be dropped in the public chat. Otherwise the bot will chose a random user to receive the key, then post the key in chat 5 minutes later. If there is no key and only a message, it is assumed that this is not a key (that it is a gift) and the bot will not do anything if this is checked.";

			var public = document.createElement('input');
			public.type="checkbox";
			public.checked=true;
			public.id=data.addedtime+"public";
			public.className = "publicCheck";
			publicCont.appendChild(public);
			var label = document.createElement('label');
			label.setAttribute('for',data.addedtime+'public');
//			label.textContent='Drop in public?';
//			$(label).hide();
			publicCont.appendChild(label);
			controls.appendChild(publicCont);
			controls.appendChild(document.createTextNode(" "));

			var drop = document.createElement('a');
			$(drop).click(function(){
				dropKey(data.addedtime,document.getElementById(data.addedtime+"public").checked);
			});
			drop.title = "Drop key in chat";
			drop.innerHTML = "Drop";
			drop.className = "dropButton";
			drop.href="#";
			controls.appendChild(drop);
			controls.appendChild(document.createTextNode(" "));
		}
		var del = document.createElement('a');
		$(del).click(function(){
			delKey(data.addedtime);
		});
		del.innerHTML = "Del";
		del.className = "deleteButton";
		del.href="#";
		del.title="Delete key from bot entirely. There is no going back and no backup here.";
		controls.appendChild(del);
		row.appendChild(controls);

		var game = document.createElement('td');
		game.textContent=data.game;
		row.appendChild(game);

		var secretname = document.createElement('td');
		secretname.textContent=data.secretname;
		row.appendChild(secretname);

		var key = document.createElement('td');
		key.textContent=data.key;
		row.appendChild(key);

		var obfuscatedkey = document.createElement('td');
		obfuscatedkey.textContent=data.obfuscatedkey;
		row.appendChild(obfuscatedkey);

		var donor = document.createElement('td');
		if(data.donor) {donor.textContent=data.donor;}
		donor.className="usercell";
		row.appendChild(donor);

		var addedby = document.createElement('td');
		var link = document.createElement('a');
		link.href="https://steamcommunity.com/profiles/"+data.addedby;
		link.textContent = data.addedby;
		addedby.appendChild(link);
		addedby.className="usercell";
		row.appendChild(addedby);

		var addedtime = document.createElement('td');
		addedtime.textContent = new Date(parseInt(data.addedtime)).toString();
		addedtime.className="timecell";
		row.appendChild(addedtime);

		var approvedby = document.createElement('td');
		if(data.approvedby) {
			var link = document.createElement('a');
			link.href="https://steamcommunity.com/profiles/"+data.approvedby;
			link.textContent = data.approvedby;
			approvedby.appendChild(link);
		}
		approvedby.className="usercell";
		row.appendChild(approvedby);

		var approvedtime = document.createElement('td');
		if(data.approvedtime) { approvedtime.textContent = new Date(parseInt(data.approvedtime)).toString();}
		approvedtime.className="timecell";
		row.appendChild(approvedtime);

		var usedby = document.createElement('td');
		if(data.usedby) {
			var link = document.createElement('a');
			link.href="https://steamcommunity.com/profiles/"+data.usedby;
			link.textContent = data.usedby;
			usedby.appendChild(link);
		}
		usedby.className="usercell";
		row.appendChild(usedby);

		var usedtime = document.createElement('td');
		if(data.usedtime) { usedtime.textContent = new Date(parseInt(data.usedtime)).toString();}
		usedtime.className="timecell";
		row.appendChild(usedtime);

		var message = document.createElement('td');
		if(data.message) { message.textContent = data.message;}
		message.className = "msgcell";
		row.appendChild(message);

		if(data.usedby) {
			document.getElementById('usedBody').appendChild(row);
		} else if(data.approvedby) {
			document.getElementById('approvedBody').appendChild(row);
		} else {
			document.getElementById('unapprovedBody').appendChild(row);
		}
	}
});

<commit_msg>KeyDropTrigger modifications<commit_after>$(document).ready(function(){
	var success = $('#success');
	var error = $('#error');
	success.hide();
	error.hide();
	$('#unapprovedTitle').click(function(){$('#unapprovedTable').toggle()});
	$('#approvedTitle').click(function(){$('#approvedTable').toggle()});
	$('#usedTitle').click(function(){$('#usedTable').toggle()});
	$('table').hide(); //hide all tables by default.

	$.ajaxSetup({
		xhrFields: {
			withCredentials: true
		}
	});
	var post = function(url,data) {
		$.ajax({
			type: 'POST',
			url: url,
			data: data,
			complete: displayResult,
			dataType: 'application/json'
		});
	}
	var showError = function(err) {
		error.innerHTML = err ||"Error!";
		error.show();
		setTimeout(function(){error.hide()},5000);
	}
	var displayResult = function(data) {
		if(!data || !data.responseText){
			showError();
			return;
		}
		var data = JSON.parse(data.responseText);
		if(data.error) {
			displayError(data.error);
			return;
		}
		success.innerHTML = 'Success!';
		success.show();
		setTimeout(function(){success.hide()},5000);
		if(data.keys) {
			document.getElementById('usedBody').innerHTML="";
			document.getElementById('approvedBody').innerHTML="";
			document.getElementById('unapprovedBody').innerHTML="";
			for(var key in data.keys.used) {
				addRow(data.keys.used[key]);
			}
			for(var key in data.keys.approved) {
				addRow(data.keys.approved[key]);
			}
			for(var key in data.keys.unapproved) {
				addRow(data.keys.unapproved[key]);
			}
		}
	}
	var addKey = function(event){
		post("addkey",{
			game: $('#game').val(),
			secretname: $('#secretname').val(),
			key: $('#key').val(),
			obfuscatedkey: $('#obfuscatedkey').val(),
			donor: $('#donor').val(),
			message: $('#message').val()
		});
	}
	var delKey = function(time){
		post("delkey",{
			time:time
		});
	}
	var approveKey = function(time){
		post("approvekey",{
			time:time
		});
	}
	var dropKey = function(time,public){
		post("dropkey",{
			time:time,
			public:public?true:false
		});
	}
	var getKeys = function(){
		post("getkeys");
	}
	$('#sendButton')    .click(addKey);
	getKeys();

	var addRow = function(data) {
		var row = document.createElement('tr');
		row.id=data.addedtime;

		var controls = document.createElement('td');
		if(!data.approvedtime) {
			var approve = document.createElement('a');
			$(approve).click(function(){
				approveKey(data.addedtime);
			});
			approve.innerHTML = "&#10004";
			approve.className = "approveButton";
			approve.href="#";
			approve.title = "Move key from unapproved to approved list";
			controls.appendChild(approve);
			controls.appendChild(document.createTextNode(" "));
		}
		if(!data.usedby && data.approvedby) {
			var public = document.createElement('input');
			public.title = "If this box is checked, the key will be dropped in the public chat. Otherwise the bot will chose a random user to receive the key, then post the key in chat 5 minutes later. If there is no key and only a message, it is assumed that this is not a key (that it is a gift) and the bot will not do anything if this is checked.";
			public.type="checkbox";
//			public.checked=true; //default should be private
			public.id=data.addedtime+"public";
			public.className = "publicCheck";
			controls.appendChild(public);
			controls.appendChild(document.createTextNode(" "));

			var drop = document.createElement('a');
			$(drop).click(function(){
				dropKey(data.addedtime,document.getElementById(data.addedtime+"public").checked);
			});
			drop.title = "Drop key in chat";
			drop.innerHTML = "Drop";
			drop.className = "dropButton";
			drop.href="#";
			controls.appendChild(drop);
			controls.appendChild(document.createTextNode(" "));
		}
		var del = document.createElement('a');
		$(del).click(function(){
			delKey(data.addedtime);
		});
		del.innerHTML = "Del";
		del.className = "deleteButton";
		del.href="#";
		del.title="Delete key from bot entirely. There is no going back and no backup here.";
		controls.appendChild(del);
		row.appendChild(controls);

		var game = document.createElement('td');
		game.textContent=data.game;
		row.appendChild(game);

		var secretname = document.createElement('td');
		secretname.textContent=data.secretname;
		row.appendChild(secretname);

		var key = document.createElement('td');
		key.textContent=data.key;
		row.appendChild(key);

		var obfuscatedkey = document.createElement('td');
		obfuscatedkey.textContent=data.obfuscatedkey;
		row.appendChild(obfuscatedkey);

		var donor = document.createElement('td');
		if(data.donor) {donor.textContent=data.donor;}
		donor.className="usercell";
		row.appendChild(donor);

		var addedby = document.createElement('td');
		var link = document.createElement('a');
		link.href="https://steamcommunity.com/profiles/"+data.addedby;
		link.textContent = data.addedby;
		addedby.appendChild(link);
		addedby.className="usercell";
		row.appendChild(addedby);

		var addedtime = document.createElement('td');
		addedtime.textContent = new Date(parseInt(data.addedtime)).toString();
		addedtime.className="timecell";
		row.appendChild(addedtime);

		var approvedby = document.createElement('td');
		if(data.approvedby) {
			var link = document.createElement('a');
			link.href="https://steamcommunity.com/profiles/"+data.approvedby;
			link.textContent = data.approvedby;
			approvedby.appendChild(link);
		}
		approvedby.className="usercell";
		row.appendChild(approvedby);

		var approvedtime = document.createElement('td');
		if(data.approvedtime) { approvedtime.textContent = new Date(parseInt(data.approvedtime)).toString();}
		approvedtime.className="timecell";
		row.appendChild(approvedtime);

		var usedby = document.createElement('td');
		if(data.usedby) {
			var link = document.createElement('a');
			link.href="https://steamcommunity.com/profiles/"+data.usedby;
			link.textContent = data.usedby;
			usedby.appendChild(link);
		}
		usedby.className="usercell";
		row.appendChild(usedby);

		var usedtime = document.createElement('td');
		if(data.usedtime) { usedtime.textContent = new Date(parseInt(data.usedtime)).toString();}
		usedtime.className="timecell";
		row.appendChild(usedtime);

		var message = document.createElement('td');
		if(data.message) { message.textContent = data.message;}
		message.className = "msgcell";
		row.appendChild(message);

		if(data.usedby) {
			document.getElementById('usedBody').appendChild(row);
		} else if(data.approvedby) {
			document.getElementById('approvedBody').appendChild(row);
		} else {
			document.getElementById('unapprovedBody').appendChild(row);
		}
	}
});

<|endoftext|>


<commit_before>(function () {

window.echat = function (onReady) {

	return new Chat(onReady);

};

function Chat(onReady) {

	var Chat = this;

	var onEvent = {},
		rooms = {},
		username = null;

	var bullet = $.bullet('ws://localhost:8080/bullet');

	(function () {

		var wasRead = false;

		bullet.onopen = function () {
			// console.log('bullet: opened');
			if (!wasRead) {
				onReady();
				wasRead = true;
			} else { // reconnect
				try {

					Chat.username(username, function (accepted) {
						if (!accepted) throw 'username not available';
					});

					var reconnectTimestamp = Date.now(); // unix in ms for messages between
					for (var name in rooms) rooms[name].reconnect(reconnectTimestamp);

				} catch (error) {
					console.error('eChat: Unable to reconnect because or error', error);
				}
			}
		};

	})();

	bullet.onmessage = function (event) {

		try {

			// console.log('received', event.data);
			var object = JSON.parse(event.data);

			var type = object.type,
				data = object.data,
				ref = object.ref;

			switch (type) {

				case 'register_res': // data = accepted
					onEvent[ref](data);
					onEvent[ref] = null;
					break;

				case 'users': // data = [username]
					onEvent[ref](data);
					onEvent[ref] = null;
					break;

				case 'messages': // data = [{ username, content, timestamp }]
					onEvent[ref](data);
					onEvent[ref] = null;
					break;

				case 'message_timestamp': // data = timestamp
					onEvent[ref](data);
					onEvent[ref] = null;
					break;

				case 'user': // data = { room, action: 'join'|'leave', username }
					rooms[data.room].onUser(data.action, data.username);
					break;

				case 'message': // data = { room, message: { username, content, timestamp } }
					rooms[data.room].onMessage(data.message.username, data.message.content, data.message.timestamp);
					break;

				default:
					throw 'invalid type';

			}

		} catch (error) {
			console.error('eChat: Unable to handle message', event.data, 'because of error', error);
		}

	};

	// send

	function newRef() {
		return Math.floor( Math.random() * Math.pow(2, 32) );
	}

	function send(type, data) {

		var ref = newRef();
		var json = JSON.stringify({
				type: type,
				data: data,
				ref: ref
		});

		// console.info('sending', json);

		bullet.send(json);
		return ref;

	}

	// api

	this.username = function (name, callback) {
		var ref = send('register', name);
		onEvent[ref] = function (accepted) {
			if (accepted) username = name;
			callback(accepted);
		};
	};

	this.join = function (room, messagesToLoad, onJoined, onUser, onMessage) {
		rooms[room] = new Room(room, messagesToLoad, onJoined, onUser, onMessage);
	};

	this.room = function (name) {
		return rooms[name];
	};

	this.leave = function (room) {
		send('leave', room);
		rooms[room] = null;
	};

	function Room(room, messagesToLoad, onJoinedCallback, onUserCallback, onMessageCallback) {

		var Room = this;

		Room.messages = [];
		Room.users = [];

		(function (room, limit, callback) {

			var usersRef = send('join', room); // will return as 'Room.users'
			var messagesRef = send('messages_before', { // will return as 'Room.messages'
				room: room,
				timestamp: Date.now(),
				limit: limit
			});

			var toReceive = 2,
				usersReceived = null,
				messagesReceived = null;

			onEvent[usersRef] = function (newUsers) {
				usersReceived = newUsers;
				chunkReceived();
			};

			onEvent[messagesRef] = function (newMessages) {
				messagesReceived = newMessages;
				chunkReceived();
			};

			function chunkReceived() {
				toReceive--;
				if (!toReceive) {

					Room.messages = messagesReceived;
					Room.users = usersReceived;

					callback(usersReceived, messagesReceived);

				}
			}

		})(room, messagesToLoad, onJoinedCallback);

		// api

		this.send = function (content, callback) {

			var ref = send('message', {
					room: room,
					content: content
			});

			onEvent[ref] = function (timestamp) {

				Room.messages.push({
					username: username,
					content: content,
					timestamp: timestamp
				});

				callback(timestamp);

			};

		};

		this.load = function (limit, callback) {

			var ref = send('messages_before', {
					room: room,
					timestamp: Room.messages[0].timestamp,
					limit: limit
			});

			onEvent[ref] = function (receivedMessages) {
				Room.messages = Room.messages.concat(receivedMessages);
				console.log('load:', Room.messages, receivedMessages);
				callback(receivedMessages, Room.messages);
			};

		};

		// event callbacks

		this.reconnect = function (reconnectTimestamp) {

			var usersRef = send('join', room);

			onEvent[usersRef] = function (newUsers) { // detects waht users joined/left the room while disconenct

				var n = newUsers,
				    o = Room.users;

				for (var i = o.length; i--;) { // go threw old
					var u = o[i];
					if (n.indexOf(u) === -1) { // user doesn't exist anymore -> left
						Room.onUser('leave', u);
					}
				}

				for (var i = n.length; i--;) { // go threw new
					var u = n[i];
					if (o.indexOf(n[i]) === -1) { // user didn't exist before -> joined
						Room.onUser('join', u);
					}
				}

			};

			if (Room.messages.length) { // if messages already loaded

				var messagesRef = send('messages_between', {
					room: room,
					startTimestamp: Room.messages[Room.messages.length-1].timestamp,
					endTimestamp: reconnectTimestamp
				});

				onEvent[messagesRef] = function (newMessages) {
					Room.messages = Room.messages.concat(newMessages);
					for (var i = 0; i < newMessages.length; i++) { // don't reverse
						var message = newMessages[i];
						Room.onMessage(message.username, message.content, message.timestamp);
					}
				};

			}

		};

		this.onUser = function (action, performingUsername) {

			switch (action) {

				case 'join':
					Room.users.push(performingUsername);
					break;

				case 'leave':
					for (var i = Room.users.length; i--;) {
						if (Room.users[i] === performingUsername) {
							Room.users.splice(i, 1);
							i = 0;
						}
					}
					break;

				default:
					throw 'invalid action';

			}

			onUserCallback(action, performingUsername, Room.users);

		};

		this.onMessage = function (username, content, timestamp) {

			Room.messages.push({
				username: username,
				content: content,
				timestamp: timestamp
			});

			onMessageCallback(username, content, timestamp, Room.messages);

		};

	}

}

})();<commit_msg>removed unwanted console.log, bug fix<commit_after>(function () {

window.echat = function (onReady) {

	return new Chat(onReady);

};

function Chat(onReady) {

	var Chat = this;

	var onEvent = {},
	    rooms = {},
	    username = null;

	var bullet = $.bullet('ws://' + window.document.location.host + '/bullet');

	(function () {

		var wasRead = false;

		bullet.onopen = function () {
			// console.log('bullet: opened');
			if (!wasRead) {
				onReady();
				wasRead = true;
			} else { // reconnect

				try {

					Chat.username(username, function (accepted) {
						if (!accepted) throw 'username not available';
					});

					var reconnectTimestamp = Date.now(); // unix in ms for messages between
					for (var name in rooms) rooms[name].reconnect(reconnectTimestamp);

				} catch (error) {

					console.error('eChat: Unable to reconnect because or error', error);

				}

			}
		};

	})();

	bullet.onmessage = function (event) {

		try {

			// console.log('received', event.data);
			var object = JSON.parse(event.data);

			var type = object.type,
			    data = object.data,
			    ref = object.ref;

			switch (type) {

				case 'register_res': // data = accepted
					onEvent[ref](data);
					onEvent[ref] = null;
					break;

				case 'users': // data = [username]
					onEvent[ref](data);
					onEvent[ref] = null;
					break;

				case 'messages': // data = [{ username, content, timestamp }]
					onEvent[ref](data);
					onEvent[ref] = null;
					break;

				case 'message_timestamp': // data = timestamp
					onEvent[ref](data);
					onEvent[ref] = null;
					break;

				case 'user': // data = { room, action: 'join'|'leave', username }
					rooms[data.room].onUser(data.action, data.username);
					break;

				case 'message': // data = { room, message: { username, content, timestamp } }
					rooms[data.room].onMessage(data.message.username, data.message.content, data.message.timestamp);
					break;

				default:
					throw 'invalid type';

			}

		} catch (error) {
			console.error('eChat: Unable to handle message', event.data, 'because of error', error);
		}

	};

	// send

	function newRef() {
		return Math.floor( Math.random() * Math.pow(2, 32) );
	}

	function send(type, data) {

		var ref = newRef();
		var json = JSON.stringify({
			type: type,
			data: data,
			ref: ref
		});

		// console.info('sending', json);

		bullet.send(json);
		return ref;

	}

	// api

	this.username = function (name, callback) {
		var ref = send('register', name);
		onEvent[ref] = function (accepted) {
			if (accepted) username = name;
			callback(accepted);
		};
	};

	this.join = function (room, messagesToLoad, onJoined, onUser, onMessage) {
		rooms[room] = new Room(room, messagesToLoad, onJoined, onUser, onMessage);
	};

	this.room = function (name) {
		return rooms[name];
	};

	this.leave = function (room) {
		send('leave', room);
		rooms[room] = null;
	};

	function Room(room, messagesToLoad, onJoinedCallback, onUserCallback, onMessageCallback) {

		var Room = this;

		Room.messages = [];
		Room.users = [];

		(function (room, limit, callback) {

			var usersRef = send('join', room); // will return as 'Room.users'
			var messagesRef = send('messages_before', { // will return as 'Room.messages'
				room: room,
				timestamp: Date.now(),
				limit: limit
			});

			var toReceive = 2,
			    usersReceived = null,
			    messagesReceived = null;

			onEvent[usersRef] = function (newUsers) {
				usersReceived = newUsers;
				chunkReceived();
			};

			onEvent[messagesRef] = function (newMessages) {
				messagesReceived = newMessages;
				chunkReceived();
			};

			function chunkReceived() {
				toReceive--;
				if (!toReceive) {

					Room.messages = messagesReceived;
					Room.users = usersReceived;

					callback(usersReceived, messagesReceived);

				}
			}

		})(room, messagesToLoad, onJoinedCallback);

		// api

		this.send = function (content, callback) {

			var ref = send('message', {
				room: room,
				content: content
			});

			onEvent[ref] = function (timestamp) {

				Room.messages.push({
					username: username,
					content: content,
					timestamp: timestamp
				});

				callback(timestamp);

			};

		};

		this.load = function (limit, callback) {

			var ref = send('messages_before', {
					room: room,
					timestamp: Room.messages[0].timestamp,
					limit: limit
			});

			onEvent[ref] = function (receivedMessages) {
				Room.messages = Room.messages.concat(receivedMessages);
				// console.log('load:', Room.messages, receivedMessages);
				callback(receivedMessages, Room.messages);
			};

		};

		// event callbacks

		this.reconnect = function (reconnectTimestamp) {

			var usersRef = send('join', room);

			onEvent[usersRef] = function (newUsers) { // detects waht users joined/left the room while disconenct

				var n = newUsers,
				    o = Room.users;

				for (var i = o.length; i--;) { // go threw old
					var u = o[i];
					if (n.indexOf(u) === -1) { // user doesn't exist anymore -> left
						Room.onUser('leave', u);
					}
				}

				for (var i = n.length; i--;) { // go threw new
					var u = n[i];
					if (o.indexOf(n[i]) === -1) { // user didn't exist before -> joined
						Room.onUser('join', u);
					}
				}

			};

			if (Room.messages.length) { // if messages already loaded

				var messagesRef = send('messages_between', {
					room: room,
					startTimestamp: Room.messages[Room.messages.length-1].timestamp,
					endTimestamp: reconnectTimestamp
				});

				onEvent[messagesRef] = function (newMessages) {
					Room.messages = Room.messages.concat(newMessages);
					for (var i = 0; i < newMessages.length; i++) { // don't reverse
						var message = newMessages[i];
						Room.onMessage(message.username, message.content, message.timestamp);
					}
				};

			}

		};

		this.onUser = function (action, performingUsername) {

			switch (action) {

				case 'join':
					Room.users.push(performingUsername);
					break;

				case 'leave':
					for (var i = Room.users.length; i--;) {
						if (Room.users[i] === performingUsername) {
							Room.users.splice(i, 1);
							i = 0;
						}
					}
					break;

				default:
					throw 'invalid action';

			}

			onUserCallback(action, performingUsername, Room.users);

		};

		this.onMessage = function (username, content, timestamp) {

			Room.messages.push({
				username: username,
				content: content,
				timestamp: timestamp
			});

			onMessageCallback(username, content, timestamp, Room.messages);

		};

	}

}

})();<|endoftext|>


<commit_before>/*
 * L.TileLayer is used for standard xyz-numbered tile layers.
 */

/* global ymaps: true */

L.Yandex = L.Layer.extend({
	includes: L.Mixin.Events,

	options: {
		minZoom: 0,
		maxZoom: 18,
		attribution: '',
		opacity: 1,
		traffic: false
	},

	possibleShortMapTypes: {
		schemaMap: 'map',
		satelliteMap: 'satellite',
		hybridMap: 'hybrid',
		publicMap: 'publicMap',
		publicMapInHybridView: 'publicMapHybrid'
	},

	_getPossibleMapType: function (mapType) {
		var result = 'yandex#map';
		if (typeof mapType !== 'string') {
			return result;
		}
		for (var key in this.possibleShortMapTypes) {
			if (mapType === this.possibleShortMapTypes[key]) {
				result = 'yandex#' + mapType;
				break;
			}
			if (mapType === ('yandex#' + this.possibleShortMapTypes[key])) {
				result = mapType;
			}
		}
		return result;
	},

	// Possible types: yandex#map, yandex#satellite, yandex#hybrid, yandex#publicMap, yandex#publicMapHybrid
	// Or their short names: map, satellite, hybrid, publicMap, publicMapHybrid
	initialize: function (type, options) {
		L.Util.setOptions(this, options);
		//Assigning an initial map type for the Yandex layer
		this._type = this._getPossibleMapType(type);
	},

	onAdd: function (map, insertAtTheBottom) {
		this._map = map;
		this._insertAtTheBottom = insertAtTheBottom;

		// create a container div for tiles
		this._initContainer();
		this._initMapObject();

		// set up events
		map.on('viewreset', this._reset, this);

		this._limitedUpdate = L.Util.throttle(this._update, 150, this);
		map.on('move', this._update, this);

		map._controlCorners.bottomright.style.marginBottom = '3em';

		this._reset();
		this._update(true);
	},

	onRemove: function (map) {
		this._map._container.removeChild(this._container);

		this._map.off('viewreset', this._reset, this);

		this._map.off('move', this._update, this);

		map._controlCorners.bottomright.style.marginBottom = '0em';
	},

	getAttribution: function () {
		return this.options.attribution;
	},

	setOpacity: function (opacity) {
		this.options.opacity = opacity;
		if (opacity < 1) {
			L.DomUtil.setOpacity(this._container, opacity);
		}
	},

	setElementSize: function (e, size) {
		e.style.width = size.x + 'px';
		e.style.height = size.y + 'px';
	},

	_initContainer: function () {
		var tilePane = this._map._container,
			first = tilePane.firstChild;

		if (!this._container) {
			this._container = L.DomUtil.create('div', 'leaflet-yandex-layer');
			this._container.id = '_YMapContainer_' + L.Util.stamp(this);
			this._container.style.zIndex = 'auto';
		}

		if (this.options.overlay) {
			first = this._map._container.getElementsByClassName('leaflet-map-pane')[0];
			first = first.nextSibling;
			// XXX: Bug with layer order
			if (L.Browser.opera)
				this._container.className += ' leaflet-objects-pane';
		}
		tilePane.insertBefore(this._container, first);

		this.setOpacity(this.options.opacity);
		this.setElementSize(this._container, this._map.getSize());
	},

	_initMapObject: function () {
		if (this._yandex) return;

		// Check that ymaps.Map is ready
		if (ymaps.Map === undefined) {
			return ymaps.load(['package.map'], this._initMapObject, this);
		}

		// If traffic layer is requested check if control.TrafficControl is ready
		if (this.options.traffic)
			if (ymaps.control === undefined ||
					ymaps.control.TrafficControl === undefined) {
				return ymaps.load(['package.traffic', 'package.controls'],
					this._initMapObject, this);
			}
		//Creating ymaps map-object without any default controls on it
		var map = new ymaps.Map(this._container, {center: [0, 0], zoom: 0, behaviors: [], controls: []});

		if (this.options.traffic)
			map.controls.add(new ymaps.control.TrafficControl({shown: true}));

		if (this._type === 'yandex#null') {
			this._type = new ymaps.MapType('null', []);
			map.container.getElement().style.background = 'transparent';
		}
		map.setType(this._type);

		this._yandex = map;
		this._update(true);

		//Reporting that map-object was initialized
		this.fire('MapObjectInitialized', {mapObject: map});
	},

	_reset: function () {
		this._initContainer();
	},

	_update: function (force) {
		if (!this._yandex) return;
		this._resize(force);

		var center = this._map.getCenter();
		var _center = [center.lat, center.lng];
		var zoom = this._map.getZoom();

		if (force || this._yandex.getZoom() !== zoom)
			this._yandex.setZoom(zoom);
		this._yandex.panTo(_center, {duration: 0, delay: 0});
	},

	_resize: function (force) {
		var size = this._map.getSize(), style = this._container.style;
		if (style.width === size.x + 'px' && style.height === size.y + 'px')
			if (force !== true) return;
		this.setElementSize(this._container, size);
		this._yandex.container.fitToViewport();
	}
});
<commit_msg>Don't use depricated L.Mixin.Events for Leaflet 1.2<commit_after>/*
 * L.TileLayer is used for standard xyz-numbered tile layers.
 */

/* global ymaps: true */

L.Yandex = L.Layer.extend({
	includes: L.Evented ? L.Evented.prototype : L.Mixin.Events,

	options: {
		minZoom: 0,
		maxZoom: 18,
		attribution: '',
		opacity: 1,
		traffic: false
	},

	possibleShortMapTypes: {
		schemaMap: 'map',
		satelliteMap: 'satellite',
		hybridMap: 'hybrid',
		publicMap: 'publicMap',
		publicMapInHybridView: 'publicMapHybrid'
	},

	_getPossibleMapType: function (mapType) {
		var result = 'yandex#map';
		if (typeof mapType !== 'string') {
			return result;
		}
		for (var key in this.possibleShortMapTypes) {
			if (mapType === this.possibleShortMapTypes[key]) {
				result = 'yandex#' + mapType;
				break;
			}
			if (mapType === ('yandex#' + this.possibleShortMapTypes[key])) {
				result = mapType;
			}
		}
		return result;
	},

	// Possible types: yandex#map, yandex#satellite, yandex#hybrid, yandex#publicMap, yandex#publicMapHybrid
	// Or their short names: map, satellite, hybrid, publicMap, publicMapHybrid
	initialize: function (type, options) {
		L.Util.setOptions(this, options);
		//Assigning an initial map type for the Yandex layer
		this._type = this._getPossibleMapType(type);
	},

	onAdd: function (map, insertAtTheBottom) {
		this._map = map;
		this._insertAtTheBottom = insertAtTheBottom;

		// create a container div for tiles
		this._initContainer();
		this._initMapObject();

		// set up events
		map.on('viewreset', this._reset, this);

		this._limitedUpdate = L.Util.throttle(this._update, 150, this);
		map.on('move', this._update, this);

		map._controlCorners.bottomright.style.marginBottom = '3em';

		this._reset();
		this._update(true);
	},

	onRemove: function (map) {
		this._map._container.removeChild(this._container);

		this._map.off('viewreset', this._reset, this);

		this._map.off('move', this._update, this);

		map._controlCorners.bottomright.style.marginBottom = '0em';
	},

	getAttribution: function () {
		return this.options.attribution;
	},

	setOpacity: function (opacity) {
		this.options.opacity = opacity;
		if (opacity < 1) {
			L.DomUtil.setOpacity(this._container, opacity);
		}
	},

	setElementSize: function (e, size) {
		e.style.width = size.x + 'px';
		e.style.height = size.y + 'px';
	},

	_initContainer: function () {
		var tilePane = this._map._container,
			first = tilePane.firstChild;

		if (!this._container) {
			this._container = L.DomUtil.create('div', 'leaflet-yandex-layer');
			this._container.id = '_YMapContainer_' + L.Util.stamp(this);
			this._container.style.zIndex = 'auto';
		}

		if (this.options.overlay) {
			first = this._map._container.getElementsByClassName('leaflet-map-pane')[0];
			first = first.nextSibling;
			// XXX: Bug with layer order
			if (L.Browser.opera)
				this._container.className += ' leaflet-objects-pane';
		}
		tilePane.insertBefore(this._container, first);

		this.setOpacity(this.options.opacity);
		this.setElementSize(this._container, this._map.getSize());
	},

	_initMapObject: function () {
		if (this._yandex) return;

		// Check that ymaps.Map is ready
		if (ymaps.Map === undefined) {
			return ymaps.load(['package.map'], this._initMapObject, this);
		}

		// If traffic layer is requested check if control.TrafficControl is ready
		if (this.options.traffic)
			if (ymaps.control === undefined ||
					ymaps.control.TrafficControl === undefined) {
				return ymaps.load(['package.traffic', 'package.controls'],
					this._initMapObject, this);
			}
		//Creating ymaps map-object without any default controls on it
		var map = new ymaps.Map(this._container, {center: [0, 0], zoom: 0, behaviors: [], controls: []});

		if (this.options.traffic)
			map.controls.add(new ymaps.control.TrafficControl({shown: true}));

		if (this._type === 'yandex#null') {
			this._type = new ymaps.MapType('null', []);
			map.container.getElement().style.background = 'transparent';
		}
		map.setType(this._type);

		this._yandex = map;
		this._update(true);

		//Reporting that map-object was initialized
		this.fire('MapObjectInitialized', {mapObject: map});
	},

	_reset: function () {
		this._initContainer();
	},

	_update: function (force) {
		if (!this._yandex) return;
		this._resize(force);

		var center = this._map.getCenter();
		var _center = [center.lat, center.lng];
		var zoom = this._map.getZoom();

		if (force || this._yandex.getZoom() !== zoom)
			this._yandex.setZoom(zoom);
		this._yandex.panTo(_center, {duration: 0, delay: 0});
	},

	_resize: function (force) {
		var size = this._map.getSize(), style = this._container.style;
		if (style.width === size.x + 'px' && style.height === size.y + 'px')
			if (force !== true) return;
		this.setElementSize(this._container, size);
		this._yandex.container.fitToViewport();
	}
});
<|endoftext|>


<commit_before>'use strict';

const dotenv = require('dotenv');
const fs = require('fs');
const yaml = require('js-yaml');

const yamlConf = function (options) {
  if (typeof options === 'string') {
    options = {path: options};
  }

  options = options || {};

  const defaults = {
    dotenv: {silent: true, path: './.env'},
    path: './config.yml',
    loadToProcess: false,
    localConfig: {path: './config.local.yml', force: false}
  };

  if (options.localConfig) {
    options.localConfig = Object.assign({}, defaults.localConfig, options.localConfig);
  }

  options = Object.assign({}, defaults, options);

  dotenv.load(options.dotenv);

  if (!fs.existsSync(options.path)) {
    throw new Error(`Config file not found: ${options.path}`);
  }

  let config = _loadConfig(options.path);

  // override values with local config if specified
  if (options.localConfig) {
    const isLocalConfig = fs.existsSync(options.localConfig.path);

    if (!isLocalConfig && options.localConfig.force) {
      throw new Error(`Local config was specified, but not found: ${options.localConfig}`);
    }

    if (isLocalConfig) {
      const localConfig = _loadConfig(options.localConfig.path);

      config = Object.assign({}, config, localConfig);
    }
  }

  if (!options.loadToProcess) {
    return config;
  }

  // make config accessible globally in process.config
  for (let variable in config) {
    if (process.config[variable]) {
      continue; // skip when it collides with already existing property
    }

    process.config[variable] = config[variable];
  }

  return config;
};

/**
 * load config file and parse it
 *
 * @param {String} path
 * @returns {*}
 */
const _loadConfig = function (path) {
  const rawConfig = fs.readFileSync(path, {encoding: 'utf-8'});
  const pattern = /process\.env\.(\w+)/g;
  const injected = rawConfig.replace(pattern, (match, envVar) => process.env[envVar]);

  return yaml.safeLoad(injected) || {};
};

module.exports = yamlConf;
<commit_msg>yamlconf configuration refactored<commit_after>'use strict';

const dotenv = require('dotenv');
const fs = require('fs');
const yaml = require('js-yaml');

const yamlConf = function (options) {
  if (typeof options === 'string') {
    options = {path: options};
  }

  options = options || {};

  const defaults = {
    dotenv: {silent: true, path: './.env'},
    path: './config.yml',
    loadToProcess: false,
    localConfig: {path: './config.local.yml', force: false}
  };

  for (let setting in defaults) {
    let value = defaults[setting];

    if (typeof value === 'object' && !!value) {
      options[setting] = Object.assign({}, value, options[setting]);
      continue;
    }

    options[setting] = options[setting] || value;
  }

  dotenv.load(options.dotenv);

  if (!fs.existsSync(options.path)) {
    throw new Error(`Config file not found: ${options.path}`);
  }

  let config = _loadConfig(options.path);

  // override values with local config if specified
  if (options.localConfig) {
    const isLocalConfig = fs.existsSync(options.localConfig.path);

    if (!isLocalConfig && options.localConfig.force) {
      throw new Error(`Local config was specified, but not found: ${options.localConfig}`);
    }

    if (isLocalConfig) {
      const localConfig = _loadConfig(options.localConfig.path);

      config = Object.assign({}, config, localConfig);
    }
  }

  if (!options.loadToProcess) {
    return config;
  }

  // make config accessible globally in process.config
  for (let variable in config) {
    if (process.config[variable]) {
      continue; // skip when it collides with already existing property
    }

    process.config[variable] = config[variable];
  }

  return config;
};

/**
 * load config file and parse it
 *
 * @param {String} path
 * @returns {*}
 */
const _loadConfig = function (path) {
  const rawConfig = fs.readFileSync(path, {encoding: 'utf-8'});
  const pattern = /process\.env\.(\w+)/g;
  const injected = rawConfig.replace(pattern, (match, envVar) => process.env[envVar]);

  return yaml.safeLoad(injected) || {};
};

module.exports = yamlConf;
<|endoftext|>


<commit_before>var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var ballRadius = 10;
var x = canvas.width/2;
var y = canvas.height-30;
var dx = 2;
var dy = -2;
var paddleHeight = 10;
var paddleWidth = 75;
var paddleX = (canvas.width-paddleWidth)/2;
var rightPressed = false;
var leftPressed = false;

document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);

function keyDownHandler(e) {
  if(e.keyCode == 39) {
    rightPressed = true;
  }
  else if(e.keyCode == 37) {
    leftPressed = true;
  }
}
function keyUpHandler(e) {
  if(e.keyCode == 39) {
    rightPressed = false;
  }
  else if(e.keyCode == 37) {
    leftPressed = false;
  }
}

function drawBall() {
  ctx.beginPath();
  ctx.arc(x, y, ballRadius, 0, Math.PI*2);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
}
function drawPaddle() {
  ctx.beginPath();
  ctx.rect(paddleX, canvas.height-paddleHeight, paddleWidth, paddleHeight);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
}

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawBall();
  drawPaddle();

  if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
    dx = -dx;
  }
  if(y + dy < ballRadius) {
    dy = -dy;
  } else if (y + dy > canvas.height-ballRadius) {
    if(x > paddleX && x < paddleX + paddleWidth) {
      dy = -dy;
    } else {
      alert("GAME OVER");
      document.location.reload();
    }
  }

  if(rightPressed && paddleX < canvas.width-paddleWidth) {
    paddleX += 7;
  }
  else if(leftPressed && paddleX > 0) {
    paddleX -= 7;
  }

  x += dx;
  y += dy;
}

setInterval(draw, 10);
<commit_msg>Episode 6 and 7<commit_after>var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var ballRadius = 10;
var x = canvas.width/2;
var y = canvas.height-30;
var dx = 2;
var dy = -2;
var paddleHeight = 10;
var paddleWidth = 75;
var paddleX = (canvas.width-paddleWidth)/2;
var rightPressed = false;
var leftPressed = false;
var brickRowCount = 3;
var brickColumnCount = 5;
var brickWidth = 75;
var brickHeight = 20;
var brickPadding = 10;
var brickOffsetTop = 30;
var brickOffsetLeft = 30;

var bricks = [];
for(c=0; c < brickColumnCount; c++) {
  bricks[c] = [];
  for(r=0; r < brickRowCount; r++) {
    bricks[c][r] = { x: 0, y: 0, status: 1 };
  }
}

document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);

function keyDownHandler(e) {
  if(e.keyCode == 39) {
    rightPressed = true;
  }
  else if(e.keyCode == 37) {
    leftPressed = true;
  }
}

function keyUpHandler(e) {
  if(e.keyCode == 39) {
    rightPressed = false;
  }
  else if(e.keyCode == 37) {
    leftPressed = false;
  }
}

function collisionDetection() {
  for(c=0; c < brickColumnCount; c++) {
    for(r=0; r < brickRowCount; r++) {
      var b = bricks[c][r];
      if(b.status == 1) {
        if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) {
          dy = -dy;
          b.status = 0;
        }
      }
    }
  }
}

function drawBall() {
  ctx.beginPath();
  ctx.arc(x, y, ballRadius, 0, Math.PI*2);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
}

function drawPaddle() {
  ctx.beginPath();
  ctx.rect(paddleX, canvas.height-paddleHeight, paddleWidth, paddleHeight);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
}

function drawBricks() {
  for(c=0; c < brickColumnCount; c++) {
    for(r=0; r < brickRowCount; r++) {
      if(bricks[c][r].status == 1) {
        var brickX = (c*(brickWidth+brickPadding))+brickOffsetLeft;
        var brickY = (r*(brickWidth+brickPadding))+brickOffsetTop;
        bricks[c][r].x = brickX;
        bricks[c][r].y = brickY;
        ctx.beginPath();
        ctx.rect(brickX, brickY, brickWidth, brickHeight);
        ctx.fillStyle = "#0095DD";
        ctx.fill();
        ctx.closePath();
      }
    }
  }
}

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawBall();
  drawBricks();
  drawPaddle();
  collisionDetection();

  if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
    dx = -dx;
  }
  if(y + dy < ballRadius) {
    dy = -dy;
  } else if (y + dy > canvas.height-ballRadius) {
    if(x > paddleX && x < paddleX + paddleWidth) {
      dy = -dy;
    } else {
      alert("GAME OVER");
      document.location.reload();
    }
  }

  if(rightPressed && paddleX < canvas.width-paddleWidth) {
    paddleX += 7;
  }
  else if(leftPressed && paddleX > 0) {
    paddleX -= 7;
  }

  x += dx;
  y += dy;
}

setInterval(draw, 10);
<|endoftext|>


<commit_before>var util = require ("util");

var Petal = require ("../lib/Petal.js");
var Connection = require ("./Connection.js");

var IRCManager = function (item_manager) {
	var self = this;

	Petal.call (this, item_manager);

	this.connections = [];

	item_manager.command (["lic", "config"], "get", ["IRC"], function(error, values) {
		if (error) {
			console.error ("Could not retrieve configuration");
			return;
		}
		self.config = values[0];
		self.connect ();
	});
};

util.inherits (IRCManager, Petal);

/* This function takes the server profile from the config and extends
 * it with the defaults from the config so that when the defaults
 * change or the server profile changes, it will updated as such
 */
IRCManager.prototype.create_profile = function (profile, defaults) {
	profile.__proto__ = defaults;
	return profile;
};

IRCManager.prototype.connect = function () {
	var connection, profile, servers, defaults;

	servers  = this.config.servers;
	defaults = this.config.default;

	for (var i = 0, len = servers.length; i < len; i++) {

		profile = this.create_profile (servers[i], defaults);
		connection = new Connection (profile, this.item_manager);

		///* The following section is a massive hack, used temporarily as a testing interface.
		connection.on("001", function (message) {
			var channel = "#oftn";

			this.raw ("JOIN " + channel);
			process.stdin.resume();
			process.stdin.on("data", function(data) {
				connection.send ("PRIVMSG " + channel + " :" + String(data).trim());
			});
		});
		//*/

		console.log ("Connecting to IRC server \"%s\"", connection.name);
		connection.connect ();

		this.connections.push (connection);
	}
};

IRCManager.prototype.shutdown = function(callback) {
	var connections, self = this;

	// First we clone the connections array to use as a queue
	connections = this.connections.slice ();
	console.log ("Waiting for IRC servers to close connections...");

	(function next () {
		var c = connections.shift ();
		if (!c) {
			callback.call (self);
			return;
		}
		c.quit (next);
	}) ();
};

if (require.main === module) {
	Petal.register (IRCManager);
}

module.exports = IRCManager;
<commit_msg>Make IRC petal listen for commands with ItemManager<commit_after>var util = require ("util");

var Petal = require ("../lib/Petal.js");
var Connection = require ("./Connection.js");

var IRCManager = function (item_manager) {
	var self = this;

	Petal.call (this, item_manager);

	this.servers = {};

	item_manager.listen ([this.name, "*"], function(item, command) {
		var server, args, method;

		server = item[1];
		args = Array.prototype.slice.call (arguments, 2);

		if (server) {
			if (self.servers.hasOwnProperty (server)) {
				method = Connection.prototype[command];
				if (typeof method === "function") {
					method.apply (self.servers[server], args);
					return true;
				}
			}
		}
		return false;
	});

	item_manager.command (["lic", "config"], "get", ["IRC"], function(error, values) {
		if (error) {
			console.error ("Could not retrieve configuration");
			return;
		}
		self.config = values[0];
		self.connect ();

		console.log ("Retreived configuration");
	});
};

util.inherits (IRCManager, Petal);

IRCManager.prototype.name = "irc";

/* This function takes the server profile from the config and extends
 * it with the defaults from the config so that when the defaults
 * change or the server profile changes, it will updated as such
 */
IRCManager.prototype.create_profile = function (profile, defaults) {
	profile.__proto__ = defaults;
	return profile;
};

IRCManager.prototype.connect = function () {
	var self, connection, profile, servers, defaults;

	self = this;
	servers  = this.config.servers;
	defaults = this.config.default;

	for (var i = 0, len = servers.length; i < len; i++) {

		profile = this.create_profile (servers[i], defaults);

		if (!this.servers.hasOwnProperty (profile.name)) {
			connection = new Connection (profile);

			console.log ("Connecting to IRC server `%s`", connection.name);
			connection.on ("message", function(data) {
				var item = [self.name, this.name];
				if (data.params[0]) {
					item.push (data.params[0]);
				}

				self.item_manager.command (item, data.command, data);
			});

			connection.connect ();

			this.servers[profile.name] = connection;

		} else {
			console.error ("IRC already has connection called `%s`. Skipping duplicate.", profile.name);
		}
	}
};

IRCManager.prototype.shutdown = function(callback) {
	var connections, self = this;

	// First we clone the connections array to use as a queue
	connections = Object.getOwnPropertyNames (this.servers)
	console.log ("Waiting for IRC servers to close connections...");

	(function next () {
		var c = connections.shift ();
		if (!c) {
			callback.call (self);
			return;
		}
		self.servers[c].quit (next);
	}) ();
};

if (require.main === module) {
	Petal.register (IRCManager);
}

module.exports = IRCManager;
<|endoftext|>


<commit_before>var
	dgram = require('dgram'),
	EventEmitter = require('events').EventEmitter,
	inherits = require('util').inherits,
	net = require('net'),
	uuid = require('uuid'),

	Base = require('./Base'),
	addrs = require('../Misc/addresses'),
	msgs = require('../Misc/messages'),
	neigh = require('../Misc/neigh');

// ----------------
// Client class
// ----------------
// Main client class
// Inherits from: EventEmitter

// ----------------
// Events emitted by this class

// server-connect
// server-close
// sever-error

// client-change
// client-cache-updated

// single-message

// listening
// close

// ----------------
// Class declaration

function Client(chan) {
	Base.call(this, chan);

	var self = this;

	// The groups the client has joined
	this._groups = {};

	// Client and group cache
	this._client_cache = new neigh.NeighborManager();
	this._group_cache = new neigh.NeighborManager();

	// ----------------
	// Server socket

	this._server_sock = undefined;

	// When socket is ready try to find server
	this.on('listening', function(){
		self.findServer();

		var message = new msgs.Message(
			msgs.types.CLIENT_ADVERTISEMENT,
			self.getProfile(),
			"I'm Here..."
		);

		self.sendUDP(self._channel, message.toString());

	});
};
inherits(Client, Base);

// ----------------
// Public methods

// function findServer
// tries to find a server by sending a SERVER_SOLICITATION
// message. Fires server-found event.
Client.prototype.findServer = function() {
	var message = new msgs.Message(
		msgs.types.SERVER_SOLICITATION,
		this.getProfile(),
		"Server solicitation..."
	);
	this.sendUDP(addrs.channels.server, message.toString());
}

// function connect
// stablish a TCP connection to given address and port.
// Used for connecting to a server
Client.prototype.connect = function(address, port) {
	var self = this;
	var addr = address + ':' + port;

	// Initializes socket
	if (this._server_sock) this._server_sock.destroy();
	this._server_sock = new net.Socket();

	this._server_sock.connect(port, address);

	// Data arrives
	this._server_sock.on('data', function(data) {
		this._tcpMessageHandler(data);
	});

	// Connection status
	this._server_sock.on('connect', function() {
		self.emit('server-connect');
	});

	this._server_sock.on('close', function() {
		self.emit('server-close');
	});

	this._server_sock.on('error', function(err) {
		self.emit('server-error', err);
	});
}

// @override
Client.prototype.close = function() {
	Base.prototype.close.call(this);
	if (this._server_sock)
		this._server_sock.end();
}

Client.prototype.createGroup = function(group_name) {
	// Sends a GROUP_CREATE message

	if (this._server_sock.writable) {

		var message = new msgs.Message(
			msgs.types.GROUP_CREATE,
			this.getProfile(),
			{
				name: group_name,
				comments: 'let m crat it plz'
			}
		);

		this._server_sock.write(message.toString());
	}
}

Client.prototype.joinGroup = function(group_uuid) {
	// Sends a GROUP_JOIN message

	if (this._server_sock.writable) {

		var message = new msgs.Message(
			msgs.types.GROUP_JOIN,
			this.getProfile(),
			{
				uuid: group_uuid,
				comments: 'let me jion plz'
			}
		);

		this._server_sock.write(message.toString());
	}
}

Client.prototype.leaveGroup = function(group_uuid) {
	// Sends GROUP_LEAVE message

	if (this._server_sock.writable) {

		var message = new msgs.Message(
			msgs.types.GROUP_LEAVE,
			this.getProfile(),
			{
				uuid: group_uuid,
				comments: 'let m go plz'
			}
		);

		this._server_sock.write(message.toString());
	}
}

// function updateClientCache
// Sends a CLIENT_SOLICITATION message to the
// channel to which this client is connected
Client.prototype.updateClientCache = function() {
	var message = new msgs.Message(
		msgs.types.CLIENT_SOLICITATION,
		this.getProfile()
	);

	this.sendUDP(this._channel, message.toString());
}

Client.prototype.getClientCache = function() {
	return this._client_cache.getNeighbors();
}

Client.prototype.setAlias = function(alias) {
	var message = new msgs.Message(

		msgs.types.CLIENT_CHANGE,
		this.getProfile(),
		{
			old_name: this.alias,
			new_name: alias
		}

	);

	this.sendUDP(this._channel, message.toString());

	this.alias = alias;
}

// function updateAlias
// @param uuid neighbor id
// @param message sended by neighbor
// @return undefined

Client.prototype.updateAlias = function(uuid, message){

	var neighbor = this.getClientCache()[uuid].data;
	console.log('old alias ${neighbor.alias}');
	console.log();
	neighbor.alias = message.new_name;
	console.log('new alias ${neighbor.alias}');

	this.emit('client-change', uuid, message);

}

// ----------------
// Private methods

// function _tcpMessageHandler
// handles the messages comming from the server
// @param data the data received
// @returns undefined
Client.prototype._tcpMessageHandler = function(data) {

	// JSON parse
	data = JSON.parse(data.toString());

	switch(data.type) {

		// GROUP_*_OK
		case msgs.types.GROUP_CREATE_OK:
			// Tell everyone that we just created a group
			var message = new msgs.Message(
				msgs.types.GROUP_CREATE_OK,
				this.getProfile(),
				data.extras
			);
			this.sendUDP(this._channel, message.toString());
		case msgs.types.GROUP_JOIN_OK:
			this._sock.addMembership(data.extras.channel.address);
			// Tell group that we joined
			var message = new msgs.Message(
				msgs.types.GROUP_JOIN_OK,
				this.getProfile(),
				'Joined!'
			);
			this.sendUDP(data.extras.channel, message.toString());
			break;

		case msgs.types.GROUP_LEAVE_OK:
			// Tell group that we left
			var message = new msgs.Message(
				msgs.types.GROUP_LEAVE_OK,
				this.getProfile(),
				'Left!'
			);
			this.sendUDP(data.extras.channel, message.toString());
			this._sock.dropMembership(data.extras.channel.address);
			break;

		// GROUP_*_ERR
		case msgs.types.GROUP_CREATE_ERR:
			break;
		case msgs.types.GROUP_JOIN_ERR:
			break;
		case msgs.types.GROUP_LEAVE_OK:
			break;
	}
}

// function _messageHandler
// @param message buffer of the message
// @remote object that contains the address and port of the sender
// @returns undefined
Client.prototype._messageHandler = function(message, remote) {

	var data = JSON.parse(message.toString());

	// Checks that this message isn't comming from us
	if (data.sender.uuid == this._uuid) return;

	// Fixes the channel of the sender
	data.sender.channel = new addrs.Channel(remote.address, remote.port);

	switch(data.type) {

		// ----------------
		// Server messages
		case msgs.types.SERVER_ADVERTISEMENT:
			this.connect(remote.address, remote.port);
			break;

		// ----------------
		// General messages handling

		case msgs.types.CLIENT_ONLINE:
		case msgs.types.CLIENT_ADVERTISEMENT:
			// Save client in cache
			this._client_cache.addNeighbor(new neigh.Neighbor(data.sender.uuid, data.sender));
			this.emit('client-cache-updated');

			break;
		case msgs.types.CLIENT_CHANGE:
			// Update client data

			this.updateAlias(data.sender.uuid, data.extras);

			break;
		case msgs.types.CLIENT_SOLICITATION:
			// Tell client we are online
			var message = new msgs.Message(
				msgs.types.CLIENT_ADVERTISEMENT,
				this.getProfile()
			);

			this.sendUDP(data.sender.channel, message.toString());
			break;
		case msgs.types.CLIENT_OFFLINE:
			// Delete client from list of neighbors
			break;

		// ----------------
		// All / Group messages handling

		case msgs.types.GROUP_SOLICITATION:
			// Tell client of all groups we have
			break;
		case msgs.types.GROUP_ADVERTISEMENT:
			// Save group in neighbor-groups list
			break;

		// ----------------
		// Single / Group messages handling

		case msgs.types.GROUP_CREATE_OK:
			// Group was created, save it in neighbor-group list
			this._group_cache.addNeighbor(new neigh.Neighbor(data.extras.uuid, data.extras));
			break;
		case msgs.types.GROUP_JOIN_OK:
			// Client is trying to join a group
			// Probably a group we joined too!
			break;
		case msgs.types.GROUP_LEAVE_OK:
			// Somebody is leaving a group
			// Probably a group we joined too!
			break;

		case msgs.types.GROUP_MESSAGE:
			// Messages to a group
			break;
		case msgs.types.SINGLE_MESSAGE:
			// We received an unicast message
			this.emit('single-message', data.sender, data.extras);
			break;
	} // switch

} // messageHandler

// ----------------
// Exports
// ----------------

module.exports = Client;<commit_msg>Fixed typo<commit_after>var
	dgram = require('dgram'),
	EventEmitter = require('events').EventEmitter,
	inherits = require('util').inherits,
	net = require('net'),
	uuid = require('uuid'),

	Base = require('./Base'),
	addrs = require('../Misc/addresses'),
	msgs = require('../Misc/messages'),
	neigh = require('../Misc/neigh');

// ----------------
// Client class
// ----------------
// Main client class
// Inherits from: EventEmitter

// ----------------
// Events emitted by this class

// server-connect
// server-close
// sever-error

// client-change
// client-cache-updated

// single-message

// listening
// close

// ----------------
// Class declaration

function Client(chan) {
	Base.call(this, chan);

	var self = this;

	// The groups the client has joined
	this._groups = {};

	// Client and group cache
	this._client_cache = new neigh.NeighborManager();
	this._group_cache = new neigh.NeighborManager();

	// ----------------
	// Server socket

	this._server_sock = undefined;

	// When socket is ready try to find server
	this.on('listening', function(){
		self.findServer();

		var message = new msgs.Message(
			msgs.types.CLIENT_ADVERTISEMENT,
			self.getProfile(),
			"I'm Here..."
		);

		self.sendUDP(self._channel, message.toString());

	});
};
inherits(Client, Base);

// ----------------
// Public methods

// function findServer
// tries to find a server by sending a SERVER_SOLICITATION
// message. Fires server-found event.
Client.prototype.findServer = function() {
	var message = new msgs.Message(
		msgs.types.SERVER_SOLICITATION,
		this.getProfile(),
		"Server solicitation..."
	);
	this.sendUDP(addrs.channels.server, message.toString());
}

// function connect
// stablish a TCP connection to given address and port.
// Used for connecting to a server
Client.prototype.connect = function(address, port) {
	var self = this;
	var addr = address + ':' + port;

	// Initializes socket
	if (this._server_sock) this._server_sock.destroy();
	this._server_sock = new net.Socket();

	this._server_sock.connect(port, address);

	// Data arrives
	this._server_sock.on('data', function(data) {
		self._tcpMessageHandler(data);
	});

	// Connection status
	this._server_sock.on('connect', function() {
		self.emit('server-connect');
	});

	this._server_sock.on('close', function() {
		self.emit('server-close');
	});

	this._server_sock.on('error', function(err) {
		self.emit('server-error', err);
	});
}

// @override
Client.prototype.close = function() {
	Base.prototype.close.call(this);
	if (this._server_sock)
		this._server_sock.end();
}

Client.prototype.createGroup = function(group_name) {
	// Sends a GROUP_CREATE message

	if (this._server_sock.writable) {

		var message = new msgs.Message(
			msgs.types.GROUP_CREATE,
			this.getProfile(),
			{
				name: group_name,
				comments: 'let m crat it plz'
			}
		);

		this._server_sock.write(message.toString());
	}
}

Client.prototype.joinGroup = function(group_uuid) {
	// Sends a GROUP_JOIN message

	if (this._server_sock.writable) {

		var message = new msgs.Message(
			msgs.types.GROUP_JOIN,
			this.getProfile(),
			{
				uuid: group_uuid,
				comments: 'let me jion plz'
			}
		);

		this._server_sock.write(message.toString());
	}
}

Client.prototype.leaveGroup = function(group_uuid) {
	// Sends GROUP_LEAVE message

	if (this._server_sock.writable) {

		var message = new msgs.Message(
			msgs.types.GROUP_LEAVE,
			this.getProfile(),
			{
				uuid: group_uuid,
				comments: 'let m go plz'
			}
		);

		this._server_sock.write(message.toString());
	}
}

// function updateClientCache
// Sends a CLIENT_SOLICITATION message to the
// channel to which this client is connected
Client.prototype.updateClientCache = function() {
	var message = new msgs.Message(
		msgs.types.CLIENT_SOLICITATION,
		this.getProfile()
	);

	this.sendUDP(this._channel, message.toString());
}

Client.prototype.getClientCache = function() {
	return this._client_cache.getNeighbors();
}

Client.prototype.setAlias = function(alias) {
	var message = new msgs.Message(

		msgs.types.CLIENT_CHANGE,
		this.getProfile(),
		{
			old_name: this.alias,
			new_name: alias
		}

	);

	this.sendUDP(this._channel, message.toString());

	this.alias = alias;
}

// function updateAlias
// @param uuid neighbor id
// @param message sended by neighbor
// @return undefined

Client.prototype.updateAlias = function(uuid, message){

	var neighbor = this.getClientCache()[uuid].data;
	console.log('old alias ${neighbor.alias}');
	console.log();
	neighbor.alias = message.new_name;
	console.log('new alias ${neighbor.alias}');

	this.emit('client-change', uuid, message);

}

// ----------------
// Private methods

// function _tcpMessageHandler
// handles the messages comming from the server
// @param data the data received
// @returns undefined
Client.prototype._tcpMessageHandler = function(data) {

	// JSON parse
	data = JSON.parse(data.toString());

	switch(data.type) {

		// GROUP_*_OK
		case msgs.types.GROUP_CREATE_OK:
			// Tell everyone that we just created a group
			var message = new msgs.Message(
				msgs.types.GROUP_CREATE_OK,
				this.getProfile(),
				data.extras
			);
			this.sendUDP(this._channel, message.toString());
		case msgs.types.GROUP_JOIN_OK:
			this._sock.addMembership(data.extras.channel.address);
			// Tell group that we joined
			var message = new msgs.Message(
				msgs.types.GROUP_JOIN_OK,
				this.getProfile(),
				'Joined!'
			);
			this.sendUDP(data.extras.channel, message.toString());
			break;

		case msgs.types.GROUP_LEAVE_OK:
			// Tell group that we left
			var message = new msgs.Message(
				msgs.types.GROUP_LEAVE_OK,
				this.getProfile(),
				'Left!'
			);
			this.sendUDP(data.extras.channel, message.toString());
			this._sock.dropMembership(data.extras.channel.address);
			break;

		// GROUP_*_ERR
		case msgs.types.GROUP_CREATE_ERR:
			break;
		case msgs.types.GROUP_JOIN_ERR:
			break;
		case msgs.types.GROUP_LEAVE_OK:
			break;
	}
}

// function _messageHandler
// @param message buffer of the message
// @remote object that contains the address and port of the sender
// @returns undefined
Client.prototype._messageHandler = function(message, remote) {

	var data = JSON.parse(message.toString());

	// Checks that this message isn't comming from us
	if (data.sender.uuid == this._uuid) return;

	// Fixes the channel of the sender
	data.sender.channel = new addrs.Channel(remote.address, remote.port);

	switch(data.type) {

		// ----------------
		// Server messages
		case msgs.types.SERVER_ADVERTISEMENT:
			this.connect(remote.address, remote.port);
			break;

		// ----------------
		// General messages handling

		case msgs.types.CLIENT_ONLINE:
		case msgs.types.CLIENT_ADVERTISEMENT:
			// Save client in cache
			this._client_cache.addNeighbor(new neigh.Neighbor(data.sender.uuid, data.sender));
			this.emit('client-cache-updated');

			break;
		case msgs.types.CLIENT_CHANGE:
			// Update client data

			this.updateAlias(data.sender.uuid, data.extras);

			break;
		case msgs.types.CLIENT_SOLICITATION:
			// Tell client we are online
			var message = new msgs.Message(
				msgs.types.CLIENT_ADVERTISEMENT,
				this.getProfile()
			);

			this.sendUDP(data.sender.channel, message.toString());
			break;
		case msgs.types.CLIENT_OFFLINE:
			// Delete client from list of neighbors
			break;

		// ----------------
		// All / Group messages handling

		case msgs.types.GROUP_SOLICITATION:
			// Tell client of all groups we have
			break;
		case msgs.types.GROUP_ADVERTISEMENT:
			// Save group in neighbor-groups list
			break;

		// ----------------
		// Single / Group messages handling

		case msgs.types.GROUP_CREATE_OK:
			// Group was created, save it in neighbor-group list
			this._group_cache.addNeighbor(new neigh.Neighbor(data.extras.uuid, data.extras));
			break;
		case msgs.types.GROUP_JOIN_OK:
			// Client is trying to join a group
			// Probably a group we joined too!
			break;
		case msgs.types.GROUP_LEAVE_OK:
			// Somebody is leaving a group
			// Probably a group we joined too!
			break;

		case msgs.types.GROUP_MESSAGE:
			// Messages to a group
			break;
		case msgs.types.SINGLE_MESSAGE:
			// We received an unicast message
			this.emit('single-message', data.sender, data.extras);
			break;
	} // switch

} // messageHandler

// ----------------
// Exports
// ----------------

module.exports = Client;<|endoftext|>


<commit_before>var
	dgram = require('dgram'),
	EventEmitter = require('events').EventEmitter,
	inherits = require('util').inherits,
	net = require('net'),
	uuid = require('uuid'),

	Base = require('./Base'),
	addrs = require('../Misc/addresses'),
	msgs = require('../Misc/messages'),
	neigh = require('../Misc/neigh');

// ----------------
// Client class
// ----------------
// Main client class
// Inherits from: EventEmitter

// ----------------
// Events

// listening
// close

// ----------------
// Class declaration

function Client(chan) {
	Base.call(this, chan);

	var self = this;

	// Client cache
	this._client_cache = new neigh.NeighborManager();

	// ----------------
	// Server socket

	this._server_sock = new net.Socket();

	// When socket is ready try to find server
	this.on('listening', this.findServer);
};
inherits(Client, Base);

// ----------------
// Public methods

// function findServer
// tries to find a server by sending a SERVER_SOLICITATION
// message. Fires server-found event.
Client.prototype.findServer = function() {
	var message = new msgs.Message(
		msgs.types.SERVER_SOLICITATION,
		"Server solicitation..."
	);
	this.sendUDP(this._channel, message.toString());
}

// function connect
// stablish a TCP connection to given address and port.
// Used for connecting to a server
Client.prototype.connect = function(address, port) {

	var addr = address + ':' + port;

	this._server_sock.connect(port, address);

	// Data arrives
	this._server_sock.on('data', this._tcpMessageHandler);

	// Connection status
	this._server_sock.on('connect', function() {
		console.log('Connected to server: ' + addr);
	});

	this._server_sock.on('close', function() {
		console.log('Disconnected from server: ' + addr);
	});

	this._server_sock.on('error', function() {
		console.log('Unable to conect to server: ' + addr)
	});
}

// @override
Client.prototype.close = function() {
	Base.prototype.close.call(this);
	if (this._server_sock)
		this._server_sock.end();
}

Client.prototype.createGroup = function(group_name) {
	// Gets Multicast address from server
	// Creates group socket
}

// function updateClientCache
// Sends a CLIENT_SOLICITATION message to the
// channel to which this client is connected
Client.prototype.updateClientCache = function() {
	var message = new msgs.Message(
		msgs.types.CLIENT_SOLICITATION,
		this.getProfile()
	);

	this.sendUDP(this._channel, message.toString());
}

// ----------------
// Private methods

// function _tcpMessageHandler
// handles the messages comming from the server
// @param data the data received
// @returns undefined
Client.prototype._tcpMessageHandler = function(data) {

	// JSON parse
	data = JSON.parse(data.toString());

	switch(data.type) {

		case msgs.types.GROUP_CREATE_OK:
			break;
		case msgs.types.GROUP_JOIN_OK:
			break;
		case msgs.types.GROUP_LEAVE_OK:
			break;
	}
}

// function _messageHandler
// @param message buffer of the message
// @remote object that contains the address and port of the sender
// @returns undefined
Client.prototype._messageHandler = function(message, remote) {

	var data = JSON.parse(message.toString());

	// Checks that this message isn't comming from us
	if (data.sender.uuid == this._uuid) return;

	switch(data.type) {

		// ----------------
		// Server messages
		case msgs.types.SERVER_ADVERTISEMENT:
			this.connect(remote.address, remote.port);
			break;

		// ----------------
		// General messages handling

		case msgs.types.CLIENT_ONLINE:
		case msgs.types.CLIENT_REPORT:
		case msgs.types.CLIENT_ADVERTISEMENT:
			// Save client in cache
			break;
		case msgs.types.CLIENT_CHANGE:
			// Update client data
			break;
		case msgs.types.CLIENT_SOLICITATION:
			// Tell client we are online
			var message = new msgs.Message(
				msgs.types.CLIENT_REPORT,
				this.getProfile()
			);
			this.sendUDP(sender.channel, message.toString());
			break;
		case msgs.types.CLIENT_OFFLINE:
			// Delete client from list of neighbors
			break;

		// ----------------
		// All / Group messages handling

		case msgs.types.GROUP_SOLICITATION:
			// Tell client of all groups we have
			break;
		case msgs.types.GROUP_ADVERTISEMENT:
			// Save group in neighbor-groups list
			break;

		// ----------------
		// Single / Group messages handling

		case msgs.types.GROUP_CREATE:
			// Group was created, save it in neighbor-group list
			break;
		case msgs.types.GROUP_DELETE:
			// Group deleted, remove it from neighbor-group list
			break;
		case msgs.types.GROUP_JOIN:
			// Client is trying to join a group (maybe of ours)
			break;
		case msgs.types.GROUP_LEAVE:
			// Somebody is leaving a group
			break;
		case msgs.types.GROUP_MESSAGE:
			// Messages to a group
			break;
		case msgs.types.GROUP_JOIN_OK:
			// We were able to join a group
			break;
		case msgs.types.GROUP_JOIN_ERR:
			// We weren't able to join a group
			break;
		case msgs.types.SINGLE_MESSAGE:
			// We received an unicast message
			break;
	} // switch

} // messageHandler

// ----------------
// Exports
// ----------------

module.exports = Client;<commit_msg>Something changed<commit_after>var
	dgram = require('dgram'),
	EventEmitter = require('events').EventEmitter,
	inherits = require('util').inherits,
	net = require('net'),
	uuid = require('uuid'),

	Base = require('./Base'),
	addrs = require('../Misc/addresses'),
	msgs = require('../Misc/messages'),
	neigh = require('../Misc/neigh');

// ----------------
// Client class
// ----------------
// Main client class
// Inherits from: EventEmitter

// ----------------
// Events

// listening
// close

// ----------------
// Class declaration

function Client(chan) {
	Base.call(this, chan);

	var self = this;

	// Client cache
	this._client_cache = new neigh.NeighborManager();

	// ----------------
	// Server socket

	this._server_sock = new net.Socket();

	// When socket is ready try to find server
	this.on('listening', this.findServer);
};
inherits(Client, Base);

// ----------------
// Public methods

// function findServer
// tries to find a server by sending a SERVER_SOLICITATION
// message. Fires server-found event.
Client.prototype.findServer = function() {
	var message = new msgs.Message(
		msgs.types.SERVER_SOLICITATION,
		this.getProfile(),
		"Server solicitation..."
	);
	this.sendUDP(this._channel, message.toString());
}

// function connect
// stablish a TCP connection to given address and port.
// Used for connecting to a server
Client.prototype.connect = function(address, port) {

	var addr = address + ':' + port;

	this._server_sock.connect(port, address);

	// Data arrives
	this._server_sock.on('data', this._tcpMessageHandler);

	// Connection status
	this._server_sock.on('connect', function() {
		console.log('Connected to server: ' + addr);
	});

	this._server_sock.on('close', function() {
		console.log('Disconnected from server: ' + addr);
	});

	this._server_sock.on('error', function() {
		console.log('Unable to conect to server: ' + addr)
	});
}

// @override
Client.prototype.close = function() {
	Base.prototype.close.call(this);
	if (this._server_sock)
		this._server_sock.end();
}

Client.prototype.createGroup = function(group_name) {
	// Gets Multicast address from server
	// Creates group socket
}

// function updateClientCache
// Sends a CLIENT_SOLICITATION message to the
// channel to which this client is connected
Client.prototype.updateClientCache = function() {
	var message = new msgs.Message(
		msgs.types.CLIENT_SOLICITATION,
		this.getProfile()
	);

	this.sendUDP(this._channel, message.toString());
}

// ----------------
// Private methods

// function _tcpMessageHandler
// handles the messages comming from the server
// @param data the data received
// @returns undefined
Client.prototype._tcpMessageHandler = function(data) {

	// JSON parse
	data = JSON.parse(data.toString());

	switch(data.type) {

		case msgs.types.GROUP_CREATE_OK:
			break;
		case msgs.types.GROUP_JOIN_OK:
			break;
		case msgs.types.GROUP_LEAVE_OK:
			break;
	}
}

// function _messageHandler
// @param message buffer of the message
// @remote object that contains the address and port of the sender
// @returns undefined
Client.prototype._messageHandler = function(message, remote) {

	var data = JSON.parse(message.toString());

	// Checks that this message isn't comming from us
	if (data.sender.uuid == this._uuid) return;

	switch(data.type) {

		// ----------------
		// Server messages
		case msgs.types.SERVER_ADVERTISEMENT:
			this.connect(remote.address, remote.port);
			break;

		// ----------------
		// General messages handling

		case msgs.types.CLIENT_ONLINE:
		case msgs.types.CLIENT_REPORT:
		case msgs.types.CLIENT_ADVERTISEMENT:
			// Save client in cache

			break;
		case msgs.types.CLIENT_CHANGE:
			// Update client data
			break;
		case msgs.types.CLIENT_SOLICITATION:
			// Tell client we are online
			var message = new msgs.Message(
				msgs.types.CLIENT_REPORT,
				this.getProfile()
			);
			this.sendUDP(sender.channel, message.toString());
			break;
		case msgs.types.CLIENT_OFFLINE:
			// Delete client from list of neighbors
			break;

		// ----------------
		// All / Group messages handling

		case msgs.types.GROUP_SOLICITATION:
			// Tell client of all groups we have
			break;
		case msgs.types.GROUP_ADVERTISEMENT:
			// Save group in neighbor-groups list
			break;

		// ----------------
		// Single / Group messages handling

		case msgs.types.GROUP_CREATE:
			// Group was created, save it in neighbor-group list
			break;
		case msgs.types.GROUP_DELETE:
			// Group deleted, remove it from neighbor-group list
			break;
		case msgs.types.GROUP_JOIN:
			// Client is trying to join a group (maybe of ours)
			break;
		case msgs.types.GROUP_LEAVE:
			// Somebody is leaving a group
			break;
		case msgs.types.GROUP_MESSAGE:
			// Messages to a group
			break;
		case msgs.types.GROUP_JOIN_OK:
			// We were able to join a group
			break;
		case msgs.types.GROUP_JOIN_ERR:
			// We weren't able to join a group
			break;
		case msgs.types.SINGLE_MESSAGE:
			// We received an unicast message
			break;
	} // switch

} // messageHandler

// ----------------
// Exports
// ----------------

module.exports = Client;<|endoftext|>


<commit_before>/**
 * @module ControllerOut
 * @description Utility object for controller responses (wraps Sails response object)
 * @see {@link https://github.com/grokible/sails-tutorial-1/blob/master/TUTORIALS/TUTORIAL02.md}
 * @see {@link http://sailsjs.org/#/documentation/reference/res|Sails Response('res') Reference}
 * @example
 * // In Sails controller:
 * var ControllerOut = require ('Local/ControllerOut')
 * ...
 * someAction: function (req, res) {
 *     var co = new ControllerOut (res)
 *     ...
 *     if (err)
 *         return co.error (err)  // jsonify err and send via Sails response obj
 *     else if (err2)
 *         return co.error (err2, { code: 'math.wayTooBig', message: "too big" });
 *                             // ^ override error properties
 * }
 */

module.exports = ControllerOut;

function ControllerOut (response) {
    this.response = response;
}

ControllerOut.prototype.error = function (error, options) {

    // Options properties {code, message} override error's
    // After options, underbar takes precedence (_code or _message) override error's

    options = options || {};
    var code = options.code || error._code || error.code || 'general.unknown';

    // Attempt to pull out any conceivable error message that we can use

    var message = options.message || error._message || error.message || error.description ||
        error.title || error.summary || error.reason || 'No message, unknown error.';

    var rc = {
        code: code,
        message: message
    };

    // If we are in a sails dev environment, supply all the error details
    if (sails.config.environment == 'development') {
        rc._internal = error;
    }

    return this.response.json ({ error: rc });
};
<commit_msg>fixed response return<commit_after>/**
 * @module ControllerOut
 * @description Utility object for controller responses (wraps Sails response object)
 * @see {@link https://github.com/grokible/sails-tutorial-1/blob/master/TUTORIALS/TUTORIAL02.md}
 * @see {@link http://sailsjs.org/#/documentation/reference/res|Sails Response('res') Reference}
 * @example
 * // In Sails controller:
 * var ControllerOut = require ('Local/ControllerOut')
 * ...
 * someAction: function (req, res) {
 *     var co = new ControllerOut (res)
 *     ...
 *     if (err)
 *         return co.error (err)  // jsonify err and send via Sails response obj
 *     else if (err2)
 *         return co.error (err2, { code: 'math.wayTooBig', message: "too big" });
 *                             // ^ override error properties
 * }
 */

module.exports = ControllerOut;

function ControllerOut (response) {
    this.response = response;
}

ControllerOut.prototype.error = function (error, options) {

    // Options properties {code, message} override error's
    // After options, underbar takes precedence (_code or _message) override error's

    options = options || {};
    var code = options.code || error._code || error.code || 'general.unknown';

    // Attempt to pull out any conceivable error message that we can use

    var message = options.message || error._message || error.message || error.description ||
        error.title || error.summary || error.reason || 'No message, unknown error.';

    var rc = {
        code: code,
        message: message
    };

    // If we are in a sails dev environment, supply all the error details
    if (sails.config.environment == 'development') {
        rc._internal = error;
    }

    return this.response.serverError ({ error: rc });
};
<|endoftext|>


<commit_before>var mysql       = require("mysql");

exports.Driver = Driver;

function Driver(opts, connection) {
	this.opts = opts || {};
	if (!this.opts.timezone) {
		// force UTC if not defined, UTC is always better..
		this.opts.timezone = "Z";
	}
	this.db = (connection ? connection : mysql.createConnection(opts));

	var escapes = {
		escape   : this.db.escape,
		escapeId : escapeId
	};

	this.QuerySelect = new (require("../sql/Select"))(escapes);
	this.QueryInsert = new (require("../sql/Insert"))(escapes);
	this.QueryUpdate = new (require("../sql/Update"))(escapes);
	this.QueryRemove = new (require("../sql/Remove"))(escapes);
}

Driver.prototype.connect = function (cb) {
	this.db.connect(cb);
};

Driver.prototype.close = function (cb) {
	this.db.end(cb);
};

Driver.prototype.find = function (table, conditions, opts, cb) {
	this.QuerySelect
		.clear()
		.table(table);
	if (opts.fields) {
		this.QuerySelect.fields(opts.fields);
	}
	if (opts.merge) {
		this.QuerySelect.merge(opts.merge.from, opts.merge.to);
	}
	if (typeof opts.limit == "number") {
		this.QuerySelect.limit(opts.limit);
	}
	if (opts.order) {
		this.QuerySelect.order(opts.order[0], opts.order[1]);
	}
	for (var k in conditions) {
		this.QuerySelect.where(k, conditions[k]);
	}

	this.db.query(this.QuerySelect.build(), cb);
};

Driver.prototype.insert = function (table, data, cb) {
	this.QueryInsert
		.clear()
		.table(table);
	for (var k in data) {
		this.QueryInsert.set(k, data[k]);
	}

	this.db.query(this.QueryInsert.build(), function (err, info) {
		if (err) {
			return cb(err);
		}
		return cb(null, {
			id: info.insertId
		});
	});
};

Driver.prototype.update = function (table, changes, id_prop, id, cb) {
	this.QueryUpdate
		.clear()
		.table(table)
		.where(id_prop, id);
	for (var k in changes) {
		this.QueryUpdate.set(k, changes[k]);
	}

	this.db.query(this.QueryUpdate.build(), cb);
};

Driver.prototype.remove = function (table, conditions, cb) {
	this.QueryRemove
		.clear()
		.table(table);
	for (var k in conditions) {
		this.QueryRemove.where(k, conditions[k]);
	}

	this.db.query(this.QueryRemove.build(), cb);
};

Driver.prototype.clear = function (table, cb) {
	this.db.query("TRUNCATE TABLE " + escapeId(table), cb);
};

Driver.prototype.valueToProperty = function (value, property) {
	if (property.type == "boolean") {
		return !!value;
	}
	return value;
};

Driver.prototype.propertyToValue = function (value, property) {
	if (property.type == "boolean") {
		return (value) ? 1 : 0;
	}
	return value;
};

function escapeId(id) {
	var m = id.match(/^(.+)\.\*$/);
	if (m) {
		return '`' + m[1].replace(/\`/g, '``') + '`.*';
	}
	return '`' + id.replace(/\`/g, '``').replace(/\./g, '`.`') + '`';
}
<commit_msg>Updates mysql driver to support object types (converting them to JSON)<commit_after>var mysql       = require("mysql");

exports.Driver = Driver;

function Driver(opts, connection) {
	this.opts = opts || {};
	if (!this.opts.timezone) {
		// force UTC if not defined, UTC is always better..
		this.opts.timezone = "Z";
	}
	this.db = (connection ? connection : mysql.createConnection(opts));

	var escapes = {
		escape   : this.db.escape,
		escapeId : escapeId
	};

	this.QuerySelect = new (require("../sql/Select"))(escapes);
	this.QueryInsert = new (require("../sql/Insert"))(escapes);
	this.QueryUpdate = new (require("../sql/Update"))(escapes);
	this.QueryRemove = new (require("../sql/Remove"))(escapes);
}

Driver.prototype.connect = function (cb) {
	this.db.connect(cb);
};

Driver.prototype.close = function (cb) {
	this.db.end(cb);
};

Driver.prototype.find = function (table, conditions, opts, cb) {
	this.QuerySelect
		.clear()
		.table(table);
	if (opts.fields) {
		this.QuerySelect.fields(opts.fields);
	}
	if (opts.merge) {
		this.QuerySelect.merge(opts.merge.from, opts.merge.to);
	}
	if (typeof opts.limit == "number") {
		this.QuerySelect.limit(opts.limit);
	}
	if (opts.order) {
		this.QuerySelect.order(opts.order[0], opts.order[1]);
	}
	for (var k in conditions) {
		this.QuerySelect.where(k, conditions[k]);
	}

	this.db.query(this.QuerySelect.build(), cb);
};

Driver.prototype.insert = function (table, data, cb) {
	this.QueryInsert
		.clear()
		.table(table);
	for (var k in data) {
		this.QueryInsert.set(k, data[k]);
	}

	this.db.query(this.QueryInsert.build(), function (err, info) {
		if (err) {
			return cb(err);
		}
		return cb(null, {
			id: info.insertId
		});
	});
};

Driver.prototype.update = function (table, changes, id_prop, id, cb) {
	this.QueryUpdate
		.clear()
		.table(table)
		.where(id_prop, id);
	for (var k in changes) {
		this.QueryUpdate.set(k, changes[k]);
	}

	this.db.query(this.QueryUpdate.build(), cb);
};

Driver.prototype.remove = function (table, conditions, cb) {
	this.QueryRemove
		.clear()
		.table(table);
	for (var k in conditions) {
		this.QueryRemove.where(k, conditions[k]);
	}

	this.db.query(this.QueryRemove.build(), cb);
};

Driver.prototype.clear = function (table, cb) {
	this.db.query("TRUNCATE TABLE " + escapeId(table), cb);
};

Driver.prototype.valueToProperty = function (value, property) {
	switch (property.type) {
		case "boolean":
			return !!value;
		case "object":
			try {
				return JSON.parse(value);
			} catch (e) {
				return null;
			}
			break;
		default:
			return value;
	}
};

Driver.prototype.propertyToValue = function (value, property) {
	switch (property.type) {
		case "boolean":
			return (value) ? 1 : 0;
		case "object":
			return JSON.stringify(value);
		default:
			return value;
	}
};

function escapeId(id) {
	var m = id.match(/^(.+)\.\*$/);
	if (m) {
		return '`' + m[1].replace(/\`/g, '``') + '`.*';
	}
	return '`' + id.replace(/\`/g, '``').replace(/\./g, '`.`') + '`';
}
<|endoftext|>


<commit_before>var commons = require('../Utils/Common');

const REGEX_KARMA_INCREMENT = /^([^\s:+]+)(:|\s)*(\+\+|\+1)/;

function Karma(karma) {
    this.karma = karma;
}

Karma.prototype.setup = function(irc) {
    this.irc = irc;

    this.irc.onCommand('karma', this.onKarma.bind(this));
    this.irc.onCommand('karmatop', this.onKarmaTop.bind(this));

    this.irc.onMessage(this.onMessage.bind(this));
};

Karma.prototype.onKarma = function(channel, nickname, command, payload) {
    var karma = this.karma.getKarma(nickname);

    if(payload) {
        karma = this.karma.getKarma(payload);
        this.irc.answer(channel, nickname, payload + ': ' + karma);
    } else {
        this.irc.answer(channel, nickname, 'You have ' + karma + ' karma.');
    }
};

Karma.prototype.onKarmaTop = function(channel, nickname, command, payload) {

    var limit = 3;
    if(payload) {
        limit = Math.min(parseInt(payload, 10), 10);
    }

    var that = this;
    var top = this.karma.getTop(limit).map(function(nickname) {
        return nickname + ': ' + that.karma.getKarma(nickname);
    });

    this.irc.answer(channel, nickname, top.join(', '));
};

Karma.prototype.onMessage = function(channel, nickname, message, isQuery) {

    var matches = message.match(REGEX_KARMA_INCREMENT);
    if(matches) {
        var favoredNickname = matches[1];

        if(isQuery) {
            return this.irc.answer(nickname, nickname, 'You can only give karma in the channel');
        }

        if(commons.sanitizeNickname(nickname) == commons.sanitizeNickname(favoredNickname)) {
            return this.irc.answer(channel, nickname, 'You can\'t give yourself karma!');
        }

        var karma = this.karma.incrementKarma(favoredNickname);
        this.irc.answer(channel, nickname, favoredNickname + ' has now ' + karma + ' karma!');
    }
};

module.exports = Karma;<commit_msg>Avoid highlighting for karmatop<commit_after>var commons = require('../Utils/Common');

const REGEX_KARMA_INCREMENT = /^([^\s:+]+)(:|\s)*(\+\+|\+1)/;

function Karma(karma) {
    this.karma = karma;
}

Karma.prototype.setup = function(irc) {
    this.irc = irc;

    this.irc.onCommand('karma', this.onKarma.bind(this));
    this.irc.onCommand('karmatop', this.onKarmaTop.bind(this));

    this.irc.onMessage(this.onMessage.bind(this));
};

Karma.prototype.onKarma = function(channel, nickname, command, payload) {
    var karma = this.karma.getKarma(nickname);

    if(payload) {
        karma = this.karma.getKarma(payload);
        this.irc.answer(channel, nickname, payload + ': ' + karma);
    } else {
        this.irc.answer(channel, nickname, 'You have ' + karma + ' karma.');
    }
};

Karma.prototype.onKarmaTop = function(channel, nickname, command, payload) {

    var limit = 3;
    if(payload) {
        limit = Math.min(parseInt(payload, 10), 10);
    }

    var that = this;
    var top = this.karma.getTop(limit).map(function(nickname) {
        return commons.avoidHighlighting(nickname) + ': ' + that.karma.getKarma(nickname);
    });

    this.irc.answer(channel, nickname, top.join(', '));
};

Karma.prototype.onMessage = function(channel, nickname, message, isQuery) {

    var matches = message.match(REGEX_KARMA_INCREMENT);
    if(matches) {
        var favoredNickname = matches[1];

        if(isQuery) {
            return this.irc.answer(nickname, nickname, 'You can only give karma in the channel');
        }

        if(commons.sanitizeNickname(nickname) == commons.sanitizeNickname(favoredNickname)) {
            return this.irc.answer(channel, nickname, 'You can\'t give yourself karma!');
        }

        var karma = this.karma.incrementKarma(favoredNickname);
        this.irc.answer(channel, nickname, favoredNickname + ' has now ' + karma + ' karma!');
    }
};

module.exports = Karma;<|endoftext|>


<commit_before>var React = require('react-native');
var {
    StyleSheet,
    Text,
    Image,
    View,
    TouchableHighlight,
    PropTypes,
} = React;

var screen = require('Dimensions').get('window');
var tweenState = require('react-tween-state');

var styles = StyleSheet.create({
    container: {
        flex: 1,
    },
    titleContainer: {
        flexDirection: 'row',
    },
    title: {
        //flex: 0,
        //backgroundColor: '#f3f3f3',
        alignItems: 'center',
        paddingHorizontal: 2,
        paddingVertical: 10,
    },
    spacer: {
        flex: 1,
    },
    barContainer: {
        height: 4,
        position: 'relative',
    },
    bar: {
        backgroundColor: 'blue',
        position: 'absolute',
        height: 4,
    }
});

var SegmentedView = React.createClass({

    mixins: [tweenState.Mixin],

    propTypes: {
        duration: PropTypes.number,
        onTransitionStart: PropTypes.func,
        onTransitionEnd: PropTypes.func,
        onPress: PropTypes.func,
        renderTitle: PropTypes.func,
        titles: PropTypes.array,
        index: PropTypes.number,
        barColor: PropTypes.string,
        underlayColor: PropTypes.string,
        stretch: PropTypes.bool,
        selectedTitleStyle: PropTypes.object,
        titleStyle: PropTypes.object,

    },

    getDefaultProps() {
        return {
            duration: 200,
            onTransitionStart: ()=>{},
            onTransitionEnd: ()=>{},
            onPress: ()=>{},
            renderTitle: null,
            index: 0,
            barColor: '#44B7E1',
            underlayColor: '#CCCCCC',
            stretch: false,
            selectedTextStyle: null,
            textStyle: null,
            barPosition:'top'
        };
    },

    getInitialState() {
        return {
            barLeft: 0,
            barRight: screen.width,
        };
    },

    componentDidMount() {
        setTimeout(() => this.moveTo(this.props.index), 0);
    },

    componentWillReceiveProps(nextProps) {
        this.moveTo(nextProps.index);
    },

    measureHandler(ox, oy, width) {

        this.tweenState('barLeft', {
            easing: tweenState.easingTypes.easeInOutQuad,
            duration: 200,
            endValue: ox
        });

        this.tweenState('barRight', {
            easing: tweenState.easingTypes.easeInOutQuad,
            duration: 200,
            endValue: screen.width - ox - width,
            onEnd: this.props.onTransitionEnd
        });

        setTimeout(this.props.onTransitionStart, 0);
    },

    moveTo(index) {
        this.refs[index].measure(this.measureHandler);
    },

    _renderTitle(title, i) {
        return (
            <View style={styles.title}>
                <Text style={[this.props.titleStyle, i === this.props.index && this.props.selectedTitleStyle]}>{title}</Text>
            </View>
        );
    },

    renderTitle(title, i) {
        return (
            <View key={i} ref={i} style={{ flex: this.props.stretch ? 1 : 0 }}>
                <TouchableHighlight underlayColor={this.props.underlayColor} onPress={() => this.props.onPress(i)}>
                    {this.props.renderTitle ? this.props.renderTitle(title, i) : this._renderTitle(title, i)}
                </TouchableHighlight>
            </View>
        );
    },

    render() {
        var items = [];
        var titles = this.props.titles;

        if (!this.props.stretch) {
            items.push(<View key={`s`} style={styles.spacer} />);
        }

        for (var i = 0; i < titles.length; i++) {
            items.push(this.renderTitle(titles[i], i));
            if (!this.props.stretch) {
                items.push(<View key={`s${i}`} style={styles.spacer} />);
            }
        }
        var barContainer = (
          <View style={styles.barContainer}>
              <View ref="bar" style={[styles.bar, {
                  left: this.getTweeningValue('barLeft'),
                  right: this.getTweeningValue('barRight'),
                  backgroundColor: this.props.barColor
              }]} />
          </View>
        );
        return (
            <View {...this.props} style={[styles.container, this.props.style]}>
                {this.props.barPosition == 'top' && barContainer}
                <View style={styles.titleContainer}>
                    {items}
                </View>
                {this.props.barPosition == 'bottom' && barContainer}
            </View>
        );
    }
});

module.exports = SegmentedView;
<commit_msg>Adding proptype<commit_after>var React = require('react-native');
var {
    StyleSheet,
    Text,
    Image,
    View,
    TouchableHighlight,
    PropTypes,
} = React;

var screen = require('Dimensions').get('window');
var tweenState = require('react-tween-state');

var styles = StyleSheet.create({
    container: {
        flex: 1,
    },
    titleContainer: {
        flexDirection: 'row',
    },
    title: {
        //flex: 0,
        //backgroundColor: '#f3f3f3',
        alignItems: 'center',
        paddingHorizontal: 2,
        paddingVertical: 10,
    },
    spacer: {
        flex: 1,
    },
    barContainer: {
        height: 4,
        position: 'relative',
    },
    bar: {
        backgroundColor: 'blue',
        position: 'absolute',
        height: 4,
    }
});

var SegmentedView = React.createClass({

    mixins: [tweenState.Mixin],

    propTypes: {
        duration: PropTypes.number,
        onTransitionStart: PropTypes.func,
        onTransitionEnd: PropTypes.func,
        onPress: PropTypes.func,
        renderTitle: PropTypes.func,
        titles: PropTypes.array,
        index: PropTypes.number,
        barColor: PropTypes.string,
        barPosition: PropTypes.string,
        underlayColor: PropTypes.string,
        stretch: PropTypes.bool,
        selectedTitleStyle: PropTypes.object,
        titleStyle: PropTypes.object,

    },

    getDefaultProps() {
        return {
            duration: 200,
            onTransitionStart: ()=>{},
            onTransitionEnd: ()=>{},
            onPress: ()=>{},
            renderTitle: null,
            index: 0,
            barColor: '#44B7E1',
            barPosition:'top',
            underlayColor: '#CCCCCC',
            stretch: false,
            selectedTextStyle: null,
            textStyle: null,
        };
    },

    getInitialState() {
        return {
            barLeft: 0,
            barRight: screen.width,
        };
    },

    componentDidMount() {
        setTimeout(() => this.moveTo(this.props.index), 0);
    },

    componentWillReceiveProps(nextProps) {
        this.moveTo(nextProps.index);
    },

    measureHandler(ox, oy, width) {

        this.tweenState('barLeft', {
            easing: tweenState.easingTypes.easeInOutQuad,
            duration: 200,
            endValue: ox
        });

        this.tweenState('barRight', {
            easing: tweenState.easingTypes.easeInOutQuad,
            duration: 200,
            endValue: screen.width - ox - width,
            onEnd: this.props.onTransitionEnd
        });

        setTimeout(this.props.onTransitionStart, 0);
    },

    moveTo(index) {
        this.refs[index].measure(this.measureHandler);
    },

    _renderTitle(title, i) {
        return (
            <View style={styles.title}>
                <Text style={[this.props.titleStyle, i === this.props.index && this.props.selectedTitleStyle]}>{title}</Text>
            </View>
        );
    },

    renderTitle(title, i) {
        return (
            <View key={i} ref={i} style={{ flex: this.props.stretch ? 1 : 0 }}>
                <TouchableHighlight underlayColor={this.props.underlayColor} onPress={() => this.props.onPress(i)}>
                    {this.props.renderTitle ? this.props.renderTitle(title, i) : this._renderTitle(title, i)}
                </TouchableHighlight>
            </View>
        );
    },

    render() {
        var items = [];
        var titles = this.props.titles;

        if (!this.props.stretch) {
            items.push(<View key={`s`} style={styles.spacer} />);
        }

        for (var i = 0; i < titles.length; i++) {
            items.push(this.renderTitle(titles[i], i));
            if (!this.props.stretch) {
                items.push(<View key={`s${i}`} style={styles.spacer} />);
            }
        }
        var barContainer = (
          <View style={styles.barContainer}>
              <View ref="bar" style={[styles.bar, {
                  left: this.getTweeningValue('barLeft'),
                  right: this.getTweeningValue('barRight'),
                  backgroundColor: this.props.barColor
              }]} />
          </View>
        );
        return (
            <View {...this.props} style={[styles.container, this.props.style]}>
                {this.props.barPosition == 'top' && barContainer}
                <View style={styles.titleContainer}>
                    {items}
                </View>
                {this.props.barPosition == 'bottom' && barContainer}
            </View>
        );
    }
});

module.exports = SegmentedView;
<|endoftext|>