// A trim() function!  Because some browsers bloody don't natively support trim()
function trim(IfYouSeeErrorIsFunctionTrim)
{
  //alert('Trim("' + IfYouSeeErrorIsFunctionTrim + '")');
  return IfYouSeeErrorIsFunctionTrim.replace(/^\s+|\s+$/g, '');
}


// Set color of highlighted table row
function RowColor(TableRow, Highlight)
{
  if(Highlight == true)
  {
    if(TableRow.className == "odd")
      TableRow.className = "oddon";
    else
      TableRow.className = "on";
  }
  else
  {
    if(TableRow.className == "oddon")
      TableRow.className = "odd";
    else
      TableRow.className = "off";
  }
}


// Generate random string
function RandomFieldString() //TheField)
{
  var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
  var MaxLength = 16;
  var Randy = '';


  for(var i = 0; i < MaxLength; i++)
  {
    var rnum = Math.floor(Math.random() * chars.length);
    Randy += chars.substring(rnum, rnum + 1);
  }

  //DaField = document.getElementById(TheField);
  //DaField.value = Randy;
  return Randy;
}


// Move selected ListBox option UP
function FoodItemUp(MealNum)
{
  var MealBox = null;
  var Index   = 0;
  var ShempValue = "";
  var ShempText  = "";


  MealBox = document.getElementById(MealNum);
  Index = MealBox.selectedIndex;

  if(Index <= 0)
    return; // nothing to do!

  // Swap selected item with preceeding item
  ShempValue = MealBox.options[Index - 1].value;
  ShempText  = MealBox.options[Index - 1].text;
  MealBox.options[Index - 1].value = MealBox.options[Index].value;
  MealBox.options[Index - 1].text  = MealBox.options[Index].text;
  MealBox.options[Index].value = ShempValue;
  MealBox.options[Index].text  = ShempText;

  MealBox.selectedIndex--;
}

// Move selected ListBox option DOWN
function FoodItemDown(MealNum)
{
  var MealBox = null;
  var Index   = 0;
  var ShempValue = "";
  var ShempText  = "";


  MealBox = document.getElementById(MealNum);
  Index = MealBox.selectedIndex;

  if(Index == -1 || Index == MealBox.length - 1)
    return; // nothing to do!

  // Swap selected item with next item
  ShempValue = MealBox.options[Index + 1].value;
  ShempText  = MealBox.options[Index + 1].text;
  MealBox.options[Index + 1].value = MealBox.options[Index].value;
  MealBox.options[Index + 1].text  = MealBox.options[Index].text;
  MealBox.options[Index].value = ShempValue;
  MealBox.options[Index].text  = ShempText;

  MealBox.selectedIndex++;
}


/* Doesn't look like I needed this
function RemoveElement(TheParent, TheChild)
{
  var Papa  = document.getElementById(TheParent);
  var Haizi = document.getElementById(TheChild); // Chinese for "child"


  Papa.removeChild(Haizi);
}
*/


// Execute some PHP AJAX and set the result in a specified field on the calling page.
//   DestField : Id of object receiving generated text.
//   FetchUrl  : Path to PHP (or other) page of code to execute.
//   Args      : Arguments to set into the URL:  An array of 2-dimensional arrays:
//              [0] = variable name, [1] = value.
//              Don't forget "new Array(new Array(" if passing only 1 argument!
//   ForceRefresh : 1 = insert time stamp to force browser refresh
//   DisallowFirstZero : 1 = Only perform retrieval if first argument value is greater than ZERO,
//                           else return blank text.
// Example: AjaxSetField('DisplayShoeInfo',
//                       'ShoeAjaxGetDesc.php',
//                       new Array(new Array('ShoeType', 5),
//                                 new Array('ShoeSize', 10),
//                                 new Array('Color', 'Brown')),
//                       1, 1);
// would fetch data from URL
// ShoeAjaxGetDesc.php?ShoeType=5&ShoeSize=10&Color=Brown&fresh=1256766412652
// If the first value, ShoeType, were 0 or a negative value, blank text would be returned.
// The returned text would then be inserted into a container ID'd as 'DisplayShoeInfo'.
function AjaxSetText(DestField, FetchUrl, Args, ForceRefresh, DisallowFirstZero)
{
  var ArgList = "?";
  var i = 0;
  var j = 0;
  var FirstValue = 0;


  for(i = 0; i < Args.length; i++)
  {
    if(i > 0)
      ArgList += '&';
    else
      FirstValue = Args[i][1];

    ArgList += Args[i][0] + "=" + Args[i][1];
  }

  // Use timestamp to force refresh?
  if(ForceRefresh == 1)
  {
    if(ArgList.length > 1)
      ArgList += '&';
    else
      ArgList +='(' + ArgList.length + ')';
    ArgList += 'fresh=' + new Date().getTime();
  }

  //alert('DestField = ' + DestField + "\nFetchUrl = " + FetchUrl + "\nArgs = \n" + ArgList);

  // Are there arguments to include?
  if(ArgList.length > 1)
    FetchUrl += ArgList;

  //alert("Url = " + FetchUrl);

  if(DisallowFirstZero == 1) // don't bother fetching content if primary value is zero
  {
    if(FirstValue <= 0) // id should always be greather than zero!
    {
      document.getElementById(DestField).innerHTML = "";
      return;
    }
  }

  xmlhttp = GetXmlHttpObject();

  if(xmlhttp == null)
  {
    alert("Your browser does not support XMLHTTP!");
    return;
  }

  xmlhttp.onreadystatechange = function()
  {
    if(xmlhttp.readyState == 4)
    {
      //alert('shibal inom'); // Pardon my French
      document.getElementById(DestField).innerHTML = xmlhttp.responseText;
      //alert('kuso yarou');
    }
  }

  xmlhttp.open("GET", FetchUrl, true);
  xmlhttp.send(null);
}


function GetXmlHttpObject() // From w3schools.com
{
  if(window.XMLHttpRequest)
  {
    // code for IE7+, Firefox, Chrome, Opera, Safari
    return new XMLHttpRequest();
  }
  if(window.ActiveXObject)
  {
    // code for IE6, IE5
    return new ActiveXObject("Microsoft.XMLHTTP");
  }
  return null;
}

// Open new window and generate a PDF for the selected meal plan.
//
// This method *appears* to not F-in' work in P.O.S. IE because that imbecilically
// designed browser can't be bothered to update the bloody MIME type after the
// PHP code finishes generating the PDF file!  It will work *if* the user clicks
// on the address bar then smacks Enter, as if *directly browsing* to the
// PHP page, but that is far too unintuitive for the average user.  Annoying, too!
function OpenPdfNewWindow()
{
  var TheList = document.getElementById('printMealPlanList');

  window.open('GuruPdfMealPlan.php?id=' + TheList.value, '_blank');

  // Because IE sucks it's like I walk against the wind everywhere I go,
  // I have to stop at every corner and put on a show...
  //var IhateMimes = new Date().valueOf();
  //window.open('SheNeverToldMeSheWasMimeType.pdf', IhateMimes);
  //window.open('GuruPdfMealPlan.php?id=' + TheList.value, IhateMimes);
}
// See http://www.w3schools.com/htmldom/met_win_open.asp for php code


function CopySelectOptionText(FromSelect, ToContainer)
{
  document.getElementById(ToContainer).value = FromSelect.options[FromSelect.selectedIndex].text;
}


function SetFocusOnLoad(TheObject)
{
  if($('#' + TheObject).length > 0)
    $('#' + TheObject).focus();
}


// Tried to use two different calls to AjaxSetText in one onclick event, but the data received for
// the second bloody call somehow overwrote the content of the first target container, so this
// function directly sets the link contained in container ID'd as SheNeverToldMeSheWasaMime.
function BloodyMime(MealPlanId, OrgId)
{
  var Bridge = '';


  //alert(navigator.appName + "\n" + navigator.appVersion);
  //alert('Your code is screwed = ' + OhCrapOhCrapItsIeMyCodeIsFubarred(8.0));

  //if(OhCrapOhCrapItsIeMyCodeIsFubarred(8.0)) // Dynamic implemetnation FAIL!
  //  Bridge = '../';
  //else // Dynamic implementation WIN!
    Bridge = SinkDepth(GetDepth());
  //alert("'" + Bridge + "'");

  if(MealPlanId == null || MealPlanId <= 0) // Id should always be greather than zero!
  {
    document.getElementById('SheNeverToldMeSheWasaMime').innerHTML = "";
  }
  else
    document.getElementById('SheNeverToldMeSheWasaMime').innerHTML =
      "<a href=\"" + Bridge + "include/GuruPdfMealPlan.php?MealPlanId=" + MealPlanId + "&OrgId=" + OrgId + "\" target=\"_blank\">View Printable Meal Plan</a>\n";
      //"<a href=\"../include/GuruPdfMealPlan.php?MealPlanId=" + MealPlanId + "&OrgId=" + OrgId + "\" target=\"_blank\">View Printable Meal Plan</a>\n";
  // To set the URL properly her, I should write JavaScript eqivellents of the GruMealDepth.php functions
}


// Sort contents of a FORM's SELECT ListBox, by .text
function SortListBoxText(BoxId, CompareMode)
{
  var Sorted = false;
  var i        = 0;
  var Comp     = 0; // Comparison result
  var TheBox = null;
  var cMode  = CompareMode.toLowerCase();
  var CompPrev = "";
  var CompNext = "";
  var ShempText = "";
  var ShempValue = "";
  var NumPrev = 0.0;
  var NumNext = 0.0;


  TheBox = document.getElementById(BoxId);

  while(Sorted == false)
  {
    Sorted = true;

    for(i = 1; i < TheBox.length; i++)
    {
      // Compare
      switch(cMode)
      {
        case 'numeric':
          NumPrev = Number(TheBox.options[i - 1].text);
          NumNext = Number(TheBox.options[i].text);

          if(NumPrev < NumNext)
            Comp = -1;
          else if(NumPrev > NumNext)
            Comp = 1;
          else // if(NumPrev == NumNext)
            Comp = 0;
          break;

        case 'sensitive':
          if(TheBox.options[i - 1].text < TheBox.options[i].text)
            Comp = -1;
          else if(TheBox.options[i - 1].text > TheBox.options[i].text)
            Comp = 1;
          else
            Comp = 0;
          break;

        //case 'insensitive':
        default:
          CompPrev = TheBox.options[i - 1].text.toLowerCase();
          CompNext = TheBox.options[i].text.toLowerCase();

          if(CompPrev < CompNext)
            Comp = -1;
          else if(CompPrev > CompNext)
            Comp = 1;
          else
            Comp = 0;
          break;
      }

      // Swap if out of order
      if(Comp > 0)
      {
        Sorted = false;

        ShempValue                  = TheBox.options[i - 1].value;
        ShempText                   = TheBox.options[i - 1].text;
        TheBox.options[i - 1].value = TheBox.options[i].value;
        TheBox.options[i - 1].text  = TheBox.options[i].text;
        TheBox.options[i].value     = ShempValue;
        TheBox.options[i].text      = ShempText;
      }

      //alert(i + " = i | Sorted = " + Sorted + " | Comp = " + Comp);
    }
    //alert("end of while");
  }
}

// Sort contents of a FORM's SELECT ListBox, by .value
function SortListBoxValue(BoxId, CompareMode)
{
  var Sorted = false;
  var i        = 0;
  var Comp     = 0; // Comparison result
  var TheBox = null;
  var cMode  = CompareMode.toLowerCase();
  var CompPrev = "";
  var CompNext = "";
  var ShempText = "";
  var ShempValue = "";
  var NumPrev = 0.0;
  var NumNext = 0.0;


  TheBox = document.getElementById(BoxId);

  while(Sorted == false)
  {
    Sorted = true;

    for(i = 1; i < TheBox.length; i++)
    {
      // Compare
      switch(cMode)
      {
        case 'numeric':
          NumPrev = Number(TheBox.options[i - 1].value);
          NumNext = Number(TheBox.options[i].value);

          if(NumPrev < NumNext)
            Comp = -1;
          else if(NumPrev > NumNext)
            Comp = 1;
          else // if(NumPrev == NumNext)
            Comp = 0;
          break;

        case 'sensitive':
          if(TheBox.options[i - 1].value < TheBox.options[i].value)
            Comp = -1;
          else if(TheBox.options[i - 1].value > TheBox.options[i].value)
            Comp = 1;
          else
            Comp = 0;
          break;

        //case 'insensitive':
        default:
          CompPrev = TheBox.options[i - 1].value.toLowerCase();
          CompNext = TheBox.options[i].value.toLowerCase();

          if(CompPrev < CompNext)
            Comp = -1;
          else if(CompPrev > CompNext)
            Comp = 1;
          else
            Comp = 0;
          break;
      }

      // Swap if out of order
      if(Comp > 0)
      {
        Sorted = false;

        ShempValue                  = TheBox.options[i - 1].value;
        ShempText                   = TheBox.options[i - 1].text;
        TheBox.options[i - 1].value = TheBox.options[i].value;
        TheBox.options[i - 1].text  = TheBox.options[i].text;
        TheBox.options[i].value     = ShempValue;
        TheBox.options[i].text      = ShempText;
      }
      //alert(i + " = i | Sorted = " + Sorted + " | Comp = " + Comp);
    }
    //alert("end of while");
  }
}


function SearchListBox(FindText, InList)
{
  var FindMe   = null;
  var LookInMe = null;
  var i     = 0;
  var Start = 0;
  var Stop  = 0;
  var HitEnd = 0;


  FindMe   = document.getElementById(FindText);
  LookInMe = document.getElementById(InList);

  if(FindMe.value.length == 0)
    return; // nothing to do!

  Start = LookInMe.selectedIndex;
  Stop  = LookInMe.options.length;

  while(HitEnd < 2)
  {
    for(i = Start + 1; i < Stop; i++)
    {
      if(LookInMe.options[i].text.toLowerCase().indexOf(FindMe.value.toLowerCase()) > -1)
      {
        //alert("Found at " + i + ": " + LookInMe.options[i].text);
        LookInMe.options[i].selected = true;
        return;
      }
    }
    HitEnd++;
    if(Start == 0)
      HitEnd++; // Already started at start of list
    else // Search started somewhere in middle of list; start again from top
    {
      Stop  = Start + 1;
      if(Stop > LookInMe.options.length)
        Stop = LookInMe.options.length;
      Start = 0;
    }
  }


  // this point reached only if no match found
  alert(FindMe.value + " not found!");
}


// Returns
//    int $DirectoryDepth
// from Root directory.  Root has a depth of 0.
// Requires implementation of
// <input type="hidden" id="DasBoot" name="DasBoot" value="<?php print strlen(GetDepth()); ?>" />
// on calling page (is part of standard template footer).
function GetDepth()
{
  // How deep has das Boot sunk?
  return $('#DasBoot').val();
}

// Generate as many '../' lower directory steps as necessary to link to a higher directory.
//    $Depth = Number of directories to traverse back through.
function SinkDepth(Depth)
{
  i = 0;
  DepthCharge = '';


  if(Depth <= 0)
    return '';

  for(i = 0; i < Depth; i++)
    DepthCharge += '../';

  return DepthCharge;
}


// Slide Show
function slideShow()
{
  //Set the opacity of all images to 0
  $('#gallery a').css({opacity: 0.0});

  //Get the first image and display it (set it to full opacity)
  $('#gallery a:first').css({opacity: 1.0});

  //Set the caption background to semi-transparent
  //$('#gallery .caption').css({opacity: 0.7});

  //Resize the width of the caption according to the image width
  //$('#gallery .caption').css({width: $('#gallery a').find('img').css('width')});

  //Get the caption of the first image from REL attribute and display it
  //$('#gallery .content').html($('#gallery a:first').find('img').attr('rel')).animate({opacity: 0.7}, 400);

  //Call the gallery function to run the slideshow, 6000 = change to next image after 6 seconds
  setInterval('gallery()',6000);
}

// Used by slideShow()
function gallery()
{
  //if no IMGs have the show class, grab the first image
  var current = ($('#gallery a.show')?  $('#gallery a.show') : $('#gallery a:first'));

  //Get next image; if it reached the end of the slideshow, rotate it back to the first image
  var next = ((current.next().length) ? ((current.next().hasClass('caption'))? $('#gallery a:first') :current.next()) : $('#gallery a:first'));	

  //Get next image caption
  //var caption = next.find('img').attr('rel');	

  //Set the fade in effect for the next image, show class has higher z-index
  next.css({opacity: 0.0})
  .addClass('show')
  .animate({opacity: 1.0}, 1000);

  //Hide the current image
  current.animate({opacity: 0.0}, 1000)
  .removeClass('show');

  //Set the opacity to 0 and height to 1px
  //$('#gallery .caption').animate({opacity: 0.0}, { queue:false, duration:0 }).animate({height: '1px'}, { queue:true, duration:300 });	

  //Animate the caption, opacity to 0.7 and heigth to 100px, a slide up effect
  //$('#gallery .caption').animate({opacity: 0.7},100 ).animate({height: '100px'},500 );

  //Display the content
  //$('#gallery .content').html(caption);
}


// Determine if Internet Explorer is in use; if that's the case, you're code is FUBARred!
//    MinNonFubar : Minimum version of IE expected to ACTUALLY work with the target JavaScript code.
// Returns
//    bool YourCodeIsFubarred
function OhCrapOhCrapItsIeMyCodeIsFubarred(MinNonFubar)
{
  var SeverityOfBeating  = 0.0;
  var HowScrewedAmI = 0.0;
  var i = 0;
  var j = 0;


  //alert(navigator.appName + "\n" + navigator.appVersion + "\n" + MinNonFubar);

  // Are you screwed?
  if(navigator.appName == 'Microsoft Internet Explorer')
  {
    // Maybe...

    // check for if this REALLY works; may need the likes of if(typeof MinNonFubar == 'undefined')
    // see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Operators/Special_Operators/typeof_Operator
    if(MinNonFubar == undefined) // You are most definately screwed!
      SeverityOfBeating = 32767.0;
    else // There's a *slim* chance of hope...
      SeverityOfBeating = MinNonFubar;

    // Extract the browser version
    i = navigator.appVersion.indexOf('MSIE', 0);
    j = navigator.appVersion.indexOf(';', i + 5);

    HowScrewedAmI = parseFloat(navigator.appVersion.substring(i + 5, j));
    //alert('i: ' + i + "\nj: " + j + "\nVer: \"" + HowScrewedAmI + "\"\n" + SeverityOfBeating);

    if(HowScrewedAmI < SeverityOfBeating) // You are absolutely SCREWED!
      return true;
    else
      return false; // Meh, it OUGHT to work.
  }
  else
    return false; // Absolutely should work!
}


// Because IE imbecilically doubles the margin, we've got half it!
//    array Screwed[int ArrayIndex] => string ObjectIdentifier (include # or . if applicable)
// Each ObjectIdentifier is passed to jQuery function $(Screwed[i]).each()
function IeMarginFubar(Screwed)
{
  var i = 0;
  var j = 0;


  if(OhCrapOhCrapItsIeMyCodeIsFubarred(8)) // what the?! they ACTUALLY fixed some things in IE8!
  {
    j = Screwed.length;

    for(i = 0; i < j; i++)
    {
      $(Screwed[i]).each(function(k)
      {
        //alert($(this).css('margin-left'));
        $(this).css('margin-left', (ParseInt($(this).css('margin-left')) / 2) + 'px');
        //alert($(this).css('margin-left'));
      });
    }
  }
}

// For the random fubars of IE:
//    array Screwed[int ArrayIndex] => [0] : string ObjectIdentifier (include # or . if applicable)
//                                     [1] : string CSS attribute to modify
//                                     [2] : string CSS value to set
function IeStyleFubar(Screwed)
{
  var i = 0;
  var j = 0;


  if(OhCrapOhCrapItsIeMyCodeIsFubarred(8)) // what the?! they ACTUALLY fixed some things in IE8!
  {
    j = Screwed.length;

    for(i = 0; i < j; i++)
    {
      $(Screwed[i][0]).each(function(k)
      {
        //alert($(this).css(Screwed[i][1]));
        $(this).css(Screwed[i][1], Screwed[i][2]);
        //alert($(this).css(Screwed[i][1]));
      });
    }
  }
}

// Add up the values of some fields which are pass in as an array, then set total to other field.
//    array  AddUs[int ArrayIndex] => string ObjectId : fields to add up from
//    string ToMe  : Field to put total into
function TotalTheseInputs(AddUs, ToMe)
{
  var i = 0;
  var j = 0;
  var Total = 0;


  j = AddUs.length;
  for(i = 0; i < j; i++)
  {
    if(isNaN(($('#' + AddUs[i]).val())))
      continue;
    Total += Number($('#' + AddUs[i]).val());
  }

  $('#' + ToMe).val(Total);
}

// Multiply and add up the values of some fields which are pass in as an array, then set total to other field.
//    array  AddUs[int ArrayIndex] => string ObjectId : fields to add up from
//    string ToMe  : Field to put total into
// Note: The fields being added up are expected to correspond to [0] => PROTEIN, [1] => CARBS, [2] => FAT !!
function TotalInputCalories(CalcUs, ToMe)
{
  var Total = 0.0;


  $('#' + ToMe).val(RoundFloat(
                    (ParseFloat($('#' + CalcUs[0]).val()) * 4.0) + // Protein
                    (ParseFloat($('#' + CalcUs[1]).val()) * 4.0) + // Carbs
                    (ParseFloat($('#' + CalcUs[2]).val()) * 9.0),  // Fat
                    2));
}


function UpOneDownOne(Upper, Downer)
{
  $('#BumpBar').slideDown('fast', function()
  {
    $('#' + Upper).slideUp('slow', function()
    {
      $('#' + Downer).slideDown('slow', function()
      {
        $('#BumpBar').slideUp('fast');
      });
    });
  });
}


// Validate e-mail address.  Does NOT report causes of invalidation.
//    string Address
// Returns
//    bool IsValid
// Note:  Dash is not allowed by established standards, but we're allowing it here as requested by client.
function ValidEmail(Address) // example input: username@anywhere.net
{
  var i = 0;
  var j = 0;
  var k = 0;
  var l = 0;
  var amp = 0; // ampersand (@)
  var per = 0; // period (.)
  var ji = '?'; // Japanese for "character"


  // Locate ampersand:  Required
  amp = Address.indexOf('@');
  if(amp <= 0) // either none found, or no username contained in address
    return false;

  // Is there a second ampersand?  Not allowed!
  if(Address.indexOf('@', amp + 1) > -1)
    return false;

  // Check for double-period:  Not allowed!
  //if(Address.indexOf('..') > -1)
  //  return false;

  // Check for bad combinations of non-alphanumerics:  Streng verboten!
  if(Address.indexOf('-.') > -1 ||
     Address.indexOf('.-') > -1 ||
     Address.indexOf('-@') > -1 ||
     Address.indexOf('@-') > -1 ||
     Address.indexOf('.@') > -1 ||
     Address.indexOf('@.') > -1 ||
     Address.indexOf('..') > -1 ||
     Address.indexOf('--') > -1)
    return false;

  // Locate first period after ampersand:  Required
  per = Address.indexOf('.', amp + 1);
  if(per == -1)
    return false;

  // Consider the 2 components of example input: username@domain.class
  for(i = 0; i < 2; i++)
  {
    switch(i)
    {
      case 0: // examine the username ("local") portion
        k = 0;
        l = amp - 1;
        break;

      case 1: // examine the domain.class portion
        k = amp + 1;
        l = Address.length - 1;
        break;
    }
    if(k == l) // segment length is zero; a component is missing!
      return 0;

    // Check component for allowed characters: letters, numbers, period, underscore
    for(j = k; j <= l; j++)
    {
      ji = Address.charAt(j).toLowerCase(); // no need to check for uppercase letters
      //alert(j + ': ' + ji);

      if(ji < '0')
      {
        if(ji == '.' || ji == '-') // PERIOD or DASH
        {
          if(j == k || j == l) // cannot start or end with period
            return false;
        }
        else
          return false;
      }
      else if('9' < ji && ji < 'a')
      {
        if(ji == '_')
        {
          if(j == k || j == l) // cannot start or end with underscore
            return false;
        }
        else
          return false;
      }
      else if('z' < ji)
        return false;
    }
  }

  // this point only reached if no problems encountered
  return true;
}

// Validate date, expected in American 8-digit slashed-format of MM/DD/YYYY
// If invalid, returns
//    0
// else returns
//    int $YYYYMMDD
function ValidDateUs8(Slashed)
{
  var s1 = 0; // Positions of slash dividers
  var s2 = 0;
  var Ye = 0; // Year
  var Mo = 0; // Month
  var Da = 0; // Day
  var Days = MonthDays();


  s1 = Slashed.indexOf('/');
  s2 = Slashed.indexOf('/', s1 + 1);
  //alert('s1 ' + s1 + "\ns2 " + s2);

  if(s1 == -1 || s2 == -1) // Dividers are missing
  {
    //alert('s1: ' + s1 + "\ns2: " + s2);
    return 0;
  }

  Mo = ParseInt(Slashed.substr(0, s1));
  Da = ParseInt(Slashed.substr(s1 + 1, s2 - s1));
  Ye = ParseInt(Slashed.substr(s2 + 1, Slashed.length - s2));
  //alert("'" + Mo + "' '" + Da + "' '" + Ye + "'");
  if(isNaN(Mo) || isNaN(Da) || isNaN(Ye))
    return 0;

  // Validate Month
  if(Mo < 1 || 12 < Mo)
  {
    //alert('Mo ' + Mo);
    return 0;
  }

  // Validate Day
  if(Da < 1 || Days[Mo] < Da)
  {
    //alert('Da ' + Da);
    return 0;
  }

  // Validate Year
  if(Ye < 1 || 9999 < Ye)
  {
    //alert('Ye ' + Ye);
    return 0;
  }


  // Valid if this point reached
  return DateInt(Ye, Mo, Da);
}


// Returns an array listing how many days are in each month.
// Array is zero-based, with 13 values, so that Jan is 1, Feb is 2, etc.)
function MonthDays()
{
  return new Array(0, // Extra value to push up index of others (so that Jan is 1, Feb is 2, etc.)
                   31,
                   29, // Hm, what to do about leap year...
                   31,
                   30,
                   31,
                   30,
                   31,
                   31,
                   30,
                   31,
                   30,
                   31);
}


// Verify date is within allowed range
//    LoDate  : Low date range
//    MidDate : Date being checked (expected to be somewhere within the range)
//    HiDate  : High date range
//    Format  : Type of formatting to expect for validation:
//              * MM/DD/YYYY
//              Else, no validation performed.
// Returns int
//    -1 Unable to validate date(s)
//     0 Not within range
//     1 Within range
function DateWithinRange(LoDate, MidDate, HiDate, Format)
{
  var Lo  = 0;
  var Mid = 0;
  var Hi  = 0;


  // Error Check
  switch(Format.toUpperCase())
  {
    case 'MM/DD/YYYY':
      if(ValidDateUs8(LoDate) == 0 || ValidDateUs8(MidDate) == 0 || ValidDateUs8(HiDate) == 0)
        return -1;

    //default: // No error checking
  }

  Lo  = (new Date(LoDate)).getTime();
  Mid = (new Date(MidDate)).getTime();
  Hi  = (new Date(HiDate)).getTime();
  //alert(Lo + " Lo\n" + Mid + " Mid\n" + Hi + ' Hi');

  if(isNaN(Lo) || isNaN(Mid) || isNaN(Hi))
    return -1;

  if(Mid < Lo || Hi < Mid)
    return 0;
  else
    return 1;
}


function PopupCalcBodyFat(IdBodyFat)
{
  var Fat = 0;
  var Wut = '';


  Fat = CalcBodyFat();

  if(Fat > 0)
  {
    $('#' + IdBodyFat).val(Fat);
    HidePopupTrim();
    if($('#TrimWaistType').val() == 'Waist' && ParseInt($('#TrimWaistSize').val()) == 0)
    {
      $('#TrimWaistSize').val($('#CalcFatWaist').val());
      Wut = 'Updated <span class="b">body fat %</span> and <span class="b">Waist Size</span>.'
    }
    else
      Wut = 'Updated <span class="b">body fat %</span>.'

    PopupMsg(Wut);
  }
  else
    PopupMsg('Body fat is <span class="b">' + Fat + '%</span>!&nbsp;  Please check your numbers.');
}

// *Body Fat Formula* For Women
// Factor 1         (Total body weight x 0.732) + 8.987
// Factor 2         Wrist measurement (at fullest point) / 3.140
// Factor 3         Waist measurement (at naval) x 0.157
// Factor 4         Hip measurement (at fullest point) x 0.249
// Factor 5         Forearm measurement (at fullest point) x 0.434
// Lean Body Mass         Factor 1 + Factor 2 - Factor 3 - Factor 4 + Factor 5
// Body Fat Weight         Total bodyweight - Lean Body Mass
// *Body Fat Percentage*         (Body Fat Weight x 100) / total bodyweight
//  
// *Body Fat Formula* For Men
// Factor 1         (Total body weight x 1.082) + 94.42
// Factor 2         Waist measurement x 4.15
// Lean Body Mass         Factor 1 - Factor 2
// Body Fat Weight         Total bodyweight - Lean Body Mass
// *Body Fat Percentage*         (Body Fat Weight x 100) / total bodyweight
function CalcBodyFat()
{
  var Sex     = $('#CalcFatSex').val();
  var Weight  = Number($('#CalcFatWeight').val());
  var Wrist   = Number($('#CalcFatWrist').val());
  var Waist   = Number($('#CalcFatWaist').val());
  var Hip     = Number($('#CalcFatHip').val());
  var Forearm = Number($('#CalcFatForearm').val());
  var Factor1 = 0.0;
  var Factor2 = 0.0;
  var Factor3 = 0.0;
  var Factor4 = 0.0;
  var Factor5 = 0.0;
  var LBM = 0.0; // Lean Body Mass
  var BFW = 0.0; // Body Fat Weight
  var BFP = 0.0; // Body Fat Percentage
  var i = 0;
  var WtLabels = new Array('Wrist', 'Waist', 'Hip', 'Forearm');
  var WtWeight = new Array( Wrist,   Waist,   Hip,   Forearm);


  for(i = 0; i < 4; i++)
  {
    if(WtWeight[i] <= 0 || isNaN(WtWeight[i]))
    {
      PopupMsg('Please enter the ' + WtLabels[i] + ' measurement.');
      return 0;
    }
  }


  switch(Sex.toUpperCase())
  {
    case 'F':
      Factor1 = (Weight * 0.732) + 8.987;
      Factor2 = Wrist / 3.140;
      Factor3 = Waist * 0.157;
      Factor4 = Hip * 0.249;
      Factor5 = Forearm * 0.434;
      LBM = Factor1 + Factor2 - Factor3 - Factor4 + Factor5;
      BFW = Weight - LBM;
      BFP = (BFW * 100.0) / Weight;
      break;

    case 'M':
      Factor1 = (Weight * 1.082) + 94.42
      Factor2 = Waist * 4.15;
      LBM = Factor1 - Factor2;
      BFW = Weight - LBM;
      BFP = (BFW * 100.0) / Weight;
      break;

    default:
      PopupMsg('Sex = ' + Sex + ' is not a valid parameter!');
      return 0;
  }

  //alert(BFP + ' => ' + Math.round(BFP));
  return Math.round(BFP);
}


function PopupBodyFat(IdWeight)
{
  var Sex  = 'X';
  var Mate = 'X';
  var Weight = 0.0;
  var Fat = 0;
  var i = 0;
  var FemOnly = new Array('Wrist', 'Hip', 'Forearm');


  if(IdWeight == 'TrimWeight')
  {
    if($('#FieldSex :checked').length == 0) // input:radio:checked - Unknown pseudo-class or pseudo-element 'radio'
    {
      PopupMsg('Please indicate Sex.');
      return;
    }
    Sex = $('#FieldSex :checked').val(); // input:radio:checked - Unknown pseudo-class or pseudo-element 'radio'

    // Hide N/A fat measurements
    if(Sex == 'M')
      Mate = 'F';
    else
      Mate = 'M';
    $('.FatTable .' + Mate).each(function(j)
    {
      $(this).addClass('hidden');
    });

    // Unhide relevent fat measurements
    $('.FatTable .' + Sex).each(function(j)
    {
      $(this).removeClass('hidden');
    });
  }
  else
    Sex = $('#Sex').val();

  Weight = Number($('#' + IdWeight).val());
  if(Weight <= 0 || isNaN(Weight))
  {
    PopupMsg('Please enter the current weight.');
    return;
  }


  $('#CalcFatSex').val(Sex);
  $('#CalcFatWeight').val(Weight);

  if(Sex == 'F')
  {
    for(i = 0; i < FemOnly.length; i++)
    {
      $('#CalcFat' + FemOnly[i]).parent().parent().removeClass('hidden');
      $('#CalcFat' + FemOnly[i]).val('');
    }
  }
  else
  {
    for(i = 0; i < FemOnly.length; i++)
    {
      $('#CalcFat' + FemOnly[i]).parent().parent().addClass('hidden');
      $('#CalcFat' + FemOnly[i]).val(32767);
    }
  }
  if($('#TrimWaistType').val() == 'Waist')
    $('#CalcFatWaist').val($('#TrimWaistSize').val());
  else
    $('#CalcFatWaist').val('');


  ShowPopup('CalcBodyFat');
}

function HidePopupTrim()
{
  //if($('#PopupTrimProcessing').is(':visible'))
  //  return;

  if($('#PopupMsgBox').is(':visible'))
  {
    $('#PopupMsgBox').fadeOut('fast');

    // If other prompts are visible, keep them visible

    if($('#PopupAdmin').is(':visible'))
      return;

    if($('#CalcBodyFat').is(':visible'))
      return;

    if($('#PopupContract').is(':visible'))
      return;

    if($('#PopupDeleteUser').is(':visible'))
      return;

    if($('#PopupMemberMail').is(':visible'))
      return;

    if($('#PopupMemberDay').is(':visible'))
      return;

    if($('#PopupMemberWeek').is(':visible'))
      return;

    if($('#PopupUploadAttachment').is(':visible'))
      return;

    if($('#PopupWithButtons').is(':visible'))
      return;
  }

  if($('#PopupAdmin').is(':visible'))
    $('#PopupAdmin').fadeOut('fast');

  if($('#CalcBodyFat').is(':visible'))
    $('#CalcBodyFat').fadeOut('fast');

  if($('#PopupContract').is(':visible'))
    $('#PopupContract').fadeOut('fast');

  if($('#PopupDeleteUser').is(':visible'))
  {
    if($('#PopupDeleteUserEscapable').val() == 1)
      $('#PopupDeleteUser').fadeOut('fast');
    else
      return;
  }

  if($('#PopupMemberDay').is(':visible'))
    $('#PopupMemberDay').fadeOut('fast');

  if($('#PopupMemberMail').is(':visible'))
    $('#PopupMemberMail').fadeOut('fast');

  if($('#PopupMemberWeek').is(':visible'))
    $('#PopupMemberWeek').fadeOut('fast');

  if($('#PopupUploadAttachment').is(':visible'))
  {
    if($('#btnUploadFile').attr('disabled') == true)
      return;

    $('#PopupUploadAttachment').fadeOut('fast');
  }

  if($('#PopupWithButtons').is(':visible'))
    $('#PopupWithButtons').fadeOut('fast');

  // Remove "faded background"
  $('#PopupBlanket').fadeOut('fast');
}

/*
function HidePopupProcessing(HideBlanket)
{
  if($('#PopupTrimProcessing').is(':visible'))
    $('#PopupTrimProcessing').fadeOut('fast');

  if(HideBlanket == true)
    $('#PopupBlanket').fadeOut('fast');
}
*/

function ShowPopup(PromptName)
{
  var wW = document.documentElement.clientWidth;
  var wH = document.documentElement.clientHeight;
  var pW = $('#' + PromptName).width();
  var pH = $('#' + PromptName).height();


  // Center prompt
  $('#' + PromptName).css(
  {
    'position'  : 'fixed',
    'top'       : (wH / 2) - (pH / 2),
    'left'      : (wW / 2) - (pW / 2)
  });

  //alert(wW + ',' + wH);

  // Display prompt
  //$('#' + PromptName).css('z-index', 32767);
  $('#PopupBlanket').css(
  {
    'opacity' : '0.7'
  });
  $('#PopupBlanket').fadeIn('fast');
  $('#' + PromptName).fadeIn('fast');
}

// Display a popup message on Trim.php; alternative to alert()
function PopupMsg(TheMsg)
{
  //$('#PopupMsgTitle').html('TRIM Consultation');
  $('#PopupMsgText').html(TheMsg);

  ShowPopup('PopupMsgBox');

  $('#btnTrimOkay').focus();
}

// Display a popup message on Trim.php, with buttons; alternative to alert()
function PopupBtn(TheMsg, TheButtons, SetFocusOnThis)
{
  $('#PopupBtnText').html(TheMsg);
  $('#PopupButtons').html(TheButtons);

  ShowPopup('PopupWithButtons');

  $('#' + SetFocusOnThis).focus();
}

// Left-Pad a string with specified characters
//    TheString : The string to pad
//    length    : Minimum string length
//    TheChar   : Character(s) to use to pad string
// Returns
//    string PaddedString
function PadLeft(TheString, length, TheChar)
{
  var Shemp = '' + TheString; // force to string if numeric


  while(Shemp.length < length)
    Shemp = TheChar + Shemp;

  return Shemp;
}

// Ping server to keep session alive
function Ping()
{
  AjaxSetText('Ping', SinkDepth(GetDepth()) + 'include/GuruBioAjaxPing.php', new Array());
}


// Generate an explanitory error message if an input string is too long.
//    string $PrintName : Identifier to display to user.
//    string $TheString : String to check.
//    int    $MaxLength : Maximum allowed length
// Returns a message if $MaxLength is exceeded, else returns empty string.
function TooMuchChar(PrintName, TheString, MaxLength, UseHtml)
{
  //alert(PrintName + "\n" + TheString + "\n" + MaxLength);
  if(TheString.length > MaxLength)
  {
    if(UseHtml == true)
      return '<span class="b">' + PrintName + '</span> is ' + (TheString.length - MaxLength) + ' characters too long! (Maximum length is ' + MaxLength + ' characters.)<br/>' + "\n";
    else
      return PrintName + ' is ' + (TheString.length - MaxLength) + ' characters too long! (Maximum length is ' + MaxLength + ' characters.)' + "\n";
  }
  else
    return '';
}


// Turn a date into an 8-digit integer (as string)
function DateInt(Year, Month, Day)
{
  return PadLeft(Year, 2, '0') + PadLeft(Month, 2, '0') + PadLeft(Day, 2, '0');
}


// Calculate Age based on current date
//    int $DobInt : Date of birth: YYYYMMDD
function CalcAge(DobInt)
{
  var Age   = 0;
  var DOBy = 0;
  var DOBm = 0;
  var DOBd = 0;
  var ThisDate = new Date();
  var ThisMonth = ThisDate.getMonth() + 1;
  var ThisDay   = ThisDate.getDate();


  // Get age by difference in years
  DOBy = ParseInt(DobInt.substr(0, 4));
  Age = ThisDate.getFullYear() - DOBy;

  // Has this year's birthday passed already? If not, decrement age
  DOBm = ParseInt(DobInt.substr(4, 2));
  DOBd = ParseInt(DobInt.substr(6, 2));
  if(DOBm > ThisMonth)
    Age--;
  else if(DOBm == ThisMonth)
    if(DOBd > ThisDay)
      Age--;


  return Age;
}


// Parse a string to an integer.  Written because parseInt FAILS
// if there are leading zeros:  parseInt('08') == 0
// Floats are truncated at the decimal (this is a property of parseInt).
// (Needs more robust handling for figures like '-0042' which is interpreted as -34)
//    various $TheInt   : Value to handle
//    bool    $AllowNaN : Set to true to preseve NaN, else NaN is changed to 0.
// Returns
//    int $TheInt
function ParseInt(TheInt, AllowNaN)
{
  var Shemp = '';
  var i = 0;
  var j = -1;


  // Force value to string type
  Shemp = trim(' ' + TheInt);

  // Locate end position of leading zeros, if any
  for(i = 0; i < Shemp.length; i++)
  {
    if(Shemp.charAt(i) != '0')
    {
      j = i;
      break;
    }
  }

  // Remove leading zeros
  if(j > -1)
    Shemp = Shemp.substring(j, Shemp.length);

  // Figure should now be safe for traditional parseInt
  i = parseInt(Shemp);

  // Allow NaN? Or do we NOT CARE?
  if(AllowNaN != true && isNaN(i))
    i = 0;


  return i;
}


// Parse a string to a float.  Written because parseFloat FAILS
// if contains non-numerics:  parseInt('') == NaN
//    various $TheFloat : Value to handle
//    bool    $AllowNaN : Set to true to preseve NaN, else NaN is changed to 0.0
// Returns
//    float $TheFloat
function ParseFloat(TheFloat, AllowNaN)
{
  var i = 0.0;


  // Figure should now be safe for traditional parseFloat
  i = parseFloat(TheFloat);

  // Allow NaN? Or do we NOT CARE?
  if(AllowNaN != true && isNaN(i))
    i = 0.0;


  return i;
}


function BinaryBool(TrueFalse)
{
  if(TrueFalse == true)
    return 1;
  else
    return 0;
}

// Invert a boolean value
//    various $BoolValue : Something to the effect of 'true' or 'false'
// Returns
//    bool $InvertedBooleanValue
function AntiBool(InvertMe)
{
  switch((InvertMe + '').toLowerCase())
  {
    case 'true':
    case '1':
    case 'on':
      return false;
    default:
      return true;
  }
}


// Set precision of a floating-point value, for string output.
// Rounds up if truncated digit is 5 or greater!
// Precision defaults to 0.
function RoundFloat(TheFloat, Precision)
{
  var Shemp = TheFloat.toString();
  var prec  = 0; // desired Precision
  var digs  = 0; // actual count of Digits on right of decimal
  var i     = 0;
  var j     = 0;
  var carry = false;


  // Set default argument value
  if(!Precision)
    var Precision = 0;


  // Set precision; no fool billy negatives!
  if(Precision < 0)
    prec = 0;
  else
    prec = Precision;


  // Ensure decimal point is preceeded by a digit
  if(Shemp.charAt(0) == '.')
    Shemp = '0' + Shemp;


  // Locate decimal point
  i = Shemp.indexOf('.');


  // Check for absent decimal
  if(i == -1)
  {
    if(prec == 0)
      return Shemp;
    else
    {
      Shemp += '.';
      i = Shemp.indexOf('.');
    }
  }


  // Get current floating-point precision (how many digits are already there)
  digs = (Shemp.length - 1) - i;


  if(digs > prec) // too many digits
  {
    // Round if applicable
    if(ParseInt(Shemp.charAt(i + 1 + prec)) >= 5)
      carry = true;
    //else
    //  carry = false;

    if(carry == true)
    for(j = i + prec; j >= 0; j--)
    {
      switch(Shemp.charAt(j))
      {
        case '.':
          break;

        case '9':
          Shemp = Shemp.substr(0, j) + '0' + Shemp.substr(j + 1);
          if(j == 0) // Need another leading digit
          {
            Shemp = '1' + Shemp;
            i++; // increase the offset
          }
          break;

        default: // 0 thru 8
          Shemp = Shemp.substr(0, j) + (ParseInt(Shemp.charAt(j)) + 1).toString() + Shemp.substr(j + 1);
          j = 0; // break the loop
      }
    }


    if(prec == 0) // truncate decimal point as well
      Shemp = Shemp.substr(0, i);
    else
      Shemp = Shemp.substr(0, i + 1 + prec);
  }
  else // not enough digits
    Shemp = Shemp + strFill(prec - digs, '0');


  // Lead with zero if less than 1.0 and greater than -1.0
  if(Shemp.charAt(0) == '.')
    Shemp = '0' + Shemp;
  else if(Shemp.substr(0, 2) == '-.')
    Shemp = '-0.' + Shemp.substr(2);


  return Shemp;
}



// A workaround for using jQuery plugin a-tools 1.2 since it didn't occur to the auther to
// let replaceSelection replace a zero-length selection.
//    string $ObjId  : Typical jQuery object reference
//    string $InsVal : Text to be inserted
function ReplaceSelection(ObjId, InsVal)
{
  if($(ObjId).getSelection().length == null)
    $(ObjId).insertAtCaretPos(InsVal);
  else
    $(ObjId).replaceSelection(InsVal);
}


// Make English-language nouns plural by adding an 's' if not euqal to one.
//    int $Quantity : Quantity to check for plurality.
// Returns 's' if plural, else ''.
function Plural(Quantity)
{
  if(Quantity != 1)
    return 's';
  else
    return '';
}

// Conjegate the English verb "to be" based on third-person quantity.
//    int $Quantity : Quantity to check for plurality.
// Returns 'are' if plural, else 'is'.
function PluralBe(Quantity)
{
  if(Quantity != 1)
    return 'are';
  else
    return 'is';
}



// Return a string left-padded with enough occurances of '&nbsp;' to display
// a required string length in HTML.
function LeftPadNbsp(TheString, MinLength)
{
  var i = 0;
  var j = 0;
  var Shemp = '';


  j = MinLength - (TheString + '').length;
  for(i = 0; i < j; i++)
  {
    Shemp += '&nbsp;';
  }

  return Shemp + TheString;
}

// Sanitize string for URL posting:  Anything that isn't alpha-numeric is converted to %HEXADECIMAL.
// Returns
//    string $SanitizedString
function SanitizeForPost(TheString)
{
  var i = 0;
  var CharVal = 0;


  for(i = TheString.length - 1; i >= 0; i--)
  {
    CharVal = TheString.charCodeAt(i);

    if(CharVal < 48 ||
                      (57 < CharVal && CharVal < 65) ||
                                                        CharVal > 122)
      TheString = TheString.substr(0, i) + '%' + DecToHex(CharVal) + TheString.substr(i + 1);
  }


  return TheString;
}


// Convert Decimal to Hexadecimal
function DecToHex(Dec)
{
  return Dec.toString(16);
}

// Convert Hexadecimal to Decimal
function HexToDec(Hex)
{
  return parseInt(Hex,16);
}


function WeekDays()
{
  var TheDays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];

  return TheDays;
}

function WeekDay(DayNum)
{
  var TheDays = WeekDays();

  return TheDays[DayNum];
}


function FunctionNotFound(TheFunc)
{
  alert("That code hasn't been written yet:\n\n" + TheFunc +
        "\n\nIn the meantime, this is acting as a placeholder.");
}


// Get the opposite dietary action of Lose/Gain
function InvertLoseGain(LoseGain)
{
  if(LoseGain == 'Gain')
    return 'Lose';
  else
    return 'Gain';
}


// Similar to PHP's print_r, returns a string displaying a tree-like breakdown
// of an array's contents.
//    array  ArrArg   => Array to examin.
//    int    ArrDepth => Used internally to track depth of recursion; leave as null when calling manually.
//
// Example output:
//
// Array
// (
//     [0] => Array
//     (
//         [0] => -1003
//         [1] => -1516
//     )
//     [1] => Array
//     (
//         [0] => 473
//         [1] => 174
//     )
// )
function print_r(ArrArg, ArrDepth)
{
  var l   = 0;  // Array Length
  var i   = 0;  // Array Index
  var d   = 0;  // Array depth (i.e. an array within an array?)
  var s   = ''; // String
  var tab = ''; // whitespace tabbing


  // Get Array Length
  l = ArrArg.length;

  // Get Array Depth
  if(ArrDepth != null)
    d = ArrDepth;

  // Set tabbing length
  tab = strFill(4 * d, '    ');


  s = "Array\n" +
      tab + "(\n";
  while(i < l)
  {
    s += '    ' + tab + '[' + i + '] => ';
    if(isArray(ArrArg[i]))
      s += print_r(ArrArg[i], d + 1); // recursion!
    else
      s += ArrArg[i] + "\n";
    i++;
  }
  s += tab + ")\n";


  return s;
}

// Determine whether object is an array.
// Returns:
//    boolean
function isArray(obj)
{
  if(obj.constructor.toString().indexOf('Array') == -1)
    return false;
  else
    return true;
}

// Return a string of a given length, padding using the input string.
//    int    strLength => target string length
//    string strFiller => character or string to use as filler.  Default is whitespace.
// Returns:
//    string
function strFill(strLength, strFiller)
{
  var s = '';
  var f = ' '; // default if no filler is provided.


  // Set Filler
  if(strFiller.length > 0)
    f = strFiller;

  // Fill string
  while(s.length < strLength)
    s += f;

  // Truncate if too long
  if(s.length > strLength)
    return s.substring(0, strLength);
  else
    return s;
}


// Extract $_GET arguments from a URL and split them to an array.
//    string $Url : URL to evaluate
// Returns
//    array $Args[int $ArrayIndex] => [0] => string $Key
//                                    [1] => string $Value
// Notes:
//   * Seeks for '?' to find start of arguments.
//   * Splits primarily on '&'.
//   * Splits secondarily on '='.
function ParseUrlArgs(Url)
{
  var i = 0;
  var j = 0;
  var Args = new Array();
  var Boom = null;
  var Bang = null;


  i = Url.indexOf('?');
  Boom = (Url.substr(i + 1)).split('&');
  //alert(print_r(Boom));

  j = Boom.length;
  for(i = 0; i < j; i++)
  {
    Bang = Boom[i].split('=');
    Args[i] = new Array(Bang[0], Bang[1]);
  }
  //alert(print_r(Args));


  return Args;
}


// Cut filename from path
//    string $Pathname : File path
// Returns
//    string $OnlyDirectoryPath
function GetOnlyDir(Pathname)
{
    var Slash = 0; // Position of backslash
    
    
    Slash = Pathname.lastIndexOf('/');
    
    if(Slash == -1) // No path; just filename
        return('');
    
    return(Pathname.substr(0, Pathname.length - (Pathname.length - Slash - 1))); // include terminating slash
}


// Verify that a phone number contains the minimum number of digits.
//    string $Num : Phone number to check
// Returns
//    bool $MeetsRequirement
function PhoneHasMinDigits(Num)
{
  var MinDigits = 10; // Current U.S. requirement:  (123)456-7890
  var Hits = 0;
  var i = 0;
  var d = 0; // digits
  var c = '?';


  for(i = 0; i < Num.length; i++)
  {
    c = Num.charAt(i);
    if('0' <= c && c <= '9')
      d++;
  }

  if(d >= MinDigits)
    return true;
  else
    return false;
}

// Reformat phone number for people who are too lazy to type in dashes
//    string $Num : Phone number to format
// Returns
//    string $FormatedNumber
// If input contains only numbers:
//    * If contains 10 digits, formats to (###)###-####
//    * If contains 11 digits, formats to #(###)###-####
//    * If contains more than 11 digits, formats to #(###)###-#### ####....
//    * Else, no formatting
// Else, no formatting.
function LazyPhone(Num)
{
  var i = 0;
  var d = 0; // digits
  var o = 0; // other
  var t = 0; // offset
  var c = '?';
  var NewNum = '';


  for(i = 0; i < Num.length; i++)
  {
    c = Num.charAt(i);
    if('0' <= c && c <= '9')
      d++; // count numbers
    else
      o++; // count non-numbers
  }


  if(o > 0) // Assume user has already formatted number
    return NewNum = Num;
  else // String contains only numbers
  {
    if(Num.length == 10) // (###)###-####
      NewNum = '(' + Num.substr(0, 3) + ')' + Num.substr(3, 3) + '-' + Num.substr(6);
    else if(Num.length == 11) // #(###)###-####
      NewNum = Num.substr(0, 1) + '(' + Num.substr(1, 3) + ')' + Num.substr(4, 3) + '-' + Num.substr(7);
    else if(Num.length > 11) // #(###)###-#### #####...
    {
      if(Num.charAt(0) == '1')
      {
        NewNum = '1';
        t = 1; // use an offset
      }
      NewNum += '(' + Num.substr(t, 3) + ')' + Num.substr(3 + t, 3) + '-' + Num.substr(6 + t, 4) + ' ' + Num.substr(10 + t);
    }
    else // length < 10
      NewNum = Num;
  }


  return NewNum;
}


// Generate integer representation (as string) of today's Date and time in the form of YYYYMMDDHHmmSS.
// Returns
//    string $DateAndTime
function getTodayDateTimeInt()
{
  var Datum = new Date(); // German: Datum = date
  var Shemp = '';


  Shemp = Datum.getFullYear() + '' +
          PadLeft(Datum.getMonth() + 1, 2, '0') +
          PadLeft(Datum.getDate(), 2, '0') +
          PadLeft(Datum.getHours(), 2, '0') +
          PadLeft(Datum.getMinutes(), 2, '0') +
          PadLeft(Datum.getSeconds(), 2, '0');

  return Shemp;
}

// Generate integer representation of today's Date in the form of YYYYMMMDD.
// Returns
//    int $DateAsInteger
function getTodayDateInt()
{
  return ParseInt(getTodayDateTimeInt().substr(0, 8));
}


function ToggleHelpBoxSlide()
{
  $('#HelpSlider').slideToggle('fast', function()
  {
    $('#HelpBox').slideToggle('slow', function()
    {
      $('#HelpSlider').slideToggle('slow');
    });
  });
}


// Expand page width to 1010 pixels
function WideTemplate()
{
  $('#wrapper').addClass('wide');
  $('#topLinksBody').addClass('wide');
  $('#topLinksBodyAdmin').addClass('wide');
  $('.topLinksCenter').addClass('wide');
  $('#bodyContent').addClass('wide');
  $('#bodyDivCenter').addClass('wide');
  $('#footSpace').addClass('wide');
}



/* doesn't quite work...
function InitInputRestrictions(Enforce)
{
  var i = 0;
  var j = 0;


  j = Enforce.length;

  for(i = 0; i < j; i++)
  {
    switch(Enforce[i].toLowerCase())
    {
      case 'intpos': // Integer, Positive
        $('.intpos').keyup(function(e)
        {
          //this.value = this.value.replace('/[^0-0\.]g', '');
          alert(e.keyCode);
          return false;
        });
    }
  }
}
*/
