// ===========================================================
//		UTILITY FUNCTIONS
// ===========================================================
		
	function popup(pageURL, width, height, targetName)
	{
		targetName = targetName || 'popup';
		var popup = window.open(pageURL, targetName, 'toolbars=0,scrollbars=1,location=0,statusbars=0,menubars=0,resizable=1,width='+(width ? width : 600)+',height='+(height ? height : 420));
		return false;
	}
	
	// The left and right RegExp contexts are only set after a successful match... so an unsuccessful match doesn't set them to null, like I thought...
	// This sets them to empty strings which test false.
	function resetRegExpContexts()
	{
		" ".search(/./);
	}

// ===========================================================
//		STRING FUNCTIONS
// ===========================================================
	
	// RETURN NULL IF THE STRING'S VALUE IS UNDEFINED, EMPTY, OR NULL
	//
	function testNullString(str, strAltReturn){
		var str	=	String(str);
		var strAltReturn;
		
		if(strAltReturn == undefined || strAltReturn == null)
			strReturn	=	null;
		else
			strReturn	=	strAltReturn;
		
		if(str == "undefined" || str == "null" || str == "")
			return strReturn;
		else
			return str;	
	}

	function cstr(str){ return testNullString(str, ""); }

	// RETURNS A "SAFE" TO DISPLAY STRING
	//
	function getSafeHtml(str, intHtmlAction, isEncodeQuotes, isEncodeAmpersands, length)
	{
		var str	=	testNullString(str, "");
		if (!str)
			return str;
	
		// INTHTMLACTION == 1: ENCODE HTML
		if (intHtmlAction && intHtmlAction != 2)
		{
			str	=	Server.HTMLEncode(str);
		}
		// INTHTMLACTION == 2: STRIP HTML
		else if (intHtmlAction == 2)
		{
			// REPLACE BLOCKS OF HTML
			str	=	str.replace(/<(?:(?:.|\n)*\b)?((?:no)?script|object|applet|iframe|map|noframes|head)(?:\b(?:.|\n)*)?>(?:.|\n)*?<\/(?:(?:.|\n)*\b)?\1(?:\b(?:.|\n)*)?>/gi, "");
			// REPLACE PARAGRAPHS AND LINE BREAKS WITH NEW LINE CHARS (IN CASE OF PLAIN TEXT E-MAILS)
			str	=	str.replace(/<\s*\/\s*p\s*>[\r\n]*/gi, "\r\n\r\n").replace(/<\s*(?:\/\s*(?:li|ul|div)|(?:br|hr)(?:\s*\/)?)\s*>[\r\n]*/gi, "\r\n");
			// REPLACE BULLETS AND NUMBERED LISTS
			str	=	str.replace(/<\s*li\s*>/gi, "* ");
			// THEN REPLACE ALL OTHER TAGS WITH NOTHING
			str	=	str.replace(/<[^>]+?>[\r\n]*/g, "");
		}
		if (isEncodeAmpersands)
		{
			str	=	str.replace(/&(?![^\s];)/gi, "&amp;");
		}
		if (isEncodeQuotes)
		{
			str	=	str.replace(/"/g, "&quot;").replace(/'/g, "&#39;");
		}
		if (length)
		{
			return str.substr(0, length)+ ((str.length > length) ? "..." : ""); 
		}
		return str;
	}

	function changeURL(strURL, strQueryStringChanges)
	{
		var strItem, strItemValue, reItemValue, strHash;
		var strURL					=	strURL;
		var isQueryString			=	(strURL.indexOf("?") != -1);
		if (strURL.indexOf("#") != -1)
		{
			strHash	=	strURL.substring(strURL.indexOf("#"));
			strURL	=	strURL.substring(0,strURL.indexOf("#"));
		}
		if (strQueryStringChanges.indexOf("#") != -1)
		{
			strHash						=	strQueryStringChanges.substring(strQueryStringChanges.indexOf("#"));
			strQueryStringChanges	=	strQueryStringChanges.substring(0,strQueryStringChanges.indexOf("#"));
		}
		var aQueryStringChanges	=	strQueryStringChanges.split("&");
		
		// CHECK FOR EXISTING QUERYSTRING
		if (isQueryString)
		{
			var strScriptName		=	strURL.substring(0, strURL.indexOf("?"));
			var strQueryString	=	strURL.substring(strURL.indexOf("?"));
		}
		else
		{
			var strScriptName		=	strURL;
			var strQueryString	=	"";
		}
		
		for (var counter=0; counter < aQueryStringChanges.length; counter++)
		{
			strItemValue	=	String(aQueryStringChanges[counter]);
			strItem			=	strItemValue.substring(0, strItemValue.indexOf("="));
			reItemValue		=	new RegExp("([\?&])"+ strItem +"=[^&]*", "i");
			reItemValues	=	new RegExp("([\?&])"+ strItem +"=[^&]*", "gi");
			
			// CHECK FOR BLANK VALUES
			if(strItemValue.indexOf("=") + 1 == strItemValue.length)
				strItemValue	=	"";

			if (strQueryString.search(reItemValue) != -1)
			{
				if (strItemValue.indexOf("order=") != -1 && strQueryString.indexOf(strItemValue.replace(/\*/g,"")) != -1)
				{
					if (strItemValue.indexOf("*ASC*") != -1)
						strItemValue	=	strItemValue.replace(/\*ASC\*/gi, "DESC");
					else if (strItemValue.indexOf("*DESC*") != -1)
						strItemValue	=	strItemValue.replace(/\*DESC\*/gi, "ASC");
				}
				// CHECK IF WE SHOULD ALLOW MULTIPLE VALUES
				var arrMultipleFlag	=	strQueryStringChanges.match(reItemValues);
				if (arrMultipleFlag && arrMultipleFlag.length >= 2)
					strQueryString		+=	String("&" + strItemValue);
				else
					strQueryString		=	strQueryString.replace(reItemValue, "$1"+ strItemValue);
			}
			else if(strItemValue != "" && !isQueryString)
			{
				strQueryString		+=	String("?" + strItemValue);
				isQueryString		=	true;
			}
			else if(strItemValue != "" && isQueryString)
			{
				strQueryString		+=	String("&" + strItemValue);
			}
		}

		// REPLACE TRAILING FIGURES, AND DOUBLE FIGURES
		strQueryString	=	strQueryString.replace(/\*ASC\*/g, "ASC");
		strQueryString	=	strQueryString.replace(/\*DESC\*/g, "DESC");
		strQueryString	=	strQueryString.replace(/^\?&+/, "?");
		strQueryString	=	strQueryString.replace(/&{2,}/g, "&");
		strQueryString	=	strQueryString.replace(/(?:&|\?)$/, "");
		
		strURL	=	strScriptName.concat(strQueryString);
		
		if (strHash)
			strURL	=	changeURL(changeURL(strURL, "1="), "1=1").concat(strHash);

		return strURL;
	}

// ===========================================================
//		MATH AND NUMBER FORMATTING FUNCTIONS
// ===========================================================

	// UPDATES MATH.ROUND TO INCLUDE DECIMAL PLACES
	//
	function math_round(expression, decimalplaces, isEurope){
		var multiplier;
	
		if(decimalplaces != null && decimalplaces != 0)
			multiplier = Math.pow(10, decimalplaces);
		else
			multiplier	=	1;
	
		strExpression	=	String(expression);
		
		if(isEurope){
	
			if(strExpression.indexOf(".") != -1)
				strExpression	=	strExpression.replace(/\./g, "");
			
			expression	=	strExpression.replace(/,/, ".").replace(/,/g, "");
				
		}else{
			if(strExpression.indexOf(",") != -1)
				expression	=	strExpression.replace(/,/g, "");
		}
		
		if(isNaN(parseFloat(expression)))
			expression	=	0;
		else
			expression	=	parseFloat(expression) * 1;
		
		return Math.round(expression * multiplier)/multiplier;
	}
	
	// FORMAT THE NUMBER TO SHOW 2 DIGITS PAST THE DECIMAL PLACE
	//
	function priceFormat(num, isSplitThousands){
		
		var num,strNum,intNum;
		
		num		=	math_round(math_round(num, 2)+.001, 3);
		
		if (num == .001)
			return "0.00";
	
		strNum	=	String(num);
		intNum	=	Math.floor(num);
		
		if (!isSplitThousands)
			return strNum.substring(0, strNum.indexOf(".") + 3);
		else
			return splitThousands(intNum, ",") + strNum.substring(strNum.length-4, strNum.length-1);
	}
	
	// FORMAT INPUT NUMBER USING SEPARATOR TO MARK THOUSANDS
	//
	function splitThousands(input, strSeparator, numDigitsAfterDecimal, incLeadingDig, parenForNegatives){
		var retVal = numberFormat(input, strSeparator, numDigitsAfterDecimal, incLeadingDig, parenForNegatives);
		return testNullString(retVal, "");
	}
	
	function numberFormat(origInput, strSeparator, numDigitsAfterDecimal, incLeadingDig, parenForNegatives) {
		if (origInput)
		{
			//european assumption -- that is, if the thousands separator is a period, the decimal sep will be a comma
			var decSeparator ="."
			if (strSeparator == ".")
			{
				decSeparator	=	",";
				
				var input		=	testNullString(origInput, "0");
				var intPart		=	numDigitsAfterDecimal ? origInput.replace(/,\d*$/, "").replace(/\D/g, "") : Math.abs(math_round(origInput, 0, true));
				var decimalPart	=	numDigitsAfterDecimal ? origInput.replace(/^.*,/, "").replace(/\D/g, "") : "";//make it a number like 0.232
				var output		=	"";
			}
			else
			{
				strSeparator	=	",";
				
				var input		=	testNullString(origInput, "0");
				var intPart		=	numDigitsAfterDecimal ? origInput.replace(/\.\d*$/, "").replace(/\D/g, "") : Math.abs(math_round(origInput));
				var decimalPart	=	numDigitsAfterDecimal ? origInput.replace(/^.*\./, "").replace(/\D/g, "") : "";//make it a number like 0.232
				var output		=	"";
			}
			
			if (!math_round(intPart))
			{
				if (!incLeadingDig)
					intPart = "";
				else
					intPart = "0";
			}
			else
			{
				intPart = String(intPart);
	
				for (var counter = intPart.length; counter > 0; counter--)
				{
					output = ((counter != 1 && counter != intPart.length + 1 && (intPart.length - counter + 1) % 3 == 0) ? strSeparator : "" ) + intPart.charAt(counter - 1) + output;
				}
			}
			
			if (numDigitsAfterDecimal)
			{
				if (math_round(decimalPart))
					decimalPart = math_round(decimalPart * Math.pow(10, numDigitsAfterDecimal - String(decimalPart).length));
				else
					decimalPart = String(Math.pow(10, numDigitsAfterDecimal)).substring(1);
				
				output += decSeparator + decimalPart;
			}
			
			//handle how negative numbers are displayed
			if (testNullString(origInput,"").search(/^-/) != -1 && output)
			{
				if (parenForNegatives)
					output = "("+(output.replace(/-/,""))+")";	
				else
					output = "-"+output;//add negative sign back if necessary	
			}
			return output;
		}
		return;
	}

	// RETURNS A STRING REPRESENTATION OF A NUMBER PADDED TO APPROPRIATE LENGTH
	// IF ORIGINAL LENGTH > DESIREDLENGTH, RETURNS TRUNCATED NUMBER REPRESENTATION
	//
	function padNumber(number, desiredLength, padBehind, padChar)
	{
		number = number + "";
		length = number.length;
		dLength = desiredLength - length;
		addStr = "";
		retVal = "";
		if (!padChar)
			padChar = "0";
		
		if (dLength <= 0)
		{
			if (padBehind)
				retVal = number.substring(0, desiredLength);
			else
				retVal = number.substring(length - desiredLength);
		}
		else
		{
			for (var i = 0; i < dLength; i ++)
				addStr += padChar;
			if (padBehind)
				retVal = number + addStr;
			else
				retVal = addStr + number;
		}
		return retVal;
	}