//Advanced Delphi Systems Code: ads_Strg
Unit ads_Strg;
{Copyright(c)2016 Advanced Delphi Systems

 Richard Maley
 Advanced Delphi Systems
 12613 Maidens Bower Drive
 Potomac, MD 20854 USA
 phone 301-840-1554
 dickmaley@advdelphisys.com

 The code herein can be used or modified by anyone.  Please retain references
 to Richard Maley at Advanced Delphi Systems.  If you make improvements to the
 code please send your improvements to dickmaley@advdelphisys.com so that the
 entire Delphi community can benefit.  All comments are welcome.
}
(*
UnitIndex Master Index Implementation Section Download Units
Description: ads_Strg.pas
This unit contains the following routines.

CharsToStartNumbersOnlyAfter   DeleteCharacterInString   DeleteLineBreaks   DeleteSubStringInString   DeleteSubStringInStringNoCase   DialogList   KeyPressOnlyAToZ   KeyPressOnlyLettersAbsolute   KeyPressOnlyNumbers   KeyPressOnlyNumbersAbsolute   KeyPressOnlyNumbersLettersAbsolute  Len   LettersOnlyAbsolute   Lower   NumbersOnly   NumbersOnlyAbsKeepMinusAndPeriod   NumbersOnlyAbsolute_1   NumbersOnlyAbsolute_2   Proper   ReplaceCharacterInString   ReplaceCharInString   ReplaceSubStringInString   ReplaceSubStringInStringNoCase   String_Grep_Contents   String_Grep_Detail   String_GrepAllToStringList   String_LineFeed_Format   String_LineFeed_Insert   String_Replace   String_Replace_NoCase   String_Reverse   StringListCommonAandBtoC   StringListSubtractBfromAtoC   StringPad   StrListCommonAandBtoC   StrListSubtractBfromAtoC   SubStr   TrimBlanksFromEnds   TrimBlanksLeft   TrimBlanksRight   TrimFast   TrimLeftFast   TrimRightFast   Upper   USPSStateAbbrs   USPSStateAndTerAbbrs   USPSStateAndTerNames   USPSStateAndTerNamesAndAbbrs   USPSStateNames   USPSStateNamesAndAbbrs  

*)
Interface

Uses
  Buttons,
  Classes,
  Controls,
  Dialogs,
  ExtCtrls,
  Forms,
  Graphics,
  StdCtrls,
  SysUtils,
  Windows;


Function StringListSubtractBfromAtoC(A,B: TStringList;out C: TStringList): String;
Function StrListSubtractBfromAtoC(A,B: String;out C: String): String;

Function StringListCommonAandBtoC(A,B: TStringList;out C: TStringList): String;
Function StrListCommonAandBtoC(A,B: String;out C: String): String;

Function TrimFast(sg : String): String;
Function TrimRightFast(sg : String): String;
Function TrimLeftFast(sg : String): String;

{!~ Throws away all characters except 0-9, except for N optional leading
Aplha charaters, can be either alpha or numceric for the first N chracters,
all after the first N chracters must be numberic}
Function CharsToStartNumbersOnlyAfter(InputString: String;
                                      NPositionForAlpha : Integer;
                                      ShiftToUpper,
                                      KeepLeadingZeros: Boolean): String;

{!~ Deletes all occurances of a Character in a String}
Function DeleteCharacterInString(InputCharacter,InputString: String): String;

{!~ Deletes all LineFeed Carriage Returns}
function DeleteLineBreaks(const S: string): string;

{!~ Deletes all occurances of specified substring in a String}
Function DeleteSubStringInString(substring,InputString: String): String;

{!~ Deletes all occurances of specified substring in a String and is case
insensitive.}
Function DeleteSubStringInStringNoCase(substring,InputString: String): String;

{!~ Presents a selection dialog to the user.  The selected items are returned
as a string.  Single or MultiSelect is supported.  If multiple items are returned
they are formatted as a TStringList Text property, which means the line returns
are embedded in the string.  To pass the list of display items to the function
either pass the text property of a TStringList or concatenate items like the
following 'item1'+#13+'itme2'+#13+'item3'....  Return values come exclusively from
the sgReturnList.  This allows there to be a difference between what is displayed
to the user and what is returned.  An initial selection can be set in the dialog
by passing values in the sgSelectedList parameter.  The items in sgSelectedList
must be items in the sgDisplayList.  MultiSelect is enabled by setting
boMultiSelect to True.  The dimensions of the dialog are controlled with
inWidth and inHeight.}
Function DialogList(
  sgCaption           : String;
  sgDisplayList       : String;
  sgReturnList        : String;
  sgSelectedList      : String;
  boMultiSelect       : Boolean;
  inHeight            : Integer;
  inWidth             : Integer
  ): String;

{!~ Throws away all keys except a-z and A-Z}
Procedure KeyPressOnlyAToZ(Var Key: Char);

{!~ Throws away all keys except letters}
Procedure KeyPressOnlyLettersAbsolute(Var Key: Char);

{!~ Throws away all keys except 0-9,-,+,.}
Procedure KeyPressOnlyNumbers(Var Key: Char);

{!~ Throws away all keys except a-z and A-Z and 0-9}
Procedure KeyPressOnlyNumbersLettersAbsolute(Var Key: Char);

{!~ Throws away all keys except 0-9}
Procedure KeyPressOnlyNumbersAbsolute(Var Key: Char);

{!~ Returns The Length Of The String}
Function Len(InputString: String): Integer;

{!~ Throws away all characters except letters}
Function LettersOnlyAbsolute(InputString: String): String;

{!~ Returns a string converted to lower case}
Function Lower(InputString: String): String;

{!~ Throws away all characters except 0-9,-,+,.}
Function NumbersOnly(InputString: String): String;

{!~ Throws away all characters except 0-9}
Function NumbersOnlyAbsolute(InputString: String): String; OverLoad;

{!~ Throws away all characters except 0-9, period and the minus sign}
Function NumbersOnlyAbsKeepMinusAndPeriod(InputString: String;KeepLeadingZeros: Boolean): String;

{!~ Throws away all characters except 0-9}
Function NumbersOnlyAbsolute(InputString: String;KeepLeadingZeros: Boolean): String; OverLoad;

{!~ Returns the Proper form of a string, i.e., each word
starts with a capitalized letter and all subsequent
letters are lowercase}
Function Proper(S : String): String;

{!~ Replaces all occurances of a character in a string
with a new character}
Function ReplaceCharInString(S,OldChar,NewChar :String): String;

{!~ Replaces all occurances of a Character in a String}
Function ReplaceCharacterInString(
           OldChar,
           NewChar,
           InputString: String): String;

{!~
Replaces all occurances of specified substring in a String.  This will have problems if
the OldSubString is Contained in the NewSubstring.  This is case sensitive.
}
Function ReplaceSubStringInString(OldSubString,NewSubString,InputString: String): String;

{!~
Replaces all occurances of specified substring in a String.  This will have problems if
the OldSubString is Contained in the NewSubstring.  This is case insensitive.
}
Function ReplaceSubStringInStringNoCase(OldSubString,NewSubString,InputString: String): String;

{!~ Pads or truncates a String and Justifies Left if StrJustify=True}
Function StringPad(
  InputStr,
  FillChar: String;
  StrLen: Integer;
  StrJustify: Boolean): String;

{!~
All matches are added to the Stringlist.
}
Function String_GrepAllToStringList(
  Source                  : String;   //The input string
  StartTag                : String;   //The start tag
  EndTag                  : String;   //The end tag
  Containing              : String;   //A match must contain this string
  Var StringList          : TStringList;   //A List of Matches
  CaseSensitiveTags       : Boolean;  //True if tags are casesensitive
  CaseSensitiveContaining : Boolean   //True if Containing string is casesensitive
  ): Boolean;                         //True if a match was found

{!~
Returns the contents of a string between two tags.  The tag
information is not returned.  Finding the tags is case sensitive.
}
Function String_Grep_Contents(Source, StartTag, EndTag: String): String;

{!~
STRING_GREP_DETAIL

This is a full featured grep function.  All data associated
with the grep operation is returned.  The substring before the
match section is stored in the BeforeString variable.  The Match
Substring is stored in two variables.  The variable MatchwithTags
stores the match substring wrapped in the Start and End Tags.
The variable MatchWithoutTags stores the match substring without
the Start and End Tags. CaseSensitivity can be toggled for both
the tags and the Containing String using the booleans
CaseSensitiveTags and CaseSensitiveContaining. For a match to be
successful it must satisfy all criteria.  If the Containing String
is null this criteria is not applied.
}
Function String_Grep_Detail(
  Source                  : String;   //The input string
  StartTag                : String;   //The start tag
  EndTag                  : String;   //The end tag
  Containing              : String;   //A match must contain this string
  Var BeforeString        : String;   //The substring prior to the match
  Var MatchWithTags       : String;   //The match string including tags
  Var MatchWithoutTags    : String;   //the match string without the tags
  Var AfterString         : String;   //The substring after the match with tags
  CaseSensitiveTags       : Boolean;  //True if tags are casesensitive
  CaseSensitiveContaining : Boolean   //True if Containing string is casesensitive
  ): Boolean;                         //True if a match was found

{!~
STRING_LINEFEED_FORMAT

The String_LineFeed_Format function adjusts all line breaks in the given
string "SourceString" to be true CR/LF sequences. The function changes any
CR characters not followed by a LF and any LF characters not preceded by a
CR into CR/LF pairs. It also converts LF/CR pairs to CR/LF pairs. The LF/CR
pair is common in Unix text files.
}
Function String_LineFeed_Format(SourceString : String): String;

{!~
Inserts a Carriage Return/Line Feed at the index position.
}
Function String_LineFeed_Insert(SourceString : String; Index : Integer): String;

{!~
STRING_REPLACE

Replace all occurances of OldSubString with NewSubString in SourceString
}
Function String_Replace(
  OldSubString : String;
  NewSubString : String;
  SourceString : String): String;

{!~
STRING_REPLACE_NOCASE

Replace all occurances of OldSubString with NewSubString in
SourceString ignoring case
}
Function String_Replace_NoCase(
  OldSubString : String;
  NewSubString : String;
  SourceString : String): String;

{!~
STRING_REVERSE

Returns a string whose values are all reversed,i.e. , the
first character is last and the last is first.
}
Function String_Reverse(S : String): String;

{!~ Returns a SubString of a String.
Can only handle strings up to 255 characters.}
Function SubStr(InputString: String; StartPos, StringLength: Byte): String;

{!~ Trims blank spaces from both sides of the string}
Function TrimBlanksFromEnds(InputString: String): String;

{!~ Trims blank spaces from the left of the string}
Function TrimBlanksLeft(InputString: String): String;

{!~ Trims blank spaces from the right of the string}
Function TrimBlanksRight(InputString: String): String;

{!~ Converts String To UpperCase}
Function Upper(InputString: String): String;

Function USPSStateAbbrs: String;
Function USPSStateAndTerAbbrs: String;
Function USPSStateAndTerNames: String;
Function USPSStateAndTerNamesAndAbbrs: String;
Function USPSStateNames: String;
Function USPSStateNamesAndAbbrs: String;

implementation


{!~
DeleteCharacterInString

Deletes all occurances of a Character in a String}
//
Unit Description UnitIndex Master Index
Function DeleteCharacterInString(InputCharacter,InputString: String): String;
Begin
  Result := DeleteSubStringInString(InputCharacter,InputString);
End;


{!~
CharsToStartNumbersOnlyAfter

Throws away all characters except 0-9, except for N optional leading
Aplha charaters, can be either alpha or numceric for the first N chracters,
all after the first N chracters must be numeric}
//
Unit Description UnitIndex Master Index
Function CharsToStartNumbersOnlyAfter(InputString: String;
                                      NPositionForAlpha : Integer;
                                      ShiftToUpper,
                                      KeepLeadingZeros: Boolean): String;
Var
  NewString: String;
  L        : Integer;
  i        : Integer;
  C        : Char;
Begin
  Result    := InputString;
  NewString := '';
  L         := Length(InputString);

  For i:= 1 To L Do
  Begin

    C := InputString[i];

    if i <= NPositionForAlpha then
    begin
         KeyPressOnlyNumbersLettersAbsolute(C);
         if Not (C = #0)
         and (ShiftToUpper) Then
            C:= UpCase(C);
    end
    else
         KeyPressOnlyNumbersAbsolute(C);

    If Not (C = #0) Then
    Begin

        If NewString = '0' Then
        Begin
          If Not KeepLeadingZeros Then NewString := '';
        End;

        NewString := NewString + C;

    End; //inner if

  End; //for

  Result    := NewString;

End;

{!~
DeleteLineBreaks

Deletes all LineFeed Carriage Returns}
//
Unit Description UnitIndex Master Index
function DeleteLineBreaks(const S: string): string;
var
  Source, SourceEnd: PChar;
begin
  Source := Pointer(S);
  SourceEnd := Source + Length(S);
  while Source < SourceEnd do
  begin
    case Source^ of
      #10: Source^ := #32;
      #13: Source^ := #32;
    end;
    Inc(Source);
  end;
  Result := S;
End;

{!~
DeleteSubStringInString

Deletes all occurances of specified substring in a String}
//
Unit Description UnitIndex Master Index
Function DeleteSubStringInString(substring,InputString: String): String;
Begin
  Result := StringReplace(InputString, substring,'',[rfReplaceAll]);
End;

{!~
DeleteSubStringInStringNoCase

Deletes all occurances of specified substring in a String and is case
insensitive.}
//
Unit Description UnitIndex Master Index
Function DeleteSubStringInStringNoCase(substring,InputString: String): String;
Begin
  Result := StringReplace(InputString, substring,'',[rfReplaceAll, rfIgnoreCase]);
End;

{!~
KeyPressOnlyAToZ

Throws away all keys except a-z and A-Z}
//
Unit Description UnitIndex Master Index
Procedure KeyPressOnlyAToZ(Var Key: Char);
Begin
  Case Key Of
    'a': Exit;
    'b': Exit;
    'c': Exit;
    'd': Exit;
    'e': Exit;
    'f': Exit;
    'g': Exit;
    'h': Exit;
    'i': Exit;
    'j': Exit;
    'k': Exit;
    'l': Exit;
    'm': Exit;
    'n': Exit;
    'o': Exit;
    'p': Exit;
    'q': Exit;
    'r': Exit;
    's': Exit;
    't': Exit;
    'u': Exit;
    'v': Exit;
    'w': Exit;
    'x': Exit;
    'y': Exit;
    'z': Exit;
    'A': Exit;
    'B': Exit;
    'C': Exit;
    'D': Exit;
    'E': Exit;
    'F': Exit;
    'G': Exit;
    'H': Exit;
    'I': Exit;
    'J': Exit;
    'K': Exit;
    'L': Exit;
    'M': Exit;
    'N': Exit;
    'O': Exit;
    'P': Exit;
    'Q': Exit;
    'R': Exit;
    'S': Exit;
    'T': Exit;
    'U': Exit;
    'V': Exit;
    'W': Exit;
    'X': Exit;
    'Y': Exit;
    'Z': Exit;
    #8 : Exit; {Backspace}
  End;
  Key := #0;   {Throw the key away}
End;

{!~
KeyPressOnlyNumbers

Throws away all keys except 0-9,-,+,.}
//
Unit Description UnitIndex Master Index
Procedure KeyPressOnlyNumbers(Var Key: Char);
Begin
  Case Key Of
    '0': Exit;
    '1': Exit;
    '2': Exit;
    '3': Exit;
    '4': Exit;
    '5': Exit;
    '6': Exit;
    '7': Exit;
    '8': Exit;
    '9': Exit;
    '-': Exit;
    '+': Exit;
    '.': Exit;
    #8 : Exit; {Backspace}
  End;
  Key := #0;   {Throw the key away}
End;

{!~
KeyPressOnlyNumbersLettersAbsolute

Throws away all keys except letters and numbers}
//
Unit Description UnitIndex Master Index
Procedure KeyPressOnlyNumbersLettersAbsolute(Var Key: Char);
Begin
  Case Key Of
    'a': Exit;
    'b': Exit;
    'c': Exit;
    'd': Exit;
    'e': Exit;
    'f': Exit;
    'g': Exit;
    'h': Exit;
    'i': Exit;
    'j': Exit;
    'k': Exit;
    'l': Exit;
    'm': Exit;
    'n': Exit;
    'o': Exit;
    'p': Exit;
    'q': Exit;
    'r': Exit;
    's': Exit;
    't': Exit;
    'u': Exit;
    'v': Exit;
    'w': Exit;
    'x': Exit;
    'y': Exit;
    'z': Exit;
    'A': Exit;
    'B': Exit;
    'C': Exit;
    'D': Exit;
    'E': Exit;
    'F': Exit;
    'G': Exit;
    'H': Exit;
    'I': Exit;
    'J': Exit;
    'K': Exit;
    'L': Exit;
    'M': Exit;
    'N': Exit;
    'O': Exit;
    'P': Exit;
    'Q': Exit;
    'R': Exit;
    'S': Exit;
    'T': Exit;
    'U': Exit;
    'V': Exit;
    'W': Exit;
    'X': Exit;
    'Y': Exit;
    'Z': Exit;
    '0': Exit;
    '1': Exit;
    '2': Exit;
    '3': Exit;
    '4': Exit;
    '5': Exit;
    '6': Exit;
    '7': Exit;
    '8': Exit;
    '9': Exit;
    #8 : Exit; {Backspace}
  End;
  Key := #0;   {Throw the key away}
End;

{!~
KeyPressOnlyNumbersAbsolute

Throws away all keys except 0-9}
//
Unit Description UnitIndex Master Index
Procedure KeyPressOnlyNumbersAbsolute(Var Key: Char);
Begin
  Case Key Of
    '0': Exit;
    '1': Exit;
    '2': Exit;
    '3': Exit;
    '4': Exit;
    '5': Exit;
    '6': Exit;
    '7': Exit;
    '8': Exit;
    '9': Exit;
    #8 : Exit; {Backspace}
  End;
  Key := #0;   {Throw the key away}
End;

{!~
Len

Returns The Length Of The String}
//
Unit Description UnitIndex Master Index
Function Len(InputString: String): Integer;
Begin
  Result := Length(InputString);
End;

{!~
Lower

Returns a string converted to lower case}
//
Unit Description UnitIndex Master Index
Function Lower(InputString: String): String;
Begin
  Result := LowerCase(InputString);
End;

{!~
NumbersOnly

Throws away all characters except 0-9,-,+,.}
//
Unit Description UnitIndex Master Index
Function NumbersOnly(InputString: String): String;
Var
  NewString: String;
  L        : Integer;
  i        : Integer;
  C        : Char;
Begin
  Result    := InputString;
  NewString := '';
  L         := Length(InputString);
  For i:= 1 To L Do
  Begin
    C := InputString[i];
    KeyPressOnlyNumbers(C);
    If Not (C = #0) Then
    Begin
      NewString := NewString + C;
    End;
  End;
  Result    := NewString;
End;

{!~
NumbersOnlyAbsolute

Throws away all characters except 0-9}
//
Unit Description UnitIndex Master Index
Function NumbersOnlyAbsolute(InputString: String;KeepLeadingZeros: Boolean): String; OverLoad;
Var
  NewString: String;
  L        : Integer;
  i        : Integer;
  C        : Char;
Begin
  Result    := InputString;
  NewString := '';
  L         := Length(InputString);
  For i:= 1 To L Do
  Begin
    C := InputString[i];
    If Not(
         (C='+')  Or
         (C='-')  Or
         (C='.')  Or
         (C=',')) Then
    Begin
      KeyPressOnlyNumbers(C);
      If Not (C = #0) Then
      Begin
        If NewString = '0' Then
        Begin
          If Not KeepLeadingZeros Then NewString := '';
        End;
        NewString := NewString + C;
      End;
    End;
  End;
  Result    := NewString;
End;

{!~
NumbersOnlyAbsKeepMinusAndPeriod

Throws away all characters except 0-9, period and the minus sign}
//
Unit Description UnitIndex Master Index
Function NumbersOnlyAbsKeepMinusAndPeriod(InputString: String;KeepLeadingZeros: Boolean): String;
Var
  NewString: String;
  L        : Integer;
  i        : Integer;
  C        : Char;
Begin
  Result    := InputString;
  NewString := '';
  L         := Length(InputString);
  For i:= 1 To L Do
  Begin
    C := InputString[i];
    If Not(
         (C='+')  Or
         (C=',')) Then
    Begin
      KeyPressOnlyNumbers(C);
      If Not (C = #0) Then
      Begin
        If NewString = '0' Then
        Begin
          If Not KeepLeadingZeros Then NewString := '';
        End;
        NewString := NewString + C;
      End;
    End;
  End;
  Result    := NewString;
End;

{!~
NumbersOnlyAbsolute

Throws away all characters except 0-9}
//
Unit Description UnitIndex Master Index
Function NumbersOnlyAbsolute(InputString: String): String;
Begin
  Result    := NumbersOnlyAbsolute(InputString,False);
End;

{!~
Proper

Returns the Proper form of a string, i.e., each word
starts with a capitalized letter and all subsequent
letters are lowercase}
//
Unit Description UnitIndex Master Index
Function Proper(S : String): String;
Var
  Capitalize : Boolean;
  NewString  : String;
  i          : Integer;
  L          : Integer;
  C          : String;
Begin
  Result     := '';
  Capitalize := True;
  NewString  := '';
  L          := Length(S);
  If L = 0 Then Exit;

  For i := 1 To L Do
  Begin
    C := SubStr(S,i,1);
    If Capitalize Then
    Begin
      NewString := NewString + UpperCase(C);
    End
    Else
    Begin
      NewString := NewString + LowerCase(C);
    End;
    If (C = ' ') Or (C = '_') Then
    Begin
      Capitalize := True;
    End
    Else
    Begin
      Capitalize := False;
    End;
  End;
  Result     := NewString;
End;

{!~
ReplaceCharInString

Replaces all occurances of a character in a string
with a new character}
//
Unit Description UnitIndex Master Index
Function ReplaceCharInString(S,OldChar,NewChar :String): String;
Begin
  Result     := StringReplace(S,OldChar,NewChar,[rfReplaceAll, rfIgnoreCase]);
End;

{!~
ReplaceCharacterInString

Replaces all occurances of a Character in a String}
//
Unit Description UnitIndex Master Index
Function ReplaceCharacterInString(
           OldChar,
           NewChar,
           InputString: String): String;
Begin
  Result := StringReplace(InputString,OldChar,NewChar,[rfReplaceAll, rfIgnoreCase]);
End;

{!~
ReplaceSubStringInString

Replaces all occurances of specified substring in a String.  This will have problems if
the OldSubString is Contained in the NewSubstring.  This is case sensitive.
}
//
Unit Description UnitIndex Master Index
Function ReplaceSubStringInString(OldSubString,NewSubString,InputString: String): String;
Begin
  Result := StringReplace(InputString,OldSubString,NewSubString,[rfReplaceAll]);
End;

{!~
ReplaceSubStringInStringNoCase

Replaces all occurances of specified substring in a String.  This will have problems if
the OldSubString is Contained in the NewSubstring.  This is case insensitive.
}
//
Unit Description UnitIndex Master Index
Function ReplaceSubStringInStringNoCase(OldSubString,NewSubString,InputString: String): String;
Begin
  Result := StringReplace(InputString,OldSubString,NewSubString,[rfReplaceAll, rfIgnoreCase]);
End;

{!~
StringPad

Pads or truncates a String and Justifies Left if StrJustify=True}
//
Unit Description UnitIndex Master Index
Function StringPad(
  InputStr,
  FillChar: String;
  StrLen: Integer;
  StrJustify: Boolean): String;
Var
  TempFill: String;
  Counter : Integer;
Begin
  If Not (Length(InputStr) = StrLen) Then
  Begin
    If Length(InputStr) > StrLen Then
    Begin
      InputStr := Copy(InputStr,1,StrLen);
    End
    Else
    Begin
      TempFill := '';
      For Counter := 1 To StrLen-Length(InputStr) Do
      Begin
        TempFill := TempFill + FillChar;
      End;
      If StrJustify Then
      Begin
        {Left Justified}
        InputStr := InputStr + TempFill;
      End
      Else
      Begin
        {Right Justified}
        InputStr := TempFill + InputStr ;
      End;
    End;
  End;
  Result := InputStr;
End;

{!~
String_GrepAllToStringList

All matches are added to the Stringlist.
}
//
Unit Description UnitIndex Master Index
Function String_GrepAllToStringList(
  Source                  : String;   //The input string
  StartTag                : String;   //The start tag
  EndTag                  : String;   //The end tag
  Containing              : String;   //A match must contain this string
  Var StringList          : TStringList;   //A List of Matches
  CaseSensitiveTags       : Boolean;  //True if tags are casesensitive
  CaseSensitiveContaining : Boolean   //True if Containing string is casesensitive
  ): Boolean;                         //True if a match was found
Var
  S                   : String;
  FoundMatch          : Boolean;
  BeforeString        : String;   //The substring prior to the match
  MatchWithTags       : String;   //The match string including tags
  MatchWithoutTags    : String;   //the match string without the tags
  AfterString         : String;   //The substring after the match with tags
Begin
  StringList.Clear;
  S         := Source;
  BeforeString        := '';      //The substring prior to the match
  MatchWithTags       := '';      //The match string including tags
  MatchWithoutTags    := '';      //the match string without the tags
  AfterString         := '';      //The substring after the match with tags
  FoundMatch:=
    String_Grep_Detail(
      S,                //Source                  : String;   //The input string
      StartTag,         //StartTag                : String;   //The start tag
      EndTag,           //EndTag                  : String;   //The end tag
      Containing,       //Containing              : String;   //A match must contain this string
      BeforeString,     //Var BeforeString        : String;   //The substring prior to the match
      MatchWithTags,    //Var MatchWithTags       : String;   //The match string including tags
      MatchWithoutTags, //Var MatchWithoutTags    : String;   //the match string without the tags
      AfterString,      //Var AfterString         : String;   //The substring after the match with tags
      CaseSensitiveTags,//CaseSensitiveTags       : Boolean;  //True if tags are casesensitive
      CaseSensitiveContaining);//CaseSensitiveContaining : Boolean   //True if Containing string is casesensitive
                        //): Boolean;                         //True if a match was found
  Result := FoundMatch;
  While FoundMatch Do
  Begin
    StringList.Add(TrimFast(MatchWithoutTags));
    S := AfterString;
    FoundMatch:=
      String_Grep_Detail(
        S,                //Source                  : String;   //The input string
        StartTag,         //StartTag                : String;   //The start tag
        EndTag,           //EndTag                  : String;   //The end tag
        Containing,       //Containing              : String;   //A match must contain this string
        BeforeString,     //Var BeforeString        : String;   //The substring prior to the match
        MatchWithTags,    //Var MatchWithTags       : String;   //The match string including tags
        MatchWithoutTags, //Var MatchWithoutTags    : String;   //the match string without the tags
        AfterString,      //Var AfterString         : String;   //The substring after the match with tags
        CaseSensitiveTags,//CaseSensitiveTags       : Boolean;  //True if tags are casesensitive
        CaseSensitiveContaining);//CaseSensitiveContaining : Boolean   //True if Containing string is casesensitive
                          //): Boolean;                         //True if a match was found
  End;
End;

{!~
String_Grep_Contents

Returns the contents of a string between two tags.  The tag
information is not returned.  Finding the tags is case sensitive.
}
//
Unit Description UnitIndex Master Index
Function String_Grep_Contents(Source, StartTag, EndTag: String): String;
Var
  Containing              : String;   //A match must contain this string
  BeforeString            : String;   //The substring prior to the match
  MatchWithTags           : String;   //The match string including tags
  MatchWithoutTags        : String;   //the match string without the tags
  AfterString             : String;   //The substring after the match with tags
  CaseSensitiveTags       : Boolean;  //True if tags are casesensitive
  CaseSensitiveContaining : Boolean;  //True if Containing string is casesensitive
Begin
  Containing              := '';      //A match must contain this string
  BeforeString            := '';      //The substring prior to the match
  MatchWithTags           := '';      //The match string including tags
  MatchWithoutTags        := '';      //the match string without the tags
  AfterString             := '';      //The substring after the match with tags
  CaseSensitiveTags       := False;   //True if tags are casesensitive
  CaseSensitiveContaining := False;   //True if Containing string is casesensitive
  String_Grep_Detail(
    Source,                  //Source                  : String;   //The input string
    StartTag,                //StartTag                : String;   //The start tag
    EndTag,                  //EndTag                  : String;   //The end tag
    Containing,              //Containing              : String;   //A match must contain this string
    BeforeString,            //Var BeforeString        : String;   //The substring prior to the match
    MatchWithTags,           //Var MatchWithTags       : String;   //The match string including tags
    MatchWithoutTags,        //Var MatchWithoutTags    : String;   //the match string without the tags
    AfterString,             //Var AfterString         : String;   //The substring after the match with tags
    CaseSensitiveTags,       //CaseSensitiveTags       : Boolean;  //True if tags are casesensitive
    CaseSensitiveContaining  //CaseSensitiveContaining : Boolean   //True if Containing string is casesensitive
    );                       //): Boolean;                         //True if a match was found
  Result := MatchWithoutTags;
End;

{!~
STRING_GREP_DETAIL

This is a full featured grep function.  All data associated
with the grep operation is returned.  The substring before the
match section is stored in the BeforeString variable.  The Match
Substring is stored in two variables.  The variable MatchwithTags
stores the match substring wrapped in the Start and End Tags.
The variable MatchWithoutTags stores the match substring without
the Start and End Tags. CaseSensitivity can be toggled for both
the tags and the Containing String using the booleans
CaseSensitiveTags and CaseSensitiveContaining. For a match to be
successful it must satisfy all criteria.  If the Containing String
is null this criteria is not applied.
}
//
Unit Description UnitIndex Master Index
Function String_Grep_Detail(
  Source                  : String;   //The input string
  StartTag                : String;   //The start tag
  EndTag                  : String;   //The end tag
  Containing              : String;   //A match must contain this string
  Var BeforeString        : String;   //The substring prior to the match
  Var MatchWithTags       : String;   //The match string including tags
  Var MatchWithoutTags    : String;   //the match string without the tags
  Var AfterString         : String;   //The substring after the match with tags
  CaseSensitiveTags       : Boolean;  //True if tags are casesensitive
  CaseSensitiveContaining : Boolean   //True if Containing string is casesensitive
  ): Boolean;                         //True if a match was found
Var
  P_StartTag      : Integer;
  P_EndTag        : Integer;
  P_Containing    : Integer;
  S               : String;
  //MaxCount        : Integer;
  Temp            : String;
  StartTagUpper   : String;
  EndTagUpper     : String;
  StartTagLen     : Integer;
  EndTagLen       : Integer;
  ContainingUpper : String;
Begin
  S                := Source;
  Result           := False;
  BeforeString     := '';
  MatchWithTags    := '';
  MatchWithoutTags := '';
  AfterString      := S;
  Temp             := '';
  StartTagUpper    := UpperCase(StartTag);
  EndTagUpper      := UpperCase(EndTag);
  StartTagLen      := Length(StartTag);
  EndTagLen        := Length(EndTag);
  ContainingUpper  := UpperCase(Containing);

  If CaseSensitiveTags Then
  Begin
    P_StartTag   := Pos(StartTag,S);
  End
  Else
  Begin
    P_StartTag   := Pos(StartTagUpper,UpperCase(S));
  End;
  If P_StartTag = 0 Then
  Begin
    Result := False;
    BeforeString     := Source;
    MatchWithTags    := '';
    MatchWithoutTags := '';
    AfterString      := '';
    Exit;
  End
  Else
  Begin
    BeforeString := BeforeString + Copy(S,1,P_StartTag-1);
    S := Copy(S,P_StartTag,Length(S)-P_StartTag+1);
    If CaseSensitiveTags Then
    Begin
      P_EndTag   := Pos(EndTag,S);
    End
    Else
    Begin
      P_EndTag   := Pos(EndTagUpper,UpperCase(S));
    End;
    If P_EndTag = 0 Then
    Begin
      Result := False;
      BeforeString     := Source;
      MatchWithTags    := '';
      MatchWithoutTags := '';
      AfterString      := '';
      Exit;
    End
    Else
    Begin
      Temp := Copy(S,StartTagLen+1,P_EndTag-StartTagLen-1);
      If Containing = '' Then
      Begin
        Result := True;
        MatchWithTags    := StartTag+Temp+EndTag;
        MatchWithoutTags := Temp;
        AfterString      := Copy(S,P_EndTag+EndTagLen,Length(S)-P_EndTag-EndTagLen+1);
        Exit;
      End;
      If CaseSensitiveContaining Then
      Begin
        P_Containing   := Pos(Containing,Temp);
      End
      Else
      Begin
        P_Containing   := Pos(ContainingUpper,UpperCase(Temp));
      End;
      If P_Containing = 0 Then
      Begin
        BeforeString := BeforeString + Copy(S,1,P_EndTag+EndTagLen-1);
        S := Copy(S,P_EndTag+EndTagLen,Length(S)-P_EndTag-EndTagLen+1);
      End
      Else
      Begin
        Result := True;
        MatchWithTags    := StartTag+Temp+EndTag;
        MatchWithoutTags := Temp;
        AfterString      := Copy(S,P_EndTag+EndTagLen,Length(S)-P_EndTag-EndTagLen+1);
        Exit;
      End;
    End;
  End;
End;

{!~
STRING_LINEFEED_FORMAT

The String_LineFeed_Format function adjusts all line breaks in the given
string "SourceString" to be true CR/LF sequences. The function changes any
CR characters not followed by a LF and any LF characters not preceded by a
CR into CR/LF pairs. It also converts LF/CR pairs to CR/LF pairs. The LF/CR
pair is common in Unix text files.
}
//
Unit Description UnitIndex Master Index
Function String_LineFeed_Format(SourceString : String): String;
Begin
  Result := AdjustLineBreaks(SourceString);
End;

{!~
String_LineFeed_Insert

Inserts a Carriage Return/Line Feed at the index position.
}
//
Unit Description UnitIndex Master Index
Function String_LineFeed_Insert(SourceString : String; Index : Integer): String;
Var
  L : Integer;
Begin
  Result := SourceString;
  L := Length(SourceString);
  If SourceString = '' Then
  Begin
    Result := #13 + #10;
    Exit;
  End;
  If Index > L Then
  Begin
    Result := SourceString + #13 + #10;
    Exit;
  End;
  If Index <= 1 Then
  Begin
    Result := #13 + #10 + SourceString;
    Exit;
  End;
  Result :=
    Copy(SourceString,1,Index-1)+
    #13+
    #10+
    Copy(SourceString,Index,L-(Index-1));
End;

{!~
STRING_REPLACE

Replace all occurances of OldSubString with NewSubString in SourceString.
This function is case sensitive.
}
//
Unit Description UnitIndex Master Index
Function String_Replace(
  OldSubString : String;
  NewSubString : String;
  SourceString : String): String;
Begin
  Result := StringReplace(SourceString,OldSubString,NewSubString,[rfReplaceAll]);
End;

{!~
STRING_REPLACE_NOCASE

Replace all occurances of OldSubString with NewSubString in
SourceString ignoring case
}
//
Unit Description UnitIndex Master Index
Function String_Replace_NoCase(
  OldSubString : String;
  NewSubString : String;
  SourceString : String): String;
Begin
  Result := StringReplace(SourceString,OldSubString,NewSubString,[rfReplaceAll, rfIgnoreCase]);
End;

{!~
STRING_REVERSE

Returns a string whose values are all reversed,i.e. , the
first character is last and the last is first.
}
//
Unit Description UnitIndex Master Index
Function String_Reverse(S : String): String;
Var
  i   : Integer;
Begin
  Result := '';
  For i := Length(S) DownTo 1 Do
  Begin
    Result := Result + Copy(S,i,1);
  End;
End;

{!~
SubStr

Returns a SubString of a String.}
//
Unit Description UnitIndex Master Index
Function SubStr(InputString: String; StartPos, StringLength: Byte): String;
Begin
  Result:=Copy(InputString,StartPos,StringLength);
End;

{!~
TrimBlanksFromEnds

Trims blank spaces from both sides of the string}
//
Unit Description UnitIndex Master Index
Function TrimBlanksFromEnds(InputString: String): String;
Begin
  Result := TrimFast(InputString);
End;

{!~
TrimBlanksLeft

Trims blank spaces from the left of the string}
//
Unit Description UnitIndex Master Index
Function TrimBlanksLeft(InputString: String): String;
Begin
  Result := TrimLeftFast(InputString);
End;

{!~
TrimBlanksRight

Trims blank spaces from the right of the string}
//
Unit Description UnitIndex Master Index
Function TrimBlanksRight(InputString: String): String;
Begin
  Result := TrimRightFast(InputString);
End;

{!~
Upper

Converts String To UpperCase}
//
Unit Description UnitIndex Master Index
Function Upper(InputString: String): String;
Begin
  Result := UpperCase(InputString);
End;

{!~
KeyPressOnlyLettersAbsolute

Throws away all keys except letters}
//
Unit Description UnitIndex Master Index
Procedure KeyPressOnlyLettersAbsolute(Var Key: Char);
Begin
  Case Key Of
    'a': Exit;
    'b': Exit;
    'c': Exit;
    'd': Exit;
    'e': Exit;
    'f': Exit;
    'g': Exit;
    'h': Exit;
    'i': Exit;
    'j': Exit;
    'k': Exit;
    'l': Exit;
    'm': Exit;
    'n': Exit;
    'o': Exit;
    'p': Exit;
    'q': Exit;
    'r': Exit;
    's': Exit;
    't': Exit;
    'u': Exit;
    'v': Exit;
    'w': Exit;
    'x': Exit;
    'y': Exit;
    'z': Exit;
    'A': Exit;
    'B': Exit;
    'C': Exit;
    'D': Exit;
    'E': Exit;
    'F': Exit;
    'G': Exit;
    'H': Exit;
    'I': Exit;
    'J': Exit;
    'K': Exit;
    'L': Exit;
    'M': Exit;
    'N': Exit;
    'O': Exit;
    'P': Exit;
    'Q': Exit;
    'R': Exit;
    'S': Exit;
    'T': Exit;
    'U': Exit;
    'V': Exit;
    'W': Exit;
    'X': Exit;
    'Y': Exit;
    'Z': Exit;
    #8 : Exit; {Backspace}
  End;
  Key := #0;   {Throw the key away}
End;

{!~
LettersOnlyAbsolute

Throws away all characters except letters}
//
Unit Description UnitIndex Master Index
Function LettersOnlyAbsolute(InputString: String): String;
Var
  NewString: String;
  L        : Integer;
  i        : Integer;
  C        : Char;
Begin
  Result    := InputString;
  NewString := '';
  L         := Length(InputString);
  For i:= 1 To L Do
  Begin
    C := InputString[i];
    KeyPressOnlyLettersAbsolute(C);
    If Not (C = #0) Then
    Begin
      NewString := NewString + C;
    End;
  End;
  Result    := NewString;
End;

{!~
DialogList

Presents a list dialog.  Returns a string with the selected
values.  The return string is equivalent to the text property
of TStrings.  If multiselect is enabled then the return
string can contain multiple values, otherwise a single value.
If the user presses cancel then the original list of Selected
items is returned, otherwise the newly selected items are
returned.

  sgCaption           : Dialog caption.
  sgDisplayList       : List of items to display as a string.
                        Text property of TStrings.
  sgReturnList        : List of items to return as a string.
                        Text property of TStrings.  The
                        Display and Return lists can be the
                        same or different.
  sgSelectedList      : List of items that appear selected.
                        The list is passed to this function
                        as a string.  The string is the same
                        as the Text property of TStrings.
  boMultiSelect       : A Boolean that controls whether
                        multiselect is allowed or not.
  inHeight            : An Integer that sets the height of the
                        dialog window.
  inWidth             : An Integer that sets the width of the
                        dialog window.
}
//
Unit Description UnitIndex Master Index
Function DialogList(
  sgCaption           : String;
  sgDisplayList       : String;
  sgReturnList        : String;
  sgSelectedList      : String;
  boMultiSelect       : Boolean;
  inHeight            : Integer;
  inWidth             : Integer
  ): String;
Var
  inSelected          : Integer;
  inCounter           : Integer;
  frm                 : TForm;
  pnlBase             : TPanel;
  pnlButtons          : TPanel;
  btnOK               : TBitBtn;
  btnCancel           : TBitBtn;
  lstReturnList       : TListBox;
  lstDisplayList      : TListBox;
  lstSReturnList      : TStringList;
  lstSDisplayList     : TStringList;
  lstSelected         : TStringList;
  lstSelectedExist    : TStringList;
Begin
  If inWidth < 180 Then inWidth := 180;
  Result              := '';
  pnlBase             := nil;
  pnlButtons          := nil;
  btnOK               := nil;
  btnCancel           := nil;
  lstReturnList       := nil;
  lstDisplayList      := nil;
  frm                 := TForm.Create(nil);
  lstSReturnList      := TStringList.Create();
  lstSDisplayList     := TStringList.Create();
  lstSelected         := TStringList.Create();
  lstSelectedExist    := TStringList.Create();
  Try
    lstSReturnList   .Clear;
    lstSDisplayList  .Clear;
    lstSelected      .Clear;
    lstSelectedExist .Clear;
    lstSReturnList   .SetText(PChar(sgReturnList));
    lstSDisplayList  .SetText(PChar(sgDisplayList));
    lstSelected      .SetText(PChar(sgSelectedList));
    If lstSDisplayList.Count <> lstSReturnList.Count Then
    Begin
      ShowMessage('DialogList Error: Display and Return lists must be the same size.');
      Exit;
    End;
    With frm Do
    Begin
      Left           := 477;
      Top            := 327;
      BorderIcons    := [];
      BorderStyle    := bsDialog;
      Caption        := sgCaption;
      ClientHeight   := inHeight;
      ClientWidth    := inWidth;
      Color          := clBtnFace;
      Font.Charset   := DEFAULT_CHARSET;
      Font.Color     := clWindowText;
      Font.Height    := -11;
      Font.Name      := 'MS Sans Serif';
      Font.Style     := [];
      OldCreateOrder := False;
      Position       := poScreenCenter;
      PixelsPerInch  := 96;
      ShowHint       := True;
    End;
    pnlBase := TPanel.Create(frm);
    With pnlBase Do
    Begin
      Parent      := frm;
      Left        := 0;
      Top         := 0;
      Width       := frm.ClientWidth;
      Height      := frm.ClientHeight;
      Align       := alClient;
      BevelOuter  := bvNone;
      BorderWidth := 10;
      Caption     := '  ';
      TabOrder    := 0;
    End;
    pnlButtons    := TPanel.Create(frm);
    With pnlButtons Do
    Begin
      Parent      := pnlBase;
      Left        := 10;
      Top         := 270;
      Width       := pnlBase.Width - 20;
      Height      := 43;
      Align       := alBottom;
      BevelOuter  := bvNone;
      Caption     := '  ';
      TabOrder    := 0;
    End;
    btnOK         := TBitBtn.Create(frm);
    With btnOK Do
    Begin
      Parent      := pnlButtons;
      Top         := 16;
      Width       := 75;
      Height      := 25;
      Enabled     := True;
      TabOrder    := 0;
      Kind        := bkOK;
      Left        := pnlButtons.Width - 160;
      Hint        := 'Close and return selection.';
    End;
    btnCancel     := TBitBtn.Create(frm);
    With btnCancel Do
    Begin
      Parent      := pnlButtons;
      Top         := 16;
      Width       := 75;
      Height      := 25;
      TabOrder    := 1;
      Kind        := bkCancel;
      Left        := pnlButtons.Width - 75;
      Hint        := 'Close and make no selection.';
    End;

    lstReturnList := TListBox.Create(frm);
    With lstReturnList Do
    Begin
      Parent       := pnlBase;
      Left         := 10;
      Top          := 10;
      Width        := 272;
      Height       := 260;
      Align        := alClient;
      ItemHeight   := 13;
      TabOrder     := 3;
      Items.SetText(PChar(sgReturnList));
    End;
    lstDisplayList := TListBox.Create(frm);
    With lstDisplayList Do
    Begin
      Parent       := pnlBase;
      MultiSelect  := boMultiSelect;
      Left         := 10;
      Top          := 10;
      Width        := 272;
      Height       := 260;
      Align        := alClient;
      ItemHeight   := 13;
      TabOrder     := 1;
      Items.SetText(PChar(sgDisplayList));
      If boMultiSelect Then
      Begin
        Hint := 'Ctrl-Click multiple items to select them.';
      End
      Else
      Begin
        Hint := 'Click an item to select it.';
      End;
    End;

    For inCounter := 0 To lstSelected.Count - 1 Do
    Begin
      inSelected := lstDisplayList.Items.IndexOf(lstSelected[inCounter]);
      If inSelected <> -1 Then
      Begin
        lstSelectedExist.Add(lstSelected[inCounter]);
        If Not boMultiSelect Then
        Begin
          lstDisplayList.ItemIndex := inSelected;
          Break;
        End
        Else
        Begin
          lstDisplayList.Selected[inSelected] := True;
        End;
      End
    End;

    If frm.ShowModal = mrOK Then
    Begin
      lstSReturnList.Clear;
      For inCounter := 0 To lstDisplayList.Items.Count - 1 Do
      Begin
        If lstDisplayList.Selected[inCounter] Then
        Begin
          lstSReturnList.Add(lstReturnList.Items[inCounter]);
          If Not boMultiSelect Then
          Begin
            Result          := lstSReturnList[0];
            Break;
          End
          Else
          Begin
            Result          := lstSReturnList.Text;
          End;
        End;
      End;
    End
    Else
    Begin
      Result := '';
    End;
  Finally
    lstDisplayList   .Free;
    lstReturnList    .Free;
    btnCancel        .Free;
    btnOK            .Free;
    pnlButtons       .Free;
    pnlBase          .Free;
    frm.Free;
    lstSReturnList   .Free;
    lstSDisplayList  .Free;
    lstSelected      .Free;
    lstSelectedExist .Free;
  End;
End;

{!~
USPSStateAndTerNamesAndAbbrs

Returns United States State and Territory Names and Abbreviations.
This function returns a string that is the text property of a TStringList.  To
populate a TStringList with this string do something like the following:
  StringList.SetText(PChar(USPSStateAndTerNamesAndAbbrs));
}
//
Unit Description UnitIndex Master Index
Function USPSStateAndTerNamesAndAbbrs: String;
Var
  lst : TStringList;
Begin
  lst := TStringList.Create();
  Try
    With lst Do
    Begin
      Clear;
      Add('ALABAMA                        AL');
      Add('ALASKA                         AK');
      Add('AMERICAN SAMOA                 AS');
      Add('ARIZONA                        AZ');
      Add('ARKANSAS                       AR');
      Add('CALIFORNIA                     CA');
      Add('COLORADO                       CO');
      Add('CONNECTICUT                    CT');
      Add('DELAWARE                       DE');
      Add('DISTRICT OF COLUMBIA           DC');
      Add('FEDERATED STATES OF MICRONESIA FM');
      Add('FLORIDA                        FL');
      Add('GEORGIA                        GA');
      Add('GUAM                           GU');
      Add('HAWAII                         HI');
      Add('IDAHO                          ID');
      Add('ILLINOIS                       IL');
      Add('INDIANA                        IN');
      Add('IOWA                           IA');
      Add('KANSAS                         KS');
      Add('KENTUCKY                       KY');
      Add('LOUISIANA                      LA');
      Add('MAINE                          ME');
      Add('MARSHALL ISLANDS               MH');
      Add('MARYLAND                       MD');
      Add('MASSACHUSETTS                  MA');
      Add('MICHIGAN                       MI');
      Add('MINNESOTA                      MN');
      Add('MISSISSIPPI                    MS');
      Add('MISSOURI                       MO');
      Add('MONTANA                        MT');
      Add('NEBRASKA                       NE');
      Add('NEVADA                         NV');
      Add('NEW HAMPSHIRE                  NH');
      Add('NEW JERSEY                     NJ');
      Add('NEW MEXICO                     NM');
      Add('NEW YORK                       NY');
      Add('NORTH CAROLINA                 NC');
      Add('NORTH DAKOTA                   ND');
      Add('NORTHERN MARIANA ISLANDS       MP');
      Add('OHIO                           OH');
      Add('OKLAHOMA                       OK');
      Add('OREGON                         OR');
      Add('PALAU                          PW');
      Add('PENNSYLVANIA                   PA');
      Add('PUERTO RICO                    PR');
      Add('RHODE ISLAND                   RI');
      Add('SOUTH CAROLINA                 SC');
      Add('SOUTH DAKOTA                   SD');
      Add('TENNESSEE                      TN');
      Add('TEXAS                          TX');
      Add('UTAH                           UT');
      Add('VERMONT                        VT');
      Add('VIRGIN ISLANDS                 VI');
      Add('VIRGINIA                       VA');
      Add('WASHINGTON                     WA');
      Add('WEST VIRGINIA                  WV');
      Add('WISCONSIN                      WI');
      Add('WYOMING                        WY');
      Result := Text;
    End;
  Finally
    lst.Free;
  End;
End;

{!~
USPSStateNamesAndAbbrs

Returns United States State Names and Abbreviations.
This function returns a string that is the text property of a TStringList.  To
populate a TStringList with this string do something like the following:
  StringList.SetText(PChar(USPSStateNamesAndAbbrs));
}
//
Unit Description UnitIndex Master Index
Function USPSStateNamesAndAbbrs: String;
Var
  lst : TStringList;
Begin
  lst := TStringList.Create();
  Try
    With lst Do
    Begin
      Clear;
      Add('ALABAMA                        AL');
      Add('ALASKA                         AK');
      Add('ARIZONA                        AZ');
      Add('ARKANSAS                       AR');
      Add('CALIFORNIA                     CA');
      Add('COLORADO                       CO');
      Add('CONNECTICUT                    CT');
      Add('DELAWARE                       DE');
      Add('DISTRICT OF COLUMBIA           DC');
      Add('FLORIDA                        FL');
      Add('GEORGIA                        GA');
      Add('HAWAII                         HI');
      Add('IDAHO                          ID');
      Add('ILLINOIS                       IL');
      Add('INDIANA                        IN');
      Add('IOWA                           IA');
      Add('KANSAS                         KS');
      Add('KENTUCKY                       KY');
      Add('LOUISIANA                      LA');
      Add('MAINE                          ME');
      Add('MARYLAND                       MD');
      Add('MASSACHUSETTS                  MA');
      Add('MICHIGAN                       MI');
      Add('MINNESOTA                      MN');
      Add('MISSISSIPPI                    MS');
      Add('MISSOURI                       MO');
      Add('MONTANA                        MT');
      Add('NEBRASKA                       NE');
      Add('NEVADA                         NV');
      Add('NEW HAMPSHIRE                  NH');
      Add('NEW JERSEY                     NJ');
      Add('NEW MEXICO                     NM');
      Add('NEW YORK                       NY');
      Add('NORTH CAROLINA                 NC');
      Add('NORTH DAKOTA                   ND');
      Add('OHIO                           OH');
      Add('OKLAHOMA                       OK');
      Add('OREGON                         OR');
      Add('PENNSYLVANIA                   PA');
      Add('RHODE ISLAND                   RI');
      Add('SOUTH CAROLINA                 SC');
      Add('SOUTH DAKOTA                   SD');
      Add('TENNESSEE                      TN');
      Add('TEXAS                          TX');
      Add('UTAH                           UT');
      Add('VERMONT                        VT');
      Add('VIRGINIA                       VA');
      Add('WASHINGTON                     WA');
      Add('WEST VIRGINIA                  WV');
      Add('WISCONSIN                      WI');
      Add('WYOMING                        WY');
      Result := Text;
    End;
  Finally
    lst.Free;
  End;
End;

{!~
USPSStateNames

Returns United States State Names.
This function returns a string that is the text property of a TStringList.  To
populate a TStringList with this string do something like the following:
  StringList.SetText(PChar(USPSStateNames));
}
//
Unit Description UnitIndex Master Index
Function USPSStateNames: String;
Var
  lst : TStringList;
Begin
  lst := TStringList.Create();
  Try
    With lst Do
    Begin
      Clear;
      Add('ALABAMA');
      Add('ALASKA');
      Add('ARIZONA');
      Add('ARKANSAS');
      Add('CALIFORNIA');
      Add('COLORADO');
      Add('CONNECTICUT');
      Add('DELAWARE');
      Add('DISTRICT OF COLUMBIA');
      Add('FLORIDA');
      Add('GEORGIA');
      Add('HAWAII');
      Add('IDAHO');
      Add('ILLINOIS');
      Add('INDIANA');
      Add('IOWA');
      Add('KANSAS');
      Add('KENTUCKY');
      Add('LOUISIANA');
      Add('MAINE');
      Add('MARYLAND');
      Add('MASSACHUSETTS');
      Add('MICHIGAN');
      Add('MINNESOTA');
      Add('MISSISSIPPI');
      Add('MISSOURI');
      Add('MONTANA');
      Add('NEBRASKA');
      Add('NEVADA');
      Add('NEW HAMPSHIRE');
      Add('NEW JERSEY');
      Add('NEW MEXICO');
      Add('NEW YORK');
      Add('NORTH CAROLINA');
      Add('NORTH DAKOTA');
      Add('OHIO');
      Add('OKLAHOMA');
      Add('OREGON');
      Add('PENNSYLVANIA');
      Add('RHODE ISLAND');
      Add('SOUTH CAROLINA');
      Add('SOUTH DAKOTA');
      Add('TENNESSEE');
      Add('TEXAS');
      Add('UTAH');
      Add('VERMONT');
      Add('VIRGINIA');
      Add('WASHINGTON');
      Add('WEST VIRGINIA');
      Add('WISCONSIN');
      Add('WYOMING');
      Result := Text;
    End;
  Finally
    lst.Free;
  End;
End;

{!~
USPSStateAbbrs

Returns United States State Abbreviations.
This function returns a string that is the text property of a TStringList.  To
populate a TStringList with this string do something like the following:
  StringList.SetText(PChar(USPSStateAbbrs));
}
//
Unit Description UnitIndex Master Index
Function USPSStateAbbrs: String;
Var
  lst : TStringList;
Begin
  lst := TStringList.Create();
  Try
    With lst Do
    Begin
      Clear;
      Add('AL');
      Add('AK');
      Add('AZ');
      Add('AR');
      Add('CA');
      Add('CO');
      Add('CT');
      Add('DE');
      Add('DC');
      Add('FL');
      Add('GA');
      Add('HI');
      Add('ID');
      Add('IL');
      Add('IN');
      Add('IA');
      Add('KS');
      Add('KY');
      Add('LA');
      Add('ME');
      Add('MD');
      Add('MA');
      Add('MI');
      Add('MN');
      Add('MS');
      Add('MO');
      Add('MT');
      Add('NE');
      Add('NV');
      Add('NH');
      Add('NJ');
      Add('NM');
      Add('NY');
      Add('NC');
      Add('ND');
      Add('OH');
      Add('OK');
      Add('OR');
      Add('PA');
      Add('RI');
      Add('SC');
      Add('SD');
      Add('TN');
      Add('TX');
      Add('UT');
      Add('VT');
      Add('VA');
      Add('WA');
      Add('WV');
      Add('WI');
      Add('WY');
      Result := Text;
    End;
  Finally
    lst.Free;
  End;
End;

{!~
USPSStateAndTerNames

Returns United States State and Territory Names.
This function returns a string that is the text property of a TStringList.  To
populate a TStringList with this string do something like the following:
  StringList.SetText(PChar(USPSStateAndTerNames));
}
//
Unit Description UnitIndex Master Index
Function USPSStateAndTerNames: String;
Var
  lst : TStringList;
Begin
  lst := TStringList.Create();
  Try
    With lst Do
    Begin
      Clear;
      Add('ALABAMA');
      Add('ALASKA');
      Add('AMERICAN SAMOA');
      Add('ARIZONA');
      Add('ARKANSAS');
      Add('CALIFORNIA');
      Add('COLORADO');
      Add('CONNECTICUT');
      Add('DELAWARE');
      Add('DISTRICT OF COLUMBIA');
      Add('FEDERATED STATES OF MICRONESIA');
      Add('FLORIDA');
      Add('GEORGIA');
      Add('GUAM');
      Add('HAWAII');
      Add('IDAHO');
      Add('ILLINOIS');
      Add('INDIANA');
      Add('IOWA');
      Add('KANSAS');
      Add('KENTUCKY');
      Add('LOUISIANA');
      Add('MAINE');
      Add('MARSHALL ISLANDS');
      Add('MARYLAND');
      Add('MASSACHUSETTS');
      Add('MICHIGAN');
      Add('MINNESOTA');
      Add('MISSISSIPPI');
      Add('MISSOURI');
      Add('MONTANA');
      Add('NEBRASKA');
      Add('NEVADA');
      Add('NEW HAMPSHIRE');
      Add('NEW JERSEY');
      Add('NEW MEXICO');
      Add('NEW YORK');
      Add('NORTH CAROLINA');
      Add('NORTH DAKOTA');
      Add('NORTHERN MARIANA ISLANDS');
      Add('OHIO');
      Add('OKLAHOMA');
      Add('OREGON');
      Add('PALAU');
      Add('PENNSYLVANIA');
      Add('PUERTO RICO');
      Add('RHODE ISLAND');
      Add('SOUTH CAROLINA');
      Add('SOUTH DAKOTA');
      Add('TENNESSEE');
      Add('TEXAS');
      Add('UTAH');
      Add('VERMONT');
      Add('VIRGIN ISLANDS');
      Add('VIRGINIA');
      Add('WASHINGTON');
      Add('WEST VIRGINIA');
      Add('WISCONSIN');
      Add('WYOMING');
      Result := Text;
    End;
  Finally
    lst.Free;
  End;
End;

{!~
USPSStateAndTerAbbrs

Returns United States State and Territory Abbreviations.
This function returns a string that is the text property of a TStringList.  To
populate a TStringList with this string do something like the following:
  StringList.SetText(PChar(USPSStateAndTerAbbrs));
}
//
Unit Description UnitIndex Master Index
Function USPSStateAndTerAbbrs: String;
Var
  lst : TStringList;
Begin
  lst := TStringList.Create();
  Try
    With lst Do
    Begin
      Clear;
      Add('AL');
      Add('AK');
      Add('AS');
      Add('AZ');
      Add('AR');
      Add('CA');
      Add('CO');
      Add('CT');
      Add('DE');
      Add('DC');
      Add('FM');
      Add('FL');
      Add('GA');
      Add('GU');
      Add('HI');
      Add('ID');
      Add('IL');
      Add('IN');
      Add('IA');
      Add('KS');
      Add('KY');
      Add('LA');
      Add('ME');
      Add('MH');
      Add('MD');
      Add('MA');
      Add('MI');
      Add('MN');
      Add('MS');
      Add('MO');
      Add('MT');
      Add('NE');
      Add('NV');
      Add('NH');
      Add('NJ');
      Add('NM');
      Add('NY');
      Add('NC');
      Add('ND');
      Add('MP');
      Add('OH');
      Add('OK');
      Add('OR');
      Add('PW');
      Add('PA');
      Add('PR');
      Add('RI');
      Add('SC');
      Add('SD');
      Add('TN');
      Add('TX');
      Add('UT');
      Add('VT');
      Add('VI');
      Add('VA');
      Add('WA');
      Add('WV');
      Add('WI');
      Add('WY');
      Result := Text;
    End;
  Finally
    lst.Free;
  End;
End;

//
Unit Description UnitIndex Master Index
Function TrimLeftFast(sg : String): String;
Begin
  Result   := sg;
  If Result = '' Then exit;
  While Copy(Result,1,1) = ' ' Do
  Begin
    Result := Copy(Result,2,Length(Result)-1);
  End;
End;

//
Unit Description UnitIndex Master Index
Function TrimRightFast(sg : String): String;
Begin
  Result   := sg;
  If Result = '' Then exit;
  While Copy(Result,Length(Result),1) = ' ' Do
  Begin
    Result := Copy(Result,1,Length(Result)-1);
  End;
End;

//
Unit Description UnitIndex Master Index
Function TrimFast(sg : String): String;
Begin
  Result := sg;
  Result := TrimLeftFast(Result);
  Result := TrimRightFast(Result);
End;

//
Unit Description UnitIndex Master Index
Function StringListSubtractBfromAtoC(A,B: TStringList;out C: TStringList): String;
Var
  i       : Integer;
  inIndex : Integer;
Begin
  Result:='';
  Try
    C.Clear;
    C.SetText(PChar(A.Text));
    For i:=0 To b.Count-1 Do
    Begin
      inIndex:=C.IndexOf(b[i]);
      If inIndex<>-1 Then c.Delete(inIndex);
    End;
    Result:=c.Text;
  Except
  End;
End;

//
Unit Description UnitIndex Master Index
Function StrListSubtractBfromAtoC(A,B: String;out C: String): String;
Var
  lstA : TStringlist;
  lstB : TStringlist;
  lstC : TStringlist;
Begin
  Result:='';
  Try
    lstA := TStringlist.Create();
    lstB := TStringlist.Create();
    lstC := TStringlist.Create();
    Try
      lstA.Duplicates:=dupIgnore;
      lstB.Duplicates:=dupIgnore;
      lstC.Duplicates:=dupIgnore;
      lstA.Sorted:=True;
      lstB.Sorted:=True;
      lstC.Sorted:=True;
      //lstA.SetText(PAnsiChar(A));
      lstA.SetText(PWideChar(A));
      lstB.SetText(PWideChar(B));
      lstC.Clear;
      Result:=StringListSubtractBfromAtoC(lstA,lstB,lstC);
      C:=Result;
    Finally
      FreeAndNil(lstA);
      FreeAndNil(lstB);
      FreeAndNil(lstC);
    End;
  Except
  End;
End;

//
Unit Description UnitIndex Master Index
Function StringListCommonAandBtoC(A,B: TStringList;out C: TStringList): String;
Var
  i       : Integer;
  inIndex : Integer;
Begin
  Result:='';
  Try
    //sgNew   := '';
    C.Clear;
    //C.SetText(PChar(A.Text));
    For i:=0 To b.Count-1 Do
    Begin
      inIndex:=A.IndexOf(B[i]);
      //If inIndex=-1 Then c.Delete(inIndex);
      //If inIndex<>-1 Then sgNew:=sgNew+b[i]+#13+#10;
      If inIndex<>-1 Then
      Begin
        C.Append(b[i]);
        If b.Objects[i]<>nil Then C.Objects[C.Count-1]:=b.Objects[i];
        //sgNew:=sgNew+b[i]+#13+#10;
      End;
    End;
    //C.SetText(PAnsiChar(sgNew));
    Result:=C.Text;
  Except
  End;
End;

//
Unit Description UnitIndex Master Index
Function StrListCommonAandBtoC(A,B: String;out C: String): String;
Var
  lstA : TStringlist;
  lstB : TStringlist;
  lstC : TStringlist;
Begin
  Result:='';
  Try
    lstA := TStringlist.Create();
    lstB := TStringlist.Create();
    lstC := TStringlist.Create();
    Try
      lstA.Duplicates:=dupIgnore;
      lstB.Duplicates:=dupIgnore;
      lstC.Duplicates:=dupIgnore;
      lstA.Sorted:=True;
      lstB.Sorted:=True;
      lstC.Sorted:=True;
      lstA.SetText(PWideChar(A));
      lstB.SetText(PWideChar(B));
      lstC.Clear;
      Result:=StringListCommonAandBtoC(lstA,lstB,lstC);
      C:=Result;
    Finally
      FreeAndNil(lstA);
      FreeAndNil(lstB);
      FreeAndNil(lstC);
    End;
  Except
  End;
End;

End.


//