<commit_before>import satelliteUtils from 'module/satelliteUtils';

const MAIN_WORKER = new SharedWorker('worker/main.js', 'satellite_services');
const MAX_TIMEOUT = 300000;

function getNewPort () {
    return (new SharedWorker('worker/main.js', 'satellite_services')).port;
}

function handleResponse () {
    return;
}

function messageServices (config, params) {
    var timer,
        promise,
        mergedParams = Object.assign({}, config, params);

    mergedParams.url = satelliteUtils.getResolvedPath(config.url, mergedParams);

    promise = (new Promise(function (resolve) {
        port.onmessage = handleResponse.bind({}, {
            resolve: resolve,
            reject: reject,
            timer: setTimeout(reject, mergedParams.timeout || TIMEOUT)
        });
        //TODO - figure out how to handle responses and fail on timeout.
        port.postMessage(mergedParams);
    })).then(function (response) {
        var rejectCodes = mergedParams.rejectCodes,
            resolveCodes = mergedParams.resolveCodes;

        if (true) {
            //todo
        }
    }, function () {
        return;
    });

    return promise;
}

/**
 * This method allows the user to register service methods onto
 *     the satellite service object.
 * @param {Object} config - The new service configuration.
 * @return {module/satellite} - The satellite object
 */
function satellite (config = {}) {
    var obj,
        name = config.name || '',
        chain = name.split('.'),
        key = chain.shift();

    if (!key) {
        return satellite;
    }

    if (chain.length) {
        obj = satelliteUtils.createResolvedChain(chain, satellite);
    } else {
        obj = satellite;
    }

    obj[key] = messageServices.bind({}, config);

    return satellite;
}

export default satellite;
<commit_msg>ISSUE 001 - Finished initial code for calling the shared worker with service params and handling the response.  UNSTABLE.<commit_after>import satelliteUtils from 'module/satelliteUtils';

const MAIN_WORKER = new SharedWorker('worker/main.js', 'satellite_services');
const MAX_TIMEOUT = 300000;

function getNewPort () {
    return (new SharedWorker('worker/main.js', 'satellite_services')).port;
}

function handleResponse (options, msg) {
    var response = msg.data,
        params = options.params,
        status = response.status;

    if (isSuccessful(status, params.resolveCodes)) {
        options.resolve(response);
    } else if (isFailure(status, params.rejectCodes)) {
        options.reject(response);
    }
}

function isFailure(status, codes = []) {
    if (codes.length) {
        return codes.map(function (code) {
            return parseInt(code, 10);
        }).indexOf(status) !== -1;
    }

    return status < 200 || status > 399;
}

function isSuccessful(status, codes = []) {
    if (codes.length) {
        return codes.map(function (code) {
            return parseInt(code, 10);
        }).indexOf(status) !== -1;
    }

    return status > 199 && status < 400;
}

function rejected (response) {
    return `${response.status} - ${response.statusText}`;
}

function resolved (response) {
    return JSON.parse(response.responseText || '0') || response;
}

function sendRequest (params, resolve, reject) {
    var port = getNewPort();

    port.onmessage = handleResponse.bind({}, {
        params: params,
        reject: reject,
        resolve: resolve,
        timer: setTimeout(reject, TIMEOUT)
    });

    port.postMessage(params);
}

function messageServices (config, params) {
    var request,
        mergedParams = Object.assign({}, config, params);

    mergedParams.url = satelliteUtils.getResolvedPath(config.url, mergedParams);
    request = sendRequest.bind({}, mergedParams);

    return(new Promise(request)).then(resolved, rejected);
}

/**
 * This method allows the user to register service methods onto
 *     the satellite service object.
 * @param {Object} config - The new service configuration.
 * @return {module/satellite} - The satellite object
 */
function satellite (config = {}) {
    var obj,
        name = config.name || '',
        chain = name.split('.'),
        key = chain.shift();

    if (!key) {
        return satellite;
    }

    if (chain.length) {
        obj = satelliteUtils.createResolvedChain(chain, satellite);
    } else {
        obj = satellite;
    }

    obj[key] = messageServices.bind({}, config);

    return satellite;
}

export default satellite;
<|endoftext|>


<commit_before>module.exports = (bot, logger, helper) => {
    bot.onText(new RegExp('^\/(?:검색|google|search|gg)+(?:@'+global.botinfo.username+')? (.+)$'), async (msg, match) => {
		if(Math.round((new Date()).getTime() / 1000) - msg.date <= 180) {
			const chatid = msg.chat.id;
			let temp;
			try{
				logger.info('chatid: '+chatid+', username: '+helper.getuser(msg.from)+', lang: '+msg.from.language_code+', command: '+msg.text+', type: command received');
                let send;
                [send, temp] = await Promise.all([
                    bot.sendChatAction(chatid, 'typing'),
                    helper.getlang(msg, logger)
                ]);
				let response = await helper.search(match[1]);
				if(response == '') {
					await bot.sendMessage(chatid, "🔍 "+temp.text(msg.chat.type, 'command.search.not_found'), {reply_to_message_id: msg.message_id});
					logger.info('chatid: '+chatid+', username: '+helper.getuser(msg.from)+', lang: '+msg.from.language_code+', command: '+msg.text+', type: valid');
				} else if(response == false) {
					await bot.sendMessage(chatid, "🔍 "+temp.text(msg.chat.type, 'command.search.bot_block'), {reply_to_message_id: msg.message_id});
					logger.info('chatid: '+chatid+', username: '+helper.getuser(msg.from)+', lang: '+msg.from.language_code+', command: '+msg.text+', type: google bot block');
				} else {
					try {
						await bot.sendMessage(chatid, "🔍 "+temp.text(msg.chat.type, 'command.search.result')+
							"\n"+response, {parse_mode: 'HTML', disable_web_page_preview: true,
							reply_to_message_id: msg.message_id,
							reply_markup: {
								inline_keyboard: [[{
									text: temp.inline('command.search.another'),
									url: 'https://www.google.com/search?q='+encodeURIComponent(match[1])+'&ie=UTF-8'
								}, {
									text: temp.inline('command.search.another'),
									switch_inline_query_current_chat: 'search '+match[1]
							}]]
						}});
						logger.info('chatid: '+chatid+', username: '+helper.getuser(msg.from)+', lang: '+msg.from.language_code+', command: '+msg.text+', type: valid');
					} catch(e) {
						sendError(e, chatid, temp, msg, match);
					}
				}
			} catch(e) {
				sendError(e);
			}
        }
        async function sendError(e, chatid, temp, msg, match) {
            try {
                await bot.sendMessage(chatid, "❗ "+temp.text(msg.chat.type, 'command.search.error')
                    .replace(/{botid}/g, '@'+global.botinfo.username).replace(/{keyword}/g, match[1]), {reply_markup:{ inline_keyboard: [[{
                        text: '@'+global.botinfo.username+' search '+match[1],
                        switch_inline_query_current_chat: 'search '+match[1]
                    }]]}, reply_to_message_id: msg.message_id, parse_mode: 'HTML'});
                logger.error('chatid: '+chatid+', username: '+helper.getuser(msg.from)+', lang: '+msg.from.language_code+', command: '+msg.text+', type: error');
                logger.debug(e.stack);
            } catch(e) {
                logger.error('chatid: '+chatid+', username: '+helper.getuser(msg.from)+', lang: '+msg.from.language_code+', command: '+msg.text+', type: error send error');
                logger.debug(e.stack);
            }
        }
    });

    bot.onText(new RegExp('^\/(?:검색|google|search|gg)+(?:@'+global.botinfo.username+')? ?$'), async (msg, match) => {
        if(Math.round((new Date()).getTime() / 1000) - msg.date <= 180) {
            const chatid = msg.chat.id;
            let temp;
            try{
                logger.info('chatid: '+chatid+', username: '+helper.getuser(msg.from)+', lang: '+msg.from.language_code+', command: '+msg.text+', type: command received');
                [temp] = await Promise.all([
                    bot.sendChatAction(chatid, 'typing'),
                    helper.getlang(msg, logger)
                ]);
                try {
                    await bot.sendMessage(chatid, "🔍 "+temp.text(msg.chat.type, 'command.search.blank'), {reply_to_message_id: msg.message_id, reply_markup: {
                        force_reply: true, selective: true
                    }});
                    logger.info('chatid: '+chatid+', username: '+helper.getuser(msg.from)+', lang: '+msg.from.language_code+', command: '+msg.text+', type: valid');
                } catch(e) {
                    logger.error('chatid: '+chatid+', username: '+helper.getuser(msg.from)+', lang: '+msg.from.language_code+', command: '+msg.text+', type: error');
                    logger.debug(e.stack);
                }
            } catch(e) {
                logger.error('chatid: '+chatid+', username: '+helper.getuser(msg.from)+', lang: '+msg.from.language_code+', command: '+msg.text+', type: error send error');
                logger.debug(e.stack);
            }
        }
    });
}<commit_msg>에러 다시수정<commit_after>module.exports = (bot, logger, helper) => {
    bot.onText(new RegExp('^\/(?:검색|google|search|gg)+(?:@'+global.botinfo.username+')? (.+)$'), async (msg, match) => {
		if(Math.round((new Date()).getTime() / 1000) - msg.date <= 180) {
			const chatid = msg.chat.id;
			let temp;
			try{
				logger.info('chatid: '+chatid+', username: '+helper.getuser(msg.from)+', lang: '+msg.from.language_code+', command: '+msg.text+', type: command received');
                let send;
                [send, temp] = await Promise.all([
                    bot.sendChatAction(chatid, 'typing'),
                    helper.getlang(msg, logger)
                ]);
				let response = await helper.search(match[1]);
				if(response == '') {
					await bot.sendMessage(chatid, "🔍 "+temp.text(msg.chat.type, 'command.search.not_found'), {reply_to_message_id: msg.message_id});
					logger.info('chatid: '+chatid+', username: '+helper.getuser(msg.from)+', lang: '+msg.from.language_code+', command: '+msg.text+', type: valid');
				} else if(response == false) {
					await bot.sendMessage(chatid, "🔍 "+temp.text(msg.chat.type, 'command.search.bot_block'), {reply_to_message_id: msg.message_id});
					logger.info('chatid: '+chatid+', username: '+helper.getuser(msg.from)+', lang: '+msg.from.language_code+', command: '+msg.text+', type: google bot block');
				} else {
					try {
						await bot.sendMessage(chatid, "🔍 "+temp.text(msg.chat.type, 'command.search.result')+
							"\n"+response, {parse_mode: 'HTML', disable_web_page_preview: true,
							reply_to_message_id: msg.message_id,
							reply_markup: {
								inline_keyboard: [[{
									text: temp.inline('command.search.another'),
									url: 'https://www.google.com/search?q='+encodeURIComponent(match[1])+'&ie=UTF-8'
								}, {
									text: temp.inline('command.search.another'),
									switch_inline_query_current_chat: 'search '+match[1]
							}]]
						}});
						logger.info('chatid: '+chatid+', username: '+helper.getuser(msg.from)+', lang: '+msg.from.language_code+', command: '+msg.text+', type: valid');
					} catch(e) {
						sendError(e, chatid, temp, msg, match);
					}
				}
			} catch(e) {
				sendError(e);
			}
        }
        async function sendError(e, chatid, temp, msg, match) {
            try {
                await bot.sendMessage(chatid, "❗ "+temp.text(msg.chat.type, 'command.search.error')
                    .replace(/{botid}/g, '@'+global.botinfo.username).replace(/{keyword}/g, match[1]), {reply_markup:{ inline_keyboard: [[{
                        text: '@'+global.botinfo.username+' search '+match[1],
                        switch_inline_query_current_chat: 'search '+match[1]
                    }]]}, reply_to_message_id: msg.message_id, parse_mode: 'HTML'});
                logger.error('chatid: '+chatid+', username: '+helper.getuser(msg.from)+', lang: '+msg.from.language_code+', command: '+msg.text+', type: error');
                logger.debug(e.stack);
            } catch(e) {
                logger.error('chatid: '+chatid+', username: '+helper.getuser(msg.from)+', lang: '+msg.from.language_code+', command: '+msg.text+', type: error send error');
                logger.debug(e.stack);
            }
        }
    });

    bot.onText(new RegExp('^\/(?:검색|google|search|gg)+(?:@'+global.botinfo.username+')? ?$'), async (msg, match) => {
        if(Math.round((new Date()).getTime() / 1000) - msg.date <= 180) {
            const chatid = msg.chat.id;
            let temp;
            try{
                logger.info('chatid: '+chatid+', username: '+helper.getuser(msg.from)+', lang: '+msg.from.language_code+', command: '+msg.text+', type: command received');
                let send;
                [send, temp] = await Promise.all([
                    bot.sendChatAction(chatid, 'typing'),
                    helper.getlang(msg, logger)
                ]);
                try {
                    await bot.sendMessage(chatid, "🔍 "+temp.text(msg.chat.type, 'command.search.blank'), {reply_to_message_id: msg.message_id, reply_markup: {
                        force_reply: true, selective: true
                    }});
                    logger.info('chatid: '+chatid+', username: '+helper.getuser(msg.from)+', lang: '+msg.from.language_code+', command: '+msg.text+', type: valid');
                } catch(e) {
                    logger.error('chatid: '+chatid+', username: '+helper.getuser(msg.from)+', lang: '+msg.from.language_code+', command: '+msg.text+', type: error');
                    logger.debug(e.stack);
                }
            } catch(e) {
                logger.error('chatid: '+chatid+', username: '+helper.getuser(msg.from)+', lang: '+msg.from.language_code+', command: '+msg.text+', type: error send error');
                logger.debug(e.stack);
            }
        }
    });
}<|endoftext|>


<commit_before>load("util.js");

var io = {
	print: function(s) {
		return print(s);
	},
	quit: function() {
		return quit();
	},
};

var connector = {
	selector: java.nio.channels.Selector.open(),
	read_buf: java.nio.ByteBuffer.allocate(1024),
	events: [],

	/* Register/unregister descriptors and operations with the selector.
	   These assume that only one ops of each type is registered per
	   descriptor; for example, you can't register two read events, because
	   when one is unregistered it will unregister the other. */
	register: function(sd, ops) {
		var key = sd.keyFor(this.selector);
		var current_ops = 0;
		if (key)
			current_ops = key.interestOps();
		sd.register(this.selector, current_ops | ops);
	},
	unregister: function(sd, ops) {
		var key = sd.keyFor(this.selector);
		if (key && key.isValid())
			sd.register(this.selector, key.interestOps() & ~ops);
	},

	bytebuffer_to_string: function(bb) {
		return String(new java.lang.String(java.util.Arrays.copyOf(bb.array(), bb.position()), "ISO-8859-1"));
	},
	string_to_bytebuffer: function(s) {
		return java.nio.ByteBuffer.wrap(new java.lang.String(s).getBytes("ISO-8859-1"));
	},

	/* Stringify/serialize a socket descriptor. */
	s_sd: function(sd) {
		var s = sd.socket();
		return s["class"] + "\0" + s.getInetAddress().getHostAddress() + "\0" + s.getPort();
	},

	handle_selection_key: function(key) {
		var channel = key.channel();
		if ((key.readyOps() & java.nio.channels.SelectionKey.OP_ACCEPT)
			== java.nio.channels.SelectionKey.OP_ACCEPT) {
			this.op_accept(channel);
			/* For accept only, do not unregister the selection key. */
		} else if ((key.readyOps() & java.nio.channels.SelectionKey.OP_CONNECT)
			== java.nio.channels.SelectionKey.OP_CONNECT) {
			this.op_connect(channel);
			this.unregister(channel, java.nio.channels.SelectionKey.OP_CONNECT);
		} else if ((key.readyOps() & java.nio.channels.SelectionKey.OP_READ)
			== java.nio.channels.SelectionKey.OP_READ) {
			this.op_read(channel);
			this.unregister(channel, java.nio.channels.SelectionKey.OP_READ);
		} else if ((key.readyOps() & java.nio.channels.SelectionKey.OP_WRITE)
			== java.nio.channels.SelectionKey.OP_WRITE) {
			this.op_write(channel);
			this.unregister(channel, java.nio.channels.SelectionKey.OP_WRITE);
		} else {
			throw new Error("Unknown selection key op.");
		}
	},
	op_accept: function(channel) {
		var c = channel.socket().accept();
		this.events.push({
			type: "accept",
			sd: channel,
			address: c.getInetAddress().getHostAddress(),
			port: c.getPort(),
			client: c.channel,
		});
	},
	op_connect: function(channel) {
		if (channel.isConnectionPending())
			channel.finishConnect();
		this.events.push({
			type: "connect",
			sd: channel,
			address: channel.socket().getInetAddress().getHostAddress(),
			port: channel.socket().getPort(),
		});
	},
	op_read: function(channel) {
		this.read_buf.clear();
		var n = channel.read(this.read_buf);
		var data;
		if (n == -1)
			data = undefined;
		else
			data = this.bytebuffer_to_string(this.read_buf);
		this.events.push({
			type: "recv",
			sd: channel,
			data: data,
		});
	},
	op_write: function(channel) {
		this.events.push({
			type: "send",
			sd: channel,
		});
	},

	wait_for_event: function() {
		while (true) {
			if (this.events.length > 0)
				return this.events.shift();

			var n;
			do {
				n = this.selector.select();
			} while (n == 0);

			var iter = this.selector.selectedKeys().iterator();
			while (iter.hasNext())
				this.handle_selection_key(iter.next());
			this.selector.selectedKeys().clear();
		}
	},
	listen: function(address, port) {
		var sd = java.nio.channels.ServerSocketChannel.open();
		sd.configureBlocking(false);
		sd.socket().bind(java.net.InetSocketAddress(port));
		this.register(sd, java.nio.channels.SelectionKey.OP_ACCEPT);
		return sd;
	},
	connect: function(address, port) {
		var sd = java.nio.channels.SocketChannel.open();
		sd.configureBlocking(false);
		this.register(sd, java.nio.channels.SelectionKey.OP_CONNECT);
		sd.connect(java.net.InetSocketAddress(address, port));
		return sd;
	},
	recv: function(sd) {
		sd.configureBlocking(false);
		this.register(sd, java.nio.channels.SelectionKey.OP_READ);
		return sd;
	},
	send: function(sd, data) {
		sd.configureBlocking(false);
		this.register(sd, java.nio.channels.SelectionKey.OP_WRITE);
		sd.write(this.string_to_bytebuffer(data));
		return sd;
	},
	close: function(sd) {
		sd.close();
	},
};

accept_pending = [];
connect_pending = [];
recv_pending = [];
send_pending = [];

function add_pending(pending_list, id, data) {
	pending_list.push({ id: id, data: data });
}

function get_pending(pending_list, id, keep) {
	for (var i = 0; i < pending_list.length; i++) {
		if (pending_list[i].id == id) {
			var pending = pending_list[i];
			if (!keep)
				pending_list.splice(i, 1)[0];
			return pending.data;
		}
	}
}

function listen(address, port, callback, userdata) {
	var sd = connector.listen(address, port);
	add_pending(accept_pending, sd, { callback: callback, userdata: userdata });
	return sd;
}

function connect(address, port, callback, userdata) {
	var sd = connector.connect(address, port);
	add_pending(connect_pending, sd, { callback: callback, userdata: userdata });
	return sd;
}

function recv(sd, callback, userdata) {
	var sd = connector.recv(sd);
	add_pending(recv_pending, sd, { callback: callback, userdata: userdata });
	return sd;
}

function send(sd, data, callback, userdata) {
	var sd = connector.send(sd, data);
	add_pending(send_pending, sd, { callback: callback, userdata: userdata });
	return sd;
}

function close(sd) {
	while (get_pending(accept_pending, sd))
		;
	while (get_pending(connect_pending, sd))
		;
	while (get_pending(recv_pending, sd))
		;
	while (get_pending(send_pending, sd))
		;
	connector.close(sd);
};

function event_loop() {
	while (true) {
		var ev = connector.wait_for_event();
		io.print("ev: " + repr(ev));

		var pending, args;
		switch (ev.type) {
		case "accept":
			/* accept events are persistent; don't remove pending
			   except on error. */
			pending = this.get_pending(this.accept_pending, ev.sd, true);
			args = [ev.client, ev.address, ev.port];
			break;
		case "connect":
			pending = this.get_pending(this.connect_pending, ev.sd);
			args = [ev.address, ev.port];
			break;
		case "recv":
			pending = this.get_pending(this.recv_pending, ev.sd);
			args = [ev.data];
			break;
		case "send":
			pending = this.get_pending(this.send_pending, ev.sd);
			args = [];
			break;
		default:
			throw new Error("Unknown event type \"" + ev.type + "\".");
		}
		/* Add standard arguments. */
		args = [ev.sd, pending.userdata].concat(args);
		if (pending.callback)
			pending.callback.apply(null, args);
	}
}

io.print("jscat starting.")

var LOCAL_ADDRESS = "0.0.0.0";
var LOCAL_PORT = 9998;

var DIRECTORY_ADDRESS = "localhost";
var DIRECTORY_PORT = 9999;

function accept_handler(sd, userdata, client, address, port) {
	io.print("Connection from " + address + ":" + port + ".");
	/* Pass the client as userdata. */
	connect(DIRECTORY_ADDRESS, DIRECTORY_PORT, connect_handler, client);
}

function connect_handler(sd, userdata, address, port) {
	io.print("Connection to " + address + ":" + port + ".");
	/* Queue initial read events. */
	recv(sd, recv_handler, userdata);
	recv(userdata, recv_handler, sd);
}

function recv_handler(sd, userdata, data) {
	if (data == undefined) {
		close(sd);
		close(userdata);
	} else {
		send(userdata, data);
		recv(sd, recv_handler, userdata);
	}
}

listen(LOCAL_ADDRESS, LOCAL_PORT, accept_handler);

event_loop();
<commit_msg>Add error events and handling.<commit_after>load("util.js");

var io = {
	print: function(s) {
		return print(s);
	},
	quit: function() {
		return quit();
	},
};

var connector = {
	selector: java.nio.channels.Selector.open(),
	read_buf: java.nio.ByteBuffer.allocate(1024),
	events: [],

	/* Register/unregister descriptors and operations with the selector.
	   These assume that only one ops of each type is registered per
	   descriptor; for example, you can't register two read events, because
	   when one is unregistered it will unregister the other. */
	register: function(sd, ops) {
		var key = sd.keyFor(this.selector);
		var current_ops = 0;
		if (key)
			current_ops = key.interestOps();
		sd.register(this.selector, current_ops | ops);
	},
	unregister: function(sd, ops) {
		var key = sd.keyFor(this.selector);
		if (key && key.isValid())
			sd.register(this.selector, key.interestOps() & ~ops);
	},

	bytebuffer_to_string: function(bb) {
		return String(new java.lang.String(java.util.Arrays.copyOf(bb.array(), bb.position()), "ISO-8859-1"));
	},
	string_to_bytebuffer: function(s) {
		return java.nio.ByteBuffer.wrap(new java.lang.String(s).getBytes("ISO-8859-1"));
	},

	/* Stringify/serialize a socket descriptor. */
	s_sd: function(sd) {
		var s = sd.socket();
		return s["class"] + "\0" + s.getInetAddress().getHostAddress() + "\0" + s.getPort();
	},

	handle_selection_key: function(key) {
		var channel = key.channel();
		if ((key.readyOps() & java.nio.channels.SelectionKey.OP_ACCEPT)
			== java.nio.channels.SelectionKey.OP_ACCEPT) {
			this.op_accept(channel);
			/* For accept only, do not unregister the selection key. */
		} else if ((key.readyOps() & java.nio.channels.SelectionKey.OP_CONNECT)
			== java.nio.channels.SelectionKey.OP_CONNECT) {
			this.op_connect(channel);
			this.unregister(channel, java.nio.channels.SelectionKey.OP_CONNECT);
		} else if ((key.readyOps() & java.nio.channels.SelectionKey.OP_READ)
			== java.nio.channels.SelectionKey.OP_READ) {
			this.op_read(channel);
			this.unregister(channel, java.nio.channels.SelectionKey.OP_READ);
		} else if ((key.readyOps() & java.nio.channels.SelectionKey.OP_WRITE)
			== java.nio.channels.SelectionKey.OP_WRITE) {
			this.op_write(channel);
			this.unregister(channel, java.nio.channels.SelectionKey.OP_WRITE);
		} else {
			throw new Error("Unknown selection key op.");
		}
	},
	op_accept: function(channel) {
		var c = channel.socket().accept();
		this.events.push({
			type: "accept",
			sd: channel,
			address: c.getInetAddress().getHostAddress(),
			port: c.getPort(),
			client: c.channel,
		});
	},
	op_connect: function(channel) {
		try {
			if (channel.isConnectionPending())
				channel.finishConnect();
		} catch (error) {
			this.events.push({
				type: "connect",
				sd: channel,
				error: error,
			});
			return;
		}
		this.events.push({
			type: "connect",
			sd: channel,
			address: channel.socket().getInetAddress().getHostAddress(),
			port: channel.socket().getPort(),
		});
	},
	op_read: function(channel) {
		this.read_buf.clear();
		try {
			var n = channel.read(this.read_buf);
		} catch (error) {
			this.events.push({
				type: "recv",
				sd: channel,
				error: error,
			});
			return;
		}
		var data;
		if (n == -1)
			data = undefined;
		else
			data = this.bytebuffer_to_string(this.read_buf);
		this.events.push({
			type: "recv",
			sd: channel,
			data: data,
		});
	},
	op_write: function(channel) {
		this.events.push({
			type: "send",
			sd: channel,
		});
	},

	wait_for_event: function() {
		while (true) {
			if (this.events.length > 0)
				return this.events.shift();

			var n;
			do {
				n = this.selector.select();
			} while (n == 0);

			var iter = this.selector.selectedKeys().iterator();
			while (iter.hasNext())
				this.handle_selection_key(iter.next());
			this.selector.selectedKeys().clear();
		}
	},
	listen: function(address, port) {
		var sd = java.nio.channels.ServerSocketChannel.open();
		sd.configureBlocking(false);
		try {
			sd.socket().bind(java.net.InetSocketAddress(port));
			this.register(sd, java.nio.channels.SelectionKey.OP_ACCEPT);
		} catch (error) {
			this.events.push({
				type: "accept",
				sd: sd,
				error: error,
				address: address,
				port: port,
			});
		}
		return sd;
	},
	connect: function(address, port) {
		var sd = java.nio.channels.SocketChannel.open();
		sd.configureBlocking(false);
		sd.connect(java.net.InetSocketAddress(address, port));
		this.register(sd, java.nio.channels.SelectionKey.OP_CONNECT);
		return sd;
	},
	recv: function(sd) {
		sd.configureBlocking(false);
		this.register(sd, java.nio.channels.SelectionKey.OP_READ);
		return sd;
	},
	send: function(sd, data) {
		sd.configureBlocking(false);
		try {
			sd.write(this.string_to_bytebuffer(data));
			this.register(sd, java.nio.channels.SelectionKey.OP_WRITE);
		} catch (error) {
			this.events.push({
				type: "send",
				sd: sd,
				error: error,
			});
		}
		return sd;
	},
	close: function(sd) {
		sd.close();
	},
};

accept_pending = [];
connect_pending = [];
recv_pending = [];
send_pending = [];

function add_pending(pending_list, id, data) {
	pending_list.push({ id: id, data: data });
}

function get_pending(pending_list, id, keep) {
	for (var i = 0; i < pending_list.length; i++) {
		if (pending_list[i].id == id) {
			var pending = pending_list[i];
			if (!keep)
				pending_list.splice(i, 1)[0];
			return pending.data;
		}
	}
}

function listen(address, port, callback, userdata) {
	var sd = connector.listen(address, port);
	add_pending(accept_pending, sd, { callback: callback, userdata: userdata });
	return sd;
}

function connect(address, port, callback, userdata) {
	var sd = connector.connect(address, port);
	add_pending(connect_pending, sd, { callback: callback, userdata: userdata });
	return sd;
}

function recv(sd, callback, userdata) {
	var sd = connector.recv(sd);
	add_pending(recv_pending, sd, { callback: callback, userdata: userdata });
	return sd;
}

function send(sd, data, callback, userdata) {
	var sd = connector.send(sd, data);
	add_pending(send_pending, sd, { callback: callback, userdata: userdata });
	return sd;
}

function close(sd) {
	while (get_pending(accept_pending, sd))
		;
	while (get_pending(connect_pending, sd))
		;
	while (get_pending(recv_pending, sd))
		;
	while (get_pending(send_pending, sd))
		;
	connector.close(sd);
};

function event_loop() {
	while (true) {
		var ev = connector.wait_for_event();
		io.print("ev: " + repr(ev));

		var pending, args;
		switch (ev.type) {
		case "accept":
			/* accept events are persistent; don't remove pending
			   except on error. */
			pending = this.get_pending(this.accept_pending, ev.sd, true);
			args = [ev.client, ev.address, ev.port];
			break;
		case "connect":
			pending = this.get_pending(this.connect_pending, ev.sd);
			args = [ev.address, ev.port];
			break;
		case "recv":
			pending = this.get_pending(this.recv_pending, ev.sd);
			args = [ev.data];
			break;
		case "send":
			pending = this.get_pending(this.send_pending, ev.sd);
			args = [];
			break;
		default:
			throw new Error("Unknown event type \"" + ev.type + "\".");
		}
		/* Add standard arguments. */
		args = [ev.sd, ev.error, pending.userdata].concat(args);
		if (pending.callback)
			pending.callback.apply(null, args);
	}
}

io.print("jscat starting.")

var LOCAL_ADDRESS = "0.0.0.0";
var LOCAL_PORT = 9998;

var DIRECTORY_ADDRESS = "localhost";
var DIRECTORY_PORT = 9999;

function accept_handler(sd, error, userdata, client, address, port) {
	if (error) {
		io.print("Error listening on " + address + ":" + port + ": " + error.message);
		return;
	}
	io.print("Connection from " + address + ":" + port + ".");
	/* Pass the client as userdata. */
	connect(DIRECTORY_ADDRESS, DIRECTORY_PORT, connect_handler, client);
}

function connect_handler(sd, error, userdata, address, port) {
	if (error) {
		io.print("Error in connect: " + error.message);
		close(userdata);
		return;
	}
	io.print("Connection to " + address + ":" + port + ".");
	/* Queue initial read events. */
	recv(sd, recv_handler, userdata);
	recv(userdata, recv_handler, sd);
}

function recv_handler(sd, error, userdata, data) {
	if (error) {
		io.print("Error in recv: " + error.message);
		close(sd);
		close(userdata);
		return;
	}
	if (data == undefined) {
		close(sd);
		close(userdata);
	} else {
		send(userdata, data);
		recv(sd, recv_handler, userdata);
	}
}

listen(LOCAL_ADDRESS, LOCAL_PORT, accept_handler);

event_loop();
<|endoftext|>


<commit_before>var config = require(process.env.HOME + "/.jsiidConfig.js");
var net = require("net");

var clients = [];

var handleClientMessage = function(msg, socket) {
    var chanLongName = msg.server + ':' + msg.chan;
    if(msg.cmd === "backlog") {
        // get nicklist for chan if we already haven't
        initChan(msg.server, msg.chan, true);

        if(ircChans[chanLongName]) {
            // send backlog
            for(var i = 0; i < config.backlog && i < ircChans[chanLongName].messages.length; i++) {
                broadcastMsg([socket], JSON.stringify(ircChans[chanLongName].messages[i]));
            }

            // send the nicklist
            broadcastMsg([socket], JSON.stringify({
                "cmd": "nicklist",
                "nicks": Object.keys(ircChans[chanLongName].nicks),
                "server": msg.server,
                "chan": msg.chan
            }));

        }
    } else if (msg.cmd === "search") {
        if(ircChans[chanLongName]) {
            // send search results
            var id = 0;
            for(var i = ircChans[chanLongName].messages.length - 1; i >= 0; i--) {
                var origMsg = ircChans[chanLongName].messages[i];
                if(origMsg.message &&
                   origMsg.message.match(new RegExp(msg.searchRE))) {

                    if(msg.skip > 0) {
                        msg.skip--;
                        continue;
                    }

                    var message = origMsg.message;
                    if(msg.onlyMatching) {
                        message = message.match(new RegExp(msg.searchRE))[0];
                    }

                    var results = {
                        "cmd": "searchResults",
                        "type": msg.type,
                        "id": id++,
                        "server": origMsg.server,
                        "chan": origMsg.chan,
                        "message": message,
                        "nick": origMsg.nick
                    }

                    broadcastMsg([socket], JSON.stringify(results));

                    if(msg.firstMatchOnly)
                        return;
                }
            }
        }
    } else {
        sendIrcMsg(msg, socket);
    }
};

var handleClientDisconnect = function(socket) {
    console.log("client disconnected.");
    clients.splice(clients.indexOf(socket), 1);
};

var createListener = function() {
    var listener = net.createServer(function (socket) {
        console.log("client connected.");
        var buffer = "";

        socket.on("data", function(data) {
            console.log("got client data:" + data);
            buffer += data.toString('utf8');
            var lastNL = buffer.lastIndexOf('\n');
            if(lastNL !== -1) {
                var recvdLines = buffer.substr(0, lastNL).split('\n');
                buffer = buffer.substr(lastNL + 1);

                for(var i = 0; i < recvdLines.length; i++) {
                    var msg = JSON.parse(recvdLines[i]);
                    handleClientMessage(msg, socket);
                }
            }
        });
        socket.on("end", function() {
            socket.end();
        });
        socket.on("close", function() {
            handleClientDisconnect(socket);
        });

        clients.push(socket);
    });

    listener.listen(config.listenPort, config.listenAddr);
};

var broadcastMsg = function(clients, msg) {
    // msg shouldn't contain any newlines, but let's be sure
    if(msg.message)
        msg.message.replace('\n', '');

    for(var i = 0; i < clients.length; i++) {
        clients[i].write(msg + '\n');
    }
    console.log("broadcastMsg(): " + msg);
};

var ircChans = {};
var ircServers = {};

var recvdIrcMsg = function(serverName, cmd, chan, nick, msgString, noBroadcast) {
    var chanLongName = serverName + ':' + chan;

    var msg = {
        "server": serverName,
        "cmd": cmd,
        "chan": chan,
        "nick": nick,
        "message": msgString
    };

    if(chan && msgString) {
        ircChans[chanLongName].messages.push(msg);
        if(ircChans[chanLongName].messages.length > config.backlog)
            ircChans[chanLongName].messages.shift();
    }

    if(!noBroadcast)
        broadcastMsg(clients, JSON.stringify(msg));
};

var sendIrcMsg = function(msg, client) {
    var ircServer = ircServers[msg.server];
    if(!ircServer)
        broadcastMsg([client], JSON.stringify({"error": "Server not found."}))
    else {
        if(!msg.chan) {
            broadcastMsg([client], JSON.stringify({"error": "Invalid recepient."}))
        } else if(!msg.message) {
            broadcastMsg([client], JSON.stringify({"error": "No message provided."}))
        } else if (msg.message[0] !== '/') {
            initChan(msg.server, msg.chan, true);

            // add message to our backlog and send it
            recvdIrcMsg(msg.server, "message", msg.chan, msg.nick, msg.message, true);
            ircServer.send('PRIVMSG ' + msg.chan + ' :' + msg.message);
        } else {
            ircServer.send(msg.message.substr(1));
        }
    }
};

var initChan = function(serverName, chan) {
    var chanLongName = serverName + ':' + chan;

    if(!ircChans[chanLongName]) {
        ircChans[chanLongName] = {
            "messages": [],
            "nicks": {}
        };
    }
};

var handleIrcLine = function(line, server, ircServer) {
    var tokens = line.split(' ');

    //console.log(server.name + ': ' + line);
    if(tokens[0] === "PING") {
        console.log('got PING, sending PONG to ' + tokens[1].substr(1));
        ircServer.send("PONG " + tokens[1].substr(1));
    } else if (tokens[0][0] === ":") {
        var prefix = tokens[0].substr(1);
        var nick = prefix.substr(0, prefix.indexOf('!'));
        var cmd = tokens[1];
        var chan = tokens[2];
        chan = chan.replace(':', '');

        if(prefix === server.serverLongName) {
            tokens.shift(); tokens.shift(); tokens.shift();
            var msg = tokens.join(' ');
            // nicklist
            if (cmd === "353") {
                chan = msg.split(':')[0];
                chan = chan.split(' ')[1];
                var nicks = msg.split(':')[1];
                nicks = nicks.split(' ');

                var chanLongName = server.name + ':' + chan;
                initChan(server.name, chan, false);

                for(var i = 0; i < nicks.length; i++) {
                    ircChans[chanLongName].nicks[nicks[i]] = true;
                }

                // send the nicklist
                broadcastMsg(clients, JSON.stringify({
                    "cmd": "nicklist",
                    "nicks": Object.keys(ircChans[chanLongName].nicks),
                    "server": msg.server,
                    "chan": msg.chan
                }));
            } else {
                initChan(server.name, server.name, false);
                recvdIrcMsg(server.name, "message", server.name, server.name, msg);
            }
        } else if(cmd === "PRIVMSG") {
            tokens.shift(); tokens.shift(); tokens.shift();
            var msg = tokens.join(' ').substr(1);

            // query message
            if(chan === config.nick) {
                chan = nick;
            }

            initChan(server.name, chan, true);
            recvdIrcMsg(server.name, "message", chan, nick, msg);
        } else if (cmd === "JOIN") {
            initChan(server.name, chan, true);
            if(nick === (server.nick || config.myNick)) {
                recvdIrcMsg(server.name, "join", chan, nick, null);
                ircChans[server.name + ':' + chan].nicks[nick] = true;
            }
        } else if (cmd === "PART") {
            initChan(server.name, chan, true);
            recvdIrcMsg(server.name, "part", chan, nick, null);
            delete(ircChans[server.name + ':' + chan].nicks[nick]);
        } else if (cmd === "QUIT") {
            for(var key in ircChans) {
                for(var chanNick in ircChans[key].nicks) {
                    if(chanNick === nick) {
                        recvdIrcMsg(server.name, "part", key, nick, null);
                        delete(ircChans[key].nicks[nick]);
                    }
                }
            }
        } else if (cmd === "001") {
            server.serverLongName = prefix;
            console.log("serverLongName changed to " + server.serverLongName);
        } else {
            console.log("got unknown msg from " + nick + ": " + line);
        }
    } else {
        console.log("got unknown msg on " + server.name + ": " + line);
    }
};

var ircConnect = function(serverConfig) {
    var buffer = "";

    var ircServer = net.connect({
        "port": serverConfig.port,
        "host": serverConfig.address
    }, function() {
        console.log('connected to irc server');
        broadcastMsg(clients, {
            nick: '!',
            message: serverConfig.name + ': Connected to IRC.',
            broadcast: true
        });

        var passString = "";
        if(serverConfig.password)
            passString = "PASS " + serverConfig.password + "\r\n";

        ircServer.write(passString +
                     "NICK " + (serverConfig.nick || config.nick) + "\r\n" +
                     "USER " + (serverConfig.nick || config.nick) + " " +
                     "localhost " + serverConfig.address + " :" +
                     (serverConfig.nick || config.nick) + "\r\n");

    });

    ircServer.send = function(data) {
        console.log("sending data to IRC: " + data);
        ircServer.write(data + '\r\n');
    };

    ircServer.on('data', function(data) {
        buffer += data.toString('utf8');
        var lastNL = buffer.lastIndexOf('\n');

        // have we received at least one whole line? else wait for more data
        if(lastNL !== -1) {
            var recvdLines = buffer.substr(0, lastNL + 1).split('\r\n');
            buffer = buffer.substr(lastNL + 1);

            for(var i = 0; i < recvdLines.length; i++) {
                if(recvdLines[i] !== '') {
                    console.log('irc server sent ' + recvdLines[i]);
                    handleIrcLine(recvdLines[i], serverConfig, ircServer);
                }
            }
        }
    });
    ircServer.on('end', function() {
        console.log(serverConfig.name + ': disconnected from irc, reconnecting...');
        broadcastMsg(clients, {
            nick: '!',
            message: serverConfig.name + ': Disconnected from irc, reconnecting...',
            broadcast: true
        });
        setTimeout(function() {
            ircConnect(serverConfig);
        }, config.reconnectDelay);
    });
    ircServer.on('close', function() {
        console.log(serverConfig.name + ': connection to irc closed, reconnecting...');
        broadcastMsg(clients, JSON.stringify({
            nick: '!',
            message: serverConfig.name + ': Connection to irc closed, reconnecting...',
            broadcast: true
        }));
        setTimeout(function() {
            ircConnect(serverConfig);
        }, config.reconnectDelay);
    });

    ircServer.config = serverConfig;
    ircServer.chanNamesRequests = [];
    ircServer.namesRequestTimeout = null;

    ircServers[serverConfig.name] = ircServer;
};

createListener();

for(var i = 0; i < config.servers.length; i++)
    ircConnect(config.servers[i]);

process.on('uncaughtException', function (err) {
    console.error(err.stack);
    console.log("ERROR! Node not exiting.");
});
<commit_msg>case insensitive chan names<commit_after>var config = require(process.env.HOME + "/.jsiidConfig.js");
var net = require("net");

var clients = [];

var handleClientMessage = function(msg, socket) {
    var chanLongName = msg.server + ':' + msg.chan;
    chanLongName = chanLongName.toLowerCase();
    if(msg.cmd === "backlog") {
        // get nicklist for chan if we already haven't
        initChan(msg.server, msg.chan, true);

        if(ircChans[chanLongName]) {
            // send backlog
            for(var i = 0; i < config.backlog && i < ircChans[chanLongName].messages.length; i++) {
                broadcastMsg([socket], JSON.stringify(ircChans[chanLongName].messages[i]));
            }

            // send the nicklist
            broadcastMsg([socket], JSON.stringify({
                "cmd": "nicklist",
                "nicks": Object.keys(ircChans[chanLongName].nicks),
                "server": msg.server,
                "chan": msg.chan
            }));

        }
    } else if (msg.cmd === "search") {
        if(ircChans[chanLongName]) {
            // send search results
            var id = 0;
            for(var i = ircChans[chanLongName].messages.length - 1; i >= 0; i--) {
                var origMsg = ircChans[chanLongName].messages[i];
                if(origMsg.message &&
                   origMsg.message.match(new RegExp(msg.searchRE))) {

                    if(msg.skip > 0) {
                        msg.skip--;
                        continue;
                    }

                    var message = origMsg.message;
                    if(msg.onlyMatching) {
                        message = message.match(new RegExp(msg.searchRE))[0];
                    }

                    var results = {
                        "cmd": "searchResults",
                        "type": msg.type,
                        "id": id++,
                        "server": origMsg.server,
                        "chan": origMsg.chan,
                        "message": message,
                        "nick": origMsg.nick
                    }

                    broadcastMsg([socket], JSON.stringify(results));

                    if(msg.firstMatchOnly)
                        return;
                }
            }
        }
    } else {
        sendIrcMsg(msg, socket);
    }
};

var handleClientDisconnect = function(socket) {
    console.log("client disconnected.");
    clients.splice(clients.indexOf(socket), 1);
};

var createListener = function() {
    var listener = net.createServer(function (socket) {
        console.log("client connected.");
        var buffer = "";

        socket.on("data", function(data) {
            console.log("got client data:" + data);
            buffer += data.toString('utf8');
            var lastNL = buffer.lastIndexOf('\n');
            if(lastNL !== -1) {
                var recvdLines = buffer.substr(0, lastNL).split('\n');
                buffer = buffer.substr(lastNL + 1);

                for(var i = 0; i < recvdLines.length; i++) {
                    var msg = JSON.parse(recvdLines[i]);
                    handleClientMessage(msg, socket);
                }
            }
        });
        socket.on("end", function() {
            socket.end();
        });
        socket.on("close", function() {
            handleClientDisconnect(socket);
        });

        clients.push(socket);
    });

    listener.listen(config.listenPort, config.listenAddr);
};

var broadcastMsg = function(clients, msg) {
    // msg shouldn't contain any newlines, but let's be sure
    if(msg.message)
        msg.message.replace('\n', '');

    for(var i = 0; i < clients.length; i++) {
        clients[i].write(msg + '\n');
    }
    console.log("broadcastMsg(): " + msg);
};

var ircChans = {};
var ircServers = {};

var recvdIrcMsg = function(serverName, cmd, chan, nick, msgString, noBroadcast) {
    var chanLongName = serverName + ':' + chan;
    chanLongName = chanLongName.toLowerCase();

    var msg = {
        "server": serverName,
        "cmd": cmd,
        "chan": chan,
        "nick": nick,
        "message": msgString
    };

    if(chan && msgString) {
        ircChans[chanLongName].messages.push(msg);
        if(ircChans[chanLongName].messages.length > config.backlog)
            ircChans[chanLongName].messages.shift();
    }

    if(!noBroadcast)
        broadcastMsg(clients, JSON.stringify(msg));
};

var sendIrcMsg = function(msg, client) {
    var ircServer = ircServers[msg.server];
    if(!ircServer)
        broadcastMsg([client], JSON.stringify({"error": "Server not found."}))
    else {
        if(!msg.chan) {
            broadcastMsg([client], JSON.stringify({"error": "Invalid recepient."}))
        } else if(!msg.message) {
            broadcastMsg([client], JSON.stringify({"error": "No message provided."}))
        } else if (msg.message[0] !== '/') {
            initChan(msg.server, msg.chan, true);

            // add message to our backlog and send it
            recvdIrcMsg(msg.server, "message", msg.chan, msg.nick, msg.message, true);
            ircServer.send('PRIVMSG ' + msg.chan + ' :' + msg.message);
        } else {
            ircServer.send(msg.message.substr(1));
        }
    }
};

var initChan = function(serverName, chan) {
    var chanLongName = serverName + ':' + chan;
    chanLongName = chanLongName.toLowerCase();

    if(!ircChans[chanLongName]) {
        ircChans[chanLongName] = {
            "messages": [],
            "nicks": {}
        };
    }
};

var handleIrcLine = function(line, server, ircServer) {
    var tokens = line.split(' ');

    //console.log(server.name + ': ' + line);
    if(tokens[0] === "PING") {
        console.log('got PING, sending PONG to ' + tokens[1].substr(1));
        ircServer.send("PONG " + tokens[1].substr(1));
    } else if (tokens[0][0] === ":") {
        var prefix = tokens[0].substr(1);
        var nick = prefix.substr(0, prefix.indexOf('!'));
        var cmd = tokens[1];
        var chan = tokens[2];
        chan = chan.replace(':', '');

        var chanLongName = server.name + ':' + chan;
        chanLongName = chanLongName.toLowerCase();

        if(prefix === server.serverLongName) {
            tokens.shift(); tokens.shift(); tokens.shift();
            var msg = tokens.join(' ');
            // nicklist
            if (cmd === "353") {
                chan = msg.split(':')[0];
                chan = chan.split(' ')[1];
                var nicks = msg.split(':')[1];
                nicks = nicks.split(' ');

                chanLongName = server.name + ':' + chan;
                chanLongName = chanLongName.toLowerCase();
                initChan(server.name, chan, false);

                for(var i = 0; i < nicks.length; i++) {
                    ircChans[chanLongName].nicks[nicks[i]] = true;
                }

                // send the nicklist
                broadcastMsg(clients, JSON.stringify({
                    "cmd": "nicklist",
                    "nicks": Object.keys(ircChans[chanLongName].nicks),
                    "server": msg.server,
                    "chan": msg.chan
                }));
            } else {
                initChan(server.name, server.name, false);
                recvdIrcMsg(server.name, "message", server.name, server.name, msg);
            }
        } else if(cmd === "PRIVMSG") {
            tokens.shift(); tokens.shift(); tokens.shift();
            var msg = tokens.join(' ').substr(1);

            // query message
            if(chan === config.nick) {
                chan = nick;
            }

            initChan(server.name, chan, true);
            recvdIrcMsg(server.name, "message", chan, nick, msg);
        } else if (cmd === "JOIN") {
            initChan(server.name, chan, true);
            if(nick === (server.nick || config.myNick)) {
                recvdIrcMsg(server.name, "join", chan, nick, null);
                ircChans[chanLongName].nicks[nick] = true;
            }
        } else if (cmd === "PART") {
            initChan(server.name, chan, true);
            recvdIrcMsg(server.name, "part", chan, nick, null);
            delete(ircChans[chanLongName].nicks[nick]);
        } else if (cmd === "QUIT") {
            for(var key in ircChans) {
                for(var chanNick in ircChans[key].nicks) {
                    if(chanNick === nick) {
                        recvdIrcMsg(server.name, "part", key, nick, null);
                        delete(ircChans[key].nicks[nick]);
                    }
                }
            }
        } else if (cmd === "001") {
            server.serverLongName = prefix;
            console.log("serverLongName changed to " + server.serverLongName);
        } else {
            console.log("got unknown msg from " + nick + ": " + line);
        }
    } else {
        console.log("got unknown msg on " + server.name + ": " + line);
    }
};

var ircConnect = function(serverConfig) {
    var buffer = "";

    var ircServer = net.connect({
        "port": serverConfig.port,
        "host": serverConfig.address
    }, function() {
        console.log('connected to irc server');
        broadcastMsg(clients, {
            nick: '!',
            message: serverConfig.name + ': Connected to IRC.',
            broadcast: true
        });

        var passString = "";
        if(serverConfig.password)
            passString = "PASS " + serverConfig.password + "\r\n";

        ircServer.write(passString +
                     "NICK " + (serverConfig.nick || config.nick) + "\r\n" +
                     "USER " + (serverConfig.nick || config.nick) + " " +
                     "localhost " + serverConfig.address + " :" +
                     (serverConfig.nick || config.nick) + "\r\n");

    });

    ircServer.send = function(data) {
        console.log("sending data to IRC: " + data);
        ircServer.write(data + '\r\n');
    };

    ircServer.on('data', function(data) {
        buffer += data.toString('utf8');
        var lastNL = buffer.lastIndexOf('\n');

        // have we received at least one whole line? else wait for more data
        if(lastNL !== -1) {
            var recvdLines = buffer.substr(0, lastNL + 1).split('\r\n');
            buffer = buffer.substr(lastNL + 1);

            for(var i = 0; i < recvdLines.length; i++) {
                if(recvdLines[i] !== '') {
                    console.log('irc server sent ' + recvdLines[i]);
                    handleIrcLine(recvdLines[i], serverConfig, ircServer);
                }
            }
        }
    });
    ircServer.on('end', function() {
        console.log(serverConfig.name + ': disconnected from irc, reconnecting...');
        broadcastMsg(clients, {
            nick: '!',
            message: serverConfig.name + ': Disconnected from irc, reconnecting...',
            broadcast: true
        });
        setTimeout(function() {
            ircConnect(serverConfig);
        }, config.reconnectDelay);
    });
    ircServer.on('close', function() {
        console.log(serverConfig.name + ': connection to irc closed, reconnecting...');
        broadcastMsg(clients, JSON.stringify({
            nick: '!',
            message: serverConfig.name + ': Connection to irc closed, reconnecting...',
            broadcast: true
        }));
        setTimeout(function() {
            ircConnect(serverConfig);
        }, config.reconnectDelay);
    });

    ircServer.config = serverConfig;
    ircServer.chanNamesRequests = [];
    ircServer.namesRequestTimeout = null;

    ircServers[serverConfig.name] = ircServer;
};

createListener();

for(var i = 0; i < config.servers.length; i++)
    ircConnect(config.servers[i]);

process.on('uncaughtException', function (err) {
    console.error(err.stack);
    console.log("ERROR! Node not exiting.");
});
<|endoftext|>


<commit_before>/**
 * 配置界面
 */
$(function(){
  var domBtnSettings = [
    '
',
      '',
        '',
        'iZhihu',
      '',
    '
'
  ].join('');

  var cbemptyimg = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAMAAAAoyzS7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAZQTFRFAAAAAAAApWe5zwAAAAF0Uk5TAEDm2GYAAAAMSURBVHjaYmAACDAAAAIAAU9tWeEAAAAASUVORK5CYII=';
    var domDlgSettings = [
      '
',
        '
',
          '配置选项',
          '',
        '
',
        '
',
          '
',
            '
',
            '
',
            	'
',
            		'
功能开关（更改后设置将立刻保存，但只有当页面再次打开时才会生效)
',
            	'
',
            	'
',
                '
在首页直接浏览常去话题	<input type="checkbox" class="t_rtjdchk" id="iZhihu_setHomeTopics" name="HomeTopics" />
',
                '
改变网页样式外观	<input type="checkbox" class="t_rtjdchk" id="iZhihu_setHomeLayout" name="HomeLayout" />
',
                '
调整首页「新动态」提醒按钮	<input type="checkbox" class="t_rtjdchk" id="iZhihu_setHomeNoti" name="HomeNoti" />
',
                '
将用户信息挪到回答下方	<input type="checkbox" class="t_rtjdchk" id="iZhihu_setAuthorRear" name="AuthorRear" />
',
                '
在页面右侧浮动显示打开的评论列表	<input type="checkbox" class="t_rtjdchk" id="iZhihu_setRightComment" name="ShowComment" />
',
                '
开启「快速屏蔽」（加入黑名单/取消关注）功能	<input type="checkbox" class="t_rtjdchk" id="iZhihu_setQuickBlock" name="QuickBlock" />
',
                '
开启「快速收藏」菜单	<input type="checkbox" class="t_rtjdchk" id="iZhihu_setQuickFavo" name="QuickFavo" />
',
                '
开启「回答目录」	<input type="checkbox" class="t_rtjdchk" id="iZhihu_setAuthorList" name="AuthorList" />
',
            	'
',
            '
',
            '
',
              '
',
                '当前版本：'+version+'；',
                '最后更新：'+updateDate+'
',
                '制作：@钢盅郭子，',
                '@天猪(刘勇)，',
                '@罗大睿
',
                '感谢：@Peter',
              '
',
              '
',
              '刷新网页',
            '
',
          '
',
        '
',
      '
'
    ].join('');

  $(domBtnSettings).insertBefore($('ul#top-nav-profile-dropdown li:last'))
  .click(function(){
    console.log(this);
    $('.modal-dialog-bg').show();
    $('input.t_rtjdchk','#izh-dlg-settings').each(function(i,e){
        if(utils.getCfg($(e).attr('name')))
            $(e).attr('checked','checked');
    });
    $('#izh-dlg-settings').css({'z-index':'123','position':'fixed','top': ($win.height() - $('#izh-dlg-settings').height()) / 2, 'left': ($win.width() - $('#izh-dlg-settings').width()) / 2}).fadeIn('slow');
  });
  var $dlg=$(domDlgSettings).appendTo(_doc.body);
  $dlg.drags({handler:'.modal-dialog-title-draggable'});
  $('.modal-dialog-title-close',$dlg).click(function(){
      $('.modal-dialog-bg').hide();
      $('#izh-dlg-settings').first().hide();
  });
  $('input.t_rtjdchk',$dlg).checkbox({cls:'t_jchkbox',empty:cbemptyimg});
  $('input.t_rtjdchk',$dlg).click(function(){
      var key=$(this).attr('name')
        , value=!this.checked;
      console.log(key+' = '+value);
      utils.setCfg(key,value);
  });
})<commit_msg>Fixed info&link of 罗大睿 Added more info for RightComment option<commit_after>/**
 * 配置界面
 */
$(function(){
  var domBtnSettings = [
    '
',
      '',
        '',
        'iZhihu',
      '',
    '
'
  ].join('');

  var cbemptyimg = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAMAAAAoyzS7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAZQTFRFAAAAAAAApWe5zwAAAAF0Uk5TAEDm2GYAAAAMSURBVHjaYmAACDAAAAIAAU9tWeEAAAAASUVORK5CYII=';
    var domDlgSettings = [
      '
',
        '
',
          '配置选项',
          '',
        '
',
        '
',
          '
',
            '
',
            '
',
            	'
',
            		'
功能开关（更改后设置将立刻保存，但只有当页面再次打开时才会生效)
',
            	'
',
            	'
',
                '
在首页直接浏览常去话题	<input type="checkbox" class="t_rtjdchk" id="iZhihu_setHomeTopics" name="HomeTopics" />
',
                '
改变网页样式外观	<input type="checkbox" class="t_rtjdchk" id="iZhihu_setHomeLayout" name="HomeLayout" />
',
                '
调整首页「新动态」提醒按钮	<input type="checkbox" class="t_rtjdchk" id="iZhihu_setHomeNoti" name="HomeNoti" />
',
                '
将用户信息挪到回答下方	<input type="checkbox" class="t_rtjdchk" id="iZhihu_setAuthorRear" name="AuthorRear" />
',
                '
在页面右侧浮动显示打开的评论列表	<input type="checkbox" class="t_rtjdchk" id="iZhihu_setRightComment" name="ShowComment" />
',
                '
开启「快速屏蔽」（加入黑名单/取消关注）功能	<input type="checkbox" class="t_rtjdchk" id="iZhihu_setQuickBlock" name="QuickBlock" />
',
                '
开启「快速收藏」菜单	<input type="checkbox" class="t_rtjdchk" id="iZhihu_setQuickFavo" name="QuickFavo" />
',
                '
开启「回答目录」	<input type="checkbox" class="t_rtjdchk" id="iZhihu_setAuthorList" name="AuthorList" />
',
            	'
',
            '
',
            '
',
              '
',
                '当前版本：'+version+'；',
                '最后更新：'+updateDate+'
',
                '制作：@钢盅郭子，',
                '@天猪(刘勇)，',
                '@罗大睿
',
                '感谢：@Peter',
              '
',
              '
',
              '刷新网页',
            '
',
          '
',
        '
',
      '
'
    ].join('');

  $(domBtnSettings).insertBefore($('ul#top-nav-profile-dropdown li:last'))
  .click(function(){
    console.log(this);
    $('.modal-dialog-bg').show();
    $('input.t_rtjdchk','#izh-dlg-settings').each(function(i,e){
        if(utils.getCfg($(e).attr('name')))
            $(e).attr('checked','checked');
    });
    $('#izh-dlg-settings').css({'z-index':'123','position':'fixed','top': ($win.height() - $('#izh-dlg-settings').height()) / 2, 'left': ($win.width() - $('#izh-dlg-settings').width()) / 2}).fadeIn('slow');
  });
  var $dlg=$(domDlgSettings).appendTo(_doc.body);
  $dlg.drags({handler:'.modal-dialog-title-draggable'});
  $('.modal-dialog-title-close',$dlg).click(function(){
      $('.modal-dialog-bg').hide();
      $('#izh-dlg-settings').first().hide();
  });
  $('input.t_rtjdchk',$dlg).checkbox({cls:'t_jchkbox',empty:cbemptyimg});
  $('input.t_rtjdchk',$dlg).click(function(){
      var key=$(this).attr('name')
        , value=!this.checked;
      console.log(key+' = '+value);
      utils.setCfg(key,value);
  });
})<|endoftext|>


<commit_before>window.multigraph.util.namespace("window.multigraph.normalizer", function (ns) {
    "use strict";

    ns.mixin.add(function (ns) {

        ns.Graph.respondsTo("normalize", function () {
            var i, j,
                haxisCount = 0,
                vaxisCount = 0,
                axis,
                axisid,
                plot;

            //
            // normalizes the data sections
            //
            for (i = 0; i < this.data().size(); i++) {
                this.data().at(i).normalize();
            }

            //
            // Handles missing horizontalaxis and vertical axis tags
            //
            for (i = 0; i < this.axes().size(); i++) {
                if (this.axes().at(i).orientation() === ns.Axis.HORIZONTAL) {
                    haxisCount++;
                } else if (this.axes().at(i).orientation() === ns.Axis.VERTICAL) {
                    vaxisCount++;
                }
            }

            if (haxisCount === 0) {
                this.axes().add(new ns.Axis(ns.Axis.HORIZONTAL));
            }
            if (vaxisCount === 0) {
                this.axes().add(new ns.Axis(ns.Axis.VERTICAL));
            }

            //
            // Handles missing id's for axes
            //
            haxisCount = 0;
            vaxisCount = 0;
            for (i = 0; i < this.axes().size(); i++) {
                if (this.axes().at(i).orientation() === ns.Axis.HORIZONTAL) {
                    axisid = "x";
                    if (haxisCount > 0) {
                        axisid += haxisCount;
                    }
                    haxisCount++;
                } else if (this.axes().at(i).orientation() === ns.Axis.VERTICAL) {
                    axisid = "y";
                    if (vaxisCount > 0) {
                        axisid += vaxisCount;
                    }
                    vaxisCount++;
                }

                if (this.axes().at(i).id() === undefined) {
                    this.axes().at(i).id(axisid);
                }
            }

            //
            // normalizes the rest of the axis properties
            //
            for (i = 0; i < this.axes().size(); i++) {
                this.axes().at(i).normalize(this);
            }

            //
            // handles missing plot tags
            //
            if (this.plots().size() === 0) {
                this.plots().add(new ns.DataPlot());
            }

            //
            // normalizes the plots
            //
            for (i = 0; i < this.plots().size(); i++) {
                var p = this.plots().at(i);
                this.plots().at(i).normalize(this);
            }

            //
            // execute the setDataRange method for each axis binding, to sync up all axes
            // that participate in the binding (this takes care of setting dataMin/dataMax
            // for any axes that don't have them already but which are bound to axes that
            // do have them)
            //
            ns.AxisBinding.syncAllBindings();

            //
            // arrange to set missing axis min/max values when data is ready, if necessary
            //
            for (i = 0; i < this.axes().size(); i++) {
                // for each axis...
                axis = this.axes().at(i);
                if (!axis.hasDataMin() || axis.hasDataMax()) {
                    // if this axis is mising either a dataMin() or dataMax() value...
                    for (j=0; j < this.plots().size(); ++j) {
                        // find a DataPlot that references this axis...
                        plot = this.plots().at(j);
                        if (plot instanceof ns.DataPlot && (plot.horizontalaxis() === axis || plot.verticalaxis() === axis)) {
                            // ... and then register a dataReady listener for this plot's data section which sets the
                            // missing bound(s) on the axis once the data is ready.  Do this inside a closure so that we
                            // can refer to a pointer to our dynamically-defined listener function from inside itself,
                            // so that we can de-register it once it is called; this is done via the the local variable
                            // axisBoundsSetter.  The closure also serves to capture the current values, via arguments,
                            // of the axis pointer, a pointer to the data object, and a boolean (isHorizontal) that
                            // indicates whether the axis is the plot's horizontal or vertical axis.
                            (function(axis, data, isHorizontal) {
                                var axisBoundsSetter = function(event) {
                                    var columnNumber = isHorizontal ? 0 : 1,
                                        bounds = data.getBounds(columnNumber),
                                        min = axis.dataMin(),
                                        max = axis.dataMax();
                                    if (!axis.hasDataMin()) {
                                        min = bounds[0];
                                    }
                                    if (!axis.hasDataMax()) {
                                        max = bounds[1];
                                    }
                                    if (!axis.hasDataMin() || !axis.hasDataMax()) {
                                        axis.setDataRange(min, max);
                                    }
                                    data.removeListener('dataReady', axisBoundsSetter);
                                };
                                data.addListener('dataReady', axisBoundsSetter);
                            }(axis,                             // axis
                              plot.data(),                      // data
                              plot.horizontalaxis() === axis    // isHorizontal
                             ));
                            break; // for (j=0; j < this.plots().size(); ++j)...
                        }
                    }
                }
            }

        });

    });

});
<commit_msg>bugfix in graph normalizer<commit_after>window.multigraph.util.namespace("window.multigraph.normalizer", function (ns) {
    "use strict";

    ns.mixin.add(function (ns) {

        ns.Graph.respondsTo("normalize", function () {
            var i, j,
                haxisCount = 0,
                vaxisCount = 0,
                axis,
                axisid,
                plot;

            //
            // normalizes the data sections
            //
            for (i = 0; i < this.data().size(); i++) {
                this.data().at(i).normalize();
            }

            //
            // Handles missing horizontalaxis and vertical axis tags
            //
            for (i = 0; i < this.axes().size(); i++) {
                if (this.axes().at(i).orientation() === ns.Axis.HORIZONTAL) {
                    haxisCount++;
                } else if (this.axes().at(i).orientation() === ns.Axis.VERTICAL) {
                    vaxisCount++;
                }
            }

            if (haxisCount === 0) {
                this.axes().add(new ns.Axis(ns.Axis.HORIZONTAL));
            }
            if (vaxisCount === 0) {
                this.axes().add(new ns.Axis(ns.Axis.VERTICAL));
            }

            //
            // Handles missing id's for axes
            //
            haxisCount = 0;
            vaxisCount = 0;
            for (i = 0; i < this.axes().size(); i++) {
                if (this.axes().at(i).orientation() === ns.Axis.HORIZONTAL) {
                    axisid = "x";
                    if (haxisCount > 0) {
                        axisid += haxisCount;
                    }
                    haxisCount++;
                } else if (this.axes().at(i).orientation() === ns.Axis.VERTICAL) {
                    axisid = "y";
                    if (vaxisCount > 0) {
                        axisid += vaxisCount;
                    }
                    vaxisCount++;
                }

                if (this.axes().at(i).id() === undefined) {
                    this.axes().at(i).id(axisid);
                }
            }

            //
            // normalizes the rest of the axis properties
            //
            for (i = 0; i < this.axes().size(); i++) {
                this.axes().at(i).normalize(this);
            }

            //
            // handles missing plot tags
            //
            if (this.plots().size() === 0) {
                this.plots().add(new ns.DataPlot());
            }

            //
            // normalizes the plots
            //
            for (i = 0; i < this.plots().size(); i++) {
                var p = this.plots().at(i);
                this.plots().at(i).normalize(this);
            }

            //
            // execute the setDataRange method for each axis binding, to sync up all axes
            // that participate in the binding (this takes care of setting dataMin/dataMax
            // for any axes that don't have them already but which are bound to axes that
            // do have them)
            //
            ns.AxisBinding.syncAllBindings();

            //
            // arrange to set missing axis min/max values when data is ready, if necessary
            //
            for (i = 0; i < this.axes().size(); i++) {
                // for each axis...
                axis = this.axes().at(i);
                if (!axis.hasDataMin() || !axis.hasDataMax()) {
                    // if this axis is mising either a dataMin() or dataMax() value...
                    for (j=0; j < this.plots().size(); ++j) {
                        // find a DataPlot that references this axis...
                        plot = this.plots().at(j);
                        if (plot instanceof ns.DataPlot && (plot.horizontalaxis() === axis || plot.verticalaxis() === axis)) {
                            // ... and then register a dataReady listener for this plot's data section which sets the
                            // missing bound(s) on the axis once the data is ready.  Do this inside a closure so that we
                            // can refer to a pointer to our dynamically-defined listener function from inside itself,
                            // so that we can de-register it once it is called; this is done via the the local variable
                            // axisBoundsSetter.  The closure also serves to capture the current values, via arguments,
                            // of the axis pointer, a pointer to the data object, and a boolean (isHorizontal) that
                            // indicates whether the axis is the plot's horizontal or vertical axis.
                            (function(axis, data, isHorizontal) {
                                var axisBoundsSetter = function(event) {
                                    var columnNumber = isHorizontal ? 0 : 1,
                                        bounds = data.getBounds(columnNumber),
                                        min = axis.dataMin(),
                                        max = axis.dataMax();
                                    if (!axis.hasDataMin()) {
                                        min = bounds[0];
                                    }
                                    if (!axis.hasDataMax()) {
                                        max = bounds[1];
                                    }
                                    if (!axis.hasDataMin() || !axis.hasDataMax()) {
                                        axis.setDataRange(min, max);
                                    }
                                    data.removeListener('dataReady', axisBoundsSetter);
                                };
                                data.addListener('dataReady', axisBoundsSetter);
                            }(axis,                             // axis
                              plot.data(),                      // data
                              plot.horizontalaxis() === axis    // isHorizontal
                             ));
                            break; // for (j=0; j < this.plots().size(); ++j)...
                        }
                    }
                }
            }

        });

    });

});
<|endoftext|>


<commit_before>EZ3.Geometry = function(data) {

  this._uv = [];
  this._indices = [];
  this._normals = [];
  this._vertices = [];
  this._tangents = [];
  this._binormals = [];
  this._maxPoint = vec3.create();
  this._minPoint = vec3.create();
  this._midPoint = vec3.create();

  this.PI = Math.PI;
  this.HALF_PI = this.PI / 2.0;
  this.DOUBLE_PI = 2.0 * this.PI;

};

EZ3.Geometry.prototype.initArray = function(size, value) {

  return Array.apply(null, new Array(size)).map(function() {
    return value;
  });

};

EZ3.Geometry.prototype.calculateNormals = function() {

  var x, y, z, k;
  var normal, point0, point1, point2, vector0, vector1;

  var temporalNormals = initArray(this.vertices.length, 0);
  var temporalAppearances = initArray(this.vertices.length / 3, 0);

  for(k = 0; k < this._indices.length; k += 3) {

    x = 3 * this._indices[k + 0];
    y = 3 * this._indices[k + 1];
    z = 3 * this._indices[k + 2];

    point0 = vec3.create(this.vertices[x + 0], this.vertices[x + 1], this.vertices[x + 2]);
    point1 = vec3.create(this.vertices[y + 0], this.vertices[y + 1], this.vertices[y + 2]);
    point2 = vec3.create(this.vertices[z + 0], this.vertices[z + 1], this.vertices[z + 2]);

    vec3.subtract(vector0, point1, point0);
    vec3.subtract(vector1, point2, point0);

    vec3.cross(normal, vector0, vector1);

    if(normal.x !== 0 || normal.y !== 0 || normal.z !== 0) {
      vec3.normalize(normal, normal);
    }

    temporalNormals[x + 0] += normal[0];
    temporalNormals[x + 1] += normal[1];
    temporalNormals[x + 2] += normal[2];

    temporalNormals[y + 0] += normal[0];
    temporalNormals[y + 1] += normal[1];
    temporalNormals[y + 2] += normal[2];

    temporalNormals[z + 0] += normal[0];
    temporalNormals[z + 1] += normal[1];
    temporalNormals[z + 2] += normal[2];

    ++temporalAppearances[x / 3];
    ++temporalAppearances[y / 3];
    ++temporalAppearances[z / 3];

  }

  for(k = 0; k < this._vertices.length / 3; ++k){

    x = 3 * k + 0;
    y = 3 * k + 1;
    z = 3 * k + 2;

    this._normals.push(temporalNormals[x] / temporalAppearances[k]);
    this._normals.push(temporalNormals[y] / temporalAppearances[k]);
    this._normals.push(temporalNormals[z] / temporalAppearances[k]);

  }

  temporalNormals.splice(0, temporalNormals.length);
  temporalAppearances.splice(0, temporalAppearances.length);

};

EZ3.Geometry.prototype.updateMaxPoint = function(x, y, z) {

  this._maxPoint[0] = Math.max(this._maxPoint[0], x);
  this._maxPoint[1] = Math.max(this._maxPoint[1], y);
  this._maxPoint[2] = Math.max(this._maxPoint[2], z);

};

EZ3.Geometry.prototype.updateMinPoint = function(x, y, z) {

  this._minPoint[0] = Math.min(this._minPoint[0], x);
  this._minPoint[1] = Math.min(this._minPoint[1], y);
  this._minPoint[2] = Math.min(this._minPoint[2], z);

};

EZ3.Geometry.prototype.calculateMidPoint = function () {

  this._midPoint[0] = (this._maxPoint[0] + this._minPoint[0]) * 0.5;
  this._midPoint[0] = (this._maxPoint[1] + this._minPoint[1]) * 0.5;
  this._midPoint[0] = (this._maxPoint[2] + this._minPoint[2]) * 0.5;

};

EZ3.Geometry.prototype.calculateTangents = function() {

};

EZ3.Geometry.prototype.calculateBoundingBox = function() {

};
<commit_msg>Updated Geometry.js<commit_after>EZ3.Geometry = function() {

  this._uv = [];
  this._indices = [];
  this._normals = [];
  this._vertices = [];
  this._tangents = [];
  this._binormals = [];
  this._maxPoint = vec3.create();
  this._minPoint = vec3.create();
  this._midPoint = vec3.create();

};

EZ3.Geometry.PI = Math.PI;
EZ3.Geometry.HALF_PI = 0.5 * Math.PI;
EZ3.Geometry.DOUBLE_PI = 2.0 * Math.PI;

EZ3.Geometry.prototype.initArray = function(size, value) {

  return Array.apply(null, new Array(size)).map(function() {
    return value;
  });

};

EZ3.Geometry.prototype.calculateNormals = function() {

  var x, y, z, k;
  var normal, point0, point1, point2, vector0, vector1;

  var temporalNormals = this.initArray(this.vertices.length, 0);
  var temporalAppearances = this.initArray(this.vertices.length / 3, 0);

  for(k = 0; k < this._indices.length; k += 3) {

    x = 3 * this._indices[k + 0];
    y = 3 * this._indices[k + 1];
    z = 3 * this._indices[k + 2];

    point0 = vec3.create(this.vertices[x + 0], this.vertices[x + 1], this.vertices[x + 2]);
    point1 = vec3.create(this.vertices[y + 0], this.vertices[y + 1], this.vertices[y + 2]);
    point2 = vec3.create(this.vertices[z + 0], this.vertices[z + 1], this.vertices[z + 2]);

    vec3.subtract(vector0, point1, point0);
    vec3.subtract(vector1, point2, point0);

    vec3.cross(normal, vector0, vector1);

    if(normal.x !== 0 || normal.y !== 0 || normal.z !== 0) {
      vec3.normalize(normal, normal);
    }

    temporalNormals[x + 0] += normal[0];
    temporalNormals[x + 1] += normal[1];
    temporalNormals[x + 2] += normal[2];

    temporalNormals[y + 0] += normal[0];
    temporalNormals[y + 1] += normal[1];
    temporalNormals[y + 2] += normal[2];

    temporalNormals[z + 0] += normal[0];
    temporalNormals[z + 1] += normal[1];
    temporalNormals[z + 2] += normal[2];

    ++temporalAppearances[x / 3];
    ++temporalAppearances[y / 3];
    ++temporalAppearances[z / 3];

  }

  for(k = 0; k < this._vertices.length / 3; ++k){

    x = 3 * k + 0;
    y = 3 * k + 1;
    z = 3 * k + 2;

    this._normals.push(temporalNormals[x] / temporalAppearances[k]);
    this._normals.push(temporalNormals[y] / temporalAppearances[k]);
    this._normals.push(temporalNormals[z] / temporalAppearances[k]);

  }

  temporalNormals.splice(0, temporalNormals.length);
  temporalAppearances.splice(0, temporalAppearances.length);

};

EZ3.Geometry.prototype.updateMaxPoint = function(x, y, z) {

  this._maxPoint[0] = Math.max(this._maxPoint[0], x);
  this._maxPoint[1] = Math.max(this._maxPoint[1], y);
  this._maxPoint[2] = Math.max(this._maxPoint[2], z);

};

EZ3.Geometry.prototype.updateMinPoint = function(x, y, z) {

  this._minPoint[0] = Math.min(this._minPoint[0], x);
  this._minPoint[1] = Math.min(this._minPoint[1], y);
  this._minPoint[2] = Math.min(this._minPoint[2], z);

};

EZ3.Geometry.prototype.calculateMidPoint = function () {

  this._midPoint[0] = (this._maxPoint[0] + this._minPoint[0]) * 0.5;
  this._midPoint[0] = (this._maxPoint[1] + this._minPoint[1]) * 0.5;
  this._midPoint[0] = (this._maxPoint[2] + this._minPoint[2]) * 0.5;

};

EZ3.Geometry.prototype.calculateTangents = function() {

};

EZ3.Geometry.prototype.calculateBoundingBox = function() {

};
<|endoftext|>


<commit_before>/**
 * Created by apizzimenti on 5/19/16.
 */

"use strict";

/**
 * @author Anthony Pizzimenti
 *
 * @desc Creates the game Inventory.
 *
 * @param game {object} Current game instance.
 * @param width {number} Phaser game window width.
 * @param height {number} Phaser game window height.
 * @param mouse {Mouse} Mouse object.
 * @param escape {object} Phaser key object.
 * @param itemGroup {object} Phaser Isometric sprite group.
 * @param map {Map} Game's Map object.
 *
 * @property game {object} Current game instance.
 * @property map {Map} Game's Map object.
 * @property width {number} Game window width.
 * @property height {number} Game window height.
 * @property mouse {Mouse} Mouse object.
 * @property escape {object} Phaser escape key.
 * @property messages {Message} Message object.
 * @property times {number} Number of times tooltips have been viewed.
 * @property menuGroup {object} Menu sprite group.
 * @property itemGroup {object} Isometric sprite group.
 *
 * @property area {object} Total space allocated to Inventory module.
 * @property area.width {number} Width of Inventory module space.
 * @property area.height {number} Height of Inventory module space.
 *
 * @property element {object} Total space allocated to each Inventory item.
 * @property element.width {number} Width of each Inventory item.
 * @property element.height {number} Height of each Inventory item.
 *
 * @property sprites {object[]} Inventory item objects.
 *
 * @class {object} Inventory
 * @this Inventory
 * @constructor
 *
 * @todo implement tooltip stuff.
 */

function Inventory (game, map, width, height, mouse, escape, itemGroup) {

    this.game = game;
    this.width = width;
    this.height = height;
    this.mouse = mouse;
    this.escape = escape;
    this.times = 0;
    this.map = map;

    this.items = [];
    this.itemsRow = [];

    var graphics = game.add.graphics(0, 0),
        menuGroup = game.add.group(),
        areaWidth = 260,
        areaHeight = 300,
        elementWidth = 65,
        elementHeight = 60;

    this.i = areaHeight;
    this.j = areaWidth;

    menuGroup.fixedToCamera = true;
    menuGroup.enableBody = true;
    this.menuGroup = menuGroup;
    this.itemGroup = itemGroup;

    graphics.fixedToCamera = true;
    graphics.lineStyle(2, 0xFF0000, 1);
    graphics.beginFill(0xFF0000, 0.4);
    graphics.drawRect(width - areaWidth, height - areaHeight, areaWidth, areaHeight);
    this.graphics = graphics;

    this.area = {};
    this.area.width = areaWidth;
    this.area.height = areaHeight;

    this.element = {};
    this.element.width = elementWidth;
    this.element.height = elementHeight;

    window.graphics = graphics;

    this.messages = new Message(this.game, this.height, 14);
    this.contextMenu = new ContextMenu(this);

    this.onClick();
}

/**
 * @author Anthony Pizzimenti
 *
 * @desc Adds an item to the inventory.
 *
 * @param item {Item} Item to be added.
 */

Inventory.prototype.addItem = function (item) {

    var w = this.element.width,
        h = this.element.height,
        x = this.width - this.j,
        y = this.height - this.i,
        name = item.key;

    item.inventorySprite = this.game.add.sprite(x, y, item.key, null, this.menuGroup);
    item.inventorySprite.width = w;
    item.inventorySprite.height = h;

    item.inventorySprite.row = (this.area.height - this.i) / h;
    item.inventorySprite.col = (this.area.width - this.j) / w;

    item.inventorySprite.inputEnabled = true;
    item.inventorySprite.input.useHandCursor = true;

    item.text = this.game.add.text(x, y, name, {
        font: "Courier",
        fontSize: 12,
        fill: "white"
    });

    item.text.fixedToCamera = true;

    this.j -= w;
    this.itemsRow.push(item);
    this.items[item.inventorySprite.row] = this.itemsRow;
    this.count++;

    if (this.j === 0) {

        this.count = 0;
        this.i -= h;
        this.j = this.area.width;
        this.items[item.inventorySprite.row + 1] = [];
        this.itemsRow = [];
    } else if (this.i === 0) {
        throw new RangeError("Number of sprites exceeds the number of available tiles.");
    }
};

/**
 * @author Anthony Pizzimenti
 *
 * @desc Loads an array of Items into the Inventory.
 *
 * @param items {Item[]} Array of Items to be loaded.
 *
 * @this Inventory
 *
 * @see Item
 * @see Loader#items
 */

Inventory.prototype.addItems = function (items) {

    if (!Array.isArray(items)) {
        throw new Error("Use addItem for single items.");
    } else {
        items.forEach((item) => {
            this.addItem(item);
        })
    }
};

/**
 * @author Anthony Pizzimenti
 *
 * @desc Handles clicks and escape keydowns.
 *
 * @this Inventory
 *
 * @see{@link Mouse}
 */

Inventory.prototype.onClick = function () {

    var that = this;
    this.game.input.onDown.add(() => {
        if (that.mouse.switch) {
            that.placeItem();
        } else {
            that.click();
        }
    }, that);

    this.escape.onDown.add(() => {
        this.mouse.switch = false;
        this.mouse.reset();
        this.reset();
    });
};

/**
 * @author Anthony Pizzimenti
 *
 * @desc Alters Inventory items when they are clicked on.
 *
 * @this Inventory
 */

Inventory.prototype.click = function () {

    var _this = this;

    this.game.canvas.oncontextmenu = function (e) {
        e.preventDefault();
        _this.contextMenu.createContextMenu();
    };

    var cornerX = this.width - this.area.width,
        cornerY = this.height - this.area.height,
        relativeX = this.mouse.twoD.x - cornerX,
        relativeY = this.mouse.twoD.y - cornerY;

    if (this.mouse.twoD.x > cornerX && this.mouse.twoD.y > cornerY) {

        var col = Math.floor(relativeX / this.element.width),
            row = Math.floor(relativeY / this.element.height),
            item;

        if (this.items[row][col]) {

            item = this.items[row][col];

            if (this.currentItem) {
                this.currentItem.inventorySprite.tint = 0xFFFFFF;
                this.currentItem.inventorySprite.clicked = false;
                this.currentItem.inventorySprite.useHandCursor = true;
            }

            this.mouse.switch = true;
            item.inventorySprite.clicked = true;
            item.inventorySprite.tint = 0xFFDD00;
            item.text.tint = 0xFFDD00;

            this.currentItem = item;
        }
    }

};

/**
 * @author Anthony Pizzimenti
 *
 * @desc Resets all Inventory sprites.
 *
 * @this Inventory
 */

Inventory.prototype.reset = function () {

    this.menuGroup.forEach((item) => {
        item.input.useHandCursor = true;
        item.tint = 0xFFFFFF;

        if (item.clicked) {
            item.clicked = false;
        }
    })
};

/**
 * @author Anthony Pizzimenti
 *
 * @desc If this.mouse is in selected mode, on mousedown, add a sprite if that tile is discovered. Otherwise,
 * display a "you can't do that" message.
 *
 * @this Inventory
 */

Inventory.prototype.placeItem = function () {

    var tileSize = this.mouse.map.tileSize,
        x = this.mouse.threeD.x - (this.mouse.threeD.x % tileSize),
        y = this.mouse.threeD.y - (this.mouse.threeD.y % tileSize),
        item = this.currentItem,
        key = item.key,
        tile = this.mouse.tile,
        message = `Sorry, you can't place the ${key} there. Choose a place that you've already seen!`,
        row,
        col;

    if (tile.discovered && isInBounds(this.mouse)) {

        row = item.inventorySprite.row;
        col = item.inventorySprite.col;

        item.sprite = this.game.add.isoSprite(x, y, 0, key, null, this.itemGroup);
        item.threeDInitialize();

        item.action();
        item.inventorySprite.destroy();
        item.text.destroy();

        this.items[row][col] = null;
        this.mouse.reset();
        this.mouse.switch = false;

    } else {
        this.messages.add(message)
    }
};
<commit_msg>change context<commit_after>/**
 * Created by apizzimenti on 5/19/16.
 */

"use strict";

/**
 * @author Anthony Pizzimenti
 *
 * @desc Creates the game Inventory.
 *
 * @param game {object} Current game instance.
 * @param width {number} Phaser game window width.
 * @param height {number} Phaser game window height.
 * @param mouse {Mouse} Mouse object.
 * @param escape {object} Phaser key object.
 * @param itemGroup {object} Phaser Isometric sprite group.
 * @param map {Map} Game's Map object.
 *
 * @property game {object} Current game instance.
 * @property map {Map} Game's Map object.
 * @property width {number} Game window width.
 * @property height {number} Game window height.
 * @property mouse {Mouse} Mouse object.
 * @property escape {object} Phaser escape key.
 * @property messages {Message} Message object.
 * @property times {number} Number of times tooltips have been viewed.
 * @property menuGroup {object} Menu sprite group.
 * @property itemGroup {object} Isometric sprite group.
 *
 * @property area {object} Total space allocated to Inventory module.
 * @property area.width {number} Width of Inventory module space.
 * @property area.height {number} Height of Inventory module space.
 *
 * @property element {object} Total space allocated to each Inventory item.
 * @property element.width {number} Width of each Inventory item.
 * @property element.height {number} Height of each Inventory item.
 *
 * @property sprites {object[]} Inventory item objects.
 *
 * @class {object} Inventory
 * @this Inventory
 * @constructor
 *
 * @todo implement tooltip stuff.
 */

function Inventory (game, map, width, height, mouse, escape, itemGroup) {

    this.game = game;
    this.width = width;
    this.height = height;
    this.mouse = mouse;
    this.escape = escape;
    this.times = 0;
    this.map = map;

    this.items = [];
    this.itemsRow = [];

    var graphics = game.add.graphics(0, 0),
        menuGroup = game.add.group(),
        areaWidth = 260,
        areaHeight = 300,
        elementWidth = 65,
        elementHeight = 60;

    this.i = areaHeight;
    this.j = areaWidth;

    menuGroup.fixedToCamera = true;
    menuGroup.enableBody = true;
    this.menuGroup = menuGroup;
    this.itemGroup = itemGroup;

    graphics.fixedToCamera = true;
    graphics.lineStyle(2, 0xFF0000, 1);
    graphics.beginFill(0xFF0000, 0.4);
    graphics.drawRect(width - areaWidth, height - areaHeight, areaWidth, areaHeight);
    this.graphics = graphics;

    this.area = {};
    this.area.width = areaWidth;
    this.area.height = areaHeight;

    this.element = {};
    this.element.width = elementWidth;
    this.element.height = elementHeight;

    window.graphics = graphics;

    this.messages = new Message(this.game, this.height, 14);
    this.contextMenu = new ContextMenu(this);

    this.onClick();
}

/**
 * @author Anthony Pizzimenti
 *
 * @desc Adds an item to the inventory.
 *
 * @param item {Item} Item to be added.
 */

Inventory.prototype.addItem = function (item) {

    var w = this.element.width,
        h = this.element.height,
        x = this.width - this.j,
        y = this.height - this.i,
        name = item.key;

    item.inventorySprite = this.game.add.sprite(x, y, item.key, null, this.menuGroup);
    item.inventorySprite.width = w;
    item.inventorySprite.height = h;

    item.inventorySprite.row = (this.area.height - this.i) / h;
    item.inventorySprite.col = (this.area.width - this.j) / w;

    item.inventorySprite.inputEnabled = true;
    item.inventorySprite.input.useHandCursor = true;

    item.text = this.game.add.text(x, y, name, {
        font: "Courier",
        fontSize: 12,
        fill: "white"
    });

    item.text.fixedToCamera = true;

    this.j -= w;
    this.itemsRow.push(item);
    this.items[item.inventorySprite.row] = this.itemsRow;
    this.count++;

    if (this.j === 0) {

        this.count = 0;
        this.i -= h;
        this.j = this.area.width;
        this.items[item.inventorySprite.row + 1] = [];
        this.itemsRow = [];
    } else if (this.i === 0) {
        throw new RangeError("Number of sprites exceeds the number of available tiles.");
    }
};

/**
 * @author Anthony Pizzimenti
 *
 * @desc Loads an array of Items into the Inventory.
 *
 * @param items {Item[]} Array of Items to be loaded.
 *
 * @this Inventory
 *
 * @see Item
 * @see Loader#items
 */

Inventory.prototype.addItems = function (items) {

    if (!Array.isArray(items)) {
        throw new Error("Use addItem for single items.");
    } else {
        items.forEach((item) => {
            this.addItem(item);
        })
    }
};

/**
 * @author Anthony Pizzimenti
 *
 * @desc Handles clicks and escape keydowns.
 *
 * @this Inventory
 *
 * @see{@link Mouse}
 */

Inventory.prototype.onClick = function () {

    this.game.input.onDown.add(() => {
        if (this.mouse.switch) {
            this.placeItem();
        } else {
            this.click();
        }
    });

    this.escape.onDown.add(() => {
        this.mouse.switch = false;
        this.mouse.reset();
        this.reset();
    });
};

/**
 * @author Anthony Pizzimenti
 *
 * @desc Alters Inventory items when they are clicked on.
 *
 * @this Inventory
 */

Inventory.prototype.click = function () {

    var _this = this;

    this.game.canvas.oncontextmenu = function (e) {
        e.preventDefault();
        _this.contextMenu.createContextMenu();
    };

    var cornerX = this.width - this.area.width,
        cornerY = this.height - this.area.height,
        relativeX = this.mouse.twoD.x - cornerX,
        relativeY = this.mouse.twoD.y - cornerY;

    if (this.mouse.twoD.x > cornerX && this.mouse.twoD.y > cornerY) {

        var col = Math.floor(relativeX / this.element.width),
            row = Math.floor(relativeY / this.element.height),
            item;

        if (this.items[row][col]) {

            item = this.items[row][col];

            if (this.currentItem) {
                this.currentItem.inventorySprite.tint = 0xFFFFFF;
                this.currentItem.inventorySprite.clicked = false;
                this.currentItem.inventorySprite.useHandCursor = true;
            }

            this.mouse.switch = true;
            item.inventorySprite.clicked = true;
            item.inventorySprite.tint = 0xFFDD00;
            item.text.tint = 0xFFDD00;

            this.currentItem = item;
        }
    }

};

/**
 * @author Anthony Pizzimenti
 *
 * @desc Resets all Inventory sprites.
 *
 * @this Inventory
 */

Inventory.prototype.reset = function () {

    this.menuGroup.forEach((item) => {
        item.input.useHandCursor = true;
        item.tint = 0xFFFFFF;

        if (item.clicked) {
            item.clicked = false;
        }
    })
};

/**
 * @author Anthony Pizzimenti
 *
 * @desc If this.mouse is in selected mode, on mousedown, add a sprite if that tile is discovered. Otherwise,
 * display a "you can't do that" message.
 *
 * @this Inventory
 */

Inventory.prototype.placeItem = function () {

    var tileSize = this.mouse.map.tileSize,
        x = this.mouse.threeD.x - (this.mouse.threeD.x % tileSize),
        y = this.mouse.threeD.y - (this.mouse.threeD.y % tileSize),
        item = this.currentItem,
        key = item.key,
        tile = this.mouse.tile,
        message = `Sorry, you can't place the ${key} there. Choose a place that you've already seen!`,
        row,
        col;

    if (tile.discovered && isInBounds(this.mouse)) {

        row = item.inventorySprite.row;
        col = item.inventorySprite.col;

        item.sprite = this.game.add.isoSprite(x, y, 0, key, null, this.itemGroup);
        item.threeDInitialize();

        item.action();
        item.inventorySprite.destroy();
        item.text.destroy();

        this.items[row][col] = null;
        this.mouse.reset();
        this.mouse.switch = false;

    } else {
        this.messages.add(message)
    }
};
<|endoftext|>