var GIncludeSaintFrancisExtensionsInAutoPrefix = false;

function StrToInt(AString)
{
  //extract first n integer symbols from AString and return as a number
  
  var i;
  var sResult;
  
  i = 0;
  while (i < AString.length && ! IsIntegerSymbol(AString.charAt(i)))
  {
    i++;
  }
  
  sResult = '';
  while (i < AString.length && IsIntegerSymbol(AString.charAt(i)))
  {
    sResult = sResult + AString.charAt(i);
    i++;
  }
  
  return Number(sResult);

}     //StrToInt()


function StrToFloat(AString)
{
  //extract first n numeric symbols from AString and return as a number
  
  var i;
  var sResult;
  
  i = 0;
  while (i < AString.length && ! IsNumericSymbol(AString.charAt(i)))
  {
    i++;
  }
  
  sResult = '';
  while (i < AString.length && IsNumericSymbol(AString.charAt(i)))
  {
    sResult = sResult + AString.charAt(i);
    i++;
  }
  
  return Number(sResult);

}     //StrToFloat()


function IncrementIntegerDescription(AIntegerDescription, ACount)
{
  var iNumber, iIndex, s;
  
  iIndex = 0;
  s = '';
  while (iIndex < AIntegerDescription.length)
  {
    if (IsDigit(AIntegerDescription.charAt(iIndex)))
    {
      s = s + AIntegerDescription.charAt(iIndex);
      iIndex++;
    }
    else
    {
      iNumber = Number(s);
      s = AIntegerDescription.substr(s.length, AIntegerDescription.length);
      break;   
    }   
  }
  
  iNumber += ACount;
  return iNumber + s;
  
}       //IncrementIntegerDescription()
    
    
function DecrementIntegerDescription(AIntegerDescription, ACount)
{
  var iNumber, iIndex, s;
  
  iIndex = 0;
  s = '';
  while (iIndex < AIntegerDescription.length)
  {
    if (IsDigit(AIntegerDescription.charAt(iIndex)))
    {
      s = s + AIntegerDescription.charAt(iIndex);
      iIndex++;
    }
    else
    {
      iNumber = Number(s);
      s = AIntegerDescription.substr(s.length, AIntegerDescription.length);
      break;   
    }   
  }
  
  iNumber -= ACount;
  return iNumber + s;
  
}       //DecrementIntegerDescription()
    
    
function CrLf()
{
	return String.fromCharCode(13) + String.fromCharCode(10);
	
}				//CrLf()


function CrLfx(ACount)
{
	var sResult = '';
	
	for (i = 1; i <= ACount; i++)
		sResult = sResult + String.fromCharCode(13) + String.fromCharCode(10);
		
	return sResult;
	
}				//CrLf()


function Tab()
{

	return String.fromCharCode(9);
	
}				//Tab()


function Tabx(ACount)
{
	var sResult = '';
	
	for (i = 1; i <= ACount; i++)
		sResult = sResult + String.fromCharCode(9);
		
	return sResult;
	
}				//CrLf()


function HasDuplicateString(AStringArray, AStartIndex)
{
	return PosDuplicateString(AStringArray, AStartIndex) > -1;
	
}		//HasDuplicateString()


function PosDuplicateString(AStringArray, AStartIndex)
{
	var i;
	
	if (AStartIndex == AStringArray.length)
		return -1
	else
	{
		for (i=AStartIndex + 1; i < AStringArray.length; i++)
			if (AStringArray[i] > '')
				if (AStringArray[i].toUpperCase() == AStringArray[AStartIndex].toUpperCase())
					return i;
		
		return PosDuplicateString(AStringArray, AStartIndex + 1);
	}

}		//PosDuplicateString()


function IsAlpha(AChar)
//Precondition: AString.length = 1;
{
	return ((AChar.charAt(0) >= 'a') && (AChar.charAt(0) <= 'z')) ||
			((AChar.charAt(0) >= 'A') && (AChar.charAt(0) <= 'Z'));
			
}				//IsAlpha()


function IsDigitString(AString)
//Precondition: AString > '';
{
	for (i=0; i < AString.length; i++)
		if (! (AString.charAt(i) >= '0' && AString.charAt(i) <= '9'))
			return false;
		
	return true;

}					//IsDigitString()


function IsDigit(AChar)
//Precondition: AString.length = 1;
{
	return (AChar.charAt(0) >= '0') && (AChar.charAt(0) <= '9');
}


function IsIntegerSymbol(AChar)
{

	return (AChar.charAt(0) >= '0') && (AChar.charAt(0) <= '9') || (AChar == '-');
	
}     //IsIntegerSymbol()


function IsNumericSymbol(AChar)
{

	return (AChar.charAt(0) >= '0') && (AChar.charAt(0) <= '9') || 
	          (AChar.charAt(0) == '-' || AChar.charAt(0) == '.');
	
}     //IsNumericSymbol()


function IsMonoString(AString)
//Precondition: AString > '';
//Postcondition: returns true if AString is all the same character.
//Examples:
//	'a': True
//	'aaaaaaaaa': true
//	'aaaaaaaa ': false
{

	for (i=1; i < AString.length; i++)
		if (AString.charAt(i) != AString.charAt(i - 1))
			return false;
		
	return true;
	
}				//IsMonoString()


function IsNotAlphaOrDigit(AChar)
{
	return ! (AChar.charAt(0) >= 'a' && AChar.charAt(0) <= 'z') &&
			! (AChar.charAt(0) >= 'A' && AChar.charAt(0) <= 'Z') &&
				! (AChar.charAt(0) >= '0' && AChar.charAt(0) <= '9');
				
}		//IsNotAlphaOrDigit()


function Slice(AString, AStartIndex, AEndIndex)
/* ----------------------------------------------------
		Precondition: AString.length > 1;
		
		This is a re-implementation of the string.slice 
		method. This function is preferred because it
		returns characters from AStartIndex to AEndIndex,
		inclusive. JScript's string.slice returns characters 
		from AStartIndex to AEndIndex - 1. The JavaScript 
		documentation at DevGuru.com specifies that slice 
		returns AStartIndex	to AEndIndex, inclusive. So, 
		maybe Microsoft's implementation is non-standard, 
		or just buggy. In any	case, the call 
		MyString.slice(0,0) should logically return the 
		first character of MyString; however, it returns 
		an empty string. A call to this routine such
		as Slice('Bob',0,0) returns 'B'.
-------------------------------------------------------*/
{
	return AString.substr(AStartIndex, (AEndIndex - AStartIndex) + 1)

}				//Slice()


function GetCharCount(AString, AChar)
{
	var iCount;

	iCount = 0;
	for (i=0; i < AString.length; i++)
		if (AString.charAt(i) == AChar)
			iCount++;
			
	return iCount;
		
}				//GetCharCount()


function GetDigitCount(AString)
{
	var iCount;
	
	iCount = 0;
	for (i=0; i < AString.length; i++)
		if (AString.charAt(i) >= '0' && AString.charAt(i) <= '9')
			iCount++;
			
	return iCount;
	
}				//GetDigitCount()


function GetDigitString(AString)
{
	var sResult, i;
	
	sResult = '';
	for (i=0; i < AString.length; i++)
		if (IsDigit(AString.charAt(i)))	
			sResult = sResult + AString.charAt(i);
			
	return sResult;
	
}					//GetDigitString()


function GetAlphaString(AString)
{
	var sResult, i;
	
	sResult = '';
	for (i=0; i < AString.length; i++)
		if (IsAlpha(AString.charAt(i)))	
			sResult = sResult + AString.charAt(i);
			
	return sResult;

}       //GetAlphaString()


function GetAlphaNumericString(AString)
{
	var sResult, i;
	
	sResult = '';
	for (i=0; i < AString.length; i++)
		if (IsAlpha(AString.charAt(i)) || IsDigit(AString.charAt(i)))
			sResult = sResult + AString.charAt(i);
			
	return sResult;

}       //GetAlphaNumericString()


function GetBadSSNDescription(ASSN)
{
	var iDashes, iDigits;
	
	switch (ASSN.length)
	{
		case 9:
			iDigits = GetDigitCount(ASSN);
			if (iDigits == 9)
				return ''
			else
			{
				iDashes = GetCharCount(ASSN, '-');
				if ((iDashes + iDigits) == 9)
					return 'SSN is incorrectly formatted.' + CrLfx(2) +
									'Contains ' + iDigits + ' digits. Nine required.'
				else
					return 'SSN is incorrectly formatted.' + CrLfx(2) +
									'Contains ' + (9 - (iDashes + iDigits)) + ' invalid character(s).'
			
			}
		case 11:
			iDashes = GetCharCount(ASSN, '-');
			if (iDashes == 0)
				return 'Dashes missing from SSN.'
			else
			if ((iDashes < 2) || (iDashes > 2))
				return 'Wrong number of dashes in SSN.'
			else
			if (! (IsDigitString(ASSN.substr(0,3)) && IsDigitString(ASSN.substr(4,2)) &&
					IsDigitString(ASSN.substr(7,4))))
				return 'SSN incorrectly formatted.' + CrLfx(2) +
									'Non-digit characters where digits expected.'
			else
				return '';
		default:
			return 'SSN is length ' + ASSN.length + '.' + CrLfx(2) +
							'Must be length 9 or 11.';
	}
}		//GetBadSSNDescription()
		

function FormatSSN(ASSN, AWithDashes)
{
  var s;
	
	function GetDashedString(AString)
	{
	  
	  return AString.substr(0, 3) + '-' + AString.substr(3, 2) + '-' + AString.substr(5, 4);
		
	}		//GetDashedString()
		
		
	if (AWithDashes)
	{
		if (ASSN.length == 9 && IsDigitString(ASSN))
			return GetDashedString(ASSN)
		else
		{
		  s = GetDigitString(ASSN);
		  if (s.length == 9)
			  return GetDashedString(s)
			else
			  return ASSN;
	  }
	}
	else
	{
		if (ASSN.length == 11 && ASSN.charAt(3) == '-' && ASSN.charAt(6) == '-')
			return ASSN.substr(0, 3) + ASSN.substr(4, 2) && ASSN.substr(7, 4)
		else
			return ASSN;
	}

}				//FormatSSN()


function IsValidSSN(ASSN)
{
	if (ASSN.length == 11)
	{
		for (i=0; i < 3; i++)
			if (! IsDigit(ASSN.charAt(i)))
				return false;
				
		if ('-' != ASSN.charAt(3))
			return false;
			
		for (i=4; i < 6; i++)
			if (! IsDigit(ASSN.charAt(i)))
				return false;
				
		if ('-' != ASSN.charAt(6))
			return false;
			
		for (i=7; i < 11; i++)
			if (! IsDigit(ASSN.charAt(i)))
				return false;
	
		return true;		
	}
	else
	if (ASSN.length == 9)
		return IsDigitString(ASSN);
	else
		return false;

}					//IsValidSSN()


function IsValidNumber(AString)
{
  var chr;
	var iDecimalCount = 0;
	
	if (AString == '.')
	  return false;
	
	for (i=0; i < AString.length; i++)
	{
	  chr = AString.charAt(i);
	  if (chr == '.')
		  iDecimalCount++
		else
		 if (! (chr >= '0' && chr <= '9'))
		  return false;
  }   //for...
		
	return iDecimalCount < 2;
	
}       //IsValidNumber()


function FormatSfExtension(AExtension, AAutoPrefix)
{
	if (AExtension.length == 5 && IsDigitString(AExtension))
		return AExtension.substr(0,1) + '-' + AExtension.substr(1,AExtension.length)
	else
	if (AExtension.length == 6 && IsDigit(AExtension.charAt(0)) && 
		(! IsDigit(AExtension.charAt(1))) && (! IsAlpha(AExtension.charAt(1))))
		return AExtension.substr(0,1) + '-' + AExtension.substr(2,AExtension.length)
	else
	if (AAutoPrefix && (AExtension.length == 4) && IsDigitString(AExtension))
		return '1-' + AExtension
	else
		return AExtension;

}		//FormatSfExtension()


function IsValidSfExtension(AExtension)
{
	var sResult

	sResult = AExtension.length == 5 && IsDigitString(AExtension);
	
	if (AExtension.length == 6)
	{
		sResult = IsDigit(AExtension.charAt(0)) && ('-' == AExtension.charAt(1)) &&
			IsDigitString(AExtension.substr(2,AExtension.length))
	}
	
	return sResult

}			//IsValidSfExtension()


function DeduceSfExtension(APhoneNumber)
//----------------------------------------
// Precondition: APhoneNumber is formatted with
// Dashes only.
//----------------------------------------
{
  var sPrefix, sExt;
  var iDashPos = LastPos('-', APhoneNumber);

  if (! IsValidPhone(APhoneNumber))
    return '';
    
  if (iDashPos < 0)
    return '';
    
  sPrefix = Slice(APhoneNumber, iDashPos - 3, iDashPos - 1);

  switch (sPrefix)
  {
    case '494':
      sExt = '1';
      break;
    case '481':
      sExt = '1';
      break;
    case '488':
      sExt = '1';
      break;
    case '491':
      sExt = '1';
      break;
    case '502':
      sExt = '2';
      break;
    default:
      return '';
 }
      
  return sExt + '-' + Slice(APhoneNumber, iDashPos + 1, iDashPos + 5);

}       //DeduceSfExtension()


function FormatExtension(AExtension)
{

	if (AExtension.length == 5 && IsDigitString(AExtension))
		return AExtension.substr(0,1) + '-' + AExtension.substr(1,AExtension.length)
  else
    return AExtension;

}       //FormatExtension()


function FormatPhone(APhoneString)
{
	var cSeparator;


	function IsFormattableSeparator(ASeparatorChar)
	{
		if (ASeparatorChar  == '-')		//separator already formatted
			return false
		else	//is separator an expected value?
			return  (! ((ASeparatorChar >= '0' && ASeparatorChar <= '9') || 
						(ASeparatorChar.toUpperCase >= 'A' && ASeparatorChar.toUpperCase <= 'Z')));
		
	}				//IsFormattableSeparator()
	

	function FormatLast8(AString)
	{
		var cSeparator;
		
		cSeparator = AString.charAt(3);
		if (IsFormattableSeparator(cSeparator))
		{
			if (IsDigitString(AString.substr(0,3)) && IsDigitString(AString.substr(4,4)))
				return AString.substr(0,3) + '-' + AString.substr(4,4)
			else
				return AString;			//invalid, cannot format
		}
		else
			return AString;
			
	}			//FormatLast8()
	
	
	function FormatFirst4(AString)
	{
		var cSeparator;
		
		cSeparator = AString.charAt(3);
		
		if (IsFormattableSeparator(cSeparator))
		{
			if (IsDigitString(AString.substr(0,3)))		//Is Valid string?
				return AString.substr(0,3) + '-'
			else
				return AString;
		}
		else
			return AString;
			
	}			//FormatFirst4()
	
  if (APhoneString.length == 7 && IsDigitString(APhoneString))
		return APhoneString.substr(0,3) + '-' + APhoneString.substr(3,4)
	else
	if (APhoneString.length == 10 && IsDigitString(APhoneString))
		return APhoneString.substr(0,3) + '-' + APhoneString.substr(3,3) + '-' +
				APhoneString.substr(6,4)
	else
	if (APhoneString.length == 8)
		return FormatLast8(APhoneString)
	else
	if (APhoneString.length == 12)
		return FormatFirst4(APhoneString.substr(0,4)) + FormatLast8(APhoneString.substr(4,8))
	else
	if (APhoneString.length == 11)
	{
		if (IsNotAlphaOrDigit(APhoneString.charAt(3)))
		{
			if (IsDigitString(Slice(APhoneString, 4, 12)))
				return APhoneString.substr(0,3) + '-' + APhoneString.substr(4,3) + '-' +
						APhoneString.substr(7,4)
			else
				return APhoneString
		}
		else
		if (IsNotAlphaOrDigit(APhoneString.charAt(6)))
			return APhoneString.substr(0,3) + '-' + APhoneString.substr(3,3) + '-' +
					APhoneString.substr(7,4)
		else
			return APhoneString
	}
	else
	  if (GIncludeSaintFrancisExtensionsInAutoPrefix)
		  return FormatSfExtension(APhoneString, true)
		else
		  return APhoneString;
		
}				//FormatPhone()


function FormatSaintFrancisPhone()
{

  GIncludeSaintFrancisExtensionsInAutoPrefix = true;
  FormatPhone();
  GIncludeSaintFrancisExtensionsInAutoPrefix = false;

}       //FormatSaintFrancisPhone()


function FormatPager(APagerString)
{
	var s;
	
	s = GetDigitString(APagerString);
	
	if (s.length == 6)
	{
		if (s.substr(0,2) == '98')
			return '98-' + s.substr(2,4)
		else
			return APagerString;
	}
	else
		return FormatPhone(APagerString);
	

}				//FormatPager()


function FormatZipCode(AZipString)
{
  if (AZipString == '' || (AZipString.length == 5 && IsDigitString(AZipString)))
    return AZipString
  else
  {
    AZipString = GetDigitString(AZipString);
    if (AZipString > '' && AZipString.length > 5)
      AZipString = AZipString.substr(0,5) + '-' + AZipString.substr(5);
    return AZipString;
  }
}

function FormatCostCenter(ACostCenterString)
//This function is only useful if 
//	1) allowing ranges with the format X-#####, where x is F (from) or T (to) and 
//		the #'s represent the starting or ending cost center numbers
//	OR
//	2) allowing patterns like ####nn, where leading one or more leading digits are
//		required and one or more n's at the end act as single character place holders.
{
	
	if (! IsValidCostCenter(ACostCenterString))
		return ACostCenterString
	else
	if (CharIn(ACostCenterString.charAt(0), 'FfTt'))
	{
		if (ACostCenterString.charAt(1) == '-')
			return ACostCenterString.toUpperCase()
		else
			return ACostCenterString.charAt(0).toUpperCase() + '-' + 
					ACostCenterString.substr(1, ACostCenterString.length);
	}
	else
	if (StringContainsAny(ACostCenterString, 'Nn'))
		return ACostCenterString.toLowerCase()
	else
		return ACostCenterString;

}			//FormatCostCenter()


function IsValidPhone(APhoneString)
{

	function IsLast8Valid(AString)
	{
		return APhoneString.charAt(3) == '-' && IsDigitString(AString.substr(0,3)) &&
				IsDigitString(AString.substr(4,4));
	
	}			//IsLast8Valid()
	
	
	function IsFirst4Valid(AString)
	{
		return APhoneString.charAt(3) == '-' && IsDigitString(AString.substr(0,3));
		
	}			//IsFirst4Valid()
	
	
	if (APhoneString.length == 8)
		return IsLast8Valid(APhoneString)
	else
	if (APhoneString.length == 12)
		return IsFirst4Valid(APhoneString.substr(0,4)) && IsLast8Valid(APhoneString.substr(4,4));
	else
		return false;

}					//IsValidPhone()


function IsValidInternalPager(APagerString)
{
	if (APagerString.length == 4)
		return IsDigitString(APagerString)
	else
	if (APagerString.length == 6)
		return IsDigitString(APagerString)
	else
	if (APagerString.length == 7)
		return (APagerString.substr(0,3) == '98-') && IsDigitString(APagerString.substr(3,4))
	else
		return false;
		
}			//IsValidInternalPager()
	
	
function IsValidPager(APagerString)
{
	return IsValidPhone(APagerString) || IsValidInternalPager(APagerString);
	
}		//IsValidPager()


function IsValidZip(AZipString, ARequireExtendedZip)
{
	function IsValidLongZip()
	{
		if (! (AZipString.length == 10 || AZipString.length == 9))
			return false
		else
			return (AZipString.length == 9 && IsDigitString(AZipString)) ||
						(AZipString.length == 10 && IsDigitString(AZipString.substr(0,5)) &&
							AZipString.charAt(5) == '-' && IsDigitString(AZipString.substr(0,5)));
							
	}		//IsValidLongZip()
	
	function IsValidShortZip()
	{
		return AZipString.length == 5 && IsDigitString(AZipString);
	
	}			//IsValidShortZip()

	if (ARequireExtendedZip)
		return IsValidLongZip()
	else
		return IsValidShortZip() || IsValidLongZip();
		
}			//IsValidZip()
	
	
function IsValidCostCenter(AString)
{
//Precondition: AString is a string > ''
//Postcondition: Boolean return value
//Examples of valid values:
//	1234
//	123nn
//	F123
//	T456
//	F-12345
//	T-12444
//Examples of invalid values
//	F-12nn		(may not mix ranges with patterns)
//	12				(value too short)
//	1234567		(value too long; numbers and patterns must be 3-6 characters)
//	F12				(value too short; numeric portion must be 3-6 characters)
//	F-1234567	(value too long; numeric portion must be 3-6 characters)
	
	var sFirstChar;
	var bResult;
	var s;
		
	sFirstChar = AString.charAt(0).toUpperCase();
	//checking for ranges
	if ((sFirstChar == 'F') || (sFirstChar == 'T'))
	{
		bResult = IsBetween(AString.length, 4, 8);
		if (bResult)
		{
			if (AString.charAt(1) == '-')
				return (AString.length > 4) && IsDigitString(Slice(AString, 2, AString.length - 1))
			else
				return (AString.length < 8) && IsDigitString(Slice(AString, 1, AString.length - 1));
		}
		else
			return false;
	}	
	else	
	{	//checking for numbers and patterns
		if (! IsBetween(AString.length, 3, 6))
			return false
		else
		if (IsDigitString(AString))
			return true
		else
		if (sFirstChar == 'N')
			return false
		else
		{
			s = AString.toLowerCase(s);
			return (s.indexOf('n') > 0) && 
							IsDigitString(Slice(s, 0, s.indexOf('n') - 1)) && 
								IsMonoString(Slice(s, s.indexOf('n'), s.length - 1));
		}
	}
}					//IsValidCostCenter()


function TrimPunctuation(AString)
{
  var sTrimChars = '.,;:?';
  var bTrimChar;
  var Result = '';
  var i, iChars;
  
  for (i=0; i < AString.length; i++)
  { 
    bTrimChar = false;
    for (iChars = 0; iChars < sTrimChars.length; iChars++)
      if (sTrimChars.charAt(iChars) == AString.charAt(i))
      {
        bTrimChar = true;
        break;
      }
    if (! bTrimChar)
      Result += AString.charAt(i);
  }
  
  return Result;
  
}           //TrimPunctuation()


function Trim(AString)
{
  return DoTrim(AString, true, true);
}


function LeftTrim(AString)
{
  return DoTrim(AString, true, false);
}


function RightTrim(AString)
{
  return DoTrim(AString, false, true);
}


function DoTrim(AString, ATrimLeft, ATrimRight)
{
  var sTrimChars;
  var iStart, iEnd;
  var Result;
  
  if (AString == '')
    return '';

  Result = AString;
  sTrimChars = ' ' + CrLf() + Tab();  
  
  if (ATrimLeft)
  {
    iStart = 0;
    while (iStart < Result.length)
      if (Pos(Result.charAt(iStart), sTrimChars) > -1)
        iStart++
      else
        break;
     
    if (iStart == Result.length)
      return ''
    else
      if (iStart > 0)
        Result = Slice(Result, iStart, Result.length - 1);
  }
  
  if (ATrimRight)
  {
    iEnd = Result.length - 1;
    while (iEnd > -1)
      if (Pos(Result.charAt(iEnd), sTrimChars) > -1)
        iEnd--
      else
        break;
        
    if (iEnd > -1 && iEnd < Result.length - 1)
      Result = Slice(Result, 0, iEnd);
  }
  
  return Result;
	
}       //DoTrim()

	
function TrimSpaces(AString)
{
  
  if (AString == '')
    return ''
  else
  {
    if (AString.charAt(0) == ' ' || AString.charAt(AString.length - 1) == ' ')
      return TrimChar(AString, ' ')
    else
      return AString;
  }
  
}		//TrimSpaces()


function TrimChar(AString, AChar)
{

  return RightTrimChar(LeftTrimChar(AString, AChar), AChar);
  
}		//TrimChar()


function RightTrimChar(AString, AChar)
{
	var iEnd;
	
	if (AString == '')
		return '';

	iEnd = AString.length - 1;
	while (true)
	{
		if (iEnd < 0)
			break
		else
		if (AString.charAt(iEnd) == AChar)
			iEnd--
		else
			break;
	}
		
	return Slice(AString, 0, iEnd);

}		//RightTrimChar()


function LeftTrimChar(AString, AChar)
{
	var iStart;
	
	if (AString == '')
		return '';

	iStart = 0;
	while (true)
	{
		if (iStart > AString.length - 1) 
			break
		else
		if (AString.charAt(iStart) == AChar)
			iStart++
		else
			break;
	}
		
	return Slice(AString, iStart, AString.length - 1);

}		//LeftTrimChar()


function LeftTrim(AString)
{

  return LeftTrimChar(AString, ' ');
  
}		//LeftTrim()


function IsMixedCase(AString)
{

	if (AString.toUpperCase() == AString)
		return false
	else
	if (AString.toLowerCase() == AString)
		return false
	else
		return true;

}		//IsMixedCase()


function IsRomanNumeral(AString)
{
  var RomanChars = 'IVXLCDM';
  var s;
  var i;
  
  if (AString > '') 
  {
    s = AString.toUpperCase();
    for (i = 0; i < s.length; i++)
      if (Pos(s.charAt(i), RomanChars) == -1)
        return false;
  }
  else 
    return false;
    
  return true;

}       //IsRomanNumeral()


function IsNameNumeral(AString)
{

  var RomanChars = 'IV';
  var s;
  var i;
  
  if (AString > '') 
  {
    s = AString.toUpperCase();
    for (i = 0; i < s.length; i++)
      if (Pos(s.charAt(i), RomanChars) == -1)
        return false;
  }
  else 
    return false;
    
  return true;

}           //IsNameNumeral()


function IsNameNumeralFuzzy(AString)
{
  //---------------------------------
  // Fuzzy Logic Routine
  //  Returns a value between 0 and 1
  //  0 = false; 1 = true
  //  values closer to 1 provide greater assurance that AString is a Roman Numeral
  //---------------------------------

  if (IsNameNumeral(AString))
  {
    switch (AString.toLowerCase())
    {
      case 'i' :
        return .4       //could be an initial
      case 'ii' :
        return .99
      case 'iii' : 
        return .99
      case 'iv' :
        return .99    //could be intravenous abbreviation; but the context here is a person's name
      case 'v' :
        return .4       //could be an initial
      case 'vi' :
        return .80      //could be short for Vivian
      case 'vii' :
        return .9
      case 'viii' :
        return .99
      default :
        return .1
    }
  }
  else
  if (IsRomanNumeral(AString))
    return .1
  else
    return 0;
    
}         //IsNameNumeralFuzzy()


function GetLastNameMixedCase(AString, ADelimiters)
{
  //returns a personal name with mixed case
  //looks for roman numerals at end of name, e.g., Howell III
  
	var i, iLast, sWord, iWordCount;
	var Result;
	
	iWordCount = 0;
	
	function GetWord(ACurrentIndex)
	{
		return AString.charAt(iLast + 1).toUpperCase() + 
			Slice(AString, iLast + 2, ACurrentIndex).toLowerCase();
	}
	
	function IsLastSpaceDelimitedWord(AWordIndex)
	{
	  var sWord = AString.substr(AWordIndex);
	  
    if (Pos(' ', sWord) == -1)
      if (AWordIndex > 0)
        if (AString.charAt(AWordIndex - 1) == ' ')
          return true;
          
    return false;
	
	}           //IsLastSpaceDelimitedWord()
	
	
	function WordIsRomanNumeral(ACurrentIndex, AWord)
	{
	  var iWordIndex = ACurrentIndex - (AWord.length - 1);
	  var AWord = TrimPunctuation(TrimSpaces(AWord));

    if (iWordCount < 2)
      return false
    else
    if (AWord.length > 1)
      switch (AWord.toLowerCase())
      {
        case 'ii' :
          return true;
        case 'iii' :
          return true;
        case 'iv' :
          return true;
        case 'vii' :
          return true;
        case 'viii' :
          return true;
      }
          
	  if (iWordCount > 1)
	    if (IsLastSpaceDelimitedWord(iWordIndex))
	    {
	      if (IsNameNumeral(AWord))
	        return true;
	    }
	    else
	    if (IsNameNumeralFuzzy(AWord) > .5)
	      return true;
	        
    return false;
	
	}       //WordIsRomanNumeral()
	
	Result = '';
	iLast = -1;
	for (i=0; i < AString.length - 1; i++)
		if (CharIn(AString.charAt(i), ' .;,-_()[]!@"`~' + "'"))
		{
		  sWord = GetWord(i);
		  iWordCount += 1;
		  if (WordIsRomanNumeral(i, sWord))
		    sWord = sWord.toUpperCase();
			Result = Result + sWord;
			iLast = i;
		}
	
	if (iLast < AString.length - 1)
	{
	  sWord = GetWord(AString.length - 1);
	  iWordCount += 1;
	  if (WordIsRomanNumeral(i, sWord))
	    sWord = sWord.toUpperCase();
		Result = Result + sWord;
  }
		
	Result = ConvertLastNameCasingForSpecialCases(Result);
	
	return Result;
	
}       //GetLastNameMixedCase()


function GetMixedCaseForStreetAddress(AString, ADelimiters)
{
	var i, iLast, sWord, iWordCount;
	var Result;
	
	iWordCount = 0;
	
	function GetWord(ACurrentIndex)
	{
		return AString.charAt(iLast + 1).toUpperCase() + 
			Slice(AString, iLast + 2, ACurrentIndex).toLowerCase();
	}
	
	function WordIsRomanNumeral(ACurrentIndex, AWord)
	{
	  var iWordIndex = ACurrentIndex - (AWord.length - 1);
	  var AWord = TrimPunctuation(TrimSpaces(AWord));

    if (iWordCount < 2)
      return false
    else
    if (AWord.length > 1)
      switch (AWord.toLowerCase())
      {
        case 'i' : 
          return true;
        case 'v' :
          return true;
        case 'x' :
          return true;
        case 'ii' :
          return true;
        case 'iii' :
          return true;
        case 'iv' :
          return true;
        case 'vii' :
          return true;
        case 'viii' :
          return true;
      }
          
    return false;
	
	}       //WordIsRomanNumeral()
	
	Result = '';
	iLast = -1;
	for (i=0; i < AString.length - 1; i++)
		if (CharIn(AString.charAt(i), ' .;,-_()[]!@"`~' + "'"))
		{
		  sWord = GetWord(i);
		  iWordCount += 1;
		  if (WordIsRomanNumeral(i, sWord))
		    sWord = sWord.toUpperCase();
			Result = Result + sWord;
			iLast = i;
		}
	
	if (iLast < AString.length - 1)
	{
	  sWord = GetWord(AString.length - 1);
	  iWordCount += 1;
	  if (WordIsRomanNumeral(i, sWord))
	    sWord = sWord.toUpperCase();
		Result = Result + sWord;
  }
		
	return Result;
	
}       //GetMixedCaseForStreetAddress()


function GetCapitalizedWords(AString)
{
	var i, iLast, sResult, sWord;
	
	
	function GetWord(ACurrentIndex)
	{
		return AString.charAt(iLast + 1).toUpperCase() + 
			Slice(AString, iLast + 2, ACurrentIndex).toLowerCase();
	}
	
	sResult = '';
	iLast = -1;
	for (i=0; i < AString.length - 1; i++)
		if (CharIn(AString.charAt(i), ' .;,-_()[]!@"`~' + "'"))
		{
		  sWord = GetWord(i);
			sResult = sResult + sWord;
			iLast = i;
		}
	
	if (iLast < AString.length - 1)
	{
	  sWord = GetWord(AString.length - 1);
		sResult = sResult + sWord;
  }
		
	return sResult;
	
}				//GetCapitalizedWords()


function GetPersonalNameCasing(AName, AIsLastName)
{
  var Result = '';
  var sDelimiters = ' ,;`~.\/()-"&[]' + "'";
  var arWords;
  var i;

  
  void function DoCasing()
  {
  
    if (AName > '')
    {
      if (AIsLastName)
        Result = GetLastNameMixedCase(AName, sDelimiters)
      else
        Result = GetCapitalizedWords(AName);
        
    }
    
  }         //DoCasing()
  
  
  Result = AName;
  
  if (! IsMixedCase(AName))
    DoCasing()
  else
  {
    arWords = GetWords(AName, sDelimiters);
    for (i=0; i < arWords.length; i++)
      if (arWords[i] == arWords[i].toLowerCase())
      {
        DoCasing();
        break;
      }
  }
    
  
  return Result;

}       //GetPersonalNameCasing()


function ConvertLastNameCasingForSpecialCases(AName)
{
  var arNames;
  var i;
  var Result;


  function GetNameArray()   //divide names from symbols and spaces between
  {
    var Result = new Array;
    var i;
    var sTemp = '';
    var sName = AName.toLowerCase();
    
    for (i=0; i < AName.length; i++)
      if (! (sName.charAt(i) >= 'a' && sName.charAt(i) <= 'z'))
      {
        if (sTemp > '')
          Result[Result.length] = sTemp;
        sTemp = '';
        Result[Result.length] = AName.charAt(i);
      }
      else
        sTemp += AName.charAt(i);
        
    if (sTemp > '')
      Result[Result.length] = sTemp;
      
    return Result;
  
  }         //GetNameArray()
  
  
  function GetConvertedName(AName)
  {
    var Result = AName;

    if (Result.length > 5)
      if (Result.substr(0, 2).toLowerCase() == 'mc')
        if ((Result.charAt(2) >= 'a') && (Result.charAt(2) <= 'z'))
          Result = Result.substr(0, 2) + Result.charAt(2).toUpperCase() + Result.substr(3);
          
    if (Result.length > 6)
      if (Result.substr(0, 3).toLowerCase() == 'mac')
        if ((Result.charAt(3) >= 'a') && (Result.charAt(3) <= 'z'))
          Result = Result.substr(0, 3) + Result.charAt(3).toUpperCase() + Result.substr(4);
          
          
    return Result;
  
  }           //GetConvertedName()
  
  if (AName.length == 0) 
    Result = ''
  else
  {
    arNames = GetNameArray();
    for (i=0; i < arNames.length; i++)
      if (arNames[i].length > 1)
        arNames[i] = GetConvertedName(arNames[i]);
      
    Result = '';
    for (i=0; i < arNames.length; i++)
      Result += arNames[i];
  }
    
  return Result; 
      

}       //ConvertLastNameCasingForSpecialCases()


function IsAllConsonants(AString)
{
  var sConsonants = 'bcdfghjklmnpqrstvwxyz';
  var i;
  
  if (AString == undefined)
    return false
  else
  if (AString == '')
    return false;
  
  for (i = 0; i < AString.length; i++)
    if (Pos(AString.charAt(i), sConsonants) == -1)
      return false;
      
  return true;

}         //IsAllConsonants()


function IsAllConsonantsStrict(AString)
{
  
  if (IsAllConsonants(AString))
  {
  
    if (AString.length == 1)
      return true
    else
      if (Pos('y', AString.substr(1)) < 0)     //y does not occur after the first position
        return true;
  
    return ! IsInYAsOnlyVowelDictionary(AString);
        
  }
  else
    return false;

}         //IsAllConsonantsStrict()


function IsAllVowels(AString)
{
  var sVowels = 'aeiou';
  var i;
  
  for (i = 0; i < AString.length; i++)
    if (Pos(AString.charAt(i), sVowels) == -1)
      return false;
      
  return true;

}         //IsAllVowels()


function IsInYAsOnlyVowelDictionary(AWord)
{
  var arDict = GetYAsOnlyVowelMicroDictionary();
  var i;
  
  for (i=0; i < arDict.length; i++)
    if (AWord.toLowerCase() == arDict[i])
      return true;
      
  return false;

}         //IsInYAsOnlyVowelDictionary()


function GetYAsOnlyVowelMicroDictionary()
{
  var Result = new Array;
  
  Result[Result.length] = 'lymph';
  Result[Result.length] = 'myth';
  Result[Result.length] = 'gym';
  Result[Result.length] = 'cyst';
  Result[Result.length] = 'gypsy';
  Result[Result.length] = 'pygmy';
  Result[Result.length] = 'crypt';
  Result[Result.length] = 'rhythm';
  Result[Result.length] = 'nymph';
  Result[Result.length] = 'hymn';
  Result[Result.length] = 'pry';
  Result[Result.length] = 'ply';
  Result[Result.length] = 'my';
  Result[Result.length] = 'sky';
  Result[Result.length] = 'sly';
  Result[Result.length] = 'spy';
  Result[Result.length] = 'fly';
  Result[Result.length] = 'by';
  Result[Result.length] = 'shy';
  Result[Result.length] = 'dry';
  Result[Result.length] = 'try';
  Result[Result.length] = 'why';
  Result[Result.length] = 'cry';
  Result[Result.length] = 'fry';
  
  return Result;

}       //GetYAsOnlyVowelMicroDictionary()


function GetStandardDelimiters()
{

  //var sDelimiters = ' ,;`~.\/()-"&[]' + "'";
  //var sDelimiters = ' .;,-_()[]/\!@"' + "'";

  return ' ,;`~.\/()-"&[]&' + "'";

}


function GetUpperCaseForSuspectedAcronyms(AString, AWordDelimiters)
{
  var sDelimiters = ' .;,-_()[]/\!@"' + "'";
  var iIndex = 0;
  var iStart = 0;
  var sWord;
  var Result = AString;
  var arExceptions = new Array;
  
  arExceptions[0] = 'Ltd';        //exceptions are processed as case insensitive
  arExceptions[1] = 'Sr';
  arExceptions[2] = 'Jr';
  arExceptions[3] = 'of';
  
      
  function IsException(AWord)
  {
    var i;
    var sWord = AWord.toLowerCase();
    
    for (i = 0; i < arExceptions.length; i++)
      if (sWord == arExceptions[i].toLowerCase())
        return true;
        
    return false;
  
  }         //IsException()
  
  
  void function UpdateResult()
  {
    
    Result = Slice(Result, 0, iStart - 1) + sWord.toUpperCase() + Result.substr(iIndex);

  }       //UpdateResult()
  
  
  void function NextWord()
  {
    sWord = Slice(AString, iStart, iIndex - 1);
    
    if (sWord.length == 2 && ! IsException(sWord))
      UpdateResult()
    else
    if (sWord.length > 2)
      if (! IsException(sWord))
        if (IsAllConsonantsStrict(sWord))
          UpdateResult()
        else
        if (IsAllVowels(sWord))
          UpdateResult();
          
    iIndex += 1;
    iStart = iIndex;
    
  }         //NextWord()
  
  
if (AWordDelimiters > '')
  sDelimiters = AWordDelimiters;
  
while (iIndex < AString.length)
    if (Pos(AString.charAt(iIndex), sDelimiters) > -1)
      NextWord()
    else
      iIndex++;
      
    NextWord();
      
  return Result;

}         //GetUpperCaseForSuspectedAcronyms()


function GetUpperCaseForSuspectedMedicalCenterAcronyms(AString, AWordDelimiters)
{
  var sDelimiters = ' .;,-_()[]/\!@"' + "'";
  var iIndex = 0;
  var iStart = 0;
  var sWord;
  var Result = AString;


  void function UpdateResult()
  {
    
    Result = Slice(Result, 0, iStart - 1) + sWord.toUpperCase() + Result.substr(iIndex);

  }       //UpdateResult()
  
  
  void function NextWord()
  {
    sWord = Slice(AString, iStart, iIndex - 1);
    
    if (sWord.length > 2 && sWord.length < 6)
      if (sWord.substr(sWord.length - 2).toLowerCase() == 'mc')
        UpdateResult();
          
    iIndex += 1;
    iStart = iIndex;
    
  }         //NextWord()
  
  if (AWordDelimiters > '')
    sDelimiters = AWordDelimiters;
    
  while (iIndex < AString.length)
    if (Pos(AString.charAt(iIndex), sDelimiters) > -1)
      NextWord()
    else
      iIndex++;
      
    NextWord();
      
  return Result;

}         //GetUpperCaseForSuspectedMedicalCenterAcronyms()


/* This routine upper cases ALL 3-letter words */
function GetUpperCaseFor3LetterWords(AString, AWordDelimiters)
{
  var sDelimiters = ' .;,-_()[]/\!@"' + "'";
  var iIndex = 0;
  var iStart = 0;
  var sWord;
  var Result = AString;


  void function UpdateResult()
  {
    
    Result = Slice(Result, 0, iStart - 1) + sWord.toUpperCase() + Result.substr(iIndex);

  }       //UpdateResult()
  
  
  void function NextWord()
  {
    sWord = Slice(AString, iStart, iIndex - 1);
    
    if (sWord.length == 3)
      UpdateResult();
          
    iIndex += 1;
    iStart = iIndex;
    
  }         //NextWord()
  
  if (AWordDelimiters > '')
    sDelimiters = AWordDelimiters;
    
  while (iIndex < AString.length)
    if (Pos(AString.charAt(iIndex), sDelimiters) > -1)
      NextWord()
    else
      iIndex++;
      
    NextWord();
      
  return Result;

}         //GetUpperCaseFor3LetterWords()


function GetStateCodesMicroDictionary()
{
  //US Postal Codes for States plus District of Columbia
  var arStates = new Array;
  
  arStates[0] = 'AL';
  arStates[1] = 'AK';
  arStates[2] = 'AZ';
  arStates[3] = 'AR';
  arStates[4] = 'CA';
  arStates[5] = 'CO';
  arStates[6] = 'CT';
  arStates[7] = 'DE';
  arStates[8] = 'DC';       //District of Columbia
  arStates[9] = 'FL';
  arStates[10] = 'GA';
  arStates[11] = 'HI';
  arStates[12] = 'ID';
  arStates[13] = 'IL';
  arStates[14] = 'IN';
  arStates[15] = 'IA';
  arStates[16] = 'KS';
  arStates[17] = 'KY';
  arStates[18] = 'LA';
  arStates[19] = 'ME';
  arStates[20] = 'MD';
  arStates[21] = 'MA';
  arStates[22] = 'MI';
  arStates[23] = 'MN';
  arStates[24] = 'MS';
  arStates[25] = 'MO';
  arStates[26] = 'MT';
  arStates[27] = 'NE';
  arStates[28] = 'NV';
  arStates[29] = 'NH';
  arStates[30] = 'NJ';
  arStates[31] = 'NM';
  arStates[32] = 'NY';
  arStates[33] = 'NC';
  arStates[34] = 'ND';
  arStates[35] = 'OH';
  arStates[36] = 'OK';
  arStates[37] = 'OR';
  arStates[38] = 'PA';
  arStates[39] = 'RI';
  arStates[40] = 'SC';
  arStates[41] = 'SD';
  arStates[42] = 'TN';
  arStates[43] = 'TX';
  arStates[44] = 'UT';
  arStates[45] = 'VT';
  arStates[46] = 'VA';
  arStates[47] = 'WA';
  arStates[48] = 'WV';
  arStates[49] = 'WI';
  arStates[50] = 'WY';
  
  return arStates;

}         //GetStateCodesMicroDictionary()


function GetUpperCaseStateCodes(AString)
{
  //---------------------------------------------
  // Be careful what context this is used in.
  // Code for Oregon is OR, for Indiana is IN.
  // These codes conflict with English words.
  //---------------------------------------------

  return GetUpperCaseWords(AString, GetStateCodesMicroDictionary());

}         //GetUpperCaseStateCodes()


function GetTitleCasingMicroDictionary() 
{
	var Result = new Array;
	
	Result[Result.length] = 'a';

	Result[Result.length] = 'an';
	Result[Result.length] = 'as';
	Result[Result.length] = 'at';
	Result[Result.length] = 'by';
	Result[Result.length] = 'in';
	Result[Result.length] = 'is';
	Result[Result.length] = 'it';
	Result[Result.length] = 'of';
	Result[Result.length] = 'on';
	Result[Result.length] = 'or';
	Result[Result.length] = 'to';

	Result[Result.length] = 'and';
	Result[Result.length] = 'are';
	Result[Result.length] = 'for';
	Result[Result.length] = 'the';
	
	return Result;

}       //GetTitleCasingMicroDictionary()


function GetWords(AString, ADelimiters)
{
  var Result = new Array;
  var i = 0;
  var sTemp = '';
    
  while (i < AString.length)
  {
    if (CharIn(AString.charAt(i), ADelimiters))
    {
      if (sTemp > '')
      {
        Result[Result.length] = sTemp;
        sTemp = '';
      }
    }
    else
      sTemp += AString.charAt(i);

    i++;
  }
  
  if (sTemp > '')
    Result[Result.length] = sTemp;
  
  return Result;

}         //GetWords()


function GetWordCount(AString, ADelimiters)
{

  return GetWords(AString, ADelimiters).length;
  
}


function GetWordsAndDelimiters(AString, ADelimiters)
{
  var Result = new Array;
  var i = 0;
  var sTempWords = '';
  var sTempDelimiters = '';
    
  while (i < AString.length)
  {
    if (CharIn(AString.charAt(i), ADelimiters))
    {
      sTempDelimiters += AString.charAt(i);
      if (sTempWords > '')
      {
        Result[Result.length] = sTempWords;
        sTempWords = '';
      }
    }
    else
    {
      sTempWords += AString.charAt(i);
      if (sTempDelimiters > '')
      {
        Result[Result.length] = sTempDelimiters;
        sTempDelimiters = '';
      }
    }

    i++;
  }
  
  if (sTempWords > '')
    Result[Result.length] = sTempWords;
    
  if (sTempDelimiters > '')
    Result[Result.length] = sTempDelimiters;
  
  return Result;

}         //GetWordsAndDelimiters()


function GetTitleCasingByWord(AString, ACapFlags)
{
  var cfLowerCaseWords = 1;
  var cfAllUpperCaseString = 2;
  var bChangeUpperCaseWords;
  var sDelimiters = ' .;,-_()/\[]!@"';
	var arLowerCase = GetTitleCasingMicroDictionary();
	var arWords = GetWordsAndDelimiters(AString, sDelimiters);
	var i;
	var Result;
	
	if (ACapFlags > cfLowerCaseWords)
	  bChangeUpperCaseWords = AString.toUpperCase() == AString
	else
	  bChangeUpperCaseWords = false;

	if (AString.toUpperCase() == AString && ! bChangeUpperCaseWords)
	  return AString;
	
	for (i = 0; i < arWords.length; i++)
	  if (Pos(arWords[i].charAt(0), sDelimiters) > -1)
	    continue
	  else
	  if (i > 0 && IsItemInArray(arWords[i], arLowerCase))
	    arWords[i] = arWords[i].toLowerCase()
	  else
    if (ACapFlags == cfLowerCaseWords)
    {
	    if (arWords[i].toLowerCase() == arWords[i])
	      arWords[i] = GetTitleCasing(arWords[i]);
	  }
	  else
	  if (bChangeUpperCaseWords || (arWords[i] != arWords[i].toUpperCase()))
	  {
	    if (! IsMixedCase(arWords[i]))
	    {
	      arWords[i] = GetTitleCasing(arWords[i]);
	    
	      //-------------------------------------------------
	      // GetTitleCasing() is conservative and doesn't
	      //  change words which are all upper case. The 
	      // following overrides that behavior and mixes the 
	      // case. This override is within a narrow context.
	      //-------------------------------------------------
	      if (arWords[i] == arWords[i].toUpperCase())
	        arWords[i] = arWords[i].substr(0, 1) + arWords[i].substr(1).toLowerCase();
	    }
	  }

  Result = '';
  for (i=0; i < arWords.length; i++)
    Result += arWords[i];
    
  return Result;  
	
}       //GetTitleCasingByWord()


function GetTitleCasing(AString)
// Same as GetCapitalizedWords() but more selective in what it caps
{
  var sDelimiters = ' .;,-_()/\[]!@"';
	var i, iLast, sResult;
	var arLowerCase = GetTitleCasingMicroDictionary();
	
	function IsLowerCaseWord(AWord)
	{
	  var i;
	  
	  for (i=0; i < arLowerCase.length; i++)
	    if (AWord.toLowerCase() == arLowerCase[i].toLowerCase())
	      return true;
	      
	  return false;
	  
	}         //IsLowerCaseWord()
	
	
	function GetWord(ACurrentIndex)
	{
	  var sWord;
	  
	
	  function CapWord()
	  {
		  return AString.charAt(iLast + 1).toUpperCase() + 
			        Slice(AString, iLast + 2, ACurrentIndex).toLowerCase();
	  }     //CapWord()
	  
	  function LowerCaseWord()
	  {
		  return Slice(AString, iLast + 1, ACurrentIndex).toLowerCase();
	  }
	  
	  if (iLast == -1)
	    return CapWord()
	  else
	  {
	    sWord = TrimSpaces(
                AString.charAt(iLast + 1).toLowerCase() + 
                  Slice(AString, iLast + 2, ACurrentIndex).toLowerCase());
	    if (IsLowerCaseWord(sWord))
	      return LowerCaseWord()
	    else
	      return CapWord();
	  }
	  
	}       //GetWord()
	
	
	function IsCapCandidate()
	// AString not a candidate for capping if single word and all upper case
	// the word count loop below is far from fool proof, but should work reasonably well
	{
	  var sString = TrimSpaces(AString);
	  var iWordCount = 0;
	  var i;

    if (sString.toUpperCase() != sString)
      return true
    else	  
    {
	    for (i=0; i < sDelimiters.length; i++)
	      iWordCount = iWordCount + GetCharCount(sString, sDelimiters.charAt(i));
	      
      iWordCount++;       //Word count is one more than delimiter count
      
      return iWordCount > 1;
    }
	    
	}       //IsCapCandidate()


	if (! IsCapCandidate())
	  return AString;
	  
	sResult = '';
	iLast = -1;
	for (i=0; i < AString.length - 1; i++)
		if (CharIn(AString.charAt(i), sDelimiters))
		{
			sResult = sResult + GetWord(i);
			iLast = i;
		}
	
	if (iLast < AString.length - 1)
		sResult = sResult + GetWord(AString.length - 1);
		
	return sResult;
	
}				//GetTitleCasing()


function GetUpperCaseWords(AString, AArrayOfWords)
{
  var sDelimiters = ' .,;/\()[]:"' + "'";
		
  return GetUpperCaseWordsXt(AString, AArrayOfWords, sDelimiters);

}         //GetUpperCaseWords()


function GetUpperCaseWordsXt(AString, AArrayOfWords, ADelimiters)
{
	var Result;
	var i;

	void function UpperCaseWord(AWord)
	{
	  var arPos = AllPos(AWord, Result);
		var i;
	
	  for (i=0; i < arPos.length; i++)
		  if (arPos[i] > -1)
			  if (IsWordAtIndex(arPos[i], AWord))
				  Result = Result.substr(0, arPos[i]) + 
							      Result.substr(arPos[i], AWord.length).toUpperCase() +
								      Result.substr(arPos[i] + AWord.length);
								
	}		//UpperCaseWord()
	
	
	function IsWordAtIndex(AIndex, AWord)
	{
		
		function IsStartDelimiter()
		{
			if (AIndex == 0)
				return true
			else
				return CharIn(Result.charAt(AIndex - 1), ADelimiters);
			
		}		//IsStartDelimiter()
		
		
		function IsEndDelimiter()
		{
			if ((AIndex + AWord.length) == Result.length)
				return true
			else
				return CharIn(Result.charAt(AIndex + AWord.length), ADelimiters);
		
		}			//IsEndDelimiter()

		if (AIndex < 0)
			return false
		else
			return IsStartDelimiter() && IsEndDelimiter();
				
	}		//IsWordAtIndex()
	
	Result = AString;

  for (i = 0; i < AArrayOfWords.length; i++)
    UpperCaseWord(AArrayOfWords[i]);	
	
	return Result;

}				//GetUpperCaseWordsXt()


function GetMedicalCredentialsList(AString)
{
	var arList = new Array;
	
	arList[0] = 'bsn';
	arList[1] = 'b.s.n';
	arList[2] = 'do';
	arList[3] = 'd.o.';
	arList[4] = 'md';
	arList[5] = 'm.d.';
	arList[6] = 'rn';
	arList[7] = 'r.n.';

	arList[8] = 'arnp';      //nurse practitioner
	arList[9] = 'arnpo';
	arList[10] = 'np';
	arList[11] = 'dmd';       //dentist
	arList[12] = 'dds';       //dentist
	arList[13] = 'rd';        //registered dietician
	arList[14] = 'ld';        //licensed dietician
	arList[15] = 'dpm';       //podiatrist
	arList[16] = 'rsn';       //registered surgical nurse
	arList[17] = 'r.s.n.';
	arList[18] = 'lpn';
	arList[19] = 'l.p.n.';    
	arList[20] = 'mph';       //master of public health
	arList[21] = 'm.p.h.';
	arList[22] = 'st';        //surgery tech
	arList[23] = 'ma';        //medical assistant
	
	return arList;

}				//GetMedicalCredentialsList()


function GetDoctoralList()
{
  var Result = new Array;
  
  Result[0] = 'Ph.D';
  Result[1] = 'PhD';
  Result[2] = 'Ed.D';
  Result[3] = 'EdD';
  
  return Result;
}


function GetDoctoralCasing(AString, ADelimiters)
{
  if (! ADelimiters)
    ADelimiters = GetStandardDelimiters();

  return GetMicroDictionaryCasing(AString, GetDoctoralList(), ADelimiters);
}


function GetUpperCaseMedicalCredentials(AString)
{
	var arWords = GetMedicalCredentialsList(AString);
	
	return GetUpperCaseWordsXt(AString, arWords, GetStandardDelimiters());
}


function IsMedicalCredential(AString)
{
  var arCredentials = GetMedicalCredentialsList(AString);
  var i;
  var s = AString.toLowerCase();
  
  for (i=0; i < arCredentials.length; i++)
    if (arCredentials[i] == s)
      return true;
  
  return false;
}


function GetCapitalizedWordsMedical(AString)
{
	var	Result;
	
	if (AString == '')
		return '';
		
	Result = GetCapitalizedWords(AString);
	Result = GetDoctoralCasing(Result, GetStandardDelimiters());
	return GetUpperCaseMedicalCredentials(Result);
}


function GetMedicalAndTitleCasing(AString)
{
  var Result;
  
  if (AString == '')
    return AString;

  Result = GetUpperCaseMedicalCredentials(AString);
	Result = GetDoctoralCasing(Result, GetStandardDelimiters());
  Result = GetTitleCasing(Result);                    //this must be called last
  
  return Result;
}


function GetInsuranceMicroDictionaryCasing(AString, ADelimiters)
{
  var arDictionary = new Array;

  arDictionary[0] = 'CommunityCare';
  arDictionary[1] = 'PCOK';
  arDictionary[2] = 'CBCA';
  arDictionary[3] = 'CCOK';
  arDictionary[4] = 'UHC';      //United Health Care
  arDictionary[5] = 'CCHMO';
  arDictionary[6] = 'HMO';
  arDictionary[7] = 'PPO';
  arDictionary[8] = 'SoonerCare';
  arDictionary[9] = 'HealthChoice';
  arDictionary[10] = 'BAC';
  arDictionary[11] = 'POS';
  
  return GetMicroDictionaryCasing(AString, arDictionary, ADelimiters);
}

 
function GetCompanyNameCasing(AString, ACapFlags, AOptionalDelimiters)
{
  return GetInsuranceCasing(AString, ACapFlags, AOptionalDelimiters);
}


function GetInsuranceCasing(AString, ACapFlags, AOptionalDelimiters)
{
  var sDelimiters = ' -;/\.(),';
  var Result;
  
  if (AString == '')
    return AString;
    
  if (AOptionalDelimiters > '')
    sDelimiters = AOptionalDelimiters;
    
  Result = AString;
  if (! IsMixedCase(AString))
  {
    if (GetWordCount(AString, sDelimiters) == 1)
      if (Result.length < 5)
        return Result.toUpperCase();
        
    if (Result == Result.toLowerCase())
      Result = GetUpperCaseStateCodes(Result);        //call this first to eliminate problems with OR and IN

    Result = GetTitleCasing(Result);
    Result = GetUpperCaseForSuspectedAcronyms(Result, sDelimiters);
    Result = GetInsuranceMicroDictionaryCasing(Result, sDelimiters);
  
  }
  else
  {
    Result = GetTitleCasingByWord(Result, ACapFlags);
    Result = GetInsuranceMicroDictionaryCasing(Result, sDelimiters);
  }  

  return Result;

}         //GetInsuranceCasing()


function GetJobTitleCasing(AString, ACapFlags, AOptionalDelimiters)
{
  var sDelimiters = GetStandardDelimiters();
  var Result;
  
  if (AString == '')
    return AString;
    
  if (AOptionalDelimiters > '')
    sDelimiters = AOptionalDelimiters;
    
  Result = AString;
  if (! IsMixedCase(AString))
  {
    if (GetWordCount(AString, sDelimiters) == 1)
      if (Result.length < 4)
        return Result.toUpperCase();
        
    Result = GetTitleCasing(Result);
    Result = GetUpperCaseForSuspectedAcronyms(Result, sDelimiters);
  }
  else
    Result = GetTitleCasingByWord(Result, ACapFlags);

  return Result;
} 


function GetMedicalGroupNameCasing(AString)
{
  var sDelimiters = ' ,.-/();';
  var Result = AString;
  var arUpperCaseWords = new Array;
  var arCaseDictionary = new Array;
  
  if (AString == '')
    return '';
  
  arUpperCaseWords[0] = 'OMNI';
  arUpperCaseWords[1] = 'MCAT';
  arUpperCaseWords[2] = 'BA';
  arUpperCaseWords[3] = 'EOPC';
  arUpperCaseWords[4] = 'PICU';
  arUpperCaseWords[5] = 'ECI';
  arUpperCaseWords[6] = 'OSU';
  arUpperCaseWords[7] = 'COT';
  arUpperCaseWords[8] = 'OHI';
  arUpperCaseWords[9] = 'VA';
  
  arCaseDictionary[0] = 'SouthCrest';
  arCaseDictionary[arCaseDictionary.length] = 'and';
  arCaseDictionary[arCaseDictionary.length] = 'are';
  arCaseDictionary[arCaseDictionary.length] = 'for';
  arCaseDictionary[arCaseDictionary.length] = 'not';
  arCaseDictionary[arCaseDictionary.length] = 'out';
  arCaseDictionary[arCaseDictionary.length] = 'Sex';
  arCaseDictionary[arCaseDictionary.length] = 'Ten';
  arCaseDictionary[arCaseDictionary.length] = 'the';
  arCaseDictionary[arCaseDictionary.length] = 'Two';
  arCaseDictionary[arCaseDictionary.length] = 'Wet';
  arCaseDictionary[arCaseDictionary.length] = 'One';
  
  /* each routine potentially overrides what the previous routine did */
  Result = GetUpperCaseFor3LetterWords(Result, sDelimiters);                    //liberal w/ broad context
  Result = GetUpperCaseForSuspectedMedicalCenterAcronyms(Result, sDelimiters);  //liberal w/ somewhat narrow context
  Result = GetUpperCaseStateCodes(Result);                                      //liberal w/ narrow context
  Result = GetTitleCasing(Result);                                              
  Result = GetUpperCaseForSuspectedAcronyms(Result, sDelimiters);               //liberal w/ narrow context
  Result = GetUpperCaseWordsXt(Result, arUpperCaseWords, sDelimiters);          //liberal w/ narrow context
  Result = GetMicroDictionaryCasing(Result, arCaseDictionary, sDelimiters);     //liberal w/ narrow context
  
  if (Result.charAt(0) != Result.charAt(0).toUpperCase())
    Result = Result.charAt(0).toUpperCase() + Slice(Result, 1, Result.length - 1);
  
  return Result;
  
}         //GetMedicalGroupNameCasing()


function GetApartmentNumberCase(AString, AWordDelimiters)
{
  var arWordsAndDelimiters = GetWordsAndDelimiters(AString, AWordDelimiters + '#');
  var i;
  var iLastChar;
  var bChanged = false;
  var Result;

  for (i=0; i < arWordsAndDelimiters.length; i++)
    if (arWordsAndDelimiters[i].length > 1)
    {
      iLastChar = arWordsAndDelimiters[i].length - 1;
      if (IsAlpha(arWordsAndDelimiters[i].charAt(iLastChar)) && IsDigit(arWordsAndDelimiters[i].charAt(iLastChar - 1)))
        if (arWordsAndDelimiters[i].length == 2 || IsDigitString(arWordsAndDelimiters[i].substr(0, iLastChar)))
        {
          arWordsAndDelimiters[i] = arWordsAndDelimiters[i].substr(0, iLastChar) + arWordsAndDelimiters[i].charAt(iLastChar).toUpperCase();
          bChanged = true;
        }
    }
    
  if (bChanged)
  { 
    Result = '';
    for (i=0; i < arWordsAndDelimiters.length; i++)
      Result += arWordsAndDelimiters[i];
  }
  else
    Result = AString;      

  return Result;
            
}           //GetApartmentNumberCase()


function GetStreetAddressCasing(AString)
{
  var sDelimiters = GetStandardDelimiters();
  var Result = AString;
  var arCaseDictionary = new Array;
  
  if (AString == '')
    return '';
    
  arCaseDictionary[0] = 'PO';
  arCaseDictionary[1] = 'RR';

  Result = GetMixedCaseForStreetAddress(Result, sDelimiters);
  Result = GetApartmentNumberCase(Result, sDelimiters);
  Result = ConvertLastNameCasingForSpecialCases(Result);
  Result = GetMicroDictionaryCasing(Result, arCaseDictionary, sDelimiters);
  Result = ReplaceAll('c/o','c/o',Result);
  
  return Result;
  
}         //GetStreetAddressCasing()


function CharIn(AChar, ACharSet)
{
	var i;
	
	for (i=0; i < ACharSet.length; i++)
		if (AChar == ACharSet.charAt(i))
			return true;
			
	return false;

}			//CharIn()


function StringContainsAny(AString, ACharSet)
{
	var i;
	
	for (i=0; i < ACharSet.length; i++)
		if (AString.indexOf(ACharSet.charAt(i)) > -1)
			return true;
			
	return false;

}			//StringContainsAny()


function Pos(ASubstring, AString)
//same as indexOf() method, but is case insensitive
//05/2006 - now corrects anomalous behaviour found in IndexOf()
  // alert('asdf'.indexOf(' '); this returns -1, as expected.
  // alert('asdf'.indexOf('');  this returns 0.
{

  if (ASubstring == '')
    return -1
  else    
    return AString.toUpperCase().indexOf(ASubstring.toUpperCase());
	
}			//Pos()


function LastPos(ASubstring, AString)
{
  var i;
  
  i = AString.length - ASubstring.length;
  while (ASubstring != AString.substr(i, ASubstring.length))
  {
    i--;
    if (i < 0)
      return i;
  }
  
  return i;

}     //LastPos()


function AllPos(ASubstring, AString)
{
  //returns an array of each Position of ASubstring in AString
  //this routine relies on Pos() and is therefore case insensitive
  
  var iPos;
  var s = AString;
  var Result = new Array;
  var iTrimCount = 0;       //Number of characters trimmed from the front of s
  
  iPos = Pos(ASubstring, s);
  while (iPos > -1)
  {
    Result[Result.length] = iPos + iTrimCount;
    iTrimCount += iPos + ASubstring.length;
    s = s.substr(iPos + ASubstring.length);
    iPos = Pos(ASubstring, s);
  } 
  
  return Result;

}       //AllPos()


function Left(AInputString, AReturnCount)
{
  if (AReturnCount <= 0)     //Invalid input, return blank string
    return ''
  else 
  if (AReturnCount > String(AInputString).length)   //Invalid input, return entire string
    return AInputString                               
  else                                 
    return String(AInputString).substring(0, AReturnCount);
    
}       //Left()


function RepeatString(AString, ARepetitions)
{
	var s, i;
	
	s = AString;
	
	for (i=1; i < ARepetitions; i++)
		s = s + AString;
		
	return s;
	
}			//RepeatString()
	

function StripChar(AString, AChar)
{
  var i, Result;
  
  Result = '';
  for (i = 0; i < AString.length; i++)
    if (AString.charAt(i) != AChar)
      Result = Result + AString.charAt(i);
      
  return Result;

}       //StripChar()


function StripCharSet(AString, ACharSet)
{
  var i, Result;
  
  Result = '';
  for (i = 0; i < AString.length; i++)
    if (Pos(AString.charAt(i), ACharSet) == -1)
      Result += AString.charAt(i);
      
  return Result;

}       //StripCharSet()


function GetEnglishList(AStringArray, AConjunction)
{
  var i;
  var Result;
  var sConj = TrimSpaces(AConjunction);
  
  if (AStringArray.length == 0)
    return ''
  else
  if (AStringArray.length == 1)
    return AStringArray[0]
  else
  if (AStringArray.length == 2)
    return AStringArray[0] + ' ' + sConj + ' ' + AStringArray[1]
  else
  {
    Result = '';
    for (i=0; i < AStringArray.length - 1; i++)
      Result = Result + AStringArray[i] + ', ';
    
    Result = Result + sConj + ' ' + AStringArray[AStringArray.length - 1];
  
    return Result;
  }

}       //GetEnglishList()


function ReplaceTags(AString, ATagIdentifier, AReplacementValue)
// -------------------------------------------------------------
//  Replaces all instances of '<<' + ATagIdentifier + '>>' in
//    AString
// -------------------------------------------------------------
{
  var iPos, iLength;
  var sReplace = '<<' + ATagIdentifier + '>>';
  var sResult = AString;
  
  iLength = sReplace.length;
  iPos = Pos(sReplace, sResult);
  while (iPos > -1)
  {
    sResult = Slice(sResult, 0, iPos - 1) + AReplacementValue +
                Slice(sResult, iPos + iLength, sResult.length - 1);
    iPos = Pos(sReplace, sResult);
  }
  
  return sResult;
    
}       //ReplaceTags()


function GetMedicalProcedureMicroDictionary()
{
  var Result = new Array;
  
  Result[Result.length] = 'X';
  
  Result[Result.length] = 'GI';
  Result[Result.length] = 'OT';
  Result[Result.length] = 'pH';
  Result[Result.length] = 'ED';
  Result[Result.length] = 'Up';

  Result[Result.length] = 'out';
  Result[Result.length] = 'Ear';
  Result[Result.length] = 'Flu';
  Result[Result.length] = 'Aid';
  Result[Result.length] = 'Eye';
  Result[Result.length] = 'Lip';
  Result[Result.length] = 'Tap';
  Result[Result.length] = 'ADD';
  Result[Result.length] = 'ACE';
  Result[Result.length] = 'ICD';
  Result[Result.length] = 'PSA';
  Result[Result.length] = 'Pap';
  Result[Result.length] = 'ALK';
  Result[Result.length] = 'CO2';
  Result[Result.length] = 'Hb';
  Result[Result.length] = 'Hgb';
  Result[Result.length] = 'Hct';
  Result[Result.length] = 'CAD';
  Result[Result.length] = 'CAT';
  Result[Result.length] = 'A1C';
  Result[Result.length] = 'MRI';
  Result[Result.length] = 'Sed';
  Result[Result.length] = 'AFP';
  Result[Result.length] = 'AMA';
  Result[Result.length] = 'ANA';
  Result[Result.length] = 'PEG';
  Result[Result.length] = 'DXA';

  Result[Result.length] = 'with';
  Result[Result.length] = 'into';
  Result[Result.length] = 'FANA';
  Result[Result.length] = 'LEEP';
  Result[Result.length] = 'EPO';
  Result[Result.length] = 'ERCP';
  Result[Result.length] = 'LVAD';
  Result[Result.length] = 'XRAY';
  Result[Result.length] = 'X-RAY';
  Result[Result.length] = 'DEXA';
  Result[Result.length] = 'TIPS';
  Result[Result.length] = 'CABG';
  Result[Result.length] = 'TENS';
  Result[Result.length] = 'PTCA';

  Result[Result.length] = 'Lymph';
  Result[Result.length] = 'Cyst';
  Result[Result.length] = 'LASEK';
  Result[Result.length] = 'LASIK';
  Result[Result.length] = 'APGAR';

  Result[Result.length] = 'without';
  
  return Result;

}         //GetMedicalProcedureMicroDictionary()


function GetMedicalProcedureCasing(AString)
{
  var sDelimiters = ' ,.\/()-&[]';
  var arDict = GetMedicalProcedureMicroDictionary();
  var arTemp = GetTitleCasingMicroDictionary();
  var bIsStringMixedCase = IsMixedCase(AString);
  var arWordsAndDelimiters = GetWordsAndDelimiters(AString, sDelimiters);
  var i;
  var Result = '';
  
  for (i=0; i < arTemp.length; i++)         //tack arTemp items onto end of arDict
    arDict[arDict.length] = arTemp[i];
  
  if (arWordsAndDelimiters.length == 1)
    if (AString == AString.toUpperCase())
      if (AString.length < 6)
        return AString;
  
  for (i=0; i < arWordsAndDelimiters.length; i++)
    if (Pos(arWordsAndDelimiters[i].charAt(0), sDelimiters) < 0)         //this is a word, not delimiters
      if ((! bIsStringMixedCase) || arWordsAndDelimiters[i] == arWordsAndDelimiters[i].toLowerCase())
      {
        if (arWordsAndDelimiters[i].length < 3)
          arWordsAndDelimiters[i] = arWordsAndDelimiters[i].toUpperCase()
        else
          arWordsAndDelimiters[i] = arWordsAndDelimiters[i].charAt(0).toUpperCase() + 
                                      arWordsAndDelimiters[i].substr(1).toLowerCase();
        
        arWordsAndDelimiters[i] = GetUpperCaseForSuspectedAcronyms(arWordsAndDelimiters[i], sDelimiters);
        arWordsAndDelimiters[i] = GetMicroDictionaryCasing(arWordsAndDelimiters[i], arDict, sDelimiters);
      }

  for (i=0; i < arWordsAndDelimiters.length; i++)
    Result += arWordsAndDelimiters[i];
  
  return Result;  

}         //GetMedicalProcedureCasing()


function GetMicroDictionaryCasing(AString, ADictionaryArray, AWordDelimiters)
{
  var i;
  var iIndex;
  var iChangeCount = 0;
  var arWordsAndDelimiters = GetWordsAndDelimiters(AString, AWordDelimiters);
  var Result = '';

  for (i=0; i < arWordsAndDelimiters.length; i++)
    if (Pos(arWordsAndDelimiters[i].charAt(0), AWordDelimiters) < 0)      //is this a word?
    {
      iIndex = GetItemIndexInArray(arWordsAndDelimiters[i], ADictionaryArray);
      if (iIndex > -1)
      {
        arWordsAndDelimiters[i] = ADictionaryArray[iIndex];
        iChangeCount++;
      }
    }
    
  if (iChangeCount == 0)
    Result = AString
  else
    for (i=0; i < arWordsAndDelimiters.length; i++)
      Result += arWordsAndDelimiters[i];
    
  return Result;
  
}         //GetMicroDictionaryCasing()


function GetLabTestCasing(AString)
{
  
  return GetDiagnosisCasing(AString);

}         //GetLabTestCasing()


function GetDiagnosisCasing(AString)
{
  var Result;
  
  AString = TrimSpaces(AString);
  if (AString > '')
  {
    Result = GetTitleCasing(AString);
    Result = GetUpperCaseForSuspectedAcronyms(Result);
    Result = GetTripletCasingForDiagnosis(Result);
    Result = GetCardiacAcronymCasing(Result);
    return Result;
  }
  else
    return AString;

}         //GetDiagnosisCasing()


function GetSpecialityCasing(AString)
{
  var Result;
  var ar = new Array;
  var sDelimiters = ' ,.\/()-&[]';

  ar[0] = 'and';
    
  AString = TrimSpaces(AString);
  if (AString > '')
  {
    Result = GetCapitalizedWords(AString);
    Result = GetUpperCaseForSuspectedAcronyms(Result);
    Result = GetMicroDictionaryCasing(Result, ar, sDelimiters);
    return Result;
  }
  else
    return AString;

}


function GetCardiacAcronymCasing(AString)
{
  var ar = new Array;
  var sDelimiters = ' ,.\/()-&[]';
  
  ar[0] = 'NSTEMI';           //non-ST segment elevation myocardial infarction 
  ar[1] = 'MI';              
  ar[2] = 'LCA';              //left coronary artery
  ar[3] = 'RCA';              //right coronary artery
  ar[4] = 'SOB';              //shortness of breath
  ar[5] = 'AF';               //atrial fib
  ar[6] = 'LAD';              //left anterior descending

  return GetMicroDictionaryCasing(AString, ar, sDelimiters);

}         //GetCardiacAcronymCasing


function GetTripletCasingForDiagnosis(AString)
{
  //alters casing for 3 letter "words"
  //if triplet is not found in arCaseDictionary, triplet is upper cased
  var sDelimiters = ' ,.\/()-&[]';
  var arCaseDictionary = new Array;
  var arWords;
  var i;
  var Result = AString;
  
  //First, upper case all 3 letter words
  arWords = GetWords(AString, sDelimiters);
  for (i = 0; i < arWords.length; i++)
    if (arWords[i].length == 3)
      arCaseDictionary[arCaseDictionary.length] = arWords[i].toUpperCase();
      
  if (arCaseDictionary.length > 0)
  {
    Result = GetMicroDictionaryCasing(Result, arCaseDictionary, sDelimiters);
    
    //Now, re-case certain 3 letter words
    arCaseDictionary.length = 0;
    arCaseDictionary[arCaseDictionary.length] = 'Age';
    arCaseDictionary[arCaseDictionary.length] = 'Ago';
    arCaseDictionary[arCaseDictionary.length] = 'Aid';
    arCaseDictionary[arCaseDictionary.length] = 'Ail';
    arCaseDictionary[arCaseDictionary.length] = 'Aim';
    arCaseDictionary[arCaseDictionary.length] = 'and';
    arCaseDictionary[arCaseDictionary.length] = 'any';
    arCaseDictionary[arCaseDictionary.length] = 'Arc';
    arCaseDictionary[arCaseDictionary.length] = 'are';
    arCaseDictionary[arCaseDictionary.length] = 'Arm';
    arCaseDictionary[arCaseDictionary.length] = 'Art';
    arCaseDictionary[arCaseDictionary.length] = 'Ash';
    arCaseDictionary[arCaseDictionary.length] = 'Asp';
    arCaseDictionary[arCaseDictionary.length] = 'Azo';
    arCaseDictionary[arCaseDictionary.length] = 'Bad';
    arCaseDictionary[arCaseDictionary.length] = 'Bag';
    arCaseDictionary[arCaseDictionary.length] = 'Bed';
    arCaseDictionary[arCaseDictionary.length] = 'Big';
    arCaseDictionary[arCaseDictionary.length] = 'Bus';
    arCaseDictionary[arCaseDictionary.length] = 'Cap';    //as in Cradle Cap
    arCaseDictionary[arCaseDictionary.length] = 'Car';    //as in Car Sickness
    arCaseDictionary[arCaseDictionary.length] = 'Cor';    //as in Cor Pulmonale
    arCaseDictionary[arCaseDictionary.length] = 'Cow';
    arCaseDictionary[arCaseDictionary.length] = 'Cry';
    arCaseDictionary[arCaseDictionary.length] = 'Cup';
    arCaseDictionary[arCaseDictionary.length] = 'Cut';
    arCaseDictionary[arCaseDictionary.length] = 'Day';
    arCaseDictionary[arCaseDictionary.length] = 'Dry';
    arCaseDictionary[arCaseDictionary.length] = 'der';      //part of German name
    arCaseDictionary[arCaseDictionary.length] = 'Ear';
    arCaseDictionary[arCaseDictionary.length] = 'Ego';
    arCaseDictionary[arCaseDictionary.length] = 'Elk';
    arCaseDictionary[arCaseDictionary.length] = 'End';
    arCaseDictionary[arCaseDictionary.length] = 'Eye';
    arCaseDictionary[arCaseDictionary.length] = 'Fat';
    arCaseDictionary[arCaseDictionary.length] = 'Fir';
    arCaseDictionary[arCaseDictionary.length] = 'Flu';
    arCaseDictionary[arCaseDictionary.length] = 'for';
    arCaseDictionary[arCaseDictionary.length] = 'Fox';
    arCaseDictionary[arCaseDictionary.length] = 'Fry';
    arCaseDictionary[arCaseDictionary.length] = 'Fur';
    arCaseDictionary[arCaseDictionary.length] = 'Gas';
    arCaseDictionary[arCaseDictionary.length] = 'Gel';
    arCaseDictionary[arCaseDictionary.length] = 'Gem';
    arCaseDictionary[arCaseDictionary.length] = 'Gin';
    arCaseDictionary[arCaseDictionary.length] = 'Gum';
    arCaseDictionary[arCaseDictionary.length] = 'Gut';
    arCaseDictionary[arCaseDictionary.length] = 'Hay';
    arCaseDictionary[arCaseDictionary.length] = 'Hen';
    arCaseDictionary[arCaseDictionary.length] = 'Hip';
    arCaseDictionary[arCaseDictionary.length] = 'Hot';
    arCaseDictionary[arCaseDictionary.length] = 'Hug';
    arCaseDictionary[arCaseDictionary.length] = 'Ice';
    arCaseDictionary[arCaseDictionary.length] = 'Ink';
    arCaseDictionary[arCaseDictionary.length] = 'Ion';
    arCaseDictionary[arCaseDictionary.length] = 'Ivy';
    arCaseDictionary[arCaseDictionary.length] = 'Jam';
    arCaseDictionary[arCaseDictionary.length] = 'Jar';
    arCaseDictionary[arCaseDictionary.length] = 'Jaw';
    arCaseDictionary[arCaseDictionary.length] = 'Jay';
    arCaseDictionary[arCaseDictionary.length] = 'Jet';
    arCaseDictionary[arCaseDictionary.length] = 'Jog';
    arCaseDictionary[arCaseDictionary.length] = 'Lab';
    arCaseDictionary[arCaseDictionary.length] = 'Lag';
    arCaseDictionary[arCaseDictionary.length] = 'Lap';
    arCaseDictionary[arCaseDictionary.length] = 'Lax';
    arCaseDictionary[arCaseDictionary.length] = 'LCA';      //left coronary artery
    arCaseDictionary[arCaseDictionary.length] = 'Leg';
    arCaseDictionary[arCaseDictionary.length] = 'Let';
    arCaseDictionary[arCaseDictionary.length] = 'Lid';
    arCaseDictionary[arCaseDictionary.length] = 'Lip';
    arCaseDictionary[arCaseDictionary.length] = 'Log';
    arCaseDictionary[arCaseDictionary.length] = 'Lye';
    arCaseDictionary[arCaseDictionary.length] = 'Man';
    arCaseDictionary[arCaseDictionary.length] = 'Mid';
    arCaseDictionary[arCaseDictionary.length] = 'Mix';
    arCaseDictionary[arCaseDictionary.length] = 'Mud';
    arCaseDictionary[arCaseDictionary.length] = 'Net';
    arCaseDictionary[arCaseDictionary.length] = 'New';
    arCaseDictionary[arCaseDictionary.length] = 'Nip';
    arCaseDictionary[arCaseDictionary.length] = 'not';
    arCaseDictionary[arCaseDictionary.length] = 'Now';
    arCaseDictionary[arCaseDictionary.length] = 'Nut';
    arCaseDictionary[arCaseDictionary.length] = 'Oak';
    arCaseDictionary[arCaseDictionary.length] = 'Oat';
    arCaseDictionary[arCaseDictionary.length] = 'Off';
    arCaseDictionary[arCaseDictionary.length] = 'Oil';
    arCaseDictionary[arCaseDictionary.length] = 'Old';
    arCaseDictionary[arCaseDictionary.length] = 'One';
    arCaseDictionary[arCaseDictionary.length] = 'Ore';
    arCaseDictionary[arCaseDictionary.length] = 'out';
    arCaseDictionary[arCaseDictionary.length] = 'Ova';
    arCaseDictionary[arCaseDictionary.length] = 'Owl';
    arCaseDictionary[arCaseDictionary.length] = 'Pad';
    arCaseDictionary[arCaseDictionary.length] = 'Pan';
    arCaseDictionary[arCaseDictionary.length] = 'Pea';
    arCaseDictionary[arCaseDictionary.length] = 'Pep';
    arCaseDictionary[arCaseDictionary.length] = 'Pig';
    arCaseDictionary[arCaseDictionary.length] = 'Pin';
    arCaseDictionary[arCaseDictionary.length] = 'Pit';
    arCaseDictionary[arCaseDictionary.length] = 'Pin';
    arCaseDictionary[arCaseDictionary.length] = 'Pod';
    arCaseDictionary[arCaseDictionary.length] = 'Pox';
    arCaseDictionary[arCaseDictionary.length] = 'Pus';
    arCaseDictionary[arCaseDictionary.length] = 'RCA';      //right coronary artery
    arCaseDictionary[arCaseDictionary.length] = 'Red';
    arCaseDictionary[arCaseDictionary.length] = 'Rib';
    arCaseDictionary[arCaseDictionary.length] = 'Rim';
    arCaseDictionary[arCaseDictionary.length] = 'Rip';
    arCaseDictionary[arCaseDictionary.length] = 'Rod';
    arCaseDictionary[arCaseDictionary.length] = 'Rot';
    arCaseDictionary[arCaseDictionary.length] = 'Rub';
    arCaseDictionary[arCaseDictionary.length] = 'Rug';
    arCaseDictionary[arCaseDictionary.length] = 'Rum';
    arCaseDictionary[arCaseDictionary.length] = 'Rye';
    arCaseDictionary[arCaseDictionary.length] = 'Sac';
    arCaseDictionary[arCaseDictionary.length] = 'Sag';
    arCaseDictionary[arCaseDictionary.length] = 'Sex';
    arCaseDictionary[arCaseDictionary.length] = 'Shy';
    arCaseDictionary[arCaseDictionary.length] = 'Six';
    arCaseDictionary[arCaseDictionary.length] = 'Ski';
    arCaseDictionary[arCaseDictionary.length] = 'Soy';
    arCaseDictionary[arCaseDictionary.length] = 'Sun';
    arCaseDictionary[arCaseDictionary.length] = 'Tag';
    arCaseDictionary[arCaseDictionary.length] = 'Tan';
    arCaseDictionary[arCaseDictionary.length] = 'Tay';      //as in Tay-Sachs
    arCaseDictionary[arCaseDictionary.length] = 'Tea';
    arCaseDictionary[arCaseDictionary.length] = 'Ten';
    arCaseDictionary[arCaseDictionary.length] = 'the';
    arCaseDictionary[arCaseDictionary.length] = 'Tic';
    arCaseDictionary[arCaseDictionary.length] = 'Tie';    //as in tougue-tie
    arCaseDictionary[arCaseDictionary.length] = 'Tin';
    arCaseDictionary[arCaseDictionary.length] = 'Tip';
    arCaseDictionary[arCaseDictionary.length] = 'Toe';
    arCaseDictionary[arCaseDictionary.length] = 'Top';
    arCaseDictionary[arCaseDictionary.length] = 'Two';
    arCaseDictionary[arCaseDictionary.length] = 'Vas';      //as in Vas Deferens
    arCaseDictionary[arCaseDictionary.length] = 'Via';
    arCaseDictionary[arCaseDictionary.length] = 'Vim';
    arCaseDictionary[arCaseDictionary.length] = 'Vox';
    arCaseDictionary[arCaseDictionary.length] = 'Wad';
    arCaseDictionary[arCaseDictionary.length] = 'Wax';      //as in Wax in Ear
    arCaseDictionary[arCaseDictionary.length] = 'Web';
    arCaseDictionary[arCaseDictionary.length] = 'Wet';
    arCaseDictionary[arCaseDictionary.length] = 'Wry';
    arCaseDictionary[arCaseDictionary.length] = 'Yam';
    arCaseDictionary[arCaseDictionary.length] = 'Zoa';
    arCaseDictionary[arCaseDictionary.length] = 'Zoo';
    Result = GetMicroDictionaryCasing(Result, arCaseDictionary, sDelimiters);
  }
    
  return Result;

}           //GetTripletCasingForDiagnosis()


function DuplicateSingleQuotes(AString)
{
  var i;
  var Result = '';
  
  if (Pos("'", AString) == -1)
    return AString
  else
    for (i=0; i < AString.length; i++)
    {
      Result += AString[i];
      if (AString.charAt(i) == "'")
        Result += "'";
    }
    
  return Result;

}       //DuplicateSingleQuotes()


function ReplaceAll(AMatchText, ANewText, ATargetString)
{
  
  if (ATargetString == '')
    return ''
  else
    return ATargetString.replace(new RegExp(AMatchText, 'gi'), ANewText);

}         //ReplaceAll()


function AllSubstringsOfGivenLength(AString, ASubstringLength)
{
  //returns all substrings from AString with length = ASubstringLength
  var i;
  var Result = new Array;
  
  for (i = 0; i + ASubstringLength <= AString.length; i++)
    Result[i] = AString.substr(i, ASubstringLength);
    
  return Result;

}       //AllSubstringsOfGivenLength()


function AllSubstringsOfMinimumLength(AString, AMinimumLength)
{
  //returns all substrings from AString with length >= AMinimumLength
  //return values are in descending order by length
  var i;
  var iCurrentLength;
  var Result = new Array;
  
  for (iCurrentLength = AString.length; iCurrentLength >= AMinimumLength; iCurrentLength--)
    for (i = 0; i + iCurrentLength <= AString.length; i++)
      Result[Result.length] = AString.substr(i, iCurrentLength);
    
  return Result;

}       //AllSubstringsOfMinimumLength()


function LongestCommonSubstring(AString1, AString2, AMinimumLength)
{
  //return value is the longest common substring, but might not be the only common substring of that length
  //Common substrings of lengths < AMinimumLength will not be found
  var arSubstrings1 = AllSubstringsOfMinimumLength(AString1, AMinimumLength);
  var arSubstrings2 = AllSubstringsOfMinimumLength(AString2, AMinimumLength);
  var i;
  var iInner;
  
  if (AString1 == '' || AString2 == '')
    return '';
    
  if (! AMinimumLength)
    AMinimumLength = 1;
    
  for (i = 0; i < arSubstrings1.length; i++)
  {
    iInner = 0;
    while (iInner < arSubstrings2.length && arSubstrings1[i].length != arSubstrings2[iInner].length)
      iInner++;
    while (iInner < arSubstrings2.length && arSubstrings1[i].length == arSubstrings2[iInner].length)
    {
      if (arSubstrings1[i] == arSubstrings2[iInner])
        return arSubstrings1[i];
      iInner++;
    }
  }       //for...
  
  return '';
    
}           //LongestCommonSubstring()


function LongestCommonInitialSubstring(AString1, AString2)
{
  var sCommon = '';
  var sLong, sShort;
  var i;
  
  if (AString1 == AString2)
    return AString1
  else
  if (AString1 == '' || AString2 == '')
    return '';
    
  if (AString1.length > AString2.length)
  {
    sLong = AString1;
    sShort = AString2;
  }
  else
  {
    sLong = AString2;
    sShort = AString1;
  }
    
  for (i = 0; i < sShort.length; i++)
  {
    if (sLong.charAt(i) == sShort.charAt(i))
      sCommon += sLong.charAt(i)
    else
      break;
  }
    
  return sCommon;

}           //LongestCommonInitialSubstring()


function LongestCommonFinalSubstring(AString1, AString2)
{
  var sLong, sShort;
  var i, iOffset;
  var iFinalSubstringLength = 0;
  var iDiff;
  
  if (AString1 == AString2)
    return AString1
  else
  if (AString1 == '' || AString2 == '')
    return '';
    
  if (AString1.length > AString2.length)
  {
    sLong = AString1;
    sShort = AString2;
  }
  else
  {
    sLong = AString2;
    sShort = AString1;
  }
    
  iOffset = sLong.length - sShort.length;
  for (i = sLong.length - 1; i - iOffset > -1; i--)
    if (sLong.charAt(i) == sShort.charAt(i - iOffset))
      iFinalSubstringLength++
    else
      break;

  iDiff = sLong.length - iFinalSubstringLength;
  if (iDiff < sLong.length)
    return sLong.substr(iDiff)
  else
    return '';

}           //LongestCommonFinalSubstring()


function LongestSuccessiveCommonSubstrings(AString1, AString2)
{
  var Result = new Array;
  var sLCS = '';          //Longest Common Substring

  function NewString(AString)
  {
    var iPos1, iPos2;
    var Result = '';
    
    iPos1 = Pos(sLCS, AString);
    iPos2 = iPos1 + sLCS.length;
    
    if (iPos1 > 0)
      Result = Slice(AString, 0, iPos1 - 1);
      
    if (iPos2 < AString.length - 1)
      Result += Slice(AString, iPos2 + 1, AString.length - 1);
      
    return Result;
    
  }       //NewString()
  
  sLCS = LongestCommonSubstring(AString1, AString2, 1);
  while (sLCS > '')
  {
    Result[Result.length] = sLCS;
    AString1 = NewString(AString1);
    AString2 = NewString(AString2);
    sLCS = LongestCommonSubstring(AString1, AString2, 1);
  }
  
  return Result;

}       //LongestSuccessiveCommonSubstrings()


function FuzzyMatch(AString1, AString2)
{
  // returns a number between 0 and 1, indicating the degree of similarity
  // 0 indicates no similarity between the input strings
  // 1 indicates the input strings are identical
  // this routine is case insenstive
  // note: the LSCS Common Chain Link Count is an approximation (underestimate) of the Longest Common Subsequence
  var lscs;
  var iCommonCharCount = 0;
  var iLscsCommonChainLinkCount = 0;    //count of LSCS characters participating in a substring of length > 1
  var i;
  var iMaxLength = Math.max(AString1.length, AString2.length);
  var iMinLength = Math.min(AString1.length, AString2.length);
  var nScore1, nScoreCharCount, nScoreChainLink, nScorePosition, nWeighting;
  var iLongestCommonTerminusSubstring;     //max of LongestCommonInitialSubstring() and LongestCommonFinalSubstring()

  AString1 = AString1.toLowerCase();
  AString2 = AString2.toLowerCase();
  
  if (AString1 == AString2)
    return 1
  else
  if (AString1 == '' || AString2 == '')
    return 0;
  
  lscs = LongestSuccessiveCommonSubstrings(AString1, AString2);

  for (i = 0; i < lscs.length; i++)
  {
    iCommonCharCount += lscs[i].length;
    if (lscs[i].length > 1)
      iLscsCommonChainLinkCount += lscs[i].length;
  }
  
  nScoreCharCount = iCommonCharCount / iMaxLength;
  nScoreChainLink = iLscsCommonChainLinkCount / iMaxLength;
  
  nScore1 = (nScoreCharCount + nScoreChainLink) / 2;     //average of two scores
  
  if (nScore1 == 1)
    return nScore1
  else
  {
    iLongestCommonTerminusSubstring = Math.max(LongestCommonInitialSubstring(AString1, AString2).length, 
                                                LongestCommonFinalSubstring(AString1, AString2).length);
    nScorePosition = iLongestCommonTerminusSubstring / iMinLength;
    nWeighting = iLongestCommonTerminusSubstring / iMaxLength;
    if (nScorePosition > nScore1)
      return (nScore1 * (1 - nWeighting)) + (nScorePosition * nWeighting)
    else
      return nScore1;
  }

}       //FuzzyMatch()


function IsCommonSubstring(AString1, AString2, AMinimumMatchPercent)
{
  var iMinimumLength;
  
  if (AString1.length > AString2.length)
    iMinimumLength = round(AString2.length * (AMinimumMatchPercent / 100))
  else
    iMinimumLength = round(AString1.length * (AMinimumMatchPercent / 100));
    
  return LongestCommonSubstring(AString1, AString2, iMinimumLength) > '';
    
}         //IsCommonSubstring()


function StartsWith(AString, ASubString)
{
  
  if (AString.length < ASubString.length)
    return false
  else
    return AString.substr(0, ASubString.length) == ASubString;
    
}           //StartsWith()


function EndsWith(AString, ASubString)
{

  if (AString.length < ASubString)
    return false
  else
    return AString.substr(AString.length - ASubString.length) == ASubString;
    
}       //EndsWith()


function IsValidEMail(AMailAddress)
{
  var iPosAt, iPosDot;
  
  if (AMailAddress > '')
  {
    iPosAt = Pos('@', AMailAddress);
    iPosDot = Pos('.', AMailAddress);
    if (iPosAt > 2 && iPosDot > 5 && iPosDot > iPosAt)
      return iPosDot < AMailAddress.length - 2
    else
      return false;  
  }
  else
    return false;

}           //IsValidEMail()


function IsPiece(AString, APiece, ADelimiter)
{
  var ar = DelimitedStringToArray(AString, ADelimiter);
  var i;
  
  for (i=0; i < ar.length; i++)
    if (ar[i] == APiece)
      return true;
      
  return false;
}


function GetPiece(AString, ADelimiter, APieceIndex)
{
  var ar = DelimitedStringToArray(AString, ADelimiter);
  
  if (APieceIndex < ar.length)
    return ar[APieceIndex]
  else
    return '';

}         //GetPiece()


function GetLastPiece(AString, ADelimiter)
{
  var ar = DelimitedStringToArray(AString, ADelimiter);
  
  if (ar.length > 0)
    return ar[ar.length - 1]
  else
    return '';

}       //GetLastPiece()


function GetEMailKeysMessage(AInputValue)
{

  if (AInputValue > '')
  {  
    if (AInputValue.indexOf('@') == -1)
      return '[Space Bar]=@ / Exit Field for @saintfrancis.com'
    else
    if (AInputValue.indexOf('@') == AInputValue.length - 1)
      return '[Space Bar]=saintfrancis.com';
  }
  
  return '';

}             //GetEMailKeysMessage()


function GetDateKeysMessage(AInputValue)
{
  var sLen;
  var sPiece1, sPiece2, sPiece3;
  var bIsDigitString;
  var bValid;
  var d = new Date();
  var mm = ConvertInteger(d.getMonth() + 1);
  var dd = ConvertInteger(d.getDate());
  var yyyy = d.getFullYear().toString();
  
  
  function ConvertInteger(AInteger)
  {
    var s = AInteger.toString();
    if (s.length == 1)
      s = '0' + s;
    return s;
  }
  
  function IsDelimiter(ACharIndex)
  {
    return CharIn(AInputValue.charAt(ACharIndex),'/-.');
  }
  
  function IsLastCharDelimiter()
  {
    return IsDelimiter(sLen - 1);
  }
  
  void function SetPieces()
  {
    var i = 0;
    var sTemp = '';
    
    sPiece1 = '';
    sPiece2 = '';
    sPiece3 = '';

    while (i < sLen && ! IsDelimiter(i))
    {
      sPiece1 += AInputValue.charAt(i);
      i++;
    }
    while (i < sLen && ! IsDigit(AInputValue.charAt(i)))
    {
      sTemp += AInputValue.charAt(i);
      i++;
    }
    if (sTemp > '' && sTemp.length > 1)
      return;
    while (i < sLen && ! IsDelimiter(i))
    {
      sPiece2 += AInputValue.charAt(i);
      i++;
    }
    sTemp = '';    
    while (i < sLen && ! IsDigit(AInputValue.charAt(i)))
    {
      sTemp += AInputValue.charAt(i);
      i++;
    }
    if (sTemp > '' && sTemp.length > 1)
      return;
    while (i < AInputValue.length && ! IsDelimiter(i))
    {
      sPiece3 += AInputValue.charAt(i);
      i++;
    }
    
    if (i < sLen)
      return;
          
    if ((sPiece1 > '' && IsDigitString(sPiece1) && sPiece1.length < 3) && 
          (sPiece2 == '' || (IsDigitString(sPiece2) && sPiece2.length < 3)) &&
          (sPiece3 == '' || (IsDigitString(sPiece3) && sPiece3.length < 5)))
      bValid = true;
    
  }       //SetPieces()

  if (AInputValue == '')
    return '[Space Bar] = ' + mm + '/';
    
  sLen = AInputValue.length;
  bIsDigitString = IsDigitString(AInputValue);
  if (AInputValue.charAt(AInputValue.length - 1) == '0')
	{
    if (AInputValue.length == 1)
		  return ''
		else
		if (IsDelimiter(AInputValue.length - 2))
		  return ''
		else
		if (AInputValue.charAt(AInputValue.length - 2) == '0')
		  return '';
  }

  if (sLen == 4 && bIsDigitString)
    return '[Space Bar] = ' + yyyy
  else
  {
    SetPieces();
    if (bValid)
      if (sPiece3 > '')
        return ''
      else
      if (! IsLastCharDelimiter())
        return '[Space Bar] = /'
      else
      if (sPiece2 > '')
        return '[Space Bar] = ' + yyyy
      else
        return '[Space Bar] = ' + dd + '/';
  }

  return '';
  
}           //GetDateKeysMessage()