//Class Utils
Utils = function () {}

//Class Utils.Element
Utils.Element = function () {}

Utils.Element.getClientWidth = function (element)
{
    return (element.clientWidth != 0)? element.clientWidth : element.offsetWidth;
}

Utils.Element.setClientWidth = function (element, width)
{
	element.style.width = width + "px";
}

Utils.Element.getClientHeight = function (element)
{
    return (element.clientHeight != 0)? element.clientHeight : element.offsetHeight;
}

Utils.Element.setClientHeight = function (element, height)
{
	element.style.height = height + "px";
}

Utils.Element.getClientLeft = function (element)
{
    //has a bug in Opera with position:absolute
    var elem = element.offsetParent;
    var left = element.offsetLeft;
    while (elem != null && elem.tagName != "HTML")
    {
        left += elem.offsetLeft;
        left -= elem.scrollLeft;
        elem = elem.offsetParent;
    }
    return left;
}

Utils.Element.getClientRight = function (element)
{
    //has a bug in Opera with position:absolute
    return Utils.Element.getClientLeft(element) + Utils.Element.getClientWidth(element);
}

Utils.Element.getClientTop = function (element)
{
    //has a bug in Opera with position:absolute
    var elem = element.offsetParent;
    var top = element.offsetTop;
    while (elem != null && elem.tagName != "HTML")
    {
        top += elem.offsetTop;
        top -= elem.scrollTop;
        elem = elem.offsetParent;
    }
    return top;
}

Utils.Element.getClientBottom = function (element)
{
    //has a bug in Opera with position:absolute
    return Utils.Element.getClientTop(element) + Utils.Element.getClientHeight(element);
}

Utils.Element.getClientLeftOffset = function (element)
{
	var left = 0;
	while (element != null && element.tagName != "BODY") {
		left += element.offsetLeft - element.scrollLeft;
		element = element.offsetParent;
	}
	return left;
}

Utils.Element.getClientTopOffset = function (element)
{
	var top = 0;
	while (element != null && element.tagName != "BODY") {
		top += element.offsetTop - element.scrollTop;
		element = element.offsetParent;
	}
	return top;
}

Utils.Element.containsClientPoint = function (element, x, y)
{
    var left = Utils.Element.getClientLeft(element);
    var right = Utils.Element.getClientRight(element);
    var top = Utils.Element.getClientTop(element);
    var bottom = Utils.Element.getClientBottom(element);
    
    if(left < x && x < right && top < y && y < bottom)
    {
        return true;
    }
    else
    {
        return false;
    }
}

//Class Utils.Node
Utils.Node = function() {}

Utils.Node.getChildById = function (node, id)
{
	var child = null;
	if (node.hasChildNodes())
	{
		for (var i = 0; i < node.childNodes.length; i++)
		{
			if (node.childNodes.item(i).id == id)
			{
				return node.childNodes.item(i);
			}
			else
			{
				child = Utils.Node.getChildById(node.childNodes.item(i), id);
				if (child != null)
				{
					return child;
				}
			}
		}
	}
	return null;
}

Utils.Node.getChildsByTagName = function (node, tagName)
{
	var childs = new Array();
	if (node.hasChildNodes != null && node.hasChildNodes())
	{
		for (var i = 0; i < node.childNodes.length; i++)
		{
			if (node.childNodes.item(i).nodeName == tagName)
			{
				childs.push(node.childNodes.item(i));
			}
			var moreChilds =
				Utils.Node.getChildsByTagName(node.childNodes.item(i), tagName);
			childs.concat(moreChilds);
		}
	}
	return childs;
}

Utils.Node.copyChildsToNode = function (original, target)
{
	if (target.hasChildNodes())
	{
		while (target.hasChildNodes())
		{
			target.removeChild(target.firstChild);
		}
	}
	if (original.hasChildNodes())
	{
		for (var i = 0; i < original.childNodes.length; i++)
		{
			var node = original.childNodes.item(i).cloneNode(true);
			target.appendChild(node);
		}
	}
}

Utils.Node.moveChildsToNode = function (original, target)
{
	while (target.hasChildNodes())
	{
		target.removeChild(target.firstChild);
	}
	while(original.hasChildNodes())
	{
		target.appendChild(original.firstChild);
	}
}

//Class Utils.Document
Utils.Document = function () {}

Utils.Document.importNode = function (document, node, deep)
{
	var newNode = node.cloneNode(deep);
	return newNode;
}

//Review math signals (on keypad)
//class Utils.KeyIdentifiers
Utils.KeyIdentifiers = function () {}
Utils.KeyIdentifiers.ALT = 18; //The Alt (Menu) key.
Utils.KeyIdentifiers.CAPS_LOCK = 20; //The Caps Lock (Capital) key.
Utils.KeyIdentifiers.CONTROL = 17; //The Control (Ctrl) key.
Utils.KeyIdentifiers.DOWN = 40; //The Down Arrow key.
Utils.KeyIdentifiers.END = 35; //The End key.
Utils.KeyIdentifiers.ENTER = 13; //The Enter key.
Utils.KeyIdentifiers.F1 = 112; //The F1 key.
Utils.KeyIdentifiers.F2 = 113; //The F2 key.
Utils.KeyIdentifiers.F3 = 114; //The F3 key.
Utils.KeyIdentifiers.F4 = 115; //The F4 key.
Utils.KeyIdentifiers.F5 = 116; //The F5 key.
Utils.KeyIdentifiers.F6 = 117; //The F6 key.
Utils.KeyIdentifiers.F7 = 118; //The F7 key.
Utils.KeyIdentifiers.F8 = 119; //The F8 key.
Utils.KeyIdentifiers.F9 = 120; //The F9 key.
Utils.KeyIdentifiers.F10 = 121; //The F10 key.
Utils.KeyIdentifiers.F11 = 122; //The F11 key.
Utils.KeyIdentifiers.F12 = 123; //The F12 key.
Utils.KeyIdentifiers.HOME = 36; //The Home key.
Utils.KeyIdentifiers.INSERT = 45; //The Insert (Ins) key.
Utils.KeyIdentifiers.LEFT = 37; //The Left Arrow key.
Utils.KeyIdentifiers.NUM_LOCK = 114; //The Num Lock key.
Utils.KeyIdentifiers.PAGE_DOWN = 34; //The Page Down (Next) key.
Utils.KeyIdentifiers.PAGE_UP = 33; //The Page Up key.
Utils.KeyIdentifiers.RIGHT = 39; //The Right Arrow key.
Utils.KeyIdentifiers.SCROLL = 145; //The Scroll Lock key.
Utils.KeyIdentifiers.SHIFT = 16; //The Shift key.
Utils.KeyIdentifiers.UP = 38; //The Up Arrow key.
Utils.KeyIdentifiers.WIN = 91; //The Windows Logo key.
Utils.KeyIdentifiers.BACKSPACE = 8; //The Backspace (Back) key.
Utils.KeyIdentifiers.TAB = 9; //The Horizontal Tabulation (Tab) key.
Utils.KeyIdentifiers.ESCAPE = 27; //The Escape (Esc) key.
Utils.KeyIdentifiers.SPACEBAR = 32; //The Space (Spacebar) key.
Utils.KeyIdentifiers.ASTERIX = 106; //The Asterix (Star) key (*).
Utils.KeyIdentifiers.PLUS = 61; //The Plus Sign (Plus) key (+).
Utils.KeyIdentifiers.COMMA = 188; //The Comma (decimal separator) sign key (,).
Utils.KeyIdentifiers.HYPHEN = 109; //The Hyphen-minus (hyphen or minus sign) key (-).
Utils.KeyIdentifiers.PERIOD = 190; //The Full Stop (period, dot, decimal point) key (.).
Utils.KeyIdentifiers.SLASH = 111; //The Solidus (slash, virgule, shilling) key (/).
Utils.KeyIdentifiers.ZERO = 48; //The Digit Zero key (0).
Utils.KeyIdentifiers.ONE = 49; //The Digit One key (1).
Utils.KeyIdentifiers.TWO = 50; //The Digit Two key (2).
Utils.KeyIdentifiers.THREE = 51; //The Digit Three key (3).
Utils.KeyIdentifiers.FOUR = 52; //The Digit Four key (4).
Utils.KeyIdentifiers.FIVE = 53; //The Digit Five key (5).
Utils.KeyIdentifiers.SIX = 54; //The Digit Six key (6).
Utils.KeyIdentifiers.SEVEN = 55; //The Digit Seven key (7).
Utils.KeyIdentifiers.EIGHT = 56; //The Digit Eight key (8).
Utils.KeyIdentifiers.NINE = 57; //The Digit Nine key (9).
Utils.KeyIdentifiers.A = 65; //The Latin Capital Letter A key (A).
Utils.KeyIdentifiers.B = 66; //The Latin Capital Letter B key (B).
Utils.KeyIdentifiers.C = 67; //The Latin Capital Letter C key (C).
Utils.KeyIdentifiers.D = 68; //The Latin Capital Letter D key (D).
Utils.KeyIdentifiers.E = 69; //The Latin Capital Letter E key (E).
Utils.KeyIdentifiers.F = 70; //The Latin Capital Letter F key (F).
Utils.KeyIdentifiers.G = 71; //The Latin Capital Letter G key (G).
Utils.KeyIdentifiers.H = 72; //The Latin Capital Letter H key (H).
Utils.KeyIdentifiers.I = 73; //The Latin Capital Letter I key (I).
Utils.KeyIdentifiers.J = 74; //The Latin Capital Letter J key (J).
Utils.KeyIdentifiers.K = 75; //The Latin Capital Letter K key (K).
Utils.KeyIdentifiers.L = 76; //The Latin Capital Letter L key (L).
Utils.KeyIdentifiers.M = 77; //The Latin Capital Letter M key (M).
Utils.KeyIdentifiers.N = 78; //The Latin Capital Letter N key (N).
Utils.KeyIdentifiers.O = 79; //The Latin Capital Letter O key (O).
Utils.KeyIdentifiers.P = 80; //The Latin Capital Letter P key (P).
Utils.KeyIdentifiers.Q = 81; //The Latin Capital Letter Q key (Q).
Utils.KeyIdentifiers.R = 82; //The Latin Capital Letter R key (R).
Utils.KeyIdentifiers.S = 83; //The Latin Capital Letter S key (S).
Utils.KeyIdentifiers.T = 84; //The Latin Capital Letter T key (T).
Utils.KeyIdentifiers.U = 85; //The Latin Capital Letter U key (U).
Utils.KeyIdentifiers.V = 86; //The Latin Capital Letter V key (V).
Utils.KeyIdentifiers.W = 87; //The Latin Capital Letter W key (W).
Utils.KeyIdentifiers.X = 88; //The Latin Capital Letter X key (X).
Utils.KeyIdentifiers.Y = 89; //The Latin Capital Letter Y key (Y).
Utils.KeyIdentifiers.Z = 90; //The Latin Capital Letter Z key (Z).
Utils.KeyIdentifiers.BACKSLASH = 220; //The Reverse Solidus (Backslash) key (\).
Utils.KeyIdentifiers.DELETE = 46; //The Delete (Del) Key.
Utils.KeyIdentifiers.NUMPAD_0 = 96;
Utils.KeyIdentifiers.NUMPAD_1 = 97;
Utils.KeyIdentifiers.NUMPAD_2 = 98;
Utils.KeyIdentifiers.NUMPAD_3 = 99;
Utils.KeyIdentifiers.NUMPAD_4 = 100;
Utils.KeyIdentifiers.NUMPAD_5 = 101;
Utils.KeyIdentifiers.NUMPAD_6 = 102;
Utils.KeyIdentifiers.NUMPAD_7 = 103;
Utils.KeyIdentifiers.NUMPAD_8 = 104;
Utils.KeyIdentifiers.NUMPAD_9 = 105;

Utils.StringUtil = function() { }

Utils.StringUtil.ComputeMD5HashToString = function(string)
{
	function WordToHex(lValue)
	{
		var WordToHexValue = "", WordToHexValue_temp = "", lByte, lCount;
		for (lCount = 0; lCount <= 3; lCount++)
		{
			lByte = (lValue >>> (lCount * 8)) & 255;
			WordToHexValue_temp = "0" + lByte.toString(16);
			WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2);
		}
		return WordToHexValue;
	};
	var wordsMD5 = Utils.StringUtil.ComputeMD5Hash(string);
	var temp = WordToHex(wordsMD5[0]) + WordToHex(wordsMD5[1]) + WordToHex(wordsMD5[2]) + WordToHex(wordsMD5[3]);
	return temp.toLowerCase();
}

Utils.StringUtil.ComputeMBPMPassword = function(username, password)
{
	var passwordMD5 = Utils.StringUtil.ComputeMD5Hash(username + password);
	return (Utils.StringUtil.ToBase64String(passwordMD5)).substring(0, 22);
}

/* 
 * Convert a raw string to a base-64 string. (It doesn't encode to UTF-8 encoding)
 */
Utils.StringUtil.ToBase64String = function(input)
{
	var symbols = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
	var output = "";
	var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
	var i = 0;
	//input = Base64._utf8_encode(input);
	while (i < input.length)
	{
		chr1 = input.charCodeAt(i++);
		chr2 = input.charCodeAt(i++);
		chr3 = input.charCodeAt(i++);

		enc1 = chr1 >> 2;
		enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
		enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
		enc4 = chr3 & 63;

		if (isNaN(chr2))
		{
			enc3 = enc4 = 64;
		}
		else if (isNaN(chr3))
		{
			enc4 = 64;
		}
		output = output + symbols.charAt(enc1) + symbols.charAt(enc2) + symbols.charAt(enc3) + symbols.charAt(enc4);
	}
	return output;
}

Utils.StringUtil.ComputeMD5HashToString = function(string)
{
	function rstr2hex(input)
	{
		try { hexcase } catch (e) { hexcase = 0; }
		var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
		var output = "";
		var x;
		for (var i = 0; i < input.length; i++)
		{
			x = input.charCodeAt(i);
			output += hex_tab.charAt((x >>> 4) & 0x0F)
           + hex_tab.charAt(x & 0x0F);
		}
		return output;
	};
	return rstr2hex(Utils.StringUtil.ComputeMD5Hash(string));
}

Utils.StringUtil.ComputeMD5Hash = function(string)
{
	function RotateLeft(lValue, iShiftBits)
	{
		return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
	}

	function AddUnsigned(lX, lY)
	{
		var lX4, lY4, lX8, lY8, lResult;
		lX8 = (lX & 0x80000000);
		lY8 = (lY & 0x80000000);
		lX4 = (lX & 0x40000000);
		lY4 = (lY & 0x40000000);
		lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
		if (lX4 & lY4)
		{
			return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
		}
		if (lX4 | lY4)
		{
			if (lResult & 0x40000000)
			{
				return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
			} else
			{
				return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
			}
		} else
		{
			return (lResult ^ lX8 ^ lY8);
		}
	}

	function F(x, y, z) { return (x & y) | ((~x) & z); }
	function G(x, y, z) { return (x & z) | (y & (~z)); }
	function H(x, y, z) { return (x ^ y ^ z); }
	function I(x, y, z) { return (y ^ (x | (~z))); }

	function FF(a, b, c, d, x, s, ac)
	{
		a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac));
		return AddUnsigned(RotateLeft(a, s), b);
	};

	function GG(a, b, c, d, x, s, ac)
	{
		a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac));
		return AddUnsigned(RotateLeft(a, s), b);
	};

	function HH(a, b, c, d, x, s, ac)
	{
		a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac));
		return AddUnsigned(RotateLeft(a, s), b);
	};

	function II(a, b, c, d, x, s, ac)
	{
		a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac));
		return AddUnsigned(RotateLeft(a, s), b);
	};

	function ConvertToWordArray(string)
	{
		var lWordCount;
		var lMessageLength = string.length;
		var lNumberOfWords_temp1 = lMessageLength + 8;
		var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
		var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
		var lWordArray = Array(lNumberOfWords - 1);
		var lBytePosition = 0;
		var lByteCount = 0;
		while (lByteCount < lMessageLength)
		{
			lWordCount = (lByteCount - (lByteCount % 4)) / 4;
			lBytePosition = (lByteCount % 4) * 8;
			lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition));
			lByteCount++;
		}
		lWordCount = (lByteCount - (lByteCount % 4)) / 4;
		lBytePosition = (lByteCount % 4) * 8;
		lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
		lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
		lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
		return lWordArray;
	};

	function WordToHex(lValue)
	{
		var WordToHexValue = "", WordToHexValue_temp = "", lByte, lCount;
		for (lCount = 0; lCount <= 3; lCount++)
		{
			lByte = (lValue >>> (lCount * 8)) & 255;
			WordToHexValue_temp = "0" + lByte.toString(16);
			WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2);
		}
		return WordToHexValue;
	};

	function Utf8Encode(string)
	{
		string = string.replace(/\r\n/g, "\n");
		var utftext = "";

		for (var n = 0; n < string.length; n++)
		{

			var c = string.charCodeAt(n);

			if (c < 128)
			{
				utftext += String.fromCharCode(c);
			}
			else if ((c > 127) && (c < 2048))
			{
				utftext += String.fromCharCode((c >> 6) | 192);
				utftext += String.fromCharCode((c & 63) | 128);
			}
			else
			{
				utftext += String.fromCharCode((c >> 12) | 224);
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
				utftext += String.fromCharCode((c & 63) | 128);
			}

		}

		return utftext;
	};
	var x = Array();
	var k, AA, BB, CC, DD, a, b, c, d;
	var S11 = 7, S12 = 12, S13 = 17, S14 = 22;
	var S21 = 5, S22 = 9, S23 = 14, S24 = 20;
	var S31 = 4, S32 = 11, S33 = 16, S34 = 23;
	var S41 = 6, S42 = 10, S43 = 15, S44 = 21;
	string = Utf8Encode(string);
	x = ConvertToWordArray(string);
	a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;
	for (k = 0; k < x.length; k += 16)
	{
		AA = a; BB = b; CC = c; DD = d;
		a = FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
		d = FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
		c = FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
		b = FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
		a = FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
		d = FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
		c = FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
		b = FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
		a = FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
		d = FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
		c = FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
		b = FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
		a = FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
		d = FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
		c = FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
		b = FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
		a = GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
		d = GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
		c = GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
		b = GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
		a = GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
		d = GG(d, a, b, c, x[k + 10], S22, 0x2441453);
		c = GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
		b = GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
		a = GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
		d = GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
		c = GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
		b = GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
		a = GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
		d = GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
		c = GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
		b = GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
		a = HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
		d = HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
		c = HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
		b = HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
		a = HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
		d = HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
		c = HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
		b = HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
		a = HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
		d = HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
		c = HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
		b = HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
		a = HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
		d = HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
		c = HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
		b = HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
		a = II(a, b, c, d, x[k + 0], S41, 0xF4292244);
		d = II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
		c = II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
		b = II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
		a = II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
		d = II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
		c = II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
		b = II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
		a = II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
		d = II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
		c = II(c, d, a, b, x[k + 6], S43, 0xA3014314);
		b = II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
		a = II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
		d = II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
		c = II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
		b = II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
		a = AddUnsigned(a, AA);
		b = AddUnsigned(b, BB);
		c = AddUnsigned(c, CC);
		d = AddUnsigned(d, DD);
	}
	var wordsMD5 = new Array(a, b, c, d);
	var output = "";
	for (var i = 0; i < wordsMD5.length * 32; i += 8)
		output += String.fromCharCode((wordsMD5[i >> 5] >>> (i % 32)) & 0xFF);
	return output;
}

function BrowserUtils() {}

BrowserUtils.getElementLeft = function (elem, isPositionAbsolute)
{
	var left = 0;
	while (elem.tagName != "BODY") {
		left += elem.offsetLeft;
		elem = elem.offsetParent;
	}
	return left;
}

BrowserUtils.getElementTop = function(elem, isPositionAbsolute)
{
	var top = 0;
	while (elem.tagName != "BODY") {
		top += elem.offsetTop;
		elem = elem.offsetParent;
	}
	return top;
}

BrowserUtils.getElementRight = function(element, isPositionAbsolute)
{
	return BrowserUtils.getElementLeft(element, isPositionAbsolute) + element.offsetWidth;
}

BrowserUtils.getElementBottom = function(element, isPositionAbsolute)
{
	return BrowserUtils.getElementTop(element, isPositionAbsolute) + element.offsetHeight;
}

BrowserUtils.getElementWidth = function(element)
{
	return element.offsetWidth;
}

BrowserUtils.getElementHeight = function(element)
{
	return element.offsetHeight;
}

BrowserUtils.isParent = function (parent, child)
{
	var aux = child;
	while(aux)
	{
		if(aux == parent)
		{
			return true;
		}
		aux = aux.parentElement;
	}
	return false;
}

//TODO: create class with methods instead

function EventUtils() {}

EventUtils.addEventListener = function (eventName, handler, elem)
{
	if (elem != null)
		W3C.EventTarget.addEventListener(elem,eventName,handler,false)	
}

EventUtils.removeEventListener = function (eventName, handler, elem)
{
	if (elem != null)
		W3C.EventTarget.removeEventListener(elem,eventName,handler,false)	
}

EventUtils.getEvent = function (ev)
{
	if (ev)
	{
		return ev;
	}
	else if (window.event)
	{
		return window.event;
	}
	else
	{
		return null;
	}
}

EventUtils.getEventTarget = function (ev)
{
	if(ev.target)
	{
		return ev.target;
	}
	else if(ev.srcElement)
	{
		return ev.srcElement;
	}
	else
	{
		return null;
	}
}

EventUtils.getCurrentTarget = function (ev)
{
	if(ev.currentTarget)
	{
		return ev.currentTarget;
	}
	else if(ev.toElement)
	{
		return ev.toElement;
	}
	else
	{
		return null;
	}
}

EventUtils.getMouseX = function (ev)
{
	if(ev.clientX)
	{
		return ev.clientX;
	}
	else
	{
		return null;
	}
}

EventUtils.getMouseY = function (ev)
{
	if(ev.clientY)
	{
		return ev.clientY;
	}
	else
	{
		return null;
	}
}

EventUtils.cancelEvent = function (ev)
{
	var evt = EventUtils.getEvent(ev);
	evt.cancelBubble = true;
	evt.returnValue = false;
}


/* debug window */
var debugWindow;
function getDebugWindow()
{
	if (debugWindow == null)
	{
		debugWindow = window.open('','debugWindow', 'resizable,height=300,width=300,scrollbars="yes"');
		debugWindow.document.open();
		debugWindow.document.write("<html><body><pre>");
	}
	return debugWindow;
}

function writeDebugLog(text)
{
	//var debugWindow = getDebugWindow();
	//if(debugWindow != null)
	//    debugWindow.document.write(text + "\n");
}
