/*
JavaScript Extension Library (JSXL) v2.0
August 21, 2006
Shawn Bailly (www.shawn-bailly.com)
(c) 2003-2006 Shawn Bailly

Please report bugs at www.shawn-bailly.com.
This library is released as open source, if you develop some new or better methods, please submit them to me and I may put them in the next version.

Online documentation available at http://www.shawn-bailly.com/projects/jsxl/documentation


---- THIS LIBRARY IS NOT YET COMPLETE ----
*/
//Constants
var __ELEMENT_NODE = 1;
var __ATTRIBUTE_NODE = 2;
var __TEXT_NODE = 3;
var __CDATA_SECTION_NODE = 4;
var __ENTITY_REFERENCE_NODE = 5;
var __ENTITY_NODE = 6;
var __PROCESSING_INSTRUCTION_NODE = 7;
var __COMMENT_NODE = 8;
var __DOCUMENT_NODE = 9;
var __DOCUMENT_TYPE_NODE = 10;
var __DOCUMENT_FRAGMENT_NODE = 11;
var __NOTATION_NODE = 12;

//Object Definitions
Object.prototype._toolkit = {
	/*
	Purpose:
		Provide general information about the current script.
	*/
	name : "JavaScript Extension Library",
	version : "2.0",
	author : "Shawn Bailly (www.shawn-bailly.com)",
	date : "Aug 21, 2006",
	license : "Open",
	verbose : false
};
Object.prototype.error = function(message){
	/*
	Parameters:
		message (string) - The error message to throw.
	Purpose:
		Throw error specified in message. This method will also alert the error to the client, if the object's verbose flag is set to true.
	Usage:
		Object.error("Error message.");
	*/
	if (this.verbose){
		alert(message);
	}
	var e = new Error(message);
	throw e;
};
Object.prototype.Inherit = function(object){
	/*
	Parameters:
		object (object) - The object to inherit properties and methods from.
	Purpose:
		To use an object as other object oriented languages use classes. Inheriting will apply all properties, and methods from one class, to a new one.
	Returns:
		A new object inherited from the object specified.
	Usage:
		Dog = Object.Inherit(Animal);
	*/
	object = (object == null ? {} : object);
	for (key in object){
		if(this[key] == null){
			this[key] = object[key];
		}
	}
	return this;
};
Object.prototype.Create = function(object){
	/*
	Parameters:
		object (object) - The object to create.
	Purpose:
		Just another way to create an object.
	Returns:
		The object created.
	Usage:
		Animal = Object.Create({
			species : "",
			genus : ""
		});
	*/
	return object;
};
Object.prototype.Clone = function(object){
	/*
	Parameters:
		object (object) - The object to clone.
	Purpose:
		Makes a duplicate of the object passed.
	Returns:
		A clone of the object passed.
	Usage:
		Animal2 = Object.Clone(Animal);
	*/
	var newObject = {};
	object = (object == null ? {} : object);
	for (key in object){
		newObject[key] = object[key];
	}
	return object;
};
Object.prototype.toHuman = function(lf){
	/*
	Parameters:
		lf (string) - The line feed character to use. Default is \n (newline).
	Purpose:
		Useful for inspecting an object's properties, and methods.
	Returns:
		String, representing the objects properties and methods.
	Usage:
		alert(Dog.toHuman());
	*/
	lf = (lf == null ? "\\n" : lf);
	if (this.humanizer == null){
		var str = "";
		if (this.length != null || this.childNodes != null){
			str += "---Start Children List---"+lf;
			if (this.length != null){
				for (var i=0; i<this.length; i++)str += "child "+i+": "+this[i]+lf;
			}
			if (this.childNodes != null){
				for (var i=0; i<this.childNodes.length; i++)str += "child "+i+": "+this.childNodes[i]+lf;
			}
			str += "---End Children List---"+lf;
		}
		for (key in this){
			str += key+" = "+this[key]+lf;
		}
	}
	else str = this.humanizer(lf);
	return str;
};
Object.prototype.type = function(){
	/*
	Parameters:
		If no parameters are specified, this method will return a string of the name of the object determined.
		If any parameters are specified; they are passed to the constructor of the object, and the new object created is returned.
	Purpose:
		Use this on any Object to determine it's type, far more precisely than the built in JavaScript typeof operator.
		If the object type is determined to be an HTML element, the arguments passed are expected to be name=value pairs, designating attributes to be set on the new object.
		If constructor arguments are passed, and the return object can not be created; a string of the name of the object is returned instead.
	Returns:
		Either a string with the name of the object found; or a new object of the type found.
		Objects Recognized:
			object
			array
			boolean
			date
			enumerator (IE Specific)
			error
			function
			number
			regexp
			string
			*UDF Objects (returns the name of the constructor function)
		Will return null if could not determine object type.
	*/
	var value = null;
	var constructor = this.constructor;
	switch (typeof this){
		case "object":
			switch (constructor){
				case Object:
					value = (arguments.length > 0 ? new Object(arguments[0]) : "object");
					break;
				case String:
					value = (arguments.length > 0 ? new String(arguments[0]) : "string");
					break;
				case Number:
					value = (arguments.length > 0 ? new Number(arguments[0]) : "number");
					break;
				case Boolean:
					value = (arguments.length > 0 ? new Boolean(arguments[0]) : "boolean");
					break;
				case Array:
					value = (arguments.length > 0 ? new Array(arguments) : "array");
					break;
				case Date:
					value = (arguments.length > 0 ? new Date(arguments) : "date");
					break;
				case Error:
					value = (arguments.length > 0 ? new Error(arguments[0],arguments[1]) : "error");
					break;
				case RegExp:
					value = (arguments.length > 0 ? new RegExp(arguments[0],arguments[1]) : "regexp");
					break;
				default:
					var cName = $getFunctionName(constructor)
					if (cName != null){
						value = (arguments.length > 0 ? constructor.call(arguments) : cName);
					}
			}
			break;
		case "function":
			switch (constructor){
				case RegExp:
					value = (arguments.length > 0 ? new RegExp(arguments[0],arguments[1]) : "regexp");
					break;
				case Function:
					value = (arguments.length > 0 ? new Function(arguments) : "function");
					break;
			}
			break;
		case "string":
		case "number":
		case "boolean":
		case "array":
		case "date":
		case "error":
		case "regexp":
			value = typeof this;
			break;
		default:
			try {
				value = (returnObj ? null : "undetermined");
			}
			catch(e){
				value = "undetermined";
			}
	}
	if (value == null){
		// If after all that we didn't find what we're looking for, let's try some browser specific objects.
		try{
			if (constructor == Enumerator)value = (arguments.length > 0 ? new Enumerator(arguments[0]) : "enumerator");
		}
		catch (e){
		};
	}
	return value;
};

//Deterministic Boolean Methods
/* These are dummy methods */
Boolean.prototype.isBoolean = function(){
	return true;
};
Boolean.prototype.toBoolean = function(){
	return this;
};

//Deterministic String Methods
String.prototype.isBoolean = function(useNegative){
	/*
	Parameters:
		useNegative (boolean) - If true, then negative numbers are considered as a boolean value. Default is false.
	Purpose:
		Check if a string is a boolean value (fuzzy).
	Returns:
		Boolean, true if the string can be interpreted as a boolean value; false if it cannot.
	Usage:
		var whatAHumanMightConsiderBoolean = "yes";
		alert(whatAHumanMightConsiderBoolean.isBoolean());
		This will return true.
	*/
	var value = false;
	useNegative = (useNegative == null ? false : useNegative);
	if (this.is("true","on","yes","false","off","no") || (parseInt(this) >= 0 && !useNegative) || (!isNaN(this) && useNegative))value = true;
	return value;
};
String.prototype.toBoolean = function(negativeIs){
	/*
	Parameters:
		negativeIs (boolean) - If negative is to be considered boolean, it is either false or true. Default is null. (not considered).
	Purpose:
		If the string can be converted to a Boolean it returns it; otherwise null is returned.
	Returns:
		Boolean,
			Returns true if the string is equal to the words "true", "on", "yes" or if the string is a number greater than 0.
			Returns false if the string is equal to the words "false", "off", "no" or if the string is a number equal to 0.
			Otherwise it will return null.
	Usage:
		var whatAHumanMightConsiderBoolean = "yes";
		alert(whatAHumanMightConsiderBoolean.isBoolean());
		This will return true.
	*/
	var value = null;
	if (this.isBoolean((negativeIs != null))){
		if (this.is("true","on","yes") || (parseInt(this) > 0) || (negativeIs && parseInt(this) < 0))value = true;
		if (this.is("false","off","no") || (parseInt(this) == 0) || (negativeIs == false && parseInt(this) < 0))value = false;
	}
	return value;
};
String.prototype.is = function(){
	/*
	Parameters:
		string,[string]... - A list of strings.
	Purpose:
		To check whether a string is equal to any one of the arguments passed.
	Returns:
		Boolean, true if the string is equal to one of the arguments, false if not.
	Usage:
		var myName = "Shawn";
		alert(myName.is("Mark","Kirk","Jason","Shawn"));
		This would return true, because myName is Shawn.
	*/
	for (var i=0; i<arguments.length; i++){
		if (arguments[i] == this){
			return true;
		}
	}
	return false;
};
String.prototype.isUpper = function(index){
	/*
	Parameters:
		index (integer) - A zero based index, from 0 to length of string-1.
	Purpose:
		Quickly check if the character at the specified index in the string is a capital letter or not.
	Returns:
		Boolean
	Usage:
		alert("ABcD".isUpper(2));
		This would return false, because c is not a capital letter.
	*/
	var str = (index == null ? this : this.charAt(index));
	return (str == str.toUpperCase());
};
String.prototype.isAmong = function(strings){
	/*
	Parameters:
		This method can be passed either a list, array, or any number of strings.
	Purpose:
		Quickly check if the string or character is equal to any one of the strings or characters passed as parameters.
	Returns:
		Boolean
	Usage:
		var myName = "Shawn";
		var result = myName.isAmong("Mark,Kirk,Jason,Shawn");				(passing a comma separated list; you could also specify a second argument which would change the delimiter).
		OR
		var result = myName.isAmong("Mark","Kirk","Jason","Shawn");		(passing an array of string arguments)
		OR
		var result = myName.isAmong(["Mark","Kirk","Jason","Shawn"]);	(passing an array as a single argument)
		alert(result);
		This would return true, because Shawn is present in the list: Mark, Kirk, Jason, Shawn.
	*/
	strings = makeArray(arguments);
	for (var i=0; i<strings.length; i++){
		if (this == strings[i]){
			return true;
		}
	}
	return false;
};
String.prototype.count = function(subStr,start,end,useCount,regex,caseSensitive){
	/*
	Parameters:
		subStr (string) - String or character to find in the string.
		start (integer) - Starting location of the string to begin counting. Default 0.
		end (integer) - Ending location of the string to stop counting; or number of characters after start to stop counting. Default end of string.
		useCount (boolean) - If true, the third argument is a count of the number of characters from the start; if false the third argument is the last position in the string to include in counting. Default is false.
		regex (boolean) - Specifies whether or not subStr is a regular expression. Default false.
		caseSensitive (boolean) - Specifies whether the character counting is case sensitive. Default is false.
	Purpose:
		Use this method to count how many occurances of subStr there are in the string.
	Returns:
		An integer; the number of occurances found.
	Usage:
		var myString = "Hello world";
		alert(myString.count("l"));
		This would return 3, because there are two l's in the string.
	*/
	start = (start == null ? 0 : start);
	end = $getEndPoint(this.length,start,end,useCount);
	var str = this.substring(start,end);
	if (regex != null)regex = regex.toBoolean();
	if (subStr.type() == "regexp"){
	   caseSensitive = (caseSensitive == null ? false : !subStr.ignoreCase);
		flags = "g";
	   flags += (caseSensitive ? "i" : "");
		if (regex == false)subStr = (!caseSensitive ? subStr.source.toLowerCase() : subStr.source);
		else{
			regex = true;
			if (!subStr.global)subStr = new RegExp(subStr.source,flags); //If we don't make sure the global property is true, we could have an infinite loop.
		}
	}
	else{
		flags = "g";
	   flags += (caseSensitive ? "i" : "");
		try{
			if (regex)subStr = new RegExp(subStr,flags);
		}
		catch (e){
			Object.error("Could not create regular expression from: "+subStr+", using flags: "+flags);
		};
	}
	var value = 0;
	if (!caseSensitive)str = str.toLowerCase();
	if (regex){
		do{
			var result = subStr.exec(str);
			if (result != null)value++;
		} while(result != null);
	}
	else{
		var pos = -1;
		do{
			pos = str.indexOf(subStr);
			if (pos > -1){
				str = str.substr(pos+subStr.length);
				value++;
			}
		} while (pos > -1);
	}
	return value;
};

//Nondeterministic functions
String.prototype.toEnum = function(inner,outer,trim){
	/*
	Parameters:
		inner (string) - The inner delimiter to use. Default is =.
		outer (string) - The outer delimiter to use. Default is ,.
		trim (boolean) - Whether or not to trim each item.
	Purpose:
		Convert a string to enumerator.
	Returns:
		A new Enum object, with the keys and values of the string.
	Usage:
		var myString = "id=1&name=Shawn";
		var myEnum = myString.toEnum();
		This would convert the string into an Enum object.
	Notes:
		The string to convert must contain two types of delimiters (like a URL).
		You could also create a new Enum object, using the Enum's constructor.
			Ex: var myEnum = new Enum(myString);
	*/
	var e = new Enum();
	inner = (inner == null ? "=" : inner);
	outer = (outer == null ? "," : outer);
	trim = (trim == null ? true : trim);
	if (this.length > 0){
		var pairs = this.split(outer);
		for (var i=0; i<pairs.length; i++){
			if (pairs[i].length > 0){
				var name = pairs[i].split(inner)[0];
				var value = pairs[i].split(inner)[1];
				if (name != null && value != null && name.length > 0){
					if (trim){
						name = name.trim();
						value = value.trim();
					}
					e.add(name,value);
				}
			}
		}
	};
	return e;
};
String.prototype.lTrim = function(str){
	/*
	Parameters:
		str (variant) - The string or regular expression to trim. Default is space.
	Purpose:
		Removes all occurances of str to the left of the string.
	Returns:
		The string with str removed from the left.
	*/
	str = (str == null ? /^\s+/ : str);
	// If str is a regular expression, we need to make sure it will only affect the left of the string.
	if (str.type() == "regexp"){
		if (str.source.charAt(0) != "^" || str.source.charAt(str.length-1) == "$" || str.global){
			var flags = (str.ignoreCase ? "i" : "");
			var source = (str.source.charAt(0) != "^" ? "^"+str.source : str.source);
			source = (source.charAt(str.length-1) == "$" ? source.substring(0,source.length-1) : source);
			str = new RegExp(source,flags);
		}
	}
	else str = new RegExp("^"+str+"+","i");
	return this.replace(str,"");
};
String.prototype.rTrim = function(str){
	/*
	Parameters:
		str (variant) - The string or regular expression to trim. Default is space.
	Purpose:
		Removes all occurances of str on the right of the string.
	Returns:
		The string with str removed from the right.
	*/
	str = (str == null ? /^\s+/ : str);
	// If str is a regular expression, we need to make sure it will only affect the right of the string.
	if (str.type() == "regexp"){
		if (str.source.charAt(str.length-1) != "$" || str.source.charAt(0) == "^" || str.global){
			var flags = (str.ignoreCase ? "i" : "");
			var source = (str.source.charAt(str.length-1) != "$" ? str.source+"$" : str.source);
			source = (source.charAt(0) == "^" ? source.substr(1) : source);
			str = new RegExp(source,flags);
		}
	}
	else str = new RegExp(str+"+$","i");
	return this.replace(str,"");
};
String.prototype.trim = function(str){
   /*
	Parameters:
		str (variant) - The string or regular expression to trim. Default is space.
	Purpose:
		Removes all occurances of str from the left and right of the string.
	Returns:
		The string with str removed from both left and right.
	*/
	var rStr = this;
	rStr = rStr.lTrim(str);
	rStr = rStr.rTrim(str);
	return rStr;
};
String.prototype.remove = function(start,end,useCount){
	/*
	Parameters:
		start (integer) - Specifies the index at which to begin removing characters.
		end (integer) - Ending location or the count of characters after start to remove.
		useCount (boolean) - If true, the second argument is a count of the number of characters to include in the process. If false, the second argument is the last character of the string to remove. Default is false.
	Purpose:
		Remove a consequetive number of characters from a string.
	Returns:
		A string with the specified characters removed.
	Usage:
		var myString = "Shawn is a good programmer.";
		alert(myString.remove(11,5,true));
		This would alert: "Shawn is a programmer.";
	*/
	start = (start == null ? 0 : start);
	end = $getEndPoint(this.length,start,end,useCount);
	return this.substring(0,start)+this.substr(end);
};
String.prototype.insert = function(str,index){
	/*
	Parameters:
		str (string) - The string to be inserted.
		index (integer) - The position at which to insert the specified string. Default is end of string.
	Purpose:
		Used to insert a new string into the specified position of another string.
	Returns:
		A new string with the string passed inserted at the specified location.
	Usage:
		var myString = "Shawn is a programmer.";
		alert(myString.insert("good ",11));
		This would alert the string: "Shawn is a good programmer.";
	*/
	index = (index == null ? str.length : index);
	return this.substring(0,index)+str+this.substr(index);
};
String.prototype.contains = function(){
	/*
	Parameters: (Any of the parameters can be specified multiple times, and can vary by type).
		(variant) - Either of type: List, String, or Array.
			List - This is a list object (one dimensional) which is a list of strings to search for.
			String - This is a string object to search for.
			Array - This is an array of strings to search for.
	Purpose:
		Quickly determine if the string passed is contained in the string the method is run against.
	Returns:
		Boolean.
	*/
	var value = false;
	for (var i=0; i<arguments.length; i++){
		switch (arguments[i].type()){
			case "number":
			case "string":
				value = (value || (this.indexOf(arguments[i]) > -1));
				break;
			case "array":
				for (var z=0; z<arguments[i].length; z++){
					value = (value || (this.indexOf(arguments[i][z]) > -1));
				}
				break;
			case "list":
				alert("its a list");
				break;
		}
	}
	return value;
};
String.prototype.toMD5 = function(){
	/*
	Purpose:
		Use this method to convert a string to an MD5 hash.
	Notes:
		I did not write this method. I just took a static JavaScript function and added to the String prototype.
		The credit of this function goes to a former coworker; Heath Provost.
	*/
	var str2blks_MD5 = function(str){
		nblk = ((str.length + 8) >> 6) + 1;
		blks = new Array(nblk * 16);
		for(i = 0; i < nblk * 16; i++){
			blks[i] = 0;
		}
		for(i = 0; i < str.length; i++){
		blks[i >> 2] |= str.charCodeAt(i) << ((i % 4) * 8);
		}
		blks[i >> 2] |= 0x80 << ((i % 4) * 8);
		blks[nblk * 16 - 2] = str.length * 8;
		return blks;
	};
	var rhex = function(num){
		var hex_chr = "0123456789abcdef";
		str = "";
		for(j = 0; j <= 3; j++){
			str += hex_chr.charAt((num >> (j * 8 + 4)) & 0x0F)+hex_chr.charAt((num >> (j * 8)) & 0x0F);
		}
		return str;
	};
	var add = function(x, y){
		var lsw = (x & 0xFFFF) + (y & 0xFFFF);
		var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
		return (msw << 16) | (lsw & 0xFFFF);
	};
	var rol = function(num, cnt){
		return (num << cnt) | (num >>> (32 - cnt));
	};
	var cmn = function(q, a, b, x, s, t){
		return add(rol(add(add(a, q), add(x, t)), s), b);
	};
	var ff = function(a, b, c, d, x, s, t){
		return cmn((b & c) | ((~b) & d), a, b, x, s, t);
	};
	var gg = function(a, b, c, d, x, s, t){
		return cmn((b & d) | (c & (~d)), a, b, x, s, t);
	};
	var hh = function(a, b, c, d, x, s, t){
		return cmn(b ^ c ^ d, a, b, x, s, t);
	};
	var ii = function(a, b, c, d, x, s, t){
		return cmn(c ^ (b | (~d)), a, b, x, s, t);
	};
	x = str2blks_MD5(this);
	a =  1732584193;
	b = -271733879;
	c = -1732584194;
	d =  271733878;

	for(i = 0; i < x.length; i += 16){
		olda = a;
		oldb = b;
		oldc = c;
		oldd = d;
		a = ff(a, b, c, d, x[i+ 0], 7 , -680876936);
		d = ff(d, a, b, c, x[i+ 1], 12, -389564586);
		c = ff(c, d, a, b, x[i+ 2], 17,  606105819);
		b = ff(b, c, d, a, x[i+ 3], 22, -1044525330);
		a = ff(a, b, c, d, x[i+ 4], 7 , -176418897);
		d = ff(d, a, b, c, x[i+ 5], 12,  1200080426);
		c = ff(c, d, a, b, x[i+ 6], 17, -1473231341);
		b = ff(b, c, d, a, x[i+ 7], 22, -45705983);
		a = ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
		d = ff(d, a, b, c, x[i+ 9], 12, -1958414417);
		c = ff(c, d, a, b, x[i+10], 17, -42063);
		b = ff(b, c, d, a, x[i+11], 22, -1990404162);
		a = ff(a, b, c, d, x[i+12], 7 ,  1804603682);
		d = ff(d, a, b, c, x[i+13], 12, -40341101);
		c = ff(c, d, a, b, x[i+14], 17, -1502002290);
		b = ff(b, c, d, a, x[i+15], 22,  1236535329);    
		a = gg(a, b, c, d, x[i+ 1], 5 , -165796510);
		d = gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
		c = gg(c, d, a, b, x[i+11], 14,  643717713);
		b = gg(b, c, d, a, x[i+ 0], 20, -373897302);
		a = gg(a, b, c, d, x[i+ 5], 5 , -701558691);
		d = gg(d, a, b, c, x[i+10], 9 ,  38016083);
		c = gg(c, d, a, b, x[i+15], 14, -660478335);
		b = gg(b, c, d, a, x[i+ 4], 20, -405537848);
		a = gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
		d = gg(d, a, b, c, x[i+14], 9 , -1019803690);
		c = gg(c, d, a, b, x[i+ 3], 14, -187363961);
		b = gg(b, c, d, a, x[i+ 8], 20,  1163531501);
		a = gg(a, b, c, d, x[i+13], 5 , -1444681467);
		d = gg(d, a, b, c, x[i+ 2], 9 , -51403784);
		c = gg(c, d, a, b, x[i+ 7], 14,  1735328473);
		b = gg(b, c, d, a, x[i+12], 20, -1926607734);
		a = hh(a, b, c, d, x[i+ 5], 4 , -378558);
		d = hh(d, a, b, c, x[i+ 8], 11, -2022574463);
		c = hh(c, d, a, b, x[i+11], 16,  1839030562);
		b = hh(b, c, d, a, x[i+14], 23, -35309556);
		a = hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
		d = hh(d, a, b, c, x[i+ 4], 11,  1272893353);
		c = hh(c, d, a, b, x[i+ 7], 16, -155497632);
		b = hh(b, c, d, a, x[i+10], 23, -1094730640);
		a = hh(a, b, c, d, x[i+13], 4 ,  681279174);
		d = hh(d, a, b, c, x[i+ 0], 11, -358537222);
		c = hh(c, d, a, b, x[i+ 3], 16, -722521979);
		b = hh(b, c, d, a, x[i+ 6], 23,  76029189);
		a = hh(a, b, c, d, x[i+ 9], 4 , -640364487);
		d = hh(d, a, b, c, x[i+12], 11, -421815835);
		c = hh(c, d, a, b, x[i+15], 16,  530742520);
		b = hh(b, c, d, a, x[i+ 2], 23, -995338651);
		a = ii(a, b, c, d, x[i+ 0], 6 , -198630844);
		d = ii(d, a, b, c, x[i+ 7], 10,  1126891415);
		c = ii(c, d, a, b, x[i+14], 15, -1416354905);
		b = ii(b, c, d, a, x[i+ 5], 21, -57434055);
		a = ii(a, b, c, d, x[i+12], 6 ,  1700485571);
		d = ii(d, a, b, c, x[i+ 3], 10, -1894986606);
		c = ii(c, d, a, b, x[i+10], 15, -1051523);
		b = ii(b, c, d, a, x[i+ 1], 21, -2054922799);
		a = ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
		d = ii(d, a, b, c, x[i+15], 10, -30611744);
		c = ii(c, d, a, b, x[i+ 6], 15, -1560198380);
		b = ii(b, c, d, a, x[i+13], 21,  1309151649);
		a = ii(a, b, c, d, x[i+ 4], 6 , -145523070);
		d = ii(d, a, b, c, x[i+11], 10, -1120210379);
		c = ii(c, d, a, b, x[i+ 2], 15,  718787259);
		b = ii(b, c, d, a, x[i+ 9], 21, -343485551);
		a = add(a, olda);
		b = add(b, oldb);
		c = add(c, oldc);
		d = add(d, oldd);
	};
	return rhex(a) + rhex(b) + rhex(c) + rhex(d);
};
String.prototype.repeat = function(count){
	/*
	Parameters:
		count (integer) - How many times to repeat the string.
	Purpose:
		Repeats the string however many times it is told to do so.
	Returns:
		A repeated string.
	*/
	var str = "";
	for (var i=0; i<count; i++){
		str += this;
	}
	return str;
};
String.prototype.escape = function(){
	/*
	Parameters: You may pass as many parameters as necessary.
		(string) - A string which identifies the method of escaping to use. Valid options are:
			regexp - Will escape regular expression matches.
			tags - Will escape HTML tags.
	TODO:
		Add escape special characters in html.
	*/
	var value = this;
	for (var i=0; i<arguments.length; i++){
		switch (arguments[i]){
			case "regexp":
				value = value.replace(/([\.\*\+\{\}\(\)\<\>\^\$\\])/g,"\\$1");
				break;
			case "tags":
				value = value.replace(/<(.+?)>/g,"&lt;$1&gt;");
				break;
		}
	}
	return value;
};
String.prototype.toBase = function(base,fromBase){
   /*
	Parameters:
		base (variant) - This is the base to convert to.
			integer - A number between 2 and 16 to convert the string or number to.
			string - A set of characters to use as numerals in the base. This set of characters must be at least 2, but can be as many as you need.
		fromBase (variant) - This is the base to convert from. Default is 10.
			integer - A number between 2 and 16, which represents what base the current number or string is in.
			string - A set of characters which represents the numerals of the base which the current number or string is in.
	Purpose:
		Use this method to convert any number or string from one base to another.
		This is especially useful if you must do some mathematically operation on a hex number. You can convert to base 10, do your math, then convert back to base 16.
	Returns:
		If the base to convert to is 10, the returned value will be a Number; otherwise it will be a string which holds the numerical representation of the number in the base of which it was converted.
	Usage:
		var myAge = 27;
		alert(myAge.toBase(16));
		This would alert 1B. (my age in Base16).
		
		var myAge = "1B";
		alert(myAge.toBase(2,16));
		This would alert 11011. (my age converted from Base16 to Base2).
		
		var myAge = 11011;
		alert(myAge.toBase("ABCDEFGHIJKLMNOPQRSTUVWXYZ",2));
		This would alert BB.  (my age converted from Base2 to a Base26 (using the capitals of the english alphabet for numerals).
	Notes:
		This method is not limited to converting positive integers, you can passed negative values and decimal values; it will convert anything.
	*/
	var rv = "";
	fromBase = (fromBase == null ? 10 : fromBase);
	var toNumerals = "0123456789ABCDEF";
	var fromNumerals = "0123456789ABCDEF";
	if (fromBase.constructor == String){
		fromNumerals = fromBase;
		fromBase = fromBase.length;
	}
	if (base.constructor == String){
		toNumerals = base;
		base = base.length;
	}
	if (fromBase > 1 && base > 1){
		var result = power = value = 0;
		var number = new String(this);
		var sign = (number.indexOf("-") > -1 ? -1 : 1);
		number = (number.indexOf("-") > -1 ? number.substr(1) : number);
		var integer = (number.indexOf(".") > -1 ? (number.indexOf(".") > 0 ? number.substring(0,number.indexOf(".")) : 0) : number);
		var decimal = (number.indexOf(".") > -1 ? number.substr(number.indexOf(".")+1) : 0);
		if (sign < 0)rv = "-";
		for (var i=0; i<integer.length; i++){
			power = (integer.length-i)-1;
			value = fromNumerals.indexOf(integer.charAt(i))*(Math.pow(fromBase,power));
			result += value;
		}
		if (result > 0){
			var i = j = 0;
			while (result >= Math.pow(base,(i+1))){
				i++;
			}
			while (result > 0){
				while (result >= ((j+1)*Math.pow(base,i))){
					j++;
				}
				result = result - (j)*Math.pow(base,i);
				rv += toNumerals.charAt(j);
				i--;
				j = 0;
			}
			for (j=i; j>=0; j--){
				rv += "0";
			}
		}
		result = value = 0;
		value = 0;
		for (var i=0; i<decimal.length; i++){
			power = (i+1)*-1;
			value += fromNumerals.indexOf(decimal.charAt(i))*(Math.pow(fromBase,power));
		}
		if (value > 0){
			rv += ".";
			while ((result = value*base) > 0){
				rv += toNumerals.charAt(Math.floor(result));
				value = result-Math.floor(result);
				if (rv.substr(rv.indexOf(".")).length > base){
					value = 0;
				}
			}
		}
	}
	else rv = this;
	return (base == 10 ? new Number(rv) : rv);
};
String.prototype.round = function(step,decimals,precision){
	/*
	This is a helper method for Number.round, it converts the string to a number and calls the round method.
	*/
	var value = parseFloat(this);
	return (value.type() == "number" ? value.round(step,decimals,precision) : this);
};

//Number methods
Number.prototype.toBase = function(base,fromBase){
	/*
	Notes:
		Converts the number to a string, then calls the String's toBase method.
	*/
	fromBase = (fromBase == null ? 10 : fromBase);
	var str = this.toString();
	return str.toBase(base,fromBase);
}
Number.prototype.isBoolean = function(useNegative){
	/*
	Parameters:
		useNegative (boolean) - If true, then negative numbers are considered as a boolean value. Default is false.
	Purpose:
		Check if a string is a boolean value (fuzzy).
	Returns:
		Boolean, true if the string can be interpreted as a boolean value; false if it cannot.
	Usage:
		var whatAHumanMightConsiderBoolean = "yes";
		alert(whatAHumanMightConsiderBoolean.isBoolean());
		This will return true.
	*/
	var value = null;
	if (this > 0 || useNegative)value = true;
	else value = false;
	return value;
}
Number.prototype.toBoolean = function(negativeIs){
	/*
	Parameters:
		negativeIs (boolean) - If negative is to be considered boolean, it is either false or true. Default is null. (not considered).
	Purpose:
		If the string can be converted to a Boolean it returns it; otherwise null is returned.
	Returns:
		Boolean,
			Returns true if the string is equal to the words "true", "on", "yes" or if the string is a number greater than 0.
			Returns false if the string is equal to the words "false", "off", "no" or if the string is a number equal to 0.
			Otherwise it will return null.
	Usage:
		var whatAHumanMightConsiderBoolean = "yes";
		alert(whatAHumanMightConsiderBoolean.isBoolean());
		This will return true.
	*/
	var value = null;
	if (this.isBoolean((negativeIs != null))){
		if (this > 0 || (negativeIs && this != 0))value = true;
		if (this == 0 || (negativeIs == false && this < 0))value = false;
	}
	return value;
};
Number.prototype.round = function(step,decimals,precision){
	/*
	Parameters:
		step (number) - The stepping block for the number to be rounded. Default is 1.
		decimals (integer) - The maximum number of decimal places to leave on the end of the number. Default is 0.
		precision (number) - The percentage point (represented in decimal format) at which to round the number up to the next step. Default is .5
	Purpose:
		This function replaces the Math.round; and gives you more control over how the rounding should behave.
	Returns:
		A number.
	Usage:
		var myNumber = 6;
		var rounded = myNumber.round();
		The result is 6.
		
		var myNumber = 6.7;
		var rounded = myNumber.round();
		The result is 7;
		
		For a more dynamic round, you may wish to round to the nearest 15 minutes of time.
		var myNumber = 7;
		var rounded = myNumber.round(15);
		This will result in 15. Because it will take any number which is >= 50% of 15, and round it to the nearest 15.
	*/
	step = (step == null ? 1 : step);
	decimals = (decimals == null ? 0 : decimals);
	precision = (precision == null ? .5 : precision);
	var value = this*Math.pow(10,decimals);
	var currentStep = Math.ceil(value/step);
	var upper = (step*precision)+(step*(currentStep-1));
	if (value >= upper)value = (step*currentStep);
	else value = ((step*currentStep)-step);
	return value/Math.pow(10,decimals);
};
Number.prototype.format = function(mask){
	/*
	Parameters:
		mask (string) - The number mask to use for the new formatting. Default is 
	Purpose:
		This function will format a number into any specified format.
	Returns:
		A string or number, depending on if the returned format includes only digits or a mix of digits and characters.
	Usage:
		var myNumber = 29301;
		myNumber.format();
		The result is 29,301;
		
	*/
	return this.toLocaleString();
};

//Array methods
Array.whatif = false;
/*
	whatif - If this is true, all manipulative methods which would normally manipulate the array return a new array object with the modifications made, instead of manipulating the original array.
		Note: This ONLY has an affect for functions written in this method (built-in array methods still act as they always have)
		Explaination of whatif property.
		This property is only on the array object; and it is here for something of a standards compliancy. Since the Array object has some methods which manipulate the array, and not return anything.
*/
Array.prototype.copy = function(){
	/*
	Purpose:
		Use this method to return a copy of the array.
	Returns:
		A copy of the array.
	*/
	var value = new Array();
	for (var i=0; i<this.length; i++)value[value.length] = this[i];
	return value;
}
Array.prototype.swap = function(index,pos){//This is a manipulative method
	/*
	Parameters:
		index (integer) - The index to swap with pos.
		pos (integer) - The position in the array to swap index with.
	Purpose:
		Use this method to swap to indexes in an array with each other.
	Returns:
		An array with the indexes swapped.
	*/
	pos = (pos == null ? this.length-1 : pos);
	var manipulate = (this.whatif ? this.copy() : this);
	var save = manipulate[pos];
	manipulate[pos] = manipulate[index];
	manipulate[index] = save;
	return manipulate;
};
Array.prototype.first = function(){
	/*	Returns: The first element in the array; just another way of writing myArray[0] */
	return this[0];
};
Array.prototype.last = function(){
	/* Returns: The last element in the array; just another way of writing myArray[myArray.length-1] */
	return this[this.length-1];
};
Array.prototype.doUntilTrue = function(exec){
	/*
	Parameters:
		exec (function) - A Function to be called, with each iteration of the array. (This function is passed the array's value and index at this iteration)
			Example of function....
				function doSomething(value,index){
					alert("Value: "+value+" at "+index);
				};
	Purpose:
		Use this method to test the values in the array against a function, which would return true or false.
	Returns:
		True, if one of the values in the array resulted in the function returning true; false if none of the values returns true.
	Usage:
		If we have a function that accepts a string and tests it against a regular expression; we could use this method like so.
			function testString(str){
				var re = /\d-\d\d/g; //We are testing whatever string is passed for n-nn (where n is any number)
				return re.test(str);
			}
			var myArray = new Array();
			myArray[myArray.length] = "1-8";
			myArray[myArray.length] = "1-9";
			myArray[myArray.length] = "1-10";
			
			alert(myArray.doUntilTrue(testString));
			This would return true, because at the last element in the array we have a match to our expression used in testString.
	*/
	var value = false;
	for (var i=0; i<this.length; i++){
		value = (value || exec(this[i],i));
	}
	return value;
};
Array.prototype.insert = function(){
	/*
	Parameters:
		value (variant) - The value to insert.	Multiple values can be passed to the method.
		index (integer) - The index at which to insert the value.
			If multiple values are passed, this argument must be passed as well; use -1 for end of array.
			If inserting only one value, this argument is not required, and defaults to the end of the array.
	Purpose:
		Use this method to insert values at any position into an array.
	Returns:
		An array with the values inserted starting at index.
	Usage:
		myArray.insert("new value"); //Would insert "new value" into that last position in the array.
		myArray.insert("one","two","three",-1); //Would insert the words: one, two, and three in that order at the end of the array.
	Notes:
		This method respects whatif; If whatif is true, then the array this method is called on is not manipulated.
	*/
	var manipulate = (this.whatif ? this.copy() : this);
	index = (arguments.length < 2 ? manipulate.length : arguments[arguments.length-1]);
	if (index < 0)index = manipulate.length;
	var left = manipulate.slice(0,index);
	for (var i=0; i<index; i++)manipulate.shift();
	for (var i=0; i<arguments.length-1; i++)manipulate.unshift(arguments[i]);
	for (var i=left.length-1; i>=0; i--)manipulate.unshift(left[i]);
	return manipulate;
};
Array.prototype.removeIndex = function(){
	/*
	Parameters:
		index (variant) - The index or array of indexes to remove. You may specify this parameter as many times as needed.
	Purpose:
		To delete specific indexes of an Array object
	Returns:
		An array, with specified indexes removed.
	Usage:
		var myArray = ["Mark","Kirk","Jason","Shawn"];
		alert(myArray.remove(0,2));
		This would alert a new array with only two elements: "Kirk","Shawn"
	*/
	var save = null;
	var value = (this.whatif ? this.copy() : this);
	var args = [];
	for (var i=0; i<arguments.length; i++){
		if (arguments[i].type() == "array"){
			for (var z=0; z<arguments[i].length; z++)args[args.length] = arguments[i][z];
		}
		else args[args.length] = arguments[i];
	};
	args.sort();
	for (var i=0; i<args.length; i++){
		var index = args[i];
		for (var z=index-i; z<value.length; z++){
			if (z+1 < value.length){
				save = value[z];
				value[z] = value[z+1];
				value[z+1] = save;
			}
			else value.pop();
		};
	};
	return value;
};
Array.prototype.remove = function(start,end,useCount){
	/*
	Parameters:
		start (integer) - Specifies the index at which to begin removing elements.
		end (integer) - Specifies the number of elements to remove or the last element to include in the removing process. Default to end of array.
			Whether being used as count or end, if this value is beyond the array length; it will only remove up to and including the last element of the array.
		useCount (boolean) - If true, the second argument is a count of the number of elements to include in the process. If false, the second argument is the last element of the array to remove. Default is false.
	Purpose:
		Remove a consequetive number of elements from an array.
	Returns:
		An array with the specified elements removed.
	Usage:
		var myArray = ["Mark","Kirk","Jason","Shawn"];
		alert(myArray.remove(2));
		This would alert an array with 2 elements: "Mark","Kirk"
		
		alert(myArray.remove(0,2));
		This would alert an array with 1 element: "Shawn"
		
		alert(myArray.remove(0,2,true));
		This would alert an array with 2 elements: "Jason","Shawn"
	*/
	start = (start == null ? 0 : start);
	end = $getEndPoint(this.length,start,end,useCount);
	var value = (this.whatif ? this.copy() : this);
	for (var i=start; i<end; i++)value = value.removeIndex(start);
	return value;
};
Array.prototype.merge = function(start,end,useCount,delimiter){
	/*
	Parameters:
		start (integer) - The first index to include in the merging process.
		end (integer) - The last index to include in the merging process or the number of elements to merge. Default is to end of array.
			Whether being used as count or end, if this value is beyond the array length; it will only merge up to and including the last element of the array.
		useCount (boolean) - Whether or not the second argument is used as the last index of the array to merge or if it is the number of elements to merge. Default is false
	Purpose:
		This method will take the specified elements in an array, and concatenate them all together as one element in the array.
		The concatenated element will be at the start index.
	Returns:
		An array with elements from start to end concatenated.
	Usage:
		var myArray = ["Mark","Kirk","Jason","Shawn"];
		alert(myArray.merge(1,2));
		Would alert a new array with three elements: Mark,KirkJason,Shawn
	*/
	start = (start == null ? 0 : start);
	end = $getEndPoint(this.length,start,end,useCount);
	delimiter = (delimiter == null ? "" : delimiter);
	var con = "";
	var value = (this.whatif ? this.copy() : this);
	for (var i=start; i<end; i++)con += this[i]+(i<end ? delimiter : "");
	value = value.remove(start,end-1);
	value[start] = con;
	return value;
};
Array.prototype.find = function(value,start,end,useCount,useRegExp){
	/*
	Parameters:
		value (variant) - Value to search the array for. Can be a regular expression.
		start (integer) - Limit the searching to everything including and after this index.
		end (integer) - Limit the search to everything including and before this index. Or to a count of indexes after start.
		useCount (boolean) - Specifies whether or not end is the last index to limit search, or if it is used as a count. Default is false.
		useRegExp (boolean) - Specifies whether or not value will be used as a regular expression searched against a string if the index is a string. Default false.
	Purpose:
		Use this method to find values in an array.
	Returns:
		An array of all matching indexes in the array. If no matches are found, it returns a zero length array.
	Usage:
		var myArray = ["Mark","Kirk","Jason","Shawn"];
		alert(myArray.find("Mark"));
		This would return a new array with one element, with a value of 0.
		
		alert(myArray.find(/a/i));
		This would return a new array with three elements, with values of 0, 2, and 3.
	*/
	start = (start == null ? 0 : start);
	end = $getEndPoint(this.length,start,end,useCount);
	useRegExp = (useRegExp == null ? false : useRegExp);
	var array = [];
	var flags;
	for (var i=start; i<end; i++){
		if (value.type() == "regexp" && (this[i].type() == "string" || this[i].type() == "number") && useRegExp){
			if (value.test(this[i]))array[array.length] = i;
		}
		else{
			if (this[i] == value)array[array.length] = i;
		}
	}
	return array;
};
Array.prototype.flatten = function(start,end,useCount,depth){
	/*
	Parameters:
		start (integer) - Limit the flattening to everything including and after this index.
		end (integer) - Limit the flattening to everything including and before this index. Or to a count of indexes after start.
		useCount (boolean) - Specifies whether or not end is the last index to limit flatten, or if it is used as a count. Default is false.
		depth (integer) - Limit the depth to recursively look into the array. Default is unlimited.
	Purpose:
		This method will recursively loop through an array, if any element is an array, it is removed and added to the top level array.
	Returns:
		A flattened array.
	Notes:
		This method will respect the whatif property.
	Usage:
		var myArray = new Array(1,2,3,[4,5,6,7],[8,9],0);
		myArray.flatten();
		This would return the new array: 1,2,3,4,5,6,7,8,9,0
	*/
	start = (start == null ? 0 : start);
	end = $getEndPoint(this.length,start,end,useCount);
	depth = (depth == null ? -1 : depth);
	manipulate = (this.whatif ? this.copy() : this);
	var depthCounter = 0;
	var portion = manipulate.slice(start,end);
	var makeFlat = function(array){
		var rArray = [];
		for (var i=0; i<array.length; i++){
			if (array[i].type() == "array" && (depthCounter < depth || depth == -1)){
				rArray = rArray.concat(makeFlat(array[i]));
				depthCounter++;
			}
			else rArray[rArray.length] = array[i];
		}
		return rArray;
	}
	return manipulate.replace(makeFlat(portion),start,end);
};
Array.prototype.replace = function(array,start,end,useCount,grow){
	/*
	Parameters:
		array (Array) - Place all the elements from passed array into this array.
		start (integer) - Index at which to begin replacing elements of the array. Default is beginning of array.
		end (integer) - Last index in the array to replace. Default is end of array.
		useCount (boolean) - Specifies whether end is the last element in the array to replace, or if end is used as a count from start. Default is false.
		grow (boolean) - Specifies whether this array is allowed to grow past the number of elements which are currently in it. Default is true.
	Purpose:
		Will replace a section of elements in the array with elements from the array that is passed.
	Returns:
		A new array with the elements from the array passed placed into the section replaced.
	Notes:
		This method respects the whatif property.
	Usage:
		var myArray = new Array("Mark","Kirk","Jason","Shawn");
		to replace Kirk and Jason with Micah, Brad, and John.....
			myArray.replace(["Micah","Brad","John"],1,2);
			This would create a new array that looks like: Mark,Micah,Brad,John,Shawn.
		to replace Kirk and Jason with Micah, Brad, and John (but not allow the array to grow).
			myArray.replace(["Micah","Brad","John"],1,2,false,true);
			This would create a new array that looks like: Mark,Micah,Brad,Shawn. Notice, it is only four elements as it was before (it wasn't allowed to grow).
	*/
	var manipulate = (this.whatif ? this.copy() : this);
	start = (start == null ? 0 : start);
	grow = (grow == null ? true : grow);
	end = $getEndPoint(manipulate.length,start,end,useCount);
	if (manipulate.length-(end-start) < array.length && !grow)array = array.slice(0,(end-start));
	manipulate.remove(start,end);
	for (var i=array.length-1; i>=0; i--)manipulate.insert(array[i],start);
	return manipulate;
};

//Enum Object -- Note this is NOT the Enumerator object available in IE; but it is basically an enumeration object.
function Enum(){
	/*
	TODO:
	Add parameters to constructor to allow building an enum object on the fly;
		pass and even number of arguments (which will be treated as name,value pairs): "name","value","name","value","name","value"
		or pairs of elements "name=value","name=value","name=value";
		or pass a 2D complex List object.
		or pass an Enum object, to inherit from.
	*/
	/* Declare private variables */
	var _valueArray = [];
	var _keyArray = [];
	var position = -1;
	
	/* Public properties */
	this.length = 0;
	this.atEnd = false;
	
	/* Public methods */
	this.add = function(key,value,replace,index){
		/*
		Parameters:
			key (string) - The key part of the item to be inserted.
			value (variant) - The value of an item to insert; this can be a string, or any other object.
			replace (boolean) - If true, it will replace the value of key if key already exists. Default is true.
			index (integer) - The position in the Enum object to insert this key,value pair. Default is End of Enum.
				This only has an effect if the key is being inserted, if the key already exists in the Enum and is being replaced it has no effect.
		Purpose:
			Use this method to add an item to the Enum object.
		Returns:
			True if successful insertion, false if not. An insertion may fail if replace is false, and the name already exists.
		Usage:
			var myEnum.add("Shawn","programmer");
		*/
		replace = (replace == null ? true : replace);
		index = (index == null ? -1 : index);
		var success = null;
		if (key.type() != "string")Enum.error("Enum add(): Key passed is not a string, it is a "+key.type()+". The key must be a string.");
		if (!this.keyExists(key) || (this.keyExists(key) && replace)){
			var pos = this.findIndexes(key);
			if (pos.length > 0)pos = pos[0];
			else pos = -1;
			if (pos > -1)_valueArray[pos] = value;
			else{
				_keyArray.insert(key,index);
				_valueArray.insert(value,index);
				this.length++;
			};
			success = true;
		}
		else{
			success = false;
		};
		return success;
	};
	this.keyExists = function(key,caseSensitive){
		/*
		Parameters:
			key (variant) - Key to search for in Enum. The key can be a regular expression.
			caseSensitive (boolean) - Whether or not to use case sensitive match. Default is true.
		Purpose:
			Use to determine if a key exists in the Enum object.
		Returns:
			Boolean; true if the key was found; otherwise false.
		Usage:
			alert(myEnum.keyExists("Shawn"));
			Would return true if myEnum has an item with a name of Shawn.
		*/
		caseSensitive = (caseSensitive == null ? true : caseSensitive);
		if (!caseSensitive)key = new RegExp("^"+key.escape("regexp")+"$","i");
		return (_keyArray.find(key,0,-1,false,true).length > 0);
	};
	this.findKey = function(value){
		/*
		Parameters:
			(variant) - A value to search for within the Enum object.
		Purpose:
			Search through the Enum object and return the key or keys which equal the value passed.
		Returns:
			An array of keys found. If no keys were found to have the specified value; then the array is empty.
		*/
		var rv = new Array();
		for (var i=0; i<_keyArray.length; i++)if (_valueArray[i] == value)rv[rv.length] = _keyArray[i];
		return rv;
	};
	this.findKeys = function(){
		/*
		Parameters:
			(variant) - The key(s) to search for this can be regular expression. You can pass as many search strings as necessary.
		Purpose:
			Search through an Enum object to find any items that match the keys searched. And return a new Enum object with those keys.
		Returns:
			a new Enum object, with only the found keys and their values.
		*/
		var e = new Enum();
		for (var i=0; i<arguments.length; i++){
			for (var z=0; z<_keyArray.length; z++){
				if ((arguments[i].type() == "string" && _keyArray[z].indexOf(arguments[i]) > -1) || (arguments[i].type() == "regexp" && arguments[i].test(_keyArray[z])))e.add(_keyArray[z],_valueArray[z]);
			}
		}
		return e;
	};
	this.findValues = function(){
		/*
		Parameters:
			(variant) - The value to search for. Value can be any object. You can pass as many values as you need.
			useRegExp (boolean) - If value is a regular expression; and the current value the method is searching for is a string; try to use a regular expression match on it. Default is false.
				You must specify this parameter, if calling the search function with more than one value.
		Purpose:
			Use ths function to search through the Enum object, and return a new Enum containing keys and values of values that match the search criteria.
		Returns:
			A new Enum object, with only the found keys and values.
		*/
		var e = new Enum();
		var useRegExp = (arguments.length < 2 ? false : arguments[arguments.length-1]);
		for (var i=0; i<(arguments.length == 1 ? arguments.length : arguments.length-1); i++){
			for (var z=0; z<_valueArray.length; z++){
				if ((arguments[i].type() == "regexp" && _valueArray[z].type() == "string" && useRegExp && arguments[i].test(_valueArray[z])) || (_valueArray[z] == arguments[i]))e.add(_keyArray[z],_valueArray[z]);
			}
		};
		return e;
	};
	this.findIndexes = function(){
		/*
		Parameters:
			(variant) - The key to search for. Key can be a regular expression. You can pass as many keys as necessary.
		Purpose:
			Use this function to search through the Enum object, and return the indexes of which key(s) match.
		Returns:
			Array of Integers - Returns all possible index matches. If no matches are found, returns a zero length array.
		*/
		var array = [];
		for (var i=0; i<arguments.length; i++)array = array.concat(_keyArray.find(arguments[i],0,-1,false,true));
		return array;
	};
	this.item = function(index,nth){
		/*
		Parameters:
			index (variant) - The integer, string, or regular expression of the name to retrieve.
				integer - This is the index number zero based of the item object to retrieve.
				string - This is an exact key match of the item to retrieve.
				regular expression - Will return the nth item matching the regular expression.
			nth (integer) - If regular expression searching is used, returns the item after matching this many times or the last possible match; which ever is the latter. Default is 1.
		Purpose:
			Use this method to get the item which is corresponds to the index or key passed.
		Returns:
			Whatever value is found, if one is found. If no value can be found it returns null.
		*/
		var value = null;
		var nth = (nth == null ? 1 : nth);
		if (index != null){
			switch (index.type()){
				case "string" :
					value = (_keyArray.find(index).length > 0 ? _valueArray[_keyArray.find(index)] : null);
					break;
				case "number" :
					value = _valueArray[index];
					break;
				case "regexp" :
					var flags = (index.ignoreCase ? "i" : "");
					if (index.global)index = new RegExp(index.source,flags);
					for (var i=0; i<_keyArray.length; i++){
						if (index.test(_keyArray[i]) && i < nth)value = _valueArray[i];
					}
					break;
				default :
					Object.error("Enum.item(): parameter 1 is not a string, number or regular expression.");
					break;
			}
		}
		else value = _valueArray[position];
		return value;
	};
	this.removeIndex = function(){
		/*
		Parameters:
			index (variant) - This is either an integer or an array of integers of the index(es) to remove. This value can be passed as many times as necessary.
		Purpose:
			Remove any index from an Enum.
		Returns:
			An integer, the number of items removed.
		*/
		var count = 0;
		var args = [];
		for (var i=0; i<arguments.length; i++)args[args.length] = arguments[i];
		args = args.flatten();
		_keyArray.removeIndex(args);
		_valueArray.removeIndex(args);
		count = this.length-_keyArray.length;
		this.length = _keyArray.length;
		return count;
	};
	this.remove = function(index,end,useCount){
		/*
		Parameters:
			index (variant) - The integer, string, or regular expression of the key to delete.
				integer - This is the index number zero based of the item object to delete.
				string - This is an exact key match of the item to delete.
				regular expression - Will delete all items matching the regular expression.
			end (integer) - If using an integer for the first argument this specifies the end index in the Enum to stop removing items. Or if useCount is true, this the count of items to be removed. Default is null.
				If this parameter is specified as -1; then it will automatically continue to the end of the Enum.
			useCount (boolean) - Specifies whether end should be the last index or a count of indexes to be removed. Default is false.
		Purpose:
			Use this method to delete items from an Enum object.
		Returns:
			An integer, the number of items removed.
		*/
		var count = 0;
		switch (index.type()){
			case "string":
				var pos = _keyArray.find(index);
				if (pos.length > 0){
					_keyArray.removeIndex(pos[0]);
					_valueArray.removeIndex(pos[0]);
					count++;
					this.length -= count;
				}
				break;
			case "number":
				if (index > -1 && index < _keyArray.length){
					end = (end == null ? index+1 : end);
					end = $getEndPoint(_keyArray.length,index,end,useCount);
					_keyArray.remove(index,end);
					_valueArray.remove(index,end);
					count = (end-index);
					this.length -= count;
				}
				break;
			case "regexp":
				var matches = _keyArray.find(index,0,-1,false,true);
				eval("_keyArray.removeIndex("+matches+")");
				eval("_valueArray.removeIndex("+matches+")");
				count = matches.length;
		      this.length -= count;
				break;
		};
		return count;
	};
	this.keyArray = function(){
		/*
		Purpose:
			Use this method to return an array of all the keys for the Enum object.
		Returns:
			An array of keys of the Enum object. Returns a zero length array if no keys exist.
		*/
		return _keyArray;
	};
	this.valueArray = function(){
		/*
		Purpose:
			Use this method to return an array of all the values for the Enum object.
		Returns:
			An array of items of the Enum object. Returns a zero length array if no values exist.
		*/
		return _valueArray;
	};
	this.insert = function(){
		/*
		Parameters:
			Enum (Enum) - The Enum object to insert. This parameter can be passed as many times as necessary.
			index (integer) - The index at which to insert the Enum(s). Default is end of Enum.
		Purpose:
			This method provides a way to insert one or more Enum objects into the current one.
		Returns:
			The number of items inserted into the Enum.
		Usage:
			myEnum.insert(anotherEnum); //Would insert all the keys and values of anotherEnum after the last position in myEnum.
			myEnum.insert(enum1,enum2,enum3,0); //Would insert all the keys and values of enum1, enum2, and enum3 before the start position of myEnum.
		*/
		var index = this.length;
		var count = 0;
		for (var i=0; i<arguments.length; i++){
			if (arguments[i].type() == "number")index = arguments[i];
		};
		for (var i=arguments.length-1; i>=0; i--){
			if (arguments[i].type() == "Enum"){
				var keyArray = arguments[i].keyArray();
				for (var z=keyArray.length-1; z>=0; z--){
					this.add(keyArray[z],arguments[i].valueArray()[z],true,index);
					count++;
				}
			}
		}
		return count;
	};
	this.slice = function(start,end,useCount){
		/*
		Parameters:
			start (integer) - The starting point in the Enum of items to return. Default is start of Enum.
			end (integer) - The end point in the Enum of items to return, or the count of items from start point if useCount is true. Default is end of Enum
			useCount (boolean) - End is a count instead of a specific end point. Default is false.
		Purpose:
			Return just a portion of an Enum object.
		Returns:
			A new Enum object.
		*/
		start = (start == null ? 0 : start);
		end = $getEndPoint(this.length,start,end,useCount);
		var keys = _keyArray.slice(start,end);
		var values = _valueArray.slice(start,end);
		return new Enum(keys,values);
	};
	this.compare = function(){
		/*
		Parameters:
			obj (Enum) - Enum object to inspect. You can pass as many as needed.
			start (integer) - The starting index to compare between the Enum objects. Default is 0.
			end (integer) - Either the last index or the count of indexes to stop comparison. Default is End of Enum.
			useCount (boolean) - Specifies whether or not end is to be used as the end point or a count of indexes. Default is false.
		Purpose:
			Use this method to test whether Enums are identical. Or whether a part of the Enums is equal.
		Returns:
			Boolean, true if the Enums are equal; false if not.
		*/
		var value = true;
		var pos = arguments.length;
		var start = 0;
		var end = -1;
		var useCount = false;
		var found = false;
		for (var i=0; i<arguments.length; i++){
			if (arguments[i].type() == "number"){
				pos = i;
				found = true;
				break;
			};
		}
		if (found){
			start = arguments[pos];
			if (arguments.length >= pos+1)end = arguments[pos+1];
			else end = -1;
			if (arguments.length >= pos+2)useCount = arguments[pos+2];
			else useCount = false;
		}
		end = $getEndPoint(this.length,start,end,useCount);
		var keys = _keyArray.slice(start,end);
		var values = _valueArray.slice(start,end);
		for (var i=0; i<pos; i++){
			var oKeys = arguments[i].keyArray();
			var oValues = arguments[i].valueArray();
			for (var z=0; z<oKeys.length; z++){
				if (keys.find(oKeys[z]).length == 0 || (keys.find(oKeys[z]).length > 0 && arguments[i].item(oKeys[z]) != values[keys.find(oKeys[z])[0]]))value = false;
			}
		}
		return value;
	};
	this.moveFirst = function(){
		position = 0;
		this.atEnd = false;
	};
	this.moveNext = function(){
		if (position < this.length)position++;
		if (position == this.length-1)this.atEnd = true;
	};
	this.moveLast = function(){
		position = this.length-1;
		this.atEnd = true;
	};
	
	/* Constructor */
	if (arguments.length > 0){
		switch (arguments[0].type()){
			case "array":
				if (arguments.length % 2 == 0){
					var keys = [];
					var values = [];
					for (var i=0; i<arguments.length; i = i+2){
						keys = keys.concat(arguments[i]);
						values = values.concat(arguments[i+1]);
					}
					if (keys.length == values.length){
						for (var i=0; i<keys.length; i++)this.add(keys[i],values[i],true);
					}
					else Enum.error("Enum constructor: Was not passed an equal number of key arrays, and value arrays.");
				}
				else Enum.error("Enum constructor: Expected an even number of arguments. First key array, then value array, etc... But the number of arguments is odd.");
				break;
			case "List":
				alert("Parse a list into Enum");
				break;
			case "Enum":
				for (var i=0; i<arguments.length; i++){
					if (arguments[i].type() == "Enum"){
						var e = arguments[i];
						var keys = e.keyArray();
						for (var z=0; z<keys.length; z++)this.add(keys[z],e.item(keys[z]),true);
					}
				}
				break;
			case "string":
				var pairs = true;
				for (var i=0; i<arguments.length; i++){
					if (arguments[i].type() != "string" || (arguments[i].type() == "string" && arguments[i].indexOf("=") == -1))pairs = false;
				}
				if (pairs){//Everything is a key=value pair.
					for (var i=0; i<arguments.length; i++)this.add(arguments[i].split("=")[0],arguments[i].split("=")[1],true);
				}
				else{
					if (arguments.length % 2 == 0){
						for (var i=0; i<arguments.length; i = i+2)this.add(arguments[i],arguments[i+1],true);
					}
					else Enum.error("Enum constructor: Expected an even number of arguments. First key, then value, etc... But the number of arguments passed are odd.");
				};
				break;
			default:
				Enum.error("Enum constructor: Unknown type passed to Enum constructor. Type was: "+arguments[0].type());
				break;
		};
	};
	return this;
};

//Keys object -- This is an Enum object of keys for keyboard press lookup purposes.
Keys = new Enum();
Keys.add("Backspace",8);
Keys.add("Tab",9);
Keys.add("Enter",13);
Keys.add("Shift",16);
Keys.add("Control",17);
Keys.add("Alt",18);
Keys.add("Pause",19);
Keys.add("Caps Lock",20);
Keys.add("Escape",27);
Keys.add("Page Up",33);
Keys.add("Page Down",34);
Keys.add("End",35);
Keys.add("Home",36);
Keys.add("Left",37);
Keys.add("Up",38);
Keys.add("Right",39);
Keys.add("Down",40);
Keys.add("Insert",45);
Keys.add("Delete",46);
Keys.add("Number 0",48);
Keys.add("Number 1",49);
Keys.add("Number 2",50);
Keys.add("Number 3",51);
Keys.add("Number 4",52);
Keys.add("Number 5",53);
Keys.add("Number 6",54);
Keys.add("Number 7",55);
Keys.add("Number 8",56);
Keys.add("Number 9",57);
Keys.add("Semi-Colon",59);
Keys.add("Equals",61);
Keys.add("A",65);
Keys.add("B",66);
Keys.add("C",67);
Keys.add("D",68);
Keys.add("E",69);
Keys.add("F",70);
Keys.add("G",71);
Keys.add("H",72);
Keys.add("I",73);
Keys.add("J",74);
Keys.add("K",75);
Keys.add("L",76);
Keys.add("M",77);
Keys.add("N",78);
Keys.add("O",79);
Keys.add("P",80);
Keys.add("Q",81);
Keys.add("R",82);
Keys.add("S",83);
Keys.add("T",84);
Keys.add("U",85);
Keys.add("V",86);
Keys.add("W",87);
Keys.add("X",88);
Keys.add("Y",89);
Keys.add("Z",90);
Keys.add("Numpad 0",96);
Keys.add("Numpad 1",97);
Keys.add("Numpad 2",98);
Keys.add("Numpad 3",99);
Keys.add("Numpad 4",100);
Keys.add("Numpad 5",101);
Keys.add("Numpad 6",102);
Keys.add("Numpad 7",103);
Keys.add("Numpad 8",104);
Keys.add("Numpad 9",105);
Keys.add("Numpad Asterick",106);
Keys.add("Numpad Plus",107);
Keys.add("Hyphen",109);
Keys.add("Numpad Period",110);
Keys.add("Numpad Forward Slash",111);
Keys.add("F1",112);
Keys.add("F2",113);
Keys.add("F3",114);
Keys.add("F4",115);
Keys.add("F5",116);
Keys.add("F6",117);
Keys.add("F7",118);
Keys.add("F8",119);
Keys.add("F9",120);
Keys.add("F10",121);
Keys.add("F11",122);
Keys.add("F12",123);
Keys.add("Num Lock",144);
Keys.add("Scroll Lock",145);
Keys.add("Comma",188);
Keys.add("Period",190);
Keys.add("Forward Slash",191);
Keys.add("Left Apostrophe",192);
Keys.add("Left Bracket",219);
Keys.add("Back Slash",220);
Keys.add("Right Bracket",221);
Keys.add("Apostrophe",222);

/* Key object -- automatically gets information on the last key pressed within the browser window
	Optionally this object can also be set with values; just understand that it will be overwritten each time a key is pressed.
	
	shiftKey (boolean) - Was the shift key held when the button was pressed?
	ctrlKey (boolean) - Was the control key held when the button was pressed?
	altKey (boolean) - Was the alternate key held when the button was pressed?
	code (integer) - The unicode keycode of the key which was pressed.
	chr (char) - The character which was pressed or null if a non printable character was pressed.
	name (string) - The name of the key pressed (including non-printable names).
*/
Key = {
   shiftKey : false,
   ctrlKey : false,
   altKey : false,
   code : 0,
   chr : function(){
      if (this.code >= 65 && this.code <= 90 && this.shiftKey){
         return Keys.findKey(this.code);
      }
      if (this.code >= 65 && this.code <= 90 && !this.shiftKey){
         return Keys.findKey(this.code).toLowerCase();
      }
      if (this.code >= 48 && this.code <= 57 && !this.shiftKey){
         return this.code-48;
      }
      if (this.code >= 48 && this.code <= 57 && this.shiftKey){
         return [")","!","@","#","$","%","^","&","*","("][this.code-48];
      }
      if (this.code >= 96 && this.code <= 105){
         return this.code-96;
      }
      if (this.code == 59 && !this.shiftKey){
         return ";";
      }
      if (this.code == 59 && this.shiftKey){
         return ":";
      }
      if (this.code == 61 && !this.shiftKey){
         return "=";
      }
      if (this.code == 61 && this.shiftKey){
         return "+";
      }
      if (this.code == 109 && !this.shiftKey){
         return "-";
      }
      if (this.code == 109 && this.shiftKey){
         return "_";
      }
      if (this.code == 188 && !this.shiftKey){
         return ",";
      }
      if (this.code == 188 && this.shiftKey){
         return "<";
      }
      if (this.code == 190 && !this.shiftKey){
         return ".";
      }
      if (this.code == 190 && this.shiftKey){
         return ">";
      }
      if (this.code == 192 && !this.shiftKey){
         return "`";
      }
      if (this.code == 192 && this.shiftKey){
         return "~";
      }
      if (this.code >= 219 && this.code <= 222 && !this.shiftKey){
         return ["[","\\","]","'"][this.code-219];
      }
      if (this.code >= 219 && this.code <= 222 && this.shiftKey){
         return ["{","|","}","\""][this.code-219];
      }
      return null;
   },
   name : function(){
      return Keys.findKey(this.code);
   },
	getInfo : function(evt){
		evt = (evt != null ? evt : window.event);
		Key.code = evt.keyCode;
		Key.altKey = evt.altKey;
		Key.ctrlKey = evt.ctrlKey;
		Key.shiftKey = evt.shiftKey;
	}
};
if (window.addEventListener)window.addEventListener("keydown",Key.getInfo,false);
if (window.attachEvent != null)window.attachEvent("onkeydown",Key.getInfo);

//XML Object
function XML(){
	var obj = null;
	try{
		obj = new ActiveXObject("Msxml2.XMLHTTP");
	}
	catch(e){
		try{
			obj = new ActiveXObject("Microsoft.XMLHTTP");
		}
		catch (e){
			try{
				obj = new XMLHttpRequest();
			}
			catch (e){
				try{
					obj = window.createRequest();
				}
				catch(e){
					obj = null;
				}
			}
		}
	}
	return obj;
};

//Regular Expression Extensions



/* Static Functions
	All functions are prefixed with $, in an effort to make them unique enough to not interfere with any other code that may be running.
*/

function $getFunctionName(f){
	/*
	Parameters:
		f (string|function) - The function or function text to get the name from.
	Purpose:
		To get the name of a function passed.
	Returns:
		A string, representing the name of the function.
	*/
	var value = null;
	var re = /^function (.+?)\(.*?\)/i;
	var result = null;
	if (typeof f){
		value = f.name; //Some browsers provide a name property on the function object, so we'll use that if we can.
		if (value != null)return value;
		f = f.toString();
	};
	result = re.exec(f);
	if (result != null)value = result[1];
	return value;
};

function $getEndPoint(length,start,end,useCount){
	/*
	Parameters:
		length (integer) - The length of the object we are dealing with. (string.length or array.length).
		start (integer) - The start index we want.
		end (integer) - The end index or count we want.
			If end is null; it becomes the last element of the object.
			If end is 0 or any negative number; it becomes the last element of the object.
			If end is less than start, and useCount is false; start and end are swapped.
			If end is greater than length; end becomes last element of the object.
		useCount (boolean) - Whether end is going to be a direct end point or a count from the start.
	Purpose:
		Many methods in this library use: start,end,useCount parameters. In an effort to standardize this across all methods, I decided to use this function to always determine my end point.
	Returns:
		An integer, the end point to use based on the parameters passed.
	*/
	length = (length == null ? 0 : length);
	start = (start == null ? 0 : start);
	useCount = (useCount == null ? false : useCount.toBoolean());
	end = ((end == null || end < 0) ? length : (useCount ? start+end : end));
	if (end < start){
		var tmp = start;
		start = end;
		end = tmp;
	}
	if (end > length)end = length;
	return end;
};

function $getAttributes(el){
	/*
	Parameters:
		el (variant) - Either a string which is the ID of an element, or the element itself.
		attribute (variant) - The attribute to check the value and return. (This can be passed more than once)
			If the attribute is passed more than one time, the return is an array of the results of all attribute checks.
	Purpose:
		Quickly determine the value of an HTML element's attribute. The standards compliant way.
	Returns:
		Null if none of the attribute is not set.
		A value, if only one attribute was passed (and was set on the element).
		or, an array of the results of multiple attribute checks.
	*/
	var attributes = null;
	el = (el.constructor == String ? document.getElementById(el) : el);
	if (el != null){
		if (arguments.length > 2){
			attributes = [];
			for (var i=1; i<arguments.length; i++){
				if (el.getAttributeNode(arguments[i]) != null)attributes[attributes.length] = el.getAttributeNode(arguments[i]).nodeValue;
				else attributes[attributes.length] = null;
			}
		}
		else{
			if (el.getAttributeNode(arguments[1]) != null){
				attributes = el.getAttributeNode(arguments[1]).nodeValue;
			}
		}
	}
	return attributes;
};

function $bind(el,handler,method,capture){
	/*
	Parameters:
		el (variant) - Either a string which is the ID of an element, or the element itself.
		handler - A string representing which event to add a listener for. Example: click,dblclick,focus, etc... Notice they are standards words, No on prefix.
		method - The function to call when the event is fired.
		capture - Whether or not to capture the event. (See addEventListener documentation for more details).
	Purpose:
		This function provides a quick one-line way to add an event listener to standards compliant browsers; and IE.
	*/
	el = (el.constructor == String ? document.getElementById(el) : el);
	capture = (capture == null ? false : capture);
	if (el.attachEvent != null)el.attachEvent("on"+handler,method);
	if (el.addEventListener != null)el.addEventListener(handler,method,capture);
};

function $selection(el,start,end){
	/*
	Parameters:
		el (variant) - Either a string which is the ID of an element, or the element itself.
		start (integer) - Move the start selection to this position. Default is null. (Return start position)
		end (integer) - Move the end of the selection to this position. Default is null. (Return end position)
	Purpose:
		This function provides an easy way to manipulate or get the cursor position in an element.
		This was originally written for textareas and text input boxes; but will probably work on anything.
	Returns:
		The position in the element where selection is located.
	*/
	el = (el.constructor == String ? document.getElementById(el) : el);
	start = (start == null ? -1 : start);
	end = (end == null ? start : (end == 0 ? el.value.length : end));
	if (document.selection){
		var sel = document.selection.createRange();
		var tr = el.createTextRange();
		if (tr != null && sel != null && el != null){
			if (start == -1){
				var pos = 0;
				while (sel.compareEndPoints("StartToStart",tr) > 0){
					tr.moveStart("character",1);
					pos++;
				}
				start = pos;
				end = sel.text.length+start;
			}
			else{
				tr.moveStart("character",start);
				tr.collapse();
				if (end > -1)tr.moveEnd("character",(end-start));
				tr.select();         
			}
		}
	}
	else{
		if (start == -1){
			start = el.selectionStart;
			end = el.selectionEnd;
		}
		else{
			el.selectionStart = start;
			if (end > -1)el.selectionEnd = end;
		}
	}
	return{
		start : start,
		end : end
	}
};

function $replaceSelection(el,str,update){
	/*
	Parameters:
		el (variant) - Either a string of the ID of the element or the actual element to manipulate.
		str (string) - The string to replace the current selection with.
		update (boolean) - Whether or not to actually manipulate the element or to just return what the new text would be. Default is true.
	Purpose:
		This function will replace the current selection of an element, for example a text area; with the string provided.
		Or if update is true, it will return only what the new element would look like.
	Returns:
		The updated string.
	*/
	update = (update == null ? true : update);
	el = (el.constructor == String ? document.getElementById(el) : el);
	var start = $selection(el).start;
	var end = $selection(el).end;
	var str = el.value.inject(str,start);
	if (update){
		el.value = str;
	}
	return str;
};

function $getElementsByAttribute(attribute,value,start){
   /*
	Parameters:
		attribute (variant) - Either a string which is an exact attribute or a regular expression.
			This parameter can also be an array of strings or regular expressions, for matches of more than one attribute.
		value (variant) - Either a string or a regular expression, of the value of the attribute to retrieve elements of. Default is null.
			If attribute is an array, this must be an array of equal length (or null).
		start (variant) - Either the ID of the element to start looking under or the element reference itself. Default is body.
	Purpose:
		This function returns an array of all matching elements which match the specified attributes or values.
	Returns:
		An array of elements, or a zero length array if no elements contain the specific attribute and value passed.
	*/
	var array = [];
	start = (start == null ? document.body : start);
	var recurse = function(el,attribute,value){
		if (el.nodeType == 1){
			var attr = attribute;
			if (attribute.type() == "regexp"){
				var attrs = el.attributes;
				for (var i=0; i<attrs.length; i++){
					var result = attribute.test(attrs[i].nodeName);
					if (result){
						attr = attrs[i].nodeName;
						break;
					};
				};
			}
			var condition1 = (el.getAttributeNode(attr) != null);
			var condition2 = (value == null || (condition1 && value != null && ((value.type() == "string" && el.getAttributeNode(attr).nodeValue == value) || (value.type() == "regexp" && new RegExp(value.source,(value.global ? "g" : "")+(value.ignoreCase ? "i" : "")+(value.multiline ? "m" : "")).test(el.getAttributeNode(attr).nodeValue)))));
			if (condition1 && condition2)array[array.length] = el;
		};
		for (var i=0; i<el.childNodes.length; i++)recurse(el.childNodes[i],attribute,value);
	};
	if (attribute != null){
		if ((attribute.type() == "array" && value != null && value.type() == "array" && value.length == attribute.length) || (attribute.type() == "array" && value == null) || (attribute.type() != "array")){
			if (attribute.type() == "array"){
				for (var i=0; i<attribute.length; i++)recurse(start,attribute[i],value[i]);
			}
			else recurse(start,attribute,value);
		}
		else Object.error("$getElementsByAttribute(): When passing attribute as an array, if value is also being checked; it must be an equal length array.");
	}
	else Object.error("$getElementsByAttribute(): No attribute was specified.");
	return array;
}