    function validDate(year, month, day)
    {
      // Returns an object with properties "isValid" and "errorMessage".
      // isValid is true if year, month and day can be parsed into a valid date and
      // the day is not greater than the maximum allowable day for the month
      // of the year.
      // Otherwise isValid is false.
      // errorMessage is set to an appropriate value for each case of an invalid date.
      // If the date is valid errorMessage is null.

      var validation = new Object();

      var isValid = true;
      var errorMessage = "";
      var noInt = false;

      if (year % 1 != 0) {
        // The year must be an integer.
        noInt = true;
        isValid = false;
        errorMessage += "The value for the year is not an integer.\n";
      }

      if (month % 1 != 0) {
        // The month must be an integer.
        noInt = true;
        isValid = false;
        errorMessage += "The value for the month is not an integer.\n";
      }

      if (day % 1 != 0) {
        // The day must be an integer.
        noInt = true;
        isValid = false;
        errorMessage += "The value for the day is not an integer.\n";
      }

      if (!noInt &&  (year < -283646 || year > 287586)) {
        isValid = false;
        errorMessage += "The value for the year must be greater than -283647 and less than 287587.\n";
      }

      if (!noInt && (month < 1 || month > 12)) {
        isValid = false;
        errorMessage += "The value for the month must be greater than 0 and less than 13.\n";
      }

      if (!noInt && (day < 1 || day > 31)) {
        isValid = false;
        errorMessage += "The value for the day must be greater than 0 and less than 32.\n";
      }

      if (isValid) {
        var leapYear = 0;
        if (!(year%4) && year%100) {
          leapYear = 1;
        }
        if (!(year%400)) {
          leapYear = 1;
        }

        var maxDays = new Array(0, 31, leapYear?29:28, 31, 30, 31, 30, 31, 31, 30, 31, 30 ,31);
        var months = new Array(0, "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");

        if (day > maxDays[month]) {
          errorMessage += months[month] + " only has " + maxDays[month] + " days";
          if (month == 2) {
            errorMessage += " in " + year + ".\n";
          } else {
            errorMessage += ".\n";
          }
          isValid = false;
        } else {
          isValid = true;
        }
      }

      if (errorMessage == "") {
        errorMessage = null;
      }

      validation["isValid"] = isValid;
      validation["errorMessage"] = errorMessage;

      return validation;
    }

    function dateCompare(d1, d2)
    {
      // Returns -1 if d1 comes before d2.
      // Returns 0 if d1 is the same date as d2.
      // Returns +1 if d1 comes after d2.
      // Returns null if neither d1 nor d2 are date objects.
      if (d1.getTime() && d2.getTime()) {
        if (d1.getTime() < d2.getTime()) {
          return -1;
        } else if (d1.getTime() > d2.getTime()) {
          return 1;
        } else {
          return 0;
        }
      } else {
        return false;
      }
    }

    function openWindow(url, windowName, menubar, toolbar, scrollbars, status, resizable, location, directories, width, height, returnWindowObject)
    {
      var menubarText = "no";
      if (menubar) {
        menubarText = "yes";
      }

      var toolbarText = "no";
      if (toolbar) {
        toolbarText = "yes";
      }

      var scrollbarsText = "no";
      if (scrollbars) {
        scrollbarsText = "yes";
      }

      var statusText = "no";
      if (status) {
        statusText = "yes";
      }

      var resizableText = "no";
      if (resizable) {
        resizableText = "yes";
      }

      var locationText = "no";
      if (location) {
        locationText = "yes";
      }

      var directoriesText = "no";
      if (directories) {
        directoriesText = "yes";
      }

      /*
      var titlebar = true;
      var titlebarText = "no";
      if (titlebar) {
        titlebarText = "yes";
      }

      var personalbar = true;
      var personalbarText = "no";
      if (personalbar) {
        personalbarText = "yes";
      }
      */

      var parameters = "menubar=" + menubarText + "," +
                       "toolbar=" + toolbarText + "," +
                       "scrollbars=" + scrollbarsText + "," +
                       "status=" + statusText + "," +
                       "resizable=" + resizableText + "," +
                       "location=" + locationText + "," +
                       "directories=" + directoriesText + "," +
                       //"titlebar=" + titlebarText + "," +
                       //"personalbar=" + personalbarText + "," +
                       "width=" + width + "," +
                       "height=" + height;

      var newWindow = window.open(url, windowName, parameters);

      if (returnWindowObject) {
        return newWindow;
      }
    }
