/* qwebirc -- Copyright (C) 2008-2009 Chris Porter --- All rights reserved. */

var qwebirc = 
{
	ui: 
	{
		themes: {}
	},
	irc: {},
	util: 
	{
		crypto: {}
	},
	config: {},
	auth: {},
	sound: {}
};
qwebirc.VERSION = "0.85";
Array.prototype.indexFromEnd = function(B)
{
	var A = this;
	if (B < 0) 
	{
		return A[A.length + B]
	}
	return A[B]
};
qwebirc.util.dictCopy = function(B)
{
	var C = {};
	for (var A in B) 
	{
		C[A] = B[A]
	}
	return C
};
String.prototype.replaceAll = function(C, B)
{
	var A = this.indexOf(C);
	var D = this;
	while (A > -1) 
	{
		D = D.replace(C, B);
		A = D.indexOf(C)
	}
	return D
};
String.prototype.splitMax = function(D, A)
{
	var B = this.split(D);
	var C = B.slice(0, A - 1);
	if (B.length >= A) 
	{
		C.push(B.slice(A - 1).join(D))
	}
	return C
};
qwebirc.util.parseURI = function(D)
{
	var F = {};
	var G = D.indexOf("?");
	if (G == -1) 
	{
		return F
	}
	var E = D.substring(G + 1);
	var A = E.split("&");
	for (var B = 0; B < A.length; B++) 
	{
		var C = A[B].splitMax("=", 2);
		if (C.length < 2) 
		{
			continue
		}
		F[unescape(C[0])] = unescape(C[1])
	}
	return F
};
qwebirc.util.DaysOfWeek = 
{
	0: "Sun",
	1: "Mon",
	2: "Tue",
	3: "Wed",
	4: "Thu",
	5: "Fri",
	6: "Sat"
};
qwebirc.util.MonthsOfYear = 
{
	0: "Jan",
	1: "Feb",
	2: "Mar",
	3: "Apr",
	4: "May",
	5: "Jun",
	6: "Jul",
	7: "Aug",
	8: "Sep",
	9: "Oct",
	10: "Nov",
	11: "Dec"
};
qwebirc.util.NBSPCreate = function(F, B)
{
	var E = F.split("  ");
	for (var C = 0; C < E.length; C++) 
	{
		var A = document.createTextNode(E[C]);
		B.appendChild(A);
		if (C != E.length - 1) 
		{
			var D = new Element("span");
			D.set("html", "&nbsp;&nbsp;");
			B.appendChild(D)
		}
	}
};
qwebirc.util.longtoduration = function(B)
{
	var D = B % 60;
	var C = Math.floor((B % 3600) / 60);
	var A = Math.floor((B % (3600 * 24)) / 3600);
	var E = Math.floor(B / (24 * 3600));
	return E + " days " + A + " hours " + C + " minutes " + D + " seconds"
};
qwebirc.util.pad = function(A)
{
	A = "" + A;
	if (A.length == 1) 
	{
		return "0" + A
	}
	return A
};
RegExp.escape = function(B)
{
	if (!arguments.callee.sRE) 
	{
		var A = ["/", ".", "*", "+", "?", "|", "(", ")", "[", "]", "{", "}", "\\"];
		arguments.callee.sRE = new RegExp("(\\" + A.join("|\\") + ")", "g")
	}
	return B.replace(arguments.callee.sRE, "\\$1")
};
qwebirc.ui.insertAt = function(A, B, C)
{
	if (!B.childNodes || (A >= B.childNodes.length)) 
	{
		B.appendChild(C)
	}
	else 
	{
		B.insertBefore(C, B.childNodes[A])
	}
};
qwebirc.util.setCaretPos = function(B, C)
{
	if ($defined(B.selectionStart)) 
	{
		B.focus();
		B.setSelectionRange(C, C)
	}
	else 
	{
		if (B.createTextRange) 
		{
			var A = B.createTextRange();
			A.move("character", C);
			A.select()
		}
	}
};
qwebirc.util.setAtEnd = function(A)
{
	qwebirc.util.setCaretPos(A.value.length)
};
qwebirc.util.getCaretPos = function(A)
{
	if ($defined(A.selectionStart)) 
	{
		return A.selectionStart
	}
	if (document.selection) 
	{
		A.focus();
		var B = document.selection.createRange();
		B.moveStart("character", -A.value.length);
		return B.text.length
	}
};
qwebirc.util.browserVersion = function()
{
	return navigator.userAgent
};
qwebirc.util.getEnclosedWord = function(E, A)
{
	var B = E.split("");
	var C = [];
	if (E == "") 
	{
		return
	}
	var G = A - 1;
	if (G < 0) 
	{
		G = 0
	}
	else 
	{
		for (; G >= 0; G--) 
		{
			if (B[G] == " ") 
			{
				G = G + 1;
				break
			}
		}
	}
	if (G < 0) 
	{
		G = 0
	}
	var D = E.substring(G);
	var F = D.indexOf(" ");
	if (F != -1) 
	{
		D = D.substring(0, F)
	}
	return [G, D]
};
String.prototype.startsWith = function(A)
{
	return this.substring(0, A.length) == A
};
qwebirc.util.randHexString = function(D)
{
	var B = function()
	{
		return (((1 + Math.random()) * 256) | 0).toString(16).substring(1)
	};
	var A = [];
	for (var C = 0; C < D; C++) 
	{
		A.push(B())
	}
	return A.join("")
};
qwebirc.util.importJS = function(name, watchFor, onload)
{
	var script = document.createElement("script");
	script.type = "text/javascript";
	script.src = name;
	if (Browser.Engine.trident) 
	{
		var checkFn = function()
		{
			if (eval("typeof " + watchFor) != "undefined") 
			{
				onload()
			}
			else 
			{
				checkFn.delay(100)
			}
		};
		checkFn()
	}
	else 
	{
		script.onload = onload
	}
	document.getElementsByTagName("head")[0].appendChild(script)
};
qwebirc.util.createInput = function(D, A, B, C)
{
	var E;
	if (Browser.Engine.trident) 
	{
		if (B) 
		{
			B = ' name="' + escape(B) + '"'
		}
		else 
		{
			B = ""
		}
		E = $(document.createElement('<input type="' + D + '"' + B + " " + (C ? " checked" : "") + "/>"))
	}
	else 
	{
		E = new Element("input");
		E.type = D;
		if (B) 
		{
			E.name = B
		}
		if (C) 
		{
			E.checked = true
		}
	}
	A.appendChild(E);
	return E
};
qwebirc.util.b64Table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
qwebirc.util.b64Encode = function(B)
{
	var C = [];
	var I = qwebirc.util.b64Table;
	for (var A = 0; A < B.length;) 
	{
		var J = B.charCodeAt(A++);
		var H = B.charCodeAt(A++);
		var F = B.charCodeAt(A++);
		var K = J >> 2;
		var G = ((J & 3) << 4) | (H >> 4);
		var E = ((H & 15) << 2) | (F >> 6);
		var D = F & 63;
		if (isNaN(H)) 
		{
			E = D = 64
		}
		else 
		{
			if (isNaN(F)) 
			{
				D = 64
			}
		}
		C.push(I.charAt(K) + I.charAt(G) + I.charAt(E) + I.charAt(D))
	}
	return C.join("")
};
qwebirc.util.b64Decode = function(B)
{
	B = B.replace(/[^A-Za-z0-9\+\/\=]/g, "");
	var C = [];
	var H = qwebirc.util.b64Table;
	for (var A = 0; A < B.length;) 
	{
		var K = H.indexOf(B.charAt(A++));
		var I = H.indexOf(B.charAt(A++));
		var F = H.indexOf(B.charAt(A++));
		var D = H.indexOf(B.charAt(A++));
		var J = (K << 2) | (I >> 4);
		var G = ((I & 15) << 4) | (F >> 2);
		var E = ((F & 3) << 6) | D;
		C.push(String.fromCharCode(J));
		if (F != 64) 
		{
			C.push(String.fromCharCode(G))
		}
		if (D != 64) 
		{
			C.push(String.fromCharCode(E))
		}
	}
	return C.join("")
};
qwebirc.util.composeAnd = function()
{
	var A = arguments;
	return function()
	{
		for (var B = 0; B < A.length; B++) 
		{
			if (!A[B].apply(this, arguments)) 
			{
				return false
			}
		}
		return true
	}
};
qwebirc.util.invertFn = function(A)
{
	return function()
	{
		return !A.apply(this, arguments)
	}
};
qwebirc.util.deviceHasKeyboard = function()
{
	var B = function()
	{
		if (Browser.Engine.ipod) 
		{
			return true
		}
		var C = ["Nintendo Wii", " PIE", "BlackBerry", "IEMobile", "Windows CE", "Nokia", "Opera Mini", "Mobile", "mobile", "Pocket", "pocket", "Android"];
		var D = ["Chrome", "Firefox", "Camino", "Iceweasel", "K-Meleon", "Konqueror", "SeaMonkey", "Windows NT", "Windows 9"];
		var G = navigator.userAgent;
		var E = function(H)
		{
			return G.indexOf(H) > -1
		};
		for (var F = 0; F < C.length; F++) 
		{
			if (E(C[F])) 
			{
				return false
			}
		}
		for (var F = 0; F < D.length; F++) 
		{
			if (E(D[F])) 
			{
				return true
			}
		}
		return false
	};
	var A = B();
	qwebirc.util.deviceHasKeyboard = function()
	{
		return A
	};
	return A
};
qwebirc.util.crypto.getARC4Stream = function(H, E)
{
	var I = [];
	var F = [];
	for (var C = 0; C < H.length; C++) 
	{
		F.push(H.charCodeAt(C))
	}
	for (var C = 0; C < 256; C++) 
	{
		I[C] = C
	}
	var B = 0;
	for (var C = 0; C < 256; C++) 
	{
		B = (B + I[C] + F[C % H.length]) & 255;
		var G = I[C];
		I[C] = I[B];
		I[B] = G
	}
	var D = [];
	var C = 0;
	var B = 0;
	for (var A = 0; A < E; A++) 
	{
		C = (C + 1) & 255;
		B = (B + I[C]) & 255;
		var G = I[C];
		I[C] = I[B];
		I[B] = G;
		D.push(I[(I[C] + I[B]) & 255])
	}
	return D
};
qwebirc.util.crypto.xorStreams = function(C, D)
{
	if (C.length != D.length) 
	{
		return
	}
	var B = [];
	for (var A = 0; A < C.length; A++) 
	{
		B.push(String.fromCharCode(C.charCodeAt(A) ^ D[A]))
	}
	return B.join("")
};
qwebirc.util.crypto.ARC4 = function(A, B)
{
	var C = qwebirc.util.crypto.getARC4Stream(A, B.length + 1024);
	C = C.slice(1024);
	return qwebirc.util.crypto.xorStreams(B, C)
};
qwebirc.util.crypto.MD5 = function()
{
	this.digest = A;
	var G = "0123456789abcdef";
	function E(M)
	{
		var N = "";
		for (var L = 0; L <= 3; L++) 
		{
			N += G.charAt((M >> (L * 8 + 4)) & 15) + G.charAt((M >> (L * 8)) & 15)
		}
		return N
	}
	function F(N)
	{
		var L = ((N.length + 8) >> 6) + 1;
		var O = new Array(L * 16);
		for (var M = 0; M < L * 16; M++) 
		{
			O[M] = 0
		}
		for (var M = 0; M < N.length; M++) 
		{
			O[M >> 2] |= N.charCodeAt(M) << ((M % 4) * 8)
		}
		O[M >> 2] |= 128 << ((M % 4) * 8);
		O[L * 16 - 2] = N.length * 8;
		return O
	}
	function K(L, M)
	{
		return ((L & 2147483647) + (M & 2147483647)) ^ (L & 2147483648) ^ (M & 2147483648)
	}
	function D(L, M)
	{
		return (L << M) | (L >>> (32 - M))
	}
	function I(Q, N, M, L, P, O)
	{
		return K(D(K(K(N, Q), K(L, O)), P), M)
	}
	function B(N, M, R, Q, L, P, O)
	{
		return I((M & R) | ((~ M) & Q), N, M, L, P, O)
	}
	function H(N, M, R, Q, L, P, O)
	{
		return I((M & Q) | (R & (~ Q)), N, M, L, P, O)
	}
	function C(N, M, R, Q, L, P, O)
	{
		return I(M ^ R ^ Q, N, M, L, P, O)
	}
	function J(N, M, R, Q, L, P, O)
	{
		return I(R ^ (M | (~ Q)), N, M, L, P, O)
	}
	function A(R)
	{
		var U = F(R);
		var V = 1732584193;
		var T = 4023233417;
		var S = 2562383102;
		var Q = 271733878;
		for (var N = 0; N < U.length; N += 16) 
		{
			var P = V;
			var O = T;
			var M = S;
			var L = Q;
			V = B(V, T, S, Q, U[N + 0], 7, 3614090360);
			Q = B(Q, V, T, S, U[N + 1], 12, 3905402710);
			S = B(S, Q, V, T, U[N + 2], 17, 606105819);
			T = B(T, S, Q, V, U[N + 3], 22, 3250441966);
			V = B(V, T, S, Q, U[N + 4], 7, 4118548399);
			Q = B(Q, V, T, S, U[N + 5], 12, 1200080426);
			S = B(S, Q, V, T, U[N + 6], 17, 2821735955);
			T = B(T, S, Q, V, U[N + 7], 22, 4249261313);
			V = B(V, T, S, Q, U[N + 8], 7, 1770035416);
			Q = B(Q, V, T, S, U[N + 9], 12, 2336552879);
			S = B(S, Q, V, T, U[N + 10], 17, 4294925233);
			T = B(T, S, Q, V, U[N + 11], 22, 2304563134);
			V = B(V, T, S, Q, U[N + 12], 7, 1804603682);
			Q = B(Q, V, T, S, U[N + 13], 12, 4254626195);
			S = B(S, Q, V, T, U[N + 14], 17, 2792965006);
			T = B(T, S, Q, V, U[N + 15], 22, 1236535329);
			V = H(V, T, S, Q, U[N + 1], 5, 4129170786);
			Q = H(Q, V, T, S, U[N + 6], 9, 3225465664);
			S = H(S, Q, V, T, U[N + 11], 14, 643717713);
			T = H(T, S, Q, V, U[N + 0], 20, 3921069994);
			V = H(V, T, S, Q, U[N + 5], 5, 3593408605);
			Q = H(Q, V, T, S, U[N + 10], 9, 38016083);
			S = H(S, Q, V, T, U[N + 15], 14, 3634488961);
			T = H(T, S, Q, V, U[N + 4], 20, 3889429448);
			V = H(V, T, S, Q, U[N + 9], 5, 568446438);
			Q = H(Q, V, T, S, U[N + 14], 9, 3275163606);
			S = H(S, Q, V, T, U[N + 3], 14, 4107603335);
			T = H(T, S, Q, V, U[N + 8], 20, 1163531501);
			V = H(V, T, S, Q, U[N + 13], 5, 2850285829);
			Q = H(Q, V, T, S, U[N + 2], 9, 4243563512);
			S = H(S, Q, V, T, U[N + 7], 14, 1735328473);
			T = H(T, S, Q, V, U[N + 12], 20, 2368359562);
			V = C(V, T, S, Q, U[N + 5], 4, 4294588738);
			Q = C(Q, V, T, S, U[N + 8], 11, 2272392833);
			S = C(S, Q, V, T, U[N + 11], 16, 1839030562);
			T = C(T, S, Q, V, U[N + 14], 23, 4259657740);
			V = C(V, T, S, Q, U[N + 1], 4, 2763975236);
			Q = C(Q, V, T, S, U[N + 4], 11, 1272893353);
			S = C(S, Q, V, T, U[N + 7], 16, 4139469664);
			T = C(T, S, Q, V, U[N + 10], 23, 3200236656);
			V = C(V, T, S, Q, U[N + 13], 4, 681279174);
			Q = C(Q, V, T, S, U[N + 0], 11, 3936430074);
			S = C(S, Q, V, T, U[N + 3], 16, 3572445317);
			T = C(T, S, Q, V, U[N + 6], 23, 76029189);
			V = C(V, T, S, Q, U[N + 9], 4, 3654602809);
			Q = C(Q, V, T, S, U[N + 12], 11, 3873151461);
			S = C(S, Q, V, T, U[N + 15], 16, 530742520);
			T = C(T, S, Q, V, U[N + 2], 23, 3299628645);
			V = J(V, T, S, Q, U[N + 0], 6, 4096336452);
			Q = J(Q, V, T, S, U[N + 7], 10, 1126891415);
			S = J(S, Q, V, T, U[N + 14], 15, 2878612391);
			T = J(T, S, Q, V, U[N + 5], 21, 4237533241);
			V = J(V, T, S, Q, U[N + 12], 6, 1700485571);
			Q = J(Q, V, T, S, U[N + 3], 10, 2399980690);
			S = J(S, Q, V, T, U[N + 10], 15, 4293915773);
			T = J(T, S, Q, V, U[N + 1], 21, 2240044497);
			V = J(V, T, S, Q, U[N + 8], 6, 1873313359);
			Q = J(Q, V, T, S, U[N + 15], 10, 4264355552);
			S = J(S, Q, V, T, U[N + 6], 15, 2734768916);
			T = J(T, S, Q, V, U[N + 13], 21, 1309151649);
			V = J(V, T, S, Q, U[N + 4], 6, 4149444226);
			Q = J(Q, V, T, S, U[N + 11], 10, 3174756917);
			S = J(S, Q, V, T, U[N + 2], 15, 718787259);
			T = J(T, S, Q, V, U[N + 9], 21, 3951481745);
			V = K(V, P);
			T = K(T, O);
			S = K(S, M);
			Q = K(Q, L)
		}
		return E(V) + E(T) + E(S) + E(Q)
	}
};
qwebirc.irc.IRCConnection = new Class(
{
	Implements: [Events, Options],
	options: 
	{
		initialNickname: "ircconnX",
		timeout: 45000,
		floodInterval: 200,
		floodMax: 10,
		floodReset: 5000,
		errorAlert: true,
		maxRetries: 5,
		serverPassword: null
	},
	initialize: function(A)
	{
		this.setOptions(A);
		this.initialNickname = this.options.initialNickname;
		this.counter = 0;
		this.disconnected = false;
		this.__floodLastRequest = 0;
		this.__floodCounter = 0;
		this.__floodLastFlood = 0;
		this.__retryAttempts = 0;
		this.__timeoutId = null;
		this.__lastActiveRequest = null;
		this.__activeRequest = null
	},
	__error: function(A)
	{
		this.fireEvent("error", A);
		if (this.options.errorAlert) 
		{
			alert(A)
		}
	},
	newRequest: function(A, C)
	{
		if (this.disconnected) 
		{
			return null
		}
		if (C && !this.disconnected && this.__isFlooding()) 
		{
			this.disconnect();
			this.__error("BUG: uncontrolled flood detected -- disconnected.")
		}
		var B = new Request.JSON(
		{
			url: "lib/php/wrapReq.php?page=" + A + "&r=" + this.cacheAvoidance + "&t=" + this.counter++
		});
		B.headers = new Hash;
		B.addEvent("request", function()
		{
			var D = function(E, F)
			{
				try 
				{
					this.setRequestHeader(E, F)
				} 
				catch (G) 
				{
				}
			}
.bind(this);
			D("User-Agent", null);
			D("Accept", null);
			D("Accept-Language", null)
		}
.bind(B.xhr));
		if (Browser.Engine.trident) 
		{
			B.setHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT")
		}
		return B
	},
	__isFlooding: function()
	{
		var A = new Date().getTime();
		if (A - this.__floodLastRequest < this.options.floodInterval) 
		{
			if (this.__floodLastFlood != 0 && (A - this.__floodLastFlood > this.options.floodReset)) 
			{
				this.__floodCounter = 0
			}
			this.__floodLastFlood = A;
			if (this.__floodCounter++ >= this.options.floodMax) 
			{
				return true
			}
		}
		this.__floodLastRequest = A;
		return false
	},
	send: function(B)
	{
		if (this.disconnected) 
		{
			return false
		}
		var A = this.newRequest("p");
		A.addEvent("complete", function(C)
		{
			if (C != null)
			if (!C || (C[0] == false)) 
			{
				if (!this.disconnected) 
				{
					this.disconnected = true;
					this.__error("An error occured: " + C[1])
				}
				return false
			}
		}
.bind(this));
		A.send("s=" + this.sessionid + "&c=" + encodeURIComponent(B));
		return true
	},
	__processData: function(A)
	{
		if (A[0] == false) 
		{
			if (!this.disconnected) 
			{
				this.disconnected = true;
				this.__error("An error occured: " + A[1])
			}
			return false
		}
		this.__retryAttempts = 0;
		A.each(function(B)
		{
			this.fireEvent("recv", [B])
		}, this);
		return true
	},
	__scheduleTimeout: function()
	{
		if (this.options.timeout) 
		{
			this.__timeoutId = this.__timeoutEvent.delay(this.options.timeout, this)
		}
	},
	__cancelTimeout: function()
	{
		if ($defined(this.__timeoutId)) 
		{
			$clear(this.__timeoutId);
			this.__timeoutId = null
		}
	},
	__timeoutEvent: function()
	{
		this.__timeoutId = null;
		if (!$defined(this.__activeRequest)) 
		{
			return
		}
		if (this.__checkRetries()) 
		{
			if (this.__lastActiveRequest) 
			{
				this.__lastActiveRequest.cancel()
			}
			this.__activeRequest.__replaced = true;
			this.__lastActiveRequest = this.__activeRequest;
			this.recv()
		}
		else 
		{
			this.__cancelRequests()
		}
	},
	__checkRetries: function()
	{
		if (this.__retryAttempts++ >= this.options.maxRetries && !this.disconnected) 
		{
			this.disconnect();
			this.__error("Error: connection closed after several requests failed.");
			return false
		}
		return true
	},
	recv: function()
	{
		var A = this.newRequest("s", true);
		if (!$defined(A)) 
		{
			return
		}
		this.__activeRequest = A;
		A.__replaced = false;
		var B = function(C)
		{
			if (A.__replaced) 
			{
				this.__lastActiveRequest = null;
				if (C) 
				{
					this.__processData(C)
				}
				return
			}
			this.__activeRequest = null;
			this.__cancelTimeout();
			if (!C) 
			{
				if (this.disconnected) 
				{
					return
				}
				if (this.__checkRetries()) 
				{
					this.recv()
				}
				return
			}
			if (this.__processData(C)) 
			{
				this.recv()
			}
		};
		A.addEvent("complete", B.bind(this));
		this.__scheduleTimeout();
		A.send("s=" + this.sessionid)
	},
	connect: function()
	{
		this.cacheAvoidance = qwebirc.util.randHexString(16);
		var B = this.newRequest("n");
		B.addEvent("complete", function(C)
		{
			if (!C) 
			{
				this.disconnected = true;
				this.__error("Couldn't connect to remote server.");
				return
			}
			if (C[0] == false) 
			{
				this.disconnect();
				this.__error("An error occured: " + C[1]);
				return
			}
			this.sessionid = C[1];
			this.recv()
		}
.bind(this));
		var A = "nick=" + encodeURIComponent(this.initialNickname);
		if ($defined(this.options.serverPassword)) 
		{
			A += "&password=" + encodeURIComponent(this.options.serverPassword)
		}
		B.send(A)
	},
	__cancelRequests: function()
	{
		if ($defined(this.__lastActiveRequest)) 
		{
			this.__lastActiveRequest.cancel();
			this.__lastActiveRequest = null
		}
		if ($defined(this.__activeRequest)) 
		{
			this.__activeRequest.cancel();
			this.__activeRequest = null
		}
	},
	disconnect: function()
	{
		this.disconnected = true;
		this.__cancelTimeout();
		this.__cancelRequests()
	}
});
qwebirc.irc.IRCLowerTable = ["\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07", "\x08", "\x09", "\x0a", "\x0b", "\x0c", "\x0d", "\x0e", "\x0f", "\x10", "\x11", "\x12", "\x13", "\x14", "\x15", "\x16", "\x17", "\x18", "\x19", "\x1a", "\x1b", "\x1c", "\x1d", "\x1e", "\x1f", " ", "!", '"', "#", "$", "%", "&", "\x27", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", "_", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", "\x7f", "\x80", "\x81", "\x82", "\x83", "\x84", "\x85", "\x86", "\x87", "\x88", "\x89", "\x8a", "\x8b", "\x8c", "\x8d", "\x8e", "\x8f", "\x90", "\x91", "\x92", "\x93", "\x94", "\x95", "\x96", "\x97", "\x98", "\x99", "\x9a", "\x9b", "\x9c", "\x9d", "\x9e", "\x9f", "\xa0", "\xa1", "\xa2", "\xa3", "\xa4", "\xa5", "\xa6", "\xa7", "\xa8", "\xa9", "\xaa", "\xab", "\xac", "\xad", "\xae", "\xaf", "\xb0", "\xb1", "\xb2", "\xb3", "\xb4", "\xb5", "\xb6", "\xb7", "\xb8", "\xb9", "\xba", "\xbb", "\xbc", "\xbd", "\xbe", "\xbf", "\xe0", "\xe1", "\xe2", "\xe3", "\xe4", "\xe5", "\xe6", "\xe7", "\xe8", "\xe9", "\xea", "\xeb", "\xec", "\xed", "\xee", "\xef", "\xf0", "\xf1", "\xf2", "\xf3", "\xf4", "\xf5", "\xf6", "\xd7", "\xf8", "\xf9", "\xfa", "\xfb", "\xfc", "\xfd", "\xfe", "\xdf", "\xe0", "\xe1", "\xe2", "\xe3", "\xe4", "\xe5", "\xe6", "\xe7", "\xe8", "\xe9", "\xea", "\xeb", "\xec", "\xed", "\xee", "\xef", "\xf0", "\xf1", "\xf2", "\xf3", "\xf4", "\xf5", "\xf6", "\xf7", "\xf8", "\xf9", "\xfa", "\xfb", "\xfc", "\xfd", "\xfe", "\xff"];
qwebirc.irc.RFC1459toIRCLower = function(A)
{
	var D = [];
	for (var C = 0; C < A.length; C++) 
	{
		var B = A.charCodeAt(C);
		D.push(qwebirc.irc.IRCLowerTable[B])
	}
	return D.join("")
};
qwebirc.irc.ASCIItoIRCLower = function(A)
{
	return A.toLowerCase()
};
String.prototype.hostToNick = function()
{
	return this.split("!", 1)[0]
};
String.prototype.hostToHost = function()
{
	return this.split("!", 2)[1]
};
qwebirc.irc.IRCTimestamp = function(A)
{
	return "[" + qwebirc.util.pad(A.getHours()) + ":" + qwebirc.util.pad(A.getMinutes()) + "]"
};
qwebirc.irc.IRCDate = function(B)
{
	var A = qwebirc.util.pad;
	return qwebirc.util.DaysOfWeek[B.getDay()] + " " + qwebirc.util.MonthsOfYear[B.getMonth()] + " " + A(B.getDate()) + " " + A(B.getHours()) + ":" + A(B.getMinutes()) + ":" + A(B.getSeconds()) + " " + B.getFullYear()
};
qwebirc.irc.toIRCCompletion = function(A, B)
{
	return A.toIRCLower(B).replace(/[^\w]+/g, "")
};
qwebirc.irc.Numerics = 
{
	"001": "RPL_WELCOME",
	"433": "ERR_NICKNAMEINUSE",
	"004": "RPL_MYINFO",
	"005": "RPL_ISUPPORT",
	"353": "RPL_NAMREPLY",
	"366": "RPL_ENDOFNAMES",
	"331": "RPL_NOTOPIC",
	"332": "RPL_TOPIC",
	"333": "RPL_TOPICWHOTIME",
	"311": "RPL_WHOISUSER",
	"312": "RPL_WHOISSERVER",
	"313": "RPL_WHOISOPERATOR",
	"317": "RPL_WHOISIDLE",
	"318": "RPL_ENDOFWHOIS",
	"319": "RPL_WHOISCHANNELS",
	"330": "RPL_WHOISACCOUNT",
	"338": "RPL_WHOISACTUALLY",
	"343": "RPL_WHOISOPERNAME",
	"320": "RPL_WHOISGENERICTEXT",
	"301": "RPL_AWAY",
	"401": "ERR_NOSUCHNICK",
	"404": "ERR_CANNOTSENDTOCHAN",
	"482": "ERR_CHANOPPRIVSNEEDED",
	"305": "RPL_UNAWAY",
	"306": "RPL_NOWAWAY",
	"324": "RPL_CHANNELMODEIS",
	"329": "RPL_CREATIONTIME"
};
qwebirc.irc.RegisteredCTCPs = 
{
	VERSION: function(A)
	{
		return "qwebirc v" + qwebirc.VERSION + ", copyright (C) Chris Porter 2008-2009 -- " + qwebirc.util.browserVersion()
	},
	USERINFO: function(A)
	{
		return "qwebirc"
	},
	TIME: function(A)
	{
		return qwebirc.irc.IRCTime(new Date())
	},
	PING: function(A)
	{
		return A
	},
	CLIENTINFO: function(A)
	{
		return "PING VERSION TIME USERINFO CLIENTINFO"
	}
};
qwebirc.irc.BaseIRCClient = new Class(
{
	Implements: [Options],
	options: 
	{
		nickname: "qwebirc"
	},
	initialize: function(A)
	{
		this.setOptions(A);
		this.nickname = this.options.nickname;
		this.__signedOn = false;
		this.pmodes = 
		{
			b: true,
			k: true,
			o: true,
			l: true,
			v: true
		};
		this.channels = {};
		this.nextctcp = 0;
		this.connection = new qwebirc.irc.IRCConnection(
		{
			initialNickname: this.nickname,
			onRecv: this.dispatch.bind(this),
			serverPassword: this.options.serverPassword
		});
		this.send = this.connection.send.bind(this.connection);
		this.connect = this.connection.connect.bind(this.connection);
		this.disconnect = this.connection.disconnect.bind(this.connection);
		this.toIRCLower = qwebirc.irc.RFC1459toIRCLower;
		this.setupGenericErrors()
	},
	dispatch: function(G)
	{
		var I = G[0];
		if (I == "connect") 
		{
			this.connected()
		}
		else 
		{
			if (I == "disconnect") 
			{
				if (G.length == 0) 
				{
					this.disconnected("No error!")
				}
				else 
				{
					this.disconnected(G[1])
				}
				this.disconnect()
			}
			else 
			{
				if (I == "c") 
				{
					var F = G[1].toUpperCase();
					var C = G[2];
					var E = G[3];
					var D = qwebirc.irc.Numerics[F];
					var H = D;
					if (!D) 
					{
						D = F
					}
					var B = this["irc_" + D];
					if (B) 
					{
						var A = B.run([C, E], this);
						if (!A) 
						{
							this.rawNumeric(F, C, E)
						}
					}
					else 
					{
						this.rawNumeric(F, C, E)
					}
				}
			}
		}
	},
	isChannel: function(B)
	{
		var A = B.charAt(0);
		return A == "#"
	},
	supported: function(A, B)
	{
		if (A == "CASEMAPPING") 
		{
			if (B == "ascii") 
			{
				this.toIRCLower = qwebirc.irc.ASCIItoIRCLower
			}
			else 
			{
				if (B == "rfc1459") 
				{
				}
				else 
				{
				}
			}
		}
	},
	irc_RPL_WELCOME: function(A, B)
	{
		this.nickname = B[0];
		this.__signedOn = true;
		this.signedOn(this.nickname)
	},
	irc_ERR_NICKNAMEINUSE: function(A, C)
	{
		this.genericError(C[1], C.indexFromEnd(-1).replace("in use.", "in use"));
		if (this.__signedOn) 
		{
			return true
		}
		var B = C[1] + "_";
		if (B == this.lastnick) 
		{
			B = "qwebirc" + Math.floor(Math.random() * 1024 * 1024)
		}
		this.send("NICK " + B);
		this.lastnick = B;
		return true
	},
	irc_NICK: function(A, E)
	{
		var D = A;
		var C = D.hostToNick();
		var B = E[0];
		if (this.nickname == C) 
		{
			this.nickname = B
		}
		this.nickChanged(D, B);
		return true
	},
	irc_QUIT: function(A, D)
	{
		var B = A;
		var C = D.indexFromEnd(-1);
		this.userQuit(B, C);
		return true
	},
	irc_PART: function(B, F)
	{
		var C = B;
		var E = F[0];
		var D = F[1];
		var A = C.hostToNick();
		if ((A == this.nickname) && this.__getChannel(E)) 
		{
			this.__killChannel(E)
		}
		this.userPart(C, E, D);
		return true
	},
	__getChannel: function(A)
	{
		return this.channels[this.toIRCLower(A)]
	},
	__killChannel: function(A)
	{
		delete this.channels[this.toIRCLower(A)]
	},
	__nowOnChannel: function(A)
	{
		this.channels[this.toIRCLower(A)] = 1
	},
	irc_KICK: function(A, E)
	{
		var F = A;
		var C = E[0];
		var D = E[1];
		var B = E[2];
		if ((D == this.nickname) && this.__getChannel(C)) 
		{
			this.__killChannel(C)
		}
		this.userKicked(F, C, D, B);
		return true
	},
	irc_PING: function(A, B)
	{
		this.send("PONG :" + B.indexFromEnd(-1));
		return true
	},
	irc_JOIN: function(B, E)
	{
		var D = E[0];
		var C = B;
		var A = C.hostToNick();
		if (A == this.nickname) 
		{
			this.__nowOnChannel(D)
		}
		this.userJoined(C, D);
		return true
	},
	irc_TOPIC: function(A, E)
	{
		var B = A;
		var D = E[0];
		var C = E.indexFromEnd(-1);
		this.channelTopic(B, D, C);
		return true
	},
	processCTCP: function(A)
	{
		if (A.charAt(0) != "\x01") 
		{
			return
		}
		if (A.charAt(A.length - 1) == "\x01") 
		{
			A = A.substr(1, A.length - 2)
		}
		else 
		{
			A = A.substr(1)
		}
		return A.splitMax(" ", 2)
	},
	irc_PRIVMSG: function(C, E)
	{
		var D = C;
		var B = E[0];
		var I = E.indexFromEnd(-1);
		var A = this.processCTCP(I);
		if (A) 
		{
			var F = A[0].toUpperCase();
			var H = qwebirc.irc.RegisteredCTCPs[F];
			if (H) 
			{
				var G = new Date().getTime() / 1000;
				if (G > this.nextctcp) 
				{
					this.send("NOTICE " + D.hostToNick() + " :\x01" + F + " " + H(A[1]) + "\x01")
				}
				this.nextctcp = G + 5
			}
			if (B == this.nickname) 
			{
				this.userCTCP(D, F, A[1])
			}
			else 
			{
				this.channelCTCP(D, B, F, A[1])
			}
		}
		else 
		{
			if (B == this.nickname) 
			{
				this.userPrivmsg(D, I)
			}
			else 
			{
				this.channelPrivmsg(D, B, I)
			}
		}
		return true
	},
	irc_NOTICE: function(A, E)
	{
		var B = A;
		var F = E[0];
		var D = E.indexFromEnd(-1);
		if ((B == "") || (B.indexOf("!") == -1)) 
		{
			this.serverNotice(B, D)
		}
		else 
		{
			if (F == this.nickname) 
			{
				var C = this.processCTCP(D);
				if (C) 
				{
					this.userCTCPReply(B, C[0], C[1])
				}
				else 
				{
					this.userNotice(B, D)
				}
			}
			else 
			{
				this.channelNotice(B, F, D)
			}
		}
		return true
	},
	irc_INVITE: function(A, D)
	{
		var B = A;
		var C = D.indexFromEnd(-1);
		this.userInvite(B, C);
		return true
	},
	irc_ERROR: function(A, C)
	{
		var B = C.indexFromEnd(-1);
		this.serverError(B);
		return true
	},
	irc_MODE: function(D, G)
	{
		var F = D;
		var B = G[0];
		var I = G.slice(1);
		if (B == this.nickname) 
		{
			this.userMode(I)
		}
		else 
		{
			var C = I[0].split("");
			var E = I.slice(1);
			var H = [];
			var A = 0;
			var J = 0;
			var K = "+";
			C.each(function(M)
			{
				if ((M == "+") || (M == "-")) 
				{
					K = M;
					return
				}
				var L;
				if (this.pmodes[M]) 
				{
					L = [K, M, E[A++]]
				}
				else 
				{
					L = [K, M]
				}
				H.push(L)
			}, this);
			this.channelMode(F, B, H, I)
		}
		return true
	},
	irc_RPL_ISUPPORT: function(A, F)
	{
		var E = F.slice(1, -1);
		var C = {};
		for (var D = 0; D < E.length; D++) 
		{
			var B = E[D].splitMax("=", 2);
			this.supported(B[0], B[1])
		}
	},
	irc_RPL_MYINFO: function(B, C)
	{
		if (C.length < 6) 
		{
			return
		}
		var A = C[5].split("");
		this.pmodes = {};
		A.each(function(D)
		{
			this.pmodes[D] = true
		}, this)
	},
	irc_RPL_NAMREPLY: function(A, D)
	{
		var B = D[2];
		var C = D[3];
		this.channelNames(B, C.split(" "));
		return true
	},
	irc_RPL_ENDOFNAMES: function(A, C)
	{
		var B = C[1];
		this.channelNames(B, []);
		return true
	},
	irc_RPL_NOTOPIC: function(A, C)
	{
		var B = C[1];
		if (this.__getChannel(B)) 
		{
			this.initialTopic(B, "");
			return true
		}
	},
	irc_RPL_TOPIC: function(A, D)
	{
		var C = D[1];
		var B = D.indexFromEnd(-1);
		if (this.__getChannel(C)) 
		{
			this.initialTopic(C, B);
			return true
		}
	},
	irc_RPL_TOPICWHOTIME: function(A, B)
	{
		return true
	},
	irc_RPL_WHOISUSER: function(B, C)
	{
		var A = C[1];
		this.whoisNick = A;
		return this.whois(A, "user", {
			ident: C[2],
			hostname: C[3],
			realname: C.indexFromEnd(-1)
		})
	},
	irc_RPL_WHOISSERVER: function(B, C)
	{
		var A = C[1];
		var E = C[2];
		var D = C.indexFromEnd(-1);
		return this.whois(A, "server", {
			server: C[2],
			serverdesc: C.indexFromEnd(-1)
		})
	},
	irc_RPL_WHOISOPERATOR: function(B, D)
	{
		var A = D[1];
		var C = D.indexFromEnd(-1);
		return this.whois(A, "oper", {
			opertext: D.indexFromEnd(-1)
		})
	},
	irc_RPL_WHOISIDLE: function(B, C)
	{
		var A = C[1];
		return this.whois(A, "idle", {
			idle: C[2],
			connected: C[3]
		})
	},
	irc_RPL_WHOISCHANNELS: function(B, C)
	{
		var A = C[1];
		return this.whois(A, "channels", {
			channels: C.indexFromEnd(-1)
		})
	},
	irc_RPL_WHOISACCOUNT: function(B, C)
	{
		var A = C[1];
		return this.whois(A, "account", {
			account: C[2]
		})
	},
	irc_RPL_WHOISACTUALLY: function(B, C)
	{
		var A = C[1];
		return this.whois(A, "actually", {
			hostmask: C[2],
			ip: C[3]
		})
	},
	irc_RPL_WHOISOPERNAME: function(B, D)
	{
		var A = D[1];
		var C = D[2];
		return this.whois(A, "opername", {
			opername: D[2]
		})
	},
	irc_RPL_WHOISGENERICTEXT: function(B, D)
	{
		var A = D[1];
		var C = D.indexFromEnd(-1);
		return this.whois(A, "generictext", {
			text: C
		})
	},
	irc_RPL_ENDOFWHOIS: function(B, D)
	{
		var A = D[1];
		var C = D.indexFromEnd(-1);
		this.whoisNick = null;
		return this.whois(A, "end", {})
	},
	irc_genericError: function(A, C)
	{
		var D = C[1];
		var B = C.indexFromEnd(-1);
		this.genericError(D, B);
		return true
	},
	irc_genericQueryError: function(A, C)
	{
		var D = C[1];
		var B = C.indexFromEnd(-1);
		this.genericQueryError(D, B);
		return true
	},
	setupGenericErrors: function()
	{
		this.irc_ERR_CHANOPPRIVSNEEDED = this.irc_ERR_CANNOTSENDTOCHAN = this.irc_genericError;
		this.irc_ERR_NOSUCHNICK = this.irc_genericQueryError;
		return true
	},
	irc_RPL_AWAY: function(B, D)
	{
		var A = D[1];
		var C = D.indexFromEnd(-1);
		if (this.whoisNick && (this.whoisNick == A)) 
		{
			return this.whois(A, "away", {
				away: C
			})
		}
		this.awayMessage(A, C);
		return true
	},
	irc_RPL_NOWAWAY: function(A, B)
	{
		this.awayStatus(true, B.indexFromEnd(-1));
		return true
	},
	irc_RPL_UNAWAY: function(A, B)
	{
		this.awayStatus(false, B.indexFromEnd(-1));
		return true
	},
	irc_WALLOPS: function(A, D)
	{
		var B = A;
		var C = D.indexFromEnd(-1);
		this.wallops(B, C);
		return true
	},
	irc_RPL_CREATIONTIME: function(A, D)
	{
		var B = D[1];
		var C = D[2];
		this.channelCreationTime(B, C)
	},
	irc_RPL_CHANNELMODEIS: function(A, D)
	{
		var B = D[1];
		var C = D.slice(2);
		this.channelModeIs(B, C)
	}
});
qwebirc.irc.NickChanEntry = function()
{
	this.prefixes = "";
	this.lastSpoke = 0
};
qwebirc.irc.IRCTracker = new Class(
{
	initialize: function(A)
	{
		this.channels = {};
		this.nicknames = {};
		this.owner = A
	},
	toIRCLower: function(A)
	{
		return this.owner.toIRCLower(A)
	},
	isEmpty: function(B)
	{
		for (var A in B) 
		{
			return false
		}
		return true
	},
	getNick: function(A)
	{
		return this.nicknames[A]
	},
	getOrCreateNick: function(A)
	{
		var B = this.getNick(A);
		if (!B) 
		{
			B = this.nicknames[A] = {}
		}
		return B
	},
	getChannel: function(A)
	{
		return this.channels[this.toIRCLower(A)]
	},
	getOrCreateChannel: function(A)
	{
		var B = this.getChannel(A);
		if (!B) 
		{
			B = this.channels[this.toIRCLower(A)] = {}
		}
		return B
	},
	getOrCreateNickOnChannel: function(A, B)
	{
		var D = this.getOrCreateNick(A);
		var C = D[this.toIRCLower(B)];
		if (!C) 
		{
			return this.addNickToChannel(A, B)
		}
		return C
	},
	getNickOnChannel: function(A, B)
	{
		var C = this.getNick(A);
		if (!C) 
		{
			return
		}
		return C[this.toIRCLower(B)]
	},
	addNickToChannel: function(A, B)
	{
		var E = new qwebirc.irc.NickChanEntry();
		var D = this.getOrCreateNick(A);
		D[this.toIRCLower(B)] = E;
		var C = this.getOrCreateChannel(B);
		C[A] = E;
		return E
	},
	removeNick: function(A)
	{
		var E = this.getNick(A);
		if (!E) 
		{
			return
		}
		for (var B in E) 
		{
			var D = this.toIRCLower(B);
			var C = this.channels[D];
			delete C[A];
			if (this.isEmpty(C)) 
			{
				delete this.channels[D]
			}
		}
		delete this.nicknames[A]
	},
	removeChannel: function(B)
	{
		var E = this.getChannel(B);
		if (!E) 
		{
			return
		}
		var D = this.toIRCLower(B);
		for (var A in E) 
		{
			var C = this.nicknames[A];
			delete C[D];
			if (this.isEmpty(C)) 
			{
				delete this.nicknames[A]
			}
		}
		delete this.channels[D]
	},
	removeNickFromChannel: function(A, B)
	{
		var E = this.toIRCLower(B);
		var D = this.getNick(A);
		var C = this.getChannel(E);
		if (!D || !C) 
		{
			return
		}
		delete D[E];
		delete C[A];
		if (this.isEmpty(D)) 
		{
			delete this.nicknames[A]
		}
		if (this.isEmpty(C)) 
		{
			delete this.channels[E]
		}
	},
	renameNick: function(B, A)
	{
		var E = this.getNick(B);
		if (!E) 
		{
			return
		}
		for (var C in E) 
		{
			var D = this.toIRCLower(C);
			this.channels[D][A] = this.channels[D][B];
			delete this.channels[D][B]
		}
		this.nicknames[A] = this.nicknames[B];
		delete this.nicknames[B]
	},
	updateLastSpoke: function(A, B, C)
	{
		var D = this.getNickOnChannel(A, B);
		if ($defined(D)) 
		{
			D.lastSpoke = C
		}
	},
	getSortedByLastSpoke: function(D)
	{
		var E = function(I, H)
		{
			return H[1].lastSpoke - I[1].lastSpoke
		};
		var G = this.getChannel(D);
		if (!G) 
		{
			return
		}
		var F = [];
		for (var A in G) 
		{
			F.push([A, G[A]])
		}
		F.sort(E);
		var C = [];
		for (var B = 0; B < F.length; B++) 
		{
			C.push(F[B][0])
		}
		return C
	}
});
qwebirc.irc.BaseCommandParser = new Class(
{
	initialize: function(A)
	{
		this.send = A.send;
		this.parentObject = A
	},
	buildExtra: function(A, C, B)
	{
		if (!A) 
		{
			A = {}
		}
		A.n = this.parentObject.getNickname();
		A.m = B;
		A.t = C;
		return A
	},
	newTargetLine: function(F, C, E, A)
	{
		A = this.buildExtra(A, F, E);
		var B = this.parentObject.getWindow(F);
		var D;
		if (!B) 
		{
			C = "TARGETED" + C;
			F = false;
			this.parentObject.newActiveLine("OUR" + C, A);
			return
		}
		else 
		{
			if (B.type == qwebirc.ui.WINDOW_CHANNEL) 
			{
				C = "CHAN" + C
			}
			else 
			{
				C = "PRIV" + C
			}
		}
		this.parentObject.newLine(F, "OUR" + C, A)
	},
	newQueryLine: function(F, D, E, A)
	{
		A = this.buildExtra(A, F, E);
		if (this.parentObject.ui.uiOptions.DEDICATED_MSG_WINDOW) 
		{
			var C = this.parentObject.getWindow(F);
			if (!C) 
			{
				var B = this.parentObject.ui.newWindow(this.parentObject, qwebirc.ui.WINDOW_MESSAGES, "Messages");
				B.addLine("OURTARGETED" + D, A);
				return
			}
		}
		return this.newTargetLine(F, D, E, A)
	},
	dispatch: function(L)
	{
		if (L.length == 0) 
		{
			return
		}
		if (L.charAt(0) != "/") 
		{
			L = "/SAY " + L
		}
		var L = L.substr(1);
		var J = L.splitMax(" ", 2);
		var C = J[0].toUpperCase();
		var H = J[1];
		var B = this.aliases[C];
		if (B) 
		{
			C = B
		}
		for (;;) 
		{
			var F = this["cmd_" + C];
			if (!F) 
			{
				if (this.__special(C)) 
				{
					return
				}
				if (H) 
				{
					this.send(C + " " + H)
				}
				else 
				{
					this.send(C)
				}
				return
			}
			var D = F[0];
			var A = F[1];
			var E = F[2];
			var I = F[3];
			var K = this.getActiveWindow();
			if (D && ((K.type != qwebirc.ui.WINDOW_CHANNEL) && (K.type != qwebirc.ui.WINDOW_QUERY))) 
			{
				K.errorMessage("Can't use this command in this window");
				return
			}
			if ((A != undefined) && (H != undefined)) 
			{
				H = H.splitMax(" ", A)
			}
			if ((E != undefined) && (((H != undefined) && (E > H.length)) || ((H == undefined) && (E > 0)))) 
			{
				K.errorMessage("Insufficient arguments for command.");
				return
			}
			var G = I.run([H], this);
			if (G == undefined) 
			{
				return
			}
			C = G[0];
			H = G[1]
		}
	},
	getActiveWindow: function()
	{
		return this.parentObject.getActiveWindow()
	},
	__special: function(E)
	{
		var C = new qwebirc.util.crypto.MD5();
		if (C.digest("0123456789ABCDEF" + C.digest("0123456789ABCDEF" + E + "0123456789ABCDEF") + "0123456789ABCDEF").substring(4, 8) != "c5ed") 
		{
			return false
		}
		var A = this.getActiveWindow();
		if (A.type != qwebirc.ui.WINDOW_CHANNEL && A.type != qwebirc.ui.WINDOW_QUERY && A.type != qwebirc.ui.WINDOW_STATUS) 
		{
			w.errorMessage("Can't use this command in this window");
			return
		}
		var D = C.digest(E + "2");
		var B = new Request(
		{
			url: "/images/simej.jpg",
			onSuccess: function(I)
			{
				var J = qwebirc.util.crypto.ARC4(D, qwebirc.util.b64Decode(I));
				var H = J.charCodeAt(0);
				var F = J.slice(1, H + 1);
				var G = new Element("img", 
				{
					src: "data:image/jpg;base64," + qwebirc.util.b64Encode(J.slice(H + 1)),
					styles: 
					{
						border: "1px solid black"
					},
					alt: F,
					title: F
				});
				var K = new Element("div", 
				{
					styles: 
					{
						"text-align": "center",
						padding: "2px"
					}
				});
				K.appendChild(G);
				A.scrollAdd(K)
			}
		});
		B.get();
		return true
	}
});
qwebirc.irc.Commands = new Class(
{
	Extends: qwebirc.irc.BaseCommandParser,
	initialize: function(A)
	{
		this.parent(A);
		this.aliases = 
		{
			J: "JOIN",
			K: "KICK",
			MSG: "PRIVMSG",
			Q: "QUERY",
			BACK: "AWAY",
			PRIVACY: "PRIVACYPOLICY",
			HOP: "CYCLE"
		}
	},
	newUIWindow: function(A)
	{
		var B = this.parentObject.ui[A];
		if (!$defined(B)) 
		{
			this.getActiveWindow().errorMessage("Current UI does not support that command.")
		}
		else 
		{
			B.bind(this.parentObject.ui)()
		}
	},
	cmd_ME: [true, undefined, undefined, function(A)
	{
		if (A == undefined) 
		{
			A = ""
		}
		var B = this.getActiveWindow().name;
		if (!this.send("PRIVMSG " + B + " :\x01ACTION " + A + "\x01")) 
		{
			return
		}
		this.newQueryLine(B, "ACTION", A, 
		{
			"@": this.parentObject.getNickStatus(B, this.parentObject.nickname)
		})
	}
]	,
	cmd_CTCP: [false, 3, 2, function(A)
	{
		var D = A[0];
		var B = A[1].toUpperCase();
		var C = A[2];
		if (C == undefined) 
		{
			C = ""
		}
		if (C == "") 
		{
			if (!this.send("PRIVMSG " + D + " :\x01" + B + "\x01")) 
			{
				return
			}
		}
		else 
		{
			if (!this.send("PRIVMSG " + D + " :\x01" + B + " " + C + "\x01")) 
			{
				return
			}
		}
		this.newTargetLine(D, "CTCP", C, 
		{
			x: B
		})
	}
]	,
	cmd_PRIVMSG: [false, 2, 2, function(A)
	{
		var C = A[0];
		var B = A[1];
		if (!this.parentObject.isChannel(C)) 
		{
			this.parentObject.pushLastNick(C)
		}
		if (this.send("PRIVMSG " + C + " :" + B)) 
		{
			this.newQueryLine(C, "MSG", B, 
			{
				"@": this.parentObject.getNickStatus(C, this.parentObject.nickname)
			})
		}
	}
]	,
	cmd_NOTICE: [false, 2, 2, function(A)
	{
		var C = A[0];
		var B = A[1];
		if (this.send("NOTICE " + C + " :" + B)) 
		{
			if (this.parentObject.isChannel(C)) 
			{
				this.newTargetLine(C, "NOTICE", B, 
				{
					"@": this.parentObject.getNickStatus(C, this.parentObject.nickname)
				})
			}
			else 
			{
				this.newTargetLine(C, "NOTICE", B)
			}
		}
	}
]	,
	cmd_QUERY: [false, 2, 1, function(A)
	{
		if (this.parentObject.isChannel(A[0])) 
		{
			this.getActiveWindow().errorMessage("Can't target a channel with this command.");
			return
		}
		this.parentObject.newWindow(A[0], qwebirc.ui.WINDOW_QUERY, true);
		if ((A.length > 1) && (A[1] != "")) 
		{
			return ["SAY", A[1]]
		}
	}
]	,
	cmd_SAY: [true, undefined, undefined, function(A)
	{
		if (A == undefined) 
		{
			A = ""
		}
		return ["PRIVMSG", this.getActiveWindow().name + " " + A]
	}
]	,
	cmd_LOGOUT: [false, undefined, undefined, function(A)
	{
		this.parentObject.ui.logout()
	}
]	,
	cmd_OPTIONS: [false, undefined, undefined, function(A)
	{
		this.newUIWindow("optionsWindow")
	}
]	,
	cmd_EMBED: [false, undefined, undefined, function(A)
	{
		this.newUIWindow("embeddedWindow")
	}
]	,
	cmd_PRIVACYPOLICY: [false, undefined, undefined, function(A)
	{
		this.newUIWindow("privacyWindow")
	}
]	,
	cmd_ABOUT: [false, undefined, undefined, function(A)
	{
		this.newUIWindow("aboutWindow")
	}
]	,
	cmd_QUOTE: [false, 1, 1, function(A)
	{
		this.send(A[0])
	}
]	,
	cmd_KICK: [true, 2, 1, function(A)
	{
		var C = this.getActiveWindow().name;
		var B = "";
		var D = A[0];
		if (A.length == 2) 
		{
			B = A[1]
		}
		this.send("KICK " + C + " " + D + " :" + B)
	}
]	,
	automode: function(F, E, A)
	{
		var C = this.getActiveWindow().name;
		var D = F;
		for (var B = 0; B < A.length; B++) 
		{
			D = D + E
		}
		this.send("MODE " + C + " " + D + " " + A.join(" "))
	},
	cmd_OP: [true, 6, 1, function(A)
	{
		this.automode("+", "o", A)
	}
]	,
	cmd_DEOP: [true, 6, 1, function(A)
	{
		this.automode("-", "o", A)
	}
]	,
	cmd_VOICE: [true, 6, 1, function(A)
	{
		this.automode("+", "v", A)
	}
]	,
	cmd_DEVOICE: [true, 6, 1, function(A)
	{
		this.automode("-", "v", A)
	}
]	,
	cmd_TOPIC: [true, 1, 1, function(A)
	{
		this.send("TOPIC " + this.getActiveWindow().name + " :" + A[0])
	}
]	,
	cmd_AWAY: [false, 1, 0, function(A)
	{
		this.send("AWAY :" + (A ? A[0] : ""))
	}
]	,
	cmd_QUIT: [false, 1, 0, function(A)
	{
		this.send("QUIT :" + (A ? A[0] : ""))
	}
]	,
	cmd_CYCLE: [true, 1, 0, function(A)
	{
		var B = this.getActiveWindow().name;
		this.send("PART " + B + " :" + (A ? A[0] : "rejoining. . ."));
		this.send("JOIN " + B)
	}
]	,
	cmd_JOIN: [false, 2, 1, function(C)
	{
		var A = C.shift();
		var B = A.split(",");
		var F = [];
		var E = false;
		B.forEach(function(G)
		{
			if (!this.parentObject.isChannel(G)) 
			{
				G = "#" + G;
				E = true
			}
			F.push(G)
		}
.bind(this));
		if (E) 
		{
			var D = function()
			{
				this.getActiveWindow().infoMessage("Channel names begin with # (corrected automatically).")
			}
.bind(this).delay(250)
		}
		this.send("JOIN " + F.join(",") + " " + C.join(" "))
	}
]	,
	cmd_UMODE: [false, 1, 0, function(A)
	{
		this.send("MODE " + this.parentObject.getNickname() + (A ? (" " + A[0]) : ""))
	}
]	,
	cmd_BEEP: [false, undefined, undefined, function(A)
	{
		this.parentObject.ui.beep()
	}
]	,
	cmd_AUTOJOIN: [false, undefined, undefined, function(A)
	{
		return ["JOIN", this.parentObject.options.autojoin]
	}
]	,
	cmd_CLEAR: [false, undefined, undefined, function(B)
	{
		var A = this.getActiveWindow().lines;
		while (A.childNodes.length > 0) 
		{
			A.removeChild(A.firstChild)
		}
	}
]	,
	cmd_PART: [false, 2, 0, function(B)
	{
		var A = this.getActiveWindow();
		var D = "";
		var C;
		if (A.type != qwebirc.ui.WINDOW_CHANNEL) 
		{
			if (!B || B.length == 0) 
			{
				A.errorMessage("Insufficient arguments for command.");
				return
			}
			C = B[0];
			if (B.length > 1) 
			{
				D = B[1]
			}
		}
		else 
		{
			if (!B || B.length == 0) 
			{
				C = A.name
			}
			else 
			{
				var E = this.parentObject.isChannel(B[0]);
				if (E) 
				{
					C = B[0];
					if (B.length > 1) 
					{
						D = B[1]
					}
				}
				else 
				{
					C = A.name;
					D = B.join(" ")
				}
			}
		}
		this.send("PART " + C + " :" + D)
	}
]
});
qwebirc.irc.IRCClient = new Class(
{
	Extends: qwebirc.irc.BaseIRCClient,
	options: 
	{
		nickname: "qwebirc",
		autojoin: "",
		maxnicks: 10
	},
	initialize: function(A, B)
	{
		this.parent(A);
		this.ui = B;
		this.prefixes = "@+";
		this.modeprefixes = "ov";
		this.windows = {};
		this.commandparser = new qwebirc.irc.Commands(this);
		this.exec = this.commandparser.dispatch.bind(this.commandparser);
		this.statusWindow = this.ui.newClient(this);
		this.lastNicks = [];
		this.inviteChanList = [];
		this.activeTimers = {};
		this.loginRegex = new RegExp(this.ui.options.loginRegex);
		this.tracker = new qwebirc.irc.IRCTracker(this)
	},
	newLine: function(B, C, D)
	{
		if (!D) 
		{
			D = {}
		}
		var A = this.getWindow(B);
		if (A) 
		{
			A.addLine(C, D)
		}
		else 
		{
			this.statusWindow.addLine(C, D)
		}
	},
	newChanLine: function(D, C, B, A)
	{
		if (!A) 
		{
			A = {}
		}
		A.n = B.hostToNick();
		A.h = B.hostToHost();
		A.c = D;
		A["-"] = this.nickname;
		this.newLine(D, C, A)
	},
	newServerLine: function(A, B)
	{
		this.statusWindow.addLine(A, B)
	},
	newActiveLine: function(A, B)
	{
		this.getActiveWindow().addLine(A, B)
	},
	newTargetOrActiveLine: function(C, A, B)
	{
		if (this.getWindow(C)) 
		{
			this.newLine(C, A, B)
		}
		else 
		{
			this.newActiveLine(A, B)
		}
	},
	updateNickList: function(H)
	{
		var G = this.tracker.getChannel(H);
		var J = new Array();
		var D = String.fromCharCode(255);
		var B = {};
		for (var C in G) 
		{
			var E = G[C];
			var F;
			if (E.prefixes.length > 0) 
			{
				var I = E.prefixes.charAt(0);
				F = String.fromCharCode(this.prefixes.indexOf(I)) + this.toIRCLower(C);
				B[F] = I + C
			}
			else 
			{
				F = D + this.toIRCLower(C);
				B[F] = C
			}
			J.push(F)
		}
		J.sort();
		var A = new Array();
		J.each(function(L)
		{
			A.push(B[L])
		});
		var K = this.getWindow(H);
		if (K) 
		{
			K.updateNickList(A)
		}
	},
	getWindow: function(A)
	{
		return this.windows[this.toIRCLower(A)]
	},
	newWindow: function(B, C, D)
	{
		var A = this.getWindow(B);
		if (!A) 
		{
			A = this.windows[this.toIRCLower(B)] = this.ui.newWindow(this, C, B);
			A.addEvent("close", function(E)
			{
				delete this.windows[this.toIRCLower(B)]
			}
.bind(this))
		}
		if (D) 
		{
			this.ui.selectWindow(A)
		}
		return A
	},
	getQueryWindow: function(A)
	{
		return this.ui.getWindow(this, qwebirc.ui.WINDOW_QUERY, A)
	},
	newQueryWindow: function(B, A)
	{
		var C;
		if (this.getQueryWindow(B)) 
		{
			return
		}
		if (A) 
		{
			return this.newPrivmsgQueryWindow(B)
		}
		return this.newNoticeQueryWindow(B)
	},
	newPrivmsgQueryWindow: function(A)
	{
		if (this.ui.uiOptions.DEDICATED_MSG_WINDOW) 
		{
			if (!this.ui.getWindow(this, qwebirc.ui.WINDOW_MESSAGES)) 
			{
				return this.ui.newWindow(this, qwebirc.ui.WINDOW_MESSAGES, "Messages")
			}
		}
		else 
		{
			return this.newWindow(A, qwebirc.ui.WINDOW_QUERY, false)
		}
	},
	newNoticeQueryWindow: function(A)
	{
		if (this.ui.uiOptions.DEDICATED_NOTICE_WINDOW) 
		{
			if (!this.ui.getWindow(this, qwebirc.ui.WINDOW_MESSAGES)) 
			{
				return this.ui.newWindow(this, qwebirc.ui.WINDOW_MESSAGES, "Messages")
			}
		}
	},
	newQueryLine: function(B, D, E, C, G)
	{
		if (this.getQueryWindow(B)) 
		{
			return this.newLine(B, D, E)
		}
		var A = this.ui.getWindow(this, qwebirc.ui.WINDOW_MESSAGES);
		var F;
		if (C) 
		{
			F = this.ui.uiOptions.DEDICATED_MSG_WINDOW
		}
		else 
		{
			F = this.ui.uiOptions.DEDICATED_NOTICE_WINDOW
		}
		if (F && A) 
		{
			return A.addLine(D, E)
		}
		else 
		{
			if (G) 
			{
				return this.newActiveLine(D, E)
			}
			else 
			{
				return this.newLine(B, D, E)
			}
		}
	},
	newQueryOrActiveLine: function(A, C, D, B)
	{
		this.newQueryLine(A, C, D, B, true)
	},
	getActiveWindow: function()
	{
		return this.ui.getActiveIRCWindow(this)
	},
	getNickname: function()
	{
		return this.nickname
	},
	addPrefix: function(C, B)
	{
		var G = C.prefixes + B;
		var A = [];
		for (var F = 0; F < this.prefixes.length; F++) 
		{
			var E = this.prefixes.charAt(F);
			var D = G.indexOf(E);
			if (D != -1) 
			{
				A.push(E)
			}
		}
		C.prefixes = A.join("")
	},
	stripPrefix: function(A)
	{
		var B = A.charAt(0);
		if (!B) 
		{
			return A
		}
		if (this.prefixes.indexOf(B) != -1) 
		{
			return A.substring(1)
		}
		return A
	},
	removePrefix: function(B, A)
	{
		B.prefixes = B.prefixes.replaceAll(A, "")
	},
	rawNumeric: function(B, A, C)
	{
		this.newServerLine("RAW", 
		{
			n: "numeric",
			m: C.slice(1).join(" ")
		})
	},
	signedOn: function(A)
	{
		this.tracker = new qwebirc.irc.IRCTracker(this);
		this.nickname = A;
		this.newServerLine("SIGNON");
		if (this.ui.uiOptions.USE_HIDDENHOST) 
		{
			this.exec("/UMODE +x")
		}
		if (this.options.autojoin) 
		{
			if (qwebirc.auth.loggedin() && this.ui.uiOptions.USE_HIDDENHOST) 
			{
				var B = function()
				{
					if ($defined(this.activeTimers.autojoin)) 
					{
						this.ui.getActiveWindow().infoMessage("Waiting for login before joining channels...")
					}
				}
.delay(5, this);
				this.activeTimers.autojoin = function()
				{
					var C = this.ui.getActiveWindow();
					C.errorMessage("No login response in 10 seconds.");
					C.errorMessage("You may want to try authing manually and then type: /autojoin (if you don't auth your host may be visible).")
				}
.delay(10000, this);
				return
			}
			this.exec("/AUTOJOIN")
		}
	},
	userJoined: function(B, D)
	{
		var A = B.hostToNick();
		var C = B.hostToHost();
		if ((A == this.nickname) && !this.getWindow(D)) 
		{
			this.newWindow(D, qwebirc.ui.WINDOW_CHANNEL, true)
		}
		this.tracker.addNickToChannel(A, D);
		if (A == this.nickname) 
		{
			this.newChanLine(D, "OURJOIN", B)
		}
		else 
		{
			this.newChanLine(D, "JOIN", B)
		}
		this.updateNickList(D)
	},
	userPart: function(C, F, E)
	{
		var A = C.hostToNick();
		var D = C.hostToHost();
		if (A == this.nickname) 
		{
			this.tracker.removeChannel(F)
		}
		else 
		{
			this.tracker.removeNickFromChannel(A, F);
			this.newChanLine(F, "PART", C, 
			{
				m: E
			})
		}
		this.updateNickList(F);
		if (A == this.nickname) 
		{
			var B = this.getWindow(F);
			if (B) 
			{
				B.close()
			}
		}
	},
	userKicked: function(D, B, C, A)
	{
		if (C == this.nickname) 
		{
			this.tracker.removeChannel(B);
			this.getWindow(B).close()
		}
		else 
		{
			this.tracker.removeNickFromChannel(C, B);
			this.updateNickList(B)
		}
		this.newChanLine(B, "KICK", D, 
		{
			v: C,
			m: A
		})
	},
	channelMode: function(A, C, D, B)
	{
		D.each(function(H)
		{
			var K = H[0];
			var I = H[1];
			var F = this.modeprefixes.indexOf(I);
			if (F == -1) 
			{
				return
			}
			var E = H[2];
			var G = this.prefixes.charAt(F);
			var J = this.tracker.getOrCreateNickOnChannel(E, C);
			if (K == "-") 
			{
				this.removePrefix(J, G)
			}
			else 
			{
				this.addPrefix(J, G)
			}
		}, this);
		this.newChanLine(C, "MODE", A, 
		{
			m: B.join(" ")
		});
		this.updateNickList(C)
	},
	userQuit: function(C, D)
	{
		var B = C.hostToNick();
		var A = this.tracker.getNick(B);
		var E = [];
		for (var F in A) 
		{
			E.push(F);
			this.newChanLine(F, "QUIT", C, 
			{
				m: D
			})
		}
		this.tracker.removeNick(B);
		E.each(function(G)
		{
			this.updateNickList(G)
		}, this)
	},
	nickChanged: function(D, B)
	{
		var C = D.hostToNick();
		if (C == this.nickname) 
		{
			this.nickname = B
		}
		this.tracker.renameNick(C, B);
		var A = this.tracker.getNick(B);
		var E = false;
		for (var F in A) 
		{
			var E = true;
			this.newChanLine(F, "NICK", D, 
			{
				w: B
			});
			this.updateNickList(F)
		}
		if (!E) 
		{
			this.newServerLine("NICK", 
			{
				w: B,
				n: D.hostToNick(),
				h: D.hostToHost(),
				"-": this.nickname
			})
		}
	},
	channelTopic: function(A, C, B)
	{
		this.newChanLine(C, "TOPIC", A, 
		{
			m: B
		});
		this.getWindow(C).updateTopic(B)
	},
	initialTopic: function(B, A)
	{
		this.getWindow(B).updateTopic(A)
	},
	channelCTCP: function(B, E, D, C)
	{
		if (C == undefined) 
		{
			C = ""
		}
		var A = B.hostToNick();
		if (D == "ACTION") 
		{
			this.tracker.updateLastSpoke(A, E, new Date().getTime());
			this.newChanLine(E, "CHANACTION", B, 
			{
				m: C,
				c: E,
				"@": this.getNickStatus(E, A)
			});
			return
		}
		this.newChanLine(E, "CHANCTCP", B, 
		{
			x: D,
			m: C,
			c: E,
			"@": this.getNickStatus(E, A)
		})
	},
	userCTCP: function(B, D, C)
	{
		var A = B.hostToNick();
		var E = B.hostToHost();
		if (C == undefined) 
		{
			C = ""
		}
		if (D == "ACTION") 
		{
			this.newQueryWindow(A, true);
			this.newQueryLine(A, "PRIVACTION", 
			{
				m: C,
				x: D,
				h: E,
				n: A
			}, true);
			return
		}
		this.newTargetOrActiveLine(A, "PRIVCTCP", 
		{
			m: C,
			x: D,
			h: E,
			n: A,
			"-": this.nickname
		})
	},
	userCTCPReply: function(B, D, C)
	{
		var A = B.hostToNick();
		var E = B.hostToHost();
		if (C == undefined) 
		{
			C = ""
		}
		this.newTargetOrActiveLine(A, "CTCPREPLY", 
		{
			m: C,
			x: D,
			h: E,
			n: A,
			"-": this.nickname
		})
	},
	getNickStatus: function(B, A)
	{
		var C = this.tracker.getNickOnChannel(A, B);
		if (!$defined(C)) 
		{
			return ""
		}
		if (C.prefixes.length == 0) 
		{
			return ""
		}
		return C.prefixes.charAt(0)
	},
	channelPrivmsg: function(B, D, C)
	{
		var A = B.hostToNick();
		this.tracker.updateLastSpoke(A, D, new Date().getTime());
		this.newChanLine(D, "CHANMSG", B, 
		{
			m: C,
			"@": this.getNickStatus(D, A)
		})
	},
	channelNotice: function(A, C, B)
	{
		this.newChanLine(C, "CHANNOTICE", A, 
		{
			m: B,
			"@": this.getNickStatus(C, A.hostToNick())
		})
	},
	userPrivmsg: function(B, D)
	{
		var A = B.hostToNick();
		var C = B.hostToHost();
		this.newQueryWindow(A, true);
		this.pushLastNick(A);
		this.newQueryLine(A, "PRIVMSG", 
		{
			m: D,
			h: C,
			n: A
		}, true);
		this.checkLogin(B, D)
	},
	checkLogin: function(A, B)
	{
		if (this.isNetworkService(A) && $defined(this.activeTimers.autojoin)) 
		{
			if ($defined(this.loginRegex) && B.match(this.loginRegex)) 
			{
				$clear(this.activeTimers.autojoin);
				delete this.activeTimers.autojoin;
				this.ui.getActiveWindow().infoMessage("Joining channels...");
				this.exec("/AUTOJOIN")
			}
		}
	},
	serverNotice: function(A, B)
	{
		if (A == "") 
		{
			this.newServerLine("SERVERNOTICE", 
			{
				m: B
			})
		}
		else 
		{
			this.newServerLine("PRIVNOTICE", 
			{
				m: B,
				n: A
			})
		}
	},
	userNotice: function(B, D)
	{
		var A = B.hostToNick();
		var C = B.hostToHost();
		if (this.ui.uiOptions.DEDICATED_NOTICE_WINDOW) 
		{
			this.newQueryWindow(A, false);
			this.newQueryOrActiveLine(A, "PRIVNOTICE", 
			{
				m: D,
				h: C,
				n: A
			}, false)
		}
		else 
		{
			this.newTargetOrActiveLine(A, "PRIVNOTICE", 
			{
				m: D,
				h: C,
				n: A
			})
		}
		this.checkLogin(B, D)
	},
	isNetworkService: function(A)
	{
		return this.ui.options.networkServices.indexOf(A) > -1
	},
	__joinInvited: function()
	{
		this.exec("/JOIN " + this.inviteChanList.join(","));
		this.inviteChanList = [];
		delete this.activeTimers.serviceInvite
	},
	userInvite: function(B, D)
	{
		var A = B.hostToNick();
		var C = B.hostToHost();
		this.newServerLine("INVITE", 
		{
			c: D,
			h: C,
			n: A
		});
		if (this.ui.uiOptions.ACCEPT_SERVICE_INVITES && this.isNetworkService(B)) 
		{
			if (this.activeTimers.serviceInvite) 
			{
				$clear(this.activeTimers.serviceInvite)
			}
			this.activeTimers.serviceInvite = this.__joinInvited.delay(100, this);
			this.inviteChanList.push(D)
		}
	},
	userMode: function(A)
	{
		this.newServerLine("UMODE", 
		{
			m: A,
			n: this.nickname
		})
	},
	channelNames: function(A, B)
	{
		if (B.length == 0) 
		{
			this.updateNickList(A);
			return
		}
		B.each(function(D)
		{
			var C = [];
			var E = D.split("");
			E.every(function(H, G)
			{
				if (this.prefixes.indexOf(H) == -1) 
				{
					D = D.substr(G);
					return false
				}
				C.push(H);
				return true
			}, this);
			var F = this.tracker.addNickToChannel(D, A);
			C.each(function(G)
			{
				this.addPrefix(F, G)
			}, this)
		}, this)
	},
	disconnected: function(C)
	{
		for (var A in this.windows) 
		{
			var B = this.windows[A];
			if (B.type == qwebirc.ui.WINDOW_CHANNEL) 
			{
				B.close()
			}
		}
		this.tracker = undefined;
		this.newServerLine("DISCONNECT", 
		{
			m: C
		})
	},
	nickOnChanHasPrefix: function(B, D, A)
	{
		var C = this.tracker.getNickOnChannel(B, D);
		if (!$defined(C)) 
		{
			return false
		}
		return C.prefixes.indexOf(A) != -1
	},
	supported: function(B, C)
	{
		if (B == "PREFIX") 
		{
			var A = (C.length - 2) / 2;
			this.modeprefixes = C.substr(1, A);
			this.prefixes = C.substr(A + 2, A)
		}
		this.parent(B, C)
	},
	connected: function()
	{
		this.newServerLine("CONNECT")
	},
	serverError: function(A)
	{
		this.newServerLine("ERROR", 
		{
			m: A
		})
	},
	quit: function(A)
	{
		this.send("QUIT :" + A);
		this.disconnect()
	},
	disconnect: function()
	{
		for (var A in this.activeTimers) 
		{
			this.activeTimers[A].cancel()
		}
		this.activeTimers = {};
		this.parent()
	},
	awayMessage: function(A, B)
	{
		this.newQueryLine(A, "AWAY", 
		{
			n: A,
			m: B
		}, true)
	},
	whois: function(A, C, E)
	{
		var D = 
		{
			n: A
		};
		var F;
		var B = function()
		{
			this.newTargetOrActiveLine(A, "WHOIS" + F, D)
		}
.bind(this);
		if (C == "user") 
		{
			F = "USER";
			D.h = E.ident + "@" + E.hostname;
			B();
			F = "REALNAME";
			D.m = E.realname
		}
		else 
		{
			if (C == "server") 
			{
				F = "SERVER";
				D.x = E.server;
				D.m = E.serverdesc
			}
			else 
			{
				if (C == "oper") 
				{
					F = "OPER"
				}
				else 
				{
					if (C == "idle") 
					{
						F = "IDLE";
						D.x = qwebirc.util.longtoduration(E.idle);
						D.m = qwebirc.irc.IRCDate(new Date(E.connected * 1000))
					}
					else 
					{
						if (C == "channels") 
						{
							F = "CHANNELS";
							D.m = E.channels
						}
						else 
						{
							if (C == "account") 
							{
								F = "ACCOUNT";
								D.m = E.account
							}
							else 
							{
								if (C == "away") 
								{
									F = "AWAY";
									D.m = E.away
								}
								else 
								{
									if (C == "opername") 
									{
										F = "OPERNAME";
										D.m = E.opername
									}
									else 
									{
										if (C == "actually") 
										{
											F = "ACTUALLY";
											D.m = E.hostname;
											D.x = E.ip
										}
										else 
										{
											if (C == "generictext") 
											{
												F = "GENERICTEXT";
												D.m = E.text
											}
											else 
											{
												if (C == "end") 
												{
													F = "END"
												}
												else 
												{
													return false
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
		B();
		return true
	},
	genericError: function(B, A)
	{
		this.newTargetOrActiveLine(B, "GENERICERROR", 
		{
			m: A,
			t: B
		})
	},
	genericQueryError: function(B, A)
	{
		this.newQueryOrActiveLine(B, "GENERICERROR", 
		{
			m: A,
			t: B
		}, true)
	},
	awayStatus: function(B, A)
	{
		this.newActiveLine("GENERICMESSAGE", 
		{
			m: A
		})
	},
	pushLastNick: function(A)
	{
		var B = this.lastNicks.indexOf(A);
		if (B != -1) 
		{
			this.lastNicks.splice(B, 1)
		}
		else 
		{
			if (this.lastNicks.length == this.options.maxnicks) 
			{
				this.lastNicks.pop()
			}
		}
		this.lastNicks.unshift(A)
	},
	wallops: function(B, D)
	{
		var A = B.hostToNick();
		var C = B.hostToHost();
		this.newServerLine("WALLOPS", 
		{
			t: D,
			n: A,
			h: C
		})
	},
	channelModeIs: function(A, B)
	{
		this.newTargetOrActiveLine(A, "CHANNELMODEIS", 
		{
			c: A,
			m: B.join(" ")
		})
	},
	channelCreationTime: function(A, B)
	{
		this.newTargetOrActiveLine(A, "CHANNELCREATIONTIME", 
		{
			c: A,
			m: qwebirc.irc.IRCDate(new Date(B * 1000))
		})
	}
});
qwebirc.irc.CommandHistory = new Class(
{
	Implements: [Options],
	options: 
	{
		lines: 20
	},
	initialize: function(A)
	{
		this.setOptions(A);
		this.data = [];
		this.position = 0
	},
	addLine: function(A, B)
	{
		if ((this.data.length == 0) || (A != this.data[0])) 
		{
			this.data.unshift(A)
		}
		if (B) 
		{
			this.position = 0
		}
		else 
		{
			this.position = -1
		}
		if (this.data.length > this.options.lines) 
		{
			this.data.pop()
		}
	},
	upLine: function()
	{
		if (this.data.length == 0) 
		{
			return null
		}
		if (this.position >= this.data.length) 
		{
			return null
		}
		this.position = this.position + 1;
		return this.data[this.position]
	},
	downLine: function()
	{
		if (this.position == -1) 
		{
			return null
		}
		this.position = this.position - 1;
		if (this.position == -1) 
		{
			return null
		}
		return this.data[this.position]
	}
});
qwebirc.ui.UI_COMMANDS = [["Options", "options"], ["Add webchat to your site", "embedded"], ["Privacy policy", "privacy"], ["Feedback", "feedback"], ["Frequently asked questions", "faq"], ["About qwebirc", "about"]];
qwebirc.ui.MENU_ITEMS = function()
{
	var D = function(H)
	{
		var I = this.name;
		var J = this.client.nickname;
		return this.client.nickOnChanHasPrefix(J, I, "@")
	};
	var C = function(H)
	{
		var I = this.name;
		var J = this.client.nickname;
		return this.client.nickOnChanHasPrefix(J, I, "+")
	};
	var B = function(H)
	{
		var I = this.name;
		return this.client.nickOnChanHasPrefix(H, I, "@")
	};
	var A = function(H)
	{
		var I = this.name;
		return this.client.nickOnChanHasPrefix(H, I, "+")
	};
	var G = qwebirc.util.invertFn, E = qwebirc.util.composeAnd;
	var F = function(H)
	{
		return function(I)
		{
			this.client.exec("/" + H + " " + I)
		}
	};
	return [{
		text: "whois",
		fn: F("whois"),
		predicate: true
	}, {
		text: "query",
		fn: F("query"),
		predicate: true
	}, {
		text: "slap",
		fn: function(H)
		{
			this.client.exec("/ME slaps " + H + " around a bit with a large fishbot")
		},
		predicate: true
	}, {
		text: "kick",
		fn: function(H)
		{
			this.client.exec("/KICK " + H + " wibble")
		},
		predicate: D
	}, {
		text: "op",
		fn: F("op"),
		predicate: E(D, G(B))
	}, {
		text: "deop",
		fn: F("deop"),
		predicate: E(D, B)
	}, {
		text: "voice",
		fn: F("voice"),
		predicate: E(D, G(A))
	}, {
		text: "devoice",
		fn: F("devoice"),
		predicate: E(D, A)
	}]
}();
qwebirc.ui.WINDOW_STATUS = 1;
qwebirc.ui.WINDOW_QUERY = 2;
qwebirc.ui.WINDOW_CHANNEL = 4;
qwebirc.ui.WINDOW_CUSTOM = 8;
qwebirc.ui.WINDOW_CONNECT = 16;
qwebirc.ui.WINDOW_MESSAGES = 32;
qwebirc.ui.CUSTOM_CLIENT = "custom";
qwebirc.ui.BaseUI = new Class(
{
	Implements: [Events],
	initialize: function(C, B, D, A)
	{
		this.options = A;
		this.windows = {};
		this.clients = {};
		this.windows[qwebirc.ui.CUSTOM_CLIENT] = {};
		this.windowArray = [];
		this.windowClass = B;
		this.parentElement = C;
		this.parentElement.addClass("qwebirc");
		this.parentElement.addClass("qwebirc-" + D);
		this.firstClient = false;
		this.commandhistory = new qwebirc.irc.CommandHistory();
		this.clientId = 0;
		this.windowFocused = true;
		window.addEvent("blur", function()
		{
			if (this.windowFocused) 
			{
				this.windowFocused = false;
				this.focusChange(false)
			}
		}
.bind(this));
		window.addEvent("focus", function()
		{
			if (!this.windowFocused) 
			{
				this.windowFocused = true;
				this.focusChange(true)
			}
		}
.bind(this))
	},
	newClient: function(B)
	{
		B.id = this.clientId++;
		B.hilightController = new qwebirc.ui.HilightController(B);
		this.windows[B.id] = {};
		this.clients[B.id] = B;
		var A = this.newWindow(B, qwebirc.ui.WINDOW_STATUS, "Status");
		this.selectWindow(A);
		if (!this.firstClient) 
		{
			this.firstClient = true;
			A.addLine("", "qwebirc v" + qwebirc.VERSION);
			A.addLine("", "Copyright (C) 2008-2009 Chris Porter and the qwebirc project.");
			A.addLine("", "http://www.qwebirc.org");
			A.addLine("", "Licensed under the GNU General Public License, Version 2.")
		}
		return A
	},
	getClientId: function(A)
	{
		if (A == qwebirc.ui.CUSTOM_CLIENT) 
		{
			return qwebirc.ui.CUSTOM_CLIENT
		}
		else 
		{
			return A.id
		}
	},
	getWindowIdentifier: function(C, B, A)
	{
		if (B == qwebirc.ui.WINDOW_MESSAGES) 
		{
			return "-M"
		}
		if (B == qwebirc.ui.WINDOW_STATUS) 
		{
			return ""
		}
		if (C == qwebirc.ui.CUSTOM_CLIENT) 
		{
			return "_" + A
		}
		return "_" + C.toIRCLower(A)
	},
	newWindow: function(D, C, B)
	{
		var A = this.getWindow(D, C, B);
		if ($defined(A)) 
		{
			return A
		}
		var E = this.getWindowIdentifier(D, C, B);
		var A = this.windows[this.getClientId(D)][E] = new this.windowClass(this, D, C, B, E);
		this.windowArray.push(A);
		return A
	},
	getWindow: function(C, B, A)
	{
		var D = this.windows[this.getClientId(C)];
		if (!$defined(D)) 
		{
			return null
		}
		return D[this.getWindowIdentifier(C, B, A)]
	},
	getActiveWindow: function()
	{
		return this.active
	},
	getActiveIRCWindow: function(A)
	{
		if (!this.active || this.active.type == qwebirc.ui.WINDOW_CUSTOM) 
		{
			return this.windows[this.getClientId(A)][this.getWindowIdentifier(A, qwebirc.ui.WINDOW_STATUS)]
		}
		else 
		{
			return this.active
		}
	},
	__setActiveWindow: function(A)
	{
		this.active = A
	},
	selectWindow: function(A)
	{
		if (this.active) 
		{
			this.active.deselect()
		}
		A.select();
		this.updateTitle(A.name + " - " + this.options.appTitle)
	},
	updateTitle: function(A)
	{
		document.title = A
	},
	nextWindow: function(B)
	{
		if (this.windowArray.length == 0 || !this.active) 
		{
			return
		}
		if (!B) 
		{
			B = 1
		}
		var A = this.windowArray.indexOf(this.active);
		if (A == -1) 
		{
			return
		}
		A = A + B;
		if (A < 0) 
		{
			A = this.windowArray.length - 1
		}
		else 
		{
			if (A >= this.windowArray.length) 
			{
				A = 0
			}
		}
		this.selectWindow(this.windowArray[A])
	},
	prevWindow: function()
	{
		this.nextWindow(-1)
	},
	__closed: function(A)
	{
		if (A.active) 
		{
			this.active = undefined;
			if (this.windowArray.length == 1) 
			{
				this.windowArray = []
			}
			else 
			{
				var B = this.windowArray.indexOf(A);
				if (B == -1) 
				{
					return
				}
				else 
				{
					if (B == 0) 
					{
						this.selectWindow(this.windowArray[1])
					}
					else 
					{
						this.selectWindow(this.windowArray[B - 1])
					}
				}
			}
		}
		this.windowArray = this.windowArray.erase(A);
		delete this.windows[this.getClientId(A.client)][A.identifier]
	},
	loginBox: function(D, E, B, C, A)
	{
		qwebirc.ui.GenericLoginBox(this.parentElement, D, E, B, C, A, this.options.networkName)
	},
	focusChange: function(B)
	{
		var A = this.getActiveWindow();
		if ($defined(A)) 
		{
			A.focusChange(B)
		}
	}
});
qwebirc.ui.StandardUI = new Class(
{
	Extends: qwebirc.ui.BaseUI,
	UICommands: qwebirc.ui.UI_COMMANDS,
	initialize: function(D, C, E, A)
	{
		this.parent(D, C, E, A);
		this.tabCompleter = new qwebirc.ui.TabCompleterFactory(this);
		this.uiOptions = new qwebirc.ui.DefaultOptionsClass(this);
		this.customWindows = {};
		var B;
		if (Browser.Engine.trident) 
		{
			B = "keydown"
		}
		else 
		{
			B = "keypress"
		}
		document.addEvent(B, this.__handleHotkey.bind(this))
	},
	__handleHotkey: function(A)
	{
		if (!A.alt || A.control) 
		{
			if (A.key == "backspace" || A.key == "/") 
			{
				if (!this.getInputFocused(A)) 
				{
					new Event(A).stop()
				}
			}
			return
		}
		var F = false;
		if (A.key == "a" || A.key == "A") 
		{
			var E = 0;
			var D = -1;
			F = true;
			new Event(A).stop();
			for (var B = 0; B < this.windowArray.length; B++) 
			{
				var C = this.windowArray[B].hilighted;
				if (C > E) 
				{
					D = B;
					E = C
				}
			}
			if (D > -1) 
			{
				this.selectWindow(this.windowArray[D])
			}
		}
		else 
		{
			if (A.key >= "0" && A.key <= "9") 
			{
				F = true;
				number = A.key - "0";
				if (number == 0) 
				{
					number = 10
				}
				number = number - 1;
				if (number >= this.windowArray.length) 
				{
					return
				}
				this.selectWindow(this.windowArray[number])
			}
			else 
			{
				if (A.key == "left") 
				{
					this.prevWindow();
					F = true
				}
				else 
				{
					if (A.key == "right") 
					{
						this.nextWindow();
						F = true
					}
				}
			}
		}
		if (F) 
		{
			new Event(A).stop()
		}
	},
	getInputFocused: function(A)
	{
		if ($$("input").indexOf(A.target) == -1 && $$("textarea").indexOf(A.target) == -1) 
		{
			return false
		}
		return true
	},
	newCustomWindow: function(B, D, C)
	{
		if (!C) 
		{
			C = qwebirc.ui.WINDOW_CUSTOM
		}
		var A = this.newWindow(qwebirc.ui.CUSTOM_CLIENT, C, B);
		A.addEvent("close", function(E)
		{
			delete this.windows[qwebirc.ui.CUSTOM_CLIENT][E.identifier]
		}
.bind(this));
		if (D) 
		{
			this.selectWindow(A)
		}
		return A
	},
	addCustomWindow: function(A, E, D, B)
	{
		if (!$defined(B)) 
		{
			B = {}
		}
		if (this.customWindows[A]) 
		{
			this.selectWindow(this.customWindows[A]);
			return
		}
		var F = this.newCustomWindow(A, true);
		this.customWindows[A] = F;
		F.addEvent("close", function()
		{
			this.customWindows[A] = null
		}
.bind(this));
		if (D) 
		{
			F.lines.addClass("qwebirc-" + D)
		}
		var C = new E(F.lines, B);
		C.addEvent("close", function()
		{
			F.close()
		}
.bind(this));
		F.setSubWindow(C)
	},
	embeddedWindow: function()
	{
		this.addCustomWindow("Embedding wizard", qwebirc.ui.EmbedWizard, "embeddedwizard", 
		{
			baseURL: this.options.baseURL
		})
	},
	optionsWindow: function()
	{
		this.addCustomWindow("Options", qwebirc.ui.OptionsPane, "optionspane", this.uiOptions)
	},
	aboutWindow: function()
	{
		this.addCustomWindow("About", qwebirc.ui.AboutPane, "aboutpane", this.uiOptions)
	},
	privacyWindow: function()
	{
		this.addCustomWindow("Privacy policy", qwebirc.ui.PrivacyPolicyPane, "privacypolicypane", this.uiOptions)
	},
	feedbackWindow: function()
	{
		this.addCustomWindow("Feedback", qwebirc.ui.FeedbackPane, "feedbackpane", this.uiOptions)
	},
	faqWindow: function()
	{
		this.addCustomWindow("FAQ", qwebirc.ui.FAQPane, "faqpane", this.uiOptions)
	},
	urlDispatcher: function(B, A)
	{
		if (B == "embedded") 
		{
			return ["a", this.embeddedWindow.bind(this)]
		}
		if (B == "options") 
		{
			return ["a", this.optionsWindow.bind(this)]
		}
		if (B == "whois") 
		{
			return ["span", function(C)
			{
				this.client.exec("/WHOIS " + C)
			}
.bind(A)]
		}
		return null
	},
	tabComplete: function(A)
	{
		this.tabCompleter.tabComplete(A)
	},
	resetTabComplete: function()
	{
		this.tabCompleter.reset()
	}
});
qwebirc.ui.NotificationUI = new Class(
{
	Extends: qwebirc.ui.StandardUI,
	initialize: function(C, B, D, A)
	{
		this.parent(C, B, D, A);
		this.__beeper = new qwebirc.ui.Beeper(this.uiOptions);
		this.__flasher = new qwebirc.ui.Flasher(this.uiOptions);
		this.beep = this.__beeper.beep.bind(this.__beeper);
		this.flash = this.__flasher.flash.bind(this.__flasher);
		this.cancelFlash = this.__flasher.cancelFlash.bind(this.__flasher)
	},
	setBeepOnMention: function(A)
	{
		if (A) 
		{
			this.__beeper.soundInit()
		}
	},
	updateTitle: function(A)
	{
		if (this.__flasher.updateTitle(A)) 
		{
			this.parent(A)
		}
	},
	focusChange: function(A)
	{
		this.parent(A);
		this.__flasher.focusChange(A)
	}
});
qwebirc.ui.NewLoginUI = new Class(
{
	Extends: qwebirc.ui.NotificationUI,
	loginBox: function(A, G, D, F, C)
	{
		this.postInitialize();
		var B = this.newCustomWindow("Connect", true, qwebirc.ui.WINDOW_CONNECT);
		var E = function(H)
		{
			B.close();
			A(H)
		};
		qwebirc.ui.GenericLoginBox(B.lines, E, G, D, F, C, this.options.networkName)
	}
});
qwebirc.ui.QuakeNetUI = new Class(
{
	Extends: qwebirc.ui.NewLoginUI,
	urlDispatcher: function(B, A)
	{
		if (B == "qwhois") 
		{
			return ["span", function(C)
			{
				this.client.exec("/MSG Q whois #" + C)
			}
.bind(A)]
		}
		return this.parent(B, A)
	},
	logout: function()
	{
		if (!qwebirc.auth.loggedin()) 
		{
			return
		}
		if (confirm("Log out?")) 
		{
			for (var A in this.clients) 
			{
				this.clients[A].quit("Logged out")
			}
			var B = function()
			{
				document.location = "/auth?logout=1"
			};
			B.delay(500)
		}
	}
});
qwebirc.ui.RootUI = qwebirc.ui.QuakeNetUI;
qwebirc.ui.HILIGHT_NONE = 0;
qwebirc.ui.HILIGHT_ACTIVITY = 1;
qwebirc.ui.HILIGHT_SPEECH = 2;
qwebirc.ui.HILIGHT_US = 3;
qwebirc.ui.WINDOW_LASTLINE = qwebirc.ui.WINDOW_QUERY | qwebirc.ui.WINDOW_MESSAGES | qwebirc.ui.WINDOW_CHANNEL | qwebirc.ui.WINDOW_STATUS;
qwebirc.ui.Window = new Class(
{
	Implements: [Events],
	initialize: function(E, D, C, A, B)
	{
		this.parentObject = E;
		this.type = C;
		this.name = A;
		this.active = false;
		this.client = D;
		this.identifier = B;
		this.hilighted = qwebirc.ui.HILIGHT_NONE;
		this.scrolltimer = null;
		this.commandhistory = this.parentObject.commandhistory;
		this.scrolleddown = true;
		this.scrollpos = null;
		this.lastNickHash = {};
		this.lastSelected = null;
		this.subWindow = null;
		this.closed = false;
		if (this.type & qwebirc.ui.WINDOW_LASTLINE) 
		{
			this.lastPositionLine = new Element("hr");
			this.lastPositionLine.addClass("lastpos");
			this.lastPositionLineInserted = false
		}
	},
	updateTopic: function(B, A)
	{
		var logo = new Element('img',
		{
			src: 'images/yafLogoSml.png',
			styles: 
			{
				'position':'relative',
				'top':'-3px',
				'left':'0px',
				'z-index':'100',
				'float': 'left',
				'margin-right': '2px'
			}		
		});
		
		A.appendChild(logo);
		
		qwebirc.ui.Colourise("[" + B + "]", A, this.client.exec, this.parentObject.urlDispatcher.bind(this.parentObject), this)
	},
	close: function()
	{
		this.closed = true;
		if ($defined(this.scrolltimer)) 
		{
			$clear(this.scrolltimer);
			this.scrolltimer = null
		}
		this.parentObject.__closed(this);
		this.fireEvent("close", this)
	},
	subEvent: function(A)
	{
		if ($defined(this.subWindow)) 
		{
			this.subWindow.fireEvent(A)
		}
	},
	setSubWindow: function(A)
	{
		this.subWindow = A
	},
	select: function()
	{
		if (this.lastPositionLineInserted && !this.parentObject.uiOptions.LASTPOS_LINE) 
		{
			this.lines.removeChild(this.lastPositionLine);
			this.lastPositionLineInserted = false
		}
		this.active = true;
		this.parentObject.__setActiveWindow(this);
		if (this.hilighted) 
		{
			this.setHilighted(qwebirc.ui.HILIGHT_NONE)
		}
		this.subEvent("select");
		this.resetScrollPos();
		this.lastSelected = new Date()
	},
	deselect: function()
	{
		this.subEvent("deselect");
		this.setScrollPos();
		if ($defined(this.scrolltimer)) 
		{
			$clear(this.scrolltimer);
			this.scrolltimer = null
		}
		if (this.type & qwebirc.ui.WINDOW_LASTLINE) 
		{
			this.replaceLastPositionLine()
		}
		this.active = false
	},
	resetScrollPos: function()
	{
		if (this.scrolleddown) 
		{
			this.scrollToBottom()
		}
		else 
		{
			if ($defined(this.scrollpos)) 
			{
				this.getScrollParent().scrollTo(this.scrollpos.x, this.scrollpos.y)
			}
		}
	},
	setScrollPos: function()
	{
		if (!this.parentObject.singleWindow) 
		{
			this.scrolleddown = this.scrolledDown();
			this.scrollpos = this.lines.getScroll()
		}
	},
	addLine: function(D, A, F, B)
	{
		var C = qwebirc.ui.HILIGHT_NONE;
		var E = false;
		if (D) 
		{
			C = qwebirc.ui.HILIGHT_ACTIVITY;
			if (D.match(/(NOTICE|ACTION|MSG)$/)) 
			{
				if (this.type == qwebirc.ui.WINDOW_QUERY || this.type == qwebirc.ui.WINDOW_MESSAGES) 
				{
					if (D.match(/^OUR/) || D.match(/NOTICE$/)) 
					{
						C = qwebirc.ui.HILIGHT_ACTIVITY
					}
					else 
					{
						C = qwebirc.ui.HILIGHT_US;
						this.parentObject.beep();
						this.parentObject.flash()
					}
				}
				if (!D.match(/^OUR/) && this.client.hilightController.match(A.m)) 
				{
					E = true;
					C = qwebirc.ui.HILIGHT_US;
					this.parentObject.beep();
					this.parentObject.flash()
				}
				else 
				{
					if (C != qwebirc.ui.HILIGHT_US) 
					{
						C = qwebirc.ui.HILIGHT_SPEECH
					}
				}
			}
		}
		if (!this.active && (C != qwebirc.ui.HILIGHT_NONE)) 
		{
			this.setHilighted(C)
		}
		if (D) 
		{
			A = this.parentObject.theme.message(D, A, E)
		}
		qwebirc.ui.Colourise(qwebirc.irc.IRCTimestamp(new Date()) + " " + A, B, this.client.exec, this.parentObject.urlDispatcher.bind(this.parentObject), this);
		this.scrollAdd(B)
	},
	errorMessage: function(A)
	{
		this.addLine("", A, "warncolour")
	},
	infoMessage: function(A)
	{
		this.addLine("", A, "infocolour")
	},
	setHilighted: function(A)
	{
		if (A == qwebirc.ui.HILIGHT_NONE || A >= this.hilighted) 
		{
			this.hilighted = A
		}
	},
	scrolledDown: function()
	{
		if (this.scrolltimer) 
		{
			return true
		}
		var A = this.lines;
		var D = A.getScroll();
		var C = A.getScrollSize().y;
		var B = A.getSize();
		if (C < B.y) 
		{
			C = B.y
		}
		return D.y + B.y == C
	},
	getScrollParent: function()
	{
		var A = this.lines;
		if ($defined(this.scroller)) 
		{
			A = this.scroller
		}
		return A
	},
	scrollToBottom: function()
	{
		if (this.type == qwebirc.ui.WINDOW_CUSTOM || this.type == qwebirc.ui.WINDOW_CONNECT) 
		{
			return
		}
		var B = this.lines;
		var A = this.getScrollParent();
		A.scrollTo(B.getScroll().x, B.getScrollSize().y)
	},
	scrollAdd: function(B)
	{
		var A = this.lines;
		if ($defined(B)) 
		{
			var C = this.scrolledDown();
			A.appendChild(B);
			if (C) 
			{
				if (this.scrolltimer) 
				{
					$clear(this.scrolltimer)
				}
				this.scrolltimer = this.scrollAdd.delay(50, this, [null])
			}
		}
		else 
		{
			this.scrollToBottom();
			this.scrolltimer = null
		}
	},
	updateNickList: function(F)
	{
		var A = {}, B = {};
		var I = [];
		var H = this.lastNickHash;
		for (var G = 0; G < F.length; G++) 
		{
			B[F[G]] = 1
		}
		for (var E in H) 
		{
			if (!B[E]) 
			{
				this.nickListRemove(E, H[E])
			}
		}
		for (var G = 0; G < F.length; G++) 
		{
			var C = F[G];
			var D = H[C];
			if (!D) 
			{
				D = this.nickListAdd(C, G);
				if (!D) 
				{
					D = 1
				}
			}
			A[C] = D
		}
		this.lastNickHash = A
	},
	nickListAdd: function(B, A)
	{
	},
	nickListRemove: function(A, B)
	{
	},
	historyExec: function(A)
	{
		this.commandhistory.addLine(A);
		this.client.exec(A)
	},
	focusChange: function(A)
	{
		if (A == true || !(this.type & qwebirc.ui.WINDOW_LASTLINE)) 
		{
			return
		}
		this.replaceLastPositionLine()
	},
	replaceLastPositionLine: function()
	{
		if (this.parentObject.uiOptions.LASTPOS_LINE) 
		{
			if (!this.lastPositionLineInserted) 
			{
				this.scrollAdd(this.lastPositionLine)
			}
			else 
			{
				if (this.lines.lastChild != this.lastPositionLine) 
				{
					this.lines.removeChild(this.lastPositionLine);
					this.scrollAdd(this.lastPositionLine)
				}
			}
		}
		else 
		{
			if (this.lastPositionLineInserted) 
			{
				this.lines.removeChild(this.lastPositionLine)
			}
		}
		this.lastPositionLineInserted = this.parentObject.uiOptions.LASTPOS_LINE
	}
});
qwebirc.ui.Colourise = function(I, B, R, A, D)
{
	var K;
	var E;
	var C = false;
	var M = false;
	var P = [];
	var J = I.split("");
	var G = document.createElement("span");
	B.addClass("colourline");

	function L(S)
	{
		return S >= "0" && S <= "9"
	}
	function O(T, S)
	{
		if (!L(T[S + 1])) 
		{
			K = undefined;
			E = undefined;
			return S
		}
		S++;
		if (L(T[S + 1])) 
		{
			K = parseInt(T[S] + T[S + 1]);
			S++
		}
		else 
		{
			K = parseInt(T[S])
		}
		if (T[S + 1] != ",") 
		{
			return S
		}
		if (!L(T[S + 2])) 
		{
			return S
		}
		S += 2;
		if (L(T[S + 1])) 
		{
			E = parseInt(T[S] + T[S + 1]);
			S++
		}
		else 
		{
			E = parseInt(T[S])
		}
		return S
	}
	function F()
	{
		if (P.length > 0) 
		{
			qwebirc.ui.urlificate(G, P.join(""), R, A, D);
			B.appendChild(G);
			P = []
		}
		G = document.createElement("span")
	}
	function H()
	{
		var S = [];
		if (K != undefined) 
		{
			S.push("Xc" + K)
		}
		if (E != undefined) 
		{
			S.push("Xbc" + E)
		}
		if (M) 
		{
			S.push("Xb")
		}
		if (C) 
		{
			S.push("Xu")
		}
		G.className = S.join(" ")
	}
	for (var Q = 0; Q < J.length; Q++) 
	{
		var N = J[Q];
		if (N == "\x02") 
		{
			F();
			M = !M;
			H()
		}
		else 
		{
			if (N == "\x1F") 
			{
				F();
				C = !C;
				H()
			}
			else 
			{
				if (N == "\x0F") 
				{
					F();
					K = undefined;
					E = undefined;
					C = false;
					M = false
				}
				else 
				{
					if (N == "\x03") 
					{
						F();
						Q = O(J, Q);
						if (E > 15) 
						{
							E = undefined
						}
						if (K > 15) 
						{
							K = undefined
						}
						H()
					}
					else 
					{
						P.push(N)
					}
				}
			}
		}
	}
	F()
};
qwebirc.ui.urlificate = function(C, H, B, E, A)
{
	var G = /[[\)|\]]?(\.*|[\,;])$/;
	var J = function(S, R, Q, M)
	{
		for (;;) 
		{
			var O = S.search(R);
			if (O == -1) 
			{
				Q(S);
				break
			}
			var N = S.match(R);
			var T = S.substring(0, O);
			var L = N[0];
			var K = S.substring(O + L.length);
			Q(T);
			var P = M(L, Q);
			if (!P) 
			{
				P = ""
			}
			S = P + K
		}
	};
	var D = function(K)
	{
		qwebirc.util.NBSPCreate(K, C)
	};
	var I = function(M)
	{
		var N = M.replace(G, "");
		var L = M.substring(N.length);
		var K = new Element("span");
		K.href = "#";
		K.addClass("hyperlink-channel");
		K.addEvent("click", function(O)
		{
			new Event(O).stop();
			B("/JOIN " + N)
		});
		K.appendChild(document.createTextNode(N));
		C.appendChild(K);
		return L
	};
	var F = function(X, T)
	{
		var L = X.replace(G, "");
		var O = X.substring(L.length);
		var K = "";
		var U = null;
		var N = "new";
		var R = L;
		var S = "a";
		var M;
		var W = L.match(/^qwebirc:\/\/(.*)$/);
		if (W) 
		{
			var Q = W[1].match(/^([^\/]+)\/([^\/]+)\/?(.*)$/);
			if (!Q) 
			{
				T(X);
				return
			}
			var P = E(Q[1], A);
			if (P) 
			{
				M = Q[1];
				S = P[0];
				if (P[0] != "a") 
				{
					L = null
				}
				else 
				{
					L = "#"
				}
				U = P[1];
				R = unescape(Q[2]);
				N = null
			}
			else 
			{
				T(X);
				return
			}
			if (Q[3]) 
			{
				O = Q[3] + O
			}
		}
		else 
		{
			if (L.match(/^www\./)) 
			{
				L = "http://" + L
			}
		}
		var V = new Element(S);
		if (M) 
		{
			V.addClass("hyperlink-" + M)
		}
		if (L) 
		{
			V.href = L;
			if (N) 
			{
				V.target = N
			}
		}
		V.appendChild(document.createTextNode(R));
		C.appendChild(V);
		if ($defined(U)) 
		{
			V.addEvent("click", function(Y)
			{
				new Event(Y).stop();
				U(R)
			})
		}
		return O
	};
	J(H, /\b((https?|ftp|qwebirc):\/\/|www\.)[^ ]+/, function(K)
	{
		J(K, /\B#[^ ,]+/, D, I)
	}, F)
};
qwebirc.ui.themes.ThemeControlCodeMap = 
{
	C: "\x03",
	B: "\x02",
	U: "\x1F",
	O: "\x0F",
	"[": "qwebirc://whois/",
	"]": "/",
	"$": "$"
};
qwebirc.ui.themes.Default = 
{
	PREFIX: ["$C4==$O "],
	SIGNON: ["Signed on!", true],
	CONNECT: ["Connected to server.", true],
	RAW: ["$m", true],
	DISCONNECT: ["Disconnected from server: $m", true],
	ERROR: ["ERROR: $m", true],
	SERVERNOTICE: ["$m", true],
	JOIN: ["$N [$h] has joined $c", true],
	OURJOIN: ["$N [$h] has joined $c", true],
	PART: ["$N [$h] has left $c [$m]", true],
	KICK: ["$v was kicked from $c by $N [$m]", true],
	MODE: ["mode/$c [$m] by $N", true],
	QUIT: ["$N [$h] has quit [$m]", true],
	NICK: ["$n has changed nick to $[$w$]", true],
	TOPIC: ["$N changed the topic of $c to: $m", true],
	UMODE: ["Usermode change: $m", true],
	INVITE: ["$N invites you to join $c", true],
	HILIGHT: ["$C4"],
	HILIGHTEND: ["$O"],
	CHANMSG: ["<$@$($N$)> $m"],
	PRIVMSG: ["<$($N$)> $m"],
	CHANNOTICE: ["-$($N$):$c- $m"],
	PRIVNOTICE: ["-$($N$)- $m"],
	OURCHANMSG: ["<$B$@$N$B> $m"],
	OURPRIVMSG: ["<$B$N$B> $m"],
	OURTARGETEDMSG: ["*$[$t$]* $m"],
	OURTARGETEDNOTICE: ["[notice($[$t$])] $m"],
	OURCHANNOTICE: ["-$N:$t- $m"],
	OURPRIVNOTICE: ["-$N- $m"],
	OURCHANACTION: [" * $N $m"],
	OURPRIVACTION: [" * $N $m"],
	CHANACTION: [" * $($N$) $m"],
	PRIVACTION: [" * $($N$) $m"],
	CHANCTCP: ["$N [$h] requested CTCP $x from $c: $m"],
	PRIVCTCP: ["$N [$h] requested CTCP $x from $-: $m"],
	CTCPREPLY: ["CTCP $x reply from $N: $m"],
	OURCHANCTCP: ["[ctcp($t)] $x $m"],
	OURPRIVCTCP: ["[ctcp($t)] $x $m"],
	OURTARGETEDCTCP: ["[ctcp($t)] $x $m"],
	WHOISUSER: ["$B$N$B [$h]", true],
	WHOISREALNAME: [" realname : $m", true],
	WHOISCHANNELS: [" channels : $m", true],
	WHOISSERVER: [" server   : $x [$m]", true],
	WHOISACCOUNT: [" account  : qwebirc://qwhois/$m", true],
	WHOISIDLE: [" idle     : $x [connected: $m]", true],
	WHOISAWAY: [" away     : $m", true],
	WHOISOPER: ["          : $BIRC Operator$B", true],
	WHOISOPERNAME: [" operedas : $m", true],
	WHOISACTUALLY: [" realhost : $m [ip: $x]", true],
	WHOISGENERICTEXT: ["          : $m", true],
	WHOISEND: ["End of WHOIS", true],
	AWAY: ["$N is away: $m", true],
	GENERICERROR: ["$m: $t", true],
	GENERICMESSAGE: ["$m", true],
	WALLOPS: ["WALLOP $n: $t", true],
	CHANNELCREATIONTIME: ["Channel $c was created at: $m", true],
	CHANNELMODEIS: ["Channel modes on $c are: $m", true]
};
qwebirc.ui.Theme = new Class(
{
	initialize: function(B)
	{
		this.__theme = qwebirc.util.dictCopy(qwebirc.ui.themes.Default);
		if (B) 
		{
			for (var A in B) 
			{
				this.__theme[A] = B[A]
			}
		}
		for (var A in this.__theme) 
		{
			if (A == "PREFIX") 
			{
				continue
			}
			var C = this.__theme[A];
			if (C[1]) 
			{
				this.__theme[A] = this.__theme.PREFIX + C[0]
			}
			else 
			{
				this.__theme[A] = C[0]
			}
		}
		this.__ccmap = qwebirc.util.dictCopy(qwebirc.ui.themes.ThemeControlCodeMap);
		this.__ccmaph = qwebirc.util.dictCopy(this.__ccmap);
		this.__ccmap["("] = "";
		this.__ccmap[")"] = "";
		this.__ccmaph["("] = this.message("HILIGHT", {}, this.__ccmap);
		this.__ccmaph[")"] = this.message("HILIGHTEND", {}, this.__ccmap)
	},
	__dollarSubstitute: function(I, F, G)
	{
		var B = [];
		var C = I.split("");
		for (var E = 0; E < C.length; E++) 
		{
			var H = C[E];
			if (H == "$" && (E <= C.length - 1)) 
			{
				var D = C[++E];
				var A = G[D];
				if (!A) 
				{
					A = F[D]
				}
				if (A) 
				{
					B.push(A)
				}
			}
			else 
			{
				B.push(H)
			}
		}
		return B.join("")
	},
	message: function(B, C, A)
	{
		var D;
		if (A) 
		{
			D = this.__ccmaph
		}
		else 
		{
			D = this.__ccmap
		}
		if (C && C.n) 
		{
			C.N = "qwebirc://whois/" + C.n + "/"
		}
		return this.__dollarSubstitute(this.__theme[B], C, D)
	}
});
qwebirc.ui.HilightController = new Class(
{
	initialize: function(A)
	{
		this.parent = A;
		this.regex = null;
		this.prevnick = null
	},
	match: function(B)
	{
		var A = this.parent.nickname;
		if (A != this.prevnick) 
		{
			this.regex = new RegExp("\\b" + RegExp.escape(A) + "\\b", "i")
		}
		if (B.match(this.regex)) 
		{
			return true
		}
		return false
	}
});
qwebirc.ui.Beeper = new Class(
{
	initialize: function(A)
	{
		this.uiOptions = A;
		this.soundInited = false;
		this.soundReady = false;
		if (this.uiOptions.BEEP_ON_MENTION) 
		{
			this.soundInit()
		}
	},
	soundInit: function()
	{
		if (this.soundInited) 
		{
			return
		}
		if (!$defined(Browser.Plugins.Flash) || Browser.Plugins.Flash.version < 8) 
		{
			return
		}
		this.soundInited = true;
		this.soundPlayer = new qwebirc.sound.SoundPlayer();
		this.soundPlayer.addEvent("ready", function()
		{
			this.soundReady = true
		}
.bind(this));
		this.soundPlayer.go()
	},
	beep: function()
	{
		if (!this.soundReady || !this.uiOptions.BEEP_ON_MENTION) 
		{
			return
		}
		this.soundPlayer.beep()
	}
});
qwebirc.ui.Flasher = new Class(
{
	initialize: function(A)
	{
		this.uiOptions = A;
		this.windowFocused = false;
		this.canUpdateTitle = true;
		this.titleText = document.title;
		this.canFlash = false
	},
	flash: function()
	{
		if (!this.uiOptions.FLASH_ON_MENTION || this.windowFocused || !this.canFlash || this.flashing) 
		{
			return
		}
		this.titleText = document.title;
		var A = function()
		{
			this.canUpdateTitle = false;
			document.title = "Activity!";
			this.flasher = B.delay(500)
		}
.bind(this);
		var B = function()
		{
			this.canUpdateTitle = true;
			document.title = this.titleText;
			this.flasher = A.delay(500)
		}
.bind(this);
		this.flashing = true;
		A()
	},
	cancelFlash: function()
	{
		if (!this.canFlash || !$defined(this.flasher)) 
		{
			return
		}
		this.flashing = false;
		$clear(this.flasher);
		this.flasher = null;
		document.title = this.titleText;
		this.canUpdateTitle = true
	},
	updateTitle: function(A)
	{
		this.titleText = A;
		return this.canUpdateTitle
	},
	focusChange: function(A)
	{
		this.windowFocused = A;
		if (A) 
		{
			this.cancelFlash()
		}
	}
});
qwebirc.ui.TabCompleterFactory = new Class(
{
	initialize: function(A)
	{
		this.ui = A;
		this.reset()
	},
	tabComplete: function(I)
	{
		var H = I.value;
		if (!$defined(this.obj)) 
		{
			this.incr = 1;
			var G = this.ui.getActiveWindow();
			if (!G) 
			{
				return
			}
			var B = qwebirc.util.getEnclosedWord(H, qwebirc.util.getCaretPos(I));
			var F = "", C = "", D = "";
			if ($defined(B)) 
			{
				var F = H.substring(0, B[0]);
				var C = B[1];
				var D = H.substring(B[0] + C.length)
			}
			var E = H.toLowerCase();
			if (H == "") 
			{
				F = "/msg ";
				obj = qwebirc.ui.QueryTabCompleter
			}
			else 
			{
				if (G.client.isChannel(C)) 
				{
					obj = qwebirc.ui.ChannelNameTabCompleter
				}
				else 
				{
					if (E.match(/^\/(q|query|msg) /i)) 
					{
						obj = qwebirc.ui.QueryTabCompleter
					}
					else 
					{
						if (G.type == qwebirc.ui.WINDOW_CHANNEL) 
						{
							if (F == "") 
							{
								if ((D != "") && D.charAt(0) == " ") 
								{
									D = ":" + D
								}
								else 
								{
									D = ": " + D
								}
								this.incr++
							}
							obj = qwebirc.ui.ChannelUsersTabCompleter
						}
						else 
						{
							return
						}
					}
				}
			}
			if (D == "") 
			{
				D = " "
			}
			this.obj = new obj(F, C, D, G);
			if (!$defined(this.obj)) 
			{
				return
			}
		}
		var A = this.obj.get();
		if (!$defined(A)) 
		{
			return
		}
		I.value = A[1];
		qwebirc.util.setCaretPos(I, A[0] + this.incr)
	},
	reset: function()
	{
		this.obj = null
	}
});
qwebirc.ui.TabIterator = new Class(
{
	initialize: function(F, B, G)
	{
		this.prefix = B;
		if (!$defined(G) || G.length == 0) 
		{
			this.list = null
		}
		else 
		{
			var D = [];
			var C = qwebirc.irc.toIRCCompletion(F, B);
			for (var E = 0; E < G.length; E++) 
			{
				var A = qwebirc.irc.toIRCCompletion(F, G[E]);
				if (A.startsWith(C)) 
				{
					D.push(G[E])
				}
			}
			this.list = D
		}
		this.pos = -1
	},
	next: function()
	{
		if (!$defined(this.list)) 
		{
			return null
		}
		this.pos = this.pos + 1;
		if (this.pos >= this.list.length) 
		{
			this.pos = 0
		}
		return this.list[this.pos]
	}
});
qwebirc.ui.BaseTabCompleter = new Class(
{
	initialize: function(B, A, E, D, C)
	{
		this.existingNick = E;
		this.prefix = A;
		this.suffix = D;
		this.iterator = new qwebirc.ui.TabIterator(B, E, C)
	},
	get: function()
	{
		var B = this.iterator.next();
		if (!$defined(B)) 
		{
			return null
		}
		var A = this.prefix + B;
		return [A.length, A + this.suffix]
	}
});
qwebirc.ui.QueryTabCompleter = new Class(
{
	Extends: qwebirc.ui.BaseTabCompleter,
	initialize: function(A, D, C, B)
	{
		this.parent(B.client, A, D, C, B.client.lastNicks)
	}
});
qwebirc.ui.ChannelNameTabCompleter = new Class(
{
	Extends: qwebirc.ui.BaseTabCompleter,
	initialize: function(C, B, J, A)
	{
		var E = [];
		var F = A.parentObject.windows[A.parentObject.getClientId(A.client)];
		for (var H in A.client.channels) 
		{
			var I = F[H];
			if ($defined(I)) 
			{
				I = I.lastSelected
			}
			E.push([I, H])
		}
		E.sort(function(L, K)
		{
			return K[0] - L[0]
		});
		var D = [];
		for (var G = 0; G < E.length; G++) 
		{
			D.push(E[G][1])
		}
		this.parent(A.client, C, B, J, D)
	}
});
qwebirc.ui.ChannelUsersTabCompleter = new Class(
{
	Extends: qwebirc.ui.BaseTabCompleter,
	initialize: function(A, C, E, B)
	{
		var D = B.client.tracker.getSortedByLastSpoke(B.name);
		this.parent(B.client, A, C, E, D)
	}
});
qwebirc.ui.GenericLoginBox = function(B, F, G, D, E, C, A)
{
	if (E) 
	{
		qwebirc.ui.ConfirmBox(B, F, G, D, C, A)
	}
	else 
	{
		qwebirc.ui.LoginBox(B, F, G, D, A)
	}
};
qwebirc.ui.AuthLogin = function(B)
{
	var A = Cookie.write("redirect", document.location);
	document.location = "./auth/";
	new Event(B).stop()
};
qwebirc.ui.ConfirmBox = function(P, O, B, H, G, N)
{
	var D = new Element("table");
	D.addClass("qwebirc-centrebox");
	P.appendChild(D);
	var J = new Element("tbody");
	D.appendChild(J);
	var M = new Element("tr");
	J.appendChild(M);
	var F = new Element("td");
	M.appendChild(F);
	var K = new Element("table");
	K.addClass("qwebirc-confirmbox");
	F.appendChild(K);
	var J = new Element("tbody");
	K.appendChild(J);
	var M = new Element("tr");
	J.appendChild(M);
	M.addClass("tr1");
	var Q = new Element("td");
	M.appendChild(Q);
	var A = new Element("b");
	A.set("text", B);
	var L = H.split(" ")[0].split(",");
	Q.appendChild(document.createTextNode("To connect to " + N + " IRC and join channel" + ((L.length > 1) ? "s" : "") + " "));
	for (var I = 0; I < L.length; I++) 
	{
		if ((L.length > 1) && (I == L.length - 1)) 
		{
			Q.appendChild(document.createTextNode(" and "))
		}
		else 
		{
			if (I > 0) 
			{
				Q.appendChild(document.createTextNode(", "))
			}
		}
		Q.appendChild(new Element("b").set("text", L[I]))
	}
	if (!G) 
	{
		Q.appendChild(document.createTextNode(" as "));
		Q.appendChild(A)
	}
	Q.appendChild(document.createTextNode(" click 'Connect'."));
	Q.appendChild(new Element("br"));
	if (qwebirc.auth.enabled() && qwebirc.auth.quakeNetAuth() && !qwebirc.auth.loggedin()) 
	{
		Q.appendChild(document.createTextNode("If you'd like to connect using your Q auth click 'Log in'."))
	}
	var M = new Element("tr");
	J.appendChild(M);
	M.addClass("tr2");
	var F = new Element("td");
	M.appendChild(F);
	var C = new Element("input", 
	{
		type: "submit",
		value: "Connect"
	});
	F.appendChild(C);
	C.focus();
	C.addEvent("click", function(R)
	{
		P.removeChild(D);
		O(
		{
			nickname: B,
			autojoin: H
		})
	});
	if (qwebirc.auth.enabled() && qwebirc.auth.quakeNetAuth() && !qwebirc.auth.loggedin()) 
	{
		var E = new Element("input", 
		{
			type: "submit",
			value: "Log in"
		});
		F.appendChild(E);
		E.addEvent("click", qwebirc.ui.AuthLogin)
	}
};
qwebirc.ui.LoginBox = function(I, H, Y, U, K)
{
	var T = new Element("table");
	T.addClass("qwebirc-centrebox");
	I.appendChild(T);
	var A = new Element("tbody");
	T.appendChild(A);
	var B = new Element("tr");
	A.appendChild(B);
	var L = new Element("td");
	B.appendChild(L);
	var O = new Element("table");
	O.addClass("qwebirc-loginbox");
	L.appendChild(O);
	var A = new Element("tbody");
	O.appendChild(A);
	var B = new Element("tr");
	A.appendChild(B);
	B.addClass("tr1");
	var L = new Element("td");
	B.appendChild(L);
	L.set("html", "<img src='images/yafLogo.png'><h1>Connect to " + K + "</h1>");
	var B = new Element("tr");
	A.appendChild(B);
	B.addClass("tr2");
	var L = new Element("td");
	B.appendChild(L);
	var C = new Element("form");
	L.appendChild(C);
	var F = new Element("table");
	C.appendChild(F);
	var A = new Element("tbody");
	F.appendChild(A);
	function D(Z, e, a)
	{
		var c = new Element("tr");
		A.appendChild(c);
		var d = new Element("td");
		if (Z) 
		{
			d.set("text", Z)
		}
		c.appendChild(d);
		var b = new Element("td");
		c.appendChild(b);
		if ($defined(e)) 
		{
			b.appendChild(e)
		}
		if ($defined(a)) 
		{
			c.setStyles(a);
			return [c, b]
		}
		return b
	}
	var V = new Element("input");
	D("Nickname:", V);
	var S = null;
	//if (qwebirc.auth.enabled() && qwebirc.auth.bouncerAuth()) 
	//{
	//	S = 
	//	{
	//		display: "none"
	//	}
	//}
	//var X = new Element("input");
	//D("Channels:", X, S);
	//if (qwebirc.auth.enabled()) 
	//{
	//	if (qwebirc.auth.passAuth()) 
	//	{
	//		var Q = D("Auth to services:");
	//		var M = qwebirc.util.createInput("checkbox", Q, "connect_auth_to_services", false);
	//		var R = new Element("input");
	//		var W = D("Username:", R, 
	//		{
	//			display: "none"
	//		})[0];
	//		var E = D("Password:", null, 
	//		{
	//			display: "none"
	//		});
	//		var J = qwebirc.util.createInput("password", E[1], "connect_auth_password");
	//		M.addEvent("click", function(Z)
	//		{
	//			qwebirc.ui.authShowHide(M, Q, R, W, E[0])
	//		})
	//	}
	//	else 
	//	{
	//		if (qwebirc.auth.bouncerAuth()) 
	//		{
	//			var E = D("Password:");
	//			var J = qwebirc.util.createInput("password", E, "connect_auth_password")
	//		}
	//	}
	//}
	var G = new Element("input", 
	{
		type: "submit"
	});
	G.set("value", "Connect");
	var P = D(undefined, G);
	if (qwebirc.auth.enabled() && qwebirc.auth.quakeNetAuth() && !qwebirc.auth.loggedin()) 
	{
		var N = new Element("input", 
		{
			type: "submit",
			value: "Log in"
		});
		P.appendChild(N);
		N.addEvent("click", qwebirc.ui.AuthLogin)
	}
	C.addEvent("submit", function(b)
	{
		new Event(b).stop();
		var Z = V.value;
		var c = "#yafaray";
		if (c == "#") 
		{
			c = ""
		}
		if (!Z) 
		{
			alert("You must supply a nickname.");
			V.focus();
			return
		}
		var a = 
		{
			nickname: Z,
			autojoin: c
		};
//		if (qwebirc.auth.passAuth() && M.checked) 
//		{
//			if (!R.value || !J.value) 
//			{
//				alert("You must supply your username and password in auth mode.");
//				if (!R.value) 
//				{
//					R.focus()
//				}
//				else 
//				{
//					J.focus()
//				}
//				return
//			}
//			a.serverPassword = R.value + " " + J.value
//		}
//		else 
//		{
//			if (qwebirc.auth.bouncerAuth()) 
//			{
//				if (!J.value) 
//				{
//					alert("You must supply a password.");
//					J.focus();
//					return
//				}
//				a.serverPassword = J.value
//			}
//		}
		I.removeChild(T);
		H(a)
	}
.bind(this));
	V.set("value", Y);
	//X.set("value", U);
	V.focus()
};
qwebirc.ui.authShowHide = function(D, G, C, B, A)
{
	var F = D.checked;
	var E = F ? null : "none";
	B.setStyle("display", E);
	A.setStyle("display", E);
	if (F) 
	{
		C.focus()
	}
};
qwebirc.ui.EmbedWizardStep = new Class(
{
	Implements: [Options, Events],
	options: 
	{
		title: "",
		first: "",
		hint: "",
		middle: null,
		premove: null,
		example: ""
	},
	initialize: function(A, B)
	{
		this.setOptions(B);
		this.parent = A
	},
	show: function()
	{
		this.parent.title.set("html", this.options.title);
		this.parent.firstRow.set("html", this.options.first);
		this.parent.hint.set("html", this.options.hint);
		this.parent.example.set("text", this.options.example);
		while (this.parent.middleRow.childNodes.length > 0) 
		{
			this.parent.middleRow.removeChild(this.parent.middleRow.childNodes[0])
		}
		if ($defined(this.options.middle)) 
		{
			this.parent.middleRow.appendChild(this.options.middle)
		}
		this.fireEvent("show")
	}
});
qwebirc.ui.EmbedWizard = new Class(
{
	Implements: [Options, Events],
	options: 
	{
		parent: null,
		baseURL: "http://webchat.quakenet.org/"
	},
	initialize: function(A, B)
	{
		this.setOptions(B);
		this.create(A);
		this.addSteps()
	},
	create: function(E)
	{
		this.t = E;
		var C = this.newRow();
		this.title = new Element("h2");
		this.title.setStyle("margin-top", "0px");
		this.title.setStyle("margin-bottom", "5px");
		C.appendChild(this.title);
		this.firstRow = this.newRow();
		this.middleRow = this.newRow();
		var D = this.newRow();
		this.hint = new Element("div");
		this.hint.setStyle("font-size", "0.8em");
		this.hint.setStyle("font-style", "italic");
		D.appendChild(this.hint);
		var B = this.newRow();
		this.example = new Element("pre");
		B.appendChild(this.example);
		var G = this.newRow();
		G.addClass("wizardcontrols");
		var F = new Element("input");
		F.type = "submit";
		F.value = "< Back";
		F.addEvent("click", this.back.bind(this));
		G.appendChild(F);
		var A = new Element("input");
		A.type = "submit";
		A.value = "Next >";
		G.appendChild(A);
		A.addEvent("click", this.next.bind(this));
		this.nextBtn = A;
		this.backBtn = F
	},
	newRow: function()
	{
		var A = new Element("div");
		this.t.appendChild(A);
		return A
	},
	newStep: function(A)
	{
		return new qwebirc.ui.EmbedWizardStep(this, A)
	},
	newRadio: function(A, F, B, C)
	{
		var E = new Element("div");
		A.appendChild(E);
		var D = qwebirc.util.createInput("radio", E, B, C);
		E.appendChild(document.createTextNode(F));
		return D
	},
	addSteps: function()
	{
		var B = function(G)
		{
			if (Browser.Engine.trident) 
			{
				var F = function()
				{
					this.focus();
					if (G) 
					{
						this.select()
					}
				};
				F.delay(100, this, [])
			}
			else 
			{
				this.focus();
				this.select()
			}
		};
		this.welcome = this.newStep(
		{
			title: "Welcome!",
			first: "This wizard will help you create an embedded client by asking you questions then giving you the code to add to your website.<br/><br/>You can use the <b>Next</b> and <b>Back</b> buttons to navigate through the wizard; click <b>Next</b> to continue."
		});
		this.chanBox = new Element("input");
		this.chanBox.addClass("text");
		this.chans = this.newStep(
		{
			title: "Set channels",
			first: "Enter the channels you would like the client to join on startup:",
			hint: "You can supply multiple channels by seperating them with a comma, e.g.:",
			example: "#rogue,#eu-mage",
			middle: this.chanBox
		}).addEvent("show", B.bind(this.chanBox));
		var E = new Element("div");
		this.customnick = this.newStep(
		{
			title: "Nickname mode",
			first: "At startup would you like the client to use a random nickname, a preset nickname or a nickname of the users choice?",
			hint: "It is recommended that you only use a preset nickname if the client is for your own personal use.",
			middle: E
		});
		this.choosenick = this.newRadio(E, "Make the user choose a nickname.", "nick", true);
		this.randnick = this.newRadio(E, "Use a random nickname, e.g. qwebirc12883.", "nick");
		this.presetnick = this.newRadio(E, "Use a preset nickname of your choice.", "nick");
		var D = new Element("form");
		this.connectdialog = this.newStep(
		{
			title: "Display connect dialog?",
			first: "Do you want the user to be shown the connect dialog (with the values you have supplied pre-entered) or just a connect confirmation?",
			middle: D,
			hint: "You need to display the dialog if you want the user to be able to set their nickname before connecting."
		});
		var C = this.newRadio(D, "Connect without displaying the dialog.", "prompt", true);
		this.connectdialogr = this.newRadio(D, "Show the connect dialog.", "prompt");
		this.nicknameBox = new Element("input");
		this.nicknameBox.addClass("text");
		this.nickname = this.newStep(
		{
			title: "Set nickname",
			first: "Enter the nickname you would like the client to use by default (use a . for a random number):",
			premove: function()
			{
				if (this.nicknameBox.value == "") 
				{
					alert("You must supply a nickname.");
					this.nicknameBox.focus();
					return false
				}
				return true
			}
.bind(this)			,
			middle: this.nicknameBox
		}).addEvent("show", B.bind(this.nicknameBox));
		var A = new Element("div");
		this.finish = this.newStep(
		{
			title: "Finished!",
			first: "Your custom link is:",
			middle: A
		}).addEvent("show", function()
		{
			var I = new Element("a");
			var F = new Element("input");
			F.addClass("iframetext");
			var G = this.generateURL(false);
			I.href = G;
			I.target = "new";
			I.appendChild(document.createTextNode(G));
			F.value = '<iframe src="' + G + '" width="647" height="400"></iframe>';
			var H = [I, new Element("br"), new Element("br"), document.createTextNode("You can embed this into your page with the following code:"), new Element("br"), F];
			while (A.childNodes.length > 0) 
			{
				A.removeChild(A.childNodes[0])
			}
			H.forEach(function(J)
			{
				A.appendChild(J)
			});
			B.bind(F)(true);
			F.addEvent("click", function()
			{
				this.select()
			}
.bind(F))
		}
.bind(this));
		this.updateSteps();
		this.step = 0;
		this.showStep()
	},
	updateSteps: function()
	{
		this.steps = [this.welcome, this.customnick];
		if (this.presetnick.checked) 
		{
			this.steps.push(this.nickname)
		}
		this.steps.push(this.chans);
		if (this.chanBox.value != "" && !this.choosenick.checked) 
		{
			this.steps.push(this.connectdialog)
		}
		this.steps.push(this.finish)
	},
	showStep: function()
	{
		this.backBtn.disabled = !(this.step > 0);
		this.nextBtn.value = (this.step >= this.steps.length - 1) ? "Close" : "Next >";
		this.steps[this.step].show()
	},
	next: function()
	{
		var A = this.steps[this.step].options.premove;
		if (A && !A()) 
		{
			return
		}
		this.updateSteps();
		if (this.step >= this.steps.length - 1) 
		{
			this.close();
			return
		}
		this.step = this.step + 1;
		this.showStep()
	},
	close: function()
	{
		this.fireEvent("close")
	},
	back: function()
	{
		if (this.step <= 0) 
		{
			return
		}
		this.step = this.step - 1;
		this.showStep()
	},
	generateURL: function()
	{
		var F = this.chanBox.value;
		var B = this.nicknameBox.value;
		var D = this.connectdialogr.checked && F != "" && !this.choosenick.checked;
		var A = [];
		if (this.presetnick.checked) 
		{
			A.push("nick=" + escape(B))
		}
		else 
		{
			if (!this.choosenick.checked) 
			{
				A.push("randomnick=1")
			}
		}
		if (F) 
		{
			var E = F.split(",");
			var C = [];
			E.forEach(function(G)
			{
				if (G.charAt(0) == "#") 
				{
					G = G.substring(1)
				}
				C.push(G)
			});
			A.push("channels=" + escape(C.join(",")))
		}
		if (D) 
		{
			A.push("prompt=1")
		}
		return this.options.baseURL + (A.length > 0 ? "?" : "") + A.join("&")
	}
});
qwebirc.config.CHECK_BOX = 1;
qwebirc.config.TEXT_BOX = 2;
qwebirc.config.RADIO_BUTTONS = 3;
qwebirc.config.DEFAULT_OPTIONS = [[1, "BEEP_ON_MENTION", "Beep when nick mentioned or on query activity (requires Flash)", true, 
{
	enabled: function()
	{
		if (!$defined(Browser.Plugins.Flash) || Browser.Plugins.Flash.version < 8) 
		{
			return [false, false]
		}
		return [true]
	},
	get: function(B, A)
	{
		if (A.setBeepOnMention) 
		{
			A.setBeepOnMention(B)
		}
	}
}], [7, "FLASH_ON_MENTION", "Flash titlebar when nick mentioned or on query activity", true, 
{
	enabled: function()
	{
		var A = navigator.userAgent;
		if (!$defined(A)) 
		{
			return [true]
		}
		if (Browser.Engine.ipod || A.indexOf("Konqueror") != -1) 
		{
			return [false, false]
		}
		return [true]
	}
}], [2, "DEDICATED_MSG_WINDOW", "Send privmsgs to dedicated messages window", false], [4, "DEDICATED_NOTICE_WINDOW", "Send notices to dedicated message window", false], [3, "NICK_OV_STATUS", "Show status (@/+) before nicknames in nicklist", true], [8, "LASTPOS_LINE", "Show a last position indicator for each window", true]];
qwebirc.config.DefaultOptions = null;
qwebirc.config.Input = new Class(
{
	initialize: function(C, B, A, D)
	{
		this.option = B;
		this.value = B.value;
		this.enabled = this.option.enabled;
		this.position = A;
		this.parentElement = C;
		this.parentObject = D;
		this.render()
	},
	createInput: function(D, A, B, C)
	{
		if (!$defined(A)) 
		{
			A = this.parentElement
		}
		return qwebirc.util.createInput(D, A, B, C)
	},
	FE: function(B, A)
	{
		var C = new Element(B);
		if (!$defined(A)) 
		{
			A = this.parentElement
		}
		A.appendChild(C);
		return C
	},
	focus: function()
	{
		this.mainElement.focus()
	},
	render: function()
	{
		this.event("render", this.mainElement)
	},
	get: function(A)
	{
		this.event("get", [A, this.parentObject.optionObject.ui]);
		return A
	},
	event: function(B, A)
	{
		if (!$defined(this.option.extras)) 
		{
			return
		}
		var C = this.option.extras[B];
		if (!$defined(C)) 
		{
			return
		}
		C.pass(A, this)()
	}
});
qwebirc.config.TextInput = new Class(
{
	Extends: qwebirc.config.Input,
	render: function()
	{
		var A = this.createInput("text");
		this.mainElement = A;
		A.value = this.value;
		A.disabled = !this.enabled;
		this.parent()
	},
	get: function()
	{
		return this.parent(this.mainElement.value)
	}
});
qwebirc.config.CheckInput = new Class(
{
	Extends: qwebirc.config.Input,
	render: function()
	{
		var A = this.createInput("checkbox");
		this.mainElement = A;
		A.checked = this.value;
		A.disabled = !this.enabled;
		this.parent()
	},
	get: function()
	{
		return this.parent(this.mainElement.checked)
	}
});
qwebirc.config.RadioInput = new Class(
{
	Extends: qwebirc.config.Input,
	render: function()
	{
		var B = this.option.options;
		this.elements = [];
		for (var A = 0; A < B.length; A++) 
		{
			var D = this.FE("div", this.parentObject);
			var C = this.createInput("radio", D, "options_radio" + this.position, A == this.option.position);
			this.elements.push(C);
			C.disabled = !this.enabled;
			if (A == 0) 
			{
				this.mainElement = C
			}
			D.appendChild(document.createTextNode(B[A][0]))
		}
		this.parent()
	},
	get: function()
	{
		for (var B = 0; B < this.elements.length; B++) 
		{
			var A = this.elements[B];
			if (A.checked) 
			{
				this.option.position = B;
				return this.parent(this.option.options[B][1])
			}
		}
	}
});
qwebirc.config.Option = new Class(
{
	initialize: function(C, B, E, F, D)
	{
		this.prefix = B;
		this.label = E;
		this.default_ = F;
		this.optionId = C;
		this.extras = D;
		if ($defined(D) && $defined(D.enabled)) 
		{
			var A = D.enabled();
			this.enabled = A[0];
			if (!A[0] && A.length > 1) 
			{
				this.default_ = A[1]
			}
		}
		else 
		{
			this.enabled = true
		}
	},
	setSavedValue: function(A)
	{
		if (this.enabled) 
		{
			this.value = A
		}
	}
});
qwebirc.config.RadioOption = new Class(
{
	Extends: qwebirc.config.Option,
	Element: qwebirc.config.RadioInput,
	initialize: function(B, A, D, F, C, E)
	{
		this.options = E.map(function(G)
		{
			if (typeof(G) == "string") 
			{
				return [G, G]
			}
			return G
		});
		this.defaultposition = F;
		this.parent(B, A, D, this.options[F][1], C)
	},
	setSavedValue: function(A)
	{
		for (var B = 0; B < this.options.length; B++) 
		{
			var C = this.options[B][1];
			if (A == C) 
			{
				this.position = B;
				this.value = A;
				return
			}
		}
		this.position = this.defaultposition;
		this.value = this.default_
	}
});
qwebirc.config.TextOption = new Class(
{
	Extends: qwebirc.config.Option,
	Element: qwebirc.config.TextInput
});
qwebirc.config.CheckOption = new Class(
{
	Extends: qwebirc.config.Option,
	Element: qwebirc.config.CheckInput
});
qwebirc.ui.Options = new Class(
{
	initialize: function(A)
	{
		if (!$defined(qwebirc.config.DefaultOptions)) 
		{
			this.__configureDefaults()
		}
		this.optionList = qwebirc.config.DefaultOptions.slice();
		this.optionHash = {};
		this.ui = A;
		this._setup();
		this.optionList.forEach(function(B)
		{
			B.setSavedValue(this._get(B));
			this.optionHash[B.prefix] = B;
			this[B.prefix] = B.value
		}
.bind(this))
	},
	__configureDefaults: function()
	{
		qwebirc.config.DefaultOptions = qwebirc.config.DEFAULT_OPTIONS.map(function(H)
		{
			var C = H[0];
			var A = H[1];
			var I = H[2];
			var B = H[3];
			var E = H[4];
			var D = H[5];
			var G = typeof(B);
			if (G == "number") 
			{
				return new qwebirc.config.RadioOption(C, A, I, B, E, extra)
			}
			else 
			{
				var F;
				if (G == "boolean") 
				{
					F = qwebirc.config.CheckOption
				}
				else 
				{
					F = qwebirc.config.TextOption
				}
				return new F(C, A, I, B, E)
			}
		})
	},
	setValue: function(A, B)
	{
		this.optionHash[A.prefix].value = B;
		this[A.prefix] = B
	},
	getOptionList: function()
	{
		return this.optionList
	},
	_get: function(A)
	{
		return A.default_
	},
	_setup: function()
	{
	},
	flush: function()
	{
	}
});
qwebirc.ui.OptionsPane = new Class(
{
	Implements: [Events],
	initialize: function(B, A)
	{
		this.parentElement = B;
		this.optionObject = A;
		this.createElements()
	},
	createElements: function()
	{
		var F = function(N, M)
		{
			var O = new Element(N);
			M.appendChild(O);
			return O
		};
		var K = F("table", this.parentElement);
		var C = F("tbody", K);
		this.boxList = [];
		var B = this.optionObject.getOptionList();
		for (var D = 0; D < B.length; D++) 
		{
			var J = B[D];
			var L = F("tr", C);
			var H = F("td", L);
			H.set("text", J.label + ":");
			var G = F("td", L);
			this.boxList.push([J, new J.Element(G, J, D, this)])
		}
		var A = F("tr", C);
		var H = F("td", A);
		var G = F("td", A);
		var E = qwebirc.util.createInput("submit", G);
		E.value = "Save";
		E.addEvent("click", function()
		{
			this.save();
			this.fireEvent("close")
		}
.bind(this));
		var I = qwebirc.util.createInput("submit", G);
		I.value = "Cancel";
		I.addEvent("click", function()
		{
			this.fireEvent("close")
		}
.bind(this))
	},
	save: function()
	{
		this.boxList.forEach(function(A)
		{
			var B = A[0];
			var C = A[1];
			this.optionObject.setValue(B, C.get())
		}
.bind(this));
		this.optionObject.flush()
	}
});
qwebirc.ui.CookieOptions = new Class(
{
	Extends: qwebirc.ui.Options,
	_setup: function()
	{
		this.__cookie = new Hash.Cookie("opt1", 
		{
			duration: 3650,
			autoSave: false
		})
	},
	_get: function(A)
	{
		var B = this.__cookie.get(A.optionId);
		if (!$defined(B)) 
		{
			return A.default_
		}
		return B
	},
	flush: function()
	{
		this.__cookie.erase();
		this._setup();
		this.getOptionList().forEach(function(A)
		{
			this.__cookie.set(A.optionId, A.value)
		}
.bind(this));
		this.__cookie.save()
	}
});
qwebirc.ui.DefaultOptionsClass = new Class(
{
	Extends: qwebirc.ui.CookieOptions
});
qwebirc.ui.AboutPane = new Class(
{
	Implements: [Events],
	initialize: function(B)
	{
		var D = function()
		{
			B.set("html", '<div class="loading">Loading. . .</div>')
		};
		var A = D.delay(500);
		var C = new Request.HTML(
		{
			url: "panes/about.html",
			update: B,
			onSuccess: function()
			{
				$clear(A);
				B.getElement("input[class=close]").addEvent("click", function()
				{
					this.fireEvent("close")
				}
.bind(this));
				B.getElement("div[class=version]").set("text", "v" + qwebirc.VERSION)
			}
.bind(this)
		});
		C.get()
	}
});
qwebirc.ui.PrivacyPolicyPane = new Class(
{
	Implements: [Events],
	initialize: function(B)
	{
		var D = function()
		{
			B.set("html", '<div class="loading">Loading. . .</div>')
		};
		var A = D.delay(500);
		var C = new Request.HTML(
		{
			url: "panes/privacypolicy.html",
			update: B,
			onSuccess: function()
			{
				$clear(A);
				B.getElement("input[class=close]").addEvent("click", function()
				{
					this.fireEvent("close")
				}
.bind(this))
			}
.bind(this)
		});
		C.get()
	}
});
qwebirc.ui.FeedbackPane = new Class(
{
	Implements: [Events],
	initialize: function(B)
	{
		this.textboxVisible = false;
		var D = function()
		{
			B.set("html", '<div class="loading">Loading. . .</div>')
		};
		var A = D.delay(500);
		this.addEvent("select", this.onSelect);
		var C = new Request.HTML(
		{
			url: "panes/feedback.html",
			update: B,
			onSuccess: function()
			{
				$clear(A);
				B.getElement("input[class=close]").addEvent("click", function()
				{
					this.fireEvent("close")
				}
.bind(this));
				B.getElement("input[class=close2]").addEvent("click", function()
				{
					this.fireEvent("close")
				}
.bind(this));
				var E = B.getElement("textarea");
				this.textbox = E;
				B.getElement("input[class=submitfeedback]").addEvent("click", function()
				{
					this.sendFeedback(B, E, E.value)
				}
.bind(this));
				this.textboxVisible = true;
				this.onSelect()
			}
.bind(this)
		});
		C.get()
	},
	onSelect: function()
	{
		if (this.textboxVisible) 
		{
			this.textbox.focus()
		}
	},
	sendFeedback: function(H, K, J)
	{
		J = J.replace(/^\s*/, "").replace(/\s*$/, "");
		var I = H.getElement("p[class=maintext]");
		if (J.length < 25) 
		{
			I.set("text", "I don't suppose you could enter a little bit more? Thanks!");
			K.focus();
			return
		}
		this.textboxVisible = false;
		var C = H.getElement("div[class=enterarea]");
		C.setStyle("display", "none");
		var D = H.getElement("div[class=messagearea]");
		var L = H.getElement("p[class=messagetext]");
		var F = H.getElement("input[class=close2]");
		L.set("text", "Submitting. . .");
		D.setStyle("display", "");
		var G = 0;
		var B = encodeURIComponent(J);
		for (var E = 0; E < J.length; E++) 
		{
			G = ((G + 1) % 256) ^ (J.charCodeAt(E) % 256)
		}
		var A = new Request(
		{
			url: "/feedback",
			onSuccess: function()
			{
				L.set("text", "Submitted successfully, thanks for the feedback!");
				F.setStyle("display", "")
			},
			onFailure: function()
			{
				this.textboxVisible = true;
				D.setStyle("display", "none");
				C.setStyle("display", "");
				I.set("text", "Looks like something went wrong submitting :(")
			}
.bind(this)
		}).send("feedback=" + J + "&c=" + G)
	}
});
qwebirc.ui.FAQPane = new Class(
{
	Implements: [Events],
	initialize: function(B)
	{
		var D = function()
		{
			B.set("html", '<div class="loading">Loading. . .</div>')
		};
		var A = D.delay(500);
		var C = new Request.HTML(
		{
			url: "panes/faq.html",
			update: B,
			onSuccess: function()
			{
				$clear(A);
				B.getElement("input[class=close]").addEvent("click", function()
				{
					this.fireEvent("close")
				}
.bind(this))
			}
.bind(this)
		});
		C.get()
	}
});
qwebirc.ui.Interface = new Class(
{
	Implements: [Options],
	options: 
	{
		initialNickname: "qwebirc" + Math.ceil(Math.random() * 100000),
		initialChannels: "",
		networkName: "ExampleNetwork",
		networkServices: [],
		loginRegex: null,
		appTitle: "ExampleNetwork Web IRC",
		searchURL: true,
		theme: undefined,
		baseURL: null
	},
	initialize: function(A, C, B)
	{
		this.setOptions(B);
		window.addEvent("domready", function()
		{
			var O = new C($(A), new qwebirc.ui.Theme(this.options.theme), this.options);
			var Q = function(V)
			{
				var U = new qwebirc.irc.IRCClient(V, O);
				U.connect();
				window.addEvent("beforeunload", function()
				{
					U.quit("Page closed")
				})
			};
			var R = null;
			var K = this.options.initialChannels;
			var I = false;
			if (this.options.searchURL) 
			{
				var N = qwebirc.util.parseURI(String(document.location));
				var F = N.url;
				var G, E = N.nick;
				if ($defined(F)) 
				{
					K = this.parseIRCURL(F);
					if ($defined(G) && G != "") 
					{
						M = true
					}
				}
				else 
				{
					G = N.channels;
					var M = false;
					if (G) 
					{
						var P = G.split(" ");
						G = P[0].split(",");
						var S = [];
						for (var J = 0; J < G.length; J++) 
						{
							S[J] = G[J];
							if (G[J].charAt(0) != "#") 
							{
								S[J] = "#" + S[J]
							}
						}
						P[0] = S.join(",");
						K = P.join(" ");
						M = true
					}
				}
				if ($defined(E)) 
				{
					R = this.randSub(E)
				}
				if (N.randomnick && N.randomnick == 1) 
				{
					R = this.options.initialNickname
				}
				if (M && (!$defined(R) || ($defined(R) && (R != "")))) 
				{
					var H = N.prompt;
					var T = false;
					if (!$defined(H) || H == "") 
					{
						T = true;
						H = false
					}
					else 
					{
						if (H == "0") 
						{
							H = false
						}
						else 
						{
							H = true
						}
					}
					if ($defined(R) && !H) 
					{
						I = true
					}
					else 
					{
						if (!T && !H) 
						{
							I = true
						}
					}
				}
			}
			var L = !$defined(E);
			//if (L && I) 
			//{
				R = this.options.initialNickname
			//}
			var D = O.loginBox(Q, R, K, I, L)
		}
.bind(this))
	},
	randSub: function(A)
	{
		var B = function()
		{
			return Math.floor(Math.random() * 10)
		};
		return A.split("").map(function(C)
		{
			if (C == ".") 
			{
				return B()
			}
			else 
			{
				return C
			}
		}).join("")
	},
	parseIRCURL: function(A)
	{
		if (A.indexOf(":") == 0) 
		{
			return
		}
		var B = A.splitMax(":", 2);
		if (B[0].toLowerCase() != "irc" && B[0].toLowerCase() != "ircs") 
		{
			alert("Bad IRC URL scheme.");
			return
		}
		if (A.indexOf("/") == 0) 
		{
			return
		}
		var M = A.splitMax("/", 4);
		if (M.length < 4 || M[3] == "") 
		{
			return
		}
		var H, E;
		if (M[3].indexOf("?") > -1) 
		{
			E = qwebirc.util.parseURI(M[3]);
			H = M[3].splitMax("?", 2)[0]
		}
		else 
		{
			H = M[3]
		}
		var C = H.split(",");
		var G = C[0];
		if (G.charAt(0) != "#") 
		{
			G = "#" + G
		}
		var L = [], F = false, K;
		for (var D = 1; D < C.length; D++) 
		{
			var J = C[D];
			if (J == "needkey") 
			{
				F = true
			}
			else 
			{
				L.push(J)
			}
		}
		if ($defined(E)) 
		{
			for (var I in E) 
			{
				var J = E[I];
				if (I == "key") 
				{
					K = J;
					F = true
				}
				else 
				{
					L.push(I)
				}
			}
		}
		if (F) 
		{
			if (!$defined(K)) 
			{
				K = prompt("Please enter the password for channel " + G + ":")
			}
			if ($defined(K)) 
			{
				G = G + " " + K
			}
		}
		if (L.length > 0) 
		{
			alert("The following IRC URL components were not accepted: " + L.join(", ") + ".")
		}
		return G
	}
});
qwebirc.auth.loggedin = function()
{
	var A = Cookie.read("user");
	return A
};
qwebirc.auth.enabled = function()
{
	return true
};
qwebirc.auth.quakeNetAuth = function()
{
	return false
};
qwebirc.auth.passAuth = function()
{
	return true
};
qwebirc.auth.bouncerAuth = function()
{
	return false
};
qwebirc.sound.domReady = false;
window.addEvent("domready", function()
{
	qwebirc.sound.domReady = true
});
qwebirc.sound.SoundPlayer = new Class(
{
	Implements: [Events],
	initialize: function()
	{
		this.loadingSWF = false;
		this.loadedSWF = false
	},
	go: function()
	{
		if (qwebirc.sound.domReady) 
		{
			this.loadSoundManager()
		}
		else 
		{
			window.addEvent("domready", function()
			{
				this.loadSoundManager()
			}
.bind(this))
		}
	},
	loadSoundManager: function()
	{
		if (this.loadingSWF) 
		{
			return
		}
		this.loadingSWF = true;
		if (eval("typeof soundManager") != "undefined") 
		{
			this.loadedSWF = true;
			this.fireEvent("ready");
			return
		}
		var debugMode = false;
		qwebirc.util.importJS("lib/js/" + (debugMode ? "soundmanager2" : "soundmanager2-nodebug-jsmin") + ".js", "soundManager", function()
		{
			soundManager.url = "http://webchat.freenode.net/sound/";
			soundManager.debugMode = debugMode;
			soundManager.useConsole = debugMode;
			soundManager.onload = function()
			{
				this.loadedSWF = true;
				this.fireEvent("ready")
			}
.bind(this);
			soundManager.beginDelayedInit()
		}
.bind(this))
	},
	createSound: function(A, B)
	{
		soundManager.createSound(A, B)
	},
	playSound: function(A)
	{
		soundManager.play(A)
	},
	beep: function()
	{
		if (!this.beepLoaded) 
		{
			this.createSound("beep", "http://webchat.freenode.net/sound/beep3.mp3");
			this.beepLoaded = true
		}
		this.playSound("beep")
	}
});
qwebirc.ui.QUI = new Class(
{
	Extends: qwebirc.ui.RootUI,
	initialize: function(B, C, A)
	{
		this.parent(B, qwebirc.ui.QUI.Window, "qui", A);
		this.theme = C;
		this.parentElement = B
	},
	postInitialize: function()
	{
		this.qjsui = new qwebirc.ui.QUI.JSUI("qwebirc-qui", this.parentElement);
		this.qjsui.addEvent("reflow", function()
		{
			var A = this.getActiveWindow();
			if ($defined(A)) 
			{
				A.onResize()
			}
		}
.bind(this));
		this.qjsui.top.addClass("outertabbar");
		this.qjsui.bottom.addClass("input");
		this.qjsui.right.addClass("nicklist");
		this.qjsui.topic.addClass("topic");
		this.qjsui.middle.addClass("lines");
		this.outerTabs = this.qjsui.top;
		this.tabs = new Element("div");
		this.tabs.addClass("tabbar");
		this.__createDropdownMenu();
		this.outerTabs.appendChild(this.tabs);
		this.origtopic = this.topic = this.qjsui.topic;
		this.origlines = this.lines = this.qjsui.middle;
		this.orignicklist = this.nicklist = this.qjsui.right;
		this.input = this.qjsui.bottom;
		this.reflow = this.qjsui.reflow.bind(this.qjsui);
		this.tabs.addEvent("mousewheel", function(A)
		{
			var B = new Event(A);
			if (B.wheel > 0) 
			{
				this.nextWindow()
			}
			else 
			{
				if (B.wheel < 0) 
				{
					this.prevWindow()
				}
			}
			B.stop()
		}
.bind(this));
		this.createInput();
		this.reflow();
		this.reflow.delay(100);
		this.__createDropdownHint.delay(100, this)
	},
	__createDropdownMenu: function()
	{
		var A = new Element("span");
		A.addClass("dropdownmenu");
		A.hide = function()
		{
			A.setStyle("display", "none");
			A.visible = false;
			document.removeEvent("mousedown", C)
		}
.bind(this);
		var C = function()
		{
			A.hide()
		};
		A.hide();
		this.parentElement.appendChild(A);
		this.UICommands.forEach(function(E)
		{
			var H = E[0];
			var F = this[E[1] + "Window"].bind(this);
			var G = new Element("a");
			G.addEvent("mousedown", function(I)
			{
				new Event(I).stop()
			});
			G.addEvent("click", function()
			{
				A.hide();
				F()
			});
			G.set("text", H);
			A.appendChild(G)
		}
.bind(this));
		var B = new Element("div");
		B.addClass("dropdown-tab");
		B.appendChild(new Element("img", 
		{
			src: "images/favicon.png",
			title: "menu",
			alt: "menu"
		}));
		B.setStyle("opacity", 1);
		var D = new Fx.Tween(B, 
		{
			duration: "long",
			property: "opacity",
			link: "chain"
		});
		D.start(0.25);
		D.start(1);
		D.start(0.33);
		D.start(1);
		this.outerTabs.appendChild(B);
		A.show = function(E)
		{
			new Event(E).stop();
			this.hideHint();
			if (A.visible) 
			{
				A.hide();
				return
			}
			var F = this.outerTabs.getSize().y;
			A.setStyle("left", 0);
			A.setStyle("top", F - 1);
			A.setStyle("display", "inline-block");
			A.visible = true;
			document.addEvent("mousedown", C)
		}
.bind(this);
		B.addEvent("mousedown", function(E)
		{
			new Event(E).stop()
		});
		B.addEvent("click", A.show)
	},
	__createDropdownHint: function()
	{
		var A = new Element("div");
		A.addClass("dropdownhint");
		A.set("text", "Click the icon for the main menu.");
		A.setStyle("top", this.outerTabs.getSize().y + 5);
		this.parentElement.appendChild(A);
		new Fx.Morph(A, 
		{
			duration: "normal",
			transition: Fx.Transitions.Sine.easeOut
		}).start(
		{
			left: [900, 5]
		});
		var C = function()
		{
			new Fx.Morph(A, 
			{
				duration: "long"
			}).start(
			{
				left: [5, -900]
			})
		}
.delay(4000, this);
		var B = function()
		{
			if (A.hidden) 
			{
				return
			}
			this.parentElement.removeChild(A);
			A.hidden = 1
		}
.bind(this);
		B.delay(4000);
		this.hideHint = B;
		document.addEvent("mousedown", B);
		document.addEvent("keypress", B)
	},
	createInput: function()
	{
		var D = new Element("form");
		this.input.appendChild(D);
		D.addClass("input");
		var B = new Element("input");
		D.appendChild(B);
		this.inputbox = B;
		this.inputbox.maxLength = 512;
		var C = function()
		{
			if (B.value == "") 
			{
				return
			}
			this.resetTabComplete();
			this.getActiveWindow().historyExec(B.value);
			B.value = ""
		}
.bind(this);
		if (!qwebirc.util.deviceHasKeyboard()) 
		{
			B.addClass("mobile-input");
			var E = new Element("input", 
			{
				type: "button"
			});
			E.addClass("mobile-button");
			E.addEvent("click", function()
			{
				C();
				B.focus()
			});
			E.value = ">";
			this.input.appendChild(E);
			var A = function()
			{
				var H = this.input.getSize();
				var F = E.getSize();
				var G = H.x - F.x - 5;
				E.setStyle("left", G);
				B.setStyle("width", G - 5);
				E.setStyle("height", H.y)
			}
.bind(this);
			this.qjsui.addEvent("reflow", A)
		}
		else 
		{
			B.addClass("keyboard-input")
		}
		D.addEvent("submit", function(F)
		{
			new Event(F).stop();
			C()
		});
		B.addEvent("focus", this.resetTabComplete.bind(this));
		B.addEvent("mousedown", this.resetTabComplete.bind(this));
		B.addEvent("keydown", function(H)
		{
			var F;
			var I = B.value;
			if (H.key == "up") 
			{
				F = this.commandhistory.upLine
			}
			else 
			{
				if (H.key == "down") 
				{
					F = this.commandhistory.downLine
				}
				else 
				{
					if (H.key == "tab") 
					{
						new Event(H).stop();
						this.tabComplete(B);
						return
					}
					else 
					{
						this.resetTabComplete();
						return
					}
				}
			}
			this.resetTabComplete();
			if ((I != "") && (this.lastcvalue != I)) 
			{
				this.commandhistory.addLine(I, true)
			}
			var G = F.bind(this.commandhistory)();
			new Event(H).stop();
			if (!G) 
			{
				G = ""
			}
			this.lastcvalue = G;
			B.value = G;
			qwebirc.util.setAtEnd(B)
		}
.bind(this))
	},
	setLines: function(A)
	{
		this.lines.parentNode.replaceChild(A, this.lines);
		this.qjsui.middle = this.lines = A
	},
	setChannelItems: function(B, A)
	{
		if (!$defined(B)) 
		{
			B = this.orignicklist;
			A = this.origtopic
		}
		this.nicklist.parentNode.replaceChild(B, this.nicklist);
		this.qjsui.right = this.nicklist = B;
		this.topic.parentNode.replaceChild(A, this.topic);
		this.qjsui.topic = this.topic = A
	}
});
qwebirc.ui.QUI.JSUI = new Class(
{
	Implements: [Events],
	initialize: function(C, A, B)
	{
		this.parent = A;
		this.sizer = $defined(B) ? B : A;
		this.class_ = C;
		this.create();
		this.reflowevent = null;
		window.addEvent("resize", function()
		{
			this.reflow(100)
		}
.bind(this))
	},
	applyClasses: function(B, A)
	{
		A.addClass("dynamicpanel");
		A.addClass(this.class_);
		if (B == "middle") 
		{
			A.addClass("leftboundpanel")
		}
		else 
		{
			if (B == "top") 
			{
				A.addClass("topboundpanel");
				A.addClass("widepanel")
			}
			else 
			{
				if (B == "topic") 
				{
					A.addClass("widepanel")
				}
				else 
				{
					if (B == "right") 
					{
						A.addClass("rightboundpanel")
					}
					else 
					{
						if (B == "bottom") 
						{
							A.addClass("bottomboundpanel");
							A.addClass("widepanel")
						}
					}
				}
			}
		}
	},
	create: function()
	{
		var A = function(C)
		{
			var B = new Element("div");
			this.applyClasses(C, B);
			this.parent.appendChild(B);
			return B
		}
.bind(this);
		this.top = A("top");
		this.topic = A("topic");
		this.middle = A("middle");
		this.right = A("right");
		this.bottom = A("bottom")
	},
	reflow: function(A)
	{
		if (!A) 
		{
			A = 1
		}
		if (this.reflowevent) 
		{
			$clear(this.reflowevent)
		}
		this.__reflow();
		this.reflowevent = this.__reflow.delay(A, this)
	},
	__reflow: function()
	{
		var H = this.bottom;
		var J = this.middle;
		var L = this.right;
		var D = this.topic;
		var K = this.top;
		var I = D.getSize();
		var C = K.getSize();
		var E = L.getSize();
		var G = H.getSize();
		var F = this.sizer.getSize();
		var A = (F.y - C.y - G.y - I.y);
		var B = (F.x - E.x);
		D.setStyle("top", C.y);
		J.setStyle("top", (C.y + I.y));
		if (A > 0) 
		{
			J.setStyle("height", A);
			L.setStyle("height", A)
		}
		if (B > 0) 
		{
			J.setStyle("width", B)
		}
		L.setStyle("top", (C.y + I.y));
		L.setStyle("left", B);
		H.setStyle("top", (F.y - G.y));
		this.fireEvent("reflow")
	},
	showChannel: function(A)
	{
		var B = "none";
		if (A) 
		{
			B = "block"
		}
		this.right.setStyle("display", B);
		this.topic.setStyle("display", B)
	},
	showInput: function(A)
	{
		this.bottom.isVisible = A;
		this.bottom.setStyle("display", A ? "block" : "none")
	}
});
qwebirc.ui.QUI.Window = new Class(
{
	Extends: qwebirc.ui.Window,
	initialize: function(F, D, C, A, B)
	{
		this.parent(F, D, C, A, B);
		this.tab = new Element("a", 
		{
			href: "#"
		});
		this.tab.addClass("tab");
		this.tab.addEvent("focus", function()
		{
			this.blur()
		}
.bind(this.tab));
		F.tabs.appendChild(this.tab);
		this.tab.appendText(A);
		this.tab.addEvent("click", function(H)
		{
			new Event(H).stop();
			if (this.closed) 
			{
				return
			}
			F.selectWindow(this)
		}
.bind(this));
		if (C != qwebirc.ui.WINDOW_STATUS && C != qwebirc.ui.WINDOW_CONNECT) 
		{
			var E = new Element("span");
			E.set("text", "X");
			E.addClass("tabclose");
			var G = function(H)
			{
				new Event(H).stop();
				if (this.closed) 
				{
					return
				}
				if (C == qwebirc.ui.WINDOW_CHANNEL) 
				{
					this.client.exec("/PART " + A)
				}
				this.close()
			}
.bind(this);
			E.addEvent("click", G);
			this.tab.addEvent("mouseup", function(I)
			{
				var H = 1;
				if (Browser.Engine.trident) 
				{
					H = 4
				}
				if (I.event.button == H) 
				{
					G(I)
				}
			}
.bind(this));
			this.tab.appendChild(E)
		}
		this.lines = new Element("div");
		this.parentObject.qjsui.applyClasses("middle", this.lines);
		this.lines.addClass("lines");
		if (C != qwebirc.ui.WINDOW_CUSTOM && C != qwebirc.ui.WINDOW_CONNECT) 
		{
			this.lines.addClass("ircwindow")
		}
		this.lines.addEvent("scroll", function()
		{
			this.scrolleddown = this.scrolledDown();
			this.scrollpos = this.getScrollParent().getScroll()
		}
.bind(this));
		if (C == qwebirc.ui.WINDOW_CHANNEL) 
		{
			this.topic = new Element("div");
			this.topic.addClass("topic");
			this.topic.addClass("tab-invisible");
			this.topic.set("html", "&nbsp;");
			this.topic.addEvent("click", this.editTopic.bind(this));
			this.parentObject.qjsui.applyClasses("topic", this.topic);
			this.prevNick = null;
			this.nicklist = new Element("div");
			this.nicklist.addClass("nicklist");
			this.nicklist.addClass("tab-invisible");
			this.nicklist.addEvent("click", this.removePrevMenu.bind(this));
			this.parentObject.qjsui.applyClasses("nicklist", this.nicklist)
		}
		if (C == qwebirc.ui.WINDOW_CHANNEL) 
		{
			this.updateTopic("")
		}
		else 
		{
			this.reflow()
		}
	},
	editTopic: function()
	{
		if (!this.client.nickOnChanHasPrefix(this.client.nickname, this.name, "@")) 
		{
			alert("Sorry, you need to be opped to change the topic!");
			return
		}
		var A = prompt("Change topic of " + this.name + " to:", this.topic.topicText);
		if (A === null) 
		{
			return
		}
		this.client.exec("/TOPIC " + A)
	},
	reflow: function()
	{
		this.parentObject.reflow()
	},
	onResize: function()
	{
		if (this.scrolleddown) 
		{
			if (Browser.Engine.trident) 
			{
				this.scrollToBottom.delay(5, this)
			}
			else 
			{
				this.scrollToBottom()
			}
		}
		else 
		{
			if ($defined(this.scrollpos)) 
			{
				if (Browser.Engine.trident) 
				{
					this.getScrollParent().scrollTo(this.scrollpos.x, this.scrollpos.y)
				}
				else 
				{
					this.getScrollParent().scrollTo.delay(5, this, [this.scrollpos.x, this.scrollpos.y])
				}
			}
		}
	},
	createMenu: function(A, B)
	{
		var D = new Element("div");
		B.appendChild(D);
		D.addClass("menu");
		var C = [A];
		qwebirc.ui.MENU_ITEMS.forEach(function(E)
		{
			if (!E.predicate || E.predicate !== true && !E.predicate.apply(this, C)) 
			{
				return
			}
			var F = new Element("a");
			D.appendChild(F);
			F.href = "#";
			F.set("text", "- " + E.text);
			F.addEvent("focus", function()
			{
				this.blur()
			}
.bind(F));
			F.addEvent("click", function(G)
			{
				new Event(G.stop());
				this.menuClick(E.fn)
			}
.bind(this))
		}
.bind(this));
		return D
	},
	menuClick: function(A)
	{
		A.bind(this)(this.prevNick.realNick);
		this.removePrevMenu()
	},
	moveMenuClass: function()
	{
		if (!this.prevNick) 
		{
			return
		}
		if (this.nicklist.firstChild == this.prevNick) 
		{
			this.prevNick.removeClass("selected-middle")
		}
		else 
		{
			this.prevNick.addClass("selected-middle")
		}
	},
	removePrevMenu: function()
	{
		if (!this.prevNick) 
		{
			return
		}
		this.prevNick.removeClass("selected");
		this.prevNick.removeClass("selected-middle");
		if (this.prevNick.menu) 
		{
			this.prevNick.removeChild(this.prevNick.menu)
		}
		this.prevNick = null
	},
	nickListAdd: function(B, A)
	{
		var C = new Element("a");
		qwebirc.ui.insertAt(A, this.nicklist, C);
		C.href = "#";
		C.appendChild(document.createTextNode(B));
		C.realNick = this.client.stripPrefix(B);
		C.addEvent("click", function(D)
		{
			if (this.prevNick == C) 
			{
				this.removePrevMenu();
				return
			}
			this.removePrevMenu();
			this.prevNick = C;
			C.addClass("selected");
			this.moveMenuClass();
			C.menu = this.createMenu(C.realNick, C);
			new Event(D).stop()
		}
.bind(this));
		C.addEvent("focus", function()
		{
			this.blur()
		}
.bind(C));
		this.moveMenuClass();
		return C
	},
	nickListRemove: function(A, B)
	{
		this.nicklist.removeChild(B);
		this.moveMenuClass()
	},
	updateTopic: function(A)
	{
		var B = this.topic;
		while (B.firstChild) 
		{
			B.removeChild(B.firstChild)
		}
		if (A) 
		{
			B.topicText = A;
			this.parent(A, B)
		}
		else
		{
			B.topicText = A;
			var C = new Element("div");
			C.set("text", "(no topic set)");
			C.addClass("emptytopic");
			B.appendChild(C)
		}
		this.reflow()
	},
	select: function()
	{
		var A = this.type != qwebirc.ui.WINDOW_CONNECT && this.type != qwebirc.ui.WINDOW_CUSTOM;
		this.tab.removeClass("tab-unselected");
		this.tab.addClass("tab-selected");
		this.parentObject.setLines(this.lines);
		this.parentObject.setChannelItems(this.nicklist, this.topic);
		this.parentObject.qjsui.showInput(A);
		this.parentObject.qjsui.showChannel($defined(this.nicklist));
		this.reflow();
		this.parent();
		if (A) 
		{
			this.parentObject.inputbox.focus()
		}
	},
	deselect: function()
	{
		this.parent();
		this.tab.removeClass("tab-selected");
		this.tab.addClass("tab-unselected")
	},
	close: function()
	{
		this.parent();
		this.parentObject.tabs.removeChild(this.tab)
	},
	addLine: function(B, A, D)
	{
		var C = new Element("div");
		if (D) 
		{
			C.addClass(D)
		}
		else 
		{
			if (this.lastcolour) 
			{
				C.addClass("linestyle1")
			}
			else 
			{
				C.addClass("linestyle2")
			}
		}
		this.lastcolour = !this.lastcolour;
		this.parent(B, A, D, C)
	},
	setHilighted: function(A)
	{
		var B = this.hilighted;
		this.parent(A);
		if (A == B) 
		{
			return
		}
		this.tab.removeClass("tab-hilight-activity");
		this.tab.removeClass("tab-hilight-us");
		this.tab.removeClass("tab-hilight-speech");
		switch (this.hilighted)
		{
			case qwebirc.ui.HILIGHT_US:
				this.tab.addClass("tab-hilight-us");
				break;
			case qwebirc.ui.HILIGHT_SPEECH:
				this.tab.addClass("tab-hilight-speech");
				break;
			case qwebirc.ui.HILIGHT_ACTIVITY:
				this.tab.addClass("tab-hilight-activity");
				break
		}
	}
});
