function Trim(S)
  // Trim white space from the beginning and/or end of string S.
  { return S.replace(/^\s+|\s+$/g,'');
  }; // Trim()

function CharCount(C,S)
  // Count the number of characters C in string S.
  { var n = 0;
    for (var i=0; i<S.length; i++)
      { if (S[i]==C)
          { n++
          };
      };
    return n;
  }; // CharCount()

function EncodeASQ(S)
  // Encode ampersands (&) and single-quotes (')
  { var R1 = /&/g;
    var R2 = /'/g;
    return (S.replace(R1,'%26')).replace(R2,'%27');
  }; // EncodeASQ()

function NoCommas(S)
  // Remove commas from sting S. Intended use is to remove commas from string-represented numeric values.
  { var R = /,/g
    return S.replace(R,'');
  }; // NoCommas()

function AddCommas(S)
  // Insert commas in string S. Intended use is to add commas to string-representations of numeric values.
  { S += '';
    N = S.split('.');
    N1 = N[0];
    N2 = N.length > 1 ? '.' + N[1] : '';
    var R = /(\d+)(\d{3})/;
    while (R.test(N1))
      { N1 = N1.replace(R,'$1'+','+'$2');
      }
    return N1 + N2;
  }; // AddCommas()

function ValidPhoneNumFormat(S)
  // Validate that string S is an empty string or that it represents a U.S. phone number.
  {  var R = /^[\\(]{0,1}([0-9]){3}[\\)]{0,1}[ ]?([^0-1]){1}([0-9]){2}[ ]?[-]?[ ]?([0-9]){4}[ ]*((x){0,1}([0-9]){1,5}){0,1}$/;  // SOURCE: Bill Anderson, http://regexlib.com/
     return (S=='') || R.test(S);
  }; // ValidPhoneNumFormat()

function ValidEmailFormat(S)
  // Validate basic email construct as contained in string S. Invalid conditions tested include:
  //   - No '@' character
  //   - The '@' character in the first-character position
  //   - More than one '@' character
  //   - No '.' character
  //   - The '.' character in the last-character position
  //   - The '@' character following the last '.' character in string S
  { var v = true;  // Assumed Valid
    var PosAT = S.indexOf('@');
    var NumAT = CharCount('@',S);
    var PosDOT = S.indexOf('.');
    var PosDOTLast = S.lastIndexOf('.');
    if ((PosAT==-1) || (PosAT==0) || (NumAT>1) || (PosDOT==-1) || (PosDOTLast==S.length-1) || (PosAT>PosDOTLast))
      { v = false;  // Determined Invalid
      };
    return v;
  }; // ValidEmailFormat()

function ValidZIPCodeFormat(S)
  // Validate ZIP code construct as contained in string S. Only a five-digit ZIP code and a five-digit
  // ZIP code followed by a hyphen and four additional digits are permitted.
  { var R1 = /^\d{5}$/;        // 55123
    var R2 = /^\d{5}-\d{4}$/;  // 55123-4567
    return (R1.test(S) || R2.test(S));
  }; // ValidZIPCodeFormat()

function ValidFYFormat(S)
  // Validate Fiscal Year (FY) format as contained in string S. Only an empty string, or YYYY and YYYY-YYYY
  // formats are permitted.
  { var R1 = /^\d{4}$/;        // YYYY
    var R2 = /^\d{4}-\d{4}$/;  // YYYY-YYYY
    return ((S=='') || R1.test(S) || R2.test(S));
  }; // ValidFYFormat()

function ValidPOSNumber(S)
  // Validate that string S is an empty string (effectively equal to zero) or represents a positive
  // integer or a floating-point number. The only known flaw in the regular expression R is that digit
  // group separators (commas), when used, are not required in every appropriate location in S.
  { var R = /^(?:0|(?:[1-9][0-9]{0,2}(?:,?[0-9]{3})*))(?:\.[0-9]{1,2})?$/;
    return ((S=='') || (R.test(S)));
  } // ValidPOSNumber()

function ValidPOSInteger(S)
  // Validate that string S is an empty string (effectively equal to zero) or represents a positive integer.
  // The only known flaw in the regular expression R is that digit group separators (commas), when used,
  // are not required in every appropriate location in S.
  { var R = /^(?:0|(?:[1-9][0-9]{0,2}(?:,?[0-9]{3})*))$/;
    return ((S=='') || (R.test(S)));
  } // ValidPOSInteger()

function GetRadioLabel(R)
  // Return the <label> text L associated with the selected radio button R[i] within a given radio group R.
  { var L = '';
    for (var i=0; i<R.length; i++)
      { if (R[i].checked)
          { var L = document.getElementById('lab'+R[i].id).innerHTML;
          }
      };
    return L
  } // GetRadioLabel

function ToggleInputText(B,E)
  // Given Boolean B, toggle the ability of element E to accept input.
  { if (B)
      { E.disabled = false;
      }
    else
      { E.disabled = true;
        E.value = '';
      };
  }; // ToggleInputText()

function ToggleInputCheckbox(B,E)
  // Given Boolean B, toggle the ability of element E to accept input.
  { if (B)
      { E.disabled = false;
      }
    else
      { E.disabled = true;
        E.checked = false;
      };
  }; // ToggleInputCheckbox()

function DisableEdits(N,B)
  // Given element id N of parent P, set disable property of all <input>, <textarea>, and <select>
  // child elements E to boolean B.
  { var P = document.getElementById(N);
    var E = P.getElementsByTagName('input');
    for (var i=0; i<E.length; i++)
      { E[i].disabled = B;
      };
    var E = P.getElementsByTagName('Textarea');
    for (var i=0; i<E.length; i++)
      { E[i].disabled = B;
      };
    var E = P.getElementsByTagName('select');
    for (var i=0; i<E.length; i++)
      { E[i].disabled = B;
      };
  }; // DisableEdits()

function ClearEdits(N)
  // Given element id N of parent P, clear all <input>, <textarea>, and <select> child elements E. Note
  // that elements are cleared only if they do not belong to the Persist class.
  { var P = document.getElementById(N);
    var E = P.getElementsByTagName('input');
    for (var i=0; i<E.length; i++)
      { if (E[i].className.indexOf('Persist')<0)
          { E[i].value = '';       // Text
            E[i].checked = false;  // Checkbox
          };
      };
    var E = P.getElementsByTagName('Textarea');
    for (var i=0; i<E.length; i++)
      { if (E[i].className.indexOf('Persist')<0)
          { E[i].value = '';
          };
      };
    var E = P.getElementsByTagName('select');
    for (var i=0; i<E.length; i++)
      { if (E[i].className.indexOf('Persist')<0)
          { E[i].selectedIndex = -1;
          };
      };
  }; // ClearEdits()

function ToggleDisplay(E)
  // Toggle the display of block element E.
  { E.style.display = (E.style.display=='none') ? 'block' : 'none';
  }; // ToggleDisplay()

function ToggleECB(I,N)
  // Given an <img> element I acting as an Expand-Collapse Button (ECB), toggle the ECB, depending on the display state of the
  // associated element E with name N. Currently, the <img> src attributes are pre-determined for the two possible states.
  { // Toggle Display
    var E = document.getElementById(N);
    ToggleDisplay(E);
    // Toggle Expand-Collapse Button
    var ECIPlus = "/images/Plus.jpg";
    var ECIMinus = '/images/Minus.jpg';
    I.src = (E.style.display=='none') ? ECIPlus : ECIMinus;
  } // ToggleECB()
