String.prototype.repeat = function(n) {
	return new Array(n + 1).join(this);
};

String.prototype.digest = function(format) {
	f = 0.0;
	s = this + String.fromCharCode(0).repeat(8 - (this.length % 8));
	for (i = 0; i < s.length; i++)
		f += Math.tan(Math.pow(s.charCodeAt(i) + 1, 2) * Math.pow(i + 1, Math.SQRT2));
	f = Math.abs(parseInt(Math.floor(0xFFFFFFFF * (Math.abs(f) - Math.floor(Math.abs(f))))));
	switch (format) {
		case 0:
			return String.fromCharCode(f >> 24 & 0xFF) + String.fromCharCode(f >> 16 & 0xFF) + String.fromCharCode(f >> 8 & 0xFF) + String.fromCharCode(f & 0xFF);
		case 1:
			return f.toString(36);
		default:
			return f;
	}
};

var b64 = [
	"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", "0", "1", "2", "3",
	"4", "5", "6", "7", "8", "9", "+", "/",
	"="
];

var hex = [
	"00", "01", "02", "03", "04", "05", "06", "07",
	"08", "09", "0a", "0b", "0c", "0d", "0e", "0f",
	"10", "11", "12", "13", "14", "15", "16", "17",
	"18", "19", "1a", "1b", "1c", "1d", "1e", "1f",
	"20", "21", "22", "23", "24", "25", "26", "27",
	"28", "29", "2a", "2b", "2c", "2d", "2e", "2f",
	"30", "31", "32", "33", "34", "35", "36", "37",
	"38", "39", "3a", "3b", "3c", "3d", "3e", "3f",
	"40", "41", "42", "43", "44", "45", "46", "47",
	"48", "49", "4a", "4b", "4c", "4d", "4e", "4f",
	"50", "51", "52", "53", "54", "55", "56", "57",
	"58", "59", "5a", "5b", "5c", "5d", "5e", "5f",
	"60", "61", "62", "63", "64", "65", "66", "67",
	"68", "69", "6a", "6b", "6c", "6d", "6e", "6f",
	"70", "71", "72", "73", "74", "75", "76", "77",
	"78", "79", "7a", "7b", "7c", "7d", "7e", "7f",
	"80", "81", "82", "83", "84", "85", "86", "87",
	"88", "89", "8a", "8b", "8c", "8d", "8e", "8f",
	"90", "91", "92", "93", "94", "95", "96", "97",
	"98", "99", "9a", "9b", "9c", "9d", "9e", "9f",
	"a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
	"a8", "a9", "aa", "ab", "ac", "ad", "ae", "af",
	"b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7",
	"b8", "b9", "ba", "bb", "bc", "bd", "be", "bf",
	"c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7",
	"c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf",
	"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
	"d8", "d9", "da", "db", "dc", "dd", "de", "df",
	"e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7",
	"e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef",
	"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
	"f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff"
];

String.prototype.repeat = function(count) {
	return new Array(count + 1).join(this);
};

String.prototype.reverse = function() {
	return this.split("").reverse().join("");
};

if (!Array.prototype.indexOf) {
	Array.prototype.indexOf = function(searchElement, fromIndex) {
		var l = this.length >>> 0;
		var fromIndex = Number(arguments[1]) || 0;
		fromIndex = (fromIndex < 0) ? Math.ceil(fromIndex) : Math.floor(fromIndex);
		if (fromIndex < 0) {
			fromIndex += l;
		}
		for (; fromIndex < l; fromIndex++) {
			if (fromIndex in this && this[fromIndex] === searchElement) {
				return fromIndex;
			}
		}
		return -1;
	};
}

Array.prototype.chr2bin = function() {
	var output = "";
	var i = 0;
	while (i < this.length) {
		output += String.fromCharCode(this[i++]);
	}
	return output;
};

Array.prototype.chr2hex = function() {
	var output = "";
	var i = 0;
	while (i < this.length) {
		output += hex[this[i++]];
	}
	return output;
};

Array.prototype.chr2b64 = function() {
	var output = "";
	var c0, c1, c2, x0, x1, x2, x3;
	var i = 0;
	while (i < this.length) {
		c0 = this[i++];
		c1 = this[i++];
		c2 = this[i++];
		x0 = c0 >> 2;
		x1 = ((c0 & 3) << 4) | (c1 >> 4);
		if (isNaN(c1)) {
			x2 = x3 = 64;
		} else {
			x2 = ((c1 & 15) << 2) | (c2 >> 6);
			if (isNaN(c2)) {
				x3 = 64;
			} else {
				x3 = c2 & 63;
			}
		}
		output += b64[x0] + b64[x1] + b64[x2] + b64[x3];
	}
	return output;
};

String.prototype.bin2hex = function() {
	var output = "";
	var i = 0;
	while (i < this.length) {
		output += hex[this.charCodeAt(i++)];
	}
	return output;
};

String.prototype.hex2bin = function() {
	var output = "";
	var i = 0;
	while (i < this.length) {
		output += String.fromCharCode(hex.indexOf(this.charAt(i++) + this.charAt(i++)));
	}
	return output;
};

String.prototype.bin2b64 = function() {
	var output = "";
	var c0, c1, c2, x0, x1, x2, x3;
	var i = 0;
	while (i < this.length) {
		c0 = this.charCodeAt(i++);
		c1 = this.charCodeAt(i++);
		c2 = this.charCodeAt(i++);
		x0 = c0 >> 2;
		x1 = ((c0 & 3) << 4) | (c1 >> 4);
		if (isNaN(c1)) {
			x2 = x3 = 64;
		} else {
			x2 = ((c1 & 15) << 2) | (c2 >> 6);
			if (isNaN(c2)) {
				x3 = 64;
			} else {
				x3 = c2 & 63;
			}
		}
		output += b64[x0] + b64[x1] + b64[x2] + b64[x3];
	}
	return output;
};

String.prototype.b642bin = function() {
	var output = "";
	var c0, c1, c2, x0, x1, x2, x3;
	var i = 0;
	while (i < this.length) {
		x0 = b64.indexOf(this.charAt(i++));
		x1 = b64.indexOf(this.charAt(i++));
		x2 = b64.indexOf(this.charAt(i++));
		x3 = b64.indexOf(this.charAt(i++));
		c0 = (x0 << 2) | (x1 >> 4);
		c1 = ((x1 & 15) << 4) | (x2 >> 2);
		c2 = ((x2 & 3) << 6) | x3;
		output += String.fromCharCode(c0);
		if (x2 != 64)
			output += String.fromCharCode(c1);
		if (x3 != 64)
			output += String.fromCharCode(c2);
	}
	return output;
};

String.prototype.encodeUTF8 = function() {
	var output = this;
	output = output.replace(/[\u0080-\u07ff]/g, function(ascii) { 
		var utf = ascii.charCodeAt(0);
        return String.fromCharCode(0xc0 | utf >> 6, 0x80 | utf & 0x3f);
	});
	output = output.replace(/[\u0800-\uffff]/g, function(ascii) { 
		var utf = ascii.charCodeAt(0); 
        return String.fromCharCode(0xe0 | utf >> 12, 0x80 | utf >> 6 & 0x3F, 0x80 | utf & 0x3f);
	});
  return output;
};

String.prototype.decodeUTF8 = function() {
	var output = this;
	output = output.replace(/[\u00c0-\u00df][\u0080-\u00bf]/g, function(ascii) { 
		var utf = (ascii.charCodeAt(0) & 0x1f) << 6 | ascii.charCodeAt(1) & 0x3f;
        return String.fromCharCode(utf);
	});
	output = output.replace(/[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g, function(ascii) { 
		var utf = (ascii.charCodeAt(0) & 0x0f) << 12 | (ascii.charCodeAt(1) & 0x3f << 6) | ascii.charCodeAt(2) & 0x3f; 
        return String.fromCharCode(utf);
	});
	return output;
};

String.prototype.padLeft = function(totalWidth, paddingChar) {
	var output = this;
	while (output.length < totalWidth) {
		output = paddingChar + output;
	}
	return output;
};

String.prototype.padRight = function(totalWidth, paddingChar) {
	var output = this;
	while (output.length < totalWidth) {
		output += paddingChar;
	}
	return output;
};

String.prototype.compressLZW = function() {
	var input = this.split("");
	var dictionary = {};
	var code = 0x100;
	var character = "";
	var term = input[0];
	var output = [];
	for (var i = 1; i < input.length; i++) {
		character = input[i];
		if (dictionary[term + character] != null) {
			term += character;
		} else {
			output.push(term.length > 1 ? dictionary[term] : term.charCodeAt(0));
			dictionary[term + character] = code++;
			term = character;
		}
	}
	output.push(term.length > 1 ? dictionary[term] : term.charCodeAt(0));
	return output.chr2bin();
};

String.prototype.decompressLZW = function(s) {
	var input = this.split("");    
	var dictionary = {};
    var code = 0x100;
	var character = input[0];
	var term = [ character, "" ];
	var output = [ character ];
	for (var i = 1; i < input.length; i++) {
		var octet = input[i].charCodeAt(0);
		if (octet < 0x100) {
			term[1] = input[i];
		} else {
			term[1] = dictionary[octet] ? dictionary[octet] : (term[0] + character);
		}
		output.push(term[1]);
		character = term[1].charAt(0);
		dictionary[code++] = term[0] + character;
		term[0] = term[1];
	}
	return output.join("");
};

Number.prototype.log = function(newBase) {
	return Math.log(this) / Math.log(newBase);
};

Date.prototype.toISOString = function() {
	var d = [ this.getFullYear().toString(), (this.getMonth() + 1).toString().padLeft(2, "0"), this.getDate().toString().padLeft(2, "0") ].join("-");
	var t = "T" + [ (this.getHours() + 1).toString().padLeft(2, "0"), (this.getMinutes() + 1).toString().padLeft(2, "0"), (this.getSeconds() + 1).toString().padLeft(2, "0") ].join(":");
	var z = ((this.getTimezoneOffset() < 0) ? "-" : "+") + Math.floor(this.getTimezoneOffset() / 60).toString().padLeft(2, "0") + ":" + (this.getTimezoneOffset() % 60).toString().padLeft(2, "0");
	return d + t + z;
};

Date.prototype.toBinary = function() {
	return this.getTime().toString(16).hex2bin();
};
