      /***************
       * DEFINITIONS *
       ***************/

      /* display names */

      var Centuries = [
        "1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", "10th",
        "11th", "12th", "13th", "14th", "15th", "16th", "17th", "18th", "19th", "20th",
        "21st", "22nd", "23rd", "24th", "25th", "26th", "27th", "28th", "29th", "30th",
        "31st", "32nd", "33rd", "34th", "35th", "36th", "37th", "38th", "39th", "40th",
        "41st", "42nd", "43rd", "44th", "45th", "46th", "47th", "48th", "49th", "50th",
        "51st", "52nd", "53rd", "54th", "55th", "56th", "57th", "58th", "59th", "60th",
        "61st", "62nd", "63rd", "64th", "65th", "66th", "67th", "68th", "69th", "70th",
        "71st", "72nd", "73rd", "74th", "75th", "76th", "77th", "78th", "79th", "80th",
        "81st", "82nd", "83rd", "84th", "85th", "86th", "87th", "88th", "89th", "90th",
        "91st", "92nd", "93rd", "94th", "95th", "96th", "97th", "98th", "99th", "100th"];

      var FrenchMonths = [
        "Vendémiaire", "Brumaire", "Frimaire", "Nivôse", "Pluviôse", "Ventôse",
        "Germinal", "Floréal", "Prairial", "Messidor", "Thermidor", "Fructidor",
        "vertu", "génie", "travail", "opinion", "récompenses", "révolution"];

      var EnglishMonths = [
        "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 EnglishDaysOfWeek =
//        ["Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri"];
        ["Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday"];

      var FrenchDaysOfWeek =
        ["Primidi", "Duodi", "Tridi", "Quartidi", "Quintidi", "Sextidi", "Septidi", "Octidi", "Nonidi", "Decadi"];

      /* internal names (should really be enumeration types) */

      englishCentury = 0;
      frenchCentury = 1;

      vendémiaire = 0;
      brumaire = 1;
      frimaire = 2;
      nivôse = 3;
      pluviôse = 4;
      ventôse = 5
      germinal = 6;
      floréal = 7;
      prairial = 8;
      messidor = 9;
      thermidor = 10;
      fructidor = 11;
      vertu = 12;
      génie = 13;
      travail = 14;
      opinion = 15;
      récompenses = 16;
      révolution = 17;

      january = 0;
      february = 1;
      march = 2;
      april = 3;
      may = 4;
      june = 5;
      july = 6;
      august = 7;
      september = 8;
      october = 9;
      november = 10;
      december = 11;

      saturday = 0;
      sunday = 1;
      monday = 2;
      tuesday = 3;
      wednesday = 4;
      thursday = 5;
      friday = 6;

      complete = -1;
      normal = 0;
      defective = 1;

      julian = 0;
      gregorian = 1;

      /*******************
       * STATE VARIABLES *
       *******************/

      var CenturyIndex;
      var CenturyTypeIndex;

      var FrenchMonthIndex;
      var FrenchDayIndex;
      var FrenchYearIndex;
      var FrenchYearKind;

      var EnglishMonthIndex;
      var EnglishDayIndex;
      var EnglishYearIndex;

      var EnglishDayOfWeekIndex;
      var FrenchYearKindForDisplay;

      var CalendarType = gregorian;

      /********
       * Misc *
       ********/

      function Mod(X, Y) {
        return X - Math.floor(X / Y) * Y;
      }

      /****************************
       * FRENCH UTILITY FUNCTIONS *
       ****************************/

      function FrenchStartYear() {
        year = 100*(CenturyIndex);
        if (CenturyTypeIndex == englishCentury) {
          year -= 1792;
        }
        return year;
      }

      function FrenchYear() {
        var x = FrenchStartYear() + FrenchYearIndex;
        return x;
      }

      function DaysInFrenchMonth(year, month) {
        if (month < vertu) {
          return 30;
        } else if (month == révolution) {
          return (IsFrenchLeapYear(year)) ? 1 : 0;
        } else {
          return 1;
        }
      }

      function IsFrenchLeapYear(year) {

        if (year == 3 || year == 7 || year == 11 || year == 15) {
          return true;
        } else if (year < 20) {
          return false;
        } else {
          return ((Mod(year,4) == 0 && Mod(year,100) != 0) || Mod(year,400) == 0) ? true : false;
        }
      }

      function DaysInFrenchYear(year) {
        return IsFrenchLeapYear(year) ? 366 : 365;
      }

      /*****************************
       * ENGLISH UTILITY FUNCTIONS *
       *****************************/

      function EnglishStartYear() {
        year = 100*(CenturyIndex);
        if (CenturyTypeIndex == frenchCentury) {
          year += 1792;
        }
        return year;
      }

      function EnglishYear() {
        return EnglishStartYear() + EnglishYearIndex;
      }

      function DaysInEnglishMonth(year, month) {
        if (month == april || month == june || month == september || month == november) {
          return 30;
        } else if (month != february) {
          return 31;
        } else if (IsEnglishLeapYear(year)) {
          return 29;
        } else {
          return 28;
        }
      }

      function IsEnglishLeapYear(year) {
        yr4 = Mod(year, 4);
        yr100 = Mod(year, 100);
        yr400 = Mod(year, 400);
        if (CalendarType == gregorian) {
          return ((yr4 == 0 && yr100 != 0) || yr400 == 0) ? true : false;
        } else {
          return (yr4 == 0) ? true : false;
        }
      }

      function DaysInEnglishYear(year) {
        return IsEnglishLeapYear(year) ? 366 : 365;
      }

      /********************************
       * MAIN COMPUTATIONAL FUNCTIONS *
       ********************************/

      var absolute = 0;

      function FrenchToAbsolute() {
        if (debugging) alert("entering FrenchToAbsolute");

        // start at beginning of French year 1
        
        absolute = 0;

        // get to start of current year

        for (var i=1; i<FrenchYear(); i++) {
          absolute += 365;
          if (IsFrenchLeapYear(i)) {
            absolute++;
          }
        }

        // add in days for each French month up to current month

        absolute += FrenchDayIndex;
        for (k=vendémiaire; k<FrenchMonthIndex; k++) {
          absolute += DaysInFrenchMonth(FrenchYear(), k);
        }
        if (debugging) alert("leaving FrenchToAbsolute");
      }

      var daysIn400JulianYears = 365*400 + 100;
      var daysIn400GregorianYears = daysIn400JulianYears - 3;

      function EnglishToAbsolute() {
        if (debugging) alert("entering EnglishToAbsolute");

        // start at September 22, 1792
        
        absolute = 0;

        // factor out 400-year cycles for efficiency

        ey = EnglishYear();
        while (ey-1792 >= 400) {
          ey -= 400;
          absolute += (CalendarType == gregorian) ? daysIn400GregorianYears : daysIn400JulianYears;
        }

        // get to start of current year

        for (var i=1792; i<ey; i++) {
          absolute += DaysInEnglishYear(i);
        }

        // add in days for each English month up to current month

        absolute += EnglishDayIndex;
        for (k=january; k<EnglishMonthIndex; k++) {
          absolute += DaysInEnglishMonth(ey, k);
        }

        // subtract out days from Jan 1 to Sep 21 in 1792

        for (k=january; k<september; k++) {
          absolute -= DaysInEnglishMonth(1792, k);
        }
        absolute -= (CalendarType == gregorian) ? 21 : 10;
        if (debugging) alert("leaving EnglishToAbsolute");
      }

      function EnglishDayOfWeek() {
        return EnglishDaysOfWeek[Mod(absolute,7)];
      }

      function FrenchDayOfWeek() {
        return FrenchDaysOfWeek[Mod(FrenchDayIndex,10)];
      }

      function AbsoluteToFrench() {
        // start with vendémiaire 1, 1

        var year = 1;
        var month = vendémiaire;
        var day = 0;
        var oldAbsolute = absolute;

        // process full years

        while (absolute >= DaysInFrenchYear(year)) {
          absolute -= DaysInFrenchYear(year);
          year++;
        }

        // process last partial year

        while (absolute >= DaysInFrenchMonth(year, month)) {
          absolute -= DaysInFrenchMonth(year, month);
          month++;
        }
        day += absolute;

        // update display

        FrenchYearIndex = year - FrenchStartYear();
        FrenchMonthIndex = month;
        FrenchDayIndex = day;

        /* make sure century start is ok
         *   note: if the century was specified as being a french century, an extra
         *   year was put into the english year list so this conversion can never give an
         *   out-of-bound year.  Problem arises only when an english century was specified.
         */

        if (CenturyTypeIndex == englishCentury) {
          while(FrenchYearIndex>100) {
            FrenchYearIndex -= 100;
            EnglishYearIndex -= 100;
            CenturyIndex++;
          }
          while(FrenchYearIndex<0) {
            FrenchYearIndex += 100;
            EnglishYearIndex += 100;
            CenturyIndex--;
          }
        }
        absolute = oldAbsolute;

        if (debugging) alert("leaving AbsoluteToEnglish");
      }

      function AbsoluteToEnglish() {

        // start with september 22, 1792

        var year = 1792;
        var month = september;
        var day = (CalendarType == gregorian) ? 21 : 10;
        var oldAbsolute = absolute;

        // process partial year 1792

        while (true) {
          if (absolute < DaysInEnglishMonth(year, month) - day) {
            day += absolute;
            absolute = 0;
            break;
          } else {
            absolute -= (DaysInEnglishMonth(year, month) - day);
            day = 0;
            month++;
            if (month > december) {
              month = january;
              year++;
            }
          }
        }

        // factor out 400-year cycles for efficiency
        
        var daysIn400Years = (CalendarType == gregorian) ? daysIn400GregorianYears : daysIn400JulianYears;
        while (absolute >= daysIn400Years) {
          absolute -= daysIn400Years;
          year += 400;
        }

        // process full years

        while (absolute >= DaysInEnglishYear(year)) {
          absolute -= DaysInEnglishYear(year);
          year++;
        }

        // process last partial year

        while (absolute >= DaysInEnglishMonth(year, month)) {
          absolute -= DaysInEnglishMonth(year, month);
          month++;
        }
        day += absolute;


        // update display

        EnglishYearIndex = year - EnglishStartYear();
        EnglishMonthIndex = month;
        EnglishDayIndex = day;

        /* make sure century start is ok
         *   note: if the century was specified as being a french century, an extra
         *   year was put into the english year list so this conversion can never give an
         *   out-of-bound year.  Problem arises only when an english century was specified.
         */
        if (CenturyTypeIndex == englishCentury) {
          while(EnglishYearIndex>99) {
            EnglishYearIndex -= 100;
            FrenchYearIndex -= 100;
            CenturyIndex++;
          }
          while(EnglishYearIndex<0) {
            EnglishYearIndex += 100;
            FrenchYearIndex += 100;
            CenturyIndex--;
          }
        }
        absolute = oldAbsolute;

        if (debugging) alert("leaving AbsoluteToEnglish");
      }

