// ###########################################################
// � 2006 CDG
// All rights reserved.
// ###########################################################

// -----------------------------------------------------------
// Global array for mapping phone characters to digits.
// -----------------------------------------------------------
var globPhoneChars	= new Array;
globPhoneChars['a']	= '2';
globPhoneChars['b']	= '2';
globPhoneChars['c']	= '2';
globPhoneChars['d']	= '3';
globPhoneChars['e']	= '3';
globPhoneChars['f']	= '3';
globPhoneChars['g']	= '4';
globPhoneChars['h']	= '4';
globPhoneChars['i']	= '4';
globPhoneChars['j']	= '5';
globPhoneChars['k']	= '5';
globPhoneChars['l']	= '5';
globPhoneChars['m']	= '6';
globPhoneChars['n']	= '6';
globPhoneChars['o']	= '6';
globPhoneChars['p']	= '7';
globPhoneChars['r']	= '7';
globPhoneChars['s']	= '7';
globPhoneChars['t']	= '8';
globPhoneChars['u']	= '8';
globPhoneChars['v']	= '8';
globPhoneChars['w']	= '9';
globPhoneChars['x']	= '9';
globPhoneChars['y']	= '9';

// -----------------------------------------------------------
// Set the global date/time information.
// -----------------------------------------------------------
var globDate	= '';
var globMonth	= '';
var globYear	= '';
function setDateTime () {
	var locDateObj	= new Date();
	globDate		= locDateObj.getDate();
	globMonth		= locDateObj.getMonth();
	globYear		= locDateObj.getFullYear();
}
setDateTime();

// -----------------------------------------------------------
// PHP-equivalent mktime function.
// -----------------------------------------------------------
function mktime() {
	var d = new Date(), r = arguments, i = 0,
		e = ['Hours', 'Minutes', 'Seconds', 'Month', 'Date', 'FullYear'];
 
	for (i = 0; i < e.length; i++) {
		if (typeof r[i] === 'undefined') {
			r[i] = d['get' + e[i]]();
			r[i] += (i === 3); // +1 to fix JS months.
		} else {
			r[i] = parseInt(r[i], 10);
			if (isNaN(r[i])) {
				return false;
			}
		}
	}

	r[5] += (r[5] >= 0 ? (r[5] <= 69 ? 2e3 : (r[5] <= 100 ? 1900 : 0)) : 0);

	// Set year, month (-1 to fix JS months), and date.    // !This must come before the call to setHours!
	d.setFullYear(r[5], r[3] - 1, r[4]);
    
	// Set hours, minutes, and seconds.
	d.setHours(r[0], r[1], r[2]);
	
	// Divide milliseconds by 1000 to return seconds and drop decimal.
	// Add 1 second if negative or it'll be off from PHP by 1 second.
	return (d.getTime() / 1e3 >> 0) - (d.getTime() < 0);
}

// -----------------------------------------------------------
// PHP-equivalent is_string function.
// -----------------------------------------------------------
function is_string (mixed_var){
	return (typeof( mixed_var ) == 'string');
}

// -----------------------------------------------------------
// PHP-equivalent is_bool function.
// -----------------------------------------------------------
function is_bool (mixed_var) {
	return (typeof mixed_var === 'boolean');
}

// -----------------------------------------------------------
// PHP-equivalent array_diff function.
// -----------------------------------------------------------
function array_diff () {
	var arr1 = arguments[0], retArr = new Array;
	var k1 = '', i = 1, k = '', arr = new Array;
 
	arr1keys:
	for (k1 in arr1) {
		for (i = 1; i < arguments.length; i++) {
			arr = arguments[i];
			for (k in arr) {
				if (arr[k] === arr1[k1]) {
					// If it reaches here, it was found in at least one array, so try next value
					continue arr1keys; 
				}
			}
			retArr[k1] = arr1[k1];
		}
	}

	return retArr;
}

// -----------------------------------------------------------
// PHP-equivalent in_array function.
// -----------------------------------------------------------
function in_array (needle, haystack, argStrict) {
	var key = '', strict = !!argStrict; 
	if (strict) {
		for (key in haystack) {
			if (haystack[key] === needle) {
				return true;
			}
		}
	} else {
		for (key in haystack) {
			if (haystack[key] == needle) {
				return true;
			}
		}
	}
	return false;
}

// -----------------------------------------------------------
// PHP-equivalent array_intersect function.
// -----------------------------------------------------------
function array_intersect () {
	var arr1 = arguments[0], retArr = new Array;
	var k1 = '', arr = new Array, i = 0, k = '';    
	arr1keys:
	for (k1 in arr1) {
		arrs:
		for (i=1; i < arguments.length; i++) {
			arr = arguments[i];
			for (k in arr) {
				if (arr[k] === arr1[k1]) {
					if (i === arguments.length-1) {
						retArr[k1] = arr1[k1];
					}
					// If the innermost loop always leads at least once to an equal value, continue the loop until done
					continue arrs;
				}
			}
			// If it reaches here, it wasn't found in at least one array, so try next value
			continue arr1keys;
		}
	}
	return retArr;
}

// -----------------------------------------------------------
// PHP-equivalent strrev function.
// -----------------------------------------------------------
function strrev (string) {
	string	= string+''; 
	var grapheme_extend = /(.)([\uDC00-\uDFFF\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u065E\u0670\u06D6-\u06DC\u06DE-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u0901-\u0903\u093C\u093E-\u094D\u0951-\u0954\u0962\u0963\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B62\u0B63\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C01-\u0C03\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C82\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0D02\u0D03\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D82\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB\u0EBC\u0EC8-\u0ECD\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86\u0F87\u0F90-\u0F97\u0F99-\u0FBC\u0FC6\u102B-\u103E\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074\u1082-\u108D\u108F\u135F\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17B6-\u17D3\u17DD\u180B-\u180D\u18A9\u1920-\u192B\u1930-\u193B\u19B0-\u19C0\u19C8\u19C9\u1A17-\u1A1B\u1B00-\u1B04\u1B34-\u1B44\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAA\u1C24-\u1C37\u1DC0-\u1DE6\u1DFE\u1DFF\u20D0-\u20F0\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA66F-\uA672\uA67C\uA67D\uA802\uA806\uA80B\uA823-\uA827\uA880\uA881\uA8B4-\uA8C4\uA926-\uA92D\uA947-\uA953\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uFB1E\uFE00-\uFE0F\uFE20-\uFE26])/g;
	string	= string.replace(grapheme_extend, '$2$1'); // Temporarily reverse 
	return string.split('').reverse().join('');
}

// -----------------------------------------------------------
// PHP-equivalent substr_replace function.
// -----------------------------------------------------------
function substr_replace (str, replace, start, length) {
	if (start < 0) { // start position in str
		start = start + str.length;
	}
	length = length !== undefined ? length : str.length;
	if (length < 0) {
		length = length + str.length - start;
	}
    return str.slice(0, start)+replace.substr(0, length)+replace.slice(length)+str.slice(start+length);
}

// -----------------------------------------------------------
// PHP-equivalent array_shift function.
// -----------------------------------------------------------
function array_shift (inputArr) {
	shift = undefined, pr = '', allDigits = /^\d$/, int_ct=-1,
			_checkToUpIndices = function (arr, ct, key) {
            // Deal with situation, e.g., if encounter index 4 and try to set it to 0, but 0 exists later in loop (need to
            // increment all subsequent (skipping current key, since we need its value below) until find unused)
			if (arr[ct] !== undefined) {
				var tmp = ct;
				ct += 1;
				if (ct === key) {
					ct += 1;
				}
				ct = _checkToUpIndices(arr, ct, key);
				arr[ct] = arr[tmp];
				delete arr[tmp];
			}
			return ct;
		};

	if (inputArr.length === 0) {
		return null;
	}
	if (inputArr.length > 0) {
		return inputArr.shift();
	}
}

// -----------------------------------------------------------
// PHP-equivalent str_split function.
// -----------------------------------------------------------
function str_split (string, split_length) {
    if (split_length === null) {
		split_length = 1;
	}
    if (string === null || split_length < 1) {
		return false;
	}
	string += '';    var chunks = [], pos = 0, len = string.length;
	while (pos < len) {
		chunks.push(string.slice(pos, pos += split_length));
	}
	return chunks;
}

// -----------------------------------------------------------
// PHP-equivalent trim function.
// -----------------------------------------------------------
function trim ( str, charlist ) {
	str		= ltrim(str, charlist);
	str		= rtrim(str, charlist);
	return str;
}

// -----------------------------------------------------------
// PHP-equivalent ltrim function.
// -----------------------------------------------------------
function ltrim ( str, charlist ) {
	charlist	= !charlist ? ' \\s\u00A0' : (charlist+'').replace(/([\[\]\(\)\.\?\/\*\{\}\+\$\^\:])/g, '$1');
	var re		= new RegExp('^[' + charlist + ']+', 'g');
	return (str+'').replace(re, '');
}

// -----------------------------------------------------------
// PHP-equivalent rtrim function.
// -----------------------------------------------------------
function rtrim ( str, charlist ) {
    charlist	= !charlist ? ' \\s\u00A0' : (charlist+'').replace(/([\[\]\(\)\.\?\/\*\{\}\+\$\^\:])/g, '\\$1');
    var re 		= new RegExp('[' + charlist + ']+$', 'g');
    return (str+'').replace(re, '');
}

// -----------------------------------------------------------
// PHP-equivalent checkdate function.
// -----------------------------------------------------------
function checkdate ( m, d, y ) {
	return m > 0 && m < 13 && y > 0 && y < 32768 && d > 0 && d <= (new Date(y, m, 0)).getDate();
}

// -----------------------------------------------------------
// PHP-equivalent str_pad function.
// -----------------------------------------------------------
function str_pad (input, pad_length, pad_string, pad_type) {

	var half = '', pad_to_go;
	var str_pad_repeater = function (s, len) {
		var collect = '', i;
 
		while (collect.length < len) {
			collect += s;
		}
		
		collect = collect.substr(0,len); 
		return collect;
	};
 
	input += '';
	pad_string = pad_string !== undefined ? pad_string : ' ';
    
	if (pad_type != 'STR_PAD_LEFT'
	&&  pad_type != 'STR_PAD_RIGHT'
	&&  pad_type != 'STR_PAD_BOTH') {
		pad_type = 'STR_PAD_RIGHT';
	}
	
	if ((pad_to_go = pad_length - input.length) > 0) {
		if (pad_type == 'STR_PAD_LEFT') {
			input = str_pad_repeater(pad_string, pad_to_go) + input;
		} else if (pad_type == 'STR_PAD_RIGHT') {
			input = input + str_pad_repeater(pad_string, pad_to_go);
		} else if (pad_type == 'STR_PAD_BOTH') {
			half = str_pad_repeater(pad_string, Math.ceil(pad_to_go/2));
			input = half + input + half;
			input = input.substr(0, pad_length);
		}
    }
 
	return input;
}

// -----------------------------------------------------------
// PHP-equivalent sprintf function.
// -----------------------------------------------------------
function sprintf () {
	var regex = /%%|%(\d+\$)?([-+\'#0 ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([scboxXuidfegEG])/g;
	var a = arguments,
		i = 0,
		format = a[i++];

	// pad()
	var pad = function (str, len, chr, leftJustify) {
		if (!chr) {
			chr = ' ';
		}
		var padding = (str.length >= len) ? '' : Array(1 + len - str.length >>> 0).join(chr);
		return leftJustify ? str + padding : padding + str;
	};

	// justify()
	var justify = function (value, prefix, leftJustify, minWidth, zeroPad, customPadChar) {
		var diff = minWidth - value.length;
		if (diff > 0) {
			if (leftJustify || !zeroPad) {
				value = pad(value, minWidth, customPadChar, leftJustify);
			} else {
				value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length);
			}
		}
		return value;
	};

	// formatBaseX()
	var formatBaseX = function (value, base, prefix, leftJustify, minWidth, precision, zeroPad) {
		// Note: casts negative numbers to positive ones
		var number = value >>> 0;
		prefix = prefix && number && {
				'2': '0b',
				'8': '0',
				'16': '0x'
		}[base] || '';
		value = prefix + pad(number.toString(base), precision || 0, '0', false);
		return justify(value, prefix, leftJustify, minWidth, zeroPad);
	};

	// formatString()
	var formatString = function (value, leftJustify, minWidth, precision, zeroPad, customPadChar) {
		if (precision != null) {
			value = value.slice(0, precision);
		}
		return justify(value, '', leftJustify, minWidth, zeroPad, customPadChar);
	};

	// doFormat()
	var doFormat = function (substring, valueIndex, flags, minWidth, _, precision, type) {
		var number;
		var prefix;
		var method;
		var textTransform;
		var value;

		if (substring == '%%') {
			return '%';
		}

		// parse flags
		var leftJustify = false,
			positivePrefix = '',
			zeroPad = false,
			prefixBaseX = false,
			customPadChar = ' ';
		var flagsl = flags.length;
		for (var j = 0; flags && j < flagsl; j++) {
			switch (flags.charAt(j)) {
			case ' ':
				positivePrefix = ' ';
				break;
			case '+':
				positivePrefix = '+';
				break;
			case '-':
				leftJustify = true;
				break;
			case "'":
				customPadChar = flags.charAt(j + 1);
				break;
			case '0':
				zeroPad = true;
				break;
			case '#':
				prefixBaseX = true;
				break;
			}
		}

		// parameters may be null, undefined, empty-string or real valued
		// we want to ignore null, undefined and empty-string values
		if (!minWidth) {
			minWidth = 0;
		} else if (minWidth == '*') {
			minWidth = +a[i++];
		} else if (minWidth.charAt(0) == '*') {
			minWidth = +a[minWidth.slice(1, -1)];
		} else {
			minWidth = +minWidth;
		}

		// Note: undocumented perl feature:
		if (minWidth < 0) {
			minWidth = -minWidth;
			leftJustify = true;
		}

		if (!isFinite(minWidth)) {
			throw new Error('sprintf: (minimum-)width must be finite');
		}

		if (!precision) {
			precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type == 'd') ? 0 : undefined;
		} else if (precision == '*') {
			precision = +a[i++];
		} else if (precision.charAt(0) == '*') {
			precision = +a[precision.slice(1, -1)];
		} else {
			precision = +precision;
		}

		// grab value using valueIndex if required?
		value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++];

		switch (type) {
		case 's':
			return formatString(String(value), leftJustify, minWidth, precision, zeroPad, customPadChar);
		case 'c':
			return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad);
		case 'b':
			return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
		case 'o':
			return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
		case 'x':
			return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
		case 'X':
			return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad).toUpperCase();
		case 'u':
			return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
		case 'i':
		case 'd':
			number = (+value) | 0;
			prefix = number < 0 ? '-' : positivePrefix;
			value = prefix + pad(String(Math.abs(number)), precision, '0', false);
			return justify(value, prefix, leftJustify, minWidth, zeroPad);
		case 'e':
		case 'E':
		case 'f':
		case 'F':
		case 'g':
		case 'G':
			number = +value;
			prefix = number < 0 ? '-' : positivePrefix;
			method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())];
			textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2];
			value = prefix + Math.abs(number)[method](precision);
			return justify(value, prefix, leftJustify, minWidth, zeroPad)[textTransform]();
		default:
			return substring;
		}
	};

	return format.replace(regex, doFormat);
}

// -----------------------------------------------------------
// PHP-equivalent substr_count function.
// -----------------------------------------------------------
function substr_count( haystack, needle, offset, length ) {
    if (isNaN(offset)) {
        offset = 0;
    }
    if (isNaN(length)) {
        length = haystack.length - offset;
    }
    if (length <= 0 || (length + offset) > haystack) {
        return false
    } else {
        return haystack.substr(offset,length).split(needle).length - 1;
    }
}

// -----------------------------------------------------------
// Format a formatted field.
// -----------------------------------------------------------
function formatField(fieldName, fieldValue, previousValue, formatType, showEndOfTime, formatOptions, rptErrAndSetFocus) {

	// Trim the field values.
	fieldValue		= trim(fieldValue);
	previousValue	= trim(previousValue);
	
	// Refresh the current date/time.
	setDateTime();

	// Separate the format options.
	var formatOption	= formatOptions.split('|');

	if (rptErrAndSetFocus === undefined || rptErrAndSetFocus !== 'N') {
		rptErrAndSetFocus = true;
	} else {
		rptErrAndSetFocus = false;
	}
	
	// -----------------------------------------------------------
	// Format the value and print the result.
	// -----------------------------------------------------------
	var rawValue		= fieldValue;
	var displayValue	= fieldValue;
	var errorFocusField	= '';
	if (fieldValue.length	> 0) {
	
		switch (true) {
	
			// -----------------------------------------------------------
			// Format CURRENCY and DECIMAL fields.
			// -----------------------------------------------------------
			case formatType.substring(0,8)	== 'CURRENCY':
			case formatType.substring(0,8)	== 'SMALLINT':
			case formatType.substring(0,7)	== 'INTEGER':
			case formatType.substring(0,7)	== 'DECIMAL':
	
				switch (true) {
					case formatType.substring(0,8)	== 'CURRENCY':
						var precision	= 15;
						var decPos		= compCurrFormatDec;
						var minValue	= -999999999999.90;
						var maxValue	= +999999999999.90;
						break;
	
					case formatType.substring(0,8)	== 'SMALLINT':
						var precision	= 4;
						var decPos		= 0;
						var minValue	= -9999;
						var maxValue	= +9999;
						break;
						
					case formatType.substring(0,7)	== 'INTEGER':
						var precision	= 9;
						var decPos		= 0;
						var minValue	= -999999999;
						var maxValue	= +999999999;
						break;
						
					default:
						var precision	= 15;
						var decPos		= 0;
						var minValue	= -999999999999990;
						var maxValue	= +999999999999990;
						break;
				}
	
				if (formatType.indexOf('@')	> -1) {
					var formatPieces	= formatType.split('@');
					var piecesTotal		= formatPieces.length;
					if (formatType.substring(0,7)	== 'DECIMAL'
					||  formatType.substring(0,8)	== 'CURRENCY') {
						if (formatPieces[1].length	> 0) {
							var precision	= formatPieces[1];
						}
						if (formatPieces[2].length	> 0) {
							var decPos		= formatPieces[2];
						}
					}
					if (formatPieces[piecesTotal - 2].length	> 0) {
						var minValue		= parseFloat(formatPieces[piecesTotal - 2]);
					}
					if (formatPieces[piecesTotal - 1].length	> 0) {
						var maxValue		= parseFloat(formatPieces[piecesTotal - 1]);
					}
				} else {
					var formatPieces	= new Array();
					formatPieces[0]		= formatType;
					formatPieces[1]		= precision;
					formatPieces[2]		= decPos;
					formatPieces[3]		= minValue;
					formatPieces[4]		= maxValue;
					var piecesTotal		= formatPieces.length;
				}

				// -----------------------------------------------------------
				// Determine the length left of the decimal and modify default
				// min/max values as necessary.
				// -----------------------------------------------------------
				var leftLength		= precision - decPos;
				if (formatPieces[piecesTotal - 2].length	== 0) {
					var minValue	= str_pad('',leftLength,'9') + '.' + str_pad('',decPos,'9');
					minValue		= parseFloat(minValue) * -1;
				}
				if (formatPieces[piecesTotal - 1].length	== 0) {
					var maxValue	= str_pad('',leftLength,'9') + '.' + str_pad('',decPos,'9');
					maxValue		= parseFloat(maxValue);
				}

				if ((minValue * Math.pow(10,decPos))	< -999999999999990) {
					var minValue	= (minValue+'').substring(0,(minValue+'').length - 1) + '0';
				}
				if ((maxValue * Math.pow(10,decPos))	> 999999999999990) {
					var maxValue	= (maxValue+'').substring(0,(maxValue+'').length - 1) + '0';
				}

				var rawValue	= parseFloat(fieldValue.replace(/[^0-9\.\-]/g, ''));
				rawValue		= rawValue * Math.pow(10,decPos);
				rawValue		= Math.round(rawValue);
				rawValue		= rawValue / Math.pow(10,decPos);
				if (substr_count(fieldValue,'.')	> 1) {
					if (rptErrAndSetFocus == true) {
						alert('Please enter no more than one decimal position.');
						errorFocusField		= fieldName;
					}
					var rawValue		= fieldValue;
				}
				if (substr_count(fieldValue,'-')	> 1) {
					if (rptErrAndSetFocus == true) {
						alert('Please enter no more than one negative sign.');
						errorFocusField		= fieldName;
					}
					var rawValue		= fieldValue;
				}
				if (fieldValue.indexOf('-')		> -1
				&&  rawValue					> 0) {
					rawValue	= Math.abs(parseFloat(rawValue)) * -1;
				}
				if (rawValue	< minValue
				||  rawValue	> maxValue) {
					if (rawValue	< minValue) {
						fieldValue	= minValue;
					}
					if (rawValue	> maxValue) {
						fieldValue	= maxValue;
					}
					if (rptErrAndSetFocus == true) {
						if (minValue 	== maxValue) {
							alert('An invalid value has been specified.  The entered value must be ' + trim(sprintf('%' + leftLength + '.' + decPos + 'f',minValue)) + '.');
						} else {
							alert('Value out of range.  The entered value must be between ' + trim(sprintf('%' + leftLength + '.' + decPos + 'f',minValue)) + ' and ' + trim(sprintf('%' + leftLength + '.' + decPos + 'f',maxValue)) + '.');
						}
						errorFocusField		= fieldName;
					}
					rawValue			= fieldValue;
				}

				rawValue	= sprintf('%' + leftLength + '.' + decPos + 'f',rawValue);
				if (formatType.substring(0,8)	== 'CURRENCY') {
					var displayValue	= f_infr_format_currency(rawValue,formatType);
				} else {
					var displayValue	= f_infr_format_numeric(rawValue,formatType);
				}
				
				break;
	
			// -----------------------------------------------------------
			// Format DATE and TIMESTAMP fields.
			// -----------------------------------------------------------
			case formatType		== 'DATE':
			case formatType		== 'DATETIME':
			case formatType		== 'TIME':
			case formatType		== 'HRSMINS':

				// Initialize date/time values.
				var year		= 0;
				var month		= 0;
				var day			= 0;
				var hour		= 0;
				var min			= 0;
				var sec			= 0;
				
				// Ensure the date is formatted correctly, in case it is user-typed input.
				if (formatType		== 'DATE'
				||  formatType		== 'DATETIME') {
					
					// Split up the date format into pieces.
					var dateFormatPieces	= compDateFormat.split(compDateSeparator);
					
					// Split the value into pieces.  If the user didn't enter
					// delimiters, then process the date as a substring.
					var datePieces	= fieldValue.split(/[-:./ ]/);
					var dateValue	= datePieces.join('');
					var dateLength	= dateValue.length;
					if (datePieces.length	== 1
					|| 	datePieces.length	== 2) {
						
						// If a timestamp and only the date was entered, pad the rest
						// with zeroes.
						if (formatType		== 'DATETIME'
						&& (dateLength		== 8
						||  dateLength		== 6)) {
							fieldValue		= fieldValue + str_pad('',6,'0');
						}
						
						if ((formatType		== 'DATETIME'
						&&   dateLength		!= 17
						&&   dateLength		!= 14
						&&   dateLength		!= 12)
						||  (formatType		== 'DATE'
						&&   dateLength		!= 8
						&&   dateLength		!= 6)) {
							year		= previousValue.substring(0,4);
							month		= previousValue.substring(5,7);
							day			= previousValue.substring(8,10);
							if (rptErrAndSetFocus == true) {
								if (formatType	== 'DATETIME') {
									alert('Invalid date/time value of ' + trim(fieldValue) + '.');
									errorFocusField		= fieldName;
								} else {
									alert('Invalid date value of ' + trim(fieldValue) + '.');
									errorFocusField		= fieldName;
								}
							}
						} else {
							// Spin through the localization format and substring the 
							// pieces of the date.
							if (dateLength	== 12
							||  dateLength	== 6) {
								var yearLength	= 2;
								var addlIncr	= 0;
							} else {
								var yearLength	= 4;
								var addlIncr	= 2;
							}
							var addAddl		= false;
							var workIndex	= 0;
							while (dateFormatPieces[workIndex]) {
								switch (true) {
									case dateFormatPieces[workIndex]	== 'Y':
										addAddl		= true;
										year		= parseFloat(dateValue.substring(workIndex * 2,(workIndex * 2) + yearLength));
										break;
									case dateFormatPieces[workIndex]	== 'm':
										month		= parseFloat(dateValue.substring((workIndex * 2) + (addAddl ? addlIncr : 0),(workIndex * 2) + (addAddl ? addlIncr : 0) + 2));
										break;
									case dateFormatPieces[workIndex]	== 'd':
										day			= parseFloat(dateValue.substring((workIndex * 2) + (addAddl ? addlIncr : 0),(workIndex * 2) + (addAddl ? addlIncr : 0) + 2));
										break;
								}
								workIndex++;
							}
						}
					}

					// If the date isn't set, find it in the pieces.
					if (year	== 0
					&&  month	== 0
					&&  day		== 0) {
						// If the first position is 4 digits, assume Y-m-d.
						if (datePieces[0].length	== 4) {
							if (datePieces[0]) {
								year	= parseFloat(datePieces[0]);
							} else {
								year	= 0;
							}
							if (datePieces[1]) {
								month	= parseFloat(datePieces[1]);
							} else {
								month	= 0;
							}
							if (datePieces[2]) {
								day		= parseFloat(datePieces[2]);
							} else {
								day		= 0;
							}
						} else {
							var workIndex	= 0;
							while (dateFormatPieces[workIndex]) {
								// The application accepts the input format based on the 
								// localization settings.
								if (datePieces[workIndex]) {
									switch (true) {
										case dateFormatPieces[workIndex]	== 'Y':
											year	= parseFloat(datePieces[workIndex]);
											break;
										case dateFormatPieces[workIndex]	== 'm':
											month	= parseFloat(datePieces[workIndex]);
											break;
										case dateFormatPieces[workIndex]	== 'd':
											day		= parseFloat(datePieces[workIndex]);
											break;
									}
								}
								workIndex++;
							}
						}
					}
				} else {
					month	= 12;
					day		= 31;
					year	= 9999;
				}

				// If the time isn't set, find it in the pieces.
				if (hour	== 0
				&&  min		== 0
				&&  sec		== 0) {
					if (formatType	== 'DATETIME'
					||  formatType	== 'TIME'
					||  formatType	== 'HRSMINS') {
						var timePieces	= fieldValue.split(/[-:.\/ ]/);
						
						// If only a date is entered, zero-fill the time.
						if (formatType			== 'DATETIME'
						&&  timePieces.length	== 3) {
							timePieces[3]		= 0;
							timePieces[4]		= 0;
							timePieces[5]		= 0;
						}
						
						var timeWhole			= '';
						if (formatType			== 'DATETIME') {
							switch (true) {
								case timePieces.length	== 1:
									if (dateLength	== 14) {
										timeWhole	= timePieces[0].substring(8,14);
									}
									if (dateLength	== 12) {
										timeWhole	= timePieces[0].substring(6,12);
									}
									break;
								case timePieces.length	== 2:
									timeWhole		= timePieces[1];
									break;
								case timePieces.length	== 4:
									hour			= parseFloat(timePieces[3].substring(0,2));
									min				= parseFloat(timePieces[3].substring(2,4));
									sec				= parseFloat(timePieces[3].substring(4,6));
									break;
								case timePieces.length	== 6:
									hour			= parseFloat(timePieces[3]);
									min				= parseFloat(timePieces[4]);
									sec				= parseFloat(timePieces[5]);
									break;
							}
						} else {
							switch (true) {
								case timePieces.length	== 1:
									timeWhole		= timePieces[0];
									break;
								case timePieces.length	== 2:
									hour			= parseFloat(timePieces[0]);
									min				= parseFloat(timePieces[1]);
									sec				= 0;
									break;
								case timePieces.length	== 3:
									hour			= parseFloat(timePieces[0]);
									min				= parseFloat(timePieces[1]);
									sec				= parseFloat(timePieces[2]);
									break;
							}
						}
						
						if (timeWhole	!= '') {
							hour	= parseFloat(timeWhole.substring(0,2));
							min		= parseFloat(timeWhole.substring(2,4));
							sec		= parseFloat(timeWhole.substring(4,6));
						}
					}
				}

				if (formatType	== 'DATE'
				||  formatType	== 'DATETIME') {
					if (dateLength	== 12
					||  dateLength	== 6) {
						globYearStr	= globYear + '';
						if (globYearStr.substring(0,2) + str_pad(year,2,'0','STR_PAD_LEFT')	> globYear + 5) {
							year	= (parseFloat(globYearStr.substring(0,2)) - 1) + str_pad(year,2,'0','STR_PAD_LEFT');
						} else {
							year	= (parseFloat(globYearStr.substring(0,2))) + str_pad(year,2,'0','STR_PAD_LEFT');
						}
					}
				}

				if (checkdate(month,day,year)
				&&  hour		>= 0
				&&  (hour		<= 23 || (hour == 24 && formatType == 'HRSMINS'))
				&&  min			>= 0
				&&  min			<= 59
				&&  sec			>= 0
				&&  sec			<= 59
				&&  year		>= 0001
				&& (year		<= 2999
				||  year		== 9999)) {
					if (formatType	== 'TIME' || formatType == 'HRSMINS') {
						var dateFormatted	= sprintf('%04d-%02d-%02d-%02d.%02d.%02d',year,month,day,hour,min,sec);
						var rawValue		= f_infr_format_timestamp_with(formatType,'DB2', dateFormatted, true);
						var displayValue	= f_infr_format_timestamp_with(formatType,'DB2', dateFormatted, true);
					} else if (formatType	== 'DATETIME') {
						var dateFormatted	= sprintf('%04d-%02d-%02d-%02d.%02d.%02d',year,month,day,hour,min,sec);
						var rawValue		= f_infr_format_timestamp_with('DB2','DB2', dateFormatted, true);
						var displayValue	= f_infr_format_timestamp_with('TIMESTAMP','DB2', dateFormatted, (showEndOfTime == 'Y' ? true : false));
					} else {
						var dateFormatted	= sprintf('%04d-%02d-%02d',year,month,day);
						var rawValue		= f_infr_format_timestamp_with('DB2','Y-m-d', dateFormatted, true, false);
						var displayValue	= f_infr_format_date(dateFormatted, (showEndOfTime == 'Y' ? true : false), false);
					}
					if (rawValue			== previousValue) {
						fieldValue			= rawValue;
					}
				} else {
					if (formatType	== 'TIME' || formatType == 'HRSMINS') {
						var rawValue		= f_infr_format_timestamp_with(formatType,'DB2', previousValue, true);
						var displayValue	= f_infr_format_timestamp_with(formatType,'DB2', previousValue, true);
						if (rptErrAndSetFocus == true) {
							alert('Invalid time value of ' + trim(fieldValue) + '.');
							errorFocusField		= fieldName;
						}
					} else if (formatType	== 'DATETIME') {
						var rawValue		= f_infr_format_timestamp_with('DB2','DB2', previousValue, true);
						var displayValue	= f_infr_format_timestamp_with('TIMESTAMP','DB2', previousValue, (showEndOfTime == 'Y' ? true : false));
						if (rptErrAndSetFocus == true) {
							alert('Invalid date/time value of ' + trim(fieldValue) + '.');
							errorFocusField		= fieldName;
						}
					} else {
						var rawValue		= f_infr_format_timestamp_with('DB2','Y-m-d', previousValue, true);
						var displayValue	= f_infr_format_date(previousValue, (showEndOfTime == 'Y' ? true : false));
						if (rptErrAndSetFocus == true) {
							alert('Invalid date value of ' + trim(fieldValue) + '.');
							errorFocusField		= fieldName;
						}
					}
				}
				break;

			// -----------------------------------------------------------
			// Format SSN fields.
			// -----------------------------------------------------------
			case formatType			== 'SSN':
				var rawValue		= fieldValue.replace(/[^0-9]/g, '');
				rawValue			= str_pad(rawValue,9,'0','STR_PAD_LEFT');
				rawValue			= rawValue.substring(0,9);
				var displayValue	= f_infr_format_string_from_mask(rawValue,compSSNFormat);
				break;

			// -----------------------------------------------------------
			// Format PHONENUMBER fields.
			// -----------------------------------------------------------
			case formatType			== 'PHONENUMBER':
				// Spin through the characters and convert any alphabetic characters to the matching number on a touchtone phone.
				fieldValue			= ltrim(fieldValue,'0');
				var chars			= str_split(fieldValue,1);
				var newValue		= '';
				var char			= '';
				for (var i=0; i<chars.length; ++i) {
					if (chars[i]	< '0'
					||  chars[i]	> '9') {
						if (globPhoneChars[chars[i].toLowerCase()]	=== undefined) {
							newValue	= newValue + chars[i];
						} else {
							newValue	= newValue + globPhoneChars[chars[i].toLowerCase()];
						}
					} else {
						newValue		= newValue + chars[i];
					}
				}
				var rawValue		= newValue.replace(/[^0-9]/g, '');
				rawValue			= str_pad(rawValue,10,'0','STR_PAD_RIGHT');
				rawValue			= rawValue.substring(0,10);
				var displayValue	= f_infr_format_phone_number(rawValue);
				break;

			// -----------------------------------------------------------
			// Format generic mask fields.
			// -----------------------------------------------------------
			default:
				maskTrunc		= '';
				maskChar		= ' ';
				maskFmtChars	= '';
				if (formatOptions[0]) {
					maskTrunc	= formatOptions[0];
				}
				if (formatOptions[1]) {
					maskChar	= formatOptions[1];
				}
				if (formatOptions[2]) {
					formatOptions	= array_shift(formatOptions);
					formatOptions	= array_shift(formatOptions);
					maskFmtChars	= formatOptions;
				}
				var displayValue	= f_infr_format_string_from_mask(fieldValue,formatType,maskTrunc,maskChar,maskFmtChars,rawValue);
				break;
		}
	} else {
		if (formatType		== 'DATE') {
			var rawValue	= f_infr_format_timestamp_with('DB2','Y-m-d', '9999-12-31', true);
			var displayValue= f_infr_format_date('9999-12-31', (showEndOfTime == 'Y' ? true : false));
		}
		if (formatType		== 'DATETIME') {
			var rawValue	= f_infr_format_timestamp_with('DB2','Y-m-d', '9999-12-31', true);
			var displayValue= f_infr_format_timestamp_with('DB2','Y-m-d', '9999-12-31', (showEndOfTime == 'Y' ? true : false));
		}
	}

	if (displayValue.indexOf('NaN') > -1
	||  rawValue.indexOf('NaN')		> -1 ) {
		displayValue	= '';
		rawValue		= '';
	}

	setFormattedFieldValue(fieldName,displayValue,trim(rawValue),fieldValue,previousValue);
	if (errorFocusField	!= '') {
		setTimeout("fieldFocus('" + fieldName + "',false)",100);
	}
}

// -----------------------------------------------------------
// Format a monetary value for display. 
// -----------------------------------------------------------
function f_infr_format_currency (currency, mask) {
	if (mask	=== undefined) {
		mask	= '';
	}
	
	if (currency.length	<= 0) {
		return;
	}
	
	// Determine any special formatting rules.
	// The mask will be defined as CURRENCY@99@8@77@66 where:
	//		99 = max length (including decimals)
	//		 8 = decimal positions
	//		77 = minimum value (not validated here)
	//		66 = maximum value (not validated here)
	if (mask.indexOf('@')	> -1) {
		var maskPieces		= mask.split('@');
		if (maskPieces[1].length	> 0) {
			var precision	= parseFloat(maskPieces[1]); 
		} else {
			var precision	= 15;
		}
		if (maskPieces[2].length	> 0) {
			var decPos		= parseFloat(maskPieces[2]); 
		} else {
			var decPos		= 2; 
		}
		var leftLength		= precision - decPos;
		if (globConfigMode	== 'T') {
			var minValue	= -999999999999.99;
			var maxValue	= +999999999999.99;
			if (maskPieces[3].length	> 0) {
				minValue	= parseFloat(maskPieces[3]);
			}
			if (maskPieces[4].length	> 0) {
				maxValue	= parseFloat(maskPieces[4]);
			}
			if (minValue	> maxValue) {
				alert('Currency minimum/maximum value is invalid.  A currency field minimum of ' + trim(sprintf('%' + leftLength + '.' + decPos + 'f',minValue)) + ' cannot be greater than the field maximum of ' + trim(sprintf('%' + leftLength + '.' + decPos + 'f',maxValue)) + '.');
			}
		}
	} else {
		var leftLength		= 13;
		var decPos			= compCurrFormatDec;
	}
	
	// Round the field.
	currency		= parseFloat(currency.replace(/[^0-9\.\-]/g, ''));
	currency		= Math.round(currency * Math.pow(10,decPos)) / Math.pow(10,decPos);
	
	// Break down the field for evaluation.
	currency		= trim(sprintf('%' + leftLength + '.' + decPos + 'f',currency));
	var pieces		= (currency.replace('-','')).split('.');
	if (!pieces[1]) {
		pieces[1]	= '0';
	}

	// Format the left side of the decimal.
	pieces[0]		= strrev((strrev(pieces[0])).substring(0,leftLength));
	var length		= trim(pieces[0]).length;
	if (length						> 3
	&&  compCurrFormatSep.length	> 0) {
		var returnValue	= pieces[0];
		while (length	> 3) {
			length		= length - 3;
			returnValue	= returnValue.substring(0,length)
						+ compCurrFormatSep
						+ returnValue.substring(length);
		}
	} else {
		var returnValue	= pieces[0];
	}

	// Format the right side of the decimal.
	pieces[1]		= str_pad(pieces[1],decPos,'0','STR_PAD_RIGHT');
	var rightLength	= pieces[1].length;
	if (rightLength	> decPos) {
		pieces[1]	= sprintf('%0' + decPos + 'd',Math.round(pieces[1] / Math.pow(10,(rightLength - decPos))));
	}
	returnValue		= returnValue + '.' + pieces[1];
	
	// Determine the sign.
	if (currency.indexOf('-')	> -1
	||  parseFloat(currency)	< 0) {
		var sign	= compCurrFormatNegSign;
		returnValue	= returnValue.replace('-','');
	} else {
		var sign	= compCurrFormatPosSign;
	}

	// Put it all together.
	switch (compCurrFormat) {
		case '2':
			returnValue		= returnValue + sign + compCurrFormatSymbol;
			break;
		case '3':
			returnValue		= compCurrFormatSymbol + returnValue + sign;
			break;
		case '4':
			returnValue		= returnValue + compCurrFormatSymbol + sign;
			break;
		case '5':
			returnValue		= compCurrFormatSymbol + sign + returnValue;
			break;
		case '7':
			returnValue		= sign + returnValue + compCurrFormatSymbol;
			break;
		default:
			returnValue		= sign + compCurrFormatSymbol + returnValue;
			break;
	}

	// For Ecare, make sure the sign is always first for presentation purposes.
	if (ecareMode) {
		if (returnValue.indexOf('-')	> -1) {
			returnValue	= returnValue.replace('-','');
			returnValue	= '-' + returnValue;
		}
		if (returnValue.indexOf('+')	> -1) {
			returnValue	= returnValue.replace('+','');
			returnValue	= '+' + returnValue;
		}
	}
	
	return returnValue;
}

// -----------------------------------------------------------
// Format a general numeric value, adding commas and 
// expanding the decimal positions. 
// -----------------------------------------------------------
function f_infr_format_numeric (number, mask) {

	if (mask	=== undefined) {
		mask	= '';
	}
	
	if (number.length	<= 0) {
		return;
	}
	
	// Determine any special formatting rules.
	// The mask will be defined as DECIMAL@99@8@77@66 where:
	//		99 = max length (including decimals)
	//		 8 = decimal positions
	//		77 = minimum value (not validated here)
	//		66 = maximum value (not validated here)
	var maskPieces		= mask.split('@');
	var piecesTotal		= maskPieces.length;
	if (mask.indexOf('@')	> -1) {
		if (globConfigMode	== 'T') {
			var minValue	= -99999999999999;
			var maxValue	= +99999999999999;
			switch (true) {
				case maskPieces[0]	== 'SMALLINT':
					minValue	= -9999;
					maxValue	= +9999;
					break;
				case maskPieces[0]	== 'INTEGER':
					minValue	= -999999999;
					maxValue	= +999999999;
					break;
			}
			if (maskPieces[piecesTotal - 2].length	> 0) {
				minValue	= parseFloat(maskPieces[piecesTotal - 2]);
			}
			if (maskPieces[piecesTotal - 1].length	> 0) {
				maxValue	= parseFloat(maskPieces[piecesTotal - 1]);
			}
			if (minValue	> maxValue) {
				alert('Numeric minimum/maximum value is invalid.  A numeric field minimum of ' + trim(minValue) + ' cannot be greater than the field maximum of ' + trim(maxValue) + '.');
			}
		}
	}
	var leftLength		= 15;
	var decPos			= 0;
	switch (true) {
		case mask.substring(0,7)	== 'DECIMAL':
			if (mask.indexOf('@')	> -1) {
				leftLength		= maskPieces[1] - maskPieces[2];
				decPos			= maskPieces[2];
			}
			break;

		case mask.substring(0,8)	== 'SMALLINT':
			leftLength			= 5;
			decPos				= 0;
			break;

		case mask.substring(0,8)	== 'INTEGER':
			leftLength			= 11;
			decPos				= 0;
			break;
	}
	
	if (decPos	== '') {
		decPos	= 0;
	}
	
	// Round the field.
	var new_number		= parseFloat(number.replace(/[^0-9\.\-]/g, ''));
	new_number			= Math.round(new_number * Math.pow(10,decPos)) / Math.pow(10,decPos);
	
	// Break down the field for evaluation.
	new_number		= trim(sprintf('%' + leftLength + '.' + decPos + 'f',new_number));
	var pieces		= (new_number.replace('-','')).split('.');
	if (!pieces[1]) {
		pieces[1]	= '0';
	}

	// Format the left side of the decimal.
	pieces[0]		= strrev((strrev(pieces[0])).substring(0,leftLength));
	var length		= trim(pieces[0]).length;
	if (length						> 3
	&&  mask.substring(0,7)			== 'DECIMAL'
	&&  mask.substring(0,14)		!= 'DECIMALNOCOMMA') {
		var returnValue	= pieces[0];
		while (length	> 3) {
			length		= length - 3;
			returnValue	= returnValue.substring(0,length)
						+ ','
						+ returnValue.substring(length);
		}
	} else {
		var returnValue	= pieces[0];
	}

	// Format the right side of the decimal.
	if (decPos	> 0) {
		pieces[1]		= str_pad(pieces[1],decPos,'0','STR_PAD_RIGHT');
		var rightLength	= pieces[1].length;
		if (rightLength	> decPos) {
			pieces[1]	= sprintf('%0' + decPos + 'd',Math.round(pieces[1] / Math.pow(10,(rightLength - decPos))));
		}
		returnValue		= returnValue + '.' + pieces[1];
	} else {
		pieces[1]	= '';
	}
	
	// Determine the sign.
	if (number.indexOf('-')		> -1
	||  parseFloat(new_number)	< 0) {
		var sign	= '-';
		returnValue	= returnValue.replace('-','');
	} else {
		var sign	= '';
	}

	// Put it all together.
	returnValue		= sign + returnValue + '';
	
	return returnValue;
}

// -----------------------------------------------------------
// Format a date for display.
// -----------------------------------------------------------
function f_infr_format_date (time, show_end_of_time, convert_2dig_year) {

	if (show_end_of_time	=== undefined) {
		show_end_of_time	= false;
	}
	if (convert_2dig_year	=== undefined) {
		convert_2dig_year	= true;
	}
	
	if (time.length	== 0) {
		time	= '9999-12-31-00.00.00';
	}

	if (time.substring(0,10)	== '9999-12-31'
	&& !show_end_of_time) {
		var returnValue	= ' ';
	} else {
		var returnValue	= f_infr_format_timestamp_with('DATE','Y-m-d',time,show_end_of_time,convert_2dig_year);
	}

	return returnValue;
}

// -----------------------------------------------------------
// Format a telephone number for display. 
// -----------------------------------------------------------
function f_infr_format_phone_number (phoneNo) {
	phoneNo		= str_pad(trim(ltrim(trim(phoneNo),'0'),'.'),10,'0','STR_PAD_RIGHT');
	return f_infr_format_string_from_mask(phoneNo,compPhoneFormat,false,'*',new Array("(", ")", "/", "-", " ", "."));
}

// -----------------------------------------------------------
// Format a string from a format/mask and return the result; 
// see method definition for better examples and use.
// -----------------------------------------------------------
function f_infr_format_string_from_mask (str_to_fmt
                                        ,fmt_str
                                        ,trunc
                                        ,mask_char
                                        ,fmt_chars
                                        ,scrubbed_string) {

	if (trunc			=== undefined) {
		trunc			= false;
	}
	if (mask_char		=== undefined) {
		mask_char		= '*';
	}
	if (fmt_chars		=== undefined) {
		fmt_chars		= new Array('(',')','/','-',' ',':');
	}
	if (scrubbed_string	=== undefined) {
		scrubbed_string	= '';
	}
	
	// -----------------------------------------------------------
	// If we don't have proper input in some cases we need to just
	// get out
	// -----------------------------------------------------------
	if (!(is_string(str_to_fmt))) {
		return '';
	}
	if (!(is_string(fmt_str))) {
		return trim(str_to_fmt);
	}
	if (is_string(fmt_chars)) {
		fmt_chars	= new Array("(", ")", "/", "-", " ", ':');
	}
	if (in_array(mask_char, fmt_chars)) {
		mask_char	= '';
	}

	// -----------------------------------------------------------
	// For the remainder of the input we'll massage it to allow 
	// this process to continue
	// -----------------------------------------------------------
	str_to_fmt		= trim(str_to_fmt);
	fmt_str			= trim(fmt_str);

	if (!(is_bool(trunc))) {
		trunc		= false;
	}
	if ((!(is_string(mask_char))) || (mask_char.length > 1)) {
		mask_char	= '*';
	}

	// Drop formatting characters from the string to format (in case user tried typing them manually)
	var formatted_string	= array_diff(str_split(str_to_fmt, 1), fmt_chars);
	formatted_string		= formatted_string.join('');
	scrubbed_string			= formatted_string;

	// Drop formatting characters from format string (as we apply masking first)
	// We'll use the formatting chars after masking to apply any special formatting).
	var fmt_scrubbed_str 	= (array_diff(str_split(fmt_str, 1), fmt_chars)).join('');
		
	// If the format string (less formatting chars) is larger than the
	// string we are going to format, pad formatted string to the size of the format string (less formatting chars)
	// string as is.
	if (fmt_scrubbed_str.length > formatted_string.length) {
		formatted_string	= str_pad(formatted_string, fmt_scrubbed_str.length, '?', 'STR_PAD_RIGHT');
	}

	// -----------------------------------------------------------
	// MASKING LOGIC
	// -----------------------------------------------------------
	if (mask_char.length == 1 && in_array(mask_char, str_split(fmt_str,1))) {
		if (fmt_scrubbed_str.length < formatted_string.length) {
			if (fmt_scrubbed_str.length == (fmt_scrubbed_str.lastIndexOf(mask_char) + 1) ) {
				fmt_scrubbed_str	= str_pad(fmt_scrubbed_str, formatted_string.length, mask_char, 'STR_PAD_RIGHT');
			} else if (fmt_scrubbed_str.indexOf(mask_char)	== 0) {
				fmt_scrubbed_str	= str_pad(fmt_scrubbed_str, formatted_string.length, mask_char, 'STR_PAD_LEFT');
			} else {
				var pad_pos			= fmt_scrubbed_str.indexOf(mask_char);
				var pad_length		= formatted_string.length - fmt_scrubbed_str.length;
				var padded_mask		= str_pad('', pad_length, mask_char);
				fmt_scrubbed_str	= substr_replace(fmt_scrubbed_str, padded_mask, pad_pos, 0);
			}
		}

		// Convert the input string and the fmt string to an array used for substitution and substitution comparison.
		formatted_string_array	= str_split(formatted_string, 1);
		fmt_scrubbed_str_array	= str_split(fmt_scrubbed_str, 1);
		
		// Loop over scrubbed str array and for any value at a given index that is = the mask char
		// replace the same position in the formatted string array with the mask.
		for (var i=0, size=fmt_scrubbed_str_array.length; i<size; ++i) {
			if (fmt_scrubbed_str_array[i] == mask_char) {
				formatted_string_array[i] = mask_char;
			}
		}
		
		// Convert the formatted string array back into the formatted string
		formatted_string	= formatted_string_array.join('');
	}

	// -----------------------------------------------------------
	// FORMATTING LOGIC
	// -----------------------------------------------------------
	if ((fmt_chars.length > 0) && (array_intersect( str_split(fmt_str,1), fmt_chars).length > 0) ) {
		// We are formatting because we have a format char array
		// AND because we have identified that one or more of these formatting chars are in the format string

		// Convert the input string and the fmt string to an array used for substitution and substitution comparison.
		var formatted_string_array	= str_split(formatted_string, 1);
		var fmt_str_array			= str_split(fmt_str, 1);
		
		// Loop over format string and if find a format char add this to formatted string
		// For each pass that we don't find the format char, add in the value from the formatted string at the offset
		var offset 				= 0;
		var formatted_string	= '';
		for (var i = 0, size = fmt_str_array.length; i < size; ++i) {
			if (in_array(fmt_str_array[i], fmt_chars) == true) {
				// The element at $i from the format string is in the list of format characters
				// Therefore add it to the formatted string at a given position
				formatted_string	= formatted_string + fmt_str_array[i];
			} else {
				formatted_string	= formatted_string + formatted_string_array[offset];

				// adjust the offset
				++offset;
			}
		}
		for (var i=offset, size=formatted_string_array.length; i < size; ++i) {
			formatted_string		= formatted_string + formatted_string_array[i];
		}
	}

	// -----------------------------------------------------------
	// SHORTHAND LOGIC
	// -----------------------------------------------------------
	if (mask_char.length == 1 && trunc == true) {
		// We are going to remove multiple sequential
		// occurrences of the mask char in the formatting string.
		
		// Convert the formatted string into an array
		var formatted_string_array	= str_split(formatted_string, 1);
		
		// Loop through the array and write out only a single occurrence of a 'run' of mask chars.
		var found_mask			= false;
		var formatted_string	= '';
		var i					= 0;
		while (formatted_string_array[i]) {
			if ((found_mask == false) || (formatted_string_array[i] != mask_char)) {
				formatted_string	= formatted_string + formatted_string_array[i];
			}
			
			if (formatted_string_array[i] == mask_char) {
				found_mask		= true;
			} else {
				found_mask		= false;
			}
			i++;
		}		
	}
	
	// Return the string we have masked and formatted
	return formatted_string;
}

// -----------------------------------------------------------
// Format a timestamp into output format from input format 
// and input value.
// -----------------------------------------------------------
function f_infr_format_timestamp_with (output_format
								 	  ,input_format
									  ,input_value
									  ,show_end_of_time
									  ,convert_2dig_year) {

	if (show_end_of_time	=== undefined) {
		show_end_of_time	= false;
	}
	if (convert_2dig_year	=== undefined) {
		convert_2dig_year	= true;
	}
	
	// Provided user some 'simple' name formats that we need to translate here.
	// If not here, not a big deal, these are just the common use translations.
	switch (output_format) {
		case 'DB2':
			output_format	= 'Y-m-d-H.i.s';
			break;
		case 'DATE':
			output_format	= compDateFormat;
			break;
		case 'TIME':
			output_format	= 'H:i:s T';
			break;
		case 'HRSMINS':
			output_format	= 'H:i';
			break;
		case 'TIMESTAMP':
			output_format	= compDateFormat + ' H:i:s T';
			break;
		case 'YMD':
			output_format	= 'Ymd';
			break;
	}

	switch (input_format) {
		case 'DB2':
			input_format	= 'Y-m-d-H.i.s'; // Also this will convert from input format Y-m-d H:i:s
			break;
		case 'DATE':
			input_format	= compDateFormat;
			break;
		case 'TIME':
			input_format	= 'H:i:s';
			// Helper logic to allow input to be a bit more loose for this
			// input format as the assumption is this could be numeric stored in the DB.
			// if that is the case we don't want the developer to have to do this logic each time before calling this method.
			if (input_value.length > 0) {
				input_value			= input_value.replace(/\./g, ":");
				input_value_pieces	= input_value.split(":");
				if (input_value_pieces.length > 1) {
					// When time parts given (delimiter used such as colon), assume first part is left most piece (hours), and so on.
					// So... 1:2 becomes 01:02:00
					input_value	= '';
					for (i=0;i<input_value_pieces.length;i++) {
						if (i <= 2) {
							input_value	= input_value + ('00' + input_value_pieces[i]).substr((('00' + input_value_pieces[i]).length - 2), 2);
						} // else we have more than the number of pieces supported by this format, just ignore it.
					}
					if (input_value.length < 6) {
						input_value = (input_value + '000000').substr(0,6);
					}
				} else {
					// When given a whole number and if length is less than expected input, assume padding on the left with zeroes.
					// So... 12 becomes 00:00:12, 123 becomes 00:01:23, 12345 becomes 01:23:45
					if (input_value.length < 6) {
						input_value = ('000000'.substr(0,(6 - input_value.length))) + input_value;
					}
				}
				input_value	= input_value.substr(0, 2) + ':' + input_value.substr(2,2) + ':' + input_value.substr(4);
			}
			break;
		case 'HRSMINS':
			input_format	= 'H:i';
			// Helper logic to allow input to be a bit more loose for this
			// input format as the assumption is this could be numeric stored in the DB.
			// if that is the case we don't want the developer to have to do this logic each time before calling this method.
			if (input_value.length > 0) {
				input_value			= input_value.replace(/\./g, ":");
				input_value_pieces	= input_value.split(":");
				if (input_value_pieces.length > 1) {
					// When time parts given (delimiter used such as colon), assume first part is left most piece (hours), and so on.
					// So... 1:2 becomes 01:02
					input_value	= '';
					for (i=0;i<input_value_pieces.length;i++) {
						if (i <= 1) {
							input_value	= input_value + ('00' + input_value_pieces[i]).substr((('00' + input_value_pieces[i]).length - 2), 2);
						} // else we have more than the number of pieces supported by this format, just ignore it.
					}
					if (input_value.length < 4) {
						input_value = (input_value + '0000').substr(0,4);
					}
				} else {
					// When given a whole number and if length is less than expected input, assume padding on the left with zeroes.
					// So... 12 becomes 00:12, 123 becomes 01:23
					if (input_value.length < 4) {
						input_value = ('0000'.substr(0,(4 - input_value.length))) + input_value;
					}
				}
				input_value	= input_value.substr(0, 2) + ':' + input_value.substr(2);
			}
			break;
		case 'TIMESTAMP':
			input_format	= compDateFormat + ' H:i:s';
			break;
		case 'YMD':
			input_format	= 'Ymd';
			break;
	}

	// Default input value and format if we don't have something for both
	if (input_value.length		< 1
	||  input_format.length 	< 1) {
		// Default input value and format to end of time
		input_value		= '12-31-9999';
		input_format	= 'm-d-Y';
	}
	
	// Default the output format to the input format if the output format is empty
	if (output_format.length	< 1) {
		output_format	= input_format;
	}

	// Until we read the input format, default positions and lengths for location information
	var year_position		= -99;
	var year_length			= -99;
	var month_position		= -99;
	var month_length		= -99;
	var day_position		= -99;
	var day_length			= -99;
	var hour_position		= -99;
	var hour_length			= -99;
	var minute_position		= -99;
	var minute_length		= -99;
	var second_position		= -99;
	var second_length		= -99;
	var offset_position		= 0;

	// Interrogate the input format	
	var input_format_array		= str_split(input_format, 1);
	for (var i = 0, size=input_format_array.length; i<size; ++i) {
		switch (input_format_array[i]) {
			case 'Y':
				year_position		= offset_position;
				year_length			= 4;
				offset_position		= offset_position + year_length;
				break;
			case 'y':
				year_position		= offset_position;
				year_length			= 2;
				offset_position		= offset_position + year_length;
				break;
			case 'm':
				month_position		= offset_position;
				month_length		= 2;
				offset_position		= offset_position + month_length;
				break;
			case 'd':
				day_position		= offset_position;
				day_length			= 2;
				offset_position		= offset_position + day_length;
				break;
			case 'H':
				hour_position		= offset_position;
				hour_length			= 2;
				offset_position		= offset_position + hour_length;
				break;
			case 'h':
				hour_position		= offset_position;
				hour_length			= 2;
				offset_position		= offset_position + hour_length;
				break;
			case 'i':
				minute_position		= offset_position;
				minute_length		= 2;
				offset_position		= offset_position + minute_length;
				break;
			case 's':
				second_position		= offset_position;
				second_length		= 2;
				offset_position		= offset_position + second_length;
				break;
			case 'T':
				tz_position			= offset_position;
				tz_length			= 3;
				offset_position		= offset_position + tz_length;
				break;
			default:
				// Ignore, but advance offset (this is likely a space, -, /, :, or .
				offset_position		= offset_position + 1;
				break;
		}
	}
	
	// The input value must be at least the size the format specifies.  If not,
	// default it to the end of time and update the input format accordingly
	if (input_value.length	< offset_position) {
		input_value 		= '9999-12-31-00.00.00';
		input_format 		= 'Y-m-d-H.i.s';
		year_position		= 0;
		year_length			= 4;
		month_position		= 5;
		month_length		= 2;
		day_position		= 8;
		day_length			= 2;
		hour_position		= 11;
		hour_length			= 2;
		minute_position		= 14;
		minute_length		= 2;
		second_position		= 17;
		second_length		= 2;
		offset_position		= 19;
	}

	// Obtain Date parts, first default, then overlay as we identify them
	var year_part		= '9999';
	var month_part		= '12';
	var day_part		= '31';
	var hour_part		= '00';
	var minute_part		= '00';
	var second_part		= '00';
	
	if (year_position	>= 0) {
		year_part	= input_value.substring(year_position, year_position + year_length);
		// We expect to operate with 4 digit years (to avoid Y2K like issues),
		// but if we don't have 4 digits for the year, then
		// assume a 2 digit 99 is really 9999 and any other 2 digit year is 20??
		if (convert_2dig_year) {
			if (year_part	== '99') {
				year_part	= '9999';
			} else if (year_part.length == 2) {
				year_part	= '20' + year_part;
			}
		}
	}
	if (month_position >= 0) {
		month_part	= input_value.substring(month_position, month_position + month_length);
	}
  	if (day_position >= 0) {
		day_part	= input_value.substring(day_position, day_position + day_length);
	}
   	if (hour_position >= 0) {
		hour_part	= input_value.substring(hour_position, hour_position + hour_length);
	}
	if (minute_position >= 0) {
		minute_part	= input_value.substring(minute_position, minute_position + minute_length);
	}
	if (second_position >= 0) {
		second_part	= input_value.substring(second_position, second_position + second_length);
	}

	// Check if date is 9999-12-31 and if we should show it or not.
	if  ((year_part			== '9999')
	&&   (month_part		== '12')
	&&   (day_part			== '31')
	&&   (show_end_of_time	!= true)) {
		// Not supposed to show it, just return blank and get out of here.
		return '';
	}

	// Here is the manual formatting resulting from the flaw in the one line above.
	var output_value		= '';
	var output_format_array	= str_split(output_format, 1);
	for (var i = 0, size = output_format_array.length; i < size; ++i) {
		switch (output_format_array[i]) {
			case 'Y':
				output_value	= output_value + year_part;
				break;
			case 'y':
				output_value	= output_value . year_part.substring(2,4);
				break;
			case 'm':
				output_value	= output_value + month_part;
				break;
			case 'd':
				output_value	= output_value + day_part;
				break;
			case 'H':
				output_value	= output_value + hour_part;
				break;
			case 'h':
				output_value	= output_value + hour_part;
				break;
			case 'i':
				output_value	= output_value + minute_part;
				break;
			case 's':
				output_value	= output_value + second_part;
				break;
			case 'T':
				var tempDate	= new Date(year_part, month_part, day_part, hour_part, minute_part, second_part);
				if (isDST(tempDate)) {
					output_value	= output_value + userTimeZoneDST;
				} else {
					output_value	= output_value + userTimeZone;
				}
				break;
			default:
				// Special formatting character (this is likely a space, -, /, :, or .
				output_value	= output_value + output_format_array[i];
				break;
		}
	}

	return output_value;
}

// -----------------------------------------------------------
// Check if DST is observed for the time zone.
// -----------------------------------------------------------
function isDST(d) {
	let jan  = new Date(d.getFullYear(), 0, 1).getTimezoneOffset();
	let jul  = new Date(d.getFullYear(), 6, 1).getTimezoneOffset();
	let curr = new Date(d).getTimezoneOffset();
	return Math.max(jan, jul) !== d.getTimezoneOffset() && curr != jan;    
}
