/**********************************************************************
#  basic.js - Basic JavaScript Functions and Definitions
#  =====================================================
#
#  Copyright © 2004 - 2011 by Ed Hohmann
#
#  Written by: Ed Hohmann
#          on: November 7, 2004
#
#  This JavaScript file contains the basic variable and function
#  definitions.
#
**********************************************************************/

/***
var  MSIE  = ( document.all ); // ( navigator.userAgent.indexOf( "MSIE" ) != -1)
var  FFox  = ( navigator.userAgent.indexOf( "Firefox"  ) != -1 );
var  Opera = ( navigator.userAgent.indexOf( "Opera"    ) != -1 );
var  Opera = ( window.opera );
var  NSNav = ( navigator.userAgent.indexOf( "Netscape" ) != -1 ); // ( document.layers )
***/

/***  from http://webreflection.blogspot.com/2009/08/opera-detection-revamped.html:  *** /
Object.prototype.toString
    .call(window.opera) ===
    "[object Opera]"
;
/***  ***/

var  IE_Compatible = ( document.all );

var  MSIE   = /MSIE/.test( navigator.userAgent );
var  FFox   = /Firefox/i.test( navigator.userAgent );
var  Opera  = /Opera/i.test( navigator.userAgent );
var  Chrome = /Chrome/i.test( navigator.userAgent );
var  NSNav  = /Netscape/i.test( navigator.userAgent );
var  Gecko  = /Gecko/i.test( navigator.userAgent );

//var  HandCursor = ( MSIE  ?  "hand"  :  "pointer" );
var  ArrayMethods   = new  Array();
var  isMacroRunning = false;
var  FocusField     = "";
var  DefaultButton  = "";
var  ScrollBarWidth;

var  dbgStr = "";
var  dbgCtr = 1;



/***
 *    saveJSSessVars
 *
 *      EAH  -  September 13, 2010
 *
 *    saveJSSessVars saves one or more JavaScript variables in
 *    the PHP session variable:
 *
 *      $_SESSION[ "JavaScriptSessionVariables" ]
 *
***/

function  saveJSSessVars( JSVarName, JSVarValue )  {

	try  {
		xajax_saveJSSessVars( JSVarName, JSVarValue );
	}
	catch  ( e )  {};
}



/***
 *    Array Object Extensions
 *
 *      EAH  -  April 14, 2010
 *
***/


Array.prototype.typeofKey = function( key )  {
	for  ( idx in this )  {
		if  ( typeof( ArrayMethods[ key ] ) != "undefined" )  {
			return  "method";
		}
		else if  ( idx == key )  {
			return "data";
		}
	}
	return  "undefined";
}


Array.prototype.indexOf = function( val )  {
	//***/  alert( "Array.prototype.indexOf: typeof( val ) = "  + typeof( val ) + ", val = \"" + val.toString() + "\"" );
	var  isValObject = ( typeof( val ) == "object"  ||  typeof( val ) == "function" );
	for  ( key in this )  {
		//***/  alert( "Array.prototype.indexOf: typeof( ArrayMethods[ " + key + " ] ) = "  + typeof( ArrayMethods[ key ] ) + " = \"" + ArrayMethods[ key ] + "\"" );
		if  ( typeof( ArrayMethods[ key ] ) == "undefined" )  {
			if  ( isValObject )  {
				if  ( this[ key ].toString() == val.toString() )
					return  key;
			}
			else  {
				if  ( this[ key ] === val )
					return  key;
			}
		}
	}
	return  false;
}


Array.prototype.contains = function( val )  {
	if  ( this.indexOf( val ) === false )  return  false;
	else  return  true;
}


Array.prototype.update = function( val, key )  {

	/***  If a key is supplied and it is not a method, add or update the key value:  ***/
	if  ( typeof( key ) != "undefined" )  {
		if  ( this.typeofKey( key ) == "method" )
			return  false;
		else
			this[ key ] = val;
		return  key;
	}

	/***  If no key is supplied, append the value if it does not yet exist:  ***/
	try  {
		var  idx = this.indexOf( val );
	}
	catch( err )  {
		/***/  alert( "Array.prototype.update: Cannot find indexOf value" );
	}

	if  ( idx !== false )
		return  idx;
	this.push( val );
	//***/  alert( "Array.prototype.update: indexOf( val ) = \"" + this.indexOf( val ) + "\"" );
	return  this.indexOf( val );
}


Array.prototype.remove = function( val )  {
	var  idx;
	if  ( ( idx = this.indexOf( val ) ) === false )
		return;
	delete( this[ idx ] );
}



function  dbgOut( strDbg, flgClear )  {

	var  dbgBox = getElem( "dbgBox" );
	var  dbgClear = ( flgClear  &&  typeof( flgClear ) == "boolean"  ||  typeof( flgClear ) == "string"  &&  flgClear.toLowerCase() == "clear" );

	if  ( dbgBox  &&  typeof( dbgBox ) != "undefined" )  {
		if  ( !strDbg  ||  typeof( strDbg ) == "undefined" )
			strDbg = "";
		if  ( dbgClear )  {
			dbgBox.innerHTML = "";
			if  ( dbgCtr )
				dbgBox.innerHTML += dbgCtr++ + "<br/>";
		}
		if  ( dbgStr )  {  //.replace( /\-/g, "\\-" );
			//dbgBox.innerHTML += dbgStr.replace( /\n/g, "<br/>" ) + "<br/>";
			dbgBox.innerHTML += FormatForHTML( dbgStr ) + "<br/>";
		}
		if  ( strDbg )  {
			//dbgBox.innerHTML += strDbg.replace( /\n/g, "<br/>" ) + "<br/>";
			dbgBox.innerHTML += FormatForHTML( strDbg ) + "<br/>";
		}
		dbgStr = "";
	}
}


function  DisplayErrorMessage( ErrorMessage, Level )  {
	//***/  alert( ErrorMessage );
	if  ( typeof( Level ) == "undefined" )  {
		Level = "Error";
	}
	displayStatusWindow( Level + " Message", ErrorMessage );
}



function  FormatForHTML( sIn )  {
	return  sIn.replace( /</g, "&lt;" ).replace( />/g, "&gt;" ).replace( /\r\n|\n/g, "<br/>" ).replace( / /g, "&nbsp;" );
}



function  FormatHTML2JS( sIn, LF )  {
/************
		str_replace( "\n", LF,
			str_replace( "\r", "",
				str_replace( "&", "&amp;",
					EscapeQuotesJS(
						$strIn
					)
				)
			)
		)
************/
	return  EscapeQuotesJS( sIn ).replace( /&/g, "&amp;" ).replace( /\n|\r\n/g, getArg( LF, " " ) );
}



function  EscapeQuotesJS( sIn )  {

/************
	return  (
		str_replace( "'",  "\u0027",
			str_replace( "\u0027", "\\\u0027",
				str_replace( "\\\u0027", "\\\\\u0027",
					str_replace( "\"", "\\\"",
						str_replace( "\\\"", "\\\u0022",
							str_replace( "\\\u0022", "\\\\\u0022",
								$strIn
							)
						)
					)
				)
			)
		)
	);
************/
	return  sIn.replace( /\\u0022/g, "\\\\u0022" ).replace( /\\"/g, "\\u0022" ).replace( /"/g, "\\\"" ).replace( /\\\\u0027/g, "\\\\\\u0027" ).replace( /\\u0027/g, "\\\\u0027" ).replace( /'/g, "\\u0027" );
}



function  typeofObject( obj )  {

	var  objConstructor, objType;

	if  ( obj == null )
		return  "null";

	if  ( typeof( obj ) != "object" )
		return  typeof( obj );

	if  ( typeof( obj.constructor ) != "undefined" )
		objConstructor = obj.constructor.toString();
	else
		return  typeof( obj );

	//objType = objConstructor.match( /(?:.*function +)(\w+)(?:\(\).*)/ );
	objType = objConstructor.match( /(?:.*function)(( +)(\w+))*(?:\(\))/ );

	if  ( objType == null )
		return  "Object Constructor = " + objConstructor; //"unknown object constructor";
	else if  ( objType.length > 1 )
		return  objType[ 3 ];
	else
		return  objType[ 0 ];
}



function  strRepeat( s, n )  {
	return  ( ( new  Array( n + 1 ) ).join( s ) );
}



function  trimStrL( sIn )  {
	/*************************
	var  s = String( sIn );
	while  ( s.substring( 0, 1 ) == " " )
		s = s.substring( 1, s.length );
	return s;
	*************************/

	return  ( sIn.replace( /^[\s]+/, "" ) )
}


function  trimStrR( sIn )  {
	/*************************
	var  s = String( sIn );
	while  ( s.substring( s.length - 1, s.length ) == " " )
		s = s.substring( 0, s.length - 1 );
	return s;
	*************************/

	return  ( sIn.replace( /[\s]+$/, "" ) )
}


function  trimStr( sIn )  {
	/*************************
	return trimStrL( trimStrR( sIn ) );
	*************************/

	return  ( sIn.replace( /^[\s]+|[\s]+$/g, "" ) )
}


function  str_is_left( strSrc, strChk )  {
	return  ( strSrc.substr( 0, strChk.length )  ==  strChk );
}


function  str_is_right( strSrc, strChk )  {
	var  l = strChk.length;
	return  ( strSrc.substr( strSrc.length - l, l )  ==  strChk );
}



/**********************************************************************
 *    JavaScript trim(), startsWith(), and endsWith() functions:
 *
 *    from:
 *      http://www.apexa.net/Blog/web_design_Blog_20090820.aspx
 *      posted Thursday, August 20, 2009
***/

String.prototype.LTrim = function()  {
	return  ( this.replace( /^[\s]+/, "" ) )
}

String.prototype.RTrim = function()  {
	return  ( this.replace( /[\s]+$/, "" ) )
}

String.prototype.Trim = function()  {
	return  ( this.replace( /^[\s]+|[\s]+$/g, "" ) )
}

String.prototype.startsWith = function( str )  {
	return  ( this.match( "^" + str ) == str )
}

String.prototype.endsWith = function( str )  {
	return  ( this.match( str + "$" ) == str )
}

/***  ***/


/***  Whitespace string trimming functions:  *** /

// LTrim, RTrim, and TRim JavaScript Functions Written by:
//    Scott Mitchell
//    mitchell@4guysfromrolla.com
//    http://www.4GuysFromRolla.com
//    http://www.4guysfromrolla.com/webtech/vb2java.shtml

function LTrim( str )  {
	var  whitespace = new String( " \t\n\r" );

	var  s = new String( str );

	if  ( whitespace.indexOf( s.charAt( 0 ) ) != -1 ) {
		var  j = 0, i = s.length;
		while  ( j < i  &&  whitespace.indexOf( s.charAt( j ) ) != -1 )
			j++;
		s = s.substring( j, i );
	}

	return  s;
}


function RTrim( str )  {
	var  whitespace = new String( " \t\n\r" );

	var  s = new String( str );

	if  ( whitespace.indexOf( s.charAt( s.length - 1 ) ) != -1 ) {
		var  i = s.length - 1;
		while  ( i >= 0  &&  whitespace.indexOf( s.charAt( i ) ) != -1 )
			i--;
		s = s.substring( 0, i + 1 );
	}

	return  s;
}


function Trim( str )  {
	return  RTrim( LTrim( str ) );
}

/***  ***/





function isDigit( c )  {
	return  ( c >= "0"  &&  c <= "9" )
}


//function isNumericStr( s )  {
//	return  ( c >= "0"  &&  c <= "9" )
//}


function isAlpha( c )  {
	return  ( ( c >= "A"  &&  c <= "Z" )  ||
	          ( c >= "a"  &&  c <= "z" ) )
}


function isAlphaNumeric( c )  {
	return  ( ( c >= "A"  &&  c <= "Z" )  ||
	          ( c >= "a"  &&  c <= "z" )  ||
	          ( c >= "0"  &&  c <= "9" ) )
}


function isObjectType ( a, t )  {
	return  ( typeofObject( a ) == t );
}


function isArray ( a )  {
	return  ( isObjectType( a, "Array" ) );
}


function  describeDOMObj( argObject )  {

	var  objAttribs, objAttrib, strOut;
	var  objX = argObject;

	strOut = "describeDOMObj( ObjectType = "+ typeofObject( argObject ) +" ):\n";

	//***/ strOut += ( (objX.id) ? "id='" + objX.id + "' " : "" ) + "\n";
	//***/ strOut += ( (objX.title) ? "title = '" + objX.title + "' " : "title='" + objX.alt + "' " ) + "\n";
	//***/ strOut += ( (objX.value) ? "value = '" + objX.value + "' " : "<no value>" ) + "\n";
	//***/ strOut += ( (objX.className) ? "className = '" + objX.className + "' " : "" ) + "\n";
	//***/ strOut += ( (objX.length) ? "length = '" + objX.length + "' " : "<no length>" ) + "\n";
	//***/ strOut += "display:inline-block;" + objX.style.cssText + "\n";

	if  ( typeof( objX ) != "undefined"  &&  typeof( objX.attributes ) != "undefined" )  {
		objAttribs = objX.attributes;
		/***/ strOut += ( (objAttribs)  ?  "attributes:"  :  "<no attributes>" ) + "\n";
		for  ( var j = 0;  j < objAttribs.length;  j++ )  {
			objAttrib = objAttribs[ j ];
			/***/ strOut += "#" + j + " - " + objAttrib.nodeName + " = \"" + objAttrib.nodeValue + "\"\n";
		}
	}
	else
		strOut += "<no attribute property>\n";
	return  strOut;
}


function  describeObj( argObject, spacer, level )  {

	if  ( typeof( level ) == "undefined"  ||  !level )
		level = 0;

	if  ( typeof( spacer ) == "undefined"  ||  !level )
		spacer = ". . ";

	var  ObjectType = typeofObject( argObject );

	var  strIndent = strRepeat( spacer, level + 1 );

	var  strObj = "";

	if  ( argObject == null )  {
		strObj += "<null>\n";
	}
	else if  ( typeof( argObject ) == "object" )  {
		strObj += "<<" + ObjectType + ">>\n";
		//***/  alert( "<<" + ObjectType + ">>" );
		for  ( var att  in  argObject )  {

			//***/  alert( "att = \"" + att + "\"" );

			if  ( ObjectType != "Array"  ||  ( ObjectType == "Array"  &&  ( typeof( ArrayMethods[ att ] ) == "undefined" ) ) )
				strObj += strIndent + "\"" + att + "\": " + describeObj( argObject[ att ], spacer, level + 1 );

			/***
			if  ( typeof( att ) == "object" )
				strObj += strIndent + describeObj( att, "+ ", level + 1 );
			else
				strObj += strIndent + "\"" + att + "\": " + describeObj( argObject[ att ], "- ", level + 1 );
			***/
		}
	}
	else  {
		strObj += "<" + typeof( argObject ) + "> \"" + argObject + "\"\n";
		//***/  alert( "<" + typeof( argObject ) + "> \"" + argObject + "\"" );
	}

	return  strObj;
}



function  strASCII2Binary( sIn )  {

	var  b = new String();
	var  len = sIn.length;
	var  idx = 0;

	while  ( idx < len )  {
		var  c = sIn.charAt( idx );
		idx++;
		b += chrASCII2Binary( c );
	}

	return  b;
}



function  chrASCII2Binary( c )  {
	var  cc = c.charCodeAt( 0 );
	if  ( cc <= 255 )
		return  BytetoHex( cc ) + " ";
	else  {
		c1 = Math.floor( cc / 256 );
		c2 = cc % 256;
		return  BytetoHex( c1 ) + " " + BytetoHex( c2 ) + " ";
	}
}



function  BytetoHex( n )  {
	n1 = Math.floor( n / 16 );
	n2 = n % 16;
	return  HexChar( n1 ) + HexChar( n2 );
}



function  HexChar( n )  {

	return  "0123456789ABCDEF".charAt( n );
}



function  ConvertCRLF2LF( text )  {
	return  text.replace(  /\r\n/g, "\n" );
}



function  ConvertLF2CRLF( text )  {
	return  text.replace(  /\r\n/g, "\n"  ).replace(  /\n/g, "\r\n" );
}



function  DisplayCRLF( text )  {
	return  text.replace( /\r/g, "{CR}" ).replace( /\n/g, "{LF}" );
}



function  DisplayedLength( text )  {

	if  ( MSIE )
		return  text.replace(  /\r\n/g, "\n"  ).length;

	if  ( Opera )
		return  text.replace(  /\r\n/g, "\n"  ).replace(  /\n/g, "\r\n" ).length;

	return  text.replace(  /\r\n/g, "\n"  ).length;
}



/**********************************************************************************************
 *
 *  Encode Unicode characters to UTF-8 in JavaScript
 *  ------------------------------------------------
 *
 *  7-bit:
 *    0bbb bbbb
 *
 *  11-bit:
 *    110b bbbb  10bb bbbb
 *
 *  16-bit:
 *    1110 bbbb  10bb bbbb  10bb bbbb
 *
 *  21-bit:
 *    1111 0bbb  10bb bbbb  10bb bbbb  10bb bbbb
 *
***/

function  chr_UTF8( sUnicode )  {

	return  String.fromCharCode( sUnicode );
}


function  xchr_UTF8( sUnicode )  {

	var  B, uChars;

	B = sUnicode | 0;  //***  Bitwise OR ensures B is an Integer.

	/***  Return empty string on Unicode out of range:  ***/
	if  ( B < 0  ||  B > 0x1FFFFF )
		return  "";

	/***  Return 7-bit Unicode character:  ***/
  if  ( B < 0x80 )
		return  ( ( B ).toString() );

	uChars = ( 0x80 | ( 0x3F & B ) ).toString();
	B = B >>> 6;

	/***  Return 11-bit Unicode character:  ***/
	if  ( B < 0x20 )
		return  ( 0xC0 | B ).toString() + uChars;

	uChars = ( 0x80 | ( 0x3F & B ) ).toString() + uChars;
	B = B >>> 6;

	/***  Return 16-bit Unicode character:  ***/
	if  ( B < 0x10 )
		return  ( 0xE0 | B ).toString() + uChars;

	uChars = ( 0x80 | ( 0x3F & B ) ).toString() + uChars;
	B = B >>> 6;

	/***  Return 21-bit Unicode character:  ***/
	return  ( 0xF0 | B ).toString() + uChars;
}


function  ord_UTF8_char( UnicodeCharacter )  {

	/***/  alert( "ord_UTF8_char( " + UnicodeCharacter + " ) =\n\"" + UnicodeCharacter.charCodeAt( 0 ) + "\"" );

	return  UnicodeCharacter.charCodeAt( 0 );
}


function  ord_UTF8_str( UnicodeString )  {

	var  sOut = "";

	for  ( var i = 0;  i < UnicodeString.length;  i++ )  {
		sOut += ord_UTF8_char( UnicodeString.substr( i, 1 ) ) + " ";
	}

	/***/  alert( "ord_UTF8_str( " + UnicodeString + " );\n" + sOut );

	return  sOut;
}



function  getArg( argObject, argDefault )  {
	if  ( typeof( argDefault ) == "undefined"  ||  argDefault == null  ||  argDefault === "" )
		argDefault = "";
	if  ( typeof( argObject ) == "undefined"  ||  argObject == null  ||  argObject === "" )
		argObject = argDefault;
	return  argObject;
}



function  getElem( elemObject, elemDefault )  {

	var  elem = getArg( elemObject, elemDefault );

	if  ( typeof( elem ) == "string" )  {

		/***  IE only version:  ***/
			if  ( elem == "" )
				return  null;
			else
				return  document.getElementById( elem );
		/***/

		/***  IE and Firefox compatible version:  ***
			return  curForm.elements[ elem ];
		/***/

	}
	else
		return  elem;
}



/******************************************************************************
  getElemName
    EAH - May 12, 2009
******************************************************************************/

function  getElemName( elemObj )  {

	if  ( elemObj )  {
		if  ( elemObj.name )
			return  elemObj.name;
		else if  ( elemObj.id )
			return  elemObj.id;
		else
			return  "";
	}
	else
		return  "";
}



function  getElementsByClassName( oElm, strTagName, strClassName )  {

	var  arrElements = ( strTagName == "*" && document.all )  ?  document.all  :  oElm.getElementsByTagName( strTagName );
	var  arrReturnElements = new Array();
	strClassName = strClassName.replace( /\-/g, "\\-" );
	var  oRegExp = new RegExp( "(^|\\s)" + strClassName + "(\\s|$)" );
	var  oElement;
	for  ( var i = 0;  i < arrElements.length;  i++ )  {
		oElement = arrElements[ i ];
		if  ( oRegExp.test( oElement.className ) )  {
			arrReturnElements.push( oElement );
		}
	}
	return  ( arrReturnElements )
}


function  getElemValue( elemObject, defValue )  {
	var elemObj = getElem( elemObject );
	if  ( elemObj != null )
		return  elemObj.value
	else
		if  ( typeof( defValue ) != "undefined" )
			return  defValue;
		else
			return  null;
}


function  getElemDataValue( elemObject, defValue )  {
	var  elemObj = getElem( elemObject );
	if  ( elemObj != null )  {
		return  parseDataValue( elemObj.value, elemObj.getAttribute( "datatype" ) );
	}
	else
		if  ( typeof( defValue ) != "undefined" )
			return  defValue;
		else
			return  null;
}


function  parseDataValue( DataValue, DataType )  {

	if  ( typeof( DataType ) == "undefined"  ||  !DataType )
		DataType = getDataType( DataValue );

	switch  ( DataType )  {
		case  "NUMERIC":
		case  "CURRENCY":
		case  "PERCENT":
			DataValue = DataValue.replace( /[,\s]/g, "" );
			switch  ( DataType )  {
				case  "NUMERIC":
					DataValue = Number( DataValue );
					break;
				case  "CURRENCY":
					DataValue = Number( DataValue.replace( /^\$|\$$/, "" ) );
					break;
				case  "PERCENT":
					DataValue = Number( shift_decimal( DataValue.replace( /^%|%$/, "" ), -2 ) );
					break;
			}
	}
	return  DataValue;
}


function  getDataType( DataValue )  {

	var  DataType = "TEXT";
	var  v = DataValue.replace( /\s/g, "" );

	if  ( v == ""  ||  v.match( /[^\d\.,$%Ee+-]/ ) )
		return  "TEXT";

	v = DataValue.replace( /,/g, "" );
	if  ( v.match( /^\$|\$$/ ) )  {
		if  ( Number( v.replace( /^\$|\$$/, "" ) ) != NaN )
			DataType = "CURRENCY";
	}
	else if  ( v.match( /^%|%$/ ) )  {
		if  ( Number( v.replace( /^%|%$/, "" ) ) != NaN )
			DataType = "PERCENT";
	}
	else  {
		if  ( Number( v ) != NaN )
			DataType = "NUMERIC";
	}

	return  DataType;
}


function  setElemValue( elemObject, newValue )  {
	var elemObj = getElem( elemObject );
	if  ( elemObj != null )  {
		elemObj.value = newValue;
		return  true;
	}
	else  {
		return  false;
	}
}


function  setElemDataValue( elemObject, newValue )  {

	var elemObj, DataType, newDataType, fmtValue, fmtSign, arrMant, arrValue, strWhole, strFraction, strExponent, strValue;

	elemObj = getElem( elemObject );

	if  ( elemObj != null )  {
		if  ( typeof( newValue ) == "undefined"  ||  newValue == null )
			newValue = getArg( newValue, elemObj.value );
		elemObj.value = newValue;
		DataType = elemObj.getAttribute( "datatype" );
		if  ( !DataType )
			return  true;

		switch  ( DataType )  {
			case  "NUMERIC":
			case  "CURRENCY":
			case  "PERCENT":
				newValue = newValue.toString().replace( /\s/g, "" );
				if  ( newValue == "" )
					newValue = "0";
				newDataType = getDataType( newValue );
				switch  ( newDataType )  {
					case  "NUMERIC":
					case  "CURRENCY":
					case  "PERCENT":
						//***/  alert( "setElemDataValue 1:\nDataType = \"" + DataType + "\", newDataType = \"" + newDataType + "\"\nnewValue = \"" + newValue + "\"" );
						fmtValue = parseDataValue( newValue, newDataType );
						if  ( fmtValue == NaN  ||  !( DataType == newDataType  ||  DataType == "NUMERIC"  ||  newDataType == "NUMERIC" ) )
							return  false;
						if  ( DataType == "PERCENT" )
							fmtValue = shift_decimal( fmtValue, 2 );
						fmtSign = ( fmtValue < 0  ?  "-"  :  "" );
						fmtValue = Math.abs( fmtValue );
						arrMant =  fmtValue.toString().split( /[Ee]/ );
						strExponent = ( arrMant.length > 1  ?  arrMant[ 1 ]  :  "" );
						arrValue = arrMant[ 0 ].toString().split( "." );
						strWhole = arrValue[ 0 ];
						strFraction = ( arrValue.length > 1  ?  arrValue[ 1 ]  :  "" );
						//***/  alert( "setElemDataValue 2:\nfmtValue = \"" + fmtValue + "\"\nstrWhole = \"" + strWhole + "\"\nstrFraction = \"" + strFraction + "\"" );
						if  ( strWhole.length == 0 )
							strWhole = "0";
						for  ( var  p = strWhole.length - 3;  p > 0;  p -= 3 )  {
							//***/  alert( "p = \"" + p + "\"" );
							strWhole = strWhole.substring( 0, p ) + "," + strWhole.substring( p );
						}
						strWhole = fmtSign + strWhole;
						//***/  alert( "setElemDataValue 3:\nfmtValue = \"" + fmtValue + "\"\nstrWhole = \"" + strWhole + "\"\nstrFraction = \"" + strFraction + "\"" );
						if  ( DataType == "CURRENCY" )  {
							strWhole = "$" + strWhole;
							for  ( var  i = strFraction.length;  i < 2;  i++ )  {
								strFraction += "0";
							}
						}
						strValue = strWhole + ( strFraction != ""  ?  "." + strFraction  :  "" ) + ( strExponent != ""  ?  "E" + strExponent  :  "" );
						//***/  alert( "setElemDataValue 4:\nstrValue = \"" + strValue + "\"\nstrWhole = \"" + strWhole + "\"\nstrFraction = \"" + strFraction + "\"" );
						if  ( DataType == "PERCENT" )
							strValue += "%";
						elemObj.value = strValue;
						break;

					default:
						return  false;
						break;
				}
		}
		return  true;
	}
	else  {
		return  false;
	}
}


function  shift_decimal( n, places )  {

	var  nSign, nLen, nDP, newDP, nN;

	if  ( places == 0 )
		return  n;

	nSign = ( n < 0  ?  "-"  :  "" );
	n = Math.abs( n ).toString();
	nLen = n.length;
	nDP  = n.indexOf( "." );
	if  ( nDP < 0 )
		nDP = nLen;
	newDP = nDP + places;
	nN = n.replace( ".", "" );

	if  ( newDP <= 0 )  {
		nN = "0." + strRepeat( "0", -newDP ) + nN;
	}
	else if  ( newDP > nN.length )  {
		nN += strRepeat( "0", newDP - nN.length );
	}
	else  {
		nN = nN.substring( 0, newDP ) + "." + nN.substring( newDP );
	}
	nN = nSign + nN;

	return  nN;
}



function  Function2String( fFunction )  {

	//***/  dbgOut( "Function2String\ntypeof( fFunction ) = \"" + typeof( fFunction ) + "\"\nfFunction:\n" + fFunction.toString() + "\n\n" );

	var  sFunction = "";

	if  ( typeof( fFunction ) == "function" )  {
		//sFunction = fFunction.toString().replace( /(function)(\s)*(\(\))/, "" );

		sFunction = fFunction.toString().replace( /function\s*\(\)\s*/, "" );

		//***/  dbgStr += "\nFunction2String = \"" + sFunction + "\"\n\n";
	}

	return  sFunction;
}



function  getScrollBarWidth() {

	if  ( typeof( ScrollBarWidth ) != "undefined" )
		return  ScrollBarWidth;

	var  outer = document.createElement( "div" );
	var  inner = document.createElement( "div" );

	outer.style.width      = "100px";
	outer.style.height     = "50px";
	outer.style.position   = "absolute";
	outer.style.visibility = "hidden";
	/*** /
	outer.style.scrollbarFaceColor       =
	outer.style.scrollbarArrowColor      =
	outer.style.scrollbarTrackColor      =
	outer.style.scrollbarHighlightColor  =
	outer.style.scrollbar3dlightColor    =
	outer.style.scrollbarShadowColor     =
	outer.style.scrollbarDarkshadowColor = "silver";
	/***/

	inner.style.height = "200px";

	outer.appendChild( inner );
	document.body.insertBefore( outer, document.body.firstChild );

	outer.style.overflow = "hidden";
	var  NoScrollW = inner.offsetWidth;
	inner.scrollIntoView( false );
	var  NoScrollH = outer.scrollTop;

	outer.style.overflow = "scroll";
	var  ScrollW = inner.offsetWidth;
	inner.scrollIntoView( false );
	var  ScrollH = outer.scrollTop;

	document.body.removeChild( document.body.firstChild );

	var  widthScrollBar  = NoScrollW - ScrollW;
	var  heightScrollBar = ScrollH - NoScrollH;

	ScrollBarWidth = ( widthScrollBar  ?  widthScrollBar  :  heightScrollBar );

	saveJSSessVars( "ScrollBarWidth", ScrollBarWidth );

	return  ScrollBarWidth;
}



/***  Event Handling functions:  ***/


function  getEventElement( evt )  {

	var  EventElement = null;

	if  ( !evt )
		evt = Window.event;

	if  ( evt.target )
		EventElement = evt.target;
	else if  ( evt.srcElement )
		EventElement = evt.srcElement;

	/***
	 *    Safari fix: If EventElement contains text,
	 *    Safari returns the text node as the event target
	 *    instead of the parent node, which is the actual target.
	***/
	if  ( EventElement.nodeType == 3 )
		EventElement = EventElement.parentNode;

	return  EventElement;
}



/***  CSS Attribute functions:  ***/


function  getElementStyle( elem, styleProp )  {

  var  elemObj, objStyle, elemStyle;

	elemObj = getElem( elem );
	sProperty = getArg( styleProp, "" );

	if  ( elemObj.currentStyle )  {
		objStyle = elemObj.currentStyle;
	}
	else if  ( window.getComputedStyle )  {
		objStyle = document.defaultView.getComputedStyle( elemObj, null );
	}
	else
		objStyle = {};

	if  ( sProperty )
		if  ( objStyle )
			elemStyle = objStyle[ sProperty ]; //.getPropertyValue( sProperty );
		else
			elemStyle = "";
	else
		elemStyle = objStyle;

	return  elemStyle;
}


function  setElementStyle( elem, styleString )  {
	if  ( MSIE )
		elem.style.setAttribute('cssText', styleString);
	else
		elem.setAttribute('style', styleString);
}


function  transferAllStyles( elemFrom, elemTo )
{
  var  prop;
  for  ( prop  in  elemFrom.style )
    if  ( typeof prop == "string" )
      try  {
				elemTo.style[ prop ] = elemFrom.style[ prop ];
			}
      catch  ( ex )  { /* don't care */ };
}




/***  Form handling functions:  ***/


function  setNewSortField( SortField, strActionFunction ) {

  if  ( curForm.SortBy.value == SortField )  {
    if  ( curForm.SortDir.value == FWD )  {
      curForm.SortDir.value = REV;
    }
    else  {
      curForm.SortDir.value = FWD;
    }
  }
  else  {
    curForm.preSortBy.value  = curForm.SecSortBy.value;
    curForm.SecSortBy.value  = curForm.SortBy.value;
    curForm.SortBy.value     = SortField;
    curForm.preSortDir.value = curForm.SecSortDir.value;
    curForm.SecSortDir.value = curForm.SortDir.value;
    curForm.SortDir.value    = FWD;
  }

  if  ( typeof( strActionFunction ) != "undefined"  &&  strActionFunction != "" )
  	eval( strActionFunction );
  else
	  setScreenAction( RESORT, curForm.EditID.value, "", SUBMIT );
}



/**********************************************************************
 *    setViewAndFocus
 *
 *      Sets the Scroll-To, Focus, and Selected objects.
 *
 *      If the first character of the ViewObj is an "=" sign, the ViewObj
 *      is considered a JavaScript variable that contains the name of the
 *      actual object to scroll to.
 *      If the scroll-to object name is followed by ":Top", then the object
 *      is scrolled to the top of the screen; otherwise the default is to
 *      scroll it to the bottom of the screen.
 *
 *      Example:
 *        =DataTable:Top
***/

function  setViewAndFocus( ViewObj, FocusObj, SelectObj )  {

	//***/  dbgOut( "\n<b>setViewAndFocus:</b>" );

	var  reqFieldFocus    = false;
	var  selFocusField    = false;
	var  ScrollToPosition = false;

	if  ( typeof( ViewObj ) == "undefined"  ||  ViewObj != "None" )  {
		if  ( typeof( ViewObj ) == "string"  &&  ViewObj.startsWith( "=" ) )  {
			var  arrViewObj = ViewObj.substr( 1 ).split( ":" );
			ViewObj = getElemValue( arrViewObj[ 0 ] );
			if  ( arrViewObj.length > 1 )  {
				ScrollToPosition = ( trimStr( arrViewObj[ 1 ] ) == "Top" );
			}
		}
		//***/  alert( "ViewObj = " + ViewObj );
		var vObj = getElem( ViewObj, "ScrollToCell" );
		//***/  dbgOut( " typeof( vObj ) = \"" + typeof( vObj ) + "\"" );
		if  ( typeof( vObj ) == "object"  &&  vObj != null )  {
			vObj.scrollIntoView( ScrollToPosition );
			//***/  dbgOut( " ViewObj = \"" + ViewObj + "\"" );
			//***/  dbgOut( " - scroll to &lt;" + vObj.tagName + " id=\"" + vObj.id + "\"&gt;" );
			if  ( typeof( ErrorIW ) != "undefined" )  {
				ErrorIW.setInfoWindow();
			}
		}
	}

	if  ( typeof( FocusObj ) == "undefined"  ||  FocusObj == null  ||  FocusObj == "" )  {
		if  ( FocusField )  {
			FocusObj = FocusField;
		}
		else  {
			var FieldList = getElemValue( "RequiredFields", "" );
			var p = FieldList.indexOf( "=" );
			if  ( p != -1  &&  getElemValue( "ScreenState" ) == ENTER )  {
				FocusObj = trimStr( FieldList.substring( 0, p ) )
				reqFieldFocus = true;
			}
			else
				FocusObj = "btnCancel";
		}
	}
	//***/  alert( "Required Field List = \"" + FieldList + "\"" );
	//***/  alert(  "FocusObj = \"" + FocusObj + "\"" );
	var fObj = getElem( FocusObj );
	//***/  dbgOut( " typeof( fObj ) = \"" + typeof( fObj ) + "\"" );
	//***/  dbgOut( " fObj.name = \"" + fObj.name + "\"" );
	//***/  dbgOut( " fObj.visibility = \"" + fObj.visibility + "\"" );
	//***/  dbgOut( " fObj.length = \"" + fObj.length + "\"" );

	/***  The following is a cludge to prevent JavaScript errors when multiple Control Buttons  ***/
	/***  appear in a single form:                                                              ***/
	try  {
		if  ( typeof( fObj.length ) != "undefined"  &&  fObj.length > 1  &&  typeof( fObj[ 0 ] ) == "object" )  {
			//***/  dbgOut( " typeof( fObj[ 0 ] ) = \"" + typeof( fObj[ 0 ] ) + "\"\n" );
			fObj = fObj[ 0 ];
		}
	}
	catch (e) {
	}

	if  ( typeof( fObj ) == "object"  &&  fObj != null  &&  fObj.visibility != "hidden" )  {
		//***/  dbgOut( " - setting focus on \"" + fObj.name + "\"" );
		//***/  dbgOut( " - fObj.class = \"" + fObj.elemType + "\"" );
		fObj.focus();
		selFocusField = reqFieldFocus;
	}
	var sObj = getElem( SelectObj );
	try  {
		if  ( typeof( sObj ) == "object"  &&  sObj != null  &&  sObj.visibility != "hidden" )  {
			//***/  dbgOut( " - selecting SelectObj \"" + sObj.name + "\"" );
			sObj.select();
			//***/  dbgOut( " - selected \"" + sObj.name + "\"" );
		}
		else  {
			if  ( selFocusField )  {
				//***/  dbgOut( " - selecting selFocusField \"" + sObj.name + "\"" );
				fObj.select();
				//***/  dbgOut( " - selected \"" + fObj.name + "\"" );
			}
		}
	}
	catch (e) {
	}
	//***/  alert( "ViewObj = \"" + vObj.name + "\", \nFocusObj = \"" + fObj.name + "\", \nSelectObjObj = \"" + sObj.name + "\"" );
}



function  setScreenAction( goAction, goEditID, goEditMode, goSubmit )  {

  var scnState = getElemValue( "ScreenState" );

  curForm.ScreenAction.value = goAction;
  curForm.prevScreenState.value = scnState;
	if  ( !( typeof( goEditID ) == "undefined"  ||  goEditID ==  null ) )
	  curForm.EditID.value = goEditID;
	if  ( !( typeof( goEditMode ) == "undefined"  ||  goEditMode ==  null  ||  goEditMode == "" ) )
	  curForm.EditMode.value = goEditMode;

	// Added goSubmit flag  -  Aug 23, 2007  by EAH
	// In order to allow the <form onsubmit=''> JavaScript code to execute.

	if  ( typeof( goSubmit ) != "undefined"  &&  goSubmit !=  null  &&  goSubmit == "Submit" )  {
	  curForm.submit();
		disableForm();
	}
}



function  disableForm()  {

	var  iElem;
	var  iElemType;

	if  ( document.all  ||  document.getElementById )  {
		for  ( i = 0;  i < curForm.length;  i++ )  {
			iElem = curForm.elements[i];
			iElemType = iElem.type.toLowerCase();
			if  ( ( iElemType == "submit"  ||  iElemType == "reset" )  /* &&  iElem != event.srcElement */ )
				iElem.disabled = true;
		}
	}
}


function  getDefaultButton( btnName )  {

	var  defBtn;

	if  ( DefaultButton )
		defBtn = DefaultButton;
	else  if  ( getElemValue( "ScreenState" ) == "Modify" )
		defBtn = "btnUpdate";
	else
		defBtn = "btnEnter";

	return  getElem( btnName, defBtn );
}


function  isEnterKey( event )  {

	return  ( ( window.event  &&  event.keyCode == 13 )  ||  ( event  &&  event.which == 13 ) );
}


function  onEnterSubmit( event, btnName )  {

	if ( isEnterKey( event ) )  {
		clickDefaultButton( btnName );
	}
}


function  clickDefaultButton( btnName )  {

	//***/  JSc.value += "<br/>clickDefaultButton( \"" + btnName + "\" )<br/>";

	var btn = getDefaultButton( btnName );

	//***/  JSc.value += "<br/>Default Button = \"" + btn.name + "\"<br/>";
	//***/  JSc.value += btn.name + " visibility = \"" + btn.style.visibility + "\"<br/>";

	clickButton( btn );

}


function  clickButton( btnName )  {

	//***/  JSc.value += "<br/>clickButton( \"" + btnName + "\" )<br/>";

	var  ClickOK = false;

	var btn = btnName;

	if  ( typeof( btnName ) == "string" )
		btn = getElem( btnName );

	//***/  JSc.value += "<br/>Button = \"" + btn.name + "\"<br/>";
	//***/  JSc.value += btn.name + " visibility = \"" + btn.style.visibility + "\"<br/>";

	if  ( btn  &&  btn.style.visibility != "hidden"  &&  !btn.disabled )  {
		//***/  JSc.value += "<br/>Clicking the \"" + btn.name + "\" button!<br/>";
		try  {
			btn.focus();
			try  {
				btn.select();
			}
			catch( e )  {};
			if  ( MSIE )
				btn.click();  //btn.onclick;
			else
				btn.click();
			ClickOK = true;
		}
		catch( e )  {
			/***/  dbgStr = "***** ERROR! *****\nclickButton( \"" + btn.name + "\" ) failed!!!\n";
			/***/  alert( dbgStr + e.message );
			/***/  JSc.value += dbgStr;
			//***/  dbgOut( e.message );
		}
	}
	return  ClickOK;
}


function  pressButton( ButtonName )  {

	if  ( ButtonName == "Macro" )  {
		setLinkField( ButtonName );
		return  true;
	}

	var  btnName = getButtonElemName( ButtonName );
	var  btn = getElem( btnName );

	if  ( btn.disabled )  {
		alert( "The \"" + ButtonName + "\" button is disabled." );
		return  false;
	}
	else  {
		return  clickButton( btnName );
	}
}


function  getButtonElemName( ButtonName )  {

	var  btnName;

	switch  ( ButtonName )  {
		case  "Link":
			btnName = "fbtnLink";
			break;

		case  "Load":
			btnName = "fbtnLoad";
			break;

		case  "Move":
			btnName = "fbtnMove";
			break;

		case  "Topic":
			btnName = "fbtnInsTLink";
			break;

		case  "Section":
			btnName = "fbtnInsSLink";
			break;

		case  "Group":
			btnName = "fbtnInsGLink";
			break;

		case  "Item":
			btnName = "fbtnInsILink";
			break;

		default:
			btnName = "";
			break;
	}
	//***/  alert( "getButtonElemName( \"" + ButtonName + "\" (" + typeof( ButtonName ) + ") ) = \"" + btnName + "\"" )
	return  btnName;
}


function  setUpdateButtonVisibility( btnVisibility )  {

	var  btnEnter  = getElem( "btnEnter"  );
	var  btnUpdate = getElem( "btnUpdate" );
	var  btnSave   = getElem( "btnSave"   );
	var  btnCommit = getElem( "btnCommit" );
	var  btnGo     = getElem( "fbtnGo"    );

	try  {

		if  ( btnEnter != null )
			btnEnter.style.visibility = btnVisibility;

		if  ( btnUpdate != null )
			btnUpdate.style.visibility = btnVisibility;

		if  ( btnSave != null )
			btnSave.style.visibility   = btnVisibility;

		if  ( btnCommit != null )
			btnCommit.style.visibility = btnVisibility;

		if  ( btnGo != null )  {
			btnGo.style.visibility = btnVisibility;
			btnGo.disabled = ( btnVisibility == "hidden" );
		}

	}
	catch  ( e )  {}
}


function  EnforceNTagxxxNotUsed( NTag )  {

	var  NTagID = NTag.name;
	var  arrNTagIX = NTagID.split( FieldIndexDelimiter );
	var  NTagIX = arrNTagIX[ 1 ];
	var  UsedNTag = getElem( NTagID.substring( 0, 2 ) + "UNTg" + FieldIndexDelimiter + NTagIX );

	if  ( UsedNTag )  {
		var  btnVisibility = ( !NTag.value  ?  "hidden"  :  EnforceRequiredFields() );

		setUpdateButtonVisibility( btnVisibility );

		chkFieldDataType( NTagID, "ANY", true );
	}
}


function  EnforceRequiredFields( reqFieldList, btnName, strFlag )  {

	var  Flag = getArg( strFlag, "" );
	var  FieldStyleGood = "color: black; background-color: #F0FFF0";
	var  FieldStyleBad  = "color: brown; background-color: pink";
	var  FieldInfo = [];
	var  NextFocusField = null;
	var  btnVisibility = "visible";

	var  fldName, fldValue, chkField, chkValue, defValue, flgNotRequired;

	var  btn = getDefaultButton( btnName );

	var  reqFields = getElemValue( "RequiredFields",  "" );
	var  ReqFields = reqFields + ( trimStr( reqFields ) != ""  ?  ";"  :  "" ) + getElemValue( "zRequiredFields", "" );

	var  FieldList = getArg( reqFieldList, ReqFields );
	var  FieldArray = FieldList.split( ";" );

	//***/ alert( "<B>EnforceRequiredFields</B>( \"" + reqFieldList + "\", \"" + btnName + "\", \"" + strFlag + "\" )" );
	//***/ dbgOut( "FieldList = \"" + FieldList + "\"<br/>" );
	//***/ dbgOut( "FieldArray length = \"" + FieldArray.length + "\"<br/>" );

	for  ( var i = 0;  i < FieldArray.length;  i++ )  {
		FieldInfo = FieldArray[ i ].split( "=" );
		if  ( FieldInfo.length == 2 )  {
			fldName  = trimStr( FieldInfo[ 0 ] );
			defValue = trimStr( FieldInfo[ 1 ] );
			flgNotRequired = ( str_is_right( fldName, "!" ) );
			if  ( flgNotRequired )  {
				fldName = trimStr( fldName.substr( 0, fldName.length - 1 ) );
			}
			chkField = getElem( fldName );
			//***/ dbgOut( "fldName = \"" + fldName + "\": " );
			//***/ dbgOut( "defValue = \"" + defValue + "\"<br/>" );
			if  ( chkField != null )  {
				fldValue = chkField.value;
				if  ( fldValue == defValue  ||  ( !flgNotRequired  &&  trimStr( fldValue ) == "" ) )  {
					btnVisibility = "hidden";
					chkField.style.cssText = FieldStyleBad;
					if  ( Flag == "NextField"  &&  NextFocusField == null )
						NextFocusField = chkField;
				}
				else  {
					chkField.style.cssText = FieldStyleGood;
				}
				//***/ dbgOut( "fldValue = \"" + fldValue + "\"<br/>" );
				//***/ dbgOut( "btnVisibility = \"" + btnVisibility + "\"<br/>" );
			}
		}
	}
	//if  ( Flag == "Initialize"  &&  FieldList != "" )
	//	btnVisibility = "hidden";

	if  ( btn != null )  {
		btn.style.visibility = btnVisibility;
		if  ( Flag == "NextField"  &&  NextFocusField == null  &&  btn.style.visibility == "visible" )
			NextFocusField == btn;
	}

	if  ( Flag == "NextField"  &&  NextFocusField != null  &&  !NextFocusField.disabled )  {
		//NextFocusField.disabled = false;
		NextFocusField.focus();
		try  {
			NextFocusField.select();
		}
		catch  ( e )  {}
	}

	setUpdateButtonVisibility( btnVisibility );
	return  ( btnVisibility == "visible" );
}



function  chkFieldDataType( fldName, fldType, fldRequired )  {

	var  FieldStyleGood = "color: black; background-color: #F0FFF0";
	var  FieldStyleBad  = "color: brown; background-color: pink";
	var  chkField;
	var  fldValue;
	var  btnVisibility;

	/***/  dbgOut( "chkFieldDataType( " + fldName + ", " + fldType + ", " + fldRequired + " )" );

	chkField = getElem( fldName );
	/*** FieldStyleGood = chkField.style.cssText; ***/
	if  ( !( typeof( chkField ) == "undefined"  ||  chkField ==  null  ||  chkField == "" ) )  {
		fldValue = chkField.value;
		if  ( fldValue == null  ||  fldValue == "" )  {
			if  ( fldRequired )  {
				chkField.style.cssText = FieldStyleBad;
				alert( "Input error:\nThis is a required field!" );
				chkField.focus();
				chkField.select();
				btnVisibility = "hidden";
				setUpdateButtonVisibility( btnVisibility );
			}
		}
		else  {
			if  (
			      ( fldType == "NUMERIC"  &&  isNaN( fldValue ) )
			    )  {
				chkField.style.cssText = FieldStyleBad;
				alert( "Input error:\nThis is a numeric field!" );
				chkField.focus();
				chkField.select();
				btnVisibility = "hidden";
			}
			else  {
				chkField.style.cssText = FieldStyleGood;
				btnVisibility = "visible";
			}
			setUpdateButtonVisibility( btnVisibility );
		}
	}
	JSc.value += "btnVisibility = " + btnVisibility + "<br/>";
}



/***********************************************************************************************/

/* ==================================================================
   THIS FUNCTION IS TAKEN DIRECTLY FROM NETSCAPE FROM:
   http://developer.netscape.com/library/examples/...
                    .../javascript/formval/FormChek.js
   which is a bunch of functions to validate forms

   FUNCTION: isCreditCard(st)
   INPUT:    st - a string representing a credit card number
   RETURNS:  true, if the credit card number passes the Luhn Mod-10 test
	         false, otherwise
   ================================================================== */

function isCreditCard(st) {
  if (st.length > 19)
    return (false);

  var sum = 0;
  var mul = 1;
  var l = st.length;
  for (var i = 0; i < l; i++) {
    var digit = st.substring(l-i-1,l-i);
    var tproduct = parseInt(digit ,10)*mul;
    if (tproduct >= 10)
      sum += (tproduct % 10) + 1;
    else
      sum += tproduct;
    if (mul == 1)
      mul++;
    else
      mul--;
  }

  if ((sum % 10) == 0)
    return (true);
  else
    return (false);
}


/***  ====================================================  ***/
/***  from http://javascript.about.com/library/blccard.htm  ***/
/***                                                        ***/
// Credit Card Validation Javascript
// copyright 12th May 2003, by Stephen Chapman, Felgall Pty Ltd

// You have permission to copy and use this javascript provided that
// the content of the script is not changed in any way.

function validateCreditCard(s) {
//function cardval(s) {
// remove non-numerics
var v = "0123456789";
var w = "";
for (i=0; i < s.length; i++) {
x = s.charAt(i);
if (v.indexOf(x,0) != -1)
w += x;
}
// validate number
j = w.length / 2;
if (j < 6.5 || j > 8 || j == 7) return false;
k = Math.floor(j);
m = Math.ceil(j) - k;
c = 0;
for (i=0; i<k; i++) {
a = w.charAt(i*2+m) * 2;
c += a > 9 ? Math.floor(a/10 + a%10) : a;
}
for (i=0; i<k+m; i++) c += w.charAt(i*2+1-m) * 1;
return (c%10 == 0);
}


/***********************************************************************************************/




function formatNameString( argStrObj )  {

	//==JSc.value += "<br /><B>formatNameString( " + argStrObj.constructor + " )</B>\n<br />";
	//==JSc.value += "<br /><B>formatNameString: " + typeof( argStrObj ) + ", size = " + argStrObj.length + "</B>\n<br />";

	if  ( typeof( argStrObj ) == "string" )  {
		var arrStrObj = argStrObj.split( ";" );
	}
	else  {
		if  ( argStrObj.constructor == Array )
			var arrStrObj = argStrObj;
		else
			var arrStrObj = new Array( argStrObj );
	}

	//==JSc.value += "<br /><B>formatNameString: " + typeof( arrStrObj ) + ", size = " + arrStrObjSize + "</B>\n<br />";

	for  ( iobj  in  arrStrObj )  {

		var curStrObj = arrStrObj[ iobj ];

		if  ( typeof( curStrObj ) == "string" )
			var StrObj = getElem( trimStr( curStrObj ) );
		else
			var StrObj = curStrObj;

		if  ( typeof( StrObj ) != "undefined"  &&  StrObj != null )  {

			var NameStr = trimStr( new String( StrObj.value ) );
			var StrArr = NameStr.split( " " );
			var StrArrSize = StrArr.length;
			var Si;
			var FmtNameStr;
			var FmtNameArr = [];
			var j = 0;

			//==JSc.value += "<br /><B>formatNameString( " + StrObj.name + " )</B>\n<br />";

			for  ( var i=0;  i < StrArrSize;  i++ )  {

				var SAi = trimStr( StrArr[ i ] );

				//==JSc.value += "<br /><B>SAi = " + SAi + "\n<br />";

				if  (
				      ( isDigit( SAi.substring( 0, 1 ) ) )
				    )
				{
					Si = SAi
					//==JSc.value += "<br /><B>Si (SAi) = " + Si + "\n<br />";
				}
				else  {
					Si = SAi.toLowerCase();
					//==JSc.value += "<br /><B>Si (SAi lowercase) = " + Si + "\n<br />";
					var Ch1   = Si.substring( 0, 1 );
					var Ch2   = Si.substring( 1, 2 );
					var Ch12  = Si.substring( 0, 2 );
					var Ch123 = Si.substring( 0, 3 );
					var Ch3   = Si.substring( 2, 3 );
					var SiLen = Si.length;

					if  ( Ch12 == "mc" )  {
						Si = "Mc" + Si.substring( 2, 3 ).toUpperCase() + Si.substring( 3, SiLen );
					}
					else if  ( Ch123 == "mac" )  {
						Si = "Mac" + Si.substring( 3, 4 ).toUpperCase() + Si.substring( 4, SiLen );
					}
					else if  ( ( Ch12 == "on"  ||  Ch12 == "or" )  &&  ( Ch3 == "e"  || Ch3 == "i" )  &&  SiLen > 4 )  {
						Si = Ch12.toUpperCase() + Si.substring( 2, SiLen );
					}
					else if  ( Ch12 == "d'" )  {
						Si = Ch123.toUpperCase() + Si.substring( 3, SiLen );
					}
					else if  ( !isAlphaNumeric( Ch2 ) )  {
						Si = Ch123.toUpperCase() + Si.substring( 3, SiLen );
					}
					else if  ( SiLen == 3  &&  ( Ch123 == "von"  ||  Ch123 == "van" ) )   {
						Si = Ch123;
					}
					else  {
						Si = Ch1.toUpperCase() + Si.substring( 1, SiLen );
					}
				}
				//==JSc.value += "<br /><B>Si (final) = " + Si + "\n<br />";
				if  ( Si != "" )
					FmtNameArr[ j++ ] = Si;
			}
			FmtNameStr = trimStr( FmtNameArr.join( " " ) );

			StrObj.value = FmtNameStr;
		}
	}
}


function  FormatNameFields( fldFirstName, fldMiddleName, fldLastName, fldFullName, fldSortName, fldPreferredName, fldNickName )  {

	var fFirst     = getElem( fldFirstName,     "fFirstName"  );
	var fMiddle    = getElem( fldMiddleName,    "fMiddleName" );
	var fLast      = getElem( fldLastName,      "fLastName"   );
	var fFull      = getElem( fldFullName,      "fFullName"   );
	var fSort      = getElem( fldSortName,      "fSortName"   );
	var fPreferred = getElem( fldPreferredName, "fUserName"   );
	var fNick      = getElem( fldNickName,      "fNickName"   );
	var allNames   = new Array( fFirst, fMiddle, fLast, fFull, fSort, fPreferred, fNick );

	JSc.value += "<br /><B>FormatNameFields()</B>\n<br />";

	formatNameString( allNames );

	var vFirst     = trimStr( fFirst.value     );
	var vMiddle    = trimStr( fMiddle.value    );
	var vLast      = trimStr( fLast.value      );
	var vPreferred = trimStr( fPreferred.value );
	var vNick      = trimStr( fNick.value      );
	var vComma  = "";
	if  ( vLast != ""  &&  ( vFirst + vMiddle ) != "" )  {
		vComma  = ", ";
		if  ( vMiddle != "" )  {
			vMiddle = " " + vMiddle;
		}
	}
	if  ( vPreferred == "" )
		fPreferred.value = trimStr( vFirst + " " + vLast );
	if  ( vNick == "" )
		fNick.value = vFirst;

	fFull.value = trimStr( vFirst + vMiddle + " " + vLast );
	fSort.value = trimStr( vLast + vComma + vFirst + vMiddle );
}


/******************************************************************************

  Attributes and Functions for Elements
  =====================================

	attributes
		returns an array of all the attributes of this element. Does not work with Internet Explorer below version 6.

	data
		returns or sets the textual data of the node

	nodeName
		returns the name of the node (the HTML element name)

	nodeType
		returns the type of the node:
			1 is an element node,
			2 attribute, and
			3 text.

	nodeValue
		returns or sets the value of the node. This value is the text when the node is a textnode, the attribute if it is an attribute or null if it is an element.

	getAttribute( attribute )
		returns the value of the attribute attribute.


	Tools to Navigate from a Certain Element
	========================================

		childNodes
			returns an array of all the nodes inside the current one. There is also firstChild and lastChild, which are shorter versions for childNodes[0] and childNodes[this.childNodes.length-1].

		parentNode
			The element containing this one

		nextSibling
			the next element on the same level in the document tree

		previousSibling
			the previous element on the same level in the document tree


******************************************************************************/


/******************************************************************************
  addElemEvent
    EAH - July 15, 2008

    Adds an event, such as onClick, to a document element.


******************************************************************************/

function  addElemEvent( elemEvent, typeEvent, codeEvent, SetOrAdd )  {

	var  objEvent, EventType, onEvent, EventAction;

	objEvent = ( ( typeof( elemEvent ) != "undefined" )  &&  ( typeof( elemEvent ) == "object" )  ?  elemEvent  :  getElem( elemEvent ) );

	if  ( objEvent )  {
		typeEvent = typeEvent.toLowerCase();

		if  ( typeof( SetOrAdd ) == "undefined"  ||  SetOrAdd != "Set" )
			SetOrAdd = "Add";

		try  {
			if  ( typeof( codeEvent ) == "string" )
				codeEvent = Function( codeEvent );
			if  ( typeof( codeEvent ) == "undefined" )  {
				/***/  alert( "addElemEvent Error: " + typeEvent + "\ncodeEvent is undefined." );
				return  false;
			}
			//***/  dbgOut( "addElemEvent: " + typeEvent + " =\n" + codeEvent );
			//***/  alert( "addElemEvent 1: " + typeEvent + " =\n" + codeEvent );

			if  ( typeEvent.substr( 0, 2 ) == "on" )
				EventType = typeEvent.substr( 2 );
			onEvent = "on" + EventType;

			if  ( SetOrAdd == "Set" )  {
				eval( "objEvent." + onEvent + "=" + codeEvent.toString() );
			}
			else  {

				if  ( typeof( objEvent.mgrEvents ) == "undefined" )
					objEvent.mgrEvents = new EventActionManager();

				//***/  alert( "addElemEvent 2: " + typeEvent + " =\n" + codeEvent );
				EventAction = objEvent.mgrEvents.addEventAction( EventType, codeEvent );
				//***/  alert( "addElemEvent 3: " + EventAction + " =\n" + EventAction.toString() );

				//***/  dbgOut( "\naddElemEvent: " + getElemName( objEvent ) + ", " + EventType + " =\n" + codeEvent + "\n" + SetOrAdd + "\nEventAction =\n" + EventAction.toString() );
				//***/  dbgOut( "\naddElemEvent: objEvent.mgrEvents.EventList =\n" + describeObj( objEvent.mgrEvents.EventList ) );
				//***/  if  ( EventType == "mouseout")
					//***/  dbgOut( "\naddElemEvent: " + EventType + " = " + codeEvent + ",\nobjEvent.mgrEvents.EventList[ " + EventType + " ] =\n" + describeObj( objEvent.mgrEvents.EventList[ EventType ] ) );

				if  ( EventAction === false )  {
					return  false;
				}

				if  ( MSIE )  {
					objEvent.detachEvent( onEvent, EventAction );
					objEvent.attachEvent( onEvent, EventAction );
				}
				else  {
					try  {
						objEvent.removeEventListener( EventType, EventAction, false );
					}
					catch( err )  {
						/***/  dbgOut( "addElemEvent: Cannot removeEventListener( " + EventType + " )" );
					}
					objEvent.addEventListener( EventType, EventAction, false );
				}
			}
		}
		catch( err )  {
			/***/  alert( "addElemEvent Error: " + getElemName( objEvent ) + ", " + typeEvent + " =\n" + codeEvent + "\n" + SetOrAdd + "\nError =\n" + err.description );
			return  false;
		}
		return  true;
	}
	else
		return  false;
}


function  xaddElemEvent( elemEvent, typeEvent, codeEvent, SetOrAdd )  {

	typeEvent = typeEvent.toLowerCase();
	if  ( typeof( SetOrAdd ) == "undefined"  ||  SetOrAdd != "Set" )
		SetOrAdd = "Add";
	var  objEvent = ( ( typeof( elemEvent ) != "undefined" )  &&  ( typeof( elemEvent ) == "object" )  ?  elemEvent  :  getElem( elemEvent ) );

	if  ( objEvent )  {
		try  {
			if  ( typeof( codeEvent ) == "string" )
				codeEvent = Function( codeEvent );
			if  ( typeof( codeEvent ) == "undefined" )  {
				/***/  alert( "addElemEvent Error: " + typeEvent + "\ncodeEvent is undefined." );
				return  false;
			}
			//***/  alert( "addElemEvent: " + typeEvent + " =\n" + codeEvent );

			if  ( SetOrAdd == "Set" )  {
				eval( "objEvent." + typeEvent + "=" + codeEvent.toString() );
			}
			else  {
				if  ( MSIE )  {
					if  ( typeEvent.substr( 0, 2 ) != "on" )
						typeEvent = "on" + typeEvent;
					objEvent.detachEvent( typeEvent, codeEvent );
					objEvent.attachEvent( typeEvent, codeEvent );
				}
				else  {
					if  ( typeEvent.substr( 0, 2 ) == "on" )
						typeEvent = typeEvent.substr( 2 );
					try  {
						objEvent.removeEventListener( typeEvent, codeEvent, false );
					}
					catch( err ) {};
					objEvent.addEventListener( typeEvent, codeEvent, false );
				}
			}
		}
		catch( err ) {
			/***/  alert( "addElemEvent Error: " + getElemName( objEvent ) + ", " + typeEvent + " =\n" + codeEvent + "\n" + SetOrAdd + "\nError =\n" + err.description );
			return  false;
		}
		return  true;
	}
	else
		return  false;
}


/******************************************************************************
  deleteElemEvent
    EAH - July 15, 2008

    Deletes an event, such as onClick, to a document element.
    Note: The Add operation has not yet been tested.

******************************************************************************/

function  deleteElemEvent( elemEvent, typeEvent, codeEvent, SetOrAdd )  {

	typeEvent = typeEvent.toLowerCase();
	var  objEvent = ( ( typeof( elemEvent ) != "undefined" )  &&  ( typeof( elemEvent ) == "object" )  ?  elemEvent  :  getElem( elemEvent ) );

	if  ( objEvent )  {
		try  {
			if  ( typeof( codeEvent ) == "string" )
				codeEvent = Function( codeEvent );

			if  ( MSIE )  {
				if  ( typeEvent.substr( 0, 2 ) != "on" )
					typeEvent = "on" + typeEvent;
				objEvent.detachEvent( typeEvent, codeEvent );
			}
			else  {
				if  ( typeEvent.substr( 0, 2 ) == "on" )
					typeEvent = typeEvent.substr( 2 );
				objEvent.removeEventListener( typeEvent, codeEvent, false );
				//***/  alert( "deleteElemEvent removeEventListener: " + typeEvent );
			}
		}
		catch( err ) {
			/***/  alert( "deleteElemEvent Error: " + typeEvent + "\n" + err.description );
		}
	}
}


/******************************************************************************
  addFieldEvent
    EAH - July 15, 2008

    Adds an event, such as onClick, to a data entry field.
    The event is actually added to the parent DisplayField container object.

******************************************************************************/

function  addFieldEvent( fieldEvent, typeEvent, strEvent, SetOrAdd )  {

	var  objEvent;
	var  parentElem;

	if  ( ( objEvent = getElem( fieldEvent ) )  &&  ( parentElem = objEvent.parentNode ) )
		addFieldEvent( parentElem, typeEvent, strEvent, SetOrAdd );
}

/***************************************** /
function  addFieldEvent( fieldEvent, typeEvent, strEvent, SetOrAdd )  {

	//*** /  dbgOut( "addFieldEvent: " + fieldEvent + "." + typeEvent.toLowerCase() + " = " + strEvent );

	if  ( SetOrAdd == null )
		SetOrAdd = "Set";

	var  objEvent;
	var  parentElem;
	var  Operation = ( SetOrAdd == "Add"  ?  " += "  :  " = " );

	if  ( ( objEvent = getElem( fieldEvent ) )  &&  ( parentElem = objEvent.parentNode ) )
		try  {
			eval( "parentElem." + typeEvent.toLowerCase() + Operation + "function anonymous() { " + strEvent + " };" );
		}
		catch( err ) {
			/*** /  alert( "addFieldEvent Error: " + typeEvent + "\n" + err.description );
		};
}
/*****************************************/



/******************************************************************************
  sortTextArea
    EAH - May 12, 2009

	SortOperation:
	- Sort
	- Reverse
	- Reset

******************************************************************************/

function  sortTextArea( elemTextArea )  {

	var  elemSortText = getElem( elemTextArea );

	with  ( elemSortText )  {

		value = value.replace( /\r\n/g, "\n" );

		if  ( typeof( elemSortText.SaveValue ) == "undefined" )
			elemSortText.SaveValue = value;

		if  ( typeof( elemSortText.LastValue ) == "undefined" )
			elemSortText.LastValue = value;

		if  ( typeof( elemSortText.SortMode ) == "undefined" )
			elemSortText.SortMode = "Sort";

		if  ( value != LastValue )  {
			SaveValue = value;
			SortMode = "Sort";
		}

		if  ( SortMode == "Reset" )  {
			value = SaveValue;
			SortMode = "Sort";
		}
		else  {
			var  arrText = value.split( "\n" );
			if  ( SortMode == "Sort" )  {
				arrText.sort();
				SortMode = "Reverse";
			}
			else  {
				arrText.reverse();
				SortMode = "Reset";
			}
			value = arrText.join( "\n" );
		}
		LastValue = value;
	}
}


/***  Old version of sortTextArea using hidden fields:  ***/
function  x_sortTextArea( elemTextArea )  {

	var  elemSortText = getElem( elemTextArea );
	var  SaveTextField = getRelatedHiddenField( elemSortText, "save_", elemSortText.value );
	var  SortModeField = getRelatedHiddenField( elemSortText, "sort_", "Reset" );

	if  ( SaveTextField  &&  SaveTextField.value )  {
		var  SortMode = SortModeField.value;
		//alert( SortMode + ", " + SortModeField.name );
		if  ( SortMode == "Reset" )  {
			elemSortText.value = SaveTextField.value;
			SortModeField.value = "Sort";
		}
		else  {
			var  strText = elemSortText.value.replace( /\r\n/g, "\n" );
			var  arrText = strText.split( "\n" );
			if  ( SortMode == "Sort" )  {
				arrText.sort();
				SortModeField.value = "Reverse";
			}
			else  {
				arrText.reverse();
				SortModeField.value = "Reset";
			}
			elemSortText.value = arrText.join( "\n" );
		}
	}
}



/******************************************************************************
  getRelatedHiddenField
    EAH - May 12, 2009


******************************************************************************/

function  getRelatedHiddenField( elemObj, NamePrefix, InitialValue )  {

	var  elemName = getElemName( elemObj );
	var  HiddenFieldName = NamePrefix + elemName;
	var  HiddenField = getElem( HiddenFieldName );

	if  ( !HiddenField )
		HiddenField = createHiddenField( elemObj.parentNode, HiddenFieldName, InitialValue );

	return  HiddenField;
}



/******************************************************************************
  createHiddenField
    EAH - May 12, 2009


******************************************************************************/

function  createHiddenField( elemParent, HiddenFieldName, InitialValue )  {

	HiddenField = document.createElement( "<input type=\"hidden\" name=\"" + HiddenFieldName + "\" id=\"" + HiddenFieldName + "\"/>" );
	HiddenField.value = InitialValue;
	elemParent.appendChild( HiddenField );

	return  HiddenField;
}



/******************************************************************************
  diagramRelationship
    EAH - May 9, 2009


******************************************************************************/

function  diagramRelationship( elemDiagramName, RelationshipList )  {

	var  elemDiagram = getElem( elemDiagramName );


	/***  Create the diagram boxes:  ***/

	elemDiagram.innerHTML = "";

	var  BoxStyle;
	var  arrBoxes = new  Array();
	var  idx = 0;

	elemDiagram.style.display    = "block";
	elemDiagram.style.visibility = "visible";

	var  BoxesX0 = elemDiagram.offsetLeft;
	var  BoxesY0 = elemDiagram.offsetTop;
	var  BoxesSpacingX = 60;
	var  BoxesSpacingY = 60;

	BoxStyle = "font-size:9px; height:50px; width:100px; float:left; margin:5px; padding:5px; color:black; background:lightblue;";
	BoxStyle = "font-size:9px; text-align:left; width:100px; float:left; margin:5px; padding:5px; white-space:nowrap; color:black; background:lightblue;";
	BoxStyle = "font-size:9px; text-align:left; width:100px; position:absolute; float:left; margin:5px; padding:5px; white-space:nowrap; color:black; background:lightblue;";


	var  curBoxX = BoxesX0 + BoxesSpacingX;
	var  curBoxY = BoxesY0 + BoxesSpacingY;


	for  ( var  key  in  RelationshipList )  {
		if  ( typeof( ArrayMethods[ key ] ) == "undefined" )  {
			arrBoxes[ idx ] = document.createElement( "<div style=\"" + BoxStyle + "\"></div>" );
			arrBoxes[ idx ].innerHTML = ( idx + 1 ) + "<br/>" + RelationshipList[ key ];
			arrBoxes[ idx ].style.left = curBoxX + "px";
			arrBoxes[ idx ].style.top  = curBoxY + "px";
			elemDiagram.appendChild( arrBoxes[ idx ] );
			alert( arrBoxes[ idx ].offsetWidth );
			curBoxX += arrBoxes[ idx ].offsetWidth + BoxesSpacingX;
			idx++;
		}
	}


	/***  Align the boxes:  *** /

	var  elemDiagramTop = elemDiagram.offsetTop;
	var  MaxBoxHeight = curLineTop = 0;

	for  ( var  i  in  arrBoxes )  {
		if  ( i%2 )
			arrBoxes[ i ].style.backgroundColor = "lightgreen";
		if  ( arrBoxes[ i ].offsetTop > curLineTop )  {
			var  newTop = elemDiagramTop + MaxBoxHeight + curLineTop + 10;
			//arrBoxes[ i ].style.top = newTop + "px";
			//arrBoxes[ i ].style.left = "10px";
			//arrBoxes[ i ].style.marginTop = "100px";
			curLineTop = arrBoxes[ i ].offsetTop;
			MaxBoxHeight = arrBoxes[ i ].offsetHeight;
		}
		else  {
			if  ( arrBoxes[ i ].offsetHeight > MaxBoxHeight )
				MaxBoxHeight = arrBoxes[ i ].offsetHeight;
		}
		arrBoxes[ i ].innerHTML += "<br/>" + arrBoxes[ i ].offsetHeight + ", " + arrBoxes[ i ].offsetTop + ", " + curLineTop + ", " + MaxBoxHeight +
		                           "<br/>" + elemDiagramTop + ", " + newTop;
	}
	/***/
}





/***
 *    AjaxQueue Class
 *    ===============
 *
 *      EAH  -  November 2, 2009
 *
 *    Queue Ajax requests and handle the responses.
 *
 *    parameters:
 *      - fncRequestHandler:   Request Handler function
 *      - fncResponseHandler:  Response Handler function
 *      - flgMultiLevel:       Single (false) or Multi-level (true) queueing
 *      - flgRepeatRequest:    Send request if new request is identical to the last request
 *
 *    Operations:
 *      - handleRequest
 *      - handleResponse
 *      - clearQueue
 *
 *
***/

var

AjaxQueue = function ( fncRequestHandler, fncResponseHandler, flgMultiLevel, flgRepeatRequest )  {

	this.initialized;

	this.RequestHandler;
	this.ResponseHandler;
	this.MultiLevel;
	this.RepeatRequest;

	this.QueueBusy;
	this.LastReq;
	this.QueueRequest;
	this.QueueResponse;


	/***  AjaxQueue.initialize():  ***/

	this.initialize = function() {

		var  fncNull = function()  { return  null; };

		this.RequestHandler  = getArg( fncRequestHandler,  fncNull );
		this.ResponseHandler = getArg( fncResponseHandler, fncNull );
		this.MultiLevel      = getArg( flgMultiLevel,      false   );
		this.RepeatRequest   = getArg( flgRepeatRequest,   false   );

		this.QueueBusy       = false;
		this.LastReq         = new  Array();
		this.RequestQueue    = new  Array();
		this.ResponseData    = new  Array();

		this.initialized     = true;
	}


	/***  AjaxQueue.clearQueue():  ***/

	this.clearQueue = function() {

		this.QueueBusy = false;
		this.RequestQueue = [];
	}


	/***  Queue Request Handler:  ***/

	this.handleRequest = function( arrRequest )  {

		//***/  dbgOut( "*****  AjaxQueue.handleRequest: arrRequest =\n" + describeObj( arrRequest ) );
		if  ( this.QueueBusy )  {
			//***/  dbgOut( "Queue Busy" );
			if  ( arrRequest != this.LastReq )  {
				//***/  dbgOut( "New Request" );
				if  ( this.MultiLevel )
					this.RequestQueue.push( arrRequest );
				else
					this.RequestQueue[ 0 ] = arrRequest;
				document.body.style.cursor = "wait";
			}
		}
		else  {
			//***/  dbgOut( "Queue NOT Busy: Set QueueBusy flag TRUE" );
			this.QueueBusy = true;
			if  ( arrRequest == this.LastReq )  {
				//***/  dbgOut( "Duplicate Request" );
				if  ( this.RepeatRequest )  {
					this.handleResponse( this.ResponseData );
				}
			}
			else  {
				//***/  dbgOut( "New Request" );
				//***/  alert( "AjaxQueue.handleRequest: New Request, Queue NOT Busy\narrRequest =\n" + describeObj( arrRequest ) );
				//***/  alert( "AjaxQueue.handleRequest call this.RequestHandler =\n" + describeObj( this.RequestHandler ) );
				document.body.style.cursor = "progress";
				this.LastReq = arrRequest;
				this.RequestQueue = [];
				this.RequestHandler( arrRequest );
				//***/  alert( "AjaxQueue.handleRequest AFTER call this.RequestHandler =\n" + describeObj( this.RequestHandler ) );
			}
		}
		//***/  dbgOut( "*****  END AjaxQueue.handleRequest" );
	}


	/***  Queue Response Handler:  ***/

	this.handleResponse = function( arrResponse )  {

		//***/  dbgOut( "*****  AjaxQueue.handleResponse: arrResponse =\n" + describeObj( arrResponse ) );
		//***/  alert( "AjaxQueue.handleResponse arrResponse =\n" + describeObj( arrResponse ) );
		//***/  alert( "AjaxQueue.handleResponse this.ResponseHandler =\n" + describeObj( this.ResponseHandler ) );
		//***/  alert( "AjaxQueue.handleResponse:\nthis.MultiLevel = \"" + this.MultiLevel + "\"\nthis.RequestQueue.length = \"" + this.RequestQueue.length + "\"" );

		//MainIW.qAjaxWriteInfoWindow( arrResponse );

		var  qReq;

		this.ResponseData = arrResponse;
		this.QueueBusy = false;

		if  ( this.MultiLevel )  {
			//***/  dbgOut( "MultiLevel Response" );
			document.body.style.cursor = "default";
			this.ResponseHandler( this.ResponseData );
			if  ( this.RequestQueue.length > 0 )  {
				/***/  dbgOut( "Handle a waiting Request in the RequestQueue" );
				qReq = this.RequestQueue.shift();
				this.handleRequest( qReq );
			}
		}
		else  {
			//***/  dbgOut( "Single Level Response" );
			if  ( this.RequestQueue.length > 0 )  {
				//***/  dbgOut( "Handle a waiting Request in the RequestQueue" );
				qReq = this.RequestQueue.shift();
				this.handleRequest( qReq );
			}
			else  {
				//***/  dbgOut( "Handle the Response" );
				//***/  alert( "AjaxQueue.handleResponse this.ResponseData =\n" + describeObj( this.ResponseData ) );
				//***/  alert( "AjaxQueue.handleResponse call this.ResponseHandler =\n" + describeObj( this.ResponseHandler ) );
				document.body.style.cursor = "default";
				this.ResponseHandler( this.ResponseData );
				//***/  alert( "AjaxQueue.handleResponse AFTER call this.ResponseHandler =\n" + describeObj( this.ResponseHandler ) );
			}
		}
		//***/  dbgOut( "*****  END AjaxQueue.handleResponse" );
	}


	/***  Main Body of AjaxQueue:  ***/

/*
	AjaxQueue.prototype.initialize     = AjaxQueue.initialize;
	AjaxQueue.prototype.clearQueue     = AjaxQueue.clearQueue;
	AjaxQueue.prototype.handleRequest  = AjaxQueue.handleRequest;
	AjaxQueue.prototype.handleResponse = AjaxQueue.handleResponse;
*/

	this.initialized = false;

	return  this.initialize();
}

/***  End of AjaxQueue Class.  ***/





/***
 *    VariableFunction Class
 *    ======================
 *
 *      EAH  -  April 9, 2010
 *
 *    Create a redefinable function that can be used with mouse events,
 *    i.e., onclick, onmouseover, etc.
 *
 *    parameters:
 *      - vfCode:   Variable Function code, as a string or function
 *
 *    Operations:
 *      - define:   (Re)Define the Variable Function
 *
 *
***/

var

VariableFunction = function( vfCode )  {

	var  ThisVF = this;

	/***  Initialize the variable function:  ***/
	this.initialize = function()  {
		if  ( typeof( vfCode ) != "undefined" )
			this.define( vfCode );
		//***/  dbgOut( "\nNew VariableFunction initialized" );
	}


	/***  The variable function declaration:  ***/
	this.vFunction = function( evt ) {};


	/***  The function that is executed externally wraps the variable function:  ***/
	this.f = function( evt )  { ThisVF.vFunction( evt ); };


	/***  The define method redefines the variable function:  ***/
	this.define = function( vfCodeNew )  {
		if  ( typeof( vfCodeNew ) == "string" )  {
			this.vFunction = Function( vfCodeNew );
		}
		else  {
			this.vFunction = vfCodeNew;
		}
	}


	/***  The get method retrieves the variable function as a string:  ***/
	this.get = function()  {
		return  this.f.toString();
	}

/*
	VariableFunction.prototype.initialize = VariableFunction.initialize;
	VariableFunction.prototype.vFunction  = VariableFunction.vFunction;
	VariableFunction.prototype.f          = VariableFunction.f;
	VariableFunction.prototype.define     = VariableFunction.define;
	VariableFunction.prototype.get        = VariableFunction.get;
*/

	return  this.initialize();
}

/***  End of VariableFunction Class.  ***/





/***
 *    EventActionManager Class
 *    ========================
 *
 *      EAH  -  April 18, 2010
 *
 *    Create and maintain a list of mouse events and actions attached to a DOM object,
 *    i.e., onclick, onmouseover, etc.
 *
 *    parameters:
 *      - objEvent:   The DOM object to be managed
 *
 *    Operations:
 *      - addEventAction:   Add/Update an event and action for the DOM object
 *
 *
***/

var

EventActionManager = function()  {

	this.EventList;


	this.initialize = function()  {
		this.EventList = new Array();
		//***/  alert( "EventActionManager: typeofObject( this ) = \"" + typeofObject( this ) + "\"" );
		//***/  dbgOut( "\nNew EventActionManager initialized" );
	}


	this.addEventAction = function( EventType, EventAction )  {

		if  ( typeof( this.EventList[ EventType ] ) == "undefined" )
			this.EventList[ EventType ] = new Array();

		//***/  dbgOut( "\nEventActionManager.addEventAction: typeof( this.EventList[ EventType ] ) = " + typeof( this.EventList[ EventType ] ) );

		try  {
			var  vf  = new VariableFunction( EventAction );
		}
		catch( err )  {
			/***/  alert( "EventActionManager: Cannot create new VariableFunction( " + EventAction.toString() + " )" );
		}

		try  {
			var  key = this.EventList[ EventType ].update( EventAction );
		}
		catch( err )  {
			/***/  alert( "EventActionManager: Cannot update EventList" );
		}

		//***/  dbgOut( "\nEventActionManager.addEventAction( " + EventType + ",\n" + vf.f.toString() + " );" );
		//***/  dbgOut( "\nEventActionManager.addEventAction:\nEventList =\n" + describeObj( this.EventList ) );
		//***/  dbgOut( "\nEventActionManager.addEventAction:\nKey = " + key );

		if  ( key !== false )
			return  this.EventList[ EventType ][ key ];
		else
			return  false;
	}

/*
	EventActionManager.prototype.initialize     = EventActionManager.initialize;
	EventActionManager.prototype.addEventAction = EventActionManager.addEventAction;
*/

	return  this.initialize();

}

/***  End of EventActionManager Class.  ***/






/***
 *    TableFilter Class
 *    =================
 *
 *      EAH  -  October 28, 2009
 *
 *    Filter a browser DOM object to only display certain elements fitting the search criteria.
 *
 *    parameters:
 *
 *      - elemSearch:  The DOM object to search
 *
 *      - TagType:     The type of tag elements to filter within elemSearch
 *
 *      - prefixID:    An optional prefix on the tag IDs to further define the elements to filter
 *
 *      - sFilter:     An optional search string containing the filter criteria
 *
 *
 *    Operations:
 *
 *      - filter:      Selectively display data fitting the search criteria
 *
 *
***/

var

TableFilter = function ( elemSearch, TagType, prefixID, sFilter )  {

	this.initialized;
	this.objSearch;
	this.objSearchList;
	this.SearchList;
	this.FilterText  = "";


	/***  TableFilter.initialize():  ***/

	this.initialize = function() {

		this.objSearch = getElem( elemSearch, document );
		this.objSearchList = this.objSearch.getElementsByTagName( getArg( TagType, "*" ) );

		var  curID, curElem, curElemList, objNodes, subNodes;
		objNodes = [];
		this.SearchList = [];

		for  ( var  i = 0;  i < this.objSearchList.length;  i++ )  {
			curID = getArg( this.objSearchList[ i ].id );
			if  ( curID  &&  curID.startsWith( prefixID ) )  {
				objNodes = subNodes = [];
				curElem = this.objSearchList[ i ];
				curElemList = curElem.childNodes;
				for  ( var  j = 0;  j < curElemList.length;  j++ )  {
					if  ( typeof( curElemList[ j ].innerHTML ) != "undefined" )  {
						subNodes[ subNodes.length ] = curElemList[ j ];
					}
				}
				if  ( subNodes.length > 0 )  {
					objNodes[ "Object" ] = curElem;
					objNodes[ "Nodes"  ] = subNodes;
					this.SearchList[ this.SearchList.length ] = objNodes;
				}
			}
		}
		this.initialized = true;
	}



	this.filter = function( sFilter )  {

		if  ( !this.initialized )
			this.initialize();

		var  FoundText, curElem, curElemList, curText, narrowSearch, expandSearch;

		lcFilterText = getArg( sFilter ).toLowerCase();

		if  ( lcFilterText == this.FilterText )
			return;

		if  ( lcFilterText == "" )  {
			for  ( var  i = 0;  i < this.SearchList.length;  i++ )  {
				this.SearchList[ i ][ "Object" ].style.visibility = "";
				this.SearchList[ i ][ "Object" ].style.display = "";
			}
		}
		else  {
			narrowSearch = ( lcFilterText.indexOf( this.FilterText ) >= 0 );
			expandSearch = ( this.FilterText.indexOf( lcFilterText ) >= 0 );
			for  ( var  i = 0;  i < this.SearchList.length;  i++ )  {
				curElem = this.SearchList[ i ][ "Object" ];
				if  ( ( narrowSearch  &&  curElem.style.visibility != "hidden" )  ||  ( expandSearch  &&  curElem.style.visibility == "hidden" )  ||  ( !narrowSearch  &&  !expandSearch ) )  {
					FoundText = false;
					if  ( curElem.innerHTML.toLowerCase().indexOf( lcFilterText ) >= 0 )  {
						curElemList = this.SearchList[ i ][ "Nodes" ];
						for  ( var  j = 0;  j < curElemList.length;  j++ )  {
							if  ( !FoundText )  {
								curText = curElemList[ j ].innerHTML.toLowerCase();
								if  ( curText.indexOf( lcFilterText ) >= 0 )  {
									FoundText = true;
								}
							}
						}
					}
					if  ( FoundText )  {
						//  Show row:
						curElem.style.visibility = "";
						curElem.style.display = "";
					}
					else  {
						//  Hide row:
						curElem.style.visibility = "hidden";
						curElem.style.display = "none";
					}
				}
			}
		}
		this.FilterText = lcFilterText;
	}


	/***  Main Body of TableFilter:  ***/

/*
	TableFilter.prototype.initialize = TableFilter.initialize;
	TableFilter.prototype.filter     = TableFilter.filter;
*/

	this.initialized = false;

	if  ( getArg( sFilter ) )
		this.filter( sFilter );
}


/***  End of TableFilter Class.  ***/




/***
 *    CursorIO Class
 *    ==============
 *
 *      EAH  -  September 24, 2009
 *
 *    Cursor and text manipulation in Text boxes in browser window.
 *
 *
 *    Operations:
 *
 *      - getText:    Read selected text
 *                    Read entire text
 *
 *      - putText:    Overwrite selected text
 *
 *      - getCursor:  Return cursor position (selection area) within the entire text
 *
 *      - setCursor:  Set the cursor position within the entire text
 *
 *                    Reposition cursor before or after the selection:
 *                    - Start   :  Start of Field
 *                    - End     :  End of Field
 *                    - Before  :  Before Selection
 *                    - After   :  After Selection
 *                    - +/-<number>   :  Absolute position within Field; from Start (+) or End (-)
 *                    - @+|-<number>  :  Relative to current position; from After (+) or Before (-)
 *
 *                    Select a range of characters within the text:
 *                    - <position>,<position>
 *                    - <position>:<length>
 *
***/

var

CursorIO = function ( obj )  {

	this.initialized;
	this.objTextBox;
	this.allText;
	this.selText;
	this.replacedText;
	this.range;
	this.selStart;
	this.selEnd;


	/***  CursorIO.initialize():  ***/

	this.initialize = function() {

		/***  All browsers:  ***/
		this.allText = this.objTextBox.value;
		this.selText = this.replacedText = "";

		/***  IE and Opera use the document selection range to manipulate text within elements:  ***/
		if  ( document.selection ) {

			/***  Focus the object before retrieving the selection:  ***/
			this.objTextBox.focus();

			this.range = document.selection.createRange();

			/***  Verify that the selected range is in desired object:  ***/
			this.initialized = ( this.range.parentElement() == this.objTextBox );
		}

		/***  Gecko (Firefox), Opera, and Chrome use selectionStart and selectionEnd to manipulate text within elements:  ***/
		if  ( typeof( this.objTextBox.selectionStart ) != "undefined"  &&  this.objTextBox.selectionStart >= 0 )  {

			/***  Find the Start and End Position:  ***/
			this.selStart = this.objTextBox.selectionStart;
			this.selEnd   = this.objTextBox.selectionEnd;
			this.allText  = this.objTextBox.value;
			this.initialized = true;
		}

		//???return  this.initialized;
	}




	/***  CursorIO.setCursor():  ***/

	this.setCursor = function( sCursor ) {

		if  ( !this.initialized )
			return  "";

		var  cmdCursor = getArg( sCursor );

		if  ( typeof( cmdCursor ) == "number" )
			cmdCursor = cmdCursor.toString();

		/***  IE and Opera use the document selection range to manipulate text within elements:  ***/
		if  ( MSIE ) {

			switch  ( cmdCursor )  {
				case  "Start":
				case  "End":
					this.objTextBox.select();
					this.range = document.selection.createRange();
					break;
			}

			switch  ( cmdCursor )  {

				case  "Start":
				case  "Before":
					this.range.collapse( true );
					break;

				case  "End":
				case  "After":
				default:
					this.range.collapse( false );
					break;
			}

			this.range.select();
		}

		/***  Gecko (Firefox), Opera, and Chrome use selectionStart and selectionEnd to manipulate text within elements:  ***/
		else if  ( typeof( this.objTextBox.selectionStart ) != "undefined"  &&  this.objTextBox.selectionStart >= 0 )  {

			var  xScrollPosition = this.objTextBox.scrollLeft;
			var  yScrollPosition = this.objTextBox.scrollTop;
			var  ScrollWidth     = this.objTextBox.scrollWidth;
			var  ScrollHeight    = this.objTextBox.scrollHeight;

			switch  ( cmdCursor )  {

				case  "Start":
					this.objTextBox.select();
					this.selStart = this.selEnd = this.objTextBox.selectionStart;
					break;

				case  "End":
					this.objTextBox.select();
					this.selStart = this.selEnd = this.objTextBox.selectionEnd;
					break;

				case  "Before":
					this.selEnd = this.selStart;
					break;

				case  "After":
				default:
					this.selStart = this.selEnd;
					break;
			}

			this.selText = "";
			this.objTextBox.selectionStart = this.selStart;
			this.objTextBox.selectionEnd   = this.selEnd;

			this.objTextBox.scrollLeft = ( this.objTextBox.scrollWidth  >= ScrollWidth   ?  ( xScrollPosition + ( this.objTextBox.scrollWidth  - ScrollWidth  ) )  :  xScrollPosition );
			this.objTextBox.scrollTop  = ( this.objTextBox.scrollHeight >= ScrollHeight  ?  ( yScrollPosition + ( this.objTextBox.scrollHeight - ScrollHeight ) )  :  yScrollPosition );

		}

		/***  Other browsers:  ***/
		else {
		}

		this.allText = this.objTextBox.value;

		return  true;
	}




	/***  CursorIO.getText():  ***/

	this.getText = function() {

		if  ( !this.initialized )
			return  "";

		/***  IE and Opera use the document selection range to manipulate text within elements:  ***/
		if  ( MSIE ) {

			/***  IE workaround to include cr-lf in returned text:  ***/
			if  ( MSIE ) {
				/*
					 Internet Explorer does not return trailing CRLF characters within the selection
					 area. However, it does replace them when range.text is set to a new value.
					 If only blank lines (only CRLF) are selected, the end point will equal the start point, and
					 the returned range.text will be empty.
					 Therefore, a non-CRLF delimiter character must be temporarily appended to the selection so
					 that the range.text function will return the trailing CRLF characters of the
					 actual selection.
					 The appended delimiter must be removed before passing the text back to the
					 calling function.
				*/

				/***  Insert a trailing delimiter after the selection:  ***/
				var  range2 = this.range.duplicate();
				range2.collapse( false );
				range2.text = " ";

				/***  Retrieve the extended selection:  ***/
				range2.setEndPoint( 'StartToStart', this.range );
				var  ExtendedText = range2.text;

				/***  Retrieve the actual selection:  ***/
				this.selText = ExtendedText.substr( 0, ExtendedText.length - 1 );

				/***  Remove the trailing delimiter:  ***/
				range2.collapse( false );
				range2.moveStart( "character", -1 );
				range2.text = "";
			}
			else  {
				this.selText = this.range.text;
			}
		}

		/***  Gecko (Firefox), Opera, and Chrome use selectionStart and selectionEnd to manipulate text within elements:  ***/
		else if  ( typeof( this.objTextBox.selectionStart ) != "undefined"  &&  this.objTextBox.selectionStart >= 0 )  {
			this.selText  = this.allText.substr( this.selStart, this.selEnd - this.selStart );
		}

		/***  Other browsers:  ***/
		else {
			this.allText = this.objTextBox.value;
			this.selText = "";
		}

		return  this.selText;

	}




	/***  CursorIO.putText():  ***/

	this.putText = function( sIn, sCursor, sPrefix, sSuffix ) {

		//***/  alert( "CursorIO.putText( " + sIn + " );" );

		if  ( !this.initialized )
			return  "";

		this.replacedText = this.getText();

		/***  Convert LF to CRLF in replacement text:  ***/
		var  repText   = getArg( sIn     );  //getArg( sIn, ( this.range  ?  "%Clipboard%"  :  "" ) );
		var  preText   = getArg( sPrefix );
		var  sufText   = getArg( sSuffix );
		var  cmdCursor = getArg( sCursor );

		/***  IE and Opera use the document selection range to manipulate text within elements:  ***/
		if  ( MSIE ) {

			/* Replace the Text */

			var  range2 = this.range.duplicate();
			range2.text = preText + sufText;
			range2.moveEnd( "character", - DisplayedLength( sufText ) );

			if  ( repText == "%Clipboard%" )  {
				range2.execCommand( "Paste" );
			}
			else  {
				range2.text = repText;
			}

			this.range.moveStart( "character", DisplayedLength( preText ) );
			this.range.setEndPoint( 'EndToEnd', range2 );
			this.range.select();

			switch  ( cmdCursor )  {

				case  "Select":
					break;

				case  "Before":
					this.range.collapse( true );
					break;

				case  "After":
				default:
					this.range.collapse( false );
					break;
			}

			this.range.select();

			if  ( repText == "%Clipboard%" )  {
				this.selText = this.getText();
			}
			else  {
				this.selText = this.range.text;
			}
		}

		/***  Gecko (Firefox), Opera, and Chrome use selectionStart and selectionEnd to manipulate text within elements:  ***/
		else if  ( typeof( this.objTextBox.selectionStart ) != "undefined"  &&  this.objTextBox.selectionStart >= 0 )  {

			var  xScrollPosition = this.objTextBox.scrollLeft;
			var  yScrollPosition = this.objTextBox.scrollTop;
			var  ScrollWidth     = this.objTextBox.scrollWidth;
			var  ScrollHeight    = this.objTextBox.scrollHeight;

			this.objTextBox.select();

			/* Replace the Text */

			if  ( repText == "%Clipboard%" )  {
				repText = getElemValue( "fClipboard" );
			}

			this.allText = this.allText.substr( 0, this.selStart )
			               + preText
										 + repText
			               + sufText
			               + this.allText.substr( this.selEnd, this.allText.length );

			this.selStart += DisplayedLength( preText );
			this.selEnd    = this.selStart + ( DisplayedLength( repText ) );

			switch  ( cmdCursor )  {

				case  "Select":
					this.selText = repText;
					break;

				case  "Before":
					this.selEnd = this.selStart;
					this.selText = "";
					break;

				case  "After":
				default:
					this.selStart = this.selEnd;
					this.selText = "";
					break;
			}

			this.objTextBox.value          = this.allText;
			this.objTextBox.selectionStart = this.selStart;
			this.objTextBox.selectionEnd   = this.selEnd;

			this.objTextBox.scrollLeft = ( this.objTextBox.scrollWidth  >= ScrollWidth   ?  ( xScrollPosition + ( this.objTextBox.scrollWidth  - ScrollWidth  ) )  :  xScrollPosition );
			this.objTextBox.scrollTop  = ( this.objTextBox.scrollHeight >= ScrollHeight  ?  ( yScrollPosition + ( this.objTextBox.scrollHeight - ScrollHeight ) )  :  yScrollPosition );
		}

		/***  Other browsers:  ***/
		else {
		}

		this.allText = this.objTextBox.value;

		return  this.replacedText;

	}




	/***  Main Body of CursorIO:  ***/

	this.initialized = false;

	if  ( typeof( obj ) == "undefined"  ||  !obj )  {

		var  curRange, curSel;

		if  ( document.selection )  {
			curRange = document.selection.createRange();
			obj = curRange.parentElement();
		}
		else if  ( ( curSel = window.getSelection() ) )  {
			try  {
				curRange = curSel.getRangeAt(0);
				obj = curRange.startContainer;
				//***/  alert( "startContainer = " + curRange.startContainer.nodeName + ", endContainer = " + curRange.endContainer.nodeName );
			}
			catch( e )  {};
		}

		if  ( typeof( obj ) == "undefined"  ||  !obj )  {
			return  false;
		}
	}

	if  ( typeof( obj ) == "string" )
		this.objTextBox = getElem( obj );
	else
		this.objTextBox = obj;

	if  ( this.objTextBox )
		return  this.initialize();
	else
		return  false;
}

/***  End of CursorIO Class.  ***/

