// JavaScript String extensions
String.prototype.startsWith = function(str) { return (this.match('^' + str) == str); }
String.prototype.endsWith   = function(str) { return (this.match(str + '$') == str); }
String.prototype.trim       = function()    { return this.replace(/^\s+|\s+$/g, ''); }
String.prototype.ltrim      = function()    { return this.replace(/^\s+/, '');       }
String.prototype.rtrim      = function()    { return this.replace(/\s+$/, '');       }

// dual submit prevention
function DualSubmitCheck(frmID) {
   var bReturnDefined = (event != undefined) && (event != null) && (event.returnValue != undefined);
   var bOk = (bReturnDefined ? event.returnValue : true);

   if (bOk) {
      var frm = document.forms[0];
      var oSubmitted = frm.attributes['Submitted'];

      if ((oSubmitted != null) && (oSubmitted.value == 'True')) {
         bOk = false;
         alert('Already submitted.');
      }
      else if ((typeof(Page_IsValid) == 'undefined') || Page_IsValid) {
         //bOk = true;
         frm.attributes['Submitted'].value = 'True';
      }
   }

   if (bReturnDefined) event.returnValue = bOk;
   return bOk;
}

// replace control references with their current values
function EvaluateControlReferences(vsStr, vsDefault) {
   var bAllBlankValues = true;
   var i1 = vsStr.indexOf('{');
   var i2;
   var sControlID;
   var sControlValue;
   var ctl;

   while (i1 >= 0) {
      i2 = vsStr.indexOf('}', i1 + 1);

      if (i2 >= i1) {
         sControlID = vsStr.substring(i1 + 1, i2);
         sControlValue = '';

         if (sControlID.substring(0, 1) == '?') {
            // skip any references to database query variables
            i1 = vsStr.indexOf('{', i1 + 1);
         }
         else {
            ctl = document.getElementById(sControlID.split(':').join('_'));
            var sIntegraType = GetAttribute(ctl, 'IntegraType', '');

            switch(sIntegraType) {
               case 'DCL':
                  sControlValue = ctl.value;
                  var sDelimiter = GetAttribute(ctl, 'Delimiter');

                  while (sControlValue.indexOf(sDelimiter) >= 0) sControlValue = sControlValue.replace(sDelimiter, '\',\'');

                  sControlValue = '\'' + sControlValue + '\'';
                  break;

               default: //sControlValue = ctl.value;
                  switch (ctl.type) {
                     case 'select-one':
                     case 'select-multiple':
                        sControlValue = ctl.options[ctl.selectedIndex].value;
                        break;

                     case 'checkbox':
                        sControlValue = ctl.checked ? '1' : '0';
                        break;

                     default: //sControlValue = ctl.value;
                        if (ctl.attributes['Decimals'] != null) {
                           var x = ValidateNumber(ctl.value);
                           if (isNaN(x)) x = 0;
                           sControlValue = x.toString();
                        }
                        else sControlValue = ctl.value;
                  }
            }

            vsStr = vsStr.replace('{' + sControlID + '}', sControlValue);          
            i1 = vsStr.indexOf('{', i1 + sControlValue.length + 1);
            bAllBlankValues = bAllBlankValues && (sControlValue == '');  
         }
      }
      else i1 = -1;
   }

   if (bAllBlankValues && (vsDefault != undefined)) vsStr = vsDefault;
   return vsStr;
}

function Revalidate(ctl) {
   var vals = ctl.Validators;

   if (vals != undefined) {
      for (var i = 0; i < vals.length; i++) {
         ValidatorValidate(vals[i]);
      }

      ValidatorUpdateIsValid();
   }
}

function EvaluateValidatorsUpToMe(val) {
   var bIsValid = true;
   var ctl = document.getElementById(val.controltovalidate);
   var aVals = ctl.Validators;

   for (var i = 0; i < aVals.length; i++) {
      if (aVals[i] == val) break;
      if (!aVals[i].isvalid) {
         bIsValid = false;
         break;
      }
   }

   return bIsValid;
}

// validator to post back only if all validators succeed (used by AutoPostBackValidator)
function AutoPostBackValidatorEvaluate(val) {
   if (EvaluateValidatorsUpToMe(val)) __doPostBack(ctl.id, '');
      else return true;
}

// DropFilter methods
function DropFilterValidatorEvaluate(val) {
   if (val.controltovalidate != event.srcElement.id) return true;

   var bIsValid = true;
   var ddf = document.getElementById(val.controltoupdate);
   var ddl = document.getElementById(val.controltoupdate + '_ddl');
   var hid = document.getElementById(val.controltoupdate + '_hid');

   var sConnKey    = ddf.attributes['ConnectionKey'].value;
   var sSource     = ddf.attributes['Source'].value;
   var sFilter     = ddf.attributes['Filter'].value;
   var sDfltFilter = ddf.attributes['DefaultFilter'].value;
   var sSort       = ddf.attributes['Sort'].value;
   var sDataValue  = ddf.attributes['DataValue'].value;
   var sDataText   = ddf.attributes['DataText'].value;

   // get value of each control
   // replace variables
   try {
      sFilter = EvaluateControlReferences(sFilter, sDfltFilter);

      var result = Integra.Core.Web.Controls.DropFilter.ClientRetrieve(sConnKey, sSource, sFilter, sSort, sDataValue, sDataText);
      bIsValid = (result.error == null);

      if (bIsValid) {
         var sSelItem = null;
         var s = result.value;

         hid.value = s;

         if (ddl.selectedIndex >= 0) sSelItem = ddl.options[ddl.selectedIndex].value;
         RemoveFromList(ddl, true);

         if (ddf.attributes['BlankItem'].value == 'True') {
            var sBlankValue = ddf.attributes['BlankValue'].value;
            var sBlankText  = ddf.attributes['BlankText'].value;
            s = sBlankValue + ';' + sBlankText + ((s != '') ? '|' : '') + s;
         }

         AddListItems(ddl, s, sSelItem);
      }
   }
   catch (ex) {
      alert(ex.message);
      bIsValid = false;
   }

   return bIsValid;
}

// script variable replacement
function ReplaceScriptVariables(sUrl) {
   if (sUrl.substring(0, 2) == '~/') sUrl = APP_ROOT_PATH + sUrl.substring(2);

   sUrl = sUrl.replace(/\{apppath\}/gi, APP_ROOT_PATH);
   sUrl = sUrl.replace(/\{igimages\}/gi, INTEGRA_IMAGE_PATH);
   sUrl = sUrl.replace(/\{igscript\}/gi, INTEGRA_SCRIPT_PATH);

   return sUrl;
}

// Client-Side Navigation
function Navigate(vsUrl) {
   vsUrl = ReplaceScriptVariables(vsUrl);
   vsUrl = vsUrl.replace(/\{\%tabindex\}/gi, GetQueryStringItem('tabindex'));
   window.location = vsUrl;
}

function ReturnToCaller(vsKey) {
   var sUrl = Integra.Core.Web.Navigation.ReturnToCaller(vsKey);
   window.location = sUrl.value;
}

function DateDiff(earlyDate, laterDate) {
   // returns number of days between two date objects
   var earlySecs = earlyDate.getTime();
   var laterSecs = laterDate.getTime();
   // 86,400,000 = 1000ms * 60sec * 60min * 24hr
   return Math.floor ((laterSecs - earlySecs) / 86400000);
}

function LTrim(vsStr) {
   if (vsStr != null) {
      while ((vsStr != '') && (vsStr.substring(0, 1) == ' ')) vsStr = vsStr.substring(1);
   }

   return vsStr;
}

function RTrim(vsStr) {
   if (vsStr != null) {
      while ((vsStr != '') && (vsStr.substring(vsStr.length - 1) == ' ')) vsStr = vsStr.substring(0, vsStr.length - 1);
   }

   return vsStr;
}

function Trim(vsStr) {
   vsStr = LTrim(vsStr);
   vsStr = RTrim(vsStr);
   return vsStr;
}

function HelpCheck(vsHelpCode) {
   try {
      ShowHelp(vsHelpCode);
      event.keyCode = 0;
      event.cancelBubble = true;
      event.returnValue = false;
      return false;
   }
   catch (ex) {
      // allow normal help to execute
   }
}

// attributes
function GetAttribute(ctl, vsAttr, voDefault) {
   if ((ctl != null) && (ctl.attributes[vsAttr])) {
      return ctl.attributes[vsAttr].value;
   }
   return voDefault;
}

function SetAttribute(ctl, vsAttr, voValue) {
   if (ctl == null) return;

   if (ctl.attributes[vsAttr] == null) {
      var a = document.createAttribute(vsAttr);
      ctl.attributes.setNamedItem(a);
   }

   ctl.attributes[vsAttr].value = voValue;
}

// style/class management
function RemoveClassName(ctl, vsName) {
   if (ctl.className == null) return;

   // Remove the given class name from the element's className property.
   var aNewList = new Array();
   var aCurList = ctl.className.split(' ');

   for (var i = 0; i < aCurList.length; i++) {
      if (aCurList[i] != vsName) aNewList.push(aCurList[i]);
   }

   ctl.className = aNewList.join(' ');
}

// QueryString management
function AppendQueryString(vsUrl, vsQueryString) {
   if ((vsQueryString == null) || (vsQueryString == '')) return vsUrl;

   var n = vsQueryString.indexOf('=');
   if (n < 0) return vsUrl;

   var s = vsQueryString.substring(0, n);
   if ((vsUrl.indexOf('&' + s + '=') >= 0) || (vsUrl.indexOf('?' + s + '=') >= 0)) return vsUrl;

   return vsUrl + ((vsUrl.indexOf('?') < 0) ? '?' : '&') + vsQueryString;
}

function RemoveQueryString(vsUrl, vsQueryKey) {
   if ((vsQueryKey == null) || (vsQueryKey == '')) return vsUrl;

   var n = vsUrl.indexOf('&' + vsQueryKey + '=');
   if (n < 0) n = vsUrl.indexOf('?' + vsQueryKey + '=');

   if (n >= 0) {
      var s = vsUrl.substring(n + 2 + vsQueryKey.length);
      vsUrl = vsUrl.substring(0, n + 1);
      n = s.indexOf('&');
      if (n >= 0) vsUrl += s.substring(n + 1);
      var c = vsUrl.substring(vsUrl.length - 1, vsUrl.length);
      if ((c == '?') || (c == '&')) vsUrl = vsUrl.substring(0, vsUrl.length - 1);
   }

   return vsUrl;
}

function ReplaceQueryString(vsUrl, vsQueryString) {
   if ((vsQueryString == null) || (vsQueryString == '')) return vsUrl;

   var n = vsQueryString.indexOf('=');
   if (n < 0) return vsUrl;

   var s = RemoveQueryString(vsUrl, vsQueryString.substring(0, n));
   s = AppendQueryString(s, vsQueryString);
   return s;
}

function GetQueryStringItem(vsKey) {
   vsKey = vsKey.toUpperCase();
   var sSearch = document.location.search;
   var i = sSearch.toUpperCase().indexOf(vsKey);

   if (i == -1) return null;

   sSearch = sSearch.substring(i + vsKey.length + 1);
   i = sSearch.indexOf('&');
   if (i >= 0) sSearch = sSearch.substring(0, i);

   return sSearch;
}

// positioning methods
function findPosX(obj) {
   var curleft = 0;

   if (obj.offsetParent) {
      while (obj.offsetParent) {
         curleft += obj.offsetLeft - obj.scrollLeft;
         obj = obj.offsetParent;
         // positioning is relative to any non-visible container
         if (obj.id && (obj.id == 'divPageBody')) break;
//         if ((obj.style.overflowX != '') && (obj.style.overflowX != 'visible') ||
//             (obj.style.overflow  != '') && (obj.style.overflow  != 'visible')) break;
      }
   } else if (obj.x) curleft += obj.x;

   return curleft;
}

function findPosY(obj) {
   var curtop = 0;

   if (obj.offsetParent) {
      while (obj.offsetParent) {
         curtop += obj.offsetTop - obj.scrollTop;
         obj = obj.offsetParent;

         // positioning is relative to any non-visible container
         if (obj.id && (obj.id == 'divPageBody')) {
            curtop += obj.offsetTop; // + obj.scrollTop;
            break;
         }
//         if ((obj.style.overflowY != '') && (obj.style.overflowY != 'visible') ||
//             (obj.style.overflow  != '') && (obj.style.overflow  != 'visible')) break;
      }
   } else if (obj.y) curtop += obj.y;

   return curtop;
}

// display of windowed controls
function ShowHideDDL(visibility) {
   for (i = 0; i < document.forms[0].elements.length; i++) {
      if (document.forms[0].elements[i].type.indexOf('select') == 0)
         document.forms[0].elements[i].style.visibility = visibility;
   }
}

// Control to Click on Enter
function ControlToClickOnEnter(e, ctlName){ 
   var ctl = document.getElementById(ctlName);

   if (ctl != null) {
      if (navigator.appName.indexOf('Netscape') > (-1)) {
            if (e.keyCode == 13) {
            ctl.click();
            return false;
         }
      }

      if (navigator.appName.indexOf('Microsoft Internet Explorer') > (-1)) {
         if (event.keyCode == 13) {
            event.cancelBubble = true;
            event.returnValue = false;
            ctl.click();
            return false;
         }
      }
   }
}

function IgnoreBackspaceNavigation(evt) {
   var e;
   var ctl;
   var key;

   if (navigator.appName.indexOf('Microsoft Internet Explorer') >= 0) {
      e = window.event;
      ctl = event.srcElement;
      key = event.keyCode;
   }
   else {
      e = evt;
      ctl = evt.target;
      key = evt.which;
   }
   
   var b = false;
   
   if (ctl.tagName) {
      b = (ctl.tagName.toUpperCase() == 'INPUT');
      if (b) b = (ctl.type == 'text') || (ctl.type == 'password') || (ctl.type == 'file');
      if (!b) b = (ctl.tagName.toUpperCase() == 'TEXTAREA');
   }

   if (!b && (key == 8)) {
      if (e.cancelBubble) e.cancelBubble = true;
      if (e.returnValue) e.returnValue = false;
      if (e.stopPropagation) e.stopPropagation();
      return false;
   }
}

// delete confirmation
function ConfirmDelete(sMessage, img) {
   var sOldImage = '';
   if (img != null) {
      sOldImage = img.src;
      img.src = INTEGRA_IMAGE_PATH + 'delete-ani.gif';
   }

   if ((sMessage == null) || (sMessage == '')) sMessage = 'Are you sure you want to delete this item?';

   var bReturnCode = confirm(sMessage);
   if (img != null) img.src = sOldImage;
   return bReturnCode;
}

// date & time validation (.NET validator)
function ValidateDateNET(source, arguments) {
   try {
      var ctl = document.getElementById(source.controltovalidate);
      var bPromptPersist = (ctl.attributes['PromptPersist'].value == 'True');
      var sPromptText = '';

      if (bPromptPersist && ctl.attributes['PromptText']) {
         sPromptText = ctl.attributes['PromptText'].value;
      }

      if (bPromptPersist && (sPromptText.toUpperCase() == arguments.Value.toUpperCase())) {
         ctl.value = sPromptText;
         arguments.IsValid = true;
         return true;
      }
      else {
         var bForceDelim = false;  //(source.attributes['ForceDelim'].value == 'True');
         var dtDate = ValidateDate(arguments.Value, bForceDelim);

         if (dtDate != null) {
            var sDisplayFmt = ctl.attributes['DisplayFormat'].value;
            ctl.value = FormatDate(dtDate, sDisplayFmt);
            arguments.IsValid = true;
            return true;
         }
         else if (ctl.value == '') {
            arguments.IsValid = true;
            return true;
         }
         else {
            arguments.IsValid = false;
            return false;
         }
      }
   }
   catch (ex) {
      arguments.IsValid = false;
      return false;
   }
}

// time only validation (.NET validator)
function ValidateTimeNET(source, arguments) {
   try {
      var ctl = document.getElementById(source.controltovalidate);
      var bPromptPersist = (ctl.attributes['PromptPersist'].value == 'True');
      var sPromptText = '';

      if (bPromptPersist && ctl.attributes['PromptText']) {
         sPromptText = ctl.attributes['PromptText'].value;
      }

      if (bPromptPersist && (sPromptText.toUpperCase() == arguments.Value.toUpperCase())) {
         ctl.value = sPromptText;
         arguments.IsValid = true;
         return true;
      }
      else {
         var bForceDelim = false;  //(source.attributes['ForceDelim'].value == 'True');
         var dtTime = ValidateTime(arguments.Value, bForceDelim);

         if (dtTime != null) {
            var sDisplayFmt = ctl.attributes['DisplayFormat'].value;
            ctl.value = FormatTime(dtTime, sDisplayFmt);
            arguments.IsValid = true;
            return true;
         }
         else if (ctl.value == '') {
            arguments.IsValid = true;
            return true;
         }
         else {
            arguments.IsValid = false;
            return false;
         }
      }
   }
   catch (ex) {
      arguments.IsValid = false;
      return false;
   }
}

// date range validation (.NET validation)
function ValidateDateRangeNET(source, arguments) {
   try {
      var ctl = document.getElementById(source.controltovalidate);
      var bPromptPersist = (ctl.attributes['PromptPersist'].value == 'True');
      var sPromptText = '';

      if (bPromptPersist && ctl.attributes['PromptText']) {
         sPromptText = ctl.attributes['PromptText'].value;
      }

      if (bPromptPersist && (sPromptText.toUpperCase() == arguments.Value.toUpperCase())) {
         arguments.IsValid = true;
         return true;
      }
      else {
         var dtDate = ValidateDate(arguments.Value, false);

         if (dtDate != null) {
            var ctl = document.getElementById(source.controltovalidate);
            var i = ctl.id.lastIndexOf('_');
            if (i >= 0) i = ctl.id.lastIndexOf('_', i - 1);
            var sPrefix = (i >= 0) ? ctl.id.substring(0, i + 1) : '';

            var dt;
            var dtMinDate = new Date(source.MinValue);
            var dtMaxDate = new Date(source.MaxValue);

            var sMinCtl = source.MinValueCtl;
            var sMaxCtl = source.MaxValueCtl;

            if (sMinCtl != '') {
               var ctlMin = document.getElementById(sPrefix + sMinCtl + '_txt');
               if (ctlMin != null) {
                  dt = ValidateDate(ctlMin.value, false);
                  if (dt != null) dtMinDate = dt;
               }
            }

            if (sMaxCtl != '') {
               var ctlMax = document.getElementById(sPrefix + sMaxCtl + '_txt');
               if (ctlMax != null) {
                  dt = ValidateDate(ctlMax.value, false);
                  if (dt != null) dtMaxDate = dt;
               }
            }

            arguments.IsValid = ((dtDate >= dtMinDate) && (dtDate <= dtMaxDate));
            return arguments.IsValid;
         }
      }
   }
   catch (ex) {
      arguments.IsValid = false;
      return false;
   }
}

function StripPunctuation(sStr, bAllowLetters, bAllowNumbers, bAllowSpaces) {
   var i;
   var c;
   var sNew = '';

   for (i = 0; i < sStr.length; i++) {
      c = sStr.substring(i, i + 1).toUpperCase();

      if ((bAllowLetters && (c >= 'A') && (c <= 'Z')) || 
          (bAllowNumbers && (c >= '0') && (c <= '9')) || 
          (bAllowSpaces && (c == ' '))) {
         sNew += c;
      }
   }

   return sNew;
}

function ValidateDate(sDate, bForceDelim) {
   try {
      var dt = new Date();
      sDate = RTrim(sDate);
      if ((sDate == null) || (sDate == '')) return null;
      if (sDate.toLowerCase() == 'n') return dt;

      var dtTime = null;
      var nMonth, nDay, nYear;
      var sMonth, sDay, sYear;
      var bSpaceDelim = false;

      // strip off weekday
      var i = sDate.indexOf(',');
      if (i >= 0) sDate = sDate.substring(i + 1);
      
      // assume: month day [year] format
      var i1 = sDate.indexOf('/');
      if (i1 < 0) i1 = sDate.indexOf('-');
      if (i1 < 0) i1 = sDate.indexOf('.');
      if (i1 < 0) { i1 = sDate.indexOf(' '); bSpaceDelim = true; }

      if ((i1 < 0) && (sDate.length > 1)) {
         if ((sDate.toLowerCase().substring(0, 1) == 't') || (sDate.toLowerCase().substring(0, 1) == 'y')) {
            sDate = sDate.substring(0, 1) + ' ' + sDate.substring(1);
            i1 = 1;
            bSpaceDelim = true;
         }
      }

      if ((i1 < 0) && bForceDelim) return null;

      if (i1 < 0) {
         // no punctuation -- assume MMddyyyy format
         sDate = StripPunctuation(sDate, true, true, false);
         sYear = dt.getFullYear().toString();

         switch (sDate.length) {
            case 1:
               switch (sDate.toLowerCase()) {
                  case 't':
                     sDay   = dt.getDate().toString();
                     nMonth = dt.getMonth() + 1;
                     sMonth = nMonth.toString();
                     break;

                  case 'y':
                     dt = new Date(dt.getFullYear(), dt.getMonth(), dt.getDate() - 1);
                     sDay   = dt.getDate().toString();
                     nMonth = dt.getMonth() + 1;
                     sMonth = nMonth.toString();
                     // ejb - need to reget the year because we have adjusted the day, potentially going back
                     // to last year
                     sYear = dt.getFullYear().toString();
                     break;
/*
                  case 'q':
                     // 't' + 1
                     dt = new Date(dt.getFullYear(), dt.getMonth(), dt.getDate() + 1);
                     sDay   = dt.getDate().toString();
                     nMonth = dt.getMonth() + 1;
                     sMonth = nMonth.toString();
                     sYear = dt.getFullYear().toString();
                     break;

                  case 'w':
                     // 't' + 2 
                     dt = new Date(dt.getFullYear(), dt.getMonth(), dt.getDate() + 2);
                     sDay   = dt.getDate().toString();
                     nMonth = dt.getMonth() + 1;
                     sMonth = nMonth.toString();
                     sYear = dt.getFullYear().toString();
                     break;

                  case 'e':
                     // 't' + 3
                     dt = new Date(dt.getFullYear(), dt.getMonth(), dt.getDate() + 3);
                     sDay   = dt.getDate().toString();
                     nMonth = dt.getMonth() + 1;
                     sMonth = nMonth.toString();
                     sYear = dt.getFullYear().toString();
                     break;

                  case 'r':
                     // 't' + 4 
                     dt = new Date(dt.getFullYear(), dt.getMonth(), dt.getDate() + 4);
                     sDay   = dt.getDate().toString();
                     nMonth = dt.getMonth() + 1;
                     sMonth = nMonth.toString();
                     sYear = dt.getFullYear().toString();
                     break;
*/
                  default: throw 'bad date entry';
               }
               break;

            case 2:
            case 3:
               sMonth = sDate.substring(0, 1);
               sDay   = sDate.substring(1);
               break;

            case 4:
               sMonth = sDate.substring(0, 2);
               sDay   = sDate.substring(2, 4);
               break;

            // if 5 or 7 digits, make 6 or 8 and fall through
            case 5:
            case 7:
               sDate = '0' + sDate;

            case 6:
            case 8:
               sMonth = sDate.substring(0, 2);
               sDay   = sDate.substring(2, 4);
               sYear  = sDate.substring(4);
               break;

            default: throw 'bad date entry';
         }

         if ((sMonth.length > 1) && (sMonth.substring(0, 1) == '0')) sMonth = sMonth.substring(1);
         if ((sDay.length   > 1) && (sDay.substring(0, 1)   == '0')) sDay   = sDay.substring(1);
         while ((sYear.length > 1) && (sYear.substring(0, 1) == '0')) sYear = sYear.substring(1);

         nMonth = parseInt(sMonth);
         nDay   = parseInt(sDay);
         nYear  = parseInt(sYear);

         if ((nMonth <= 0) || (nMonth > 12) || (nDay <= 0) || (nDay > 31)) throw 'bad date entry';

         if (nYear < 100) {
            var nCentury = parseInt(dt.getFullYear().toString().substring(0, 2) + '00');
            if (nYear > 50) nCentury -= 100;
            nYear += nCentury;
            sYear = nYear.toString();
         }

         sMonth = nMonth.toString();
         sDay   = nDay.toString();
         sYear  = nYear.toString();
      }
      else {
         var i2 = sDate.indexOf('/', i1 + 1);
         if (i2 == -1) i2 = sDate.indexOf('-', i1 + 1);
         if (i2 == -1) i2 = sDate.indexOf('.', i1 + 1);
         if (i2 == -1) {
            i2 = sDate.indexOf(' ', i1 + 1);

            if ((i2 >= 0) && !bSpaceDelim) {
               dtTime = ValidateTime(sDate.substring(i2 + 1), false);
               if (dtTime == null) throw 'bad time entry';
               sDate = sDate.substring(0, i2);
               i2 = -1;
            }
         }

         sMonth = sDate.substring(0, i1).toLowerCase();

         if ((sMonth == 't') || (sMonth == 'y')) {
            nDay   = dt.getDate() - (sMonth == 'y' ? 1 : 0);
            sDay   = nDay.toString();
            nMonth = dt.getMonth() + 1;
            sMonth = nMonth.toString();
            sYear  = dt.getFullYear().toString();
            dtTime = ValidateTime(sDate.substring(i1 + 1), false);
            if (dtTime == null) throw 'bad time entry';
         }
         else if (i2 >= 0) {
            var i3 = sDate.indexOf(' ', i2 + 1);
            if (i3 >= 0) {
               dtTime = ValidateTime(sDate.substring(i3 + 1), false);
               if (dtTime == null) throw 'bad time entry';
               sDate = sDate.substring(0, i3);
            }

            sDay = sDate.substring(i1 + 1, i2);
            sYear = sDate.substring(i2 + 1);
            while ((sYear.length > 0) && (sYear.substring(0, 1) == '0')) sYear = sYear.substring(1);
            if (sYear.length == 0) sYear = dt.getFullYear().toString();

            try {
               nYear = parseInt(sYear);

               if (nYear < 100) {
                  var nCentury = parseInt(dt.getFullYear().toString().substring(0, 2) + '00');
                  if (nYear > 50) nCentury -= 100;
                  nYear += nCentury;
                  sYear = nYear.toString();
               }
            }
            catch (ex) {
               sYear = dt.getFullYear();
            }
         }
         else {
            sDay = sDate.substring(i1 + 1);
            sYear = dt.getFullYear().toString();
         }
      }

      try {
         var s = sMonth.substring(0, 1);
         var b = (s >= '0') && (s <= '9');

         if (dtTime != null) s = ' ' + FormatTime(dtTime, 'hh:mm:ss tt');
            else s = '';

         if ((sMonth.length > 1) && (sMonth.substring(0, 1) == '0')) sMonth = sMonth.substring(1);
         if ((sDay.length   > 1) && (sDay.substring(0, 1)   == '0')) sDay   = sDay.substring(1);

         nMonth = parseInt(sMonth);
         nDay = parseInt(sDay);

         // first create the date without any time component. This will handle any last-day-of-the-month transitions. 
         dt = new Date(sMonth + (b ? '/' : ' ') + sDay + (b ? '/' : ', ') + sYear);
         dt = new Date(dt.getFullYear().toString() + '/' + (dt.getMonth() + 1).toString() + '/' + dt.getDate().toString() + ' ' + s);

         if (sDay == "0") {
            //The case of sDay = zero is handled outside of the regular check for input matching output
            // In this case just return the calcuated date
            return dt;
         }
         else {
            // Check to see if the requested input string matches the calculated date
            if (nDay != dt.getDate() || (b && (nMonth != dt.getMonth() + 1))) return null; else return dt;
         }
      }
      catch (ex) {
         return null;
      }
   }
   catch (ex) {
      return null;
   }
}

function ValidateTime(sTime, bForceDelim) {
   try {
      sTime = Trim(sTime).toUpperCase();
      if ((sTime == null) || (sTime == '')) return null;

      var sHour, sMin;
      var sSec = '0';
      var sTT = '';
      var i1 = sTime.length;

      if ((sTime.length > 2) && ((sTime.substring(i1 - 1) == 'A') || (sTime.substring(i1 - 1) == 'P'))) {
         sTT = sTime.substring(i1 - 1) + 'M';
         Trim(sTime = sTime.substring(0, i1 - 1));
      }
      else if ((sTime.length > 3) && ((sTime.substring(i1 - 2) == 'AM') || (sTime.substring(i1 - 2) == 'PM'))) {
         sTT = sTime.substring(i1 - 2);
         sTime = Trim(sTime.substring(0, i1 - 2));
      }

      i1 = sTime.indexOf(':');
      if (i1 < 0) i1 = sTime.indexOf('.');
      if (i1 < 0) i1 = sTime.indexOf('-');

      if ((i1 < 0) && bForceDelim) return null;

      if (i1 < 0) {
         i1 = sTime.indexOf(' ');

         if (i1 >= 0) {
            sTT = sTime.substring(i1 + 1);
            sTime = sTime.substring(0, i1);
         }

         switch (sTime.length) {
            // make 2 digits and fall through
            case 1: sTime = '0' + sTime;

            case 2:
               nHour = parseInt(sTime);
               if (nHour < 24) {
                  sHour = sTime;
                  sMin  = '0';
               }
               else {
                  sHour = sTime.substring(0, 1);
                  sMin  = sTime.substring(1);
               }
               break;

            // make 4 digits and fall through
            case 3: sTime = '0' + sTime;

            case 4:
               sHour = sTime.substring(0, 2);
               sMin  = sTime.substring(2);
               break;

            // make 6 digits and fall through
            case 5: sTime = '0' + sTime;

            case 6:
               sHour = sTime.substring(0, 2);
               sMin  = sTime.substring(2, 4);
               sSec  = sTime.substring(4);
               break;

            default: return null;
         }
      }
      else {
         sTime = sTime.replace('.', ':');
         sTime = sTime.replace('-', ':');

         i1 = sTime.indexOf(' ');
         if (i1 >= 0) {
            sTT = sTime.substring(i1);
            sTime = sTime.substring(0, i1);
         }

         var asParts = sTime.split(':');
         if (asParts.length > 4) throw 'bad time entry';

         sHour = Trim(asParts[0]);
         sMin  = Trim(asParts[1]);
         if (asParts.length > 2) sSec = Trim(asParts[2]);

         if (sMin  == '') sMin = '0';
         if (sSec  == '') sSec = '0';
         if (sHour == '') throw 'bad time entry';
      }

      // strip leading zeros -- parseInt doesn't like them
      if ((sHour.length > 1) && (sHour.substring(0, 1) == '0')) sHour = sHour.substring(1);
      if ((sMin.length  > 1) && (sMin.substring(0, 1)  == '0')) sMin  = sMin.substring(1);
      if ((sSec.length  > 1) && (sSec.substring(0, 1)  == '0')) sSec  = sSec.substring(1);

      var nHour = parseInt(sHour);
      var nMin  = parseInt(sMin);
      var nSec  = parseInt(sSec);

      if ((sTT != '') && ((nHour < 1) || (nHour > 12))) return null;
      if ((sTT == '') && ((nHour < 0) || (nHour > 23))) return null;
      if ((nMin < 0) || (sMin > 59) || (sSec < 0) || (sSec > 59)) return null;

      var dt = new Date(Date.parse('01/01/2000 ' + sHour + ':' + sMin + ':' + sSec + ' ' + sTT));
      return isNaN(dt.getHours()) ? null : dt;
   }
   catch (ex) {
      alert(ex);
      return null;
   }
}

function FormatDate(dtDate, sFormat) {
   if (isNaN(dtDate.getMonth())) return '';

   // format time first so text for month & weekday is not mangled
   var sResult = FormatTime(dtDate, sFormat);
   var i;

   // check for full month name
   i = sResult.indexOf('MMMM');
   if (i >= 0) {
      var asFullMonth = new Array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');
      sResult = sResult.substring(0, i) + 'asFullMonth[dtDate.getMonth()]' + sResult.substring(i + 4);
   }

   // check for abbreviated month name
   i = sResult.indexOf('MMM');
   if (i >= 0) {
      var asAbbrevMonth = new Array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
      sResult = sResult.substring(0, i) + asAbbrevMonth[dtDate.getMonth()] + sResult.substring(i + 3);
   }

   // check for two-digit month number
   i = sResult.indexOf('MM');
   if (i >= 0) {
      var nMonth = dtDate.getMonth() + 1;
      sResult = sResult.substring(0, i) + ((nMonth < 10) ? '0' : '') + nMonth.toString() + sResult.substring(i + 2);
   }

   // check for one-digit month number
   i = sResult.indexOf('M');
   if (i >= 0) {
      var nMonth = dtDate.getMonth() + 1;
      sResult = sResult.substring(0, i) + nMonth.toString() + sResult.substring(i + 1);
   }

   // check for full weekday
   i = sResult.indexOf('dddd');
   if (i >= 0) {
      var asFullWeekday = new Array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');
      sResult = sResult.substring(0, i) + asFullWeekday[dtDate.getDay()] + sResult.substring(i + 4);
   }

   // check for abbreviated weekday
   i = sResult.indexOf('ddd');
   if (i >= 0) {
      var asAbbrevWeekday = new Array('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
      sResult = sResult.substring(0, i) + asAbbrevWeekday[dtDate.getDay()] + sResult.substring(i + 3);
   }

   // check for two-digit day
   i = sResult.indexOf('dd');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + ((dtDate.getDate() < 10) ? '0' : '') + dtDate.getDate().toString() + sResult.substring(i + 2);
   }

   // check for one-digit day
   i = sResult.indexOf('d');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + dtDate.getDate().toString() + sResult.substring(i + 1);
   }

   // check for four-digit year
   i = sResult.indexOf('yyyy');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + dtDate.getFullYear().toString() + sResult.substring(i + 4);
   }

   // check for four-digit year
   i = sResult.indexOf('yy');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + dtDate.getFullYear().toString().substring(2) + sResult.substring(i + 2);
   }

   // check for four-digit year
   i = sResult.indexOf('y');
   if (i >= 0) {
      var sYear = dtDate.getFullYear().toString();
      var nYear = parseInt(sYear.substring(2));
      sResult = sResult.substring(0, i) + nYear.toString() + sResult.substring(i + 1);
   }

   return sResult;
}

function FormatTime(dtTime, sFormat) {
   var i;
   var sResult = sFormat;
   var nHour = dtTime.getHours();

   if (isNaN(nHour)) return '';

   // check for two-digit hour (24-hour format)
   i = sResult.indexOf('HH');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + ((nHour < 10) ? '0' : '') + nHour.toString() + sResult.substring(i + 2);
   }

   // check for one-digit hour (24-hour format)
   i = sResult.indexOf('H');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + nHour.toString() + sResult.substring(i + 1);
   }

   if (nHour > 12) nHour -= 12;
   if (nHour == 0) nHour = 12;

   // check for two-digit hour (12-hour format)
   i = sResult.indexOf('hh');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + ((nHour < 10) ? '0' : '') + nHour.toString() + sResult.substring(i + 2);
   }

   // check for one-digit hour (12-hour format)
   i = sResult.indexOf('h');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + nHour.toString() + sResult.substring(i + 1);
   }

   // check for two-digit minute
   i = sResult.indexOf('mm');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + ((dtTime.getMinutes() < 10) ? '0' : '') + dtTime.getMinutes().toString() + sResult.substring(i + 2);
   }

   // check for one-digit minute
   i = sResult.indexOf('m');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + dtTime.getMinutes().toString() + sResult.substring(i + 1);
   }

   // check for one-digit second
   i = sResult.indexOf('ss');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + ((dtTime.getSeconds() < 10) ? '0' : '') + dtTime.getSeconds().toString() + sResult.substring(i + 2);
   }

   // check for one-digit second
   i = sResult.indexOf('s');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + dtTime.getSeconds().toString() + sResult.substring(i + 1);
   }

   // check for two-character lowercase AM/PM
   i = sResult.indexOf('tt');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + ((dtTime.getHours() < 12) ? 'am' : 'pm') + sResult.substring(i + 2);
   }

   // check for one-character lowercase AM/PM
   i = sResult.indexOf('t');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + ((dtTime.getHours() < 12) ? 'a' : 'p') + sResult.substring(i + 1);
   }

   // check for two-character uppercase AM/PM
   i = sResult.indexOf('TT');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + ((dtTime.getHours() < 12) ? 'AM' : 'PM') + sResult.substring(i + 2);
   }

   // check for one-character uppercase AM/PM
   i = sResult.indexOf('T');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + ((dtTime.getHours() < 12) ? 'A' : 'P') + sResult.substring(i + 1);
   }

   return sResult;
}

function IncrementDate(sPart, dtDate, nIncr) {
   var nYear  = dtDate.getFullYear();
   var nMonth = dtDate.getMonth();
   var nDay   = dtDate.getDate();
   var nHour  = dtDate.getHours();
   var nMin   = dtDate.getMinutes();
   var nSec   = dtDate.getSeconds();

   switch (sPart.toLowerCase()) {
      case 'y': nYear  += nIncr; break;
      case 'm': nMonth += nIncr; break;
      case 'd': nDay   += nIncr; break;
      case 'h': nHour  += nIncr; break;
      case 'n': nMin   += nIncr; break;
      case 's': nSec   += nIncr; break;
   }

   return new Date(nYear, nMonth, nDay, nHour, nMin, nSec);
}

function DateBox_KeyDown(evt, txt) {
   var bHandled = false;
   var nKeyCode;

   if (navigator.appName.indexOf('Microsoft Internet Explorer') >= 0) {
      nKeyCode = event.keyCode;
   }
   else {
      nKeyCode = evt.which;
   }

   if (((nKeyCode >= 33) && (nKeyCode <= 36)) || (nKeyCode == 188) || (nKeyCode == 190)) {
      var dt   = ValidateDate(txt.value);
      var sFmt = txt.attributes['DisplayFormat'].value;

      if (dt != null) {
         switch (nKeyCode) {
            case 188:   // comma : (shift) subtract day
            case 190:   // period: (shift) add day
               var sPart = 'd';

               if (event.shiftKey) {
                  txt.value = FormatDate(IncrementDate(sPart, dt, (nKeyCode == 188) ? -1 : 1), sFmt);
                  txt.select();
                  bHandled = true;
               }

               break;
/*
            case 38:    // up arrow  : subtract day, (shift) month, (ctrl) year
            case 40:    // down arrow: add day, (shift) month, (ctrl) year
               var sPart = 'd';

               if (event.shiftKey) sPart = 'm';
                  else if (event.ctrlKey) sPart = 'y';

               txt.value = FormatDate(IncrementDate(sPart, dt, (nKeyCode == 38) ? -1 : 1), sFmt);
               bHandled = true;
               break;
*/
            case 33:    // PGUP: subtract week
            case 34:    // PGDN: add week
               txt.value = FormatDate(IncrementDate('d', dt, (nKeyCode == 33) ? -7 : 7), sFmt);
               txt.select();
               bHandled = true;
               break;

            case 36:    // HOME: (ctrl) first day of month
            case 35:    // END : (ctrl) last day of month
               if (event.ctrlKey) {
                  var nYear  = dt.getFullYear();
                  var nMonth = dt.getMonth();
                  var nDay   = dt.getDate();

                  if (nKeyCode == 35) {
                     nMonth += 1;
                     nDay = 0;
                  }
                  else nDay = 1;

                  txt.value = FormatDate(new Date(nYear, nMonth, nDay), sFmt);
                  txt.select();
                  bHandled = true;
               }

               break;

         }  // switch
      }  // if (dt != null)

      if (bHandled && (navigator.appName.indexOf('Microsoft Internet Explorer') >= 0)) {
         event.cancelBubble = true;
         event.returnValue = false;
      }
   }

   return !bHandled;
}

// number validation (.NET validator)
function ValidateNumberNET(source, arguments) {
   var ctl = document.getElementById(source.controltovalidate);
   var sNewValue = '';

   try {
      var bPromptPersist = (ctl.attributes['PromptPersist'].value == 'True');
      var sPromptText = '';

      if (bPromptPersist && ctl.attributes['PromptText']) {
         sPromptText = ctl.attributes['PromptText'].value;
      }

      if (bPromptPersist && (sPromptText.toUpperCase() == arguments.Value.toUpperCase())) {
         sNewValue = sPromptText;
         arguments.IsValid = true;
      }
      else {
         var s = arguments.Value;
         while (s.substring(s.length - 1, s.length) == ' ') { s = s.substring(0, s.length - 1); }

         if (s == '') {
            sNewValue = (ctl.attributes['AllowBlank'].value == 'True') ? '' : '0';
            arguments.IsValid = true;
         }
         else {
            var dNum = ValidateNumber(s);

            if (!isNaN(dNum)) {
               var nDec = parseInt(ctl.attributes['Decimals'].value);
               var bRound = (ctl.attributes['Round'].value == 'True');
               var bCommas = (ctl.attributes['ShowCommas'].value == 'True');
               var bCurrency = (ctl.attributes['ShowCurrency'].value == 'True');
               var sNegDisplay = ctl.attributes['NegDisplay'].value;

               arguments.IsValid = true;

               if (!bRound) {
                  s = dNum.toString();
                  i = s.indexOf('.');
                  if (i >= 0) {
                     s = s.substring(i + 1);
                     if (s.length > nDec) arguments.IsValid = false;
                  }
               }

               if (arguments.IsValid) sNewValue = FormatNumber(dNum, nDec, sNegDisplay, bCommas, bCurrency);
            }
            else {
               arguments.IsValid = false;
            }
         }
      }
   }
   catch (ex) {
      arguments.IsValid = false;
   }

   if (arguments.IsValid) ctl.value = sNewValue;
   return arguments.IsValid;
}

// number range validation (.NET validation)
function ValidateNumberRangeNET(source, arguments) {
   try {
      var ctl = document.getElementById(source.controltovalidate);
      var bPromptPersist = (ctl.attributes['PromptPersist'].value == 'True');
      var sPromptText = '';

      if (bPromptPersist && ctl.attributes['PromptText']) {
         sPromptText = ctl.attributes['PromptText'].value;
      }

      if (bPromptPersist && (sPromptText.toUpperCase() == arguments.Value.toUpperCase())) {
         arguments.IsValid = true;
         return true;
      }
      else {
         var dNum = ValidateNumber(arguments.Value);

         if (!isNaN(dNum)) {
            var i = ctl.id.lastIndexOf('_');
            if (i >= 0) i = ctl.id.lastIndexOf('_', i - 1);
            var sPrefix = (i >= 0) ? ctl.id.substring(0, i + 1) : '';

            var d;
            var dMinValue = parseFloat(source.MinValue);
            var dMaxValue = parseFloat(source.MaxValue);

            var sMinCtl = source.MinValueCtl;
            var sMaxCtl = source.MaxValueCtl;

            if (sMinCtl != '') {
               var ctlMin = document.getElementById(sPrefix + sMinCtl + '_txt');
               if (ctlMin != null) {
                  d = ValidateNumber(ctlMin.value);
                  if (!isNaN(d)) dMinValue = d;
               }
            }

            if (sMaxCtl != '') {
               var ctlMax = document.getElementById(sPrefix + sMaxCtl + '_txt');
               if (ctlMax != null) {
                  d = ValidateNumber(ctlMax.value);
                  if (!isNaN(d)) dMaxValue = d;
               }
            }

            arguments.IsValid = ((dNum >= dMinValue) && (dNum <= dMaxValue));
            return arguments.IsValid;
         }
      }
   }
   catch (ex) {
      arguments.IsValid = false;
      return false;
   }
}

function ValidateNumber(sValue) {
   var sNewValue = '';
   var c;
   var bFoundMinus = false;
   var i;

   // strip commas and dollar signs (they confuse the parser)
   // also strip negative symbols and parentheses, record that the number is negative
   for (i = 0; i < sValue.length; i++) {
      c = sValue.substring(i, i + 1);

      if (c == '(') c = '-';

      if (c == '-') {
         bFoundMinus = true;
         c = ')';
      }

      if ((c != ',') && (c != '$') && (c != ')') && (c != '%')) {
         if (((c < '0') || (c > '9')) && (c != '.')) return NaN;

         sNewValue += c;
      }
   }

   if (bFoundMinus) sNewValue = '-' + sNewValue;

   try {
      var d = parseFloat(sNewValue);
      return d;
   }
   catch (ex) {
      return NaN;
   }
}

function FormatNumber(dNum, nDec, sNegDisplay, bCommas, bCurrency) {
   if (isNaN(dNum)) return '';

   var sNum = '';
   var sDec = '';
   var i;
   var bIsNegative = (dNum < 0);

   dNum = Math.abs(dNum);

   // handle rounding to correct decimal place
   if (nDec >= 0) {
      // now add trailing zeros
      sNum = dNum.toFixed(nDec);
   }
   else {
      sNum = dNum.toString();
   }

   if (bCommas) {
      var nLen;

      // strip decimals for now (they are an unknown length)
      i = sNum.indexOf('.');

      if (i >= 0) {
         sDec = sNum.substring(i);
         sNum = sNum.substring(0, i);
      }
      else {
         sDec = '';
      }

      // add comma in thousands place
      if (dNum >= 1000) {
         nLen = sNum.length
         sNum = parseInt('' + (dNum / 1000)) + ',' + sNum.substring(nLen - 3, nLen)
      }

      // add comma in millions place
      if (dNum >= 1000000) {
         nLen = sNum.length
         sNum = parseInt('' + (dNum / 1000000)) + ',' + sNum.substring(nLen - 7, nLen)
      }

      // re-add decimals
      sNum += sDec;
   }

   if (sNum.substring(0, 1) == '.') sNum = '0' + sNum;

   if (bIsNegative) {
      switch (sNegDisplay) {
         case 'Parens':
            sNum = '(' + (bCurrency ? '$' : '') + sNum + ')';
            bCurrency = false;
            break;

         case 'Postfix': sNum += '-'; break;
         default: sNum = '-' + sNum; break;
      }
   }

   if (bCurrency) sNum = '$' + sNum;
   return sNum;
}

// phone number validation
function ValidatePhoneNET(source, arguments) {
   var ctl = document.getElementById(source.controltovalidate);
   var bPromptPersist = (ctl.attributes['PromptPersist'].value == 'True');
   var sPromptText = '';

   if (bPromptPersist && ctl.attributes['PromptText']) {
      sPromptText = ctl.attributes['PromptText'].value;
   }

   if (bPromptPersist && (sPromptText.toUpperCase() == arguments.Value.toUpperCase())) {
      ctl.value = sPromptText;
      arguments.IsValid = true;
   }
   else {
      var bAllowLetters = (source.attributes['AllowLetters'].value == 'True');
      var sPhone = StripPunctuation(arguments.Value, bAllowLetters, true, false);

      if (!bAllowLetters) {
         var s = StripPunctuation(arguments.Value, true, true, false);
         if (sPhone != s) sPhone = '';
      }

      if (sPhone.length == 7) {
         var sDfltAC = source.attributes['DefaultAreaCode'].value;
         if (sDfltAC != '') sPhone = sDfltAC + sPhone;
      }

      if (sPhone.length == 10) {
         var sDispFmt = source.attributes['DisplayFormat'].value;

         switch (sDispFmt) {
            case 'Local':
               sPhone = '(' + sPhone.substring(0, 3) + ') ' + sPhone.substring(3, 6) + '-' + sPhone.substring(6, 10);
               break;

            case 'Dashes':
            case 'Dots'  :
               var s = (sDispFmt == 'Dots') ? '.' : '-';
               sPhone = sPhone.substring(0, 3) + s + sPhone.substring(3, 6) + s + sPhone.substring(6, 10);
               break;

         }

         ctl.value = sPhone.toUpperCase();
         arguments.IsValid = true;
      }
      else arguments.IsValid = (arguments.Value == '');
   }

   return arguments.IsValid;
}

// SSN validation
function ValidateSSNNET(source, arguments) {
   var ctl = document.getElementById(source.controltovalidate);
   var bPromptPersist = (ctl.attributes['PromptPersist'].value == 'True');
   var sPromptText = '';

   if (bPromptPersist && ctl.attributes['PromptText']) {
      sPromptText = ctl.attributes['PromptText'].value;
   }

   if (bPromptPersist && (sPromptText.toUpperCase() == arguments.Value.toUpperCase())) {
      ctl.value = sPromptText;
      arguments.IsValid = true;
   }
   else {
      var sSSN = StripPunctuation(arguments.Value, false, true, false);
      var s    = StripPunctuation(arguments.Value, true,  true, false);

      if (sSSN != s) sSSN = '';

      if (sSSN.length == 9) {
         ctl.value = sSSN.substring(0, 3) + '-' + sSSN.substring(3, 5) + '-' + sSSN.substring(5, 9);
         arguments.IsValid = true;
      }
      else arguments.IsValid = (arguments.Value == '');
   }

   return arguments.IsValid;
}

// alien ID validation
function ValidateAlienNET(source, arguments) {
   var ctl = document.getElementById(source.controltovalidate);
   var bPromptPersist = (ctl.attributes['PromptPersist'].value == 'True');
   var sPromptText = '';

   if (bPromptPersist && ctl.attributes['PromptText']) {
      sPromptText = ctl.attributes['PromptText'].value;
   }

   if (bPromptPersist && (sPromptText.toUpperCase() == arguments.Value.toUpperCase())) {
      ctl.value = sPromptText;
      arguments.IsValid = true;
   }
   else {
      var sAlienID = StripPunctuation(arguments.Value, false, true, false);

      if (sAlienID.length == 9) {
         ctl.value = sAlienID.toUpperCase();
         arguments.IsValid = true;
      }
      else arguments.IsValid = (arguments.Value == '');
   }

   return arguments.IsValid;
}

// zip code validation
function ValidateZipNET(source, arguments) {
   var ctl = document.getElementById(source.controltovalidate);
   var bPromptPersist = (ctl.attributes['PromptPersist'].value == 'True');
   var sPromptText = '';

   if (bPromptPersist && ctl.attributes['PromptText']) {
      sPromptText = ctl.attributes['PromptText'].value;
   }

   if (bPromptPersist && (sPromptText.toUpperCase() == arguments.Value.toUpperCase())) {
      ctl.value = sPromptText;
      arguments.IsValid = true;
   }
   else {
      var sZip = StripPunctuation(arguments.Value, false, true, false);
      var s    = StripPunctuation(arguments.Value, true,  true, false);

      if (sZip != s) sZip = '';

      if ((sZip.length == 5) || (sZip.length == 9)) {
         if (sZip.length == 9) sZip = sZip.substring (0, 5) + '-' + sZip.substring(5, 9);
         ctl.value = sZip;
         arguments.IsValid = true;
      }
      else arguments.IsValid = (arguments.Value == '');
   }

   return arguments.IsValid;
}

function LUHN(sCardNum) {
	var n;
	var nSum = 0;

   for (var i = 1; i <= sCardNum.length; i++) {
      n = parseInt(sCardNum.substring(sCardNum.length - i, sCardNum.length - i + 1));

      // every other digit is multiplied by 2
      // add the resulting digits (not number)
      // subtracting 9 does the trick
      // ex. 6 * 2 = 13, so add 1 + 3 (or 13 - 9) = 4
      if ((i % 2) == 0) {
         n *= 2;
         if (n > 9) n -= 9;
      }

      nSum += n;
   }

   return ((nSum % 10) == 0) ? true : false;
}

function ValidateCreditCardNET (source, arguments) {
   var CardType_VISA        = 1;
   var CardType_MasterCard  = 2;
   var CardType_Discover    = 4;
   var CardType_AMEX        = 8;
   var CardType_DinersClub  = 16;
   var CardType_AusBankCard = 32;
   var CardType_enRoute     = 64;
   var CardType_JCB         = 128;

   try {
      var ctl = document.getElementById(source.controltovalidate);
      var bPromptPersist = (ctl.attributes['PromptPersist'].value == 'True');
      var sPromptText = '';

      if (bPromptPersist && ctl.attributes['PromptText']) {
         sPromptText = ctl.attributes['PromptText'].value;
      }

      if (bPromptPersist && (sPromptText.toUpperCase() == arguments.Value.toUpperCase())) {
         ctl.value = sPromptText;
         arguments.IsValid = true;
         return true;
      }
      else {
         var s = arguments.Value;
         var sNew = '';
         var c;
         var sDelimiter       = source.attributes['Delimiter'].value;
         var nAllowedTypes    = source.attributes['AllowedTypes'].value;
         var bPerformChecksum = (source.attributes['PerformChecksum'].value == 'True');

         if (sDelimiter == null) sDelimiter = ' ';

         // reset format message
         var sErrMsg = source.attributes['OrigMsg'].value;
         //source.attributes['FormatMessage'].value = '&nbsp;' + sErrMsg;

         for (var i = 0; i < s.length; i++) {
            c = s.substring(i, i + 1);
            if (((c < '0') || (c > '9')) && (c != ' ') && (c != '-') && (c != '.')) {
               arguments.IsValid = false;
               break;
            }
            else if ((c >= '0') && (c <= '9')) sNew += c;
         }
         // validate general length
         if (arguments.IsValid) {
            arguments.IsValid = (sNew.length >= 13) && (sNew.length <= 16);
            sErrMsg = 'Must be 13 to 16 digits';
         }

         var sMasterCard = ',51,52,53,54,55,';
         var sDinersClub = ',300,301,302,303,304,305,';

         // validate lengths of known card types
         if (arguments.IsValid) {
            // VISA
            if ((nAllowedTypes & CardType_VISA) && (sNew.substring(0, 1) == '4')) {
               arguments.IsValid = (sNew.length == 13) || (sNew.length == 16);
               sErrMsg = 'VISA must be 13 or 16 digits';
            }
            // Discover
            else if ((nAllowedTypes & CardType_Discover) && (sNew.substring(0, 4) == '6011')) {
               arguments.IsValid = (sNew.length == 16);
               sErrMsg = 'Discover must be 16 digits';
            }
            // MasterCard
            else if ((nAllowedTypes & CardType_MasterCard) && (sMasterCard.indexOf(',' + sNew.substring(0, 2) + ',') >= 0)) {
               arguments.IsValid = (sNew.length == 16);
               sErrMsg = 'MasterCard must be 16 digits';
            }
            // American Express
            else if ((nAllowedTypes & CardType_AMEX) && ((sNew.substring(0, 2) == '34') || (sNew.substring(0, 2) == '37'))) {
               arguments.IsValid = (sNew.length == 15);
               sErrMsg = 'AMEX must be 15 digits';
            }
            // Diner's Club/Carte Blanche
            else if ((nAllowedTypes & CardType_DinersClub) && ((sNew.substring(0, 2) == '36') || (sNew.substring(0, 2) == '38') || 
                                                              (sDinersClub.indexOf(',' + sNew.substring(0, 3) + ',') >= 0))) {
               arguments.IsValid = (sNew.length == 14);
               sErrMsg = 'Diner\'s Club must be 14 digits';
            }
            // Australian BankCard
            else if ((nAllowedTypes & CardType_AusBankCard) && (sNew.substring(0, 4) == '5610')) {
               arguments.IsValid = (sNew.length == 16);
               sErrMsg = 'Aus BankCard must be 16 digits';
            }
            // enRoute
            else if ((nAllowedTypes & CardType_enRoute) && ((sNew.substring(0, 4) == '2014') || (sNew.substring(0, 4) == '2149'))) {
               bPerformChecksum = false;
               arguments.IsValid = (sNew.length == 15);
               sErrMsg = 'enRoute must be 15 digits';
            }
            // JCB(1)
            else if ((nAllowedTypes & CardType_JCB) && ((sNew.substring(0, 4) == '2131') || (sNew.substring(0, 4) == '1800'))) {
               arguments.IsValid = (sNew.length == 15);
               sErrMsg = 'JCB(1) must be 15 digits';
            }
            // JCB(3)
            else if ((nAllowedTypes & CardType_JCB) && (sNew.substring(0, 1) == '3')) {
               arguments.IsValid = (sNew.length == 16);
               sErrMsg = 'JCB(3) must be 16 digits';
            }
            else {
               arguments.IsValid = false;
               sErrMsg = 'Invalid number';
            }
         }

         // perform checksum using LUHN formula (mod 10)
         if (arguments.IsValid && bPerformChecksum) {
            arguments.IsValid = LUHN(sNew);
            sErrMsg = 'Checksum failed';
         }

         if (arguments.IsValid) {
            ctl.value = sNew.substring(0,  4) + sDelimiter + sNew.substring(4, 8) + sDelimiter + 
                        sNew.substring(8, 12) + sDelimiter + sNew.substring(12);
         }
         else {
            source.innerHTML = '&nbsp;' + sErrMsg;
         }

         return arguments.IsValid;
      }
   }
   catch (ex) {
      arguments.IsValid = false;
      return false;
   }
}

// NumberBox spinner methods
function SpinCheck(nb) {
   var txt = document.getElementById(nb.id + '_txt');

   var curValue = parseInt(txt.value);
   var minValue = parseInt(txt.MinValue);
   var maxValue = parseInt(txt.MaxValue);

   var imbUp = document.getElementById(nb.id + '_imbSpinUp');
   var imbDn = document.getElementById(nb.id + '_imbSpinDown');

   if (imbUp != null) {
      imbUp.disabled = (curValue >= maxValue);
      imbUp.src = INTEGRA_IMAGE_PATH + (imbUp.disabled ? 'up-dis.gif' : 'up.gif');
   }

   if (imbDn != null) {
      imbDn.disabled = (curValue <= minValue);
      imbDn.src = INTEGRA_IMAGE_PATH + (imbDn.disabled ? 'down-dis.gif' : 'down.gif');
   }
}

function SpinNumber(nb,val) {
   var txt = eval(document.forms[0].elements[nb.id + '_txt']);

   var curValue = parseInt(txt.value);
   var minValue = parseInt(txt.MinValue);
   var maxValue = parseInt(txt.MaxValue);

   curValue += val;
   if (curValue > maxValue) curValue = maxValue;
   if (curValue < minValue) curValue = minValue;

   txt.value = curValue.toString();
   SpinCheck(nb);
}

