
if (typeof(common) == 'undefined') {
// If we're not the top window, attempt to inherit from the top window
/*
if ((window != top) && (typeof(top.common) != 'undefined')) {
	common = top.common;
} else {
*/
	common = {

		// The following table defines the HTML entity mapping used by common.html_entity_decode()
		// It only supports the encoding for ISO 8859-1 as defined in the HTML 4.01 specification
		html_entity_table : {
			// C0 Controls and Basic Latin
			quot : '\x22',
			amp : '\x26',
			lt : '\x3C',
			gt : '\x3E',
			// Character entity references for ISO 8859-1 characters
			nbsp : '\xA0',
			iexcl : '\xA1',
			cent : '\xA2',
			pound : '\xA3',
			curren : '\xA4',
			yen : '\xA5',
			brvbar : '\xA6',
			sect : '\xA7',
			uml : '\xA8',
			copy : '\xA9',
			ordf : '\xAA',
			laquo : '\xAB',
			not : '\xAC',
			shy : '\xAD',
			reg :'\xAE',
			macr : '\xAF',
			deg : '\xB0',
			plusmn : '\xB1',
			sup2 :'\xB2',
			sup3 : '\xB3',
			acute :'\xB4',
			micro : '\xB5',
			para : "\xB6",
			middot : "\xB7",
			cedil : "\xB8",
			sup1 : "\xB9",
			ordm : "\xBA",
			raquo : "\xBB",
			frac14 : "\xBC",
			frac12 : "\xBD",
			frac34 : "\xBE",
			iquest : "\xBF",
			Agrave : "\xC0",
			Aacute : "\xC1",
			Acirc : "\xC2",
			Atilde : "\xC3",
			Auml : "\xC4",
			Aring : "\xC5",
			AElig : "\xC6",
			Ccedil : "\xC7",
			Egrave : "\xC8",
			Eacute : "\xC9",
			Ecirc : "\xCA",
			Euml : "\xCB",
			Igrave : "\xCC",
			Iacute : "\xCD",
			Icirc : "\xCE",
			Iuml : "\xCF",
			ETH : "\xD0",
			Ntilde : "\xD1",
			Ograve : "\xD2",
			Oacute : "\xD3",
			Ocirc : "\xD4",
			Otilde : "\xD5",
			Ouml : "\xD6",
			times : "\xD7",
			Oslash : "\xD8",
			Ugrave : "\xD9",
			Uacute : "\xDA",
			Ucirc : "\xDB",
			Uuml : "\xDC",
			Yacute : "\xDD",
			THORN : "\xDE",
			szlig : "\xDF",
			agrave : "\xE0",
			aacute : "\xE1",
			acirc : "\xE2",
			atilde : "\xE3",
			auml : "\xE4",
			aring : "\xE5",
			aelig : "\xE7",
			egrave : "\xE8",
			eacute : "\xE9",
			ecirc : "\xEA",
			euml : "\xEB",
			igrave : "\xEC",
			iacute : "\xED",
			icirc : "\xEE",
			iuml : "\xEF",
			eth : "\xF0",
			ntilde : "\xF1",
			ograve : "\xF2",
			oacute : "\xF3",
			ocirc : "\xF4",
			otilde : "\xF5",
			ouml : "\xF6",
			divide : "\xF7",
			oslash : "\xF8",
			ugrave : "\xF9",
			uacute : "\xFA",
			ucirc : "\xFB",
			uuml : "\xFC",
			yacute : "\xFD",
			thorn : '\xFE',
			yuml : '\xFF'
			},
	
		/**
		 * Encodes unsafe characters using HTML entity encoding
		 *
		 * @param	String	val	The value to encode
		 *
		 * @return	String	The enocoded string
		 */
		htmlentities : function(val) {
			if (val == null) return '';
			if (typeof(val) != 'string')
				val = ''+ val;
			return val.replace(/[^\sa-zA-Z0-9]/g,
				function(match) {
					return '&#'+ match.charCodeAt(0) +';';
				});
		}, // common.htmlentities(val)


		/**
		 * Encodes certain characters with their respective entities
		 *
		 * The following characters are encoded:
		 *		& => &amp;
		 *		" => &quot;
		 *		' => &apos;
		 *		< => &lt;
		 *		> => &gt;
		 *
		 * @param	string	val	The value to perform entity replacement on
		 *
		 * @return	string	The encoded string
		 */
		htmlspecialchars : function(val) {
			if (val == null)
				return '';

			return val.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;').replace('"', '&quot;').replace("'", '&apos;');
		}, // common.htmlspecialchars(val)

		// xmlentities is defined below as an alias to htmlspecialchars

		/**
		 * Decodes HTML entities in a string to their respective characters (the reverse of common.htmlentities())
		 *
		 * @param	String	val	The value to decode
		 *
		 * @return	String	The decoded string
		 *
		 * @todo		TODO: The html_entity_decode function should be tested/debugged if it is used extensively.  It appears to work, but has not been tested thoroughly.
		 */
		html_entity_decode : function(val) {
			// {1,6} = 1..6 chars between & and ;
			// It is not neccessary to check more than this because there are no defined entities with longer names
			return val.replace(/&([^;]{1,6});/g,
				function(match, entity) {
					if (entity in common.html_entity_table)	// Entity name defined in HTML 4.01 spec?
						return common.html_entity_table[entity];
					else if (match.substr(0,1) == '#') { // Numeric value entity?
						var charCode;
						if (match.substr(1,1).toLowerCase() == 'x') {	// Hex value
							charCode = parseInt(match.substr(2), 16);
						} else { // Decimal value
							charCode = parseInt(match.substr(2), 10);
						}
						if (!isNaN(charCode))
							return String.fromCharCode(charCode);
					}

					return match;
				});
		}, // html_entity_decode(val),


		nl2br : function(str) {
			if (typeof(str) != 'string') str = ''+str;
			return str.replace(/\n/g, '<br />\n');
		}, // nl2br(str)

		/**
		 * Escapes a string in c-style
		 *
		 * @param	String	v	The string to escape
		 *
		 * @return	String	The escaped string
		 */
		addcslashes : function(v) {
			var map = {
				'\n' : '\\n',
				'\r' : '\\r',
				'\t' : '\\t',
				'\v' : '\\v',
				'\f' : '\\f',
				'\\' : '\\\\',
				'\0' : '\\0'
				};

			v = v+'';	// Convert to string
			return v.replace(/[\\'"\0-\x1f\x7f-\xff]/g, function (ch, ofs, s) {
									if (typeof(map[ch]) != 'undefined')
										return map[ch];
									else {
										ch = ch.charCodeAt(0).toString(16);
										if (ch.length < 2)
											ch = '0' + ch;
										return '\\x'+ ch;
									}
								});
		}, // common.addcslashes(v)


		/**
		 * Quotes a string for use in a JavaScript expression
		 *
		 * @param	{string}	val		The value to quote
		 *
		 * @return	str
		 */
		quotestring : function(val) {
			// Types that need no special quoting
			var tp = typeof(val);
			if ((val == null) ||
				(tp == 'number') ||
				(val instanceof Number) ||
				(tp == 'boolean') ||
				(val instanceof Boolean)
				)
				return ""+val;

			// All other types we try to quote
			return '"'+ common.addcslashes(""+val) +'"';
		}, // common.quotestring(val)


		/**
		 * Escape a string for use in a regular expression
		 *
		 * @param	String	v	The string to escape
		 *
		 * @return	String	The escaped string
		 */
		quotemeta : function(v) {
			return (common.addcslashes(v)).replace(/[{}().*+?^$\[\]]/g, '\\$0');
		}, // common.quotemeta(v)


		/**
		 * Tests whether the given value is numeric or not
		 *
		 * @param	mixed	val	The value to test
		 *
		 * @return	boolean	Whether the given value appeared to be numeric or not
		 */
		is_numeric : function(val) {
			var re = /\s*[-+]?([0-9]*)(?:\.([0-9]*))?\s*/;
			var m = re.exec(val);
			return ((m[1] != '') || ((m[2] != null) && (m[2] != '')));
		}, // common.is_numeric(val)

		formatNumber : function(pnum, decimalNum, bolLeadingZero, bolParens, bolCommas)
		/**********************************************************************
			IN:
				NUM - the number to format
				decimalNum - the number of decimal places to format the number to
				bolLeadingZero - true / false - display a leading zero for
												numbers between -1 and 1
				bolParens - true / false - use parenthesis around negative numbers
				bolCommas - put commas as number separators.
		 
			RETVAL:
				The formatted number!
		 **********************************************************************/
		{ 
		    var num = new String(pnum);
//		    num = num.replace(/^\s*(.*?)\s*$/g, '$1');	// Trim leading & trailing whitespace
		    num = num.replace(/,/g, "");	// Remove commas

			if (num.length == 0 ) return "";
			num = Number(num);
	        if (isNaN(num)) return "NaN";
	        if (!isFinite(num)) return (num == Number.NEGATIVE_INFINITY ? '-' : '') +"Infinity";

			var tmpNum = num;
			var iSign = ((tmpNum < 0) ? -1 : 1);	// Get sign of number
			
			// Adjust number so only the specified number of numbers after
			// the decimal point are shown.
			tmpNum *= Math.pow(10, decimalNum);
			tmpNum = Math.round(Math.abs(tmpNum))
			tmpNum /= Math.pow(10, decimalNum);
			tmpNum *= iSign;					// Readjust for sign

			// Create a string object to do our formatting on
			var tmpNumStr = new String(tmpNum);

			// See if we need to strip out the leading zero or not.
			if (!bolLeadingZero && (num < 1) && (num > -1) && (num != 0))
				if (num > 0)
					tmpNumStr = tmpNumStr.substring(1, tmpNumStr.length);
				else
					tmpNumStr = "-" + tmpNumStr.substring(2, tmpNumStr.length);

			// See if we need to put in the commas
			var iStart = tmpNumStr.indexOf(".");
			if (iStart < 0) {
				iStart = tmpNumStr.length;
				if (decimalNum > 0)
					tmpNumStr += '.';
			} else if (decimalNum == 0) {
				tmpNumStr = tmpNumStr.substr(0, iStart);
			}

			if (decimalNum > 0) {
				while (tmpNumStr.length - iStart <= decimalNum)
					tmpNumStr += '0';
			}

			if (bolCommas && ((num >= 1000) || (num <= -1000))) {
				iStart -= 3;
				while (iStart >= 1) {
					tmpNumStr = tmpNumStr.substring(0, iStart) + "," + tmpNumStr.substring(iStart, tmpNumStr.length)
					iStart -= 3;
				}
			}

			// See if we need to use parenthesis
			if (bolParens && (num < 0))
				tmpNumStr = "(" + tmpNumStr.substring(1,tmpNumStr.length) + ")";

			return tmpNumStr;		// Return our formatted string!
		}, //formatNumber(pnum, decimalNum, bolLeadingZero, bolParens, bolCommas)


		array_values : function(obj) {
			var rv = [ ];
			for (var i in obj) {
				if (obj.hasOwnProperty(i)) {
					rv[rv.length] = obj[i];
				}
			} // for
			return rv;
		}, // array_values(obj)


		array_keys : function(obj) {
			var rv = [ ];
			for (var i in obj) {
				if (obj.hasOwnProperty(i)) {
					rv[rv.length] = i;
				}
			} // for
			return rv;
		}, // array_keys(obj)


		/*private*/
		_http_build_query_helper : function( key, val, arg_separator ) {
			var rv = "";
			var type = typeof(val);
			if (type == 'object') {
				var sep = "";

				if (type instanceof Array) {
					for (var i = 0; i < val.length; ++i) {
						var t = common._http_build_query_helper(key +'['+ encodeURIComponent(i) +']', val[i], arg_separator);
						if (t != '') {
							rv += sep + t;
							sep = arg_separator;
						}
					} // for
				} else {
					for (var i in val) if (val.hasOwnProperty(i)) {
						var t = common._http_build_query_helper(key +'['+ encodeURIComponent(i) +']', val[i], arg_separator);
						if (t != '') {
							rv += sep + t;
							sep = arg_separator;
						}
					} // for
				}

				// It seems that not sending the key may be better than sending an empty string for the key since we wouldn't
				//	want a string where we are expecting an array.
//				if (rv == "")
//					rv = key + '=';
			} else if (type == 'boolean') {
				rv = key +"="+ (val ? '1' : '0');
			} else {
//alert(key +'='+ val +'  type='+ typeof(val));
				rv = key +"="+ encodeURIComponent((typeof(val) != 'undefined') ? val : '');
			}

			return rv;
		}, // common._http_build_query_helper ( key, val, arg_separator )


		/**
		 * Generates a URL-encoded query string from the associative (or indexed) array provided.
		 *
		 * @param	Array|Object	formdata			May be an array or object containing properties. A formdata array may be a simple
		 *										one-dimensional structure, or an array of arrays (who in turn may contain other arrays).
		 *										May also be a HTMLForm DOM object, in which case the form's element values are encoded
		 *										and returned.
		 * @param	String		numeric_prefix	If numeric indices are used in the base array and a numeric_prefix is provided, it will
		 *										be prepended to the numeric index for elements in the base array only. This is to allow
		 *										for legal variable names when the data is decoded by PHP or another CGI application later on. 
		 * @param	String		arg_separator		The argument separator to use (defaults to '&')
		 *
		 * @return	String		
		 */
		http_build_query : function( data, numeric_prefix /* = '' */, arg_separator /* = '&' */ ) {
			if (numeric_prefix == null)
				numeric_prefix = '';

			if (arg_separator == null)
				arg_separator = '&';

			if (typeof(data) != 'object')
				throw "common.http_build_query(): Parameter 1 must be an object/array";

			var rv = "";
			var sep = "";

			if (data.tagName == 'FORM') {
				var radio_values = { };
				var submit_button = {
						"found" : 0,
						"value" : ""
						};

				for (var i = 0; i < data.elements.length; ++i) {
					// ref: http://www.w3.org/TR/html401/interact/forms.html#h-17.13
					// 
					// ! - A successful control must be defined within a FORM element and must have a control name.
					// ! - Controls that are disabled cannot be successful
					// ! - All "on" checkboxes may be successful
					// ! - If a control doesn't have a current value when the form is submitted, user agents are not
					//		required to treat it as a successful control. ( We do treat it as successful here.. )
					// ! - For radio buttons that share the same value of the name attribute,
					//		only the "on" radio button may be successful
					// ! - Only selected options may be successful. When no options are selected, the control is
					//		not successful and neither the name nor any values are submitted to the server when the
					//		form is submitted.
					// ? - If a form contains more than one submit button, only the activated submit button is successful.
					//		( We cannot emulate this completely since we don't know which submit button may have been
					//			activated if there is more than one.  If there is exactly one submit button, then we
					//			can send that one )
					//
					// UNSUPPORTED CONTROL TYPES:
					//   - The current value of a file select is a list of one or more file names. Upon submission
					//		of the form, the contents of each file are submitted with the rest of the form data.
					//		The file contents are packaged according to the form's content type.
					// 		THIS CANNOT BE SUPPORTED DUE TO SECURITY WITHIN THE BROWSER
					//   - The current value of an object control is determined by the object's implementation.
					//		WE DO NOT KNOW WHAT IMPLEMENTATIONS MAY OCCUR HERE, AND THUS DO NOT SUPPORT THIS.

// TODO: Are control names case-insensitive or not?  They are sent in the original case specified, but this is a question
//		that needs to be answered for radio controls since we need to check for duplicate names in that case...

					var o = data.elements[i];
					if (o.disabled || !o.name)	// Don't send values for disabled form controls or controls with no name
						continue;

					switch (o.tagName) {
					case 'FIELDSET':	// This is not at actual form control with a value, so don't submit
					case 'BUTTON':		// No way to know which button was selected, so don't add any into submission
						continue;

					case 'SELECT':
						if (o.multiple) {
							// Multi-SELECT elements need special processing
							for (var j = 0; j < o.options.length; ++j) {
								var opt = o.options[j];
								if (opt.selected) {
									rv += sep +
											encodeURIComponent(common.is_numeric(o.name) ? numeric_prefix + o.name : o.name) +
											"="+
											encodeURIComponent(opt.value);
								}
							} // for
							continue;
						}
						break;

					case 'INPUT':
						switch (o.type) {
						case 'file':
							throw "common.http_build_query: The form has a file input control on it.  This type of control cannot be encoded in the query due to security constraints.";
							continue;

						case 'button':		// Cannot be successful
						case 'reset':		// Cannot be successful
							// Don't submit anything for a button control
							continue;

						case 'submit':
							submit_button.found++;
							if (submit_button.found == 1) {
								var n = encodeURIComponent(common.is_numeric(o.name) ? numeric_prefix + o.name : o.name);
								submit_button.value = n +"="+ encodeURIComponent(o.value);
							}
							break;

						case 'image':		// image is actually a submit button too...
											// The issue here is: what coordinates should we send for this?
											//	For now, we'll return 0,0
							submit_button.found++;
							if (submit_button.found == 1) {
								var n = encodeURIComponent(common.is_numeric(o.name) ? numeric_prefix + o.name : o.name);
								submit_button.value = n +"="+ encodeURIComponent(o.value) + arg_separator +
														n +".x=0"+ arg_separator +
														n +".y=0";
							}
							break;

						case 'radio':
							// If we find another radio by this name with the 'checked' property set, we take that value instead
							// Unless... We've already found a previous one with 'checked' set
							if (o.checked) {
								if (!radio_values.hasOwnProperty(o.name) || radio_values[o.name].implied)
									radio_values[o.name] = { "value" : o.value, "implied" : false };
							}
							// Take value of first radio with this name by default.
							/*else if (!radio_values.hasOwnProperty(o.name)) {
								radio_values[o.name] = { "value" : o.value, "implied" : true };
							}*/
							// We don't add the value yet.  We need to look at the entire form before we know there aren't any more controls with this name
							continue;

						case 'checkbox':
							// Don't submit value if this element isn't selected
							if (!o.checked) continue;
						} // switch
						break;
					} // switch

					rv += sep +
							encodeURIComponent(common.is_numeric(o.name) ? numeric_prefix + o.name : o.name) +
							"="+
							encodeURIComponent(o.value);

					sep = arg_separator;
				} // for

				// Add in radio button values now that we've processed all controls in the form
				for (var i in radio_values) if (radio_values.hasOwnProperty(i)) {
					rv += sep +
							encodeURIComponent(common.is_numeric(i) ? numeric_prefix + i : i) +
							"="+
							encodeURIComponent(radio_values[i].value);
					sep = arg_separator;
				} // for

				if (submit_button.found == 1) {
					rv += sep + submit_button.value;
				}
			} else {
				for (i in data) {
					if (data.hasOwnProperty(i)) {	// Not required in FF, but is in IE (enumerates added methods from the prototype)
						rv += sep + common._http_build_query_helper(encodeURIComponent(common.is_numeric(i) ? numeric_prefix + i : i), data[i], arg_separator);
						sep = arg_separator;
					}
				}
			}

			return rv;
		}, // common.http_build_query ( data [, numeric_prefix = '' [, arg_separator = '&' ]] ) {

		/**
		 * Parses a string formatted as a GET or POST value (ie. same format as returned by http_build_query)
		 *
		 * In PHP, the equivalent function is "parse_str"
		 *
		 * @param	String	str		The query string to parse
		 *
		 * @return	Object	An object containing the parsed data
		 */
		http_parse_query : function(str) {
			var rv = { };

			// Not the smartest parser, but will hopefully work well enough...
			var parts = str.split('&');
			for (var i = 0; i < parts.length; ++i) {
				// Determine the key and value
				var key;
				var val = '';
				var p = parts[i].indexOf('=');
				if (p != -1) {
					key = decodeURIComponent(parts[i].substr(0, p));
					val = decodeURIComponent(parts[i].substr(p + 1, parts[i].length));
				} else {
					// Possibly invalid data, just create an empty string value for it
					key = parts[i];
				}

				// Parse the key and create/find the proper sub-element
				var sk;
				p = key.indexOf('[');
				if (p != -1) {
					sk = key.substr(0, p);
					key = key.substr(p + 1, key.length);
				} else {
					sk = key;
					key = '';
				}

				var o = rv;
				while (key.length > 0) {
					// More sub-keys following, add sub-element
					// NOTE: This will blow away any previous scalar values added at this key index
					if (typeof(o[sk]) != 'object')
						o[sk] = { };	
					o = o[sk];

					// Parse next sub-key and continue
					p = key.indexOf(']');
					if (p != -1) {
						sk = key.substr(0, p);
						key = key.substr(p + 1, key.length);
						if (key.substr(0, 1) == '[')
							key = key.substr(1, key.length);
					} else {
						sk = key;
						key = '';
					}
				} // while

				// Just top-level
				o[sk] = val;
			} // for

			return rv;
		}, // http_parse_query( str )


		getBaseURL : function(doc) {
			if  (!doc)
				doc = document;
			else if (doc.nodeType != 9 /* DOCUMENT_NODE */)
				doc = doc.ownerDocument;

			var rv = doc.location.pathname;
			rv = rv.replace(/\/[^\/]*$/, '') + '/';

			return rv;
		}, // getBaseURL([ doc ])
		
		
		/**
		* Merges an object of params with the given parameter string and returns a relative url
		* @Param 	STRING	String of current querystring (will be converted to an object)
		* @Param	STRING	page name to load
		* @Param	OBJECT  object of new parameters (overwrites and/or appends querystring objects in the first param)
		*
		* @RETURN	STRING	relative url with the merged querystring
		*
		* Example:
		*		getMergedURL(
		*			window.location.search.substring(1), //this is the querystring of the window location
		*			window.location.pathname, //this is the page name of the window location
		*			{'myID':456}
		*		);
		* 	If window.location.search.substring(1) has myID then myID will be overwritten to 456
		*	If it does not than myID will be added with the value of 456.
		*/
		getMergedURL : function(cur_qs,page,objParams){
			var qso,qs;
			if (cur_qs)
				qso = common.http_parse_query(cur_qs);
			else
				qso = {};
			if (objParams && objParams !== 'undefined'){
				for(var k in objParams){
					//do not include functions or objects
					if(typeof objParams[k] != 'function' && typeof objParams[k] != 'object')
						qso[k] = objParams[k];
				}
			}
			qs = common.http_build_query(qso);
			return page + "?" + qs;
		}, //getMergedURL(cur_qs,page,objParams)
		
		
		/**
		 * Parses and returns the arguments passed to a linked script via the get portion of the src attribute
		 *
		 * NOTE: THIS ONLY WORKS WITH SCRIPTS LINKED IN USING <script src="..."> AND WILL GIVE BOGUS RESULTS FOR INLINE SCRIPTS
		 *
		 * @return	Object	Associative object containing the parsed key->value pairs
		 *
		 * Some ideas used herein are from: http://feather.elektrum.org/book/src.html
		 * It seems there is a problem in Firefox where the DOM doesn't appear to be updated for each script
		 * (or maybe it's that the first call to getElementsByTagName() caches the results?)  Anyway, it breaks
		 * if more than one script requires this function to work.
		 */
		getScriptArgs : function(doc) {

throw "common.getScriptArgs(): This function is currently broken in Firefox 1.5 (at least) due to some possible result caching.  Please use another method for now.";

			if (!doc)
				doc = document;
			else if (doc.nodeType != 9 /* DOCUMENT_NODE */)
				doc = doc.ownerDocument;

			// Determine the query string from the script element for this code
//			var queryParts = doc.getElementsByTagName('script');
			var scripts = doc.getElementsByTagName('script');
			var queryVals = { };
			queryParts = scripts[scripts.length - 1].src.replace(/^[^?]+\??/, '');

			if (queryParts != '') {
				queryParts = queryParts.split(/[;&]/);
				// Parse the query parts
				for (var i = 0; i < queryParts.length; ++i) {
					var t = queryParts[i].split('=');
					queryVals[decodeURIComponent(t[0])] = decodeURIComponent(t[1]);
				} // for
				queryParts = null;
			}
			return queryVals;
		} // getScriptArgs()

	} // END OF common NAMESPACE

	// Create alias function
	common.xmlentities = common.htmlspecialchars;
//}

	/**
	 * Adds a method to the Function class that creates a closure to execute the function in the context of a given object
	 *
	 * This function is based on an idea from the Prototype library
	 *
	 * @param	Object	obj		The object to bind the function to
	 *
	 * @return	Function		The closure implementing the binding
	 */
	Function.prototype.bind = function(obj) {
		var method = this;
		var temp = function() {
				return method.apply(obj, arguments);
			};
		return temp;
	} // Function.prototype.bind(obj)


	/**
	 * Static method of the Object class for implementing single inheritance
	 *
	 * Based on code from "http://www.kevlindev.com/tutorials/javascript/inheritance/index.htm"
	 *
	 * @param	Object	subClass		The class (constructor) that is to be extended
	 * @param	Object	baseClass	The class (constructor) that is being inherited from 
	 * @param	String	className	The name of the subClass as a string (default = "Object")
	 */
	Object.extend = function(subClass, baseClass, className) {
		function inheritance() { }
		inheritance.prototype = baseClass.prototype;

		subClass.prototype = new inheritance();
		subClass.prototype.constructor = subClass;
		subClass.className = (className ? className : 'Object');
		subClass.baseClass = baseClass;
	} // Object.extend(subClass, baseClass [, className = "Object" ])


	/**
	 * Method of the Object class for implementing multiple inheritance...?
	 */
	Object.prototype.extend = function(src) {
		throw("Object.prototype.extend(): Not supported on an instance")
	} // Object.prototype.extend(src)


	if (!Array.prototype.indexOf) {
		// IE 6 doesn't seem to support indexOf() for Array objects, so add it if it's missing
		Array.prototype.indexOf = function(elem, i) {
			if (!i) i = 0;
			var l = this.length;
			if (i >= 0) {
				for (; i < l; ++i)
					if (this[i] === elem)
						return i;
			} else
				return this.indexOf(elem, l + i);
			return -1;
		} // Array.prototype.indexOf(elem [, i ])
	}


	/*	Cross-Browser Split v0.1;
		MIT-style license By Steven Levithan <http://stevenlevithan.com>
		http://blog.stevenlevithan.com/archives/cross-browser-split/
		An ECMA-compliant, uniform cross-browser split method
	*/
	String.prototype.split = function(separator, limit) {
		var flags = ""; /* Behavior for separator: If it's...
							- Undefined: Return an array containing one element consisting of the entire string
							- A regexp or string: Use it
							- Anything else: Convert it to a string, then use it */

		if (separator === undefined) {
			return [this.toString()]; // toString is used because the typeof this is object
		} else if (separator === null || separator.constructor !== RegExp) {
			// Convert to a regex with escaped metacharacters
			separator = new RegExp(String(separator).replace(/[.*+?^${}()|[\]\/\\]/g, "\\$&"), "g");
		} else {
			flags = separator.toString().replace(/^[\S\s]+\//, "");

			if (!separator.global) {
				separator = new RegExp(separator.source, "g" + flags);
			}
		}

		// Used for the IE non-participating capturing group fix
		var separator2 = new RegExp("^" + separator.source + "$", flags);

		/* Behavior for limit: If it's...
			- Undefined: No limit
			- Zero: Return an empty array
			- A positive number: Use limit after dropping any decimal value (if it's then zero, return an empty array)
			- A negative number: No limit, same as if limit is undefined
			- A type/value which can be converted to a number: Convert, then use the above rules
			- A type/value which cannot be converted to a number: Return an empty array
		*/
		if (limit === undefined || +limit < 0) {
			limit = false;
		} else {
			limit = Math.floor(+limit);
			if (!limit) return []; // NaN and 0 (the values which will trigger the condition here) are both falsy
		}

		var match, output = [], lastLastIndex = 0, i = 0;
		while ((limit ? i++ <= limit : true) && (match = separator.exec(this))) {
			// Fix IE's infinite-loop-resistant but incorrect RegExp.lastIndex
			if ((match[0].length === 0) && (separator.lastIndex > match.index)) {
				separator.lastIndex--;
			}

			if (separator.lastIndex > lastLastIndex) {
				/* Fix IE to return undefined for non-participating capturing groups (NPCGs).
					Although IE incorrectly uses empty strings for NPCGs with the exec method,
					it uses undefined for NPCGs with the replace method. Conversely, Firefox
					incorrectly uses empty strings for NPCGs with the replace and split methods,
					but uses undefined with the exec method. Crazy!
				*/
				if (match.length > 1) {
					match[0].replace(separator2,
						function(){
							for (var j = 1; j < arguments.length - 2; j++) {
								if (arguments[j] === undefined) match[j] = undefined;
							}
						});
				}

				output = output.concat(this.substring(lastLastIndex, match.index),
										(match.index === this.length ? [] : match.slice(1)));
				lastLastIndex = separator.lastIndex;
			}

			if (match[0].length === 0) {
				separator.lastIndex++;
			}
		}

		return (lastLastIndex === this.length)
					? (separator.test("")
							? output
							: output.concat(""))
					: (limit
							? output
							: output.concat(this.substring(lastLastIndex)));
	}; // String.prototype.split(separator, limit)


	/**
	 * Adds a method to strings to trim leading and trailing whitespace
	 *
	 * @return	String	The trimmed string
	 */
	String.prototype.trim = function() {
		return this.replace(/^\s*(.*?)\s*$/, "$1");
	}; // String.prototype.trim()


	/**
	 * Adds a method to strings to trim leading whitespace
	 *
	 * @return	String	The trimmed string
	 */
	String.prototype.ltrim = function() {
		return this.replace(/^\s*(.*)$/, "$1");
	}; // String.prototype.ltrim()


	/**
	 * Adds a method to strings to trim trailing whitespace
	 *
	 * @return	String	The trimmed string
	 */
	String.prototype.rtrim = function() {
		return this.replace(/^(.*?)\s*$/, "$1");
	}; // String.prototype.rtrim()


	// Augmentations of the Date object
	Date.Months = [ 'January', 'February', 'March', 'April', 'May', 'June',
					'July', 'August', 'September', 'October', 'November', 'December' ];
	Date.ShortMonths = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
						'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ];
	Date.DaysOfWeek = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ];
	Date.ShortDaysOfWeek = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ];

	/**
	 * Formats a date as a string using formatting codes similar to PHP's date() function
	 *
	 * @param	String	fmtString	The format string to use
	 *								Examples:
	 *									"m/d/Y"		=> 08/20/2006
	 *									"n/j/Y"		=> 8/20/2006
	 *									"l, F nS, Y"	=> Friday, August 20th, 2006
	 *
	 *								The following formatting codes are supported:
	 *									\	Escape character, skip it and insert the next char directly
	 *									d	Day of the month, 2 digits with leading zeros (01 to 31)
	 *									D	A textual representation of a day, three letters (Mon through Sun)
	 *									l	A full textual representation of the day of the week (Monday through Sunday)
	 *									j	Day of the month without leading zeros (1 to 31)
	 *									N	ISO-8601 numeric representation of the day of the week (1 (for Monday) through 7 (for Sunday))
	 *									S	English ordinal suffix for the day of the month, 2 characters (st, nd, rd or th. Works well with j)
	 *									w	Numeric representation of the day of the week (0 (for Sunday) through 6 (for Saturday))
	 *									z	The day of the year (starting from 0)	(0 through 365)
	 *									F	A full textual representation of a month, such as January or March (January through December)
	 *									m	Numeric representation of a month, with leading zeros (01 through 12)
	 *									M	A short textual representation of a month, three letters (Jan through Dec)
	 *									n	Numeric representation of a month, without leading zeros (1 through 12)
	 *									t	Number of days in the given month (28 through 31)
	 *									Y	A full numeric representation of a year, 4 digits (Examples: 1999 or 2003)
	 *									y	A two digit representation of a year (Examples: 99 or 03)
	 *									a	Lowercase Ante meridiem and Post meridiem (am or pm)
	 *									A	Uppercase Ante meridiem and Post meridiem (AM or PM)
	 *									g	12-hour format of an hour without leading zeros (1 through 12)
	 *									G	24-hour format of an hour without leading zeros (0 through 23)
	 *									h	12-hour format of an hour with leading zeros (01 through 12)
	 *									H	24-hour format of an hour with leading zeros (00 through 23)
	 *									i	Minutes with leading zeros (00 to 59)
	 *									s	Seconds, with leading zeros (00 through 59)
	 *									u	Milliseconds (Example: 54321)
	 *									r	RFC 2822 formatted date (Example: Thu, 21 Dec 2000 16:01:07 +0200)
	 *									U	Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)
	 *
	 *								The following fomatting chars supported by PHP are currently _NOT_ supported:
	 *									W	ISO-8601 week number of year, weeks starting on Monday (Example: 42 (the 42nd week in the year))
	 *									L	Whether it's a leap year (1 if it is a leap year, 0 otherwise)
	 *									o	ISO-8601 year number. This has the same value as Y, except that if the ISO week number (W)
	 *										belongs to the previous or next year, that year is used instead. (Examples: 1999 or 2003)
	 *									B	Swatch Internet time (000 through 999)
	 *									e	Timezone identifier (added in PHP 5.1.0)	Examples: UTC, GMT, Atlantic/Azores
	 *									I	Whether or not the date is in daylight saving time	1 if Daylight Saving Time, 0 otherwise.
	 *									O	Difference to Greenwich time (GMT) in hours	Example: +0200
	 *									P	Difference to Greenwich time (GMT) with colon between hours and minutes (added in PHP 5.1.3)	Example: +02:00
	 *									T	Timezone abbreviation	Examples: EST, MDT ...
	 *									Z	Timezone offset in seconds. The offset for timezones west of UTC is always negative, and for those east of UTC is always positive.	-43200 through 50400
	 *									c	ISO 8601 date (added in PHP 5)	2004-02-12T15:19:21+00:00
	 *
	 * @return	String	The formatted date
	 */
	Date.prototype.format = function(fmtStr) {
		fmtStr = fmtStr.toString();

		var y = this.getFullYear();
		var m = this.getMonth();
		var d = this.getDate();
		var dow = this.getDay();
		var hour = this.getHours();
		var min = this.getMinutes();
		var sec = this.getSeconds();
		var ms = this.getMilliseconds();

		var rv = '';
		for (var i = 0; i < fmtStr.length; ++i) {
			var ch = fmtStr.substr(i, 1);
			switch (ch) {
			// Escape character, skip it and insert the next char directly
			case '\\':
				++i;
				ch = fmtStr.substr(i, 1);
				break;

			// Day of the month, 2 digits with leading zeros (01 to 31)
			case 'd':
				if (d < 10)
					ch = '0' + d;
				else
					ch = d;
				break;

			// A textual representation of a day, three letters (Mon through Sun)
			case 'D':
				ch = Date.ShortDaysOfWeek[dow];
				break;

			// A full textual representation of the day of the week (Monday through Sunday)
			case 'l':
				ch = Date.DaysOfWeek[dow];
				break;

			// Day of the month without leading zeros (1 to 31)
			case 'j':
				ch = d;
				break;

			// ISO-8601 numeric representation of the day of the week (1 (for Monday) through 7 (for Sunday))
			case 'N':
				if (dow == 0)
					ch = 7;
				else
					ch = dow;
				break;

			// English ordinal suffix for the day of the month, 2 characters (st, nd, rd or th. Works well with j)
			case 'S':
				// 1st, 2nd, 3rd, 4th-10th
				// 11-20 all th
				switch (d%100<20 ? d%100 : d % 10) {
				case 1:
					ch = 'st';
					break;
				case 2:
					ch = 'nd';
					break;
				case 3:
					ch = 'rd';
					break;
				default:
					ch = 'th';
				} // switch
				break;

			// Numeric representation of the day of the week (0 (for Sunday) through 6 (for Saturday))
			case 'w':
				ch = dow;
				break;

			// The day of the year (starting from 0)	(0 through 365)
			case 'z':
				var z = 0;
				for (var i = 0; i < m; i ++) {
					var tmpDate = new Date(y, i + 1, 0, 12, 0, 0);
					z += tmpDate.getDate();
				}
				z += d - 1;
				ch = z;
				break;

/*
			// ISO-8601 week number of year, weeks starting on Monday (Example: 42 (the 42nd week in the year))
			case 'W':
				throw "Date.format(): Unsupported format char 'W'";
				break;
*/

			// A full textual representation of a month, such as January or March (January through December)
			case 'F':
				ch = Date.Months[m];
				break;

			// Numeric representation of a month, with leading zeros (01 through 12)
			case 'm':
				ch = m + 1;
				if (ch < 10)
					ch = '0' + ch;
				break;

			// A short textual representation of a month, three letters (Jan through Dec)
			case 'M':
				ch = Date.ShortMonths[m];
				break;

			// Numeric representation of a month, without leading zeros (1 through 12)
			case 'n':
				ch = m + 1;
				break;

			// Number of days in the given month (28 through 31)
			case 't':
				var d = new Date(y, m + 1, 0, 12, 0, 0);
				ch = d.getDate();
				break;

/*
			// Whether it's a leap year (1 if it is a leap year, 0 otherwise)
			case 'L':
				break;

			// ISO-8601 year number. This has the same value as Y, except that if the ISO week number (W)
			// belongs to the previous or next year, that year is used instead. (Examples: 1999 or 2003)
			case 'o':
				break;
*/

			// A full numeric representation of a year, 4 digits (Examples: 1999 or 2003)
			case 'Y':
				ch = y;
				break;

			// A two digit representation of a year (Examples: 99 or 03)
			case 'y':
				ch = y % 100;
				if (ch < 10) ch = '0' + ch;
				break;

			// Lowercase Ante meridiem and Post meridiem (am or pm)
			case 'a':
				ch = ((hour < 12) ? 'am' : 'pm');
				break;

			// Uppercase Ante meridiem and Post meridiem (AM or PM)
			case 'A':
				ch = ((hour < 12) ? 'AM' : 'PM');
				break;

/*
			// Swatch Internet time (000 through 999)
			case 'B':
				break;
*/

			// 12-hour format of an hour without leading zeros (1 through 12)
			case 'g':
				ch = hour % 12;
				if (ch == 0) ch = 12;
				break;

			// 24-hour format of an hour without leading zeros (0 through 23)
			case 'G':
				ch = hour;
				break;

			// 12-hour format of an hour with leading zeros (01 through 12)
			case 'h':
				ch = hour % 12;
				if (ch == 0) ch = 12;
				if (ch < 10) ch = '0' + ch;
				break;

			// 24-hour format of an hour with leading zeros (00 through 23)
			case 'H':
				ch = hour;
				if (ch < 10) ch = '0' + ch;
				break;

			// Minutes with leading zeros (00 to 59)
			case 'i':
				ch = min;
				if (ch < 10) ch = '0' + ch;
				break;

			// Seconds, with leading zeros (00 through 59)
			case 's':
				ch = sec;
				if (ch < 10) ch = '0' + ch;
				break;

			// Milliseconds (Example: 54321)
			case 'u':
				ch = ms;
				break;

/*
e	Timezone identifier (added in PHP 5.1.0)	Examples: UTC, GMT, Atlantic/Azores
I (capital i)	Whether or not the date is in daylight saving time	1 if Daylight Saving Time, 0 otherwise.
O	Difference to Greenwich time (GMT) in hours	Example: +0200
P	Difference to Greenwich time (GMT) with colon between hours and minutes (added in PHP 5.1.3)	Example: +02:00
T	Timezone abbreviation	Examples: EST, MDT ...
Z	Timezone offset in seconds. The offset for timezones west of UTC is always negative, and for those east of UTC is always positive.	-43200 through 50400
c	ISO 8601 date (added in PHP 5)	2004-02-12T15:19:21+00:00
*/

			// RFC 2822 formatted date (Example: Thu, 21 Dec 2000 16:01:07 +0200)
			case 'r':
				ch = this.toUTCString();
				break;

			// Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)
			case 'U':
				ch = Math.round(ms / 1000);
				break;
			} // switch
			rv += ch;
		} // for

		return rv;
	}; // Date.prototype.format(fmtStr)

} // if (!common)

function emailCheck (emailStr) {

/* The following variable tells the rest of the function whether or not
to verify that the address ends in a two-letter country or well-known
TLD.  1 means check it, 0 means don't. */

var checkTLD=1;

/* The following is the list of known TLDs that an e-mail address must end with. */

var knownDomsPat=/^(com|net|org|edu|int|mil|gov|arpa|biz|aero|name|coop|info|pro|museum)$/;

/* The following pattern is used to check if the entered e-mail address
fits the user@domain format.  It also is used to separate the username
from the domain. */

var emailPat=/^(.+)@(.+)$/;

/* The following string represents the pattern for matching all special
characters.  We don't want to allow special characters in the address. 
These characters include ( ) < > @ , ; : \ " . [ ] */

var specialChars="\\(\\)><@,;:\\\\\\\"\\.\\[\\]";

/* The following string represents the range of characters allowed in a 
username or domainname.  It really states which chars aren't allowed.*/

var validChars="\[^\\s" + specialChars + "\]";

/* The following pattern applies if the "user" is a quoted string (in
which case, there are no rules about which characters are allowed
and which aren't; anything goes).  E.g. "jiminy cricket"@disney.com
is a legal e-mail address. */

var quotedUser="(\"[^\"]*\")";

/* The following pattern applies for domains that are IP addresses,
rather than symbolic names.  E.g. joe@[123.124.233.4] is a legal
e-mail address. NOTE: The square brackets are required. */

var ipDomainPat=/^\[(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\]$/;

/* The following string represents an atom (basically a series of non-special characters.) */

var atom=validChars + '+';

/* The following string represents one word in the typical username.
For example, in john.doe@somewhere.com, john and doe are words.
Basically, a word is either an atom or quoted string. */

var word="(" + atom + "|" + quotedUser + ")";

// The following pattern describes the structure of the user

var userPat=new RegExp("^" + word + "(\\." + word + ")*$");

/* The following pattern describes the structure of a normal symbolic
domain, as opposed to ipDomainPat, shown above. */

var domainPat=new RegExp("^" + atom + "(\\." + atom +")*$");

/* Finally, let's start trying to figure out if the supplied address is valid. */

/* Begin with the coarse pattern to simply break up user@domain into
different pieces that are easy to analyze. */

var matchArray=emailStr.match(emailPat);

if (matchArray==null) {

/* Too many/few @'s or something; basically, this address doesn't
even fit the general mould of a valid e-mail address. */

alert("Email address seems incorrect (check @ and .'s)");
return false;
}
var user=matchArray[1];
var domain=matchArray[2];

// Start by checking that only basic ASCII characters are in the strings (0-127).

for (i=0; i<user.length; i++) {
if (user.charCodeAt(i)>127) {
alert("Ths username contains invalid characters.");
return false;
   }
}
for (i=0; i<domain.length; i++) {
if (domain.charCodeAt(i)>127) {
alert("Ths domain name contains invalid characters.");
return false;
   }
}

// See if "user" is valid 

if (user.match(userPat)==null) {

// user is not valid

alert("The username doesn't seem to be valid.");
return false;
}

/* if the e-mail address is at an IP address (as opposed to a symbolic
host name) make sure the IP address is valid. */

var IPArray=domain.match(ipDomainPat);
if (IPArray!=null) {

// this is an IP address

for (var i=1;i<=4;i++) {
if (IPArray[i]>255) {
alert("Destination IP address is invalid!");
return false;
   }
}
return true;
}

// Domain is symbolic name.  Check if it's valid.
 
var atomPat=new RegExp("^" + atom + "$");
var domArr=domain.split(".");
var len=domArr.length;
for (i=0;i<len;i++) {
if (domArr[i].search(atomPat)==-1) {
alert("The domain name does not seem to be valid.");
return false;
   }
}

/* domain name seems valid, but now make sure that it ends in a
known top-level domain (like com, edu, gov) or a two-letter word,
representing country (uk, nl), and that there's a hostname preceding 
the domain or country. */

if (checkTLD && domArr[domArr.length-1].length!=2 && 
domArr[domArr.length-1].search(knownDomsPat)==-1) {
alert("The address must end in a well-known domain or two letter " + "country.");
return false;
}

// Make sure there's a host name preceding the domain.

if (len<2) {
alert("This address is missing a hostname!");
return false;
}

// If we've gotten this far, everything's valid!
return true;
}


	/***********************************************

	* CSS Horizontal List Menu- by JavaScript Kit (www.javascriptkit.com)
	* Menu interface credits: http://www.dynamicdrive.com/style/csslibrary/item/glossy-vertical-menu/ 
	* This notice must stay intact for usage
	* Visit JavaScript Kit at http://www.javascriptkit.com/ for this script and 100s more

	***********************************************/
var cssmenuids=["cssmenu1"] //Enter id(s) of CSS Horizontal UL menus, separated by commas
var csssubmenuoffset=-1 //Offset of submenus from main menu. Default is 0 pixels.

function createcssmenu2(){
for (var i=0; i<cssmenuids.length; i++){
  var ultags=document.getElementById(cssmenuids[i]).getElementsByTagName("ul")
    for (var t=0; t<ultags.length; t++){
			ultags[t].style.top=ultags[t].parentNode.offsetHeight+csssubmenuoffset+"px"
    	var spanref=document.createElement("span")
			spanref.className="arrowdiv"
			spanref.innerHTML="&nbsp;&nbsp;&nbsp;&nbsp;"
			ultags[t].parentNode.getElementsByTagName("a")[0].appendChild(spanref)
    	ultags[t].parentNode.onmouseover=function(){
					this.style.zIndex=100
    	this.getElementsByTagName("ul")[0].style.visibility="visible"
					this.getElementsByTagName("ul")[0].style.zIndex=0
    	}
    	ultags[t].parentNode.onmouseout=function(){
					this.style.zIndex=0
					this.getElementsByTagName("ul")[0].style.visibility="hidden"
					this.getElementsByTagName("ul")[0].style.zIndex=100
    	}
    }
  }
}

var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));

try {
var pageTracker = _gat._getTracker("UA-13073861-1");
pageTracker._trackPageview();
} catch(err) {}

function getQueryVariable(variable) {
  var query = window.location.search.substring(1);
  var vars = query.split("&");
  for (var i=0;i<vars.length;i++) {
    var pair = vars[i].split("=");
    if (pair[0] == variable) {
      return pair[1];
    }
  }
//  alert('Query Variable ' + variable + ' not found');
return null;
}
 