<!--
  /***********************************************************************************************************/
  /* Erase the input fields value.  This input field mite have onchange event, so assign *** then "" string. */
  /* If this is a select box, all options will be deleted.  Will put this object in focus.                   */
  /***********************************************************************************************************/
  function eraseObjVal(obj)
  {
    if((obj.type == "text") || (obj.type == "textarea"))
    {
      obj.value = "***";
      obj.value = "";
      obj.focus();
    }
    else if(obj.type == "select-one")
    {
      while(obj.hasChildNodes()) //remove all the options for the previous chosen customer
        obj.removeChild(obj.lastChild);
    }
    else if(obj.type == "hidden")
      obj.value = "";
  }

  /********************************************************************************************/
  /* Function check this is number and it is negative                                         */
  /********************************************************************************************/
  function isNeg(val)
  {
    var ValidChars = "0123456789.";
    var Char;
    val = val.toString(); //need to convert number to string first
    for (i = 0; i < val.length; i++)
    {
      Char = val.charAt(i);
      if(ValidChars.indexOf(Char) == -1)  return true;
    }
  }

  /********************************************************************************************/
  /* Function jumpNext and chkFieldDt are used in conjuction with php function proj_dt_entry  */
  /********************************************************************************************/
  function jumpNext(obj, fdNm, rowNo) //jump to the next field
  {
    if(obj.value.length == 2) //if user entered the second digit, jump to the next field
    { 
      var objName = obj.name.split("["); 
      var index   = parseInt(objName[1])+1;

      //if user re-enter the dd/m, and the mm && yyyy is not empty, automatically check for the date
      if((obj.form.elements["dt[1]["+fdNm+"]["+rowNo+"]"].value.length != 0) &&
         (obj.form.elements["dt[2]["+fdNm+"]["+rowNo+"]"].value.length != 0))
      {
        chkFieldDt(obj, fdNm, rowNo, index);
        return;
      }

      obj.form.elements["dt["+index+"]["+fdNm+"]["+rowNo+"]"].focus(); //set the next field onfocus
    }
  }

  /********************************************************************************************/
  /* Check the date entered, if not valid, alert user and erase the value.  At the same time, */
  /* put dd onfocus                                                                           */
  /********************************************************************************************/
  function chkFieldDt(obj, fdNm, rowNo)
  {
    var counter = 0;
    for(var i=0; i<3; i++)
    {
      //if dd and mm field contains 1 digit, e.g. 8 instead of 08, pad the string with a zero
      var val = trimString(obj.form.elements["dt["+i+"]["+fdNm+"]["+rowNo+"]"].value);
      if((val.length == 1) && (i < 2))
        obj.form.elements["dt["+i+"]["+fdNm+"]["+rowNo+"]"].value = "0"+val;

      if(val.length == 0)
        counter++;
    }

    if(counter >= 1) //the dd,mm and yyyy are empty, so erase the projDt value if exist and return
    {
      obj.form.elements["projDt["+fdNm+"]["+rowNo+"]"].value = ""; //erase the value assigned to projDt
      return;
    }
    else
      var dt = obj.form.elements["dt[0]["+fdNm+"]["+rowNo+"]"].value+"/"+obj.form.elements["dt[1]["+fdNm+"]["+rowNo+"]"].value+"/"+obj.form.elements["dt[2]["+fdNm+"]["+rowNo+"]"].value;

    if(isDate(dt)) //the date is valid, hence, put it into the hidden field so can retrieve after form submission
      obj.form.elements["projDt["+fdNm+"]["+rowNo+"]"].value = obj.form.elements["dt[2]["+fdNm+"]["+rowNo+"]"].value+"-"+obj.form.elements["dt[1]["+fdNm+"]["+rowNo+"]"].value+"-"+obj.form.elements["dt[0]["+fdNm+"]["+rowNo+"]"].value;
    else //the date is not valid
    {
      alert("The date you have entered, "+dt+" is not valid.\nPlease fill in a valid date.");
      obj.form.elements["projDt["+fdNm+"]["+rowNo+"]"].value = ""; //erase the value assigned to projDt

      for(var j=0; j<3; j++)
      {
        obj.form.elements["dt["+j+"]["+fdNm+"]["+rowNo+"]"].value = ""; //erase the dd/mm/yyyy value entered
        obj.form.elements["dt[0]["+fdNm+"]["+rowNo+"]"].focus();  //set dd to focus
      }

      return;
    }

    if(arguments.length > 3)  //this is from function jumpNext of which user re-enter the dd/mm so jump to next field after checking date
      obj.form.elements["dt["+arguments[3]+"]["+fdNm+"]["+rowNo+"]"].focus(); //set the next field onfocus

  } //end of function

  /********************************************************************************************/
  /* Compare 2 dates and make sure the ToDt is > FromDt (from and to dates are in yyyy-mm-dd) */
  /********************************************************************************************/
  function compareDt(fromDt, toDt)
  {
    //change yyyy-mm-dd format to yyyymmdd
    var fromDate = fromDt.substr(0, 4)+fromDt.substr(5, 2)+fromDt.substr(8, 2);
    var toDate   = toDt.substr(0, 4)+toDt.substr(5, 2)+toDt.substr(8, 2);

    if(toDate < fromDate)  return false;

    return true;
  }

  /************************************************************************************************/
  /* This function will encode non-alphanumeric symbol, including + into % string representation  */
  /************************************************************************************************/
  function encodeUrl(sStr)
  {
    return escape(sStr).
             replace(/\+/g, '%2B').
                replace(/\"/g,'%22').
                   replace(/\'/g, '%27');
  }

  //**************************************************
  // Toggle the display of <div> to hidden or visible
  // Written by H.H.Ng
  // Date: 23/Aug/04
  //**************************************************
  function exMenu(tName)
  {
     tMenu = document.all[tName].style;
     tMenu.display = (tMenu.display == 'none') ?  "block" : "none";
  }

  //*******************************************************
  // Focus the pointer to the field that contains an error
  // Written by H.H.Ng
  // Date: 23/Aug/04, rev1: 8/Jun/05
  //*******************************************************
  function focusElement(formName, elemName)
  {
     var elem = document.forms[formName].elements[elemName];
     elem.focus();

     //if this is not a select box, we highlight the entry in the box
     if((elem.type != "select-one") && (elem.type != "select-multiple"))
       elem.select();
  }

  //*******************************************************
  // Trim the string of leading and trailing spaces
  // Written by H.H.Ng
  // Date: 25/Jan/05
  //*******************************************************
  function trimString(str)
  {
    while((str.charAt(0) == ' ') || (str.charAt(0) == '\t'))
      str = str.substring(1);

    while((str.charAt(str.length - 1) == ' ') || (str.charAt(str.length - 1) == '\t'))
      str = str.substring(0, str.length - 1);

    return str;
  }

  //*************************************
  // Check if the field is empty
  // Written by H.H.Ng
  // Date: 23/Aug/04, rev1: 25/Jan/05
  //*************************************
  function isNotEmpty(fieldObj)
  {
    var str = trimString(fieldObj.value);

    if((str == null) || (str.length == 0))
    {
      //if there is only one argument, we focus on the object.
      //if there are more than one argument, it means user does not want to focus on the element
      if(arguments.length == 1)
        fieldObj.focus();

      return false;
    }

    return true;
  }

  //**********************************************************************
  // Check if the field contains a valid number with max 1 decimal places
  // Written by H.H.Ng
  // Date: 23/Aug/04, rev01:17/Feb/05
  //**********************************************************************
  function isNumber(elem)
  {
     var str = elem.value;
     var oneDecimal = false;
     var oneChar = 0;

     if(str.substring(0,1) == "-") //if this is possibly a negative number, we take the numerals for verification only
       str = str.substring(1, str.length);

     str = str.toString();

     for(var i=0; i<str.length; i++)
     {
        oneChar = str.charAt(i).charCodeAt(0);

        if(oneChar == 46)
        {
            if(!oneDecimal)
            {
                oneDecimal = true;
                continue;
            }
            else
            {
                alert("Only one decimal is allowed.");
                return false;
            }
        }

        if((oneChar < 48) || (oneChar > 57))
        {
           alert("Enter only numbers.");
           return false;
        }
     }

     return true;
  }

  //**********************************************************************
  // Check if the field contains a valid integer
  // Written by H.H.Ng
  // Date: 03/Feb/05
  //**********************************************************************
  function isInteger(elem)
  {
    var str = elem.value;
    var oneChar = 0;

    str = str.toString();

    for(var i=0; i<str.length; i++)
    {
      oneChar = str.charAt(i).charCodeAt(0);

      if (oneChar > 31 && (oneChar < 48 || oneChar > 57))
      {
        setTimeout("focusElement('" + elem.form.name + "', '" + elem.name + "')", 0);
        alert("Enter integers only in this field.");
        return false;
      }
    }

    return true;
  }

  //**********************************************************************
  // Check if the field contains a valid date
  // Written by H.H.Ng
  // Date: 12/Aug/05
  //**********************************************************************
    var dtCh    = "/";
    var minYear = 0000;
    var maxYear = 9999;

  function isDate(dtStr)
  {
    var daysInMonth = DaysArray(12);
    var pos1        = dtStr.indexOf(dtCh);
    var pos2        = dtStr.indexOf(dtCh,pos1+1);
    var strDay      = dtStr.substring(0,pos1);
    var strMonth    = dtStr.substring(pos1+1,pos2);
    var strYear     = dtStr.substring(pos2+1);

    strYr = strYear;

    if(strDay.charAt(0)=="0" && strDay.length>1)
      strDay=strDay.substring(1);

    if(strMonth.charAt(0)=="0" && strMonth.length>1)
      strMonth=strMonth.substring(1);

    for (var i = 1; i <= 3; i++)
    {
      if (strYr.charAt(0)=="0" && strYr.length>1)
        strYr=strYr.substring(1);
    }

    month = parseInt(strMonth);
    day   = parseInt(strDay);
    year  = parseInt(strYr);

    if(pos1==-1 || pos2==-1) //date format is not dd/mm/yyyy
      return false;

    if(strMonth.length<1 || month<1 || month>12) //month is invalid
      return false;

    if(strDay.length<1 || day<1 || day>31 || (month==2 && day>daysInFebruary(year)) || day > daysInMonth[month]) //day is invalid
      return false;

    if(strYear.length != 4 || year==0 || year<minYear || year>maxYear) //year is not 4 digits
      return false;

    if (dtStr.indexOf(dtCh,pos2+1)!=-1 || isDtInt(stripCharsInBag(dtStr, dtCh))==false) //alphabets were provided
      return false;

    return true;
  }

  function isDtInt(s)
  {
    var i;

      for (i = 0; i < s.length; i++)
      {
        // Check that current character is number.
        var c = s.charAt(i);

        if (((c < "0") || (c > "9")))
          return false;
      }

      // All characters are numbers.
      return true;
  }

  function stripCharsInBag(s, bag)
  {
    var i;
    var returnString = "";

    // Search through string's characters one by one.
    // If character is not in bag, append to returnString.
    for(i=0; i<s.length; i++)
    {
      var c = s.charAt(i);

      if(bag.indexOf(c) == -1)
        returnString += c;
    }

    return returnString;
  }

  function daysInFebruary(year)
  {
    // February has 29 days in any year evenly divisible by four,
    // EXCEPT for centurial years which are not also divisible by 400.
    return (((year % 4 == 0) && ( (!(year % 100 == 0)) || (year % 400 == 0))) ? 29 : 28 );
  }

  function DaysArray(n)
  {
    for(var i = 1; i <= n; i++)
    {
      this[i] = 31;

      if (i==4 || i==6 || i==9 || i==11)
       this[i] = 30;

      if (i==2)
        this[i] = 29;
     }

     return this;
  }

  //***************************************************************************
  // Calculate the days difference from the FROM date and then get the TO date
  // Written by H.H.Ng
  // Date: 23/Aug/04, rev1:16/Feb/05
  //**************************************************************************
  function calGetToDt(formDt, oldInDt, oldOutDt)
  {
     var theFormDate = new Date();
     var theOldDate  = new Date();
     var theOutDate  = new Date();

     theFormDate = convertDate(formDt);
     theOldDate  = convertDate(oldInDt);
     theOutDate  = convertDate(oldOutDt);

     // The number of milliseconds in one day
     var ONE_DAY = 1000 * 60 * 60 * 24;

     // Convert both dates to milliseconds
     var date1_ms = theFormDate.getTime();
     var date2_ms = theOldDate.getTime();

     // Calculate the difference in milliseconds
     var real_diff_ms = date1_ms - date2_ms;

     var difference_ms = Math.abs(date1_ms - date2_ms);

     // Convert back to days and return
     numDaysDiff = Math.round(difference_ms/ONE_DAY);

     if(real_diff_ms>0)
       theOutDate.setDate(theOutDate.getDate() + numDaysDiff);
     else
       theOutDate.setDate(theOutDate.getDate() - numDaysDiff);

     return theOutDate.getYear() + "-" + pad(theOutDate.getMonth()+1) + "-" + pad(theOutDate.getDate());
  }

  //***************************************************************************
  // Formats the date to something that MySQL understands
  // Written by H.H.Ng
  // Date: 28/June/05
  //**************************************************************************
  function getSQLDt(dt)
  {
     var theDate = new Date();

     theDate = convertDate(dt);

     if(theDate == false)
       return false;

     return theDate.getYear() + "-" + pad(theDate.getMonth()+1) + "-" + pad(theDate.getDate());
  }

  //***********************************
  // Formats the date to dd/mmm/yy
  // Written by H.H.Ng
  // Date: 12/Aug/05
  //***********************************
  function getUKDt(dt)
  {
    var UKDate  = dt;
    var str = trimString(dt);

    if((str == null) || (str.length == 0))
       return "";

    if ((n = str.indexOf("/")) == -1)
      UKDate = str.substr(0, 2) + "/" + str.substr(2, 2) + "/" + str.substr(4, 4);

     var theDate = new Date();
     var arrMMM  = new Array("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec");

     theDate = convertDate(UKDate);

     if(theDate == false)
       return false;

     return pad(theDate.getDate()) + "/" + arrMMM[theDate.getMonth()] + "/" + (theDate.getYear()+"");
  }

  //**********************************************************************
  // Converts a date into the format that Javascript comprehends
  // This is a utility function for the calDaysDiff, getToDate and getSQLDt
  // Types of dates that gets converted (these are the UK standards):
  // d/m/yyyy, d/mm/yyyy, d/mmm/yyyy, dd/m/yyyy, dd/mm/yyyy, dd/mmm/yyyy
  // d/m/yy, d/mm/yy, d/mmm/yy, dd/m/yy, dd/mm/yy, dd/mmm/yy
  // d/m, d/mm, d/mmm, dd/m, dd/mm, dd/mmm
  // Written by H.H.Ng
  // Date: 12/Aug/05
  //**********************************************************************
  function convertDate(inDate)
  {
     dateComponent = inDate.split("/");

     if (dateComponent.length == 1)
     {
        dateComponent = inDate.split("-");

        if (dateComponent.length == 1)
        {
           dateComponent = inDate.split(".");

           if (dateComponent.length == 1)
           {
              alert('Your date input is not valid.');
              return false;
           }
        }
     }

     var inDay = dateComponent[0];
     var inMth = dateComponent[1];
     var inYr  = dateComponent[2];

     //set the format of day
     inDay = (inDay.length == 1) ? "0" + inDay : inDay;

     //set the year and it's format
     if(typeof inYr == "undefined") //if this is in the form d/m, d/mm, d/mmm, dd/m, dd/mm, dd/mmm, we set the year to current year
     {
        var today = new Date();
        var inYr  = today.getYear();
     }
     else
       inYr  = (inYr.length  == 2) ? "20" + inYr : inYr ; //set format to yyyy

     //set the format of month
     if(isNaN(inMth)) //month is in the format of Aug so we use the string method
       var theDate = new Date(inMth + " " + inDay + ", " + inYr)
     else //this is a number, means date is in the form d/m or dd/mm
     {
       //check if this is a valid date first
       if(isDate(inDay + "/" + inMth + "/" + inYr) == false)
       {
         alert('Your date input is not valid.');
         return false;
       }

       inMth = inMth - 1;
       inMth = (inMth.length == 1) ? "0" + inMth : inMth;

       var theDate = new Date(inYr, inMth, inDay);
     }

     return theDate;
  }

  //**********************************************************************
  // Converts a date into the format that Javascript comprehends
  // This is a utility function for the calDaysDiff and getToDate.
  // This is used for dates that follow the JP way of mm/dd or yyyy/mm/dd
  // Written by H.H.Ng
  // Date: 23/Aug/04
  //**********************************************************************
  function convertDateJP(inDate)
  {
     dateComponent = inDate.split("/");

     if (dateComponent.length == 1)
     {
        dateComponent = inDate.split("-");

        if (dateComponent.length == 1)
        {
           dateComponent = inDate.split(".");

           if (dateComponent.length == 1)
           {
              alert('Your date input is not valid.');
              return false;
           }
        }
     }

     if(dateComponent.length == 2)
     {
        today     = new Date();
        var inMth = dateComponent[0];
        var inDay = dateComponent[1];
        var inYr  = today.getYear();
     }
     else if(dateComponent.length == 3)
     {
        if(dateComponent[2].length == 4) //if it is like 05-05-2005, the last component will be the year
        {
          var inDay = dateComponent[0];
          var inMth = dateComponent[1];
          var inYr  = dateComponent[2];
        }
        else
        {
          var inYr  = dateComponent[0];
          var inMth = dateComponent[1];
          var inDay = dateComponent[2];
        }
     }

     inMth = inMth -1;

     inMth = (inMth.length == 1) ? "0" + inMth : inMth;
     inDay = (inDay.length == 1) ? "0" + inDay : inDay;
     inYr  = (inYr.length  == 2) ? "20" + inYr : inYr ;

     var theDate = new Date(inYr, inMth, inDay);

     return theDate;
  }

  //*****************************************************************************************
  // Calculate the TO date given the FROM date and the interval between the FROM and TO date
  // Written by H.H.Ng
  // Date: 23/Aug/04, rev1:16/Feb/05
  //*****************************************************************************************
  function getToDate(theInDt, numOfDays)
  {
     num = new Number(numOfDays);

     var inDate  = theInDt;
     var theDate = new Date();

     theDate = convertDate(inDate);

     if(theDate == false)
       return "";

     theDate.setDate(theDate.getDate() + num);

     return theDate.getYear() + "-" + pad(theDate.getMonth() + 1) + "-" + pad(theDate.getDate());
  }

  //*****************************************************************************************
  // To pad a number smaller than 10 with a leading zero (used for getToDate)
  // Written by H.H.Ng
  // Date: 09/May/05
  //*****************************************************************************************
  function pad(int)
  {
    return int = (int < 10) ? '0' + int : int;
  }

  //******************************************************************************
  // Round a floating point number to only 2 decimal places
  // NB: need to add 0.0001 because if not 2.3 will become 2.29 under it
  // Written by H.H.Ng
  // Date: 03/May/05
  //******************************************************************************
  function roundDecimal(val)
  {
    var num = new Number(val);
    var amt = new Number();

    amt = Math.round((num+0.0001)*100)/100;

    return parseFloat(amt);
  }

  function decimalCut4(val)
  {
    var num = new Number(val);
    var amt = new Number();

    amt = Math.floor((num+0.000001)*10000)/10000;

    return parseFloat(amt);
  }

  //****************************************
  // Dialog box pop up for combo boxes
  // Written by H.H.Ng
  // Date: 19/Jul/05
  //****************************************
  var glDWin     = null;                   //global variable to keep the status of dialog box window
  var glCurField = null;                   //global variable to indicate if this is the current field
  var glMainWind = window.dialogArguments; //global variable to keep the arguments that are sent to the dialog box window
  var glArrList  = new Array();            //global variable to keep all the codes and names in a hash table for easy jumping to

  //to open the dialog window with the given sURL
  function openDialog(obj, sURL)
  {
    var myObject  = new Object(obj); //initialise an object to pass arguments to the dialog window
    myObject.wind = window;          //initialise the window variable so as to access the global variables from the dialog window

    //if user is not on the same text field, we reload the dialog box again
    if(obj.name != glCurField)
    {
      glCurField = obj.name; //set the current textfield to this object's name

      if(glDWin != null) //if a dialog box has been opened, we closed it first before opening it
        glDWin.close();

      //open the modal dialog box;
      //if user do not want it to be in the centre, set dialogLeft:400px; dialogTop:200px; center:no;
      glDWin = window.showModalDialog(sURL, myObject, "dialogWidth:703px; dialogHeight:400px; center:yes; help:no; resizable:yes; status:no;");
    }
    else //user is still on the same textfield, so we just scroll the opened dialog box to the relevant spot
      glDWin.newXY(obj.value);

    return true;
  }

  //to be called onload and by the parent window to scroll to the position of the starting alphabets
  function newXY(str)
  { 
    
    for(var i=0; i<glArrList.length; i++)
    {
      var searchOn = (document.searchForm.searchField.value == 'cd') ? glArrList[i].cd : glArrList[i].nm;

      //if the name of the link is more than or the same as the user's entry, set the "Yaxis coordinate" to it
      if(searchOn.toUpperCase() >= str.toUpperCase())
      {
        if (document.searchForm.keyIdx != null)
          document.searchForm.keyIdx.value = i;
        
        var Yaxis = (i*21); //21 is determined by trial and error depending on the cellpadding, cellspacing, border and font size
        break; //if we have found the entry, break out of the loop and scroll to the entry
      }
    }

    //set any initial value into the searchValue field
    document.searchForm.searchValue.value = str;

    if(newXY.arguments.length>1) //if this is the first time that newXY is being called,
      document.searchForm.searchValue.select();

    document.searchForm.searchValue.focus();

    //scroll to the desired position in the div
    document.getElementById("listing").scrollTop = Yaxis;
    return true;
  }

  //closing of the dialog box involves resetting the global variables
  function closeWin()
  {
    glMainWind.wind.glDWin     = null;
    glMainWind.wind.glCurField = null;
    window.close();
  }

  //***********************************************************************************
  // Sort table (used for dialog box when user change to a different search category)
  // Written H.H.Ng
  // Date: 03/Oct/05
  //***********************************************************************************
  // Draw table from glArrList of objects
  function drawTable(tbody)
  {
    var tr, td, link, text;
    tbody = document.getElementById(tbody);

    // remove existing rows, if any
    clearTable(tbody);

    // loop through data source
    for(var i = 0; i < glArrList.length; i++)
    {
      //draw the table
      tr   = document.createElement("<tr>");
      td   = document.createElement("<td width='25%' class='borderRightThin' nowrap>");
      link = document.createElement("<a href='#' onclick=\"returnVal("+i+");\">");
      text = document.createTextNode(glArrList[i].cd);
      link.appendChild(text);
      td.appendChild(link);
      tr.appendChild(td);

      td   = document.createElement("<td nowrap>");
      text = document.createTextNode(glArrList[i].nm);
      td.appendChild(text);
      tr.appendChild(td);

      tbody.appendChild(tr);
    }
  }

  // Remove existing table rows
  function clearTable(tbody)
  {
    while(tbody.rows.length > 0)
      tbody.deleteRow(0);
  }

  // Sorting function dispatcher
  function sortTable(obj)
  { 
    //if the array list is empty, we just return
    if(glArrList.length == 0)
      return true;

    //since there is something in the array list, we sort them first and then draw the table again
    if(obj.value == "cd")
      glArrList.sort(sortByCd);
    else //this is a sorting by name
      glArrList.sort(sortByNm);

    drawTable("searchList");
    newXY(obj.form.searchValue.value);
    return false;
  }

  function sortByCd(a, b)
  { 
    ta = a.cd.toLowerCase();
    tb = b.cd.toLowerCase();
    return ((ta < tb) ? -1 : ((ta > tb) ? 1 : 0));
  }

  function sortByNm(a, b)
  {
    ta = a.nm.toLowerCase();
    tb = b.nm.toLowerCase();
    return ((ta < tb) ? -1 : ((ta > tb) ? 1 : 0));
  }

  function sortByNmDesc(a, b)
  {
    ta = a.nm.toLowerCase();
    tb = b.nm.toLowerCase();
    return ((ta < tb) ? 1 : ((ta > tb) ? -1 : 0));
  }

  //for dialog_B062Commodity.php/ dialog_B061Category to sort more than 1 field
  function sortByCdDesc(a, b)
  {
    ta = a.cd.toLowerCase();
    tb = b.cd.toLowerCase();
    return ((ta < tb) ? 1 : ((ta > tb) ? -1 : 0));
  }

  function sortByNm1Asc(a, b)
  {
    ta = a.nm1.toLowerCase();
    tb = b.nm1.toLowerCase();
    return ((ta < tb) ? -1 : ((ta > tb) ? 1 : 0));
  }

  function sortByNm1Desc(a, b)
  {
    ta = a.nm1.toLowerCase();
    tb = b.nm1.toLowerCase();
    return ((ta < tb) ? 1 : ((ta > tb) ? -1 : 0));
  }

  function sortByNm2Asc(a, b)
  {
    ta = a.nm2.toLowerCase();
    tb = b.nm2.toLowerCase();
    return ((ta < tb) ? -1 : ((ta > tb) ? 1 : 0));
  }

  function sortByNm2Desc(a, b)
  {
    ta = a.nm2.toLowerCase();
    tb = b.nm2.toLowerCase();
    return ((ta < tb) ? 1 : ((ta > tb) ? -1 : 0));
  }


  //*****************************************************************************************
  // To highlight and de-highlight a row in a table with an onmouseover and onclick event
  // Written by H.H.Ng
  // Date: 23/Aug/04
  //*****************************************************************************************
  function setPointer(theRow, theRowNum, theAction, theDefaultColor, thePointerColor, theMarkColor)
  {
     var marked_row = new Array; // This array is used to remember mark status of rows in browse mode
     var theCells = null;

     // 1. Pointer and mark feature are disabled or the browser can't get the
     //    row -> exits
     if((thePointerColor == '' && theMarkColor == '') || typeof(theRow.style) == 'undefined')
       return false;

     // 2. Gets the current row and exits if the browser can't get it
     if(typeof(document.getElementsByTagName) != 'undefined')
       theCells = theRow.getElementsByTagName('td');
     else if(typeof(theRow.cells) != 'undefined')
       theCells = theRow.cells;
     else
       return false;

     // 3. Gets the current color...
     var rowCellsCnt  = theCells.length;
     var domDetect    = null;
     var currentColor = null;
     var newColor     = null;

     // 3.1 ... with DOM compatible browsers except Opera that does not return
     //         valid values with "getAttribute"
     if (typeof(window.opera) == 'undefined' && typeof(theCells[0].getAttribute) != 'undefined')
     {
        currentColor = theCells[0].getAttribute('bgcolor');
        domDetect    = true;
     }
     else // 3.2 ... with other browsers
     {
        currentColor = theCells[0].style.backgroundColor;
        domDetect    = false;
     } // end 3

     // 3.3 ... Opera changes colors set via HTML to rgb(r,g,b) format so fix it
     if (currentColor.indexOf("rgb") >= 0)
     {
        var rgbStr    = currentColor.slice(currentColor.indexOf('(') + 1, currentColor.indexOf(')'));
        var rgbValues = rgbStr.split(",");
        var hexChars  = "0123456789ABCDEF";
        currentColor  = "#";

        for (var i = 0; i < 3; i++)
        {
           var v = rgbValues[i].valueOf();
           currentColor += hexChars.charAt(v/16) + hexChars.charAt(v%16);
        }
     }

     // 4. Defines the new color
     // 4.1 Current color is the default one
     if (currentColor == '' || currentColor.toLowerCase() == theDefaultColor.toLowerCase())
     {
        if (theAction == 'over' && thePointerColor != '')
           newColor = thePointerColor;
        else if (theAction == 'click' && theMarkColor != '')
        {
           newColor              = theMarkColor;
           marked_row[theRowNum] = true;
        }
     }
     // 4.1.2 Current color is the pointer one
     else if (currentColor.toLowerCase() == thePointerColor.toLowerCase() &&
             (typeof(marked_row[theRowNum]) == 'undefined' || !marked_row[theRowNum]))
     {
        if (theAction == 'out')
           newColor = theDefaultColor;
        else if (theAction == 'click' && theMarkColor != '')
        {
           newColor              = theMarkColor;
           marked_row[theRowNum] = true;
        }
     }
     // 4.1.3 Current color is the marker one
     else if (currentColor.toLowerCase() == theMarkColor.toLowerCase())
     {
        if (theAction == 'click')
        {
           newColor              = (thePointerColor != '') ? thePointerColor : theDefaultColor;
           marked_row[theRowNum] = (typeof(marked_row[theRowNum]) == 'undefined' || !marked_row[theRowNum])
                                  ? true
                                  : null;
        }
     } // end 4

     // 5. Sets the new color...
     if (newColor)
     {
        var c = null;

        // 5.1 ... with DOM compatible browsers except Opera
        if (domDetect)
          for (c = 0; c < rowCellsCnt; c++)
            theCells[c].setAttribute('bgcolor', newColor, 0);
        else // 5.2 ... with other browsers
          for (c = 0; c < rowCellsCnt; c++)
            theCells[c].style.backgroundColor = newColor;
     } // end 5

    return true;
  } // end of the 'setPointer()' function

  //***********************************************************************
  // Function for setting and deleting and retrieving the value of cookies
  // Written by H.H.Ng
  // Date: 23/Aug/04
  //************************************************************************
  // utility function to retrieve a future expiration date in proper format;
  // pass three integer parameters for the number of days, hours,
  // and minutes from now you want the cookie to expire; all three
  // parameters required, so use zeros where appropriate
  function getExpDate(days, hours, minutes)
  {
     var expDate = new Date();
     if (typeof days == "number" && typeof hours == "number" && typeof minutes == "number")
     {
        expDate.setDate(expDate.getDate() + parseInt(days));
        expDate.setHours(expDate.getHours() + parseInt(hours));
        expDate.setMinutes(expDate.getMinutes() + parseInt(minutes));
        return expDate.toGMTString();
     }
  }

  // utility function called by getCookie()
  function getCookieVal(offset)
  {
     var endstr = document.cookie.indexOf (";", offset);

     if (endstr == -1)
        endstr = document.cookie.length;

     return unescape(document.cookie.substring(offset, endstr));
  }

  // primary function to retrieve cookie by name
  function getCookie(name)
  {
     var arg = name + "=";
     var alen = arg.length;
     var clen = document.cookie.length;
     var i = 0;

     while (i < clen)
     {
        var j = i + alen;

        if (document.cookie.substring(i, j) == arg)
            return getCookieVal(j);

        i = document.cookie.indexOf(" ", i) + 1;

        if (i == 0)
          break;
     }

     return null;
  }

  // store cookie value with optional details as needed
  function setCookie(name, value, expires, path, domain, secure)
  {
     document.cookie = name + "=" + escape (value) +
                       ((expires) ? "; expires=" + expires : "") +
                       ((path)    ? "; path=" + path       : "") +
                       ((domain)  ? "; domain=" + domain   : "") +
                       ((secure)  ? "; secure"             : "");
  }

  // remove the cookie by setting ancient expiration date
  function deleteCookie(name, path, domain)
  {
     if (document.cookie.indexOf(name) != -1)
     {
        document.cookie = name + "=" +
                          ((path)   ? "; path=" + path     : "") +
                          ((domain) ? "; domain=" + domain : "") +
                          "; expires=Thu, 04-Jan-01 00:00:01 GMT";
     }
  }

  ns4 = (document.layers) ? true : false;
  ie4 = (document.all)    ? true : false;

  //set the page that is to be printed to be at "print preview"; added 15/02/05
  function printPreview()
  {
     var OLECMDID = 7;
     /* OLECMDID values:
      * 6 - print
      * 7 - print preview
      * 1 - open window
      * 4 - Save As
     */

     var PROMPT = 1; // 1 PROMPT & 2 DONT PROMPT USER
     var WebBrowser = '<OBJECT ID="WebBrowser1" WIDTH=0 HEIGHT=0 CLASSID="CLSID:8856F961-340A-11D0-A96B-00C04FD705A2"></OBJECT>';

     document.body.insertAdjacentHTML('beforeEnd', WebBrowser);
     WebBrowser1.ExecWB(OLECMDID, PROMPT);
     WebBrowser1.outerHTML = "";
  }

  //bring the cursor to the first form element. this is a user-friendly tool
  function focusFirstElem()
  {
     for (i = 0; i < document.forms[0].elements.length; i++)
     {
        if (((ns4) || (ie4)) && (document.forms[0].elements[i].type != "hidden"))
        {
           document.forms[0].elements[i].focus();
           break;
        }
     }
  }

  //this allows only integers to be entered in a form field. added 02/Feb/05
  function integersOnly(evt)
  {
    evt = (evt) ? evt : event;
    var charCode = (evt.charCode) ? evt.charCode : ((evt.keyCode) ? evt.keyCode : ((evt.which) ? evt.which : 0));

    if (charCode > 31 && (charCode < 48 || charCode > 57))
    {
      alert("Enter integers only in this field.");
      return false;
    }

    return true;
  }

  //**********************************************************************************
  // Set the keypress event to prevent user from submitting the form with ENTER.
  // This function also brings the pointer to the next field when user hits ENTER.
  // Furthermore, when user hits Backspace, when focus is on a select box, a checkbox
  // or radio button, we prevent the browser from going back 1 step in history.
  // Written by H.H.Ng
  // Date: 23/Aug/04, rev1:09/Sep/05
  //**********************************************************************************
  function keyDown(evt)
  {
    evt = (evt) ? evt : event;

    if (ns4) { PKey=evt.which;   el = evt.target.type;        sk = evt.modifiers; }
    if (ie4) { PKey=evt.keyCode; el = evt.srcElement.tagName; sk = evt.shiftKey;  }

    if(evt.srcElement.type) et = evt.srcElement.type;

    if(PKey == "13")
    {
      if (el.toLowerCase() != "textarea")
      {
        //change the keycode to 9, means the Enter now act as Tab key
        //and hence, it doensn't submit the form but jump to next field
        evt.keyCode = 9;
        return;
      }
      else
      {
        if ((ns4) && (sk == '4') || (ie4) && (sk))
        {
          // try to cancel the enter key event
          window.event.cancelBubble = true;
          window.event.returnValue = false;
          return false;
        }
      }
    }
    else if (PKey == "8")
    {
      if (((el.toLowerCase() != 'textarea') && (el.toLowerCase() != 'input')) ||
          ((et && et.toLowerCase() == 'checkbox') || (et && et.toLowerCase() == 'radio')))
      {
        // try to cancel the backspace
        window.event.cancelBubble = true;
        window.event.returnValue = false;
        return false;
      }
    }
  }

  document.onkeydown = keyDown;
  if (ns4) document.captureEvents(Event.KEYDOWN);
-->
