/***********************************************************
@# file : md5.js
#  modified date : 07/09/09
/***********************************************************/



/*
 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
 * Digest Algorithm, as defined in RFC 1321.
 * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for more info.
 */

/*
 * Configurable variables. You may need to tweak these to be compatible with
 * the server-side, but the defaults work in most cases.
 */
var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */
var chrsz   = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode      */

/*
 * These are the functions you'll usually want to call
 * They take string arguments and return either hex or base-64 encoded strings
 */
function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}
function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }

/*
 * Perform a simple self-test to see if the VM is working
 */
function md5_vm_test()
{
  return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
}

/*
 * Calculate the MD5 of an array of little-endian words, and a bit length
 */
function core_md5(x, len)
{
  /* append padding */
  x[len >> 5] |= 0x80 << ((len) % 32);
  x[(((len + 64) >>> 9) << 4) + 14] = len;

  var a =  1732584193;
  var b = -271733879;
  var c = -1732584194;
  var d =  271733878;

  for(var i = 0; i < x.length; i += 16)
  {
    var olda = a;
    var oldb = b;
    var oldc = c;
    var oldd = d;

    a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
    d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
    c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
    b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
    a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
    d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
    c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
    b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
    a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
    d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
    c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
    b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
    a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
    d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
    c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
    b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);

    a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
    d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
    c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
    b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
    a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
    d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
    c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
    b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
    a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
    d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
    c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
    b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
    a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
    d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
    c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
    b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);

    a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
    d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
    c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
    b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
    a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
    d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
    c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
    b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
    a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
    d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
    c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
    b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
    a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
    d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
    c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
    b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);

    a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
    d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
    c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
    b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
    a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
    d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
    c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
    b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
    a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
    d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
    c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
    b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
    a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
    d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
    c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
    b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);

    a = safe_add(a, olda);
    b = safe_add(b, oldb);
    c = safe_add(c, oldc);
    d = safe_add(d, oldd);
  }
  return Array(a, b, c, d);

}

/*
 * These functions implement the four basic operations the algorithm uses.
 */
function md5_cmn(q, a, b, x, s, t)
{
  return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
}
function md5_ff(a, b, c, d, x, s, t)
{
  return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function md5_gg(a, b, c, d, x, s, t)
{
  return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function md5_hh(a, b, c, d, x, s, t)
{
  return md5_cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5_ii(a, b, c, d, x, s, t)
{
  return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
}

/*
 * Calculate the HMAC-MD5, of a key and some data
 */
function core_hmac_md5(key, data)
{
  var bkey = str2binl(key);
  if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);

  var ipad = Array(16), opad = Array(16);
  for(var i = 0; i < 16; i++)
  {
    ipad[i] = bkey[i] ^ 0x36363636;
    opad[i] = bkey[i] ^ 0x5C5C5C5C;
  }

  var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
  return core_md5(opad.concat(hash), 512 + 128);
}

/*
 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
 * to work around bugs in some JS interpreters.
 */
function safe_add(x, y)
{
  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  return (msw << 16) | (lsw & 0xFFFF);
}

/*
 * Bitwise rotate a 32-bit number to the left.
 */
function bit_rol(num, cnt)
{
  return (num << cnt) | (num >>> (32 - cnt));
}

/*
 * Convert a string to an array of little-endian words
 * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
 */
function str2binl(str)
{
  var bin = Array();
  var mask = (1 << chrsz) - 1;
  for(var i = 0; i < str.length * chrsz; i += chrsz)
    bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
  return bin;
}

/*
 * Convert an array of little-endian words to a string
 */
function binl2str(bin)
{
  var str = "";
  var mask = (1 << chrsz) - 1;
  for(var i = 0; i < bin.length * 32; i += chrsz)
    str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
  return str;
}

/*
 * Convert an array of little-endian words to a hex string.
 */
function binl2hex(binarray)
{
  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
  var str = "";
  for(var i = 0; i < binarray.length * 4; i++)
  {
    str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
           hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
  }
  return str;
}

/*
 * Convert an array of little-endian words to a base-64 string
 */
function binl2b64(binarray)
{
  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  var str = "";
  for(var i = 0; i < binarray.length * 4; i += 3)
  {
    var triplet = (((binarray[i   >> 2] >> 8 * ( i   %4)) & 0xFF) << 16)
                | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
                |  ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
    for(var j = 0; j < 4; j++)
    {
      if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
      else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
    }
  }
  return str;
}

/***********************************************************************************/
/***********************************************************************************/
/* file : Crypt.js
    purpose: has algorithms for encryption as well as decryption.
    author : muthu
    */
/***********************************************************************************/    
    
var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

/* This funciton uses base64 algoritm for encoding*/

function encode64(input) 
{
   var output = "";
   var chr1, chr2, chr3;
   var enc1, enc2, enc3, enc4;
   var i = 0;

   do {
      chr1 = input.charCodeAt(i++);
      chr2 = input.charCodeAt(i++);
      chr3 = input.charCodeAt(i++);

      enc1 = chr1 >> 2;
      enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
      enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
      enc4 = chr3 & 63;

      if (isNaN(chr2)) {
         enc3 = enc4 = 64;
      } else if (isNaN(chr3)) {
         enc4 = 64;
      }

      output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + 
         keyStr.charAt(enc3) + keyStr.charAt(enc4);
   } while (i < input.length);
   
   return output;
}

/* This funciton uses base64 algoritm for decoding*/
function decode64(input) 
{
   var output = "";
   var chr1, chr2, chr3;
   var enc1, enc2, enc3, enc4;
   var i = 0;

   // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
   input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

   do {
      enc1 = keyStr.indexOf(input.charAt(i++));
      enc2 = keyStr.indexOf(input.charAt(i++));
      enc3 = keyStr.indexOf(input.charAt(i++));
      enc4 = keyStr.indexOf(input.charAt(i++));

      chr1 = (enc1 << 2) | (enc2 >> 4);
      chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
      chr3 = ((enc3 & 3) << 6) | enc4;

      output = output + String.fromCharCode(chr1);

      if (enc3 != 64) {
         output = output + String.fromCharCode(chr2);
      }
      if (enc4 != 64) {
         output = output + String.fromCharCode(chr3);
      }
   } while (i < input.length);

   return output;
}



/**************************************************************************************
@file : calendarDateInput.js
/***********************************************
 Fool-Proof Date Input Script with DHTML Calendar
 by Jason Moon - calendar@moonscript.com
 ************************************************/

// Customizable variables
var DefaultDateFormat = 'MM/DD/YYYY'; // If no date format is supplied, this will be used instead
var HideWait = 3; // Number of seconds before the calendar will disappear
var Y2kPivotPoint = 76; // 2-digit years before this point will be created in the 21st century
var UnselectedMonthText = ''; // Text to display in the 1st month list item when the date isn't required
var FontSize = 11; // In pixels
var FontFamily = 'Tahoma';
var CellWidth = 18;
var CellHeight = 16;
var ImageURL = '../images/calendar.gif';
var NextURL = '../images/arrows.gif';
var PrevURL = '../images/back_arrow.gif';
var CalBGColor = 'white';
var TopRowBGColor = 'buttonface';
var DayBGColor = 'lightgrey';

// Global variables
var ZCounter = 100;
var Today = new Date();
var WeekDays = new Array('S','M','T','W','T','F','S');
var MonthDays = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
var MonthNames = new Array('January','February','March','April','May','June','July','August','September','October','November','December');

// Write out the stylesheet definition for the calendar
with (document) {
   writeln('<style>');
   writeln('td.calendarDateInput {letter-spacing:normal;line-height:normal;font-family:' + FontFamily + ',Sans-Serif;font-size:' + FontSize + 'px;}');
   writeln('select.calendarDateInput {letter-spacing:.06em;font-family:Verdana,Sans-Serif;font-size:11px;}');
   writeln('input.calendarDateInput {letter-spacing:.06em;font-family:Verdana,Sans-Serif;font-size:11px;}');
   writeln('</style>');
}

// Only allows certain keys to be used in the date field
function YearDigitsOnly(e) {
   var KeyCode = (e.keyCode) ? e.keyCode : e.which;
   return ((KeyCode == 8) // backspace
        || (KeyCode == 9) // tab
        || (KeyCode == 37) // left arrow
        || (KeyCode == 39) // right arrow
        || (KeyCode == 46) // delete
        || ((KeyCode > 47) && (KeyCode < 58)) // 0 - 9
   );
}

// Gets the absolute pixel position of the supplied element
function GetTagPixels(StartTag, Direction) {
   var PixelAmt = (Direction == 'LEFT') ? StartTag.offsetLeft : StartTag.offsetTop;
   while ((StartTag.tagName != 'BODY') && (StartTag.tagName != 'HTML')) {
      StartTag = StartTag.offsetParent;
      PixelAmt += (Direction == 'LEFT') ? StartTag.offsetLeft : StartTag.offsetTop;
   }
   return PixelAmt;
}

// Is the specified select-list behind the calendar?
function BehindCal(SelectList, CalLeftX, CalRightX, CalTopY, CalBottomY, ListTopY) {
   var ListLeftX = GetTagPixels(SelectList, 'LEFT');
   var ListRightX = ListLeftX + SelectList.offsetWidth;
   var ListBottomY = ListTopY + SelectList.offsetHeight;
   return (((ListTopY < CalBottomY) && (ListBottomY > CalTopY)) && ((ListLeftX < CalRightX) && (ListRightX > CalLeftX)));
}

// For IE, hides any select-lists that are behind the calendar
function FixSelectLists(Over) {
   if (navigator.appName == 'Microsoft Internet Explorer') {
      var CalDiv = this.getCalendar();
      var CalLeftX = CalDiv.offsetLeft;
      var CalRightX = CalLeftX + CalDiv.offsetWidth;
      var CalTopY = CalDiv.offsetTop;
      var CalBottomY = CalTopY + (CellHeight * 9);
      var FoundCalInput = false;
      formLoop :
      for (var j=this.formNumber;j<document.forms.length;j++) {
         for (var i=0;i<document.forms[j].elements.length;i++) {
            if (typeof document.forms[j].elements[i].type == 'string') {
               if ((document.forms[j].elements[i].type == 'hidden') && (document.forms[j].elements[i].name == this.hiddenFieldName)) {
                  FoundCalInput = true;
                  i += 3; // 3 elements between the 1st hidden field and the last year input field
               }
               if (FoundCalInput) {
                  if (document.forms[j].elements[i].type.substr(0,6) == 'select') {
                     ListTopY = GetTagPixels(document.forms[j].elements[i], 'TOP');
                     if (ListTopY < CalBottomY) {
                        if (BehindCal(document.forms[j].elements[i], CalLeftX, CalRightX, CalTopY, CalBottomY, ListTopY)) {
                           document.forms[j].elements[i].style.visibility = (Over) ? 'hidden' : 'visible';
                        }
                     }
                     else break formLoop;
                  }
               }
            }
         }
      }
   }
}

// Displays a message in the status bar when hovering over the calendar days
function DayCellHover(Cell, Over, Color, HoveredDay) {
   Cell.style.backgroundColor = (Over) ? DayBGColor : Color;
   if (Over) {
      if ((this.yearValue == Today.getFullYear()) && (this.monthIndex == Today.getMonth()) && (HoveredDay == Today.getDate())) self.status = 'Click to select today';
      else {
         var Suffix = HoveredDay.toString();
         switch (Suffix.substr(Suffix.length - 1, 1)) {
            case '1' : Suffix += (HoveredDay == 11) ? 'th' : 'st'; break;
            case '2' : Suffix += (HoveredDay == 12) ? 'th' : 'nd'; break;
            case '3' : Suffix += (HoveredDay == 13) ? 'th' : 'rd'; break;
            default : Suffix += 'th'; break;
         }
         self.status = 'Click to select ' + this.monthName + ' ' + Suffix;
      }
   }
   else self.status = '';
   return true;
}

// Sets the form elements after a day has been picked from the calendar
function PickDisplayDay(ClickedDay) {
   this.show();
   var MonthList = this.getMonthList();
   var DayList = this.getDayList();
   var YearField = this.getYearField();
   FixDayList(DayList, GetDayCount(this.displayed.yearValue, this.displayed.monthIndex));
   // Select the month and day in the lists
   for (var i=0;i<MonthList.length;i++) {
      if (MonthList.options[i].value == this.displayed.monthIndex) MonthList.options[i].selected = true;
   }
   for (var j=1;j<=DayList.length;j++) {
      if (j == ClickedDay) DayList.options[j-1].selected = true;
   }
   this.setPicked(this.displayed.yearValue, this.displayed.monthIndex, ClickedDay);
   // Change the year, if necessary
   YearField.value = this.picked.yearPad;
   YearField.defaultValue = YearField.value;
}

// Builds the HTML for the calendar days
function BuildCalendarDays() {
   var Rows = 5;
   if (((this.displayed.dayCount == 31) && (this.displayed.firstDay > 4)) || ((this.displayed.dayCount == 30) && (this.displayed.firstDay == 6))) Rows = 6;
   else if ((this.displayed.dayCount == 28) && (this.displayed.firstDay == 0)) Rows = 4;
   var HTML = '<table width="' + (CellWidth * 7) + '" cellspacing="0" cellpadding="1" style="cursor:default">';
   for (var j=0;j<Rows;j++) {
      HTML += '<tr>';
      for (var i=1;i<=7;i++) {
         Day = (j * 7) + (i - this.displayed.firstDay);
         if ((Day >= 1) && (Day <= this.displayed.dayCount)) {
            if ((this.displayed.yearValue == this.picked.yearValue) && (this.displayed.monthIndex == this.picked.monthIndex) && (Day == this.picked.day)) {
               TextStyle = 'color:white;font-weight:bold;'
               BackColor = DayBGColor;
            }
            else {
               TextStyle = 'color:black;'
               BackColor = CalBGColor;
            }
            if ((this.displayed.yearValue == Today.getFullYear()) && (this.displayed.monthIndex == Today.getMonth()) && (Day == Today.getDate())) TextStyle += 'border:1px solid darkred;padding:0px;';
            HTML += '<td align="center" class="calendarDateInput" style="cursor:default;height:' + CellHeight + ';width:' + CellWidth + ';' + TextStyle + ';background-color:' + BackColor + '" onClick="' + this.objName + '.pickDay(' + Day + ')" onMouseOver="return ' + this.objName + '.displayed.dayHover(this,true,\'' + BackColor + '\',' + Day + ')" onMouseOut="return ' + this.objName + '.displayed.dayHover(this,false,\'' + BackColor + '\')">' + Day + '</td>';
         }
         else HTML += '<td class="calendarDateInput" style="height:' + CellHeight + '">&nbsp;</td>';
      }
      HTML += '</tr>';
   }
   return HTML += '</table>';
}

// Determines which century to use (20th or 21st) when dealing with 2-digit years
function GetGoodYear(YearDigits) {
   if (YearDigits.length == 4) return YearDigits;
   else {
      var Millennium = (YearDigits < Y2kPivotPoint) ? 2000 : 1900;
      return Millennium + parseInt(YearDigits,10);
   }
}

// Returns the number of days in a month (handles leap-years)
function GetDayCount(SomeYear, SomeMonth) {
   return ((SomeMonth == 1) && ((SomeYear % 400 == 0) || ((SomeYear % 4 == 0) && (SomeYear % 100 != 0)))) ? 29 : MonthDays[SomeMonth];
}

// Highlights the buttons
function VirtualButton(Cell, ButtonDown) {
   if (ButtonDown) {
      Cell.style.borderLeft = 'buttonshadow 1px solid';
      Cell.style.borderTop = 'buttonshadow 1px solid';
      Cell.style.borderBottom = 'buttonhighlight 1px solid';
      Cell.style.borderRight = 'buttonhighlight 1px solid';
   }
   else {
      Cell.style.borderLeft = 'buttonhighlight 1px solid';
      Cell.style.borderTop = 'buttonhighlight 1px solid';
      Cell.style.borderBottom = 'buttonshadow 1px solid';
      Cell.style.borderRight = 'buttonshadow 1px solid';
   }
}

// Mouse-over for the previous/next month buttons
function NeighborHover(Cell, Over, DateObj) {
   if (Over) {
      VirtualButton(Cell, false);
      self.status = 'Click to view ' + DateObj.fullName;
   }
   else {
      Cell.style.border = 'buttonface 1px solid';
      self.status = '';
   }
   return true;
}

// Adds/removes days from the day list, depending on the month/year
function FixDayList(DayList, NewDays) {
   var DayPick = DayList.selectedIndex + 1;
   if (NewDays != DayList.length) {
      var OldSize = DayList.length;
      for (var k=Math.min(NewDays,OldSize);k<Math.max(NewDays,OldSize);k++) {
         (k >= NewDays) ? DayList.options[NewDays] = null : DayList.options[k] = new Option(k+1, k+1);
      }
      DayPick = Math.min(DayPick, NewDays);
      DayList.options[DayPick-1].selected = true;
   }
   return DayPick;
}

// Resets the year to its previous valid value when something invalid is entered
function FixYearInput(YearField) {
   var YearRE = new RegExp('\\d{' + YearField.defaultValue.length + '}');
   if (!YearRE.test(YearField.value)) YearField.value = YearField.defaultValue;
}

// Displays a message in the status bar when hovering over the calendar icon
function CalIconHover(Over) {
   var Message = (this.isShowing()) ? 'hide' : 'show';
   self.status = (Over) ? 'Click to ' + Message + ' the calendar' : '';
   return true;
}

// Starts the timer over from scratch
function CalTimerReset() {
   eval('clearTimeout(' + this.timerID + ')');
   eval(this.timerID + '=setTimeout(\'' + this.objName + '.show()\',' + (HideWait * 1000) + ')');
}

// The timer for the calendar
function DoTimer(CancelTimer) {
   if (CancelTimer) eval('clearTimeout(' + this.timerID + ')');
   else {
      eval(this.timerID + '=null');
      this.resetTimer();
   }
}

// Show or hide the calendar
function ShowCalendar() {
   if (this.isShowing()) {
      var StopTimer = true;
      this.getCalendar().style.zIndex = --ZCounter;
      this.getCalendar().style.visibility = 'hidden';
      this.fixSelects(false);
   }
   else {
      var StopTimer = false;
      this.fixSelects(true);
      this.getCalendar().style.zIndex = ++ZCounter;
      this.getCalendar().style.visibility = 'visible';
   }
   this.handleTimer(StopTimer);
   self.status = '';
}

// Hides the input elements when the "blank" month is selected
function SetElementStatus(Hide) {
   this.getDayList().style.visibility = (Hide) ? 'hidden' : 'visible';
   this.getYearField().style.visibility = (Hide) ? 'hidden' : 'visible';
   this.getCalendarLink().style.visibility = (Hide) ? 'hidden' : 'visible';
}

// Sets the date, based on the month selected
function CheckMonthChange(MonthList) {
   var DayList = this.getDayList();
   if (MonthList.options[MonthList.selectedIndex].value == '') {
      DayList.selectedIndex = 0;
      this.hideElements(true);
      this.setHidden('');
   }
   else {
      this.hideElements(false);
      if (this.isShowing()) {
         this.resetTimer(); // Gives the user more time to view the calendar with the newly-selected month
         this.getCalendar().style.zIndex = ++ZCounter; // Make sure this calendar is on top of any other calendars
      }
      var DayPick = FixDayList(DayList, GetDayCount(this.picked.yearValue, MonthList.options[MonthList.selectedIndex].value));
      this.setPicked(this.picked.yearValue, MonthList.options[MonthList.selectedIndex].value, DayPick);
   }
}

// Sets the date, based on the day selected
function CheckDayChange(DayList) {
   if (this.isShowing()) this.show();
   this.setPicked(this.picked.yearValue, this.picked.monthIndex, DayList.selectedIndex+1);
}

// Changes the date when a valid year has been entered
function CheckYearInput(YearField) {
   if ((YearField.value.length == YearField.defaultValue.length) && (YearField.defaultValue != YearField.value)) {
      if (this.isShowing()) {
         this.resetTimer(); // Gives the user more time to view the calendar with the newly-entered year
         this.getCalendar().style.zIndex = ++ZCounter; // Make sure this calendar is on top of any other calendars
      }
      var NewYear = GetGoodYear(YearField.value);
      var MonthList = this.getMonthList();
      var NewDay = FixDayList(this.getDayList(), GetDayCount(NewYear, this.picked.monthIndex));
      this.setPicked(NewYear, this.picked.monthIndex, NewDay);
      YearField.defaultValue = YearField.value;
   }
}

// Holds characteristics about a date
function dateObject() {
   if (Function.call) { // Used when 'call' method of the Function object is supported
      var ParentObject = this;
      var ArgumentStart = 0;
   }
   else { // Used with 'call' method of the Function object is NOT supported
      var ParentObject = arguments[0];
      var ArgumentStart = 1;
   }
   ParentObject.date = (arguments.length == (ArgumentStart+1)) ? new Date(arguments[ArgumentStart+0]) : new Date(arguments[ArgumentStart+0], arguments[ArgumentStart+1], arguments[ArgumentStart+2]);
   ParentObject.yearValue = ParentObject.date.getFullYear();
   ParentObject.monthIndex = ParentObject.date.getMonth();
   ParentObject.monthName = MonthNames[ParentObject.monthIndex];
   ParentObject.fullName = ParentObject.monthName + ' ' + ParentObject.yearValue;
   ParentObject.day = ParentObject.date.getDate();
   ParentObject.dayCount = GetDayCount(ParentObject.yearValue, ParentObject.monthIndex);
   var FirstDate = new Date(ParentObject.yearValue, ParentObject.monthIndex, 1);
   ParentObject.firstDay = FirstDate.getDay();
}

// Keeps track of the date that goes into the hidden field
function storedMonthObject(DateFormat, DateYear, DateMonth, DateDay) {
   (Function.call) ? dateObject.call(this, DateYear, DateMonth, DateDay) : dateObject(this, DateYear, DateMonth, DateDay);
   this.yearPad = this.yearValue.toString();
   this.monthPad = (this.monthIndex < 9) ? '0' + String(this.monthIndex + 1) : this.monthIndex + 1;
   this.dayPad = (this.day < 10) ? '0' + this.day.toString() : this.day;
   this.monthShort = this.monthName.substr(0,3).toUpperCase();
   // Formats the year with 2 digits instead of 4
   if (DateFormat.indexOf('YYYY') == -1) this.yearPad = this.yearPad.substr(2);
   // Define the date-part delimiter
   if (DateFormat.indexOf('/') >= 0) var Delimiter = '/';
   else if (DateFormat.indexOf('-') >= 0) var Delimiter = '-';
   else var Delimiter = '';
   // Determine the order of the months and days
   if (/DD?.?((MON)|(MM?M?))/.test(DateFormat)) {
      this.formatted = this.dayPad + Delimiter;
      this.formatted += (RegExp.$1.length == 3) ? this.monthShort : this.monthPad;
   }
   else if (/((MON)|(MM?M?))?.?DD?/.test(DateFormat)) {
      this.formatted = (RegExp.$1.length == 3) ? this.monthShort : this.monthPad;
      this.formatted += Delimiter + this.dayPad;
   }
   // Either prepend or append the year to the formatted date
   this.formatted = (DateFormat.substr(0,2) == 'YY') ? this.yearPad + Delimiter + this.formatted : this.formatted + Delimiter + this.yearPad;
}

// Object for the current displayed month
function displayMonthObject(ParentObject, DateYear, DateMonth, DateDay) {
   (Function.call) ? dateObject.call(this, DateYear, DateMonth, DateDay) : dateObject(this, DateYear, DateMonth, DateDay);
   this.displayID = ParentObject.hiddenFieldName + '_Current_ID';
   this.getDisplay = new Function('return document.getElementById(this.displayID)');
   this.dayHover = DayCellHover;
   this.goCurrent = new Function(ParentObject.objName + '.getCalendar().style.zIndex=++ZCounter;' + ParentObject.objName + '.setDisplayed(Today.getFullYear(),Today.getMonth());');
   if (ParentObject.formNumber >= 0) this.getDisplay().innerHTML = this.fullName;
}

// Object for the previous/next buttons
function neighborMonthObject(ParentObject, IDText, DateMS) {
   (Function.call) ? dateObject.call(this, DateMS) : dateObject(this, DateMS);
   this.buttonID = ParentObject.hiddenFieldName + '_' + IDText + '_ID';
   this.hover = new Function('C','O','NeighborHover(C,O,this)');
   this.getButton = new Function('return document.getElementById(this.buttonID)');
   this.go = new Function(ParentObject.objName + '.getCalendar().style.zIndex=++ZCounter;' + ParentObject.objName + '.setDisplayed(this.yearValue,this.monthIndex);');
   if (ParentObject.formNumber >= 0) this.getButton().title = this.monthName;
}

// Sets the currently-displayed month object
function SetDisplayedMonth(DispYear, DispMonth) {
   this.displayed = new displayMonthObject(this, DispYear, DispMonth, 1);
   // Creates the previous and next month objects
   this.previous = new neighborMonthObject(this, 'Previous', this.displayed.date.getTime() - 86400000);
   this.next = new neighborMonthObject(this, 'Next', this.displayed.date.getTime() + (86400000 * (this.displayed.dayCount + 1)));
   // Creates the HTML for the calendar
   if (this.formNumber >= 0) this.getDayTable().innerHTML = this.buildCalendar();
}

// Sets the current selected date
function SetPickedMonth(PickedYear, PickedMonth, PickedDay) {
//alert('koooooooooi');
//alert(PickedMonth)
   this.picked = new storedMonthObject(this.format, PickedYear, PickedMonth, PickedDay);
   this.setHidden(this.picked.formatted);
   this.setDisplayed(PickedYear, PickedMonth);
}

// The calendar object
function calendarObject(DateName, DateFormat, DefaultDate) {

   /* Properties */
   this.hiddenFieldName = DateName;
   this.monthListID = DateName + '_Month_ID';
   this.dayListID = DateName + '_Day_ID';
   this.yearFieldID = DateName + '_Year_ID';
   this.monthDisplayID = DateName + '_Current_ID';
   this.calendarID = DateName + '_ID';
   this.dayTableID = DateName + '_DayTable_ID';
   this.calendarLinkID = this.calendarID + '_Link';
   this.timerID = this.calendarID + '_Timer';
   this.objName = DateName + '_Object';
   this.format = DateFormat;
   this.formNumber = -1;
   this.picked = null;
   this.displayed = null;
   this.previous = null;
   this.next = null;

   /* Methods */
   this.setPicked = SetPickedMonth;
   this.setDisplayed = SetDisplayedMonth;
   this.checkYear = CheckYearInput;
   this.fixYear = FixYearInput;
   this.changeMonth = CheckMonthChange;
   this.changeDay = CheckDayChange;
   this.resetTimer = CalTimerReset;
   this.hideElements = SetElementStatus;
   this.show = ShowCalendar;
   this.handleTimer = DoTimer;
   this.iconHover = CalIconHover;
   this.buildCalendar = BuildCalendarDays;
   this.pickDay = PickDisplayDay;
   this.fixSelects = FixSelectLists;
   this.setHidden = new Function('D','if (this.formNumber >= 0) this.getHiddenField().value=D');
   // Returns a reference to these elements
   this.getHiddenField = new Function('return document.forms[this.formNumber].elements[this.hiddenFieldName]');
   this.getMonthList = new Function('return document.getElementById(this.monthListID)');
   this.getDayList = new Function('return document.getElementById(this.dayListID)');
   this.getYearField = new Function('return document.getElementById(this.yearFieldID)');
   this.getCalendar = new Function('return document.getElementById(this.calendarID)');
   this.getDayTable = new Function('return document.getElementById(this.dayTableID)');
   this.getCalendarLink = new Function('return document.getElementById(this.calendarLinkID)');
   this.getMonthDisplay = new Function('return document.getElementById(this.monthDisplayID)');
   this.isShowing = new Function('return !(this.getCalendar().style.visibility != \'visible\')');

   /* Constructor */
   // Functions used only by the constructor
   function getMonthIndex(MonthAbbr) { // Returns the index (0-11) of the supplied month abbreviation
      for (var MonPos=0;MonPos<MonthNames.length;MonPos++) {
         if (MonthNames[MonPos].substr(0,3).toUpperCase() == MonthAbbr.toUpperCase()) break;
      }
      return MonPos;
   }
   function SetGoodDate(CalObj, Notify) { // Notifies the user about their bad default date, and sets the current system date
      CalObj.setPicked(Today.getFullYear(), Today.getMonth(), Today.getDate());
      if (Notify) alert('WARNING: The supplied date is not in valid \'' + DateFormat + '\' format: ' + DefaultDate + '.\nTherefore, the current system date will be used instead: ' + CalObj.picked.formatted);
   }
   // Main part of the constructor
   if (DefaultDate != '') {
      if ((this.format == 'YYYYMMDD') && (/^(\d{4})(\d{2})(\d{2})$/.test(DefaultDate))) this.setPicked(RegExp.$1, parseInt(RegExp.$2,10)-1, RegExp.$3);
      else {
         // Get the year
         if ((this.format.substr(0,2) == 'YY') && (/^(\d{2,4})(-|\/)/.test(DefaultDate))) { // Year is at the beginning
            var YearPart = GetGoodYear(RegExp.$1);
            // Determine the order of the months and days
            if (/(-|\/)(\w{1,3})(-|\/)(\w{1,3})$/.test(DefaultDate)) {
               var MidPart = RegExp.$2;
               var EndPart = RegExp.$4;
               if (/D$/.test(this.format)) { // Ends with days
                  var DayPart = EndPart;
                  var MonthPart = MidPart;
               }
               else {
                  var DayPart = MidPart;
                  var MonthPart = EndPart;
               }
               MonthPart = (/\d{1,2}/i.test(MonthPart)) ? parseInt(MonthPart,10)-1 : getMonthIndex(MonthPart);
               this.setPicked(YearPart, MonthPart, DayPart);
            }
            else SetGoodDate(this, true);
         }
         else if (/(-|\/)(\d{2,4})$/.test(DefaultDate)) { // Year is at the end
            var YearPart = GetGoodYear(RegExp.$2);
            // Determine the order of the months and days
            if (/^(\w{1,3})(-|\/)(\w{1,3})(-|\/)/.test(DefaultDate)) {
               if (this.format.substr(0,1) == 'D') { // Starts with days
                  var DayPart = RegExp.$1;
                  var MonthPart = RegExp.$3;
               }
               else { // Starts with months
                  var MonthPart = RegExp.$1;
                  var DayPart = RegExp.$3;
               }
               MonthPart = (/\d{1,2}/i.test(MonthPart)) ? parseInt(MonthPart,10)-1 : getMonthIndex(MonthPart);
               this.setPicked(YearPart, MonthPart, DayPart);
            }
            else SetGoodDate(this, true);
         }
         else SetGoodDate(this, true);
      }
   }
}

// Main function that creates the form elements
function DateInput(DateName, Required, DateFormat, DefaultDate) {
   if (arguments.length == 0) document.writeln('<span style="color:red;font-size:' + FontSize + 'px;font-family:' + FontFamily + ';">ERROR: Missing required parameter in call to \'DateInput\': [name of hidden date field].</span>');
   else {
      // Handle DateFormat
      if (arguments.length < 3) { // The format wasn't passed in, so use default
         DateFormat = DefaultDateFormat;
         if (arguments.length < 2) Required = false;
      }
      else if (/^(Y{2,4}(-|\/)?)?((MON)|(MM?M?)|(DD?))(-|\/)?((MON)|(MM?M?)|(DD?))((-|\/)Y{2,4})?$/i.test(DateFormat)) DateFormat = DateFormat.toUpperCase();
      else { // Passed-in DateFormat was invalid, use default format instead
         var AlertMessage = 'WARNING: The supplied date format for the \'' + DateName + '\' field is not valid: ' + DateFormat + '\nTherefore, the default date format will be used instead: ' + DefaultDateFormat;
         DateFormat = DefaultDateFormat;
         if (arguments.length == 4) { // DefaultDate was passed in with an invalid date format
            var CurrentDate = new storedMonthObject(DateFormat, Today.getFullYear(), Today.getMonth(), Today.getDate());
            AlertMessage += '\n\nThe supplied date (' + DefaultDate + ') cannot be interpreted with the invalid format.\nTherefore, the current system date will be used instead: ' + CurrentDate.formatted;
            DefaultDate = CurrentDate.formatted;
         }
         alert(AlertMessage);
      }
      // Define the current date if it wasn't set already
      if (!CurrentDate) var CurrentDate = new storedMonthObject(DateFormat, Today.getFullYear(), Today.getMonth(), Today.getDate());
      // Handle DefaultDate
      if (arguments.length < 4) { // The date wasn't passed in
         DefaultDate = (Required) ? CurrentDate.formatted : ''; // If required, use today's date
      }
      // Creates the calendar object!
      eval(DateName + '_Object=new calendarObject(\'' + DateName + '\',\'' + DateFormat + '\',\'' + DefaultDate + '\')');
      // Determine initial viewable state of day, year, and calendar icon
      if ((Required) || (arguments.length == 4)) {
         var InitialStatus = '';
         var InitialDate = eval(DateName + '_Object.picked.formatted');
      }
      else {
         var InitialStatus = ' style="visibility:hidden"';
         var InitialDate = '';
         eval(DateName + '_Object.setPicked(' + Today.getFullYear() + ',' + Today.getMonth() + ',' + Today.getDate() + ')');
      }
      // Create the form elements
      with (document) {
         writeln('<input id="' + DateName + '" type="hidden" name="' + DateName + '" value="' + InitialDate + '">');
         // Find this form number
         for (var f=0;f<forms.length;f++) {
            for (var e=0;e<forms[f].elements.length;e++) {
               if (typeof forms[f].elements[e].type == 'string') {
                  if ((forms[f].elements[e].type == 'hidden') && (forms[f].elements[e].name == DateName)) {
                     eval(DateName + '_Object.formNumber='+f);
                     break;
                  }
               }
            }
         }
         writeln('<table cellpadding="0" cellspacing="2"><tr>' + String.fromCharCode(13) + '<td valign="middle">');
         writeln('<select class="calendarDateInput" id="' + DateName + '_Month_ID" onChange="' + DateName + '_Object.changeMonth(this)">');
         if (!Required) {
            var NoneSelected = (DefaultDate == '') ? ' selected' : '';
            writeln('<option value=""' + NoneSelected + '>' + UnselectedMonthText + '</option>');
         }
         for (var i=0;i<12;i++) {
            MonthSelected = ((DefaultDate != '') && (eval(DateName + '_Object.picked.monthIndex') == i)) ? ' selected' : '';
            writeln('<option value="' + i + '"' + MonthSelected + '>' + MonthNames[i].substr(0,3) + '</option>');
         }
         writeln('</select>' + String.fromCharCode(13) + '</td>' + String.fromCharCode(13) + '<td valign="middle">');
         writeln('<select' + InitialStatus + ' class="calendarDateInput" id="' + DateName + '_Day_ID" onChange="' + DateName + '_Object.changeDay(this)">');
         for (var j=1;j<=eval(DateName + '_Object.picked.dayCount');j++) {
            DaySelected = ((DefaultDate != '') && (eval(DateName + '_Object.picked.day') == j)) ? ' selected' : '';
            writeln('<option' + DaySelected + '>' + j + '</option>');
         }
         writeln('</select>' + String.fromCharCode(13) + '</td>' + String.fromCharCode(13) + '<td valign="middle">');
         writeln('<input' + InitialStatus + ' class="calendarDateInput" type="text" id="' + DateName + '_Year_ID" size="' + eval(DateName + '_Object.picked.yearPad.length') + '" maxlength="' + eval(DateName + '_Object.picked.yearPad.length') + '" title="Year" value="' + eval(DateName + '_Object.picked.yearPad') + '" onKeyPress="return YearDigitsOnly(window.event)" onKeyUp="' + DateName + '_Object.checkYear(this)" onBlur="' + DateName + '_Object.fixYear(this)">');
         write('<td valign="middle">' + String.fromCharCode(13) + '<a' + InitialStatus + ' id="' + DateName + '_ID_Link" href="javascript:' + DateName + '_Object.show()" onMouseOver="return ' + DateName + '_Object.iconHover(true)" onMouseOut="return ' + DateName + '_Object.iconHover(false)"><img src="' + ImageURL + '" align="baseline" title="Calendar" border="0"></a>&nbsp;');
         writeln('<span id="' + DateName + '_ID" style="position:absolute;visibility:hidden;width:' + (CellWidth * 7) + 'px;background-color:' + CalBGColor + ';border:1px solid dimgray;" onMouseOver="' + DateName + '_Object.handleTimer(true)" onMouseOut="' + DateName + '_Object.handleTimer(false)">');
         writeln('<table width="' + (CellWidth * 7) + '" cellspacing="0" cellpadding="1">' + String.fromCharCode(13) + '<tr style="background-color:' + TopRowBGColor + ';">');
         writeln('<td id="' + DateName + '_Previous_ID" style="cursor:default" align="center" class="calendarDateInput" style="height:' + CellHeight + '" onClick="' + DateName + '_Object.previous.go()" onMouseDown="VirtualButton(this,true)" onMouseUp="VirtualButton(this,false)" onMouseOver="return ' + DateName + '_Object.previous.hover(this,true)" onMouseOut="return ' + DateName + '_Object.previous.hover(this,false)" title="' + eval(DateName + '_Object.previous.monthName') + '"><img src="' + PrevURL + '"></td>');
         writeln('<td id="' + DateName + '_Current_ID" style="cursor:pointer" align="center" class="calendarDateInput" style="height:' + CellHeight + '" colspan="5" onClick="' + DateName + '_Object.displayed.goCurrent()" onMouseOver="self.status=\'Click to view ' + CurrentDate.fullName + '\';return true;" onMouseOut="self.status=\'\';return true;" title="Show Current Month">' + eval(DateName + '_Object.displayed.fullName') + '</td>');
         writeln('<td id="' + DateName + '_Next_ID" style="cursor:default" align="center" class="calendarDateInput" style="height:' + CellHeight + '" onClick="' + DateName + '_Object.next.go()" onMouseDown="VirtualButton(this,true)" onMouseUp="VirtualButton(this,false)" onMouseOver="return ' + DateName + '_Object.next.hover(this,true)" onMouseOut="return ' + DateName + '_Object.next.hover(this,false)" title="' + eval(DateName + '_Object.next.monthName') + '"><img src="' + NextURL + '"></td></tr>' + String.fromCharCode(13) + '<tr>');
         for (var w=0;w<7;w++) writeln('<td width="' + CellWidth + '" align="center" class="calendarDateInput" style="height:' + CellHeight + ';width:' + CellWidth + ';font-weight:bold;border-top:1px solid dimgray;border-bottom:1px solid dimgray;">' + WeekDays[w] + '</td>');
         writeln('</tr>' + String.fromCharCode(13) + '</table>' + String.fromCharCode(13) + '<span id="' + DateName + '_DayTable_ID">' + eval(DateName + '_Object.buildCalendar()') + '</span>' + String.fromCharCode(13) + '</span>' + String.fromCharCode(13) + '</td>' + String.fromCharCode(13) + '</tr>' + String.fromCharCode(13) + '</table>');
      }
   }
}

 /*
//Reoccruing Box

function showBox()
{

    var chkbox = document.getElementById('showrecbox');
       
    if(chkbox.checked)
    {
        document.getElementById('box').style.visibility = 'visible';           
    }else
    {
        document.getElementById('box').style.visibility = 'hidden';
    }
}

//Reoccruing Box

function recDivBox(wid,wtype,sdate)
{
         
    var recbox = document.getElementById('recbox');
    recbox.style.visibility = 'visible';           
    document.getElementById('workoutId').value = wid;
    document.getElementById('workoutType').value = wtype;
    document.getElementById('scheduledDate').value = sdate;
    
    //send the form via ajax
    
    
    
}


function checkBoxes()
{         

    var chkbx = document.recboxform.week;// getElementById('week');
                
    var status = 0;
    
    for(i=0;i<chkbx.length;i++)
    {
        //atleast any one should be checked
        if(chkbx[i].checked)
        {
            status =1;
        }
    }
    
    if(status == 1)
          return true;
    else
        alert('Please select atleast one day');    
    
      return false;
}*/

/**************************************************************************************/

/* file : basiccalendar */

var Dialog = {};
     Dialog.Box = Class.create();
     Object.extend(Dialog.Box.prototype, {
       initialize: function(id) {
         this.createOverlay();
     
         this.dialog_box = $(id);
         this.dialog_box.show = this.show.bind(this);
         this.dialog_box.persistent_show = this.persistent_show.bind(this);
        this.dialog_box.hide = this.hide.bind(this);
    
        this.parent_element = this.dialog_box.parentNode;
        
        this.dialog_box.style.position = "absolute";
    
        var e_dims = Element.getDimensions(this.dialog_box);
        var b_dims = Element.getDimensions(this.overlay);
        this.dialog_box.style.left = ((b_dims.width/2) - (e_dims.width/2)) + 'px';
       // this.dialog_box.style.top = '12px';
       this.dialog_box.style.top = ((this.winHeight() - (e_dims.width/2))/2) + 'px';
       this.dialog_box.style.zIndex = this.overlay.style.zIndex + 1;
      },
    
      createOverlay: function() {
        if($('dialog_overlay')) {
          this.overlay = $('dialog_overlay');
       } else {
         this.overlay = document.createElement('div');
          this.overlay.id = 'dialog_overlay';
         Object.extend(this.overlay.style, {
             position: 'absolute',
             top: 0,
             left: 0,
             zIndex: 90,
             width: '100%',
             backgroundColor: '#000',
             display: 'none'
         });
          document.body.insertBefore(this.overlay, document.body.childNodes[0]);
        }
      },
   
      moveDialogBox: function(where) {
        Element.remove(this.dialog_box);
        if(where == 'back')
          this.dialog_box = this.parent_element.appendChild(this.dialog_box);
        else
         this.dialog_box = this.overlay.parentNode.insertBefore(this.dialog_box, this.overlay);
      },
    
      /*show: function() {
        this.overlay.style.height = $('body').getHeight()+'px';
        this.moveDialogBox('out');
       this.overlay.onclick = this.hide.bind(this);
       this.selectBoxes('hide');
       new Effect.Appear(this.overlay, {duration: 0.1, from: 0.0, to: 0.3});
       this.dialog_box.style.display = ''
     }, */
     
     show: function() {
//       this.overlay.style.height = this.winHeight()+'px';
       this.overlay.style.height = '2000px';//this.winHeight()+'px';
        this.moveDialogBox('out');
        
        this.overlay.onclick = this.hide.bind(this);
            
       this.selectBoxes('hide');
        new Effect.Appear(this.overlay, {duration: 0.1, from: 0.0, to: 0.3});
       this.dialog_box.style.display = '';
   
         this.dialog_box.style.left = '0px';
     
       var e_dims = Element.getDimensions(this.dialog_box);
          
          this.dialog_box.style.left = ((this.winWidth()/2) - (e_dims.width)/2) + 'px';
          
          //set it to the values according to the screen  
          this.dialog_box.style.left = '48%';
          this.dialog_box.style.top = '50%';
          this.dialog_box.style.zIndex = '800000';
                                            
         // alert('left =>'+this.dialog_box.style.left);
         // alert('top =>'+this.dialog_box.style.top);
          
      },
      
     persistent_show: function() {
        this.overlay.style.height = this.winHeight()+'px';
        this.moveDialogBox('out');
    
        this.selectBoxes('hide');
       new Effect.Appear(this.overlay, {duration: 0.1, from: 0.0, to: 0.3});
       
        this.dialog_box.style.display = '';
         this.dialog_box.style.left = '0px';
        var e_dims = Element.getDimensions(this.dialog_box);
          this.dialog_box.style.left = ((this.winWidth()/2) - (e_dims.width)/2) + 'px';
          
      },
   
     hide: function() {
       this.selectBoxes('show');
       new Effect.Fade(this.overlay, {duration: 0.1});
       this.dialog_box.style.display = 'none';
       this.moveDialogBox('back');
       $A(this.dialog_box.getElementsByTagName('input')).each(function(e){if(e.type!='submit')e.value=''});
     },
   
     selectBoxes: function(what) {
       $A(document.getElementsByTagName('select')).each(function(select) {
          Element[what](select);
       });
   
        if(what == 'hide')
         $A(this.dialog_box.getElementsByTagName('select')).each(function(select){Element.show(select)})
      },
      
      winWidth: function() 
      { 
        return document.body.offsetWidth || window.innerWidth || document.documentElement.clientWidth || 0; 
      },
     winHeight: function() { return document.body.offsetHeight || window.innerHeight || document.documentElement.clientHeight || 0; }
 
      
      
    });


function buildCal(m, y, cM, cH, cDW, cD, brdr)
{                                

var mn=['January','February','March','April','May','June','July','August','September','October','November','December'];
var dim=[31,0,31,30,31,30,31,31,30,31,30,31];

var oD = new Date(y, m-1, 1); //DD replaced line to fix date bug when current day is 31st
oD.od=oD.getDay()+1; //DD replaced line to fix date bug when current day is 31st

var todaydate=new Date() //DD added
var scanfortoday=(y==todaydate.getFullYear() && m==todaydate.getMonth()+1)? todaydate.getDate() : 0 //DD added

dim[1]=(((oD.getFullYear()%100!=0)&&(oD.getFullYear()%4==0))||(oD.getFullYear()%400==0))?29:28;
var t='<div class="mainContainer"><table class="'+cM+'" cols="7" cellpadding="0" border="'+brdr+'" cellspacing="0"><tr align="center">';
t+='<td colspan="7" align="center" class="'+cH+'">'+mn[m-1]+' - '+y+'</td></tr><tr align="center">';
for(s=0;s<7;s++)t+='<td class="'+cDW+'">'+"SMTWTFS".substr(s,1)+'</td>';
t+='</tr><tr align="center">';
for(i=1;i<=42;i++)
{
    var x=((i-oD.od>=0)&&(i-oD.od<dim[m-1]))? i-oD.od+1 : '&nbsp;';
   /* if (x==scanfortoday) //DD added
        x='<span id="today">'+x+'</span>' //DD added*/
    t+='<td class="'+cD+'"><a style="text-decoration:none" href="javascript:frameDate('+y+','+m+','+x+')">'+x+'</a></td>';
    if(((i)%7==0)&&(i<36))t+='</tr><tr align="center">';
}
    t+='</tr></table><input type="text" name="date" id="date" /><input type="hidden" name="dragId" id="dragId" /><button onclick="confirmIt()">Confirm</button> </div>';
    
    $('smallcalc').innerHTML = t;
}


function frameDate(year,month,day)
{
    var sdate = year+'-'+month+'-'+day;
                            
    $('date').value = sdate;

}

function dropOnMonth()
{                     
    Droppables.add('previousMonth',
                {
                    onDrop:showCalc
                });
                
    Droppables.add('nextMonth',
            {
                onDrop:showCalc
            });                
}

function showCalc(drag,drop)
{                     
    // Show modal dialog
    new Dialog.Box('smallcalc');
    $('smallcalc').show(); 
       
    //make it draggable
//    new Draggable('smallcalc');       
       
    var id = drop.getAttribute('id');
    var Month = id+'_'+'month';
    Month = $(Month).value;
    
    var Year = id+'_'+'year';
    Year = $(Year).value;
                 
    buildCal(Month ,Year, 'main', 'month', 'daysofweek', 'days', 1);   
    
    
    var dragid = drag.getAttribute("id");      
//    var rid = $("dvd_rid"+dragid.substring(4)).value;
    
   // $('rotationId').value = rid;
    $('dragId').value = dragid;
    
    
}


function confirmIt()
{
    
    var date = $('date').value;
    var dragid = $('dragId').value;
    
    var rid = $("dvd_rid"+dragid.substring(4)).value;
    //*******code added for general exercises(muthu)*/
                    
     dragid = dragid.substring(4);   // remove the 'drop'                    
      var getType = 'update'+dragid;   
      if(document.getElementById(getType))
      {
          var typeId = document.getElementById(getType).value;
                                              
          var getDateId = dragid+'_'+typeId;
          var dragDateId = document.getElementById(getDateId).value;    
      }else
      {
        var typeId = '';
        var dragDateId = '';
      }
         
    /******************************************/
        
    
    
    if(date && rid)
    {
    //    var url = "update_rotations.php?id="+rid+"&date="+date;
        var url = DIR+"/update_rotations.php?id="+rid+"&date="+date+"&typeId="+typeId+"&dragDateId="+dragDateId;
        
        if($('work_type'+dragid))
        {           
            workout_type = $F('work_type'+dragid);
            url += "&Workout_type="+workout_type;
        }
        
        callAjax_Rotation(url,"calender",date);    
        //close 
        $('smallcalc').hide();
        
        var sdate = date.split('-');
        var showDate  = sdate[1]+sdate[0];
//        alert(showDate)
        
        loadCalendarTab(date,showDate);
        //showInHome('tab2');  
    }
                //callAjax_Rotation(url,"calender");
    
}

/**************************************************************************
# file : tableSort.js
// ===================================================================
// Author: Denis Howlett <feedback@isocra.com>
// WWW: http://www.isocra.com/
//
// NOTICE: You may use this code for any purpose, commercial or
// private, without any further permission from the author. You may
// remove this notice from your final code if you wish, however we
// would appreciate it if at least the web site address is kept.
//
// You may *NOT* re-distribute this code in any way except through its
// use. That means, you can include it in your product, or your web
// site, or any other form where the code is actually being used. You
// may not put the plain javascript up on your site for download or
// include it in your javascript libraries for download.
// If you wish to share this code with others, please just point them
// to the URL instead.
//
// Please DO NOT link directly to this .js files from your site. Copy
// the files to your server and use them there. Thank you.
// ===================================================================

/** Keep hold of the current table being dragged */
var currenttable = null;

/** Capture the onmousemove so that we can see if a row from the current
 *  table if any is being dragged.
 * @param ev the event (for Firefox and Safari, otherwise we use window.event for IE)
 */
document.onmousemove = function(ev){
    if (currenttable && currenttable.dragObject) {
        ev   = ev || window.event;
        var mousePos = currenttable.mouseCoords(ev);
        var y = mousePos.y - currenttable.mouseOffset.y;
        if (y != currenttable.oldY) {
            // work out if we're going up or down...
            var movingDown = y > currenttable.oldY;
            // update the old value
            currenttable.oldY = y;
            // update the style to show we're dragging
            currenttable.dragObject.style.backgroundColor = "#eee";
            // If we're over a row then move the dragged row to there so that the user sees the
            // effect dynamically
            var currentRow = currenttable.findDropTargetRow(y);

            if (currentRow) {
                if (movingDown && currenttable.dragObject != currentRow) {
                    currenttable.dragObject.parentNode.insertBefore(currenttable.dragObject, currentRow.nextSibling);
                } else if (! movingDown && currenttable.dragObject != currentRow) {
                    currenttable.dragObject.parentNode.insertBefore(currenttable.dragObject, currentRow);
                }
            }
        }

        return false;
    }
}

// Similarly for the mouseup
document.onmouseup   = function(ev){
    if (currenttable && currenttable.dragObject) {
        var droppedRow = currenttable.dragObject;
        // If we have a dragObject, then we need to release it,
        // The row will already have been moved to the right place so we just reset stuff
        droppedRow.style.backgroundColor = 'transparent';
        currenttable.dragObject   = null;
        // And then call the onDrop method in case anyone wants to do any post processing
        currenttable.onDrop(currenttable.table, droppedRow);
        currenttable = null; // let go of the table too
    }
}


/** get the source element from an event in a way that works for IE and Firefox and Safari
 * @param evt the source event for Firefox (but not IE--IE uses window.event) */
function getEventSource(evt) {
    if (window.event) {
        evt = window.event; // For IE
        return evt.srcElement;
    } else {
        return evt.target; // For Firefox
    }
}

/**
 * Encapsulate table Drag and Drop in a class. We'll have this as a Singleton
 * so we don't get scoping problems.
 */
function TableDnD() {
    /** Keep hold of the current drag object if any */
    this.dragObject = null;
    /** The current mouse offset */
    this.mouseOffset = null;
    /** The current table */
    this.table = null;
    /** Remember the old value of Y so that we don't do too much processing */
    this.oldY = 0;

    /** Initialise the drag and drop by capturing mouse move events */
    this.init = function(table) {
        this.table = table;
        var rows = table.tBodies[1].rows; //getElementsByTagName("tr")  // 0 changed to 1 because of additional tbody
        for (var i=0; i<rows.length; i++) {
            // John Tarr: added to ignore rows that I've added the NoDnD attribute to (Category and Header rows)
            var nodrag = rows[i].getAttribute("NoDrag")
            if (nodrag == null || nodrag == "undefined") { //There is no NoDnD attribute on rows I want to drag
                this.makeDraggable(rows[i]);
            }
        }
    }

    
    /** code added by Muthu **/
/** To stop the drag and drop */
        this.stop = function(table) {
                this.table = table;
                var rows = table.tBodies[1].rows; //getElementsByTagName("tr")
                for (var i=0; i<rows.length; i++) {
                    // John Tarr: added to ignore rows that I've added the NoDnD attribute to (Category and Header rows)
                    var nodrag = rows[i].getAttribute("NoDrag")
                    if (nodrag == null || nodrag == "undefined") { //There is no NoDnD attribute on rows I want to drag
                        this.noDraggable(rows[i]);
                    }
                }
            }
    
    /** This function is called when you drop a row, so redefine it in your code
        to do whatever you want, for example use Ajax to update the server */
    this.onDrop = function(table, droppedRow) {
        // Do nothing for now
        
        // code altered by Muthu Vijayan to order the sorted elements
                var rows = table.tBodies[1].rows; //getElementsByTagName("tr")
            for (var i=0; i<rows.length; i++) 
                {
                    var nodrag = rows[i].getAttribute("NoDrag");
                    if (nodrag == null || nodrag == "undefined") 
                    {
                        var id = rows[i].getAttribute('id'); // get the id value
        
                        $('order_'+id).value = i+1; //reorder the sorted values
                    }
                }
            
    }

    
    /** Get the position of an element by going up the DOM tree and adding up all the offsets */
    this.getPosition = function(e){
        var left = 0;
        var top  = 0;
        /** Safari fix -- thanks to Luis Chato for this! */
        if (e.offsetHeight == 0) {
            /** Safari 2 doesn't correctly grab the offsetTop of a table row
                this is detailed here:
                http://jacob.peargrove.com/blog/2006/technical/table-row-offsettop-bug-in-safari/
                the solution is likewise noted there, grab the offset of a table cell in the row - the firstChild.
                note that firefox will return a text node as a first child, so designing a more thorough
                solution may need to take that into account, for now this seems to work in firefox, safari, ie */
            e = e.firstChild; // a table cell
        }

        while (e.offsetParent){
            left += e.offsetLeft;
            top  += e.offsetTop;
            e     = e.offsetParent;
        }

        left += e.offsetLeft;
        top  += e.offsetTop;

        return {x:left, y:top};
    }

    /** Get the mouse coordinates from the event (allowing for browser differences) */
    this.mouseCoords = function(ev){
        if(ev.pageX || ev.pageY){
            return {x:ev.pageX, y:ev.pageY};
        }
        return {
            x:ev.clientX + document.body.scrollLeft - document.body.clientLeft,
            y:ev.clientY + document.body.scrollTop  - document.body.clientTop
        };
    }

    /** Given a target element and a mouse event, get the mouse offset from that element.
        To do this we need the element's position and the mouse position */
    this.getMouseOffset = function(target, ev){
        ev = ev || window.event;

        var docPos    = this.getPosition(target);
        var mousePos  = this.mouseCoords(ev);
        return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y};
    }

    /** Take an item and add an onmousedown method so that we can make it draggable */
    this.makeDraggable = function(item) {
        if(!item) return;
        var self = this; // Keep the context of the TableDnd inside the function
        item.onmousedown = function(ev) {
            // Need to check to see if we are an input or not, if we are an input, then
            // return true to allow normal processing
            var target = getEventSource(ev);
            if (target.tagName == 'INPUT' || target.tagName == 'SELECT') return true;
            currenttable = self;
            self.dragObject  = this;
            self.mouseOffset = self.getMouseOffset(this, ev);
            return false;
        }
        item.style.cursor = "move";
    }
    
    
    /** code added by Muthu **/
/** To stop the drag and drop. This will unset the initialized values */
    this.noDraggable = function(item) {
        if(!item) return;
        var self = this; // Keep the context of the TableDnd inside the function
        item.onmousedown = function(ev) {
            // Need to check to see if we are an input or not, if we are an input, then
            // return true to allow normal processing
            var target = getEventSource(ev);
            if (target.tagName == 'INPUT' || target.tagName == 'SELECT') return true;
            currenttable = self;
            self.dragObject  = '';
            self.mouseOffset = '';
            return false;
        }
        item.style.cursor = "default";
    }

    /** We're only worried about the y position really, because we can only move rows up and down */
    this.findDropTargetRow = function(y) {
        var rows = this.table.tBodies[1].rows;
        for (var i=0; i<rows.length; i++) {
            var row = rows[i];
            // John Tarr added to ignore rows that I've added the NoDnD attribute to (Header rows)
            var nodrop = row.getAttribute("NoDrop");
            if (nodrop == null || nodrop == "undefined") {  //There is no NoDnD attribute on rows I want to drag
                var rowY    = this.getPosition(row).y;
                var rowHeight = parseInt(row.offsetHeight)/2;
                if (row.offsetHeight == 0) {
                    rowY = this.getPosition(row.firstChild).y;
                    rowHeight = parseInt(row.firstChild.offsetHeight)/2;
                }
                // Because we always have to insert before, we need to offset the height a bit
                if ((y > rowY - rowHeight) && (y < (rowY + rowHeight))) {
                    // that's the row we're over
                    return row;
                }
            }
        }
        return null;
    }
}

/******************************************************************
#file : epoch_classes.js
/******************************************************************/
/*!!
Epoch DHTML JavaScript Calendar - Version 2.0.2
English Edition
Primary JavaScript File
(c) 2006-2007 MeanFreePath
Free for NON-COMMERCIAL use - see website for details and updates
http://www.meanfreepath.com/javascript_calendar/index.html
!!*/

/**
* The main Epoch class.  All publicly-accessible methods and properties are called from this class
*/
function Epoch(name,mode,targetelement,ourTab,multiselect) {
    var self = this;  //workaround due to varying definitions of "this" in variable scopes. see http://www.meanfreepath.com/support/epoch/epoch.html#self for details
    //DEFINE PRIVATE METHODS
    //-----------------------------------------------------------------------------
    /**
    * Declares and initializes the calendar variables.  All the variables here can be safely changed
    * (within reason ;) by the developer
    */
    function calConfig() {
        self.versionNumber = '2.0.2';
        self.displayYearInitial = self.curDate.getFullYear(); //the initial year to display on load
        self.displayMonthInitial = self.curDate.getMonth(); //the initial month to display on load (0-11)
        self.displayYear = self.displayYearInitial;
        self.displayMonth = self.displayMonthInitial;
        self.minDate = new Date(2006,0,1);
        self.maxDate = new Date(2050,11,31);
        self.startDay = 0; // the day the week will 'start' on: 0(Sun) to 6(Sat)
        self.showWeeks = true; //whether the week numbers will be shown
        self.selCurMonthOnly = true; //allow user to only select dates in the currently displayed month
    }
    //-----------------------------------------------------------------------------
    /**
    * All language settings for Epoch are made here.
    * Check Date.dateFormat() for the Date object's language settings
    */
    function setLang() {
        self.daylist = new Array('S','M','T','W','T','F','S','S','M','T','W','T','F','S');
        self.months_sh = new Array('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
        self.monthup_title = 'Go to the next month';
        self.monthdn_title = 'Go to the previous month';
        self.clearbtn_caption = 'Clear';
        self.clearbtn_title = 'Clears any dates selected on the calendar';
        self.maxrange_caption = 'This is the maximum range';
        self.closebtn_caption = 'Close';
        self.closebtn_title = 'Close the calendar';
    }
    //-----------------------------------------------------------------------------
    /**
    * Initializes the standard Gregorian Calendar parameters
    */
    function setDays() {
        self.daynames = new Array();
        var j=0;
        for(var i=self.startDay;i<self.startDay + 7;i++) {
            self.daynames[j++] = self.daylist[i];
        }
        self.monthDayCount = new Array(31,((self.curDate.getFullYear() - 2000) % 4 ? 28 : 29),31,30,31,30,31,31,30,31,30,31);
    }
    //-----------------------------------------------------------------------------
    /**
    * Creates the full DOM implementation of the calendar
    */
    function createCalendar() {
        var tbody, tr, td;
        self.calendar = document.createElement('table');
        self.calendar.setAttribute('id',self.name+'_calendar');
        setClass(self.calendar,'calendar');
        self.calendar.style.display = 'none'; //default to invisible
        //to prevent IE from selecting text when clicking on the calendar
        addEventHandler(self.calendar,'selectstart', function() {return false;});
        addEventHandler(self.calendar,'drag', function() {return false;});
        tbody = document.createElement('tbody');

        //create the Main Calendar Heading
        tr = document.createElement('tr');
        td = document.createElement('td');
        td.appendChild(createMainHeading());
        tr.appendChild(td);
        tbody.appendChild(tr);

        //create the calendar Day Heading & the calendar Day Cells
        tr = document.createElement('tr');
        td = document.createElement('td');
        self.calendar.celltable = document.createElement('table');
        setClass(self.calendar.celltable,'cells');
        self.calendar.celltable.appendChild(createDayHeading());
        self.calendar.celltable.appendChild(createCalCells());
        td.appendChild(self.calendar.celltable);
        tr.appendChild(td);
        tbody.appendChild(tr);

        //create the calendar footer
        tr = document.createElement('tr');
        td = document.createElement('td');
        td.appendChild(createFooter());
        tr.appendChild(td);
        tbody.appendChild(tr);

        //add the tbody element to the main calendar table
        self.calendar.appendChild(tbody);

        //and add the onmouseover events to the calendar table
        addEventHandler(self.calendar,'mouseover',cal_onmouseover);
        addEventHandler(self.calendar,'mouseout',cal_onmouseout);
    }
    //-----------------------------------------------------------------------------
    /**
    * Creates the primary calendar heading, with months & years
    */
    function createMainHeading() {
        //create the containing <div> element
        var container = document.createElement('div');
        setClass(container,'mainheading');
        //create the child elements and other variables
        self.monthSelect = document.createElement('select');
        self.yearSelect = document.createElement('select');
        var monthDn = document.createElement('input'), monthUp = document.createElement('input');
        var opt, i;
        //fill the month select box
        for(i=0;i<12;i++) {
            opt = document.createElement('option');
            opt.setAttribute('value',i);
            if(self.displayMonth == i) {
                opt.setAttribute('selected','selected');
            }
            opt.appendChild(document.createTextNode(self.months_sh[i]));
            self.monthSelect.appendChild(opt);
        }
        //and fill the year select box
        var yrMax = self.maxDate.getFullYear(), yrMin = self.minDate.getFullYear();
        for(i=yrMin;i<=yrMax;i++) {
            opt = document.createElement('option');
            opt.setAttribute('value',i);
            if(self.displayYear == i) {
                opt.setAttribute('selected','selected');
            }
            opt.appendChild(document.createTextNode(i));
            self.yearSelect.appendChild(opt);
        }
        //add the appropriate children for the month buttons
        monthUp.setAttribute('type','button');
        monthUp.setAttribute('value','>');
        monthUp.setAttribute('title',self.monthup_title);
        monthDn.setAttribute('type','button');
        monthDn.setAttribute('value','<');
        monthDn.setAttribute('title',self.monthdn_title);
        self.monthSelect.owner = self.yearSelect.owner = monthUp.owner = monthDn.owner = self;  //hack to allow us to access self calendar in the events (<fix>??)

        //assign the event handlers for the controls
        function selectonchange()    {
            if(self.goToMonth(self.yearSelect.value,self.monthSelect.value)) {
                self.displayMonth = self.monthSelect.value;
                self.displayYear = self.yearSelect.value;
            }
            else {
                self.monthSelect.value = self.displayMonth;
                self.yearSelect.value = self.displayYear;
            }
        }
        addEventHandler(monthUp,'click',function(){self.nextMonth();});
        addEventHandler(monthDn,'click',function(){self.prevMonth();});
        addEventHandler(self.monthSelect,'change',selectonchange);
        addEventHandler(self.yearSelect,'change',selectonchange);

        //and finally add the elements to the containing div
        container.appendChild(monthDn);
        container.appendChild(self.monthSelect);
        container.appendChild(self.yearSelect);
        container.appendChild(monthUp);
        return container;
    }
    //-----------------------------------------------------------------------------
    /**
    * Creates the footer of the calendar - goes under the calendar cells
    */
    function createFooter() {
        var container = document.createElement('div');
        var clearSelected = document.createElement('input');
        clearSelected.setAttribute('type','button');
        clearSelected.setAttribute('value',self.clearbtn_caption);
        clearSelected.setAttribute('title',self.clearbtn_title);
        clearSelected.owner = self;
        addEventHandler(clearSelected,'click',function() {self.resetSelections(false);});
        container.appendChild(clearSelected);
        if(self.mode == 'popup') {
            var closeBtn = document.createElement('input');
            closeBtn.setAttribute('type','button');
            closeBtn.setAttribute('value',self.closebtn_caption);
            closeBtn.setAttribute('title',self.closebtn_title);
            addEventHandler(closeBtn,'click',function(){self.hide();});
            setClass(closeBtn,'closeBtn');
            container.appendChild(closeBtn);
        }
        return container;
    }
    //-----------------------------------------------------------------------------
    /**
    * Creates the heading containing the day names
    */
    function createDayHeading() {
        //create the table element
        self.calHeading = document.createElement('thead');
        setClass(self.calHeading,'caldayheading');
        var tr = document.createElement('tr'), th;
        self.cols = new Array(false,false,false,false,false,false,false);

        //if we're showing the week headings, create an empty <td> for filler
        if(self.showWeeks) {
            th = document.createElement('th');
            setClass(th,'wkhead');
            tr.appendChild(th);
        }
        //populate the day titles
        for(var dow=0;dow<7;dow++) {
            th = document.createElement('th');
            th.appendChild(document.createTextNode(self.daynames[dow]));
            if(self.selectMultiple) { //if selectMultiple is true, assign the cell a CalHeading Object to handle all events
                th.headObj = new CalHeading(self,th,(dow + self.startDay < 7 ? dow + self.startDay : dow + self.startDay - 7));
            }
            tr.appendChild(th);
        }
        self.calHeading.appendChild(tr);
        return self.calHeading;
    }
    //-----------------------------------------------------------------------------
    /**
    * Creates the table containing the calendar day cells
    */
    function createCalCells() {
        self.rows = new Array(false,false,false,false,false,false);
        self.cells = new Array();
        var row = -1, totalCells = (self.showWeeks ? 48 : 42);
        var beginDate = new Date(self.displayYear,self.displayMonth,1);
        var endDate = new Date(self.displayYear,self.displayMonth,self.monthDayCount[self.displayMonth]);
        var sdt = new Date(beginDate);
        sdt.setDate(sdt.getDate() + (self.startDay - beginDate.getDay()) - (self.startDay - beginDate.getDay() > 0 ? 7 : 0) );
        //create the table element to hold the cells
        self.calCells = document.createElement('tbody');
        var tr,td;
        var cellIdx = 0, cell, week, dayval;

        for(var i=0;i<totalCells;i++) {
            if(self.showWeeks) { //if we are showing the week headings
                if(i % 8 == 0) {
                    row++;
                    week = sdt.getWeek(self.startDay);
                    tr = document.createElement('tr');
                    td = document.createElement('td');
                    if(self.selectMultiple) { //if selectMultiple is enabled, create the associated weekObj objects
                        td.weekObj = new WeekHeading(self,td,week,row)
                    }
                    else {//otherwise just set the class of the td for consistent look
                        setClass(td,'wkhead');
                    }
                    td.appendChild(document.createTextNode(week));
                    tr.appendChild(td);
                    i++;
                }
            }
            else if(i % 7 == 0) { //otherwise, new row every 7 cells
                row++;
                week = sdt.getWeek(self.startDay);
                tr = document.createElement('tr');
            }
            //create the day cells
            dayval = sdt.getDate();
            td = document.createElement('td');
            td.appendChild(document.createTextNode(dayval));
            cell = new CalCell(self,td,sdt,row,week,ourTab);//,'normal',sdt.getTime() >= self.minDate.getTime() && sdt.getTime() <= self.maxDate.getTime());
            self.cells[cellIdx] = cell;
            td.cellObj = cell;
            tr.appendChild(td);
            self.calCells.appendChild(tr);
            self.reDraw(cellIdx++); //and paint the cell according to its properties
            sdt.setDate(dayval + 1); //increment the date
        }
        return self.calCells;
    }
    //-----------------------------------------------------------------------------
    /**
    * Runs all the operations necessary to change the mode of the calendar
    * @param HTMLInputElement targetelement
    */
    function setMode(targetelement)    {
        if(self.mode == 'popup') { //set positioning to absolute for popup
            self.calendar.style.position = 'absolute';
        }
        //if a target element has been set, append the calendar to it
        if(targetelement) {
            switch(self.mode) {
                case 'flat':
                    self.tgt = targetelement;
                    self.tgt.appendChild(self.calendar);
                    self.visible = true;
                    break;
                case 'popup':
                    self.calendar.style.position = 'absolute';
                    document.body.appendChild(self.calendar);
                    self.setTarget(targetelement,false);
                    break;
            }
        }
        else { //otherwise, add the calendar to the document.body (useful if targetelement will not be defined until after the calendar is initialized)
            document.body.appendChild(self.calendar);
            self.visible = false;
        }
    }
    //-----------------------------------------------------------------------------
    /**
    * Removes the calendar table cells from the DOM (does not delete the cell objects associated with them)
    */
    function deleteCells() {
        self.calendar.celltable.removeChild(self.calendar.celltable.childNodes[1]); //remove the tbody element from the cell table
    }
    //-----------------------------------------------------------------------------
    /**
    * Sets the CSS class of the element, W3C & IE
    * @param HTMLElement element
    * @param string className
    */
    function setClass(element,className) {
        element.setAttribute('class',className);
        element.setAttribute('className',className); //<iehack>
    }
    /**
    * Updates a cell's data, including css class and selection properties
    * @param int cellindex
    */
    function setCellProperties(cellindex) {
        var cell = self.cells[cellindex];
        var date;
        idx = self.dateInArray(self.dates,cell.date);
        if(idx > -1) {
            date = self.dates[idx]; //reduce indirection
            cell.date.selected = date.selected || false;
            cell.date.type = date.type;
            cell.date.canSelect = date.canSelect;
            cell.setTitle(date.title);
            cell.setURL(date.href);
            cell.setHTML(date.cellHTML);
        }
        else {
            cell.date.selected = false; //if the cell's date isn't in the dates array, set it's selected value to false
        }
        //make all cells lying outside the min and max dates un-selectable
        if(cell.date.getTime() < self.minDate.getTime() || cell.date.getTime() > self.maxDate.getTime()) {
            cell.date.canSelect = false;
        }
        cell.setClass();
    }
    //-----------------------------------------------------------------------------
    function cal_onmouseover() {
        self.mousein = true;
    }
    //-----------------------------------------------------------------------------
    function cal_onmouseout()    {
        self.mousein = false;
    }
    //-----------------------------------------------------------------------------
    /**
     * Updates the calendar's selectedDates pointer array
     */
    function updateSelectedDates() {
        var idx = 0;
        self.selectedDates = new Array();
        for(i=0;i<self.dates.length;i++) {
            if(self.dates[i].selected) {
                self.selectedDates[idx++] = self.dates[i];
                /*alert(self.selectedDates);   */
            }
        }
    }
    //PUBLIC METHODS
    //-----------------------------------------------------------------------------
    /**
    * Find a date in the given array, returning its index if found, -1 if not
    * @param array arr
    * @param Date searchVal
    * @param int startIndex
    * @return int
    */
    self.dateInArray = function(arr,searchVal,startIndex) {
        startIndex = (startIndex != null ? startIndex : 0); //default startIndex to 0, if not set
        for(var i=startIndex;i<arr.length;i++) {
            if(searchVal.getUeDay() == arr[i].getUeDay()) {
                return i;
            }
        }
        return -1;
    };
    //-----------------------------------------------------------------------------
    /**
    * Changes the target element of this calendar to another input.
    * Many thanks to Jake Olefsky - jake@olefsky.com
    * @param HTMLInputElement targetelement
    * @param bool focus
    */
    self.setTarget = function (targetelement, focus)
    {
        //if this is a popup calendar
        if(self.mode == 'popup') {
            //declare the event handlers for the target element
            function popupFocus() {
                self.show();
            }
            function popupBlur() {
                if(!self.mousein){
                    self.hide();
                }
            }
            function popupKeyDown() {
                self.hide();
            }
            
            
            //unset old target element event handlers (if there is one yet)
            if(self.tgt) {
                removeEventHandler(self.tgt,'focus',popupFocus);
                removeEventHandler(self.tgt,'blur',popupBlur);
                removeEventHandler(self.tgt,'keydown',popupKeyDown);
            }
            //and set the new target element
            self.tgt = targetelement;
            //create a pointer to the INPUT's date object and init the new data array
            var dto = self.tgt.dateObj,pdateArr = new Array;
            //if a date is set for the target element
            if(dto) {
                if(self.tgt.value.length) { //load it into the calendar...
                    pdateArr[0] = dto;
                }
                self.goToMonth(dto.getFullYear(),dto.getMonth()); //...and go to the target's month/year
            }
            self.selectDates(pdateArr,true,true,true);

            self.topOffset = self.tgt.offsetHeight; // the vertical distance (in pixels) to display the calendar from the Top of its input element
            self.leftOffset = 0;                     // the horizontal distance (in pixels) to display the calendar from the Left of its input element
            self.updatePos(self.tgt);
            //and add the event handlers to the new element
            addEventHandler(self.tgt,'focus',popupFocus);
            addEventHandler(self.tgt,'blur',popupBlur);
            addEventHandler(self.tgt,'keydown',popupKeyDown);
            if(focus !== false) { //focus the target element immediately, unless otherwise specified
                popupFocus();
            }
        }
        else { //if this is a flat or inline calendar
            //if the target is already set, remove the calendar's DOM representation from it
            if(self.tgt) {
                self.tgt.removeChild(self.calendar);
            }
            //now, set the calendar's target to the new target element, and show the calendar
            self.tgt = targetelement; 
            self.tgt.appendChild(self.calendar);
            self.show();
        }
    };
    //-----------------------------------------------------------------------------
    /**
    * Go to the next month.  if the month is December, go to January of the next year
    * Returns true if the month will be incremented
    * @return bool
    */
    self.nextMonth = function () {
        var month = self.displayMonth;
        var year = self.displayYear;
        //increment the month/year values, provided they're within the min/max ranges
        if(self.displayMonth < 11) { //i.e. if currently in the year
            month++;
        }
        else if(self.yearSelect.value < self.maxDate.getFullYear()) { //if not, increment the year as well
            month = 0;
            year++;
        }
        return self.goToMonth(year,month);
    };
    //-----------------------------------------------------------------------------
    /**
    * Go to the previous month - if the month is January, go to December of the previous year.
    * Returns true if the month will be decremented
    * @return bool
    */
    self.prevMonth = function () {
        var month = self.displayMonth;
        var year = self.displayYear;
        //increment the month/year values, provided they're within the min/max ranges
        if(self.displayMonth > 0) { //i.e. if currently in the year
            month--;
        }
        else { //if not, decrement the year as well
            month = 11;
            year--;
        }
        return self.goToMonth(year,month);
    };
    //-----------------------------------------------------------------------------
    /**
    * Sets the calendar to display the requested month/year, returning true if the
    * date is within the minimum and maximum allowed dates
    * @param int year
    * @param int month
    * @return bool
    */
    self.goToMonth = function (year,month) {
        var testdatemin = new Date(year, month, 31);
        var testdatemax = new Date(year, month, 1);
        if(testdatemin >= self.minDate && testdatemax <= self.maxDate) {
            self.monthSelect.value = self.displayMonth = month;
            self.yearSelect.value = self.displayYear = year;
            //recreate the calendar for the new month
            createCalCells();
            deleteCells();
            self.calendar.celltable.appendChild(self.calCells);
            return true;
        }
        else {
            alert(self.maxrange_caption);
            return false;
        }
    };
    //-----------------------------------------------------------------------------
    /**
    * Moves the calendar's position to the target element's location (popup mode only)
    */
    self.updatePos = function (target) {
        if(self.mode == 'popup') {
            self.calendar.style.top = getTop(target) + self.topOffset + 'px';
            self.calendar.style.left = getLeft(target) + self.leftOffset + 'px';
        }
    };
    //-----------------------------------------------------------------------------
    /**
    * Displays the calendar
    */
    self.show = function ()    {
        self.updatePos(self.tgt); //update the calendar position, in case the page layout has changed since loading
        self.calendar.style.display = 'block'; //'table'; //<iehack> 'table' is the W3C-recommended spec, but IE isn't a fan of those
        self.visible = true;
    };
    //-----------------------------------------------------------------------------
    /**
    * Hides the calendar
    */
    self.hide = function () {
        self.calendar.style.display = 'none';
        self.visible = false;
    };
    //-----------------------------------------------------------------------------
    /**
    * Toggles (shows/hides) the calendar depending on its current state
    */
    self.toggle = function () {
        self.visible ? self.hide() : self.show();
    };
    //-----------------------------------------------------------------------------
    /**
    * Adds the array "dates" to the calendar's dates array, removing duplicate dates,
    * and redraws the calendar if redraw is true
    * @param array dates
    * @param bool redraw
    */
    self.addDates = function (dates,redraw) {
        var i;
        for(i=0;i<dates.length;i++) {
            if(self.dateInArray(self.dates,dates[i]) == -1) { //if the date isn't already in the array, add it!
                self.dates[self.dates.length] = dates[i];
            }
        }
        //now rebuild the selectedDates pointer array
        updateSelectedDates();
        if(redraw != false) { //redraw  the calendar if "redraw" is false or undefined
            self.reDraw();
        }
    };
    //-----------------------------------------------------------------------------
    /**
    * Removes the dates from the calendar's dates array and redraws the calendar
    * if redraw is true
    * @param array dates
    * @param bool redraw
    */
    self.removeDates = function (dates,redraw) {
        var idx;
        for(var i=0;i<dates.length;i++) {
            idx = self.dateInArray(self.dates,dates[i]);
            if(idx != -1) { //search for the dates in the dates array, removing them if the dates match
                self.dates.splice(idx,1);
            }
        }
        updateSelectedDates(); 
        if(redraw != false) { //redraw  the calendar if "redraw" is true or undefined
            self.reDraw();
        }
    };
    //-----------------------------------------------------------------------------
    /**
    * Selects or Deselects an array of dates
    * @param Array inpdates
    * @param bool selectVal
    * @param bool redraw
    * @param bool removeothers
    */
    self.selectDates = function (inpdates,selectVal,redraw,removeothers) {
        var i, idx;
        if(removeothers == true) {
            for(i=0;i<self.dates.length;i++) {
                self.dates[i].selected = false;
            }
        }
        for(i=0;i<inpdates.length;i++) {
            idx = self.dateInArray(self.dates,inpdates[i]);
            if(selectVal == true) {
                inpdates[i].selected = true;
                if(idx == -1) { //if the date does not exist in the calendar's dates array, add it
                    self.dates[self.dates.length] = inpdates[i];
               
                    /*alert(inpdates[i]);*/
                }
                else { //if not, just select it
                    self.dates[idx].selected = true;
                }
            }
            else { //if deselecting...
                if(idx > -1) { //if the date is found, deselect and/or remove it from the calendar's dates array
                    self.dates[idx].selected = inpdates[i].selected = false;
                    if(self.dates[idx].type == 'normal') { //remove 'normal' dates from the dates array, since they're useless unless selected
                        self.dates.splice(idx,1);
                    }
                }
            }
        }
        //now rebuild the selectedDates pointer array
        updateSelectedDates();
        if(redraw != false) { //redraw the calendar if "redraw" is false or undefined
            self.reDraw();
        }
    };
    //-----------------------------------------------------------------------------
    /**
    * Adds the dates in dates as hidden inputs to the form "form".  inputname
    * is the name of each hidden element. "form" can either be a pointer to the form's
    * DOM element or its id string.
    * @param mixed form
    * @param string inputname
    */
    self.sendForm = function(form,inputname) {
        var inpname = inputname || 'epochdates', f, inp;
        f = (typeof(form) == 'string' ? document.getElementById(form) : form);
        if(!f) {
            alert('ERROR: Invalid form input');
            return false;
        }
        for(var i=0;i<self.dates.length;i++) {
            inp = document.createElement('input');
            inp.setAttribute('type','hidden');
            inp.setAttribute('name',inpname + '['+i+']');
           
            inp.setAttribute('value',encodeURIComponent(self.dates[i].dateFormat('Y-m-d')));  //default to the ISO date format      
/*             alert("test")  */
            f.appendChild(inp);
        }
        return true;
    };
    //-----------------------------------------------------------------------------
    /**
    * Erases the dates array and resets the calendar's selection variables to defaults.
    * If retMonth is true, the calendar will return to the initial default month/year
    * @param bool retMonth
    */
    self.resetSelections = function (retMonth) {
        var dateArray = new Array();
        var dt = self.dates;
        for(var i=0;i<dt.length;i++) {
            if(dt[i].selected) {
                dateArray[dateArray.length] = dt[i];
            }
        }
        self.selectDates(dateArray,false,false);
        self.rows = new Array(false,false,false,false,false,false,false);
        self.cols = new Array(false,false,false,false,false,false,false);
        if(self.mode == 'popup') { //hide the calendar and clear the input element if in popup mode
            self.tgt.value = '';
            self.hide();
        }
        retMonth == true ? self.goToMonth(self.displayYearInitial,self.displayMonthInitial) : self.reDraw();
    };
    //-----------------------------------------------------------------------------
    /**
    * Reapplies all the CSS classes for the calendar cells - usually called after changing their state
    * If index is specified, it will redraw that cell only.
    * @param int index
    */
    self.reDraw = function (index) {
        self.state = 1;
        var len = index ? index + 1 : self.cells.length;
        for(var i = index || 0;i<len;i++) {
            setCellProperties(i);
        }
        self.state = 2;
    };
    //-----------------------------------------------------------------------------
    /**
    * Returns the index of the cell whose date value matches "date", or -1 if not found
    * @param Date date
    * @return int
    */
    self.getCellIndex = function(date) {
        for(var i=0;i<self.cells.length;i++) {
            if(self.cells[i].date.getUeDay() == date.getUeDay()) {
                return i;
            }
        }
        return -1;
    };
    //-----------------------------------------------------------------------------
    //begin constructor code:

    //PUBLIC VARIABLES
    self.state = 0;
    self.name = name;
    da = new Date();
   /* alert(da);    */
    self.curDate = da;
    self.mode = mode;
    self.selectMultiple = (multiselect == true); //'false' if not true or not set at all
    //the various calendar variables
    self.dates = new Array();
    self.selectedDates = new Array();

    self.calendar;
    self.calHeading;
    self.calCells;
    self.rows;
    self.cols;
    self.cells = new Array();
    //The controls
    self.monthSelect;
    self.yearSelect;
    self.mousein = false;

    //Initialize the calendar and its variables{
    calConfig();
    setLang();
    setDays();
    createCalendar(); //create the calendar DOM element and its children, and their related objects
    targetelement = typeof(targetelement) == 'string' ? document.getElementById(targetelement) : targetelement;
    setMode(targetelement);
    self.state = 2; //0: initializing, 1: redrawing, 2: finished!
    self.visible ? self.show() : self.hide();
}
//-----------------------------------------------------------------------------
/*****************************************************************************/
/**
* Object that contains the methods and properties for the calendar day headings
*/
function CalHeading(owner,tableCell,dayOfWeek) {
    //-----------------------------------------------------------------------------
    function DayHeadingonclick() {//selects/deselects the days for this object's day of week
        //reduce indirection:
        var sdates = owner.dates;
        var cells = owner.cells;
        var dateArray = new Array();
        owner.cols[dayOfWeek] = !owner.cols[dayOfWeek];
        for(var i=0;i<cells.length;i++) { //cycle through all the cells in the calendar, selecting all cells with the same dayOfWeek as this heading
            if(cells[i].dayOfWeek == dayOfWeek && cells[i].date.canSelect && (!owner.selCurMonthOnly || cells[i].date.getMonth() == owner.displayMonth && cells[i].date.getFullYear() == owner.displayYear)) { //if the cell's DoW matches, with other conditions
                dateArray[dateArray.length] = cells[i].date;
            }
        }
        owner.selectDates(dateArray,owner.cols[dayOfWeek],true);
    }
    //-----------------------------------------------------------------------------
    var self = this;
    self.dayOfWeek = dayOfWeek;
    addEventHandler(tableCell,'mouseup',DayHeadingonclick);
}
/*****************************************************************************/
/**
* Object that contains the methods and properties for the calendar week headings
*/
function WeekHeading(owner,tableCell,week,tableRow) {
    //-----------------------------------------------------------------------------
    function weekHeadingonclick() {
        //reduce indirection:
        var cells = owner.cells;
        var sdates = owner.dates;
        var dateArray = new Array();
        owner.rows[tableRow] = !owner.rows[tableRow];
        for(var i=0;i<cells.length;i++) {
            if(cells[i].tableRow == tableRow && cells[i].date.canSelect && (!owner.selCurMonthOnly || cells[i].date.getMonth() == owner.displayMonth && cells[i].date.getFullYear() == owner.displayYear)) { //if the cell's DoW matches, with other conditions)
                dateArray[dateArray.length] = cells[i].date;
            }
        }
        owner.selectDates(dateArray,owner.rows[tableRow],true);
    }
    //-----------------------------------------------------------------------------
    var self = this;
    self.week = week;
    tableCell.setAttribute('class','wkhead');
    tableCell.setAttribute('className','wkhead'); //<iehack>
    addEventHandler(tableCell,'mouseup',weekHeadingonclick);
}
/*****************************************************************************/
/**
* Object that holds all data & code related to a calendar cell
*/
/**
 * The CalCell constructor function
 * @param Epoch owner
 * @param HTMLTableCellElement tableCell
 * @param Date dateObj
 * @param int row
 * @param int week
 */
function CalCell(owner,tableCell,dateObj,row,week,ourTab) {
    var self = this;
    //-----------------------------------------------------------------------------
    function calCellonclick() {
        if(self.date.canSelect) {
            if(owner.selectMultiple == true) { //if we can select multiple cells simultaneously, add the currently selected self's date to the dates array
                owner.selectDates(new Array(self.date),!self.date.selected,false);
                self.setClass(); //update the current cell's style to reflect the changes - a full redraw isn't necessary
            }
            else { //if we can only select one date at a time
                owner.selectDates(new Array(self.date),true,false,true);
                if(owner.mode == 'popup') 
                { //update the target element's value and hide the calendar if in popup mode
                    owner.tgt.value = self.date.dateFormat(); //use the default date format defined in dateFormat
                      if(ourTab) 
                      { 
                        if(ourTab == 'tab4')
                        {
                            type = 4;
                            fnGetBodyLog_Values(self.date.dateFormat(),type); 
                        }
                        if(ourTab == 'tab9')
                        {
                            type = 9;
                            fnGetBodyLog_Values(self.date.dateFormat(),type); 
                        }
                      }
                    owner.tgt.dateObj = new Date(self.date); //add a Date object to the target element for later reference
                    owner.hide();
                }
                owner.reDraw(); //redraw all the calendar cells
            }
        }
    }
    //-----------------------------------------------------------------------------
    /**
    * Replicate the CSS :hover effect for non-supporting browsers <iehack>
    */
    function calCellonmouseover() {
        if(self.date.canSelect) {
            tableCell.setAttribute('class',self.cellClass + ' hover');
            tableCell.setAttribute('className',self.cellClass + ' hover');
        }
    }
    //-----------------------------------------------------------------------------
    /**
    * Replicate the CSS :hover effect for non-supporting browsers <iehack>
    */
    function calCellonmouseout() {
        self.setClass();
    }
    //-----------------------------------------------------------------------------
    /**
    * Sets the CSS class of the cell based on the specified criteria
    */
    self.setClass = function ()
    {
        if(self.date.canSelect !== false) {
            if(self.date.selected) {
                self.cellClass = 'cell_selected';
            }
            else if(owner.displayMonth != self.date.getMonth() ) {
                self.cellClass = 'notmnth';
            }
            else if(self.date.type == 'holiday') {
                self.cellClass = 'hlday';
            }
            else if(self.dayOfWeek > 0 && self.dayOfWeek < 6) {
                self.cellClass = 'wkday';
            }
            else {
                self.cellClass = 'wkend';
            }
        }
        else {
            self.cellClass = 'noselect';
        }
        //highlight the current date
        if(self.date.getUeDay() == owner.curDate.getUeDay()) {
            self.cellClass = self.cellClass + ' curdate';
        }
        tableCell.setAttribute('class',self.cellClass);
        tableCell.setAttribute('className',self.cellClass); //<iehack>
    };
    //-----------------------------------------------------------------------------
    /**
    * Sets the cell's hyperlink, if declared
    * @param string href
    * @param string type ('anchor' or 'js' - default 'anchor')
    */
    self.setURL = function(href,type) {
        if(href) {
            if(type == 'js') { //Make the WHOLE cell be a clickable link
                addEventHandler(self.tableCell,'mousedown',function(){window.location.href = href;});
            }
            else { //make only the date number of the cell a clickable link:
                var url = document.createElement('a');
                url.setAttribute('href',href);
                url.appendChild(document.createTextNode(self.date.getDate()));
                self.tableCell.replaceChild(url,self.tableCell.firstChild); //assumes the first child of the cell DOM node is the date text
            }
        }
    };
    //-----------------------------------------------------------------------------
    /**
    * Sets the title (i.e. tooltip) that appears when a user holds their mouse cursor over a cell
    * @param string titleStr
    */
    self.setTitle = function(titleStr) {
        if(titleStr && titleStr.length > 0) {
            self.title = titleStr;
            self.tableCell.setAttribute('title',titleStr);
        }
    };
    //-----------------------------------------------------------------------------
    /**
    * Sets the internal html of the cell, using a string containing html markup
    * @param string html
    */
    self.setHTML = function(html) {
        if(html && html.length > 0) {
            if(self.tableCell.childNodes[1]) {
                self.tableCell.childNodes[1].innerHTML = html;
            }
            else {
                var htmlCont = document.createElement('div');
                htmlCont.innerHTML = html;
                self.tableCell.appendChild(htmlCont);
            }
        }
    };
    //-----------------------------------------------------------------------------
    self.cellClass;            //the CSS class of the cell
    self.tableRow = row;
    self.tableCell = tableCell;
    self.date = new Date(dateObj);
    self.date.canSelect = true; //whether this cell can be selected or not - always true unless set otherwise externally
    self.date.type = 'normal';  //i.e. normal date, holiday, etc - always true unless set otherwise externally
    self.date.selected = false;    //whether the cell is selected (and is therefore stored in the owner's dates array)
    self.date.cellHTML = '';
    self.dayOfWeek = self.date.getDay();
    self.week = week;
    //assign the event handlers for the table cell element
    addEventHandler(tableCell,'click', calCellonclick);
    addEventHandler(tableCell,'mouseover', calCellonmouseover);
    addEventHandler(tableCell,'mouseout', calCellonmouseout);
    self.setClass();
}
/*****************************************************************************/
Date.prototype.getDayOfYear = function () //returns the day of the year for this date
{
    return parseInt((this.getTime() - new Date(this.getFullYear(),0,1).getTime())/86400000 + 1);
};
//-----------------------------------------------------------------------------
/**
 * Returns the week number for this date.  dowOffset is the day of week the week
 * "starts" on for your locale - it can be from 0 to 6. If dowOffset is 1 (Monday),
 * the week returned is the ISO 8601 week number.
 * @param int dowOffset
 * @return int
 */
Date.prototype.getWeek = function (dowOffset) {
    dowOffset = typeof(dowOffset) == 'int' ? dowOffset : 0; //default dowOffset to zero
    var newYear = new Date(this.getFullYear(),0,1);
    var day = newYear.getDay() - dowOffset; //the day of week the year begins on
    day = (day >= 0 ? day : day + 7);
    var weeknum, daynum = Math.floor((this.getTime() - newYear.getTime() - (this.getTimezoneOffset()-newYear.getTimezoneOffset())*60000)/86400000) + 1;
    //if the year starts before the middle of a week
    if(day < 4) {
        weeknum = Math.floor((daynum+day-1)/7) + 1;
        if(weeknum > 52) {
            nYear = new Date(this.getFullYear() + 1,0,1);
            nday = nYear.getDay() - dowOffset;
            nday = nday >= 0 ? nday : nday + 7;
            weeknum = nday < 4 ? 1 : 53; //if the next year starts before the middle of the week, it is week #1 of that year
        }
    }
    else {
        weeknum = Math.floor((daynum+day-1)/7);
    }
    return weeknum;
};
//-----------------------------------------------------------------------------
Date.prototype.getUeDay = function () //returns the number of DAYS since the UNIX Epoch - good for comparing the date portion
{
    return parseInt(Math.floor((this.getTime() - this.getTimezoneOffset() * 60000)/86400000)); //must take into account the local timezone
};
//-----------------------------------------------------------------------------
Date.prototype.dateFormat = function(format)
{
    if(!format) { // the default date format to use - can be customized to the current locale
        format = 'm/d/Y';
    }
    LZ = function(x) {return(x < 0 || x > 9 ? '' : '0') + x};
    var MONTH_NAMES = new Array('January','February','March','April','May','June','July','August','September','October','November','December','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
    var DAY_NAMES = new Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sun','Mon','Tue','Wed','Thu','Fri','Sat');
    var result="";
    var i_format=0;
    var c="";
    var token="";
  /*  alert(y);             */
    var y=this.getFullYear().toString();
    var M=this.getMonth()+1;
    var d=this.getDate();
    var E=this.getDay();
    var H=this.getHours();
    var m=this.getMinutes();
    var s=this.getSeconds();
    value = {
        Y: y.toString(),
        y: y.substring(2),
        n: M,
        m: LZ(M),
        F: MONTH_NAMES[M-1],
        M: MONTH_NAMES[M+11],
        j: d,
        d: LZ(d),
        D: DAY_NAMES[E+7],
        l: DAY_NAMES[E],
        G: H,
        H: LZ(H)
    };
    if (H==0) {value['g']=12;}
    else if (H>12){value['g']=H-12;}
    else {value['g']=H;}
    value['h']=LZ(value['g']);
    if (H > 11) {value['a']='pm'; value['A'] = 'PM';}
    else { value['a']='am'; value['A'] = 'AM';}
    value['i']=LZ(m);
    value['s']=LZ(s);
    //construct the result string
    while (i_format < format.length) {
        c=format.charAt(i_format);
        token="";
        while ((format.charAt(i_format)==c) && (i_format < format.length)) {
            token += format.charAt(i_format++);
        }
        if (value[token] != null) { result=result + value[token]; }
        else { result=result + token; }
    }
    return result;
};
 
/*****************************************************************************/
//-----------------------------------------------------------------------------
function addEventHandler(element, type, func) { //unfortunate hack to deal with Internet Explorer's horrible DOM event model <iehack>
    if(element.addEventListener) {
        element.addEventListener(type,func,false);
    }
    else if (element.attachEvent) {
        element.attachEvent('on'+type,func);
    }
}
//-----------------------------------------------------------------------------
function removeEventHandler(element, type, func) { //unfortunate hack to deal with Internet Explorer's horrible DOM event model <iehack>
    if(element.removeEventListener) {
        element.removeEventListener(type,func,false);
    }
    else if (element.attachEvent) {
        element.detachEvent('on'+type,func);
    }
}
//-----------------------------------------------------------------------------
function getTop(element) {//returns the absolute Top value of element, in pixels
    var oNode = element;
    var iTop = 0;

    while(oNode.tagName != 'HTML') {
        iTop += oNode.offsetTop || 0;
        if(oNode.offsetParent) { //i.e. the parent element is not hidden
            oNode = oNode.offsetParent;
        }
        else {
            break;
        }
    }
    return iTop;
}
//-----------------------------------------------------------------------------
function getLeft(element) { //returns the absolute Left value of element, in pixels
    var oNode = element;
    var iLeft = 0;
    while(oNode.tagName != 'HTML') {
        iLeft += oNode.offsetLeft || 0;
        if(oNode.offsetParent) { //i.e. the parent element is not hidden
            oNode = oNode.offsetParent;
        }
        else {
            break;
        }
    }
    return iLeft;
}
//-----------------------------------------------------------------------------


