<commit_before>var qs;
(window.onpopstate = function () {
    var match,
        pl     = /\+/g,  // Regex for replacing addition symbol with a space
        search = /([^&=]+)=?([^&]*)/g,
        decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); },
        query  = window.location.search.substring(1);

    qs = {};
    while (match = search.exec(query))
       qs[decode(match[1])] = decode(match[2]);
})();

var channels;
if ("channel" in qs) {
channels = [qs['channel']], // Channels to initially join
	fadeDelay = 5000, // Set to false to disable chat fade
	showChannel = true, // Show repespective channels if the channels is longer than 1
	useColor = true, // Use chatters' colors or to inherit
	showBadges = true, // Show chatters' badges
	showEmotes = true, // Show emotes in the chat
	doTimeouts = true, // Hide the messages of people who are timed-out
	doChatClears = true, // Hide the chat from an entire channel
	showHosting = true, // Show when the channel is hosting or not
	showConnectionNotices = true; // Show messages like "Connected" and "Disconnected"
} else {
channels = ['yongjhih', 'mistakelolz', 'twitchplayspokemon'], // Channels to initially join
	fadeDelay = 5000, // Set to false to disable chat fade
	showChannel = true, // Show repespective channels if the channels is longer than 1
	useColor = true, // Use chatters' colors or to inherit
	showBadges = true, // Show chatters' badges
	showEmotes = true, // Show emotes in the chat
	doTimeouts = true, // Hide the messages of people who are timed-out
	doChatClears = true, // Hide the chat from an entire channel
	showHosting = true, // Show when the channel is hosting or not
	showConnectionNotices = true; // Show messages like "Connected" and "Disconnected"
}

var chat = document.getElementById('chat'),
	defaultColors = ['rgb(255, 0, 0)','rgb(0, 0, 255)','rgb(0, 128, 0)','rgb(178, 34, 34)','rgb(255, 127, 80)','rgb(154, 205, 50)','rgb(255, 69, 0)','rgb(46, 139, 87)','rgb(218, 165, 32)','rgb(210, 105, 30)','rgb(95, 158, 160)','rgb(30, 144, 255)','rgb(255, 105, 180)','rgb(138, 43, 226)','rgb(0, 255, 127)'],
	randomColorsChosen = {},
	clientOptions = {
			options: {
					debug: true
				},
			channels: channels
		},
	client = new irc.client(clientOptions);

function dehash(channel) {
	return channel.replace(/^#/, '');
}

function capitalize(n) {
	return n[0].toUpperCase() +  n.substr(1);
}

function htmlEntities(html) {
	function it() {
		return html.map(function(n, i, arr) {
				if(n.length == 1) {
					return n.replace(/[\u00A0-\u9999<>\&]/gim, function(i) {
						   return '&#'+i.charCodeAt(0)+';';
						});
				}
				return n;
			});
	}
	var isArray = Array.isArray(html);
	if(!isArray) {
		html = html.split('');
	}
	html = it(html);
	if(!isArray) html = html.join('');
	return html;
}

function formatEmotes(text, emotes) {
	var splitText = text.split('');
	for(var i in emotes) {
		var e = emotes[i];
		for(var j in e) {
			var mote = e[j];
			if(typeof mote == 'string') {
				mote = mote.split('-');
				mote = [parseInt(mote[0]), parseInt(mote[1])];
				var length =  mote[1] - mote[0],
					empty = Array.apply(null, new Array(length + 1)).map(function() { return '' });
				splitText = splitText.slice(0, mote[0]).concat(empty).concat(splitText.slice(mote[1] + 1, splitText.length));
				splitText.splice(mote[0], 1, '');
			}
		}
	}
	return htmlEntities(splitText).join('')
}

function badges(chan, user, isBot) {

	function createBadge(name) {
		var badge = document.createElement('div');
		badge.className = 'chat-badge-' + name;
		return badge;
	}

	var chatBadges = document.createElement('span');
	chatBadges.className = 'chat-badges';

	if(!isBot) {
		if(user.username == chan) {
			chatBadges.appendChild(createBadge('broadcaster'));
		}
		if(user['user-type']) {
			chatBadges.appendChild(createBadge(user['user-type']));
		}
		if(user.turbo) {
			chatBadges.appendChild(createBadge('turbo'));
		}
	}
	else {
		chatChages.appendChild(createBadge('bot'));
	}

	return chatBadges;
}

function handleChat(channel, user, message, self) {
	var chan = dehash(channel),
		name = user.username,
		chatBubbler = document.createElement('div'),
		chatBubble = document.createElement('span'),
		chatLine = document.createElement('span'),
		chatTail = document.createElement('span'),
		chatChannel = document.createElement('span'),
		chatAvatar = document.createElement('div'),
		chatName = document.createElement('span'),
		chatColon = document.createElement('span'),
		chatMessage = document.createElement('span');

	var color = useColor ? user.color : 'inherit';
	if(color === null) {
		if(!randomColorsChosen.hasOwnProperty(chan)) {
			randomColorsChosen[chan] = {};
		}
		if(randomColorsChosen[chan].hasOwnProperty(name)) {
			color = randomColorsChosen[chan][name];
		}
		else {
			color = defaultColors[Math.floor(Math.random()*defaultColors.length)];
			randomColorsChosen[chan][name] = color;
		}
	}

	chatLine.className = 'chat-line bubble';
	chatLine.dataset.username = name;
	chatLine.dataset.channel = channel;

	if(user['message-type'] == 'action') {
		chatLine.className += ' chat-action';
	}

	chatChannel.className = 'chat-channel';
	chatChannel.innerHTML = chan;

	chatName.className = 'chat-name';
	chatName.style.color = color;
	chatName.innerHTML = user['display-name'] || name;

	chatColon.className = 'chat-colon';

	chatMessage.className = 'chat-message';

	chatMessage.style.color = color;
	chatMessage.innerHTML = showEmotes ? formatEmotes(message, user.emotes) : htmlEntities(message);

	chatBubbler.className = 'chat-bubbler';
	chatAvatar.className = 'chat-avatar';

	if(client.opts.channels.length > 1 && showChannel) chatLine.appendChild(chatChannel);
	if(showBadges) chatLine.appendChild(badges(chan, user, self));
	//chatLine.appendChild(chatName);
	chatAvatar.appendChild(chatName);
	//chatLine.appendChild(chatColon);
	chatAvatar.appendChild(chatColon);
	chatLine.appendChild(chatMessage);
	chatBubble.appendChild(chatLine);
	chatBubbler.appendChild(chatAvatar);
	chatBubbler.appendChild(chatBubble);
	chat.appendChild(chatBubbler);

	if(typeof fadeDelay == 'number') {
		setTimeout(function() {
				chatLine.dataset.faded = '';
			}, fadeDelay);
	}

	if(chat.children.length > 50) {
		var oldMessages = [].slice.call(chat.children).slice(0, 10);
		for(var i in oldMessages) oldMessages[i].remove();
	}
}

function chatNotice(information, noticeFadeDelay, level, additionalClasses) {
	var ele = document.createElement('div');

	ele.className = 'chat-line chat-notice';
	ele.innerHTML = information;

	if(additionalClasses !== undefined) {
		if(Array.isArray(additionalClasses)) {
			additionalClasses = additionalClasses.join(' ');
		}
		ele.className += ' ' + additionalClasses;
	}

	if(typeof level == 'number' && level != 0) {
		ele.dataset.level = level;
	}

	chat.appendChild(ele);

	if(typeof noticeFadeDelay == 'number') {
		setTimeout(function() {
				ele.dataset.faded = '';
			}, noticeFadeDelay || 500);
	}

	return ele;
}

var recentTimeouts = {};

function timeout(channel, username) {
	if(!doTimeouts) return false;
	if(!recentTimeouts.hasOwnProperty(channel)) {
		recentTimeouts[channel] = {};
	}
	if(!recentTimeouts[channel].hasOwnProperty(username) || recentTimeouts[channel][username] + 1000*10 < +new Date) {
		recentTimeouts[channel][username] = +new Date;
		chatNotice(capitalize(username) + ' was timed-out in ' + capitalize(dehash(channel)), 1000, 1, 'chat-delete-timeout')
	};
	var toHide = document.querySelectorAll('.chat-line[data-channel="' + channel + '"][data-username="' + username + '"]:not(.chat-timedout) .chat-message');
	for(var i in toHide) {
		var h = toHide[i];
		if(typeof h == 'object') {
			h.innerText = '<Message deleted>';
			h.parentElement.className += ' chat-timedout';
		}
	}
}
function clearChat(channel) {
	if(!doChatClears) return false;
	var toHide = document.querySelectorAll('.chat-line[data-channel="' + channel + '"]');
	for(var i in toHide) {
		var h = toHide[i];
		if(typeof h == 'object') {
			h.className += ' chat-cleared';
		}
	}
	chatNotice('Chat was cleared in ' + capitalize(dehash(channel)), 1000, 1, 'chat-delete-clear')
}
function hosting(channel, target, viewers, unhost) {
	if(!showHosting) return false;
	if(viewers == '-') viewers = 0;
	var chan = dehash(channel);
	chan = capitalize(chan);
	if(!unhost) {
		var targ = capitalize(target);
		chatNotice(chan + ' is now hosting ' + targ + ' for ' + viewers + ' viewer' + (viewers !== 1 ? 's' : '') + '.', null, null, 'chat-hosting-yes');
	}
	else {
		chatNotice(chan + ' is no longer hosting.', null, null, 'chat-hosting-no');
	}
}

client.addListener('message', handleChat);
client.addListener('timeout', timeout);
client.addListener('clearchat', clearChat);
client.addListener('hosting', hosting);
client.addListener('unhost', function(channel, viewers) { hosting(channel, null, viewers, true) });

var joinAccounced = [];

client.addListener('connecting', function (address, port) {
		if(showConnectionNotices) {
			chatNotice('Connecting', 1000, -4, 'chat-connection-good-connecting');
		}
	});
client.addListener('logon', function () {
		if(showConnectionNotices) chatNotice('Authenticating', 1000, -3, 'chat-connection-good-logon');
	});
client.addListener('connectfail', function () {
		if(showConnectionNotices) chatNotice('Connection failed', 1000, 3, 'chat-connection-bad-fail');
	});
client.addListener('connected', function (address, port) {
		if(showConnectionNotices) chatNotice('Connected', 1000, -2, 'chat-connection-good-connected');
		joinAccounced = [];
	});
client.addListener('disconnected', function (reason) {
		if(showConnectionNotices) chatNotice('Disconnected: ' + (reason || ''), 3000, 2, 'chat-connection-bad-disconnected');
	});
client.addListener('reconnect', function () {
		if(showConnectionNotices) chatNotice('Reconnected', 1000, 'chat-connection-good-reconnect');
	});
client.addListener('join', function (channel, username) {
		if(joinAccounced.indexOf(channel) == -1) {
			if(showConnectionNotices) chatNotice(capitalize(dehash(username)) + ' joined ' + capitalize(dehash(channel)), 1000, -1, 'chat-room-join');
                        responsiveVoice.speak('歡迎來到老K的遊戲間 ' + username, 'Chinese Female');
                        var user;
                        user.username = qs['channel'];
                        user.name = qs['channel'];
                        handleChat(channel, user, '歡迎來到老K的遊戲間 ' + username, self);
			joinAccounced.push(channel);
		}
	});
client.addListener('part', function (channel, username) {
		var index = joinAccounced.indexOf(channel);
		if(index > -1) {
			if(showConnectionNotices) chatNotice(capitalize(dehash(username)) + ' parted ' + capitalize(dehash(channel)), 1000, -1, 'chat-room-part');
			joinAccounced.splice(joinAccounced.indexOf(channel), 1)
		}
	});

client.addListener('crash', function () {
		chatNotice('Crashed', 10000, 4, 'chat-crash');
	});

client.connect();
<commit_msg>try to fix welcome<commit_after>var qs;
(window.onpopstate = function () {
    var match,
        pl     = /\+/g,  // Regex for replacing addition symbol with a space
        search = /([^&=]+)=?([^&]*)/g,
        decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); },
        query  = window.location.search.substring(1);

    qs = {};
    while (match = search.exec(query))
       qs[decode(match[1])] = decode(match[2]);
})();

var channels;
if ("channel" in qs) {
channels = [qs['channel']], // Channels to initially join
	fadeDelay = 5000, // Set to false to disable chat fade
	showChannel = true, // Show repespective channels if the channels is longer than 1
	useColor = true, // Use chatters' colors or to inherit
	showBadges = true, // Show chatters' badges
	showEmotes = true, // Show emotes in the chat
	doTimeouts = true, // Hide the messages of people who are timed-out
	doChatClears = true, // Hide the chat from an entire channel
	showHosting = true, // Show when the channel is hosting or not
	showConnectionNotices = true; // Show messages like "Connected" and "Disconnected"
} else {
channels = ['yongjhih', 'mistakelolz', 'twitchplayspokemon'], // Channels to initially join
	fadeDelay = 5000, // Set to false to disable chat fade
	showChannel = true, // Show repespective channels if the channels is longer than 1
	useColor = true, // Use chatters' colors or to inherit
	showBadges = true, // Show chatters' badges
	showEmotes = true, // Show emotes in the chat
	doTimeouts = true, // Hide the messages of people who are timed-out
	doChatClears = true, // Hide the chat from an entire channel
	showHosting = true, // Show when the channel is hosting or not
	showConnectionNotices = true; // Show messages like "Connected" and "Disconnected"
}

var chat = document.getElementById('chat'),
	defaultColors = ['rgb(255, 0, 0)','rgb(0, 0, 255)','rgb(0, 128, 0)','rgb(178, 34, 34)','rgb(255, 127, 80)','rgb(154, 205, 50)','rgb(255, 69, 0)','rgb(46, 139, 87)','rgb(218, 165, 32)','rgb(210, 105, 30)','rgb(95, 158, 160)','rgb(30, 144, 255)','rgb(255, 105, 180)','rgb(138, 43, 226)','rgb(0, 255, 127)'],
	randomColorsChosen = {},
	clientOptions = {
			options: {
					debug: true
				},
			channels: channels
		},
	client = new irc.client(clientOptions);

function dehash(channel) {
	return channel.replace(/^#/, '');
}

function capitalize(n) {
	return n[0].toUpperCase() +  n.substr(1);
}

function htmlEntities(html) {
	function it() {
		return html.map(function(n, i, arr) {
				if(n.length == 1) {
					return n.replace(/[\u00A0-\u9999<>\&]/gim, function(i) {
						   return '&#'+i.charCodeAt(0)+';';
						});
				}
				return n;
			});
	}
	var isArray = Array.isArray(html);
	if(!isArray) {
		html = html.split('');
	}
	html = it(html);
	if(!isArray) html = html.join('');
	return html;
}

function formatEmotes(text, emotes) {
	var splitText = text.split('');
	for(var i in emotes) {
		var e = emotes[i];
		for(var j in e) {
			var mote = e[j];
			if(typeof mote == 'string') {
				mote = mote.split('-');
				mote = [parseInt(mote[0]), parseInt(mote[1])];
				var length =  mote[1] - mote[0],
					empty = Array.apply(null, new Array(length + 1)).map(function() { return '' });
				splitText = splitText.slice(0, mote[0]).concat(empty).concat(splitText.slice(mote[1] + 1, splitText.length));
				splitText.splice(mote[0], 1, '');
			}
		}
	}
	return htmlEntities(splitText).join('')
}

function badges(chan, user, isBot) {

	function createBadge(name) {
		var badge = document.createElement('div');
		badge.className = 'chat-badge-' + name;
		return badge;
	}

	var chatBadges = document.createElement('span');
	chatBadges.className = 'chat-badges';

	if(!isBot) {
		if(user.username == chan) {
			chatBadges.appendChild(createBadge('broadcaster'));
		}
		if(user['user-type']) {
			chatBadges.appendChild(createBadge(user['user-type']));
		}
		if(user.turbo) {
			chatBadges.appendChild(createBadge('turbo'));
		}
	}
	else {
		chatChages.appendChild(createBadge('bot'));
	}

	return chatBadges;
}

function handleChat(channel, user, message, self) {
	var chan = dehash(channel),
		name = user.username,
		chatBubbler = document.createElement('div'),
		chatBubble = document.createElement('span'),
		chatLine = document.createElement('span'),
		chatTail = document.createElement('span'),
		chatChannel = document.createElement('span'),
		chatAvatar = document.createElement('div'),
		chatName = document.createElement('span'),
		chatColon = document.createElement('span'),
		chatMessage = document.createElement('span');

	var color = useColor ? user.color : 'inherit';
	if(color === null) {
		if(!randomColorsChosen.hasOwnProperty(chan)) {
			randomColorsChosen[chan] = {};
		}
		if(randomColorsChosen[chan].hasOwnProperty(name)) {
			color = randomColorsChosen[chan][name];
		}
		else {
			color = defaultColors[Math.floor(Math.random()*defaultColors.length)];
			randomColorsChosen[chan][name] = color;
		}
	}

	chatLine.className = 'chat-line bubble';
	chatLine.dataset.username = name;
	chatLine.dataset.channel = channel;

	if(user['message-type'] == 'action') {
		chatLine.className += ' chat-action';
	}

	chatChannel.className = 'chat-channel';
	chatChannel.innerHTML = chan;

	chatName.className = 'chat-name';
	chatName.style.color = color;
	chatName.innerHTML = user['display-name'] || name;

	chatColon.className = 'chat-colon';

	chatMessage.className = 'chat-message';

	chatMessage.style.color = color;
	chatMessage.innerHTML = showEmotes ? formatEmotes(message, user.emotes) : htmlEntities(message);

	chatBubbler.className = 'chat-bubbler';
	chatAvatar.className = 'chat-avatar';

	if(client.opts.channels.length > 1 && showChannel) chatLine.appendChild(chatChannel);
	if(showBadges) chatLine.appendChild(badges(chan, user, self));
	//chatLine.appendChild(chatName);
	chatAvatar.appendChild(chatName);
	//chatLine.appendChild(chatColon);
	chatAvatar.appendChild(chatColon);
	chatLine.appendChild(chatMessage);
	chatBubble.appendChild(chatLine);
	chatBubbler.appendChild(chatAvatar);
	chatBubbler.appendChild(chatBubble);
	chat.appendChild(chatBubbler);

	if(typeof fadeDelay == 'number') {
		setTimeout(function() {
				chatLine.dataset.faded = '';
			}, fadeDelay);
	}

	if(chat.children.length > 50) {
		var oldMessages = [].slice.call(chat.children).slice(0, 10);
		for(var i in oldMessages) oldMessages[i].remove();
	}
}

function chatNotice(information, noticeFadeDelay, level, additionalClasses) {
	var ele = document.createElement('div');

	ele.className = 'chat-line chat-notice';
	ele.innerHTML = information;

	if(additionalClasses !== undefined) {
		if(Array.isArray(additionalClasses)) {
			additionalClasses = additionalClasses.join(' ');
		}
		ele.className += ' ' + additionalClasses;
	}

	if(typeof level == 'number' && level != 0) {
		ele.dataset.level = level;
	}

	chat.appendChild(ele);

	if(typeof noticeFadeDelay == 'number') {
		setTimeout(function() {
				ele.dataset.faded = '';
			}, noticeFadeDelay || 500);
	}

	return ele;
}

var recentTimeouts = {};

function timeout(channel, username) {
	if(!doTimeouts) return false;
	if(!recentTimeouts.hasOwnProperty(channel)) {
		recentTimeouts[channel] = {};
	}
	if(!recentTimeouts[channel].hasOwnProperty(username) || recentTimeouts[channel][username] + 1000*10 < +new Date) {
		recentTimeouts[channel][username] = +new Date;
		chatNotice(capitalize(username) + ' was timed-out in ' + capitalize(dehash(channel)), 1000, 1, 'chat-delete-timeout')
	};
	var toHide = document.querySelectorAll('.chat-line[data-channel="' + channel + '"][data-username="' + username + '"]:not(.chat-timedout) .chat-message');
	for(var i in toHide) {
		var h = toHide[i];
		if(typeof h == 'object') {
			h.innerText = '<Message deleted>';
			h.parentElement.className += ' chat-timedout';
		}
	}
}
function clearChat(channel) {
	if(!doChatClears) return false;
	var toHide = document.querySelectorAll('.chat-line[data-channel="' + channel + '"]');
	for(var i in toHide) {
		var h = toHide[i];
		if(typeof h == 'object') {
			h.className += ' chat-cleared';
		}
	}
	chatNotice('Chat was cleared in ' + capitalize(dehash(channel)), 1000, 1, 'chat-delete-clear')
}
function hosting(channel, target, viewers, unhost) {
	if(!showHosting) return false;
	if(viewers == '-') viewers = 0;
	var chan = dehash(channel);
	chan = capitalize(chan);
	if(!unhost) {
		var targ = capitalize(target);
		chatNotice(chan + ' is now hosting ' + targ + ' for ' + viewers + ' viewer' + (viewers !== 1 ? 's' : '') + '.', null, null, 'chat-hosting-yes');
	}
	else {
		chatNotice(chan + ' is no longer hosting.', null, null, 'chat-hosting-no');
	}
}

client.addListener('message', handleChat);
client.addListener('timeout', timeout);
client.addListener('clearchat', clearChat);
client.addListener('hosting', hosting);
client.addListener('unhost', function(channel, viewers) { hosting(channel, null, viewers, true) });

var joinAccounced = [];

client.addListener('connecting', function (address, port) {
		if(showConnectionNotices) {
			chatNotice('Connecting', 1000, -4, 'chat-connection-good-connecting');
		}
	});
client.addListener('logon', function () {
		if(showConnectionNotices) chatNotice('Authenticating', 1000, -3, 'chat-connection-good-logon');
	});
client.addListener('connectfail', function () {
		if(showConnectionNotices) chatNotice('Connection failed', 1000, 3, 'chat-connection-bad-fail');
	});
client.addListener('connected', function (address, port) {
		if(showConnectionNotices) chatNotice('Connected', 1000, -2, 'chat-connection-good-connected');
		joinAccounced = [];
	});
client.addListener('disconnected', function (reason) {
		if(showConnectionNotices) chatNotice('Disconnected: ' + (reason || ''), 3000, 2, 'chat-connection-bad-disconnected');
	});
client.addListener('reconnect', function () {
		if(showConnectionNotices) chatNotice('Reconnected', 1000, 'chat-connection-good-reconnect');
	});
client.addListener('join', function (channel, username) {
		if(joinAccounced.indexOf(channel) == -1) {
			if(showConnectionNotices) chatNotice(capitalize(dehash(username)) + ' joined ' + capitalize(dehash(channel)), 1000, -1, 'chat-room-join');
                        responsiveVoice.speak('歡迎來到老K的遊戲間 ' + username, 'Chinese Female');
                        var user;
                        user.username = qs['channel'];
                        user.name = qs['channel'];
                        user['display-name'] = qs['channel'];
                        user.emotes = [];
                        user['message-type'] = null;
                        handleChat(channel, user, '歡迎來到老K的遊戲間 ' + username, self);
			joinAccounced.push(channel);
		}
	});
client.addListener('part', function (channel, username) {
		var index = joinAccounced.indexOf(channel);
		if(index > -1) {
			if(showConnectionNotices) chatNotice(capitalize(dehash(username)) + ' parted ' + capitalize(dehash(channel)), 1000, -1, 'chat-room-part');
			joinAccounced.splice(joinAccounced.indexOf(channel), 1)
		}
	});

client.addListener('crash', function () {
		chatNotice('Crashed', 10000, 4, 'chat-crash');
	});

client.connect();
<|endoftext|>


<commit_before>/**
 * Created by halcwb on 06/06/15.
 */

(function () {
    "use strict";

    var PORT = '3000';

    var http = require('http');
    var server = require("../src/server/Server.js");

    var fs = require('fs');

    var request = function (file) { return http.get('http://localhost:' + PORT + "/" + file); };

    var getHttp = function (url, testResponse, processError) {
        var req = request(url);
        req.on('response', function (response) {
            testResponse(response);
        }).on('error', function (e) {
            // Fail test when error
            console.log('Got error:' + e.message);
            processError(e);
        });
    };

    exports.setUp = function (begin) {
        server.start(PORT);
        begin();
    };

    exports.tearDown = function (done) {
        server.stop(done);
    };

    exports.test_serverStartWithoutPortThrowsException = function (test) {
        server.stop();
        test.throws(function () {
            server.start();
        });
        server.start(PORT);
        test.done();
    };

    exports.test_serverStopBeforeStartThrowsException = function (test) {
        server.stop();
        test.throws(function () {
            server.stop();
        });
        server.start(PORT);
        test.done();
    };

    exports.test_serverReturnsResponse = function (test) {
        // Make a request
        var url = "";
        // Test the response
        var testResponse = function (response) {
            // Check if there is a response
            test.ok(response, 'Expected response received');

            response.on('data', function () {
                test.done();
            });
        };
        // Process the error
        var processError = function (e) {
            // Fail test when error
            console.log('Got error:' + e.message);
            test.fail(e);
            test.done();
        };
        // Run the test
        getHttp(url, testResponse, processError);
    };

    exports.test_serverServesFile = function (test) {
        var testDir = "generated/test";
        var testFile = testDir + "/test.html";
        var testData = "This is data from a file";

        fs.writeFileSync(testFile, testData);
        test.ok(fs.existsSync(testFile), "File [" + testFile + "] should have been created");

        // Make a request
        var testResponse =  function (response) {
            // Check the status code
            test.equals(200, response.statusCode);

            response.setEncoding('utf8');
            response.on('data', function (data) {
                // Check if the response contains hello world
                console.log('got data', data);
                test.equals(testData, data, 'Expected response received');
            });

            response.on('end', function () {
                test.done();
            });

        };

        var processError = function (e) {
            // Fail test when error
            console.log('Got error:' + e.message);

            fs.unlinkSync(testFile);
            test.ok(!fs.existsSync(testFile), "Could not delete test file [" + testFile + "]");

            test.fail(e);
            test.done();
        };

        // Run the test
        getHttp(testFile, testResponse, processError);

    };

    exports.test_serverReturns404ForNonExistingUrl = function (test) {
        // Test the response
        var testResponse = function (response) {
            // Check the status code, should return a 404
            test.equals(404, response.statusCode);
            test.done();

        };

        // Process an error
        var processError =  function (e) {
            // Should not get an error

            test.fail(e);
            test.done();
        };

        // Run the test
        getHttp("foobar", testResponse, processError);
    };

})();

<commit_msg>Further refactored tests<commit_after>/**
 * Created by halcwb on 06/06/15.
 */

(function () {
    "use strict";

    var PORT = '3000';

    var http = require('http');
    var server = require("../src/server/Server.js");

    var fs = require('fs');

    var request = function (file) { return http.get('http://localhost:' + PORT + "/" + file); };

    var getHttp = function (url, testResponse, processError) {
        var req = request(url);
        var data = "";
        req.on('response', function (response) {
            response.setEncoding('utf8');

            response.on('data', function (chunk) {
               data += chunk;
            });

            response.on('end', function () {
                testResponse(response, data);
            });

        }).on('error', function (e) {
            // Fail test when error
            console.log('Got error:' + e.message);
            processError(e);
        });
    };

    exports.setUp = function (begin) {
        server.start(PORT);
        begin();
    };

    exports.tearDown = function (done) {
        server.stop(done);
    };

    exports.test_serverStartWithoutPortThrowsException = function (test) {
        server.stop();
        test.throws(function () {
            server.start();
        });
        server.start(PORT);
        test.done();
    };

    exports.test_serverStopBeforeStartThrowsException = function (test) {
        server.stop();
        test.throws(function () {
            server.stop();
        });
        server.start(PORT);
        test.done();
    };

    exports.test_serverReturnsResponse = function (test) {
        // Make a request
        var url = "";
        // Test the response
        var testResponse = function (response /*, data*/) {
            // Check if there is a response
            test.ok(response, 'Expected response received');
            test.done();
        };
        // Process the error
        var processError = function (e) {
            // Fail test when error
            console.log('Got error:' + e.message);
            test.fail(e);
            test.done();
        };
        // Run the test
        getHttp(url, testResponse, processError);
    };

    exports.test_serverServesFile = function (test) {
        var testDir = "generated/test";
        var testFile = testDir + "/test.html";
        var testData = "This is data from a file";

        fs.writeFileSync(testFile, testData);
        test.ok(fs.existsSync(testFile), "File [" + testFile + "] should have been created");

        // Make a request
        var testResponse =  function (response, data) {
            // Check the status code
            test.equals(200, response.statusCode);
            test.equals(testData, data, 'Expected response received');
            test.done();
        };

        var processError = function (e) {
            // Fail test when error
            console.log('Got error:' + e.message);

            fs.unlinkSync(testFile);
            test.ok(!fs.existsSync(testFile), "Could not delete test file [" + testFile + "]");

            test.fail(e);
            test.done();
        };

        // Run the test
        getHttp(testFile, testResponse, processError);

    };

    exports.test_serverReturns404ForNonExistingUrl = function (test) {
        // Test the response
        var testResponse = function (response /*, data */) {
            // Check the status code, should return a 404
            test.equals(404, response.statusCode);
            test.done();

        };

        // Process an error
        var processError =  function (e) {
            // Should not get an error

            test.fail(e);
            test.done();
        };

        // Run the test
        getHttp("foobar", testResponse, processError);
    };

})();

<|endoftext|>


<commit_before>import request from "@/request";

export default {
  data() {
    return {
      fetched: false
    };
  },
  methods: {
    fetchItem(name, response, arrays, values, childrens) {
      if (!this.fetched) {
        request.get(`${name}/item/${this.$route.params.id}`).then(r => {
          this[name] = this.removeNull(r.data[response]);
          arrays.forEach(e => {
            this[name][e] = this.checkArray(this[name][e]);
          });
          values.forEach(e => {
            this.fetchSelect(name, `${e}s`, e, `${e}_id`);
          });
          childrens.forEach(e => {
            this.fetchChildren(name, e[0], e[1]);
          });
        });
      }
    },
    fetchSelect(root, list, item, value) {
      request.get(`${item}/select`).then(r => {
        this[list] = r.data.SelectItem;
        this.setSelect(root, list, item, value);
      });
    },
    fetchChildren(root, children, name) {
      request.get(`${root}/list/${children}/${this[root].id}`).then(r => {
        this[`${children}s`] = r.data[name];
      });
    },
    setSelect(root, list, item, value) {
      this[root][item] = this[list].find(v => v.id === this[root][value]);
    },
    removeNull(values) {
      Object.keys(values).forEach(key => {
        if (!values[key]) {
          values[key] = "";
        }
      });
      return values;
    },
    postItem(url, data) {
      request
        .post(url, data)
        .then()
        .catch(e => console.log("error post", e));
    },
    cleanFields(values) {
      Object.keys(values).forEach(key => {
        if (
          !Array.isArray(values[key]) &&
          (values[key] === undefined || values[key] === "")
        ) {
          delete values[key];
        }
      });
      return values;
    }
  }
};
<commit_msg>only null convert to empty string<commit_after>import request from "@/request";

export default {
  data() {
    return {
      fetched: false
    };
  },
  methods: {
    fetchItem(name, response, arrays, values, childrens) {
      if (!this.fetched) {
        request.get(`${name}/item/${this.$route.params.id}`).then(r => {
          this[name] = this.removeNull(r.data[response]);
          arrays.forEach(e => {
            this[name][e] = this.checkArray(this[name][e]);
          });
          values.forEach(e => {
            this.fetchSelect(name, `${e}s`, e, `${e}_id`);
          });
          childrens.forEach(e => {
            this.fetchChildren(name, e[0], e[1]);
          });
        });
      }
    },
    fetchSelect(root, list, item, value) {
      request.get(`${item}/select`).then(r => {
        this[list] = r.data.SelectItem;
        this.setSelect(root, list, item, value);
      });
    },
    fetchChildren(root, children, name) {
      request.get(`${root}/list/${children}/${this[root].id}`).then(r => {
        this[`${children}s`] = r.data[name];
      });
    },
    setSelect(root, list, item, value) {
      this[root][item] = this[list].find(v => v.id === this[root][value]);
    },
    removeNull(values) {
      Object.keys(values).forEach(key => {
        if (values[key] === null) {
          values[key] = "";
        }
      });
      return values;
    },
    postItem(url, data) {
      request
        .post(url, data)
        .then()
        .catch(e => console.log("error post", e));
    },
    cleanFields(values) {
      Object.keys(values).forEach(key => {
        if (
          !Array.isArray(values[key]) &&
          (values[key] === undefined || values[key] === "")
        ) {
          delete values[key];
        }
      });
      return values;
    }
  }
};
<|endoftext|>


<commit_before>import request from 'request';
import _ from 'underscore';
import { typeCheck } from 'type-check';
import ApifyError, {
    INVALID_PARAMETER_ERROR_TYPE,
    REQUEST_FAILED_ERROR_TYPE,
    REQUEST_FAILED_ERROR_MESSAGE,
} from './apify_error';

const RATE_LIMIT_EXCEEDED_STATUS_CODE = 429;
const EXP_BACKOFF_MILLIS = 500;
const EXP_BACKOFF_MAX_REPEATS = 8; // 64s

export const REQUEST_PROMISE_OPTIONS = ['promise', 'expBackOffMillis', 'expBackOffMaxRepeats'];

/**
 * Parses a JSON string. If string is not JSON then catches an error and returns empty object.
 */
export const safeJsonParse = (str) => {
    let parsed;

    try {
        parsed = JSON.parse(str);
    } catch (err) {
        parsed = {};
    }

    return parsed;
};

/**
 * Creates an error from API response body and statusCode.
 * If body is object or JSON string in form
 *
 * { type: 'ITEM_NOT_FOUND', message: 'Requested item was not found.' }
 *
 * then uses it's error type or message or both.
 */
export const newApifyErrorFromResponse = (statusCode, body) => {
    let parsedBody = {};

    if (_.isObject(body)) parsedBody = body;
    else if (_.isString(body)) parsedBody = safeJsonParse(body);

    const type = parsedBody.type || REQUEST_FAILED_ERROR_TYPE;
    const message = parsedBody.message || REQUEST_FAILED_ERROR_MESSAGE;

    return new ApifyError(type, message, { statusCode });
};

/**
 * Promised version of request(options) function.
 *
 * If response status code is >= 500 or RATE_LIMIT_EXCEEDED_STATUS_CODE then uses exponential backoff
 * alghorithm to repeat the request.
 *
 * Possible options parameters are:
 * - everything supported by 'request' npm package (mainly 'method', 'url' and 'qs')
 * - resolveWithResponse - to resolve promise with { body, response } instead of just body
 * - expBackOffMillis - initial wait time before next repeat in a case of error
 * - expBackOffMaxRepeats - maximal number of repeats
 */
export const requestPromise = (options, iteration = 0) => {
    const PromisesDependency = options.promise;
    const expBackOffMillis = options.expBackOffMillis || EXP_BACKOFF_MILLIS;
    const expBackOffMaxRepeats = options.expBackOffMaxRepeats || EXP_BACKOFF_MAX_REPEATS;
    const method = _.isString(options.method) ? options.method.toLowerCase() : options.method;

    if (typeof PromisesDependency !== 'function') {
        throw new ApifyError(INVALID_PARAMETER_ERROR_TYPE, '"options.promise" parameter must be provided');
    }

    if (!method) {
        throw new ApifyError(INVALID_PARAMETER_ERROR_TYPE, '"options.method" parameter must be provided');
    }

    if (!request[method]) {
        throw new ApifyError(INVALID_PARAMETER_ERROR_TYPE, '"options.method" is not a valid http request method');
    }

    return new PromisesDependency((resolve, reject) => {
        // We have to use request[method]({ ... }) instead of request({ method, ... })
        // to be able to mock request when unit testing requestPromise().
        request[method](options, (error, response, body) => {
            if (error) return reject(new ApifyError(REQUEST_FAILED_ERROR_TYPE, error.message));

            const statusCode = response.statusCode;

            // If status code is >= 500 or RATE_LIMIT_EXCEEDED_STATUS_CODE then we repeat the request.
            // We use exponential backoff alghorithm with up to `expBackOffMillis` repeats.
            if (statusCode >= 500 || statusCode === RATE_LIMIT_EXCEEDED_STATUS_CODE) {
                if (iteration >= expBackOffMaxRepeats) {
                    const errMessage = `Server request failed with ${iteration + 1} tries.`;
                    reject(new ApifyError(REQUEST_FAILED_ERROR_TYPE, errMessage, { statusCode, iteration }));
                }

                const waitMillis = _.random(expBackOffMillis, expBackOffMillis * 2);
                const repeatCall = () => {
                    const nextCallOptions = Object.assign({}, options, { expBackOffMillis: expBackOffMillis * 2 });

                    requestPromise(nextCallOptions, iteration + 1).then(resolve, reject);
                };

                return setTimeout(repeatCall, waitMillis);
            }

            // For status codes 300-499 except RATE_LIMIT_EXCEEDED_STATUS_CODE we immediately rejects the promise
            // since it's probably caused by invalid url (redirect 3xx) or invalid user input (4xx).
            if (statusCode >= 300) return reject(newApifyErrorFromResponse(statusCode, body));

            if (options.resolveWithResponse) resolve({ body, response });
            else resolve(body);
        });
    });
};

/**
 * Checks that given parameter is of given type and throws ApifyError.
 *
 * See: https://github.com/gkz/type-check
 */
export const checkParamOrThrow = (type, value, name, errorMessage) => {
    if (!errorMessage) errorMessage = `Parameter "${name}" of type ${type} must be provided`;

    if (!typeCheck(type, value)) {
        throw new ApifyError(INVALID_PARAMETER_ERROR_TYPE, errorMessage);
    }
};
<commit_msg>Commenting<commit_after>import request from 'request';
import _ from 'underscore';
import { typeCheck } from 'type-check';
import ApifyError, {
    INVALID_PARAMETER_ERROR_TYPE,
    REQUEST_FAILED_ERROR_TYPE,
    REQUEST_FAILED_ERROR_MESSAGE,
} from './apify_error';

const RATE_LIMIT_EXCEEDED_STATUS_CODE = 429;
const EXP_BACKOFF_MILLIS = 500;
const EXP_BACKOFF_MAX_REPEATS = 8; // 64s

export const REQUEST_PROMISE_OPTIONS = ['promise', 'expBackOffMillis', 'expBackOffMaxRepeats'];

/**
 * Parses a JSON string. If string is not JSON then catches an error and returns empty object.
 */
export const safeJsonParse = (str) => {
    let parsed;

    try {
        parsed = JSON.parse(str);
    } catch (err) {
        parsed = {};
    }

    return parsed;
};

/**
 * Creates an error from API response body and statusCode.
 * If body is object or JSON string in form
 *
 * { type: 'ITEM_NOT_FOUND', message: 'Requested item was not found.' }
 *
 * then uses it's error type or message or both.
 */
export const newApifyErrorFromResponse = (statusCode, body) => {
    let parsedBody = {};

    if (_.isObject(body)) parsedBody = body;
    else if (_.isString(body)) parsedBody = safeJsonParse(body);

    const type = parsedBody.type || REQUEST_FAILED_ERROR_TYPE;
    const message = parsedBody.message || REQUEST_FAILED_ERROR_MESSAGE;

    return new ApifyError(type, message, { statusCode });
};

/**
 * Promised version of request(options) function.
 *
 * If response status code is >= 500 or RATE_LIMIT_EXCEEDED_STATUS_CODE then uses exponential backoff
 * alghorithm to repeat the request.
 *
 * Possible options parameters are:
 * - everything supported by 'request' npm package (mainly 'method', 'url' and 'qs')
 * - resolveWithResponse - to resolve promise with { body, response } instead of just body
 * - expBackOffMillis - initial wait time before next repeat in a case of error
 * - expBackOffMaxRepeats - maximal number of repeats
 */
export const requestPromise = (options, iteration = 0) => {
    const PromisesDependency = options.promise;
    const expBackOffMillis = options.expBackOffMillis || EXP_BACKOFF_MILLIS;
    const expBackOffMaxRepeats = options.expBackOffMaxRepeats || EXP_BACKOFF_MAX_REPEATS;
    const method = _.isString(options.method) ? options.method.toLowerCase() : options.method;

    if (typeof PromisesDependency !== 'function') {
        throw new ApifyError(INVALID_PARAMETER_ERROR_TYPE, '"options.promise" parameter must be provided');
    }

    if (!method) {
        throw new ApifyError(INVALID_PARAMETER_ERROR_TYPE, '"options.method" parameter must be provided');
    }

    if (!request[method]) {
        throw new ApifyError(INVALID_PARAMETER_ERROR_TYPE, '"options.method" is not a valid http request method');
    }

    return new PromisesDependency((resolve, reject) => {
        // We have to use request[method]({ ... }) instead of request({ method, ... })
        // to be able to mock request when unit testing requestPromise().
        request[method](options, (error, response, body) => {
            if (error) return reject(new ApifyError(REQUEST_FAILED_ERROR_TYPE, error.message));

            const statusCode = response.statusCode;

            // If status code is >= 500 or RATE_LIMIT_EXCEEDED_STATUS_CODE then we repeat the request.
            // We use exponential backoff alghorithm with up to `expBackOffMillis` repeats.
            if (statusCode >= 500 || statusCode === RATE_LIMIT_EXCEEDED_STATUS_CODE) {
                if (iteration >= expBackOffMaxRepeats) {
                    const errMessage = `Server request failed with ${iteration + 1} tries.`;
                    reject(new ApifyError(REQUEST_FAILED_ERROR_TYPE, errMessage, { statusCode, iteration }));
                }

                const waitMillis = _.random(expBackOffMillis, expBackOffMillis * 2);
                const repeatCall = () => {
                    const nextCallOptions = Object.assign({}, options, { expBackOffMillis: expBackOffMillis * 2 });

                    requestPromise(nextCallOptions, iteration + 1).then(resolve, reject);
                };

                return setTimeout(repeatCall, waitMillis);
            }

            // For status codes 300-499 except RATE_LIMIT_EXCEEDED_STATUS_CODE we immediately rejects the promise
            // since it's probably caused by invalid url (redirect 3xx) or invalid user input (4xx).
            if (statusCode >= 300) return reject(newApifyErrorFromResponse(statusCode, body));

            if (options.resolveWithResponse) resolve({ body, response });
            else resolve(body);
        });
    });
};

/**
 * Checks that given parameter is of given type and throws ApifyError.
 * If errorMessage is not provided then error message is created from name and type of param.
 *
 * @param type         string - "String", "Number", ... (see ee: https://github.com/gkz/type-check)
 * @param value        string - user entered value of that parameter
 * @param name         string - parameter name (crawlerId for options.crawlerId)
 * @param errorMessage string - optional error message
 */
export const checkParamOrThrow = (type, value, name, errorMessage) => {
    if (!errorMessage) errorMessage = `Parameter "${name}" of type ${type} must be provided`;

    if (!typeCheck(type, value)) {
        throw new ApifyError(INVALID_PARAMETER_ERROR_TYPE, errorMessage);
    }
};
<|endoftext|>


<commit_before>import React from 'react';
import Checkbox from 'material-ui/Checkbox';
import {connect} from 'react-redux';
import Section from './section';
import * as ConfigurationActions from '../actions/configuration';

const Configuration = ({overrideProxy, replaceHttps, dispatch, disabled, useDelays}) => {

    function toggleOverrideProxy() {
        dispatch(ConfigurationActions.toggleOverrideProxy());
    }

    function toggleReplaceHttps() {
        dispatch(ConfigurationActions.toggleReplaceHttps());
    }

    function toggleUseDelays() {
        dispatch(ConfigurationActions.toggleUseDelays());
    }

    return (

            <Checkbox disabled={disabled} label="Override Proxy" checked={overrideProxy} onCheck={toggleOverrideProxy}/>
            <Checkbox disabled={disabled} label="Replace HTTPS in data and URLs" checked={replaceHttps} onCheck={toggleReplaceHttps}/>
            <Checkbox disabled={disabled} label="Replay delays" checked={useDelays} onCheck={toggleUseDelays} />

    );
};

const mapStateToProps = (state) => {
    return {
        overrideProxy: state.configuration.get('overrideProxy'),
        replaceHttps: state.configuration.get('replaceHttps'),
        useDelays: state.configuration.get('useDelays'),
        disabled: state.configuration.get('running')
    };
};

export default connect(mapStateToProps)(Configuration);
<commit_msg>change strings<commit_after>import React from 'react';
import Checkbox from 'material-ui/Checkbox';
import {connect} from 'react-redux';
import Section from './section';
import * as ConfigurationActions from '../actions/configuration';

const Configuration = ({overrideProxy, replaceHttps, dispatch, disabled, useDelays}) => {

    function toggleOverrideProxy() {
        dispatch(ConfigurationActions.toggleOverrideProxy());
    }

    function toggleReplaceHttps() {
        dispatch(ConfigurationActions.toggleReplaceHttps());
    }

    function toggleUseDelays() {
        dispatch(ConfigurationActions.toggleUseDelays());
    }

    return (

            <Checkbox disabled={disabled} label="Automatically set Chrome proxy configuration" checked={overrideProxy} onCheck={toggleOverrideProxy}/>
            <Checkbox disabled={disabled} label="Replace HTTPS in data and URLs" checked={replaceHttps} onCheck={toggleReplaceHttps}/>
            <Checkbox disabled={disabled} label="Respond with logged delays" checked={useDelays} onCheck={toggleUseDelays} />

    );
};

const mapStateToProps = (state) => {
    return {
        overrideProxy: state.configuration.get('overrideProxy'),
        replaceHttps: state.configuration.get('replaceHttps'),
        useDelays: state.configuration.get('useDelays'),
        disabled: state.configuration.get('running')
    };
};

export default connect(mapStateToProps)(Configuration);
<|endoftext|>


<commit_before>'use strict';

var io = require('socket.io');
var moment = require('moment');
var util = require('util');

var models = require('./models');
var enet = require('./eventnet');

var SwiftCODESockets = function() {
    var self = this;

    self.listen = function(server) {
        self.io = server;
        self.io.set('log level', 1);

        self.setupListeners();
    };

    /**
     * Setup socket listeners
     */
    self.setupListeners = function() {
        var lobbyCount = 0;

        var lobbySockets = self.io.of('/lobby')
        .on('connection', function(socket) {
            socket.on('games:fetch', function(data) {
                models.Game.find({ isViewable: true }, null, { sort: { isJoinable: -1 } }, function(err, docs) {
                    socket.emit('games:fetch:res', docs);
                });
            });

            socket.on('games:join', function(data) {
                models.User.findById(data.player, function(err, user) {
                    if (err) {
                        util.log(err);
                        util.log('games:join error'); return;
                    }
                    if (user) {
                        user.prepareIngameAction('join', {
                            game: data.game
                        }, function(err) {
                            if (err) {
                                util.log(err);
                            }
                            socket.emit('games:join:res', { success: !err });
                        });
                    }
                });
            });

            socket.on('games:createnew', function(data) {
                models.User.findById(data.player, function(err, user) {
                    if (err) {
                        util.log(err);
                        util.log('games:join error'); return;
                    }
                    if (user) {
                        user.prepareIngameAction('createnew', {
                            lang: data.key,
                            isSinglePlayer: data.gameType === 'single'
                        }, function(err) {
                            if (err) {
                                util.log(err);
                            }
                            socket.emit('games:createnew:res', { success: !err });
                        });
                    }
                });
            });

            socket.on('disconnect', function() {
                lobbyCount--;
                lobbySockets.emit('lobbycount', { count: lobbyCount });
            });

            lobbyCount++;
            lobbySockets.emit('lobbycount', { count: lobbyCount });
        });

        var gameSockets = self.io.of('/game')
        .on('connection', function(socket) {
            socket.on('ingame:ready', function(data) {
                socket.set('player', data.player, function() {
                    models.User.findById(data.player, function(err, user) {
                        if (err) {
                            util.log(err);
                            util.log('ingame:ready error');
                            return socket.emit('ingame:ready:res', {
                                success: false,
                                err: err
                            });
                        }
                        if (user) {
                            user.performIngameAction(function(err, success, game) {
                                if (!success) {
                                    return socket.emit('ingame:ready:res', {
                                        success: false,
                                        err: err
                                    });
                                }

                                socket.set('game', game.id);
                                models.Exercise.findById(game.exercise, 'code projectName typeableCode typeables', function(err, exercise) {
                                    if (exercise) {
                                        // Join a room and broadcast join
                                        socket.join('game-' + game.id);

                                        socket.emit('ingame:ready:res', {
                                            success: true,
                                            game: game,
                                            timeLeft: game.starting ? moment().diff(game.startTime) : undefined,
                                            exercise: exercise,
                                            nonTypeables: models.NON_TYPEABLE_CLASSES
                                        });
                                    } else {
                                        util.log('exercise not found');
                                        socket.emit('ingame:ready:res', {
                                            success: false,
                                            err: 'exercise not found'
                                        });
                                    }
                                });
                            });
                        }
                    });
                });
            });

            socket.on('ingame:complete', function(data) {
                socket.get('player', function(err, player) {
                    if (err) {
                        util.log(err);
                        return;
                    }
                    socket.get('game', function(err, game) {
                        if (err) {
                            util.log(err);
                            return;
                        }

                        var stats = new models.Stats({
                            player: player,
                            game: game,
                            time: data.time,
                            keystrokes: data.keystrokes,
                            mistakes: data.mistakes
                        });

                        stats.updateStatistics(function(err, stats, user, game) {
                            if (err) {
                                util.log(err);
                                return;
                            }
                            socket.emit('ingame:complete:res', {
                                stats: stats,
                                game: game
                            });
                        });
                    });
                });
            });

            socket.on('ingame:advancecursor', function(data) {
                socket.broadcast.to('game-' + data.game).emit('ingame:advancecursor', {
                    player: data.player,
                    game: data.game
                });
            });

            socket.on('ingame:retreatcursor', function(data) {
                socket.broadcast.to('game-' + data.game).emit('ingame:retreatcursor', {
                    player: data.player,
                    game: data.game
                });
            });

            socket.on('report:highlightingerror', function(data) {
                models.Exercise.findById(data.exercise, function(err, exercise) {
                    if (exercise) {
                        exercise.highlightingErrorReports++;
                        exercise.save();
                    }
                });
            });

            socket.on('disconnect', function() {
                socket.get('game', function(err, game) {
                    if (err) {
                        util.log(err);
                        return;
                    }
                    socket.get('player', function(err, player) {
                        if (err) {
                            util.log(err);
                            return;
                        }
                        models.User.findById(player, function(err, user) {
                            if (err) {
                                util.log(err);
                                util.log('ingame:exit error'); return;
                            }
                            if (user) {
                                user.quitCurrentGame(function(err, game) {
                                    if (err) {
                                        util.log(err);
                                        util.log('ingame:exit error'); return;
                                    }
                                });
                            }
                        });
                    });
                });
            });
        });

        enet.on('games:new', function(game) {
            if (game.isViewable) {
                lobbySockets.emit('games:new', game);
            }
        });

        enet.on('games:update', function(game) {
            if (game.isViewable) {
                lobbySockets.emit('games:update', game);
            }
            gameSockets.in('game-' + game.id).emit('ingame:update', {
                game: game,
                timeLeft: moment().diff(game.startTime)
            });
        });

        enet.on('games:remove', function(game) {
            // By definition, a game must be removed when it isn't viewable
            lobbySockets.emit('games:remove', game);
        });

    };
};

module.exports = SwiftCODESockets;
<commit_msg>Fix socket.io.<commit_after>'use strict';

var io = require('socket.io');
var moment = require('moment');
var util = require('util');

var models = require('./models');
var enet = require('./eventnet');

var SwiftCODESockets = function() {
    var self = this;

    self.listen = function(server) {
        self.io = server;
        self.io.set('log level', 1);

        self.setupListeners();
    };

    /**
     * Setup socket listeners
     */
    self.setupListeners = function() {
        var lobbyCount = 0;

        var lobbySockets = self.io.of('/lobby')
        .on('connection', function(socket) {
            socket.on('games:fetch', function(data) {
                models.Game.find({ isViewable: true }, null, { sort: { isJoinable: -1 } }, function(err, docs) {
                    socket.emit('games:fetch:res', docs);
                });
            });

            socket.on('games:join', function(data) {
                models.User.findById(data.player, function(err, user) {
                    if (err) {
                        util.log(err);
                        util.log('games:join error'); return;
                    }
                    if (user) {
                        user.prepareIngameAction('join', {
                            game: data.game
                        }, function(err) {
                            if (err) {
                                util.log(err);
                            }
                            socket.emit('games:join:res', { success: !err });
                        });
                    }
                });
            });

            socket.on('games:createnew', function(data) {
                models.User.findById(data.player, function(err, user) {
                    if (err) {
                        util.log(err);
                        util.log('games:join error'); return;
                    }
                    if (user) {
                        user.prepareIngameAction('createnew', {
                            lang: data.key,
                            isSinglePlayer: data.gameType === 'single'
                        }, function(err) {
                            if (err) {
                                util.log(err);
                            }
                            socket.emit('games:createnew:res', { success: !err });
                        });
                    }
                });
            });

            socket.on('disconnect', function() {
                lobbyCount--;
                lobbySockets.emit('lobbycount', { count: lobbyCount });
            });

            lobbyCount++;
            lobbySockets.emit('lobbycount', { count: lobbyCount });
        });

        var gameSockets = self.io.of('/game')
        .on('connection', function(socket) {
            socket.on('ingame:ready', function(data) {
                socket.player = data.player;
                models.User.findById(data.player, function(err, user) {
                    if (err) {
                        util.log(err);
                        util.log('ingame:ready error');
                        return socket.emit('ingame:ready:res', {
                            success: false,
                            err: err
                        });
                    }
                    if (user) {
                        user.performIngameAction(function(err, success, game) {
                            if (!success) {
                                return socket.emit('ingame:ready:res', {
                                    success: false,
                                    err: err
                                });
                            }

                            socket.game = game.id;
                            models.Exercise.findById(game.exercise, 'code projectName typeableCode typeables', function(err, exercise) {
                                if (exercise) {
                                    // Join a room and broadcast join
                                    socket.join('game-' + game.id);

                                    socket.emit('ingame:ready:res', {
                                        success: true,
                                        game: game,
                                        timeLeft: game.starting ? moment().diff(game.startTime) : undefined,
                                        exercise: exercise,
                                        nonTypeables: models.NON_TYPEABLE_CLASSES
                                    });
                                } else {
                                    util.log('exercise not found');
                                    socket.emit('ingame:ready:res', {
                                        success: false,
                                        err: 'exercise not found'
                                    });
                                }
                            });
                        });
                    }
                });
            });

            socket.on('ingame:complete', function(data) {
                if (socket.player == undefined) {
                    util.log('could not find player');
                    return;
                }
                if (socket.game == undefined) {
                    util.log('could not find game');
                    return;
                }

                var stats = new models.Stats({
                    player: socket.player,
                    game: socket.game,
                    time: data.time,
                    keystrokes: data.keystrokes,
                    mistakes: data.mistakes
                });

                stats.updateStatistics(function(err, stats, user, game) {
                    if (err) {
                        util.log(err);
                        return;
                    }
                    socket.emit('ingame:complete:res', {
                        stats: stats,
                        game: game
                    });
                });
            });

            socket.on('ingame:advancecursor', function(data) {
                socket.broadcast.to('game-' + data.game).emit('ingame:advancecursor', {
                    player: data.player,
                    game: data.game
                });
            });

            socket.on('ingame:retreatcursor', function(data) {
                socket.broadcast.to('game-' + data.game).emit('ingame:retreatcursor', {
                    player: data.player,
                    game: data.game
                });
            });

            socket.on('report:highlightingerror', function(data) {
                models.Exercise.findById(data.exercise, function(err, exercise) {
                    if (exercise) {
                        exercise.highlightingErrorReports++;
                        exercise.save();
                    }
                });
            });

            socket.on('disconnect', function() {
                if (socket.player == undefined) {
                    util.log('could not find player');
                    return;
                }
                if (socket.game == undefined) {
                    util.log('could not find game');
                    return;
                }
                models.User.findById(socket.player, function(err, user) {
                    if (err) {
                        util.log(err);
                        util.log('ingame:exit error'); return;
                    }
                    if (user) {
                        user.quitCurrentGame(function(err, game) {
                            if (err) {
                                util.log(err);
                                util.log('ingame:exit error'); return;
                            }
                        });
                    }
                });
            });
        });

        enet.on('games:new', function(game) {
            if (game.isViewable) {
                lobbySockets.emit('games:new', game);
            }
        });

        enet.on('games:update', function(game) {
            if (game.isViewable) {
                lobbySockets.emit('games:update', game);
            }
            gameSockets.in('game-' + game.id).emit('ingame:update', {
                game: game,
                timeLeft: moment().diff(game.startTime)
            });
        });

        enet.on('games:remove', function(game) {
            // By definition, a game must be removed when it isn't viewable
            lobbySockets.emit('games:remove', game);
        });

    };
};

module.exports = SwiftCODESockets;
<|endoftext|>


<commit_before>var OP_CODES = [
  new Buffer([0x00]), // wild-card to be defined
  new Buffer([0x01]), // All Hashes in OP_RETURN - Pay-to-PubkeyHash
  new Buffer([0x02]), // SHA2 in Pay-to-Script-Hash multi-sig output (1 out of 2)
  new Buffer([0x03]), // All Hashes in Pay-to-Script-Hash multi-sig outputs (1 out of 3)
  new Buffer([0x04]), // Low security issue no SHA2 for torrent data. SHA1 is always inside OP_RETURN in this case.
  new Buffer([0x05]), // No rules, no torrent, no meta data ( no one may add rules in the future, anyone can add metadata )
  new Buffer([0x06])  // No meta data (anyone can add rules and/or metadata  in the future)
]

var sffc = require('sffc-encoder')
var issueFlagsCodex = require('./issueFlagsEncoder.js')
var paymentCodex = require('cc-payment-encoder')

var consumer = function (buff) {
  var curr = 0
  return function consume (len) {
    return buff.slice(curr, curr += len)
  }
}

var padLeadingZeros = function (hex, byteSize) {
  return (hex.length === byteSize * 2) ? hex : padLeadingZeros('0' + hex, byteSize)
}

module.exports = {
  encode: function (data, byteSize) {
    if (!data) throw new Error('Missing Data')
    if (typeof data.amountOfUnits === 'undefined') throw new Error('Missing amountOfUnits')
    if (typeof data.lockStatus === 'undefined') throw new Error('Missing lockStatus')
    if (typeof data.divisibility === 'undefined') throw new Error('Missing divisibility')
    if (typeof data.protocol === 'undefined') throw new Error('Missing protocol')
    if (typeof data.version === 'undefined') throw new Error('Missing version')
    var opcode
    var hash = new Buffer(0)
    var protocol = new Buffer(padLeadingZeros(data.protocol.toString(16), 2), 'hex')
    var version = new Buffer([data.version])
    var issueHeader = Buffer.concat([protocol, version])
    var amountOfUnits = sffc.encode(data.amountOfUnits)
    var payments = new Buffer(0)
    if (data.payments) payments = paymentCodex.encodeBulk(data.payments)
    var issueFlagsByte = issueFlagsCodex.encode({divisibility: data.divisibility, lockStatus: data.lockStatus})
    var issueTail = Buffer.concat([amountOfUnits, payments, issueFlagsByte])
    var issueByteSize = issueHeader.length + issueTail.length + 1

    if (issueByteSize > byteSize) throw new Error('Data code is bigger then the allowed byte size')
    if (!data.sha2) {
      if (data.torrentHash) {
        if (issueByteSize + data.torrentHash.length > byteSize) throw new Error('Can\'t fit Torrent Hash in byte size')
        return {codeBuffer: Buffer.concat([issueHeader, OP_CODES[4], data.torrentHash, issueTail]), leftover: []}
      }
      opcode = data.noRules ? OP_CODES[5] : OP_CODES[6]
      return {codeBuffer: Buffer.concat([issueHeader, opcode, hash, issueTail]), leftover: []}
    }
    if (!data.torrentHash) throw new Error('Torrent Hash is missing')
    var leftover = [data.torrentHash, data.sha2]

    opcode = OP_CODES[3]
    issueByteSize = issueByteSize + data.torrentHash.length

    if (issueByteSize <= byteSize) {
      hash = Buffer.concat([hash, leftover.shift()])
      opcode = OP_CODES[2]
      issueByteSize = issueByteSize + data.sha2.length
    }
    if (issueByteSize <= byteSize) {
      hash = Buffer.concat([hash, leftover.shift()])
      opcode = OP_CODES[1]
    }

    return {codeBuffer: Buffer.concat([issueHeader, opcode, hash, issueTail]), leftover: leftover}
  },

  decode: function (op_code_buffer) {
    var data = {}
    if (!Buffer.isBuffer(op_code_buffer)) {
      op_code_buffer = new Buffer(op_code_buffer, 'hex')
    }
    var byteSize = op_code_buffer.length
    var lastByte = op_code_buffer.slice(-1)
    var issueTail = issueFlagsCodex.decode(consumer(lastByte))
    data.divisibility = issueTail.divisibility
    data.lockStatus = issueTail.lockStatus
    var consume = consumer(op_code_buffer.slice(0, byteSize - 1))
    data.protocol = parseInt(consume(2).toString('hex'), 16)
    data.version = parseInt(consume(1).toString('hex'), 16)
    data.multiSig = []
    var opcode = consume(1)
    if (opcode[0] === OP_CODES[1][0]) {
      data.torrentHash = consume(20)
      data.sha2 = consume(32)
    } else if (opcode[0] === OP_CODES[2][0]) {
      data.torrentHash = consume(20)
      data.multiSig.push({'index': 1, 'hashType': 'sha2'})
    } else if (opcode[0] === OP_CODES[3][0]) {
      data.multiSig.push({'index': 1, 'hashType': 'sha2'})
      data.multiSig.push({'index': 2, 'hashType': 'torrentHash'})
    } else if (opcode[0] === OP_CODES[4][0]) {
    } else if (opcode[0] === OP_CODES[5][0]) {
      data.noRules = true
    } else if (opcode[0] === OP_CODES[6][0]) {
      data.noRules = false
    } else {
      throw new Error('Unrecognized Code')
    }

    data.amountOfUnits = sffc.decode(consume)
    data.payments = paymentCodex.decodeBulk(consume)

    return data
  }
}
<commit_msg>change amountOfUnits to amount<commit_after>var OP_CODES = [
  new Buffer([0x00]), // wild-card to be defined
  new Buffer([0x01]), // All Hashes in OP_RETURN - Pay-to-PubkeyHash
  new Buffer([0x02]), // SHA2 in Pay-to-Script-Hash multi-sig output (1 out of 2)
  new Buffer([0x03]), // All Hashes in Pay-to-Script-Hash multi-sig outputs (1 out of 3)
  new Buffer([0x04]), // Low security issue no SHA2 for torrent data. SHA1 is always inside OP_RETURN in this case.
  new Buffer([0x05]), // No rules, no torrent, no meta data ( no one may add rules in the future, anyone can add metadata )
  new Buffer([0x06])  // No meta data (anyone can add rules and/or metadata  in the future)
]

var sffc = require('sffc-encoder')
var issueFlagsCodex = require('./issueFlagsEncoder.js')
var paymentCodex = require('cc-payment-encoder')

var consumer = function (buff) {
  var curr = 0
  return function consume (len) {
    return buff.slice(curr, curr += len)
  }
}

var padLeadingZeros = function (hex, byteSize) {
  return (hex.length === byteSize * 2) ? hex : padLeadingZeros('0' + hex, byteSize)
}

module.exports = {
  encode: function (data, byteSize) {
    if (!data) throw new Error('Missing Data')
    if (typeof data.amount === 'undefined') throw new Error('Missing amount')
    if (typeof data.lockStatus === 'undefined') throw new Error('Missing lockStatus')
    if (typeof data.divisibility === 'undefined') throw new Error('Missing divisibility')
    if (typeof data.protocol === 'undefined') throw new Error('Missing protocol')
    if (typeof data.version === 'undefined') throw new Error('Missing version')
    var opcode
    var hash = new Buffer(0)
    var protocol = new Buffer(padLeadingZeros(data.protocol.toString(16), 2), 'hex')
    var version = new Buffer([data.version])
    var issueHeader = Buffer.concat([protocol, version])
    var amount = sffc.encode(data.amount)
    var payments = new Buffer(0)
    if (data.payments) payments = paymentCodex.encodeBulk(data.payments)
    var issueFlagsByte = issueFlagsCodex.encode({divisibility: data.divisibility, lockStatus: data.lockStatus})
    var issueTail = Buffer.concat([amount, payments, issueFlagsByte])
    var issueByteSize = issueHeader.length + issueTail.length + 1

    if (issueByteSize > byteSize) throw new Error('Data code is bigger then the allowed byte size')
    if (!data.sha2) {
      if (data.torrentHash) {
        if (issueByteSize + data.torrentHash.length > byteSize) throw new Error('Can\'t fit Torrent Hash in byte size')
        return {codeBuffer: Buffer.concat([issueHeader, OP_CODES[4], data.torrentHash, issueTail]), leftover: []}
      }
      opcode = data.noRules ? OP_CODES[5] : OP_CODES[6]
      return {codeBuffer: Buffer.concat([issueHeader, opcode, hash, issueTail]), leftover: []}
    }
    if (!data.torrentHash) throw new Error('Torrent Hash is missing')
    var leftover = [data.torrentHash, data.sha2]

    opcode = OP_CODES[3]
    issueByteSize = issueByteSize + data.torrentHash.length

    if (issueByteSize <= byteSize) {
      hash = Buffer.concat([hash, leftover.shift()])
      opcode = OP_CODES[2]
      issueByteSize = issueByteSize + data.sha2.length
    }
    if (issueByteSize <= byteSize) {
      hash = Buffer.concat([hash, leftover.shift()])
      opcode = OP_CODES[1]
    }

    return {codeBuffer: Buffer.concat([issueHeader, opcode, hash, issueTail]), leftover: leftover}
  },

  decode: function (op_code_buffer) {
    var data = {}
    if (!Buffer.isBuffer(op_code_buffer)) {
      op_code_buffer = new Buffer(op_code_buffer, 'hex')
    }
    var byteSize = op_code_buffer.length
    var lastByte = op_code_buffer.slice(-1)
    var issueTail = issueFlagsCodex.decode(consumer(lastByte))
    data.divisibility = issueTail.divisibility
    data.lockStatus = issueTail.lockStatus
    var consume = consumer(op_code_buffer.slice(0, byteSize - 1))
    data.protocol = parseInt(consume(2).toString('hex'), 16)
    data.version = parseInt(consume(1).toString('hex'), 16)
    data.multiSig = []
    var opcode = consume(1)
    if (opcode[0] === OP_CODES[1][0]) {
      data.torrentHash = consume(20)
      data.sha2 = consume(32)
    } else if (opcode[0] === OP_CODES[2][0]) {
      data.torrentHash = consume(20)
      data.multiSig.push({'index': 1, 'hashType': 'sha2'})
    } else if (opcode[0] === OP_CODES[3][0]) {
      data.multiSig.push({'index': 1, 'hashType': 'sha2'})
      data.multiSig.push({'index': 2, 'hashType': 'torrentHash'})
    } else if (opcode[0] === OP_CODES[4][0]) {
    } else if (opcode[0] === OP_CODES[5][0]) {
      data.noRules = true
    } else if (opcode[0] === OP_CODES[6][0]) {
      data.noRules = false
    } else {
      throw new Error('Unrecognized Code')
    }

    data.amount = sffc.decode(consume)
    data.payments = paymentCodex.decodeBulk(consume)

    return data
  }
}
<|endoftext|>


<commit_before>require([
    'app/project/FeatureDetails',

    'dojo/Deferred',
    'dojo/dom-class',
    'dojo/dom-construct',

    'stubmodule'
], function (
    WidgetUnderTest,

    Deferred,
    domClass,
    domConstruct,

    stubModule
) {
    describe('app/project/FeatureDetails', function () {
        var widget;
        var destroy = function (widget) {
            widget.destroyRecursive();
            widget = null;
        };

        beforeEach(function () {
            widget = new WidgetUnderTest({
                title: 'Title',
                projectId: 1234,
                status: 'Completed',
                description: 'asdf',
                acres: 123,
                streamMiles: 34,
                leadAgency: 'asdf',
                region: 'asdf',
                projectManagerName: 'Scott Davis'
            }, domConstruct.create('div', null, document.body));
            widget.startup();
        });

        afterEach(function () {
            if (widget) {
                destroy(widget);
            }
        });

        describe('Sanity', function () {
            it('should create a FeatureDetails', function () {
                expect(widget).toEqual(jasmine.any(WidgetUnderTest));
            });
        });
        describe('onFeatureSelected', function () {
            beforeEach(function () {
                if (widget) {
                    destroy(widget);
                }
            });

            it('places template in contents', function (done) {
                stubModule('app/project/FeatureDetails', {
                    'dojo/request/xhr': {
                        get: jasmine.createSpy('xhr').and.returnValue({
                            response: new Deferred().promise
                        })
                    },
                    'app/router': {
                        getProjectId: function () {
                            return 999;
                        }
                    }
                }).then(function (StubbedModule) {
                    widget = new StubbedModule({
                        title: 'Title',
                        projectId: 1234,
                        status: 'Completed',
                        description: 'asdf',
                        acres: 123,
                        streamMiles: 34,
                        leadAgency: 'asdf',
                        region: 'asdf',
                        projectManagerName: 'Scott Davis'
                    }, domConstruct.create('div', null, document.body));
                    widget.startup();

                    widget.onFeatureSelected({});

                    expect(widget.featureTabContents.innerHTML.length).toBeGreaterThan(5);
                    done();
                });
            });
            it('shows the feature tab', function (done) {
                stubModule('app/project/FeatureDetails', {
                    'dojo/request/xhr': {
                        get: jasmine.createSpy('xhr').and.returnValue({
                            response: new Deferred().promise
                        })
                    },
                    'app/router': {
                        getProjectId: function () {
                            return 999;
                        }
                    }
                }).then(function (StubbedModule) {
                    widget = new StubbedModule({
                        title: 'Title',
                        projectId: 1234,
                        status: 'Completed',
                        description: 'asdf',
                        acres: 123,
                        streamMiles: 34,
                        leadAgency: 'asdf',
                        region: 'asdf',
                        projectManagerName: 'Scott Davis'
                    }, domConstruct.create('div', null, document.body));
                    widget.startup();

                    expect(domClass.contains(widget.featureTabContents.parentElement, 'hidden')).toBe(true);

                    widget.onFeatureSelected({});

                    expect(domClass.contains(widget.featureTabContents, 'hidden')).toBe(false);
                    done();
                });
            });
            it('clears out any previous data', function (done) {
                stubModule('app/project/FeatureDetails', {
                    'dojo/request/xhr': {
                        get: jasmine.createSpy('xhr').and.returnValue({
                            response: new Deferred().promise
                        })
                    },
                    'app/router': {
                        getProjectId: function () {
                            return 999;
                        }
                    }
                }).then(function (StubbedModule) {
                    widget = new StubbedModule({
                        title: 'Title',
                        projectId: 1234,
                        status: 'Completed',
                        description: 'asdf',
                        acres: 123,
                        streamMiles: 34,
                        leadAgency: 'asdf',
                        region: 'asdf',
                        projectManagerName: 'Scott Davis'
                    }, domConstruct.create('div', null, document.body));
                    widget.startup();

                    widget.featureTabContents.innerHTML = 'test';

                    widget.onFeatureSelected({});

                    expect(widget.featureTabContents.innerHTML).not.toContain('test');
                    done();
                });
            });
        });
    });
});
<commit_msg>refactor tests<commit_after>require([
    'app/project/FeatureDetails',

    'dojo/Deferred',
    'dojo/dom-class',
    'dojo/dom-construct',

    'stubmodule'
], function (
    WidgetUnderTest,

    Deferred,
    domClass,
    domConstruct,

    stubModule
) {
    describe('app/project/FeatureDetails', function () {
        var widget;
        var destroy = function (widget) {
            widget.destroyRecursive();
            widget = null;
        };

        beforeEach(function () {
            widget = new WidgetUnderTest({
                title: 'Title',
                projectId: 1234,
                status: 'Completed',
                description: 'asdf',
                acres: 123,
                streamMiles: 34,
                leadAgency: 'asdf',
                region: 'asdf',
                projectManagerName: 'Scott Davis'
            }, domConstruct.create('div', null, document.body));
            widget.startup();
        });

        afterEach(function () {
            if (widget) {
                destroy(widget);
            }
        });

        describe('Sanity', function () {
            it('should create a FeatureDetails', function () {
                expect(widget).toEqual(jasmine.any(WidgetUnderTest));
            });
        });
        describe('onFeatureSelected', function () {
            beforeEach(function (done) {
                stubModule('app/project/FeatureDetails', {
                    'dojo/request/xhr': {
                        get: jasmine.createSpy('xhr').and.returnValue({
                            response: new Deferred().promise
                        })
                    },
                    'app/router': {
                        getProjectId: function () {
                            return 999;
                        }
                    }
                }).then(function (StubbedModule) {
                    if (widget) {
                        destroy(widget);
                    }

                    widget = new StubbedModule({
                        title: 'Title',
                        projectId: 1234,
                        status: 'Completed',
                        description: 'asdf',
                        acres: 123,
                        streamMiles: 34,
                        leadAgency: 'asdf',
                        region: 'asdf',
                        projectManagerName: 'Scott Davis'
                    }, domConstruct.create('div', null, document.body));
                    widget.startup();
                    done();
                });
            });

            afterEach(function () {
                if (widget) {
                    destroy(widget);
                }
            });

            it('places template in contents', function () {
                widget.onFeatureSelected({});

                expect(widget.featureTabContents.innerHTML.length).toBeGreaterThan(5);
            });
            it('shows the feature tab', function () {
                expect(domClass.contains(widget.featureTabContents.parentElement, 'hidden')).toBe(true);

                widget.onFeatureSelected({});

                expect(domClass.contains(widget.featureTabContents, 'hidden')).toBe(false);
            });
            it('clears out any previous data', function () {
                widget.featureTabContents.innerHTML = 'test';

                widget.onFeatureSelected({});

                expect(widget.featureTabContents.innerHTML).not.toContain('test');
            });
        });
    });
});
<|endoftext|>


<commit_before>$(document).ready(function() {
    // load filename from url
    var urlFilename = getURLParameter('mapillary');
    if (urlFilename) {
        $('#mapillary').val(urlFilename);
        processFilename();  // lookup directly if filename
    }
    // responsive buttons
    $('.btn').hover(
        function() {
            if (!$(this).prop("disabled")) {
                $(this).addClass('active');
            }
        },
        function() {
            $(this).removeClass('active');
        }
    );
    // on enter or clicking button, look up info on Mapillary
    $('#mapillary').keypress(function(e) {
        if(e.which == 13) {
            processFilename();
        }
    });
    $('#button').click(function() {
        processFilename();
    });

});

// Validate filename and request info from Commons
function processFilename() {
    // reset later fields
    $('#reflect').empty();
    $('#button').prop('disabled', true);
    $('#submit_button').addClass('hidden');
    $('#thumbDiv').addClass('hidden');

    // test filename
    var run = true;
    var input = $('#mapillary').val();
    if (input === ''){
        $('#mapillary').addClass('highlighted');
        run = false;
    }
    else if ( input.match(/\/\/www.mapillary.com\/map\/im\//gi) ) {
        input = decodeURIComponent(input.split('/im/')[1]);
        $('#mapillary').val(input);
    }
    // run if mapillary_id is likely to be valid
    queryMapillary(input);
    $('#button').prop('disabled', false);
}

// query mapillary and process response
function queryMapillary(file_key) {
    var url = 'https://a.mapillary.com/v2/g/' + file_key + "?client_id=NzNRM2otQkR2SHJzaXJmNmdQWVQ0dzoxNjQ3MDY4ZTUxY2QzNGI2";

    $.ajax({
        url: url,
        dataType: 'json',
        success: function (data) {
            // console.log('raw mapillary data', data);
            var parseddata = data;
            if (parseddata.nodes.length === 0) {
                $('#reflect').text('Mapillary could not find any information on that id. Sure it is right?');
            }
            else {
                while (parseddata.nodes[0].location === '') {
                    parseddata.nodes[0].location = prompt("Please enter a short description of the location", "");
                }
                parseddata.nodes[0].key = parseddata.nodes[0].key.replace ( /_/g , "$US$" ) ;
                var isoDate = new Date(parseddata.nodes[0].captured_at).toISOString().replace(/T/g, ' ').replace(/.000Z/g, '');
                var uploadDescription = '{{subst:Mapillary' +
                    '|location=' + parseddata.nodes[0].location +
                    '|key=' + parseddata.nodes[0].key +
                    '|date=' + isoDate +
                    '|username=' + parseddata.nodes[0].username +
                    '|lat=' + parseddata.nodes[0].lat +
                    '|lon=' + parseddata.nodes[0].lon +
                    '|ca=' + parseddata.nodes[0].ca +
                    '}}';
                var destFile = parseddata.nodes[0].location + ' - Mapillary (' + parseddata.nodes[0].key + ').jpg';
                var imageurl = parseddata.nodes[0].image.replace('thumb-1024.jpg', 'thumb-2048.jpg');  //request larger size
                var magnusurl = '//tools.wmflabs.org/url2commons/index.html?urls=' + imageurl + ' ' + destFile + '|' + encodeURIComponent(uploadDescription) + '&desc=$DESCRIPTOR$';
                // Ready to produce upload link
                $('#thumb').attr("src", imageurl);
                $('#thumbDiv').removeClass('hidden');
                $('#submit_button').attr("href", magnusurl);
                $('#submit_button').html('<big>Upload as</big>
' + destFile);
                $('#submit_button').removeClass('hidden');
            }
        },
        error: function (jqxhr, textStatus, errorThrown) {
            $('#reflect').text('The ajax call failed: ' + textStatus + ' : ' + errorThrown);
            console.log(textStatus);
            console.log(errorThrown);
        }
    });
}

// returns the named url parameter
function getURLParameter(param) {
    var pageURL = decodeURIComponent(window.location.search.substring(1));
    var urlVariables = pageURL.split('&');
    for (var i = 0; i < urlVariables.length; i++) {
        var parameterName = urlVariables[i].split('=');
        if (parameterName[0] == param) {
            return parameterName[1];
        }
    }
}
<commit_msg>Handle empty filenames, linebreaks in code<commit_after>$(document).ready(function() {
    // load filename from url
    var urlFilename = getURLParameter('mapillary');
    if (urlFilename) {
        $('#mapillary').val(urlFilename);
        processFilename();  // lookup directly if filename
    }
    // responsive buttons
    $('.btn').hover(
        function() {
            if (!$(this).prop("disabled")) {
                $(this).addClass('active');
            }
        },
        function() {
            $(this).removeClass('active');
        }
    );
    // on enter or clicking button, look up info on Mapillary
    $('#mapillary').keypress(function(e) {
        if(e.which == 13) {
            processFilename();
        }
    });
    $('#button').click(function() {
        processFilename();
    });

});

// Validate filename and request info from Commons
function processFilename() {
    // reset later fields
    $('#reflect').empty();
    $('#button').prop('disabled', true);
    $('#thumbDiv').addClass('hidden');
    $('#mapillary').removeClass('highlighted');

    // test filename
    var run = true;
    var input = $('#mapillary').val();
    if (input === ''){
        $('#mapillary').addClass('highlighted');
        run = false;
    }
    else if ( input.match(/\/\/www.mapillary.com\/map\/im\//gi) ) {
        input = decodeURIComponent(input.split('/im/')[1]);
        $('#mapillary').val(input);
    }
    // run if mapillary_id is likely to be valid
    if (run) {
        queryMapillary(input);
        $('#button').prop('disabled', false);
    }
    else {
        $('#button').prop('disabled', false);
    }
}

// query mapillary and process response
function queryMapillary(file_key) {
    var url = 'https://a.mapillary.com/v2/g/' +
              file_key +
              "?client_id=NzNRM2otQkR2SHJzaXJmNmdQWVQ0dzoxNjQ3MDY4ZTUxY2QzNGI2";

    $.ajax({
        url: url,
        dataType: 'json',
        success: function (data) {
            // console.log('raw mapillary data', data);
            var parseddata = data;
            if (parseddata.nodes.length === 0) {
                $('#reflect').text('Mapillary could not find any information on that id. Sure it is right?');
            }
            else {
                while (parseddata.nodes[0].location === '') {
                    parseddata.nodes[0].location = prompt("Please enter a short description of the location", "");
                }
                parseddata.nodes[0].key = parseddata.nodes[0].key.replace ( /_/g , "$US$" ) ;
                var isoDate = new Date(parseddata.nodes[0].captured_at).toISOString().replace(/T/g, ' ').replace(/.000Z/g, '');
                var uploadDescription = '{{subst:Mapillary' +
                    '|location=' + parseddata.nodes[0].location +
                    '|key=' + parseddata.nodes[0].key +
                    '|date=' + isoDate +
                    '|username=' + parseddata.nodes[0].username +
                    '|lat=' + parseddata.nodes[0].lat +
                    '|lon=' + parseddata.nodes[0].lon +
                    '|ca=' + parseddata.nodes[0].ca +
                    '}}';
                var destFile = parseddata.nodes[0].location +
                               ' - Mapillary (' +
                               parseddata.nodes[0].key +
                               ').jpg';
                //request larger size
                var imageurl = parseddata.nodes[0].image.replace('thumb-1024.jpg', 'thumb-2048.jpg');
                var magnusurl = '//tools.wmflabs.org/url2commons/index.html?' +
                                //'run=1&' +
                                'urls=' + imageurl + ' ' +
                                destFile + '|' +
                                encodeURIComponent(uploadDescription) +
                                '&desc=$DESCRIPTOR$';
                // Ready to produce upload link
                $('#thumb').attr("src", imageurl);
                $('#submit_button').attr("href", magnusurl);
                $('#submit_button').html('<big>Upload as</big>
' + destFile);
                $('#thumbDiv').removeClass('hidden');
            }
        },
        error: function (jqxhr, textStatus, errorThrown) {
            $('#reflect').text('The ajax call failed: ' + textStatus + ' : ' + errorThrown);
            console.log(textStatus);
            console.log(errorThrown);
        }
    });
}

// returns the named url parameter
function getURLParameter(param) {
    var pageURL = decodeURIComponent(window.location.search.substring(1));
    var urlVariables = pageURL.split('&');
    for (var i = 0; i < urlVariables.length; i++) {
        var parameterName = urlVariables[i].split('=');
        if (parameterName[0] == param) {
            return parameterName[1];
        }
    }
}
<|endoftext|>