Commits

Anonymous committed a5e542a

Created

Comments (0)

Files changed (15)

+1998-01-03  SL Baur  <steve@altair.xemacs.org>
+
+	* Makefile: Update to new package interface.
+
+1997-12-24  SL Baur  <steve@altair.xemacs.org>
+
+	* Makefile: Created.
+# Makefile for Calendar lisp code
+
+# This file is part of XEmacs.
+
+# XEmacs is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any
+# later version.
+
+# XEmacs is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with XEmacs; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+VERSION = 1.02
+PACKAGE = calendar
+PKG_TYPE = regular
+REQUIRES = xemacs-base
+CATEGORY = oa
+
+ELCS = appt.elc cal-dst.elc cal-french.elc cal-mayan.elc cal-x.elc \
+	cal-xemacs.elc calendar.elc diary-ins.elc diary-lib.elc holidays.elc \
+	lunar.elc solar.elc
+
+include ../../XEmacs.rules
+
+all:: $(ELCS) auto-autoloads.elc custom-load.elc
+
+srckit: srckit-std
+
+binkit: binkit-sourceonly
+;;; appt.el --- appointment notification functions.
+;; Keywords: calendar
+
+;;; -*- Mode:Emacs-Lisp -*-
+;; Appointment notification functions.
+;; Copyright (C) 1989, 1990, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+;; This file is part of XEmacs.
+
+;; XEmacs is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; XEmacs is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with XEmacs; see the file COPYING.  If not, write to the Free
+;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; 29-nov-89	created by Neil Mager <neilm@juliet.ll.mit.edu>.
+;;; 23-feb-91	hacked upon by Jamie Zawinski <jwz@lucid.com>.
+;;;  1-apr-91	some more.
+;;; 12-jul-95   updated for XEmacs 19.12 by Greg Veres 
+;;;             <gveres@cgl.uwaterloo.ca>
+;;; 21-mar-97   better support for fancy diary display by Tomasz J. Cholewo 
+;;;             <t.cholewo@ieee.org>
+;;;
+;; appt.el - visible and/or audible notification of
+;;           appointments from ~/diary file generated from
+;;           Edward M. Reingold's calendar.el.
+;;
+;; Version 2.1
+;;
+;; Comments, corrections, and improvements should be sent to
+;; Neil M. Mager
+;; Net                     <neilm@juliet.ll.mit.edu>
+;; Voice                   (617) 981-4803
+;;;
+;;; Thanks to  Edward M. Reingold for much help and many suggestions, 
+;;; And to many others for bug fixes and suggestions.
+;;;
+;;;
+;;; This functions in this file will alert the user of a 
+;;; pending appointment based on their diary file.
+;;;
+;;; ******* It is necessary to invoke 'display-time' and ********
+;;; ******* 'appt-initialize' for this to work properly. ********
+;;; 
+;;; A message will be displayed in the mode line of the emacs buffer and (if
+;;; the user desires) the terminal will beep and display a message from the
+;;; diary in the mini-buffer, or the user may select to have a message
+;;; displayed in a new buffer.
+;;;
+;;; Variables of note:
+;;;
+;;; appt-issue-message		If this variable is nil, then the code in this
+;;;				file does nothing.
+;;; appt-msg-countdown-list	Specifies how much warning you want before 
+;;;				appointments.
+;;; appt-audible		Whether to beep when it's notification-time.
+;;; appt-display-mode-line	Whether to display a countdown to the next 
+;;;				appointment in the mode-line.
+;;; appt-announce-method	The function used to do the notifications.
+;;;	'appt-window-announce		   do it in a pop-up window.
+;;;     'appt-frame-announce		   do it in a pop-up frame (v19 only)
+;;;	'appt-message-announce		   do it in the echo area.
+;;;	'appt-persistent-message-announce  do it in the echo area, but make the
+;;;				    messages not go away at the next keystroke.
+;;; appt-display-duration	If appt-announce-method is set to the function
+;;;				'appt-window-announce, this specifies how many
+;;;				seconds the pop-up window should stick around.
+;;;
+;;; In order to use this, create a diary file, and add the following to your
+;;; .emacs file:
+;;;
+;;;    (require 'appt)
+;;;    (display-time)
+;;;    (appt-initialize)
+;;;
+;;; If you wish to see a list of appointments, or a full calendar, when emacs
+;;; starts up, you can add a call to (diary) or (calendar) after this.
+;;;
+;;;  This is an example of what can be in your diary file:
+;;;	 Monday
+;;;	   9:30am Coffee break
+;;;	  12:00pm Lunch
+;;; 
+;;; Based upon the above lines in your .emacs and diary files, the calendar
+;;; and/or diary will be displayed when you enter emacs and your appointments
+;;; list will automatically be created.  You will then be reminded at 9:20am
+;;; about your coffee break and at 11:50am to go to lunch.
+;;;
+;;; In order to interactively add or delete items from today's list, use 
+;;; Meta-x appt-add and Meta-x appt-delete.  (This does not modify your 
+;;; diary file, so these will be forgotten when you exit emacs.)
+;;;
+;;; Additionally, the appointments list is recreated automatically at 12:01am 
+;;; for those who do not logout every day or are programming late.
+;;;
+;;; You can have special appointments which execute arbitrary code rather than
+;;; simply notifying you -- sort of like the unix "cron" facility.  The syntax
+;;; for this is borrowed from the Calendar's special-date format.  If you have
+;;; a diary entry like
+;;;
+;;;  Monday
+;;;    3:00am	%%(save-all-modified-buffers)
+;;;
+;;; then on monday at 3AM, the function `save-all-modified-buffers' will be
+;;; invoked.  (Presumably this function is defined in your .emacs file.)
+;;; There will be no notification that these "special" appointments are being
+;;; triggered, unless the form evaluated produces a notification.
+;;;
+;;; It is necessary for the entire list after the "%%" to be on one line in 
+;;; your .diary file -- there may not be embedded newlines in it.  This is a
+;;; bit of a misfeature.
+;;;
+;;; This also interacts correctly with Benjamin Pierce's reportmail.el package.
+;;;
+;;; Brief internal description - Skip this if you are not interested!
+;;;
+;;; The function appt-initialize invokes 'diary' to get a list of today's
+;;; appointments, and parses the lines beginning with date descriptions.
+;;; This list is cached away.  'diary' is invoked in such a way so as to
+;;; not pop up a window displaying the diary buffer.
+;;;
+;;; The function appt-check is run from the 'loadst' process (or the 'wakeup'
+;;; process in emacs 18.57 or newer) which is started by invoking display-time.
+;;; It checks this cached list, and announces as appropriate.  At midnight,
+;;; appt-initialize is called again to rebuild this list.
+;;;
+;;; display-time-filter is modified to invoke appt-check.
+;;;
+;;; TO DO:
+;;;
+;;;  o  multiple adjacent appointments are not handled gracefully.  If there 
+;;;     is an appointment at 3:30 and another at 3:35, and you have set things
+;;;     up so that you get a notification twenty minutes before each appt,
+;;;     then a notification should come at 3:10 for the first appt, and at
+;;;     3:15 for the second.  Currently, no notifications are generated for an
+;;;     appointment until all preceding appointments have completely expired.
+;;;
+;;;  o  If there are two appointments at the same time, all but the first are
+;;;     ignored (not announced.)
+;;;
+;;;  o  Appointments which are early enough in the morning that their 
+;;;     announcements should begin before midnight are not announced until
+;;;     midnight.
+;;;
+;;;  o  There should be some way to mark certain appointments as "important,"
+;;;     so that you will be harassed about them even after they have expired.
+
+
+(require 'calendar)
+(require 'diary-lib)
+
+(defcustom appt-issue-message t
+  "*If T, the diary buffer is checked for appointments.  For an
+ appointment warning to be made, the time must be the first thing on
+ the line."
+  :type 'boolean
+  :group 'appt)
+
+(defcustom appt-msg-countdown-list '(20 15 10 5 3 1)
+  "*A list of the intervals in minutes before the appointment when
+ the warnings will be given.  That is, if this were the list '(5 3 1),
+ then a notification would be given five minutes, three minutes, and
+ one minute before the appointment."
+  :type '(repeat integer)
+  :group 'appt)
+
+(defcustom appt-check-time-syntax nil
+  "*Whether all diary entries are intended to beging with time specifications.
+Appt will beep and issue a warning message when encountering unparsable 
+lines."
+  :type 'boolean
+  :group 'appt)
+
+(defcustom appt-audible t
+  "*Controls whether appointment announcements should beep.
+Appt uses two sound-types for beeps: `appt' and `appt-final'.
+If this is a number, then that many beeps will occur.
+If this is a cons, the car is how many beeps, and the cdr is the
+  delay between them (a float, fraction of a second to sleep.)
+See also the variable `appt-msg-countdown-list'"
+  :type 'boolean
+  :group 'appt)
+
+(defcustom appt-display-mode-line t
+  "*Controls if minutes-to-appointment should be displayed on the mode line."
+  :type 'boolean
+  :group 'appt)
+
+(defcustom appt-announce-method 'appt-window-announce
+  "*The name of the function used to notify the user of an impending 
+appointment.  This is called with two arguments, the number of minutes
+until the appointment, and the appointment description list.
+
+Reasonable values for this variable are 'appt-window-announce,
+'appt-message-announce, or 'appt-persistent-message-announce."
+  :type 'function
+  :group 'appt)
+
+
+(defvar appt-time-msg-list nil
+  "The list of appointments for today.  Use appt-add and appt-delete
+ to add and delete appointments from list.  The original list is generated
+ from the today's diary-entries-list. The number before each time/message
+ is the time in minutes after midnight.")
+
+(defconst max-time 1439
+  "11:59pm in minutes - number of minutes in a day minus 1.")
+
+(defconst appt-check-tick -1)
+
+(defvar appt-disp-frame nil
+  "If non-nil, frame to display appointments in.")
+(defvaralias 'appt-disp-screen 'appt-disp-frame)
+  
+
+;;; Announcement methods
+
+(defun appt-message-announce (min-to-app appt)
+  "Set appt-announce-method to the name of this function to cause appointment
+notifications to be given via messages in the minibuffer."
+  (message (if (eq min-to-app 0) "App't NOW."
+	       (format "App't in %d minute%s -- %s"
+		       min-to-app
+		       (if (eq 1 min-to-app) "" "s")
+		       (car (cdr appt))))))
+
+
+(defun appt-persistent-message-announce (min-to-app appt)
+  "Set appt-announce-method to the name of this function to cause appointment
+notifications to be given via messages in the minibuffer, but have those 
+messages stay around even if you type something (unlike normal messages)."
+  (let ((str (if (eq min-to-app 0)
+		 (format "App't NOW -- %s" (car (cdr appt)))
+		 (format "App't in %d minute%s -- %s"
+			 min-to-app
+			 (if (eq 1 min-to-app) "" "s")
+			 (car (cdr appt)))))
+	(in-echo-area-already (eq (selected-window) (minibuffer-window))))
+    (if (not in-echo-area-already)
+	;; don't stomp the echo-area-buffer if reading from the minibuffer now.
+	(save-excursion
+	  (save-window-excursion
+	    (select-window (minibuffer-window))
+	    (delete-region (point-min) (point-max))
+	    (insert str))))
+    ;; if we're reading from the echo-area, and all we were going to do is
+    ;; clear the thing, like, don't bother, that's annoying.
+    (if (and in-echo-area-already (string= "" str))
+	nil
+      (message "%s" str))
+    ))
+
+
+(defcustom appt-display-duration 5
+  "*The number of seconds an appointment message is displayed in its own 
+ window if appt-announce-method is 'appt-window-announce."
+  :type 'integer
+  :group 'appt)
+
+(defun appt-window-announce (min-to-app appt)
+  "Set appt-announce-method to the name of this function to cause appointment 
+notifications to be given via messages in a pop-up window.  The variable
+appt-display-duration controls how long this window should be left up."
+  (require 'electric)
+  (save-excursion
+   (save-window-excursion
+    ;; Make sure we're not in the minibuffer
+    ;; before splitting the window.
+     (if (window-minibuffer-p (selected-window))
+	 nil
+       (select-window (frame-lowest-window))
+       (split-window))
+    (let (appt-disp-buf)
+      (unwind-protect
+	   (progn
+	     (setq appt-disp-buf (set-buffer (get-buffer-create "*appt-buf*")))
+	     ;; set the mode-line of the pop-up window
+	     (setq modeline-format 
+	       (concat "-------------------- Appointment "
+		 (if (eq min-to-app 0)
+		     "NOW"
+		   (concat "in " min-to-app
+		     (if (eq min-to-app 1) " minute" " minutes")))
+		 ". ("
+		 (let ((h (string-to-int
+			    (substring (current-time-string) 11 13))))
+		   (concat (if (> h 12) (- h 12) h) ":"
+			   (substring (current-time-string) 14 16)
+			   (if (< h 12) "am" "pm")))
+		 ") %-"))
+	     (pop-to-buffer appt-disp-buf)
+	     (insert (car (cdr appt)))
+	     (shrink-window-if-larger-than-buffer
+	       (get-buffer-window appt-disp-buf))
+	     (set-buffer-modified-p nil)
+	     (sit-for appt-display-duration))
+	(and appt-disp-buf (kill-buffer appt-disp-buf)))))))
+
+(defvar appt-frame-defaults nil)
+(defvaralias 'appt-screen-defaults 'appt-frame-defaults)
+
+(defun appt-frame-announce (min-to-app appt)
+  "Set appt-announce-method to the name of this function to cause appointment 
+notifications to be given via messages in a pop-up frame."
+  (let ()
+    (save-excursion
+      (set-buffer (get-buffer-create "*appt-buf*"))
+      (erase-buffer)
+      ;; set the mode-line of the pop-up window
+      (setq modeline-format 
+	    (concat "-------------------- Appointment "
+		    (if (eq min-to-app 0)
+			"NOW"
+		      (concat "in " min-to-app
+			      (if (eq min-to-app 1) " minute" " minutes")))
+		    ". ("
+		    (let ((h (string-to-int
+			      (substring (current-time-string) 11 13))))
+		      (concat (if (> h 12) (- h 12) h) ":"
+			      (substring (current-time-string) 14 16)
+			      (if (< h 12) "am" "pm")))
+		    ") %-"))
+      (insert (car (cdr appt)))
+      (let ((height (max 10 (min 20 (+ 2 (count-lines (point-min)
+						      (point-max)))))))
+        ;; If we already have a frame constructed, use it. If not, or it has
+        ;; been deleted, then make a new one
+	(if (and appt-disp-frame (frame-live-p appt-disp-frame))
+	    (let ((s (selected-frame)))
+	      (select-frame appt-disp-frame)
+	      (make-frame-visible appt-disp-frame)
+	      (set-frame-height appt-disp-frame height)
+	      (sit-for 0)
+	      (select-frame s))
+          (progn
+            (setq appt-disp-frame (make-frame))
+            (set-frame-height appt-disp-frame height)
+            )
+          )
+        )
+      )
+    )
+  )
+(defalias 'appt-screen-announce 'appt-frame-announce)
+
+;;; To display stuff in the mode line, we use a new variable instead of
+;;; just adding stuff to the display-time-string -- this causes less
+;;; flicker.
+
+(defcustom appt-mode-line-string ""
+  "*The string displayed in the mode line by the appointment package."
+  :type 'string
+  :group 'appt)
+
+(defun appt-display-mode-line (min-to-app)
+  "Add an appointment annotation to the mode line."
+  (setq appt-mode-line-string
+	(if (and appt-display-mode-line min-to-app)
+	    (if (eq 0 min-to-app)
+		"App't NOW "
+		(concat "App't in " min-to-app
+			(if (eq 1 min-to-app) " minute  " " minutes ")))
+	    ""))
+  ;; make sure our variable is visible in global-mode-string.
+  (cond ((not appt-display-mode-line) nil)
+	((null global-mode-string)
+	 (setq global-mode-string (list "" 'appt-mode-line-string)))
+	((stringp global-mode-string)
+	 (setq global-mode-string
+	       (list global-mode-string 'appt-mode-line-string)))
+	((not (memq 'appt-mode-line-string global-mode-string))
+	 (setq global-mode-string
+	       (append global-mode-string (list 'appt-mode-line-string)))))
+  ;; force mode line updates - from time.el
+  (save-excursion (set-buffer (other-buffer)))
+  (set-buffer-modified-p (buffer-modified-p))
+  (sit-for 0))
+
+
+;;; Internal stuff
+
+(defun appt-convert-time (time2conv)
+  "Convert hour:min[am/pm] format to minutes from midnight."
+  (cond ((string-match "^[ \t]*midni\\(ght\\|te\\)[ \t]*\\'" time2conv)
+	 0)
+	((string-match "^[ \t]*noon[ \t]*\\'" time2conv)
+	 (* 12 60))
+	(t
+	 (let ((hr 0)
+	       (min 0))
+	   (or (string-match
+		 "\\`[ \t]*\\([0-9][0-9]?\\)[ \t]*\\(:[ \t]*\\([0-9][0-9]\\)\\)?[ \t]*\\(am\\|pm\\)?"
+		 time2conv)
+	       (error "unparsable time \"%s\"" time2conv))
+	   (setq hr (string-to-int
+		      (substring time2conv
+				 (match-beginning 1) (match-end 1))))
+	   (if (match-beginning 3)
+	       (setq min (string-to-int 
+			   (substring time2conv 
+				      (match-beginning 3) (match-end 3)))))
+	   ;; convert the time appointment time into 24 hour time
+	   (if (match-beginning 4)
+	       (progn
+		 (if (or (= hr 0) (> hr 12))
+		     (error "mixing 12hr and 24 hr time!  %s" time2conv))
+		 (if (string-match "am"
+				   (substring time2conv (match-beginning 4)))
+		     (if (= hr 12) (setq hr 0))
+		   (if (< hr 12) (setq hr (+ 12 hr))))))
+	   (if (> min 59) (error "minutes outa bounds - %s" time2conv))
+	   (+ (* hr 60) min)))))
+
+
+(defun appt-current-time-in-minutes ()
+  "Returns the current time in minutes since midnight."
+  (let* ((str (current-time-string))
+	 (hour (string-to-int (substring str 11 13)))
+	 (min  (string-to-int (substring str 14 16))))
+    (+ (* hour 60) min)))
+
+
+(defun appt-sort-list (appt-list)
+  (sort (copy-sequence appt-list)
+	(function (lambda (x y)
+	  (< (car (car x)) (car (car y)))))))
+
+(defun appt-diary-entries ()
+  "Return an updated list of appointments for today."
+  (let ((list-diary-entries-hook '(appt-make-list))
+	(diary-display-hook 'ignore)
+	(diary-list-include-blanks nil))
+    ;; this will set appt-time-msg-list.
+    (diary 1)
+    appt-time-msg-list))
+
+(defun appt-initialize ()
+  "Read your `diary-file' and remember today's appointments.  Call this from 
+ your .emacs file, or any time you want your .diary file re-read (this happens 
+ automatically at midnight to notice the next day's appointments).
+ 
+ The time must be at the beginning of a line for it to be put in the 
+ appointments list.
+               02/23/89
+                  12:00pm    lunch
+                Wednesday
+                  10:00am    group meeting"
+  (install-display-time-hook)
+  (let ((n (length (appt-diary-entries))))
+    (cond ((= n 0) (message "no appointments today."))
+	  ((= n 1) (message "1 appointment today."))
+	  (t (message "%d appointments today." n)))))
+
+(defun appt-make-list ()
+  "Don't call this directly; call appt-initialize or appt-diary-entries."
+  (setq appt-time-msg-list nil)
+  (if diary-entries-list
+      ;; Cycle through the entry-list (diary-entries-list) looking for
+      ;; entries beginning with a time. If the entry begins with a time,
+      ;; add it to the appt-time-msg-list. Then sort the list.
+      ;;
+      (let ((entry-list diary-entries-list)
+	    (new-appts '()))
+	(while (and entry-list
+		    (calendar-date-equal
+		      (calendar-current-date) (car (car entry-list))))
+	  (let ((time-string (car (cdr (car entry-list)))))
+	    (while (string-match
+		    "\\`[ \t\n]*\\([0-9]?[0-9]\\(:[0-9][0-9]\\)?[ \t]*\\(am\\|pm\\)?\\|noon\\|midnight\\|midnite\\).*$"
+		     time-string)
+	      (let* ((eol (match-end 0))
+		     (appt-time-string
+		      (substring time-string (match-beginning 1)
+				 (match-end 1)))
+		     (appt-msg-string
+		      (substring time-string (match-end 1) eol))
+		     (appt-time (list (appt-convert-time appt-time-string))))
+		(setq time-string (substring time-string eol)
+		      new-appts (cons (cons appt-time
+					    (list (concat appt-time-string ":"
+							  appt-msg-string)))
+				      new-appts))))
+	    (if appt-check-time-syntax
+		(while (string-match "\n*\\([^\n]+\\)$" time-string)
+		  (beep)
+		  (message "Unparsable time: %s"
+			   (substring time-string (match-beginning 1)
+				      (match-end 1)))
+		  (sit-for 3)
+		  (setq time-string (substring time-string (match-end 0)))))
+					       
+	    )
+	  (setq entry-list (cdr entry-list)))
+	(setq appt-time-msg-list ; seems we can't nconc this list...
+	      (append (nreverse new-appts) appt-time-msg-list))))
+  (setq appt-time-msg-list (appt-sort-list appt-time-msg-list))
+  ;;
+  ;; Get the current time and convert it to minutes from midnight, i.e.,
+  ;; 12:01am = 1, midnight = 0, so that the elements in the list that
+  ;; are earlier than the present time can be removed.
+  ;;
+  (let ((cur-comp-time (appt-current-time-in-minutes))
+	(appt-comp-time (car (car (car appt-time-msg-list)))))
+    (while (and appt-time-msg-list (< appt-comp-time cur-comp-time))
+      (setq appt-time-msg-list (cdr appt-time-msg-list)) 
+      (if appt-time-msg-list
+          (setq appt-comp-time (car (car (car appt-time-msg-list)))))))
+  appt-time-msg-list)
+
+
+(defun appt-beep (&optional final-p)
+  (cond ((null appt-audible) nil)
+	((numberp appt-audible)
+	 (let ((i appt-audible))
+	   (while (> i 0) (beep) (setq i (1- i)))))
+	((consp appt-audible)
+	 (let ((i (car appt-audible))
+	       (j (cdr appt-audible)))
+	   (if (consp j) (setq j (car j)))
+	   (while (> i 0)
+	     (if (fboundp 'play-sound)
+		 (beep nil (if final-p 'appt-final 'appt))
+	       (beep))
+             (sleep-for j)
+	     (setq i (1- i)))))
+	(t (beep))))
+
+
+(defun appt-check ()
+  "Check for an appointment and update the mode line and minibuffer if
+ desired. Note: the time must be the first thing in the line in the diary
+ for a warning to be issued.
+  The format of the time can be either 24 hour or am/pm.  Example: 
+ 
+               02/23/89
+                 18:00 Dinner
+              Thursday
+                11:45am Lunch meeting.
+  
+ The following variables control the action of the notification:
+ 
+ appt-issue-message		If this variable is nil, then the code in this
+				file does nothing.
+ appt-msg-countdown-list	Specifies how much warning you want before 
+				appointments.
+ appt-audible			Whether to beep when it's notification-time.
+ appt-display-mode-line		Whether to display a countdown to the next 
+				appointment in the mode-line.
+ appt-announce-method   	The function used to do the notifications.
+				'appt-window-announce to do it in a pop-up
+				window, 'appt-message-announce or 
+				'appt-persistent-message-announce to do it 
+				in the echo-area.
+ appt-display-duration  	If appt-announce-method is set to the function
+				'appt-window-announce, this specifies how many
+				seconds the pop-up window should stick around.
+ 
+ This function is run from the `loadst' or `wakeup' process for display-time.
+ Therefore, you need to have (display-time) in your .emacs file."
+  (if appt-issue-message
+   (let ((min-to-app -1))
+     ;; Get the current time and convert it to minutes
+     ;; from midnight, i.e., 12:01am = 1, midnight = 0.
+     (let* ((cur-comp-time (appt-current-time-in-minutes))
+	    ;; If the current time is the same as the tick, just return.
+	    ;; This means that this function has been called more than once
+	    ;; in the current minute, which is not useful.
+	    (shut-up-this-time (= cur-comp-time appt-check-tick))
+	    (turnover-p (> appt-check-tick cur-comp-time)))
+       (setq appt-check-tick cur-comp-time)
+       ;;
+       ;; If it is now the next day (we have crossed midnight since the last
+       ;; time this was called) then we should update our appointments to
+       ;; today's list.  Show the diary entries (tjc).
+       (if turnover-p (diary 1))
+       ;;
+       ;; Get the first time off of the list and calculate the number
+       ;; of minutes until the appointment.
+       (if appt-time-msg-list
+	   (let ((appt-comp-time (car (car (car appt-time-msg-list)))))
+	     (setq min-to-app (- appt-comp-time cur-comp-time))
+	     (while (and appt-time-msg-list (< appt-comp-time cur-comp-time))
+	       (setq appt-time-msg-list (cdr appt-time-msg-list)) 
+	       (if appt-time-msg-list
+		   (setq appt-comp-time (car (car (car appt-time-msg-list))))))
+	     ;;
+	     ;; If we have an appointment between midnight and warning-time
+	     ;; minutes after midnight, we must begin to issue a message
+	     ;; before midnight.  Midnight is considered 0 minutes and 11:59pm
+	     ;; is 1439 minutes. Therefore we must recalculate the minutes to
+	     ;; appointment variable. It is equal to the number of minutes
+	     ;; before midnight plus the number of minutes after midnight our
+	     ;; appointment is.
+	     ;;
+	     ;; ## I don't think this does anything -- it would if it were
+	     ;; (for example) a 12:01am appt on the list at 11:55pm, but that
+	     ;; can't ever happen, because the applicable 12:01am appt is for
+	     ;; tomorrow, not today, and we only have today's diary list.
+	     ;; It's not simply a matter of concatenating two days together,
+	     ;; either, because then tuesday's appts would be signalled on
+	     ;; monday.  We have to do a real one-day lookahead -- keep a list
+	     ;; of tomorrow's appts, and check it when near midnight.
+	     ;;
+	     (if (and (< appt-comp-time (apply 'max appt-msg-countdown-list))
+		      (> (+ cur-comp-time (apply 'max appt-msg-countdown-list))
+			 max-time))
+		 (setq min-to-app (+ (- (1+ max-time) cur-comp-time))
+		       appt-comp-time))
+	     ;;
+	     ;; issue warning if the appointment time is within warning-time
+	     (cond
+	       ;; if there should not be any notifications in the mode-line,
+	       ;; clear it.
+	       ((> min-to-app (apply 'max appt-msg-countdown-list))
+		(appt-display-mode-line nil))
+	       ;; do nothing if this is the second time this minute we've
+	       ;; gotten here, of if we shouldn't be notifying right now.
+	       ((or shut-up-this-time
+		    (and (not (= min-to-app 0))
+			 (not (memq min-to-app appt-msg-countdown-list))))
+		nil)
+
+	       ((and (= min-to-app 0)
+		     (string-match "%%(" (nth 1 (car appt-time-msg-list))))
+		;;
+		;; If this is a magic evaluating-notification, evaluate it.
+		;; these kinds of notifications aren't subject to the
+		;; appt-msg-countdown-list.
+		;;
+		(let* ((list-string (substring (nth 1 (car appt-time-msg-list))
+					       (1- (match-end 0))))
+		       (form (condition-case ()
+				 (read list-string)
+			       (error
+				 (ding)
+				 (message "Appt: error reading from \"%s\""
+					  (nth 1 (car appt-time-msg-list)))
+				 (sit-for 2)
+				 nil))))
+		  (eval form)))
+
+	       ((and (<= min-to-app (apply 'max appt-msg-countdown-list))
+		     (>= min-to-app 0))
+		;;
+		;; produce a notification.
+		(appt-beep (= min-to-app 0))
+		(funcall appt-announce-method min-to-app
+			 (car appt-time-msg-list))
+		;; update mode line and expire if necessary
+		(appt-display-mode-line min-to-app)
+		;; if it's expired, remove it.
+		(if (= min-to-app 0)
+		    (setq appt-time-msg-list (cdr appt-time-msg-list))))
+	       (t
+		;; else we're not near any appointment, or there are no
+		;; apointments; make sure mode line is clear.
+		(appt-display-mode-line nil))))
+	   (appt-display-mode-line nil))))))
+
+
+
+;;; Interactively adding and deleting appointments
+
+(defun appt-add (new-appt-time new-appt-msg)
+  "Adds an appointment to the list of appointments for the day at TIME
+ and issue MESSAGE. The time should be in either 24 hour format or
+ am/pm format. "
+ 
+  (interactive "sTime (hh:mm[am/pm]): \nsMessage: ")
+  (if (string-match "[0-9]?[0-9]:[0-9][0-9]\\(am\\|pm\\)?" new-appt-time)
+      nil
+    (error "Unacceptable time-string"))
+  
+  (let* ((appt-time-string (concat new-appt-time " " new-appt-msg))
+         (appt-time (list (appt-convert-time new-appt-time)))
+         (time-msg (cons appt-time (list appt-time-string))))
+    (setq appt-time-msg-list (append appt-time-msg-list
+                                     (list time-msg)))
+    (setq appt-time-msg-list (appt-sort-list appt-time-msg-list)))) 
+
+(defun appt-delete ()
+  "Deletes an appointment from the list of appointments."
+  (interactive)
+  (let* ((tmp-msg-list appt-time-msg-list))
+    (while tmp-msg-list
+      (let* ((element (car tmp-msg-list))
+             (prompt-string (concat "Delete " 
+                                    (prin1-to-string (car (cdr element))) 
+                                    " from list? "))
+             (test-input (y-or-n-p prompt-string)))
+        (setq tmp-msg-list (cdr tmp-msg-list))
+        (if test-input
+            (setq appt-time-msg-list (delq element appt-time-msg-list)))))
+    (message "")))
+
+
+;;; Patching in to existing time code to install our hook.
+
+
+(defvar display-time-hook-installed nil)
+
+(defun install-display-time-hook ()
+ (unless display-time-hook-installed	; only do this stuff once!
+   (unless (boundp 'display-time-hook)	; Need to wrapper it.
+     (defvar display-time-hook nil
+       "*List of functions to be called when the time is updated on the mode line.")
+     (let ((old-fn (if (or (featurep 'reportmail)
+			   ;; old reportmail without a provide statement
+			   (and (fboundp 'display-time-filter-18-55)
+				(fboundp 'display-time-filter-18-57)))
+		       (if (and (featurep 'itimer)  ; XEmacs reportmail.el
+				(fboundp 'display-time-timer-function))
+			   'display-time-timer-function
+			 ;; older reportmail, or no timer.el.
+			 (if (string-match "18\\.5[0-5]" (emacs-version))
+			     'display-time-filter-18-55
+			   'display-time-filter-18-57))
+		     ;; othewise, time.el
+		     (if (and (featurep 'itimer)
+			      (fboundp 'display-time-function)) ; XEmacs
+			 'display-time-function
+		       'display-time-filter))))
+    ;; we're about to redefine it...
+       (fset 'old-display-time-filter (symbol-function old-fn))
+       (fset old-fn
+	     (lambda (&rest args)  ;; ...here's the revised definition
+	       "Revised version of the original function: this version calls a hook."
+	       (apply 'old-display-time-filter args)
+	       (run-hooks 'display-time-hook)))))
+   (setq display-time-hook-installed t)
+   (if (fboundp 'add-hook)
+       (add-hook 'display-time-hook 'appt-check)
+     (setq display-time-hook (cons appt-check display-time-hook)))
+   ))
+
+(provide 'appt)
+;;; cal-dst.el --- calendar functions for daylight savings rules.
+
+;; Copyright (C) 1993, 1994 Free Software Foundation, Inc.
+
+;; Author: Paul Eggert <eggert@twinsun.com>
+;;	Edward M. Reingold <reingold@cs.uiuc.edu>
+;; Keywords: calendar
+;; Human-Keywords: daylight savings time, calendar, diary, holidays
+
+;; This file is part of XEmacs.
+
+;; XEmacs is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; XEmacs is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with XEmacs; see the file COPYING.  If not, write to the Free
+;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Commentary:
+
+;; This collection of functions implements the features of calendar.el and
+;; holiday.el that deal with daylight savings time.
+
+;; Comments, corrections, and improvements should be sent to
+;;  Edward M. Reingold               Department of Computer Science
+;;  (217) 333-6733                   University of Illinois at Urbana-Champaign
+;;  reingold@cs.uiuc.edu             1304 West Springfield Avenue
+;;                                   Urbana, Illinois 61801
+
+;;; Code:
+
+(require 'calendar)
+
+(defvar calendar-current-time-zone-cache nil
+  "Cache for result of calendar-current-time-zone.")
+
+(defvar calendar-system-time-basis
+  (calendar-absolute-from-gregorian '(1 1 1970))
+  "Absolute date of starting date of system clock.")
+
+(defun calendar-absolute-from-time (x utc-diff)
+  "Absolute local date of time X; local time is UTC-DIFF seconds from UTC.
+
+X is (HIGH . LOW) or (HIGH LOW . IGNORED) where HIGH and LOW are the
+high and low 16 bits, respectively, of the number of seconds since
+1970-01-01 00:00:00 UTC, ignoring leap seconds.
+
+Returns the pair (ABS-DATE . SECONDS) where SECONDS after local midnight on
+absolute date ABS-DATE is the equivalent moment to X."
+  (let* ((h (car x))
+	 (xtail (cdr x))
+         (l (+ utc-diff (if (numberp xtail) xtail (car xtail))))
+         (u (+ (* 512 (mod h 675)) (floor l 128))))
+    ;; Overflow is a terrible thing!
+    (cons (+ calendar-system-time-basis
+	     ;; floor((2^16 h +l) / (60*60*24))
+	     (* 512 (floor h 675)) (floor u 675))
+	  ;; (2^16 h +l) mod (60*60*24)
+	  (+ (* (mod u 675) 128) (mod l 128)))))
+
+(defun calendar-time-from-absolute (abs-date s)
+  "Time of absolute date ABS-DATE, S seconds after midnight.
+
+Returns the pair (HIGH . LOW) where HIGH and LOW are the high and low
+16 bits, respectively, of the number of seconds 1970-01-01 00:00:00 UTC,
+ignoring leap seconds, that is the equivalent moment to S seconds after
+midnight UTC on absolute date ABS-DATE."
+  (let* ((a (- abs-date calendar-system-time-basis))
+         (u (+ (* 163 (mod a 512)) (floor s 128))))
+    ;; Overflow is a terrible thing!
+    (cons
+     ;; floor((60*60*24*a + s) / 2^16)
+     (+ a (* 163 (floor a 512)) (floor u 512))
+     ;; (60*60*24*a + s) mod 2^16
+     (+ (* 128 (mod u 512)) (mod s 128)))))
+
+(defun calendar-next-time-zone-transition (time)
+  "Return the time of the next time zone transition after TIME.
+Both TIME and the result are acceptable arguments to current-time-zone.
+Return nil if no such transition can be found."
+  (let* ((base 65536);; 2^16 = base of current-time output
+	 (quarter-multiple 120);; approx = (seconds per quarter year) / base
+	 (time-zone (current-time-zone time))
+	 (time-utc-diff (car time-zone))
+         hi
+	 hi-zone
+         (hi-utc-diff time-utc-diff)
+         (quarters '(2 1 3)))
+    ;; Heuristic: probe the time zone offset in the next three calendar
+    ;; quarters, looking for a time zone offset different from TIME.
+    (while (and quarters (eq time-utc-diff hi-utc-diff))
+      (setq hi (cons (+ (car time) (* (car quarters) quarter-multiple)) 0))
+      (setq hi-zone (current-time-zone hi))
+      (setq hi-utc-diff (car hi-zone))
+      (setq quarters (cdr quarters)))
+    (and
+     time-utc-diff
+     hi-utc-diff
+     (not (eq time-utc-diff hi-utc-diff))
+     ;; Now HI is after the next time zone transition.
+     ;; Set LO to TIME, and then binary search to increase LO and decrease HI
+     ;; until LO is just before and HI is just after the time zone transition.
+     (let* ((tail (cdr time))
+	    (lo (cons (car time) (if (numberp tail) tail (car tail))))
+	    probe)
+       (while
+	   ;; Set PROBE to halfway between LO and HI, rounding down.
+	   ;; If PROBE equals LO, we are done.
+	   (let* ((lsum (+ (cdr lo) (cdr hi)))
+		  (hsum (+ (car lo) (car hi) (/ lsum base)))
+		  (hsumodd (logand 1 hsum)))
+	     (setq probe (cons (/ (- hsum hsumodd) 2)
+			       (/ (+ (* hsumodd base) (% lsum base)) 2)))
+	     (not (equal lo probe)))
+	 ;; Set either LO or HI to PROBE, depending on probe results.
+	 (if (eq (car (current-time-zone probe)) hi-utc-diff)
+	     (setq hi probe)
+	   (setq lo probe)))
+       hi))))
+
+(defun calendar-time-zone-daylight-rules (abs-date utc-diff)
+  "Return daylight transition rule for ABS-DATE, UTC-DIFF sec offset from UTC.
+ABS-DIFF must specify a day that contains a daylight savings transition.
+The result has the proper form for calendar-daylight-savings-starts'."
+  (let* ((date (calendar-gregorian-from-absolute abs-date))
+	 (weekday (% abs-date 7))
+	 (m (extract-calendar-month date))
+	 (d (extract-calendar-day date))
+	 (y (extract-calendar-year date))
+         (last (calendar-last-day-of-month m y))
+	 (candidate-rules
+	  (append
+	   ;; Day D of month M.
+	   (list (list 'list m d 'year))
+	   ;; The first WEEKDAY of month M.
+           (if (< d 8)
+               (list (list 'calendar-nth-named-day 1 weekday m 'year)))
+	   ;; The last WEEKDAY of month M.
+           (if (> d (- last 7))
+               (list (list 'calendar-nth-named-day -1 weekday m 'year)))
+	   ;; The first WEEKDAY after day J of month M, for D-6 < J <= D.
+           (let (l)
+             (calendar-for-loop j from (max 2 (- d 6)) to (min d (- last 8)) do
+		(setq l
+		      (cons
+		       (list 'calendar-nth-named-day 1 weekday m 'year j)
+		       l)))
+	     l)))
+	 (prevday-sec (- -1 utc-diff)) ;; last sec of previous local day
+	 (year (1+ y)))
+    ;; Scan through the next few years until only one rule remains.
+    (while
+	(let ((rules candidate-rules)
+	      new-rules)
+	  (while
+	      (let*
+		  ((rule (car rules))
+		   (date
+		    ;; The following is much faster than
+		    ;; (calendar-absolute-from-gregorian (eval rule)).
+		    (cond ((eq (car rule) 'calendar-nth-named-day)
+			   (eval (cons 'calendar-nth-named-absday (cdr rule))))
+			  ((eq (car rule) 'calendar-gregorian-from-absolute)
+			   (eval (car (cdr rule))))
+			  (t (let ((g (eval rule)))
+			       (calendar-absolute-from-gregorian g))))))
+		(or (equal
+		     (current-time-zone
+		      (calendar-time-from-absolute date prevday-sec))
+		     (current-time-zone
+		      (calendar-time-from-absolute (1+ date) prevday-sec)))
+		    (setq new-rules (cons rule new-rules)))
+		(setq rules (cdr rules))))
+	  ;; If no rules remain, just use the first candidate rule;
+	  ;; it's wrong in general, but it's right for at least one year.
+	  (setq candidate-rules (if new-rules (nreverse new-rules)
+				  (list (car candidate-rules))))
+	  (setq year (1+ year))
+	  (cdr candidate-rules)))
+    (car candidate-rules)))
+
+(defun calendar-current-time-zone ()
+  "Return UTC difference, dst offset, names and rules for current time zone.
+
+Returns (UTC-DIFF DST-OFFSET STD-ZONE DST-ZONE DST-STARTS DST-ENDS
+DST-STARTS-TIME DST-ENDS-TIME), based on a heuristic probing of what the
+system knows:
+
+UTC-DIFF is an integer specifying the number of minutes difference between
+    standard time in the current time zone and Coordinated Universal Time
+    (Greenwich Mean Time).  A negative value means west of Greenwich.
+DST-OFFSET is an integer giving the daylight savings time offset in minutes.
+STD-ZONE is a string giving the name of the time zone when no seasonal time
+    adjustment is in effect.
+DST-ZONE is a string giving the name of the time zone when there is a seasonal
+    time adjustment in effect.
+DST-STARTS and DST-ENDS are sexps in the variable `year' giving the daylight
+    savings time start and end rules, in the form expected by
+    `calendar-daylight-savings-starts'.
+DST-STARTS-TIME and DST-ENDS-TIME are integers giving the number of minutes
+    after midnight that daylight savings time starts and ends.
+
+If the local area does not use a seasonal time adjustment, STD-ZONE and
+DST-ZONE are equal, and all the DST-* integer variables are 0.
+
+Some operating systems cannot provide all this information to Emacs; in this
+case, `calendar-current-time-zone' returns a list containing nil for the data
+it can't find."
+  (or
+   calendar-current-time-zone-cache
+   (setq
+    calendar-current-time-zone-cache
+    (let* ((t0 (current-time))
+	   (t0-zone (current-time-zone t0))
+	   (t0-utc-diff (car t0-zone))
+	   (t0-name (car (cdr t0-zone))))
+      (if (not t0-utc-diff)
+	  ;; Little or no time zone information is available.
+	  (list nil nil t0-name t0-name nil nil nil nil)
+	(let* ((t1 (calendar-next-time-zone-transition t0))
+	       (t2 (and t1 (calendar-next-time-zone-transition t1))))
+	  (if (not t2)
+	      ;; This locale does not have daylight savings time.
+	      (list (/ t0-utc-diff 60) 0 t0-name t0-name nil nil 0 0)
+	    ;; Use heuristics to find daylight savings parameters.
+	    (let* ((t1-zone (current-time-zone t1))
+		   (t1-utc-diff (car t1-zone))
+		   (t1-name (car (cdr t1-zone)))
+		   (t1-date-sec (calendar-absolute-from-time t1 t0-utc-diff))
+		   (t2-date-sec (calendar-absolute-from-time t2 t1-utc-diff))
+		   (t1-rules (calendar-time-zone-daylight-rules
+			      (car t1-date-sec) t0-utc-diff))
+		   (t2-rules (calendar-time-zone-daylight-rules
+			      (car t2-date-sec) t1-utc-diff))
+		   (t1-time (/ (cdr t1-date-sec) 60))
+		   (t2-time (/ (cdr t2-date-sec) 60)))
+	      (cons
+	       (/ (min t0-utc-diff t1-utc-diff) 60)
+	       (cons
+		(/ (abs (- t0-utc-diff t1-utc-diff)) 60)
+		(if (< t0-utc-diff t1-utc-diff)
+		    (list t0-name t1-name t1-rules t2-rules t1-time t2-time)
+		    (list t1-name t0-name t2-rules t1-rules t2-time t1-time)
+		    )))))))))))
+
+;;; The following six defvars relating to daylight savings time should NOT be
+;;; marked to go into loaddefs.el where they would be evaluated when Emacs is
+;;; dumped.  These variables' appropriate values depend on the conditions under
+;;; which the code is INVOKED; so it's inappropriate to initialize them when
+;;; Emacs is dumped---they should be initialized when calendar.el is loaded.
+;;; They default to US Eastern time if time zone info is not available.
+
+(calendar-current-time-zone)
+
+(defvar calendar-time-zone (or (car calendar-current-time-zone-cache) -300)
+  "*Number of minutes difference between local standard time at
+`calendar-location-name' and Coordinated Universal (Greenwich) Time.  For
+example, -300 for New York City, -480 for Los Angeles.")
+
+(defvar calendar-daylight-time-offset
+  (or (car (cdr calendar-current-time-zone-cache)) 60)
+  "*Number of minutes difference between daylight savings and standard time.
+  
+If the locale never uses daylight savings time, set this to 0.")
+
+(defvar calendar-standard-time-zone-name
+  (or (car (nthcdr 2 calendar-current-time-zone-cache)) "EST")
+  "*Abbreviated name of standard time zone at `calendar-location-name'.
+For example, \"EST\" in New York City, \"PST\" for Los Angeles.")
+
+(defvar calendar-daylight-time-zone-name
+  (or (car (nthcdr 3 calendar-current-time-zone-cache)) "EDT")
+  "*Abbreviated name of daylight-savings time zone at `calendar-location-name'.
+For example, \"EDT\" in New York City, \"PDT\" for Los Angeles.")
+  
+;;;###autoload
+(put 'calendar-daylight-savings-starts 'risky-local-variable t)
+(defvar calendar-daylight-savings-starts
+  (or (car (nthcdr 4 calendar-current-time-zone-cache))
+      (and (not (zerop calendar-daylight-time-offset))
+	   '(calendar-nth-named-day 1 0 4 year)))
+  "*Sexp giving the date on which daylight savings time starts.
+This is an expression in the variable `year' whose value gives the Gregorian
+date in the form (month day year) on which daylight savings time starts.  It is
+used to determine the starting date of daylight savings time for the holiday
+list and for correcting times of day in the solar and lunar calculations.
+
+For example, if daylight savings time is mandated to start on October 1,
+you would set `calendar-daylight-savings-starts' to
+
+      '(10 1 year)
+
+If it starts on the first Sunday in April, you would set it to
+
+      '(calendar-nth-named-day 1 0 4 year)
+
+If the locale never uses daylight savings time, set this to nil.")
+
+;;;###autoload
+(put 'calendar-daylight-savings-ends 'risky-local-variable t)
+(defvar calendar-daylight-savings-ends
+  (or (car (nthcdr 5 calendar-current-time-zone-cache))
+      (and (not (zerop calendar-daylight-time-offset))
+	   '(calendar-nth-named-day -1 0 10 year)))
+  "*Sexp giving the date on which daylight savings time ends.
+This is an expression in the variable `year' whose value gives the Gregorian
+date in the form (month day year) on which daylight savings time ends.  It is
+used to determine the starting date of daylight savings time for the holiday
+list and for correcting times of day in the solar and lunar calculations.
+
+For example, if daylight savings time ends on the last Sunday in October:
+
+      '(calendar-nth-named-day -1 0 10 year)
+
+If the locale never uses daylight savings time, set this to nil.")
+  
+(defvar calendar-daylight-savings-starts-time
+  (or (car (nthcdr 6 calendar-current-time-zone-cache)) 120)
+  "*Number of minutes after midnight that daylight savings time starts.")
+  
+(defvar calendar-daylight-savings-ends-time
+  (or (car (nthcdr 7 calendar-current-time-zone-cache))
+      calendar-daylight-savings-starts-time)
+  "*Number of minutes after midnight that daylight savings time ends.")
+
+(provide 'cal-dst)
+
+;;; cal-dst.el ends here
+;;; cal-french.el --- calendar functions for the French Revolutionary calendar.
+
+;; Copyright (C) 1988, 1989, 1992, 1994 Free Software Foundation, Inc.
+
+;; Author: Edward M. Reingold <reingold@cs.uiuc.edu>
+;; Keywords: calendar
+;; Human-Keywords: French Revolutionary calendar, calendar, diary
+
+;; This file is part of XEmacs.
+
+;; XEmacs is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; XEmacs is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with XEmacs; see the file COPYING.  If not, write to the Free
+;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Commentary:
+
+;; This collection of functions implements the features of calendar.el and
+;; diary.el that deal with the French Revolutionary calendar.
+
+;; Technical details of the French Revolutionary calendar can be found in
+;; ``Calendrical Calculations, Part II: Three Historical Calendars''
+;; by E. M. Reingold,  N. Dershowitz, and S. M. Clamen,
+;; Software--Practice and Experience, Volume 23, Number 4 (April, 1993),
+;; pages 383-404.
+
+;; Comments, corrections, and improvements should be sent to
+;;  Edward M. Reingold               Department of Computer Science
+;;  (217) 333-6733                   University of Illinois at Urbana-Champaign
+;;  reingold@cs.uiuc.edu             1304 West Springfield Avenue
+;;                                   Urbana, Illinois 61801
+
+;;; Code:
+
+(require 'calendar)
+
+(defconst french-calendar-month-name-array
+  ["Vend�miaire" "Brumaire" "Frimaire" "Niv�se" "Pluvi�se" "Vent�se"
+   "Germinal" "Flor�al" "Prairial" "Messidor" "Thermidor" "Fructidor"])
+
+(defconst french-calendar-day-name-array
+  ["Primidi" "Duodi" "Tridi" "Quartidi" "Quintidi" "Sextidi" "Septidi"
+   "Octidi" "Nonidi" "Decadi"])
+
+(defconst french-calendar-special-days-array
+  ["de la Vertu" "du Genie" "du Labour" "de la Raison" "de la Recompense"
+   "de la Revolution"])
+
+(defun french-calendar-leap-year-p (year)
+  "True if YEAR is a leap year on the French Revolutionary calendar.
+For Gregorian years 1793 to 1805, the years of actual operation of the
+calendar, uses historical practice based on equinoxes is followed (years 3, 7,
+and 11 were leap years; 15 and 20 would have been leap years).  For later
+years uses the proposed rule of Romme (never adopted)--leap years fall every
+four years except century years not divisible 400 and century years that are
+multiples of 4000."
+  (or (memq year '(3 7 11));; Actual practice--based on equinoxes
+      (memq year '(15 20)) ;; Anticipated practice--based on equinoxes
+      (and (> year 20)     ;; Romme's proposal--never adopted
+           (zerop (% year 4))
+           (not (memq (% year 400) '(100 200 300)))
+           (not (zerop (% year 4000))))))
+
+(defun french-calendar-last-day-of-month (month year)
+  "Return last day of MONTH, YEAR on the French Revolutionary calendar.
+The 13th month is not really a month, but the 5 (6 in leap years) day period of
+`sansculottides' at the end of the year."
+  (if (< month 13)
+      30
+    (if (french-calendar-leap-year-p year)
+        6
+      5)))
+
+(defun calendar-absolute-from-french (date)
+  "Compute absolute date from French Revolutionary date DATE.
+The absolute date is the number of days elapsed since the (imaginary)
+Gregorian date Sunday, December 31, 1 BC."
+  (let ((month (extract-calendar-month date))
+        (day (extract-calendar-day date))
+        (year (extract-calendar-year date)))
+    (+ (* 365 (1- year));; Days in prior years
+       ;; Leap days in prior years
+       (if (< year 20)
+           (/ year 4);; Actual and anticipated practice (years 3, 7, 11, 15)
+         ;; Romme's proposed rule (using the Principle of Inclusion/Exclusion)
+         (+ (/ (1- year) 4);; Luckily, there were 4 leap years before year 20
+            (- (/ (1- year) 100))
+            (/ (1- year) 400)
+            (- (/ (1- year) 4000))))
+       (* 30 (1- month));; Days in prior months this year
+       day;; Days so far this month
+       654414)));; Days before start of calendar (September 22, 1792).
+
+(defun calendar-french-from-absolute (date)
+  "Compute the French Revolutionary equivalent for absolute date DATE.
+The result is a list of the form (MONTH DAY YEAR).
+The absolute date is the number of days elapsed since the
+\(imaginary) Gregorian date Sunday, December 31, 1 BC."
+  (if (< date 654415)
+      (list 0 0 0);; pre-French Revolutionary date
+    (let* ((approx (/ (- date 654414) 366));; Approximation from below.
+           (year                ;; Search forward from the approximation.
+            (+ approx
+               (calendar-sum y approx
+                 (>= date (calendar-absolute-from-french (list 1 1 (1+ y))))
+                 1)))
+           (month               ;; Search forward from Vendemiaire.
+            (1+ (calendar-sum m 1
+                  (> date
+                     (calendar-absolute-from-french
+                      (list m
+                            (french-calendar-last-day-of-month m year)
+                            year)))
+                  1)))
+           (day                   ;; Calculate the day by subtraction.
+            (- date
+               (1- (calendar-absolute-from-french (list month 1 year))))))
+    (list month day year))))
+
+(defun calendar-french-date-string (&optional date)
+  "String of French Revolutionary date of Gregorian DATE.
+Returns the empty string if DATE is pre-French Revolutionary.
+Defaults to today's date if DATE is not given."
+  (let* ((french-date (calendar-french-from-absolute
+                       (calendar-absolute-from-gregorian
+                        (or date (calendar-current-date)))))
+         (y (extract-calendar-year french-date))
+         (m (extract-calendar-month french-date))
+         (d (extract-calendar-day french-date)))
+    (cond
+     ((< y 1) "")
+     ((= m 13) (format "Jour %s de l'Ann�e %d de la Revolution"
+                       (aref french-calendar-special-days-array (1- d))
+                       y))
+     (t (format "Decade %s, %s de %s de l'Ann�e %d de la Revolution"
+                (make-string (1+ (/ (1- d) 10)) ?I)
+                (aref french-calendar-day-name-array (% (1- d) 10))
+                (aref french-calendar-month-name-array (1- m))
+                y)))))
+
+(defun calendar-print-french-date ()
+  "Show the French Revolutionary calendar equivalent of the selected date."
+  (interactive)
+  (let ((f (calendar-french-date-string (calendar-cursor-to-date t))))
+    (if (string-equal f "")
+        (message "Date is pre-French Revolution")
+      (message f))))
+
+(defun calendar-goto-french-date (date &optional noecho)
+  "Move cursor to French Revolutionary date DATE.
+Echo French Revolutionary date unless NOECHO is t."
+  (interactive
+   (let* ((year (calendar-read
+                 "Ann�e de la Revolution (>0): "
+                 '(lambda (x) (> x 0))
+                 (int-to-string
+                  (extract-calendar-year
+                   (calendar-french-from-absolute
+                    (calendar-absolute-from-gregorian
+                     (calendar-current-date)))))))
+          (month-list
+           (mapcar 'list
+                   (append french-calendar-month-name-array
+                           (if (french-calendar-leap-year-p year)
+                               (mapcar
+                                '(lambda (x) (concat "Jour " x))
+                                french-calendar-special-days-array)
+                             (nreverse
+                              (cdr;; we don't want rev. day in a non-leap yr.
+                               (nreverse
+                                (mapcar
+                                 '(lambda (x) (concat "Jour " x))
+                                 french-calendar-special-days-array))))))))
+          (completion-ignore-case t)
+          (month (cdr (assoc
+                       (capitalize
+                        (completing-read
+                         "Mois ou Sansculottide: "
+                         month-list
+                         nil t))
+                       (calendar-make-alist
+                        month-list
+                        1
+                        '(lambda (x) (capitalize (car x)))))))
+          (decade (if (> month 12)
+                      1
+                    (calendar-read
+                     "D�cade (1-3): "
+                     '(lambda (x) (memq x '(1 2 3))))))
+          (day (if (> month 12)
+                   (- month 12)
+                 (calendar-read
+                  "Jour (1-10): "
+                  '(lambda (x) (and (<= 1 x) (<= x 10))))))
+          (month (if (> month 12) 13 month))
+          (day (+ day (* 10 (1- decade)))))
+     (list (list month day year))))
+  (calendar-goto-date (calendar-gregorian-from-absolute
+                       (calendar-absolute-from-french date)))
+  (or noecho (calendar-print-french-date)))
+
+(defun diary-french-date ()
+  "French calendar equivalent of date diary entry."
+  (let ((f (calendar-french-date-string (calendar-cursor-to-date t))))
+    (if (string-equal f "")
+        "Date is pre-French Revolution"
+      f)))
+
+(provide 'cal-french)
+
+;;; cal-french.el ends here
+;;; cal-mayan.el --- calendar functions for the Mayan calendars.
+
+;; Copyright (C) 1992, 1993 Free Software Foundation, Inc.
+
+;; Author: Stewart M. Clamen <clamen@cs.cmu.edu>
+;;	Edward M. Reingold <reingold@cs.uiuc.edu>
+;; Keywords: calendar
+;; Human-Keywords: Mayan calendar, Maya, calendar, diary
+
+;; This file is part of XEmacs.
+
+;; XEmacs is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; XEmacs is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with XEmacs; see the file COPYING.  If not, write to the Free
+;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Commentary:
+
+;; This collection of functions implements the features of calendar.el and
+;; diary.el that deal with the Mayan calendar.  It was written jointly by
+
+;;  Stewart M. Clamen                School of Computer Science
+;;  clamen@cs.cmu.edu                Carnegie Mellon University
+;;                                   5000 Forbes Avenue
+;;                                   Pittsburgh, PA 15213
+
+;; and
+
+;;  Edward M. Reingold               Department of Computer Science
+;;  (217) 333-6733                   University of Illinois at Urbana-Champaign
+;;  reingold@cs.uiuc.edu             1304 West Springfield Avenue
+;;                                   Urbana, Illinois 61801
+
+;; Comments, improvements, and bug reports should be sent to Reingold.
+
+;; Technical details of the Mayan calendrical calculations can be found in
+;; ``Calendrical Calculations, Part II: Three Historical Calendars''
+;; by E. M. Reingold,  N. Dershowitz, and S. M. Clamen,
+;; Software--Practice and Experience, Volume 23, Number 4 (April, 1993),
+;; pages 383-404.
+
+;;; Code:
+
+(require 'calendar)
+
+(defun mayan-adjusted-mod (m n)
+  "Non-negative remainder of M/N with N instead of 0."
+  (1+ (mod (1- m) n)))
+
+(defconst calendar-mayan-days-before-absolute-zero 1137140
+  "Number of days of the Mayan calendar epoch before absolute day 0.
+According to the Goodman-Martinez-Thompson correlation.  This correlation is
+not universally accepted, as it still a subject of astro-archeological
+research.  Using 1232041 will give you Spinden's correlation; using
+1142840 will give you Hochleitner's correlation.")
+
+(defconst calendar-mayan-haab-at-epoch '(8 . 18)
+  "Mayan haab date at the epoch.")
+
+(defconst calendar-mayan-haab-month-name-array
+  ["Pop" "Uo" "Zip" "Zotz" "Tzec" "Xul" "Yaxkin" "Mol" "Chen" "Yax"
+   "Zac" "Ceh" "Mac" "Kankin" "Muan" "Pax" "Kayab" "Cumku"])
+
+(defconst calendar-mayan-tzolkin-at-epoch '(4 . 20)
+  "Mayan tzolkin date at the epoch.")
+
+(defconst calendar-mayan-tzolkin-names-array
+  ["Imix" "Ik" "Akbal" "Kan" "Chicchan" "Cimi" "Manik" "Lamat" "Muluc" "Oc"
+   "Chuen" "Eb" "Ben" "Ix" "Men" "Cib" "Caban" "Etznab" "Cauac" "Ahau"])
+
+(defun calendar-mayan-long-count-from-absolute (date)
+  "Compute the Mayan long count corresponding to the absolute DATE."
+  (let ((long-count (+ date calendar-mayan-days-before-absolute-zero)))
+    (let* ((baktun (/ long-count 144000))
+           (remainder (% long-count 144000))
+           (katun (/ remainder 7200))
+           (remainder (% remainder 7200))
+           (tun (/ remainder 360))
+           (remainder (% remainder 360))
+           (uinal (/ remainder 20))
+           (kin (% remainder 20)))
+      (list baktun katun tun uinal kin))))
+
+(defun calendar-mayan-long-count-to-string (mayan-long-count)
+  "Convert MAYAN-LONG-COUNT into traditional written form."
+  (apply 'format (cons "%s.%s.%s.%s.%s" mayan-long-count)))
+
+(defun calendar-string-to-mayan-long-count (str)
+  "Given STR, a string of format \"%d.%d.%d.%d.%d\", return list of nums."
+  (let ((rlc nil)
+        (c (length str))
+        (cc 0))
+    (condition-case condition
+        (progn
+          (while (< cc c)
+	    (let* ((start (string-match "[0-9]+" str cc))
+		   (end (match-end 0))
+		   datum)
+	      (setq datum (read (substring str start end)))
+	      (setq rlc (cons datum rlc))
+	      (setq cc end)))
+          (if (not (= (length rlc) 5)) (signal 'invalid-read-syntax nil)))
+      (invalid-read-syntax nil))
+    (reverse rlc)))
+
+(defun calendar-mayan-haab-from-absolute (date)
+  "Convert absolute DATE into a Mayan haab date (a pair)."
+  (let* ((long-count (+ date calendar-mayan-days-before-absolute-zero))
+         (day-of-haab
+          (% (+ long-count
+                (car calendar-mayan-haab-at-epoch)
+                (* 20 (1- (cdr calendar-mayan-haab-at-epoch))))
+             365))
+         (day (% day-of-haab 20))
+         (month (1+ (/ day-of-haab 20))))
+    (cons day month)))
+
+(defun calendar-mayan-haab-difference (date1 date2)
+  "Number of days from Mayan haab DATE1 to next occurrence of haab date DATE2."
+  (mod (+ (* 20 (- (cdr date2) (cdr date1)))
+	  (- (car date2) (car date1)))
+       365))
+
+(defun calendar-mayan-haab-on-or-before (haab-date date)
+  "Absolute date of latest HAAB-DATE on or before absolute DATE."
+  (- date
+     (% (- date
+	   (calendar-mayan-haab-difference
+	    (calendar-mayan-haab-from-absolute 0) haab-date))
+	365)))
+
+(defun calendar-next-haab-date (haab-date &optional noecho)
+  "Move cursor to next instance of Mayan HAAB-DATE. 
+Echo Mayan date if NOECHO is t."
+  (interactive (list (calendar-read-mayan-haab-date)))
+  (calendar-goto-date
+   (calendar-gregorian-from-absolute
+    (calendar-mayan-haab-on-or-before
+     haab-date
+     (+ 365
+        (calendar-absolute-from-gregorian (calendar-cursor-to-date))))))
+  (or noecho (calendar-print-mayan-date)))
+
+(defun calendar-previous-haab-date (haab-date &optional noecho)
+  "Move cursor to previous instance of Mayan HAAB-DATE. 
+Echo Mayan date if NOECHO is t."
+  (interactive (list (calendar-read-mayan-haab-date)))
+  (calendar-goto-date
+   (calendar-gregorian-from-absolute
+    (calendar-mayan-haab-on-or-before
+     haab-date
+     (1- (calendar-absolute-from-gregorian (calendar-cursor-to-date))))))
+  (or noecho (calendar-print-mayan-date)))
+
+(defun calendar-mayan-haab-to-string (haab)
+  "Convert Mayan haab date (a pair) into its traditional written form."
+  (let ((month (cdr haab))
+        (day (car haab)))
+  ;; 19th month consists of 5 special days
+  (if (= month 19)
+      (format "%d Uayeb" day)
+    (format "%d %s"
+            day
+            (aref calendar-mayan-haab-month-name-array (1- month))))))
+
+(defun calendar-mayan-tzolkin-from-absolute (date)
+  "Convert absolute DATE into a Mayan tzolkin date (a pair)."
+  (let* ((long-count (+ date calendar-mayan-days-before-absolute-zero))
+         (day (mayan-adjusted-mod
+               (+ long-count (car calendar-mayan-tzolkin-at-epoch))
+               13))
+         (name (mayan-adjusted-mod
+                (+ long-count (cdr calendar-mayan-tzolkin-at-epoch))
+                20)))
+    (cons day name)))
+
+(defun calendar-mayan-tzolkin-difference (date1 date2)
+  "Number of days from Mayan tzolkin DATE1 to next occurrence of tzolkin DATE2."
+  (let ((number-difference (- (car date2) (car date1)))
+        (name-difference (- (cdr date2) (cdr date1))))
+    (mod (+ number-difference
+	    (* 13 (mod (* 3 (- number-difference name-difference))
+		       20)))
+	 260)))
+
+(defun calendar-mayan-tzolkin-on-or-before (tzolkin-date date)
+  "Absolute date of latest TZOLKIN-DATE on or before absolute DATE."
+  (- date
+     (% (- date (calendar-mayan-tzolkin-difference
+		 (calendar-mayan-tzolkin-from-absolute 0)
+		 tzolkin-date))
+	260)))
+
+(defun calendar-next-tzolkin-date (tzolkin-date &optional noecho)
+  "Move cursor to next instance of Mayan TZOLKIN-DATE. 
+Echo Mayan date if NOECHO is t."
+  (interactive (list (calendar-read-mayan-tzolkin-date)))
+  (calendar-goto-date
+   (calendar-gregorian-from-absolute
+    (calendar-mayan-tzolkin-on-or-before
+     tzolkin-date
+     (+ 260
+        (calendar-absolute-from-gregorian (calendar-cursor-to-date))))))
+  (or noecho (calendar-print-mayan-date)))
+
+(defun calendar-previous-tzolkin-date (tzolkin-date &optional noecho)
+  "Move cursor to previous instance of Mayan TZOLKIN-DATE. 
+Echo Mayan date if NOECHO is t."
+  (interactive (list (calendar-read-mayan-tzolkin-date)))
+  (calendar-goto-date
+   (calendar-gregorian-from-absolute
+    (calendar-mayan-tzolkin-on-or-before
+     tzolkin-date
+     (1- (calendar-absolute-from-gregorian (calendar-cursor-to-date))))))
+  (or noecho (calendar-print-mayan-date)))
+
+(defun calendar-mayan-tzolkin-to-string (tzolkin)
+  "Convert Mayan tzolkin date (a pair) into its traditional written form."
+  (format "%d %s"
+          (car tzolkin)
+          (aref calendar-mayan-tzolkin-names-array (1- (cdr tzolkin)))))
+
+(defun calendar-mayan-tzolkin-haab-on-or-before (tzolkin-date haab-date date)
+  "Absolute date that is Mayan TZOLKIN-DATE and HAAB-DATE.
+Latest such date on or before DATE.
+Returns nil if such a tzolkin-haab combination is impossible." 
+  (let* ((haab-difference
+          (calendar-mayan-haab-difference
+           (calendar-mayan-haab-from-absolute 0)
+           haab-date))
+         (tzolkin-difference
+          (calendar-mayan-tzolkin-difference
+           (calendar-mayan-tzolkin-from-absolute 0)
+           tzolkin-date))
+         (difference (- tzolkin-difference haab-difference)))
+    (if (= (% difference 5) 0)
+        (- date
+           (mod (- date
+		   (+ haab-difference (* 365 difference)))
+		18980))
+      nil)))
+
+(defun calendar-read-mayan-haab-date ()
+  "Prompt for a Mayan haab date"
+  (let* ((completion-ignore-case t)
+         (haab-day (calendar-read
+                    "Haab kin (0-19): "
+                    '(lambda (x) (and (>= x 0) (< x 20)))))
+         (haab-month-list (append calendar-mayan-haab-month-name-array 
+                                  (and (< haab-day 5) '("Uayeb"))))
+         (haab-month (cdr
+                      (assoc
+                       (capitalize
+                        (completing-read "Haab uinal: "
+                                         (mapcar 'list haab-month-list)
+                                         nil t))
+                       (calendar-make-alist
+                        haab-month-list 1 'capitalize)))))
+    (cons haab-day haab-month)))
+
+(defun calendar-read-mayan-tzolkin-date ()
+  "Prompt for a Mayan tzolkin date"
+  (let* ((completion-ignore-case t)
+         (tzolkin-count (calendar-read
+                         "Tzolkin kin (1-13): "
+                         '(lambda (x) (and (> x 0) (< x 14)))))
+         (tzolkin-name-list (append calendar-mayan-tzolkin-names-array nil))
+         (tzolkin-name (cdr
+                        (assoc
+                         (capitalize
+                          (completing-read "Tzolkin uinal: " 
+                                           (mapcar 'list tzolkin-name-list)
+                                           nil t))
+                         (calendar-make-alist
+                          tzolkin-name-list 1 'capitalize)))))
+    (cons tzolkin-count tzolkin-name)))
+
+(defun calendar-next-calendar-round-date
+  (tzolkin-date haab-date &optional noecho)
+  "Move cursor to next instance of Mayan HAAB-DATE TZOKLIN-DATE combination.
+Echo Mayan date if NOECHO is t."
+  (interactive (list (calendar-read-mayan-tzolkin-date)
+                     (calendar-read-mayan-haab-date)))
+  (let ((date (calendar-mayan-tzolkin-haab-on-or-before
+               tzolkin-date haab-date
+               (+ 18980 (calendar-absolute-from-gregorian
+                         (calendar-cursor-to-date))))))
+    (if (not date)
+        (error "%s, %s does not exist in the Mayan calendar round"
+               (calendar-mayan-tzolkin-to-string tzolkin-date)
+               (calendar-mayan-haab-to-string haab-date))
+      (calendar-goto-date (calendar-gregorian-from-absolute date))
+      (or noecho (calendar-print-mayan-date)))))
+
+(defun calendar-previous-calendar-round-date
+  (tzolkin-date haab-date &optional noecho)
+  "Move to previous instance of Mayan TZOKLIN-DATE HAAB-DATE combination.
+Echo Mayan date if NOECHO is t."
+  (interactive (list (calendar-read-mayan-tzolkin-date)
+                     (calendar-read-mayan-haab-date)))
+  (let ((date (calendar-mayan-tzolkin-haab-on-or-before
+               tzolkin-date haab-date
+               (1- (calendar-absolute-from-gregorian
+                    (calendar-cursor-to-date))))))
+    (if (not date)
+        (error "%s, %s does not exist in the Mayan calendar round"
+               (calendar-mayan-tzolkin-to-string tzolkin-date)
+               (calendar-mayan-haab-to-string haab-date))
+      (calendar-goto-date (calendar-gregorian-from-absolute date))
+      (or noecho (calendar-print-mayan-date)))))
+
+(defun calendar-absolute-from-mayan-long-count (c)
+  "Compute the absolute date corresponding to the Mayan Long Count C.
+Long count is a list (baktun katun tun uinal kin)"
+  (+ (* (nth 0 c) 144000)        ; baktun
+     (* (nth 1 c) 7200)          ; katun
+     (* (nth 2 c) 360)           ; tun
+     (* (nth 3 c) 20)            ; uinal
+     (nth 4 c)                   ; kin (days)
+     (-                          ; days before absolute date 0
+      calendar-mayan-days-before-absolute-zero)))
+
+(defun calendar-mayan-date-string (&optional date)
+  "String of Mayan date of Gregorian DATE.
+Defaults to today's date if DATE is not given."
+  (let* ((d (calendar-absolute-from-gregorian 
+             (or date (calendar-current-date))))
+         (tzolkin (calendar-mayan-tzolkin-from-absolute d))
+         (haab (calendar-mayan-haab-from-absolute d))
+         (long-count (calendar-mayan-long-count-from-absolute d)))
+      (format "Long count = %s; tzolkin = %s; haab = %s"
+              (calendar-mayan-long-count-to-string long-count)
+              (calendar-mayan-tzolkin-to-string tzolkin)
+              (calendar-mayan-haab-to-string haab))))
+
+(defun calendar-print-mayan-date ()
+  "Show the Mayan long count, tzolkin, and haab equivalents of date."
+  (interactive)
+  (message "Mayan date: %s"
+           (calendar-mayan-date-string (calendar-cursor-to-date t))))
+
+(defun calendar-goto-mayan-long-count-date (date &optional noecho)
+  "Move cursor to Mayan long count DATE.  Echo Mayan date unless NOECHO is t."
+  (interactive
+   (let (lc)
+     (while (not lc)
+       (let ((datum
+              (calendar-string-to-mayan-long-count 
+               (read-string "Mayan long count (baktun.katun.tun.uinal.kin): "
+                            (calendar-mayan-long-count-to-string
+                             (calendar-mayan-long-count-from-absolute
+                               (calendar-absolute-from-gregorian
+                                (calendar-current-date))))))))
+         (if (calendar-mayan-long-count-common-era datum)
+             (setq lc datum))))
+     (list lc)))
+  (calendar-goto-date
+   (calendar-gregorian-from-absolute
+    (calendar-absolute-from-mayan-long-count date)))
+  (or noecho (calendar-print-mayan-date)))
+              
+(defun calendar-mayan-long-count-common-era (lc)
+  "T if long count represents date in the Common Era."
+  (let ((base (calendar-mayan-long-count-from-absolute 1)))
+    (while (and (not (null base)) (= (car lc) (car base)))
+      (setq lc (cdr lc)
+            base (cdr base)))
+    (or (null lc) (> (car lc) (car base)))))
+
+(defun diary-mayan-date ()
+  "Show the Mayan long count, haab, and tzolkin dates as a diary entry."
+  (format "Mayan date: %s" (calendar-mayan-date-string date)))
+
+(provide 'cal-mayan)
+
+;;; cal-mayan.el ends here
+;;; cal-x.el --- calendar windows in dedicated frames in x-windows
+
+;; Copyright (C) 1994 Free Software Foundation, Inc.
+
+;; Author: Michael Kifer <kifer@cs.sunysb.edu>
+;;      Edward M. Reingold <reingold@cs.uiuc.edu>
+;; Modified for XEmacs by:  Chuck Thompson <cthomp@cs.uiuc.edu>
+;; Keywords: calendar
+;; Human-Keywords: calendar, dedicated frames, x-windows
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to
+;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Commentary:
+
+;; This collection of functions implements dedicated frames in x-windows for
+;; calendar.el.
+
+;; Comments, corrections, and improvements should be sent to
+;;  Edward M. Reingold               Department of Computer Science
+;;  (217) 333-6733                   University of Illinois at Urbana-Champaign
+;;  reingold@cs.uiuc.edu             1304 West Springfield Avenue
+;;                                   Urbana, Illinois 61801
+
+;;; Code:
+
+(require 'calendar)
+(if (not (fboundp 'calendar-basic-setup))
+    (fset 'calendar-basic-setup (symbol-function 'calendar)))
+ 
+;;;###autoload
+(defvar calendar-setup 'one-frame
+  "The frame set up of the calendar.
+The choices are `one-frame' (calendar and diary together in one separate,
+dediciated frame) or `two-frames' (calendar and diary in separate, dedicated
+frames); with any other value the current frame is used.")
+
+(defun calendar (&optional arg)
+  "Choose between the one frame, two frame, or basic calendar displays.
+The original function `calendar' has been renamed `calendar-basic-setup'."
+  (interactive "P")
+  (cond ((equal calendar-setup 'one-frame) (calendar-one-frame-setup arg))
+        ((equal calendar-setup 'two-frames) (calendar-two-frame-setup arg))
+        (t (calendar-basic-setup arg))))
+
+(defvar calendar-frame nil "Frame in which to display the calendar.")
+
+(defvar diary-frame nil "Frame in which to display the diary.")
+  
+(defvar diary-frame-parameters
+  '((name . "Diary") (height . 10) (width . 80) (unsplittable . t)
+    (font . "6x13") (auto-lower . t) (auto-raise . t) (minibuffer . nil))
+  "Parameters of the diary frame, if the diary is in its own frame.
+Location and color should be set in .Xdefaults.")
+                                 
+(defvar calendar-frame-parameters
+  '((name . "Calendar") (minibuffer . nil) (height . 10) (width . 80)
+    (auto-raise . t) (auto-lower . t) (font . "6x13") (unsplittable . t)
+    (vertical-scroll-bars . nil))
+  "Parameters of the calendar frame, if the calendar is in a separate frame.
+Location and color should be set in .Xdefaults.")
+
+(defvar calendar-and-diary-frame-parameters
+  '((name . "Calendar") (height . 28) (width . 80) (minibuffer . nil)
+    (font . "6x13") (auto-raise . t) (auto-lower . t))
+  "Parameters of the frame that displays both the calendar and the diary.
+Location and color should be set in .Xdefaults.")
+  
+(defvar calendar-after-frame-setup-hooks nil
+  "Hooks to be run just after setting up a calendar frame.
+Can be used to change frame parameters, such as font, color, location, etc.")
+
+(defun calendar-not-using-window-system-p ()
+  "Return t if not running under a window system."
+  (if (fboundp 'device-type)
+      (not (eq (device-type (selected-device)) 'x))
+    (not window-system)))
+
+(defun calendar-deiconify-frame (frame)
+  "Deiconify the given frame if it is currently iconified."
+  (if (string-match "XEmacs" emacs-version)
+      (if (frame-iconified-p frame)
+	  (deiconify-frame frame))
+    (if (eq 'icon (cdr (assoc 'visibility (frame-parameters frame))))
+	;; This isn't necessary going to do what is intended since it
+	;; only works with the selected frame.
+	(iconify-or-deiconify-frame))))
+
+(defun calendar-one-frame-setup (&optional arg)
+  "Start calendar and display it in a dedicated frame together with the diary."
+  (if (calendar-not-using-window-system-p)
+      (calendar-basic-setup arg)
+    (if (frame-live-p calendar-frame) (delete-frame calendar-frame))
+    (if (frame-live-p diary-frame) (delete-frame diary-frame))
+    (let ((special-display-buffer-names nil)
+          (view-diary-entries-initially t))
+      (save-window-excursion
+        (save-excursion
+          (setq calendar-frame
+		(make-frame calendar-and-diary-frame-parameters))
+          (run-hooks 'calendar-after-frame-setup-hooks)
+          (select-frame calendar-frame)
+	  (calendar-deiconify-frame calendar-frame)
+          (calendar-basic-setup arg)
+          (set-window-dedicated-p (selected-window) 'calendar)
+          (set-window-dedicated-p
+           (display-buffer
+            (if (not (memq 'fancy-diary-display diary-display-hook))
+                (get-file-buffer diary-file)
+              (if (not (bufferp (get-buffer fancy-diary-buffer)))
+                  (make-fancy-diary-buffer))
+              fancy-diary-buffer))
+           'diary))))))
+
+(defun calendar-two-frame-setup (&optional arg)
+  "Start calendar and diary in separate, dedicated frames."
+  (if (calendar-not-using-window-system-p)
+      (calendar-basic-setup arg)
+    (if (frame-live-p calendar-frame) (delete-frame calendar-frame))
+    (if (frame-live-p diary-frame) (delete-frame diary-frame))
+    (let ((pop-up-windows nil)
+          (view-diary-entries-initially nil)
+          (special-display-buffer-names nil))
+      (save-window-excursion
+        (save-excursion (calendar-basic-setup arg))
+        (setq calendar-frame (make-frame calendar-frame-parameters))
+        (run-hooks 'calendar-after-frame-setup-hooks)
+        (select-frame calendar-frame)
+	(calendar-deiconify-frame calendar-frame)
+        (display-buffer calendar-buffer)
+        (set-window-dedicated-p (selected-window) 'calendar)
+        (setq diary-frame (make-frame diary-frame-parameters))
+        (run-hooks 'calendar-after-frame-setup-hooks)
+        (select-frame diary-frame)
+	(calendar-deiconify-frame diary-frame)
+        (save-excursion (diary))
+        (set-window-dedicated-p
+         (display-buffer
+          (if (not (memq 'fancy-diary-display diary-display-hook))
+              (get-file-buffer diary-file)
+            (if (not (bufferp (get-buffer fancy-diary-buffer)))
+                (make-fancy-diary-buffer))
+            fancy-diary-buffer))
+         'diary)))))
+
+(defun make-fancy-diary-buffer ()
+  (save-excursion
+    (set-buffer (get-buffer-create fancy-diary-buffer))
+    (setq buffer-read-only nil)
+    (make-local-variable 'mode-line-format)
+    (calendar-set-mode-line "Diary Entries")
+    (erase-buffer)
+    (set-buffer-modified-p nil)
+    (setq buffer-read-only t)))
+
+(if (not (string-match "XEmacs" emacs-version))
+    (setq special-display-buffer-names
+	  (append special-display-buffer-names
+		  (list "*Yahrzeits*" lunar-phases-buffer holiday-buffer
+			fancy-diary-buffer (get-file-buffer diary-file)
+			calendar-buffer))))
+
+(run-hooks 'cal-x-load-hook)
+
+(provide 'cal-x)
+
+;;; cal-x.el ends here
+;;; cal-xemacs.el --- calendar functions for menu bar and popup menu support
+;;; Original file is cal-menu.el.
+
+;; Copyright (C) 1994 Free Software Foundation, Inc.
+
+;; Author: Edward M. Reingold <reingold@cs.uiuc.edu>
+;;	Lara Rios <lrios@coewl.cen.uiuc.edu>
+;; Ported to XEmacs by Chuck Thompson <cthomp@cs.uiuc.edu>
+;; Keywords: calendar
+;; Human-Keywords: calendar, popup menus, menu bar
+
+;; This file is part of XEmacs.
+
+;; XEmacs is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; XEmacs is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with XEmacs; see the file COPYING.  If not, write to the Free
+;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Commentary:
+
+;; This collection of functions implements menu bar and popup menu support for
+;; calendar.el.
+
+;; Comments, corrections, and improvements should be sent to
+;;  Edward M. Reingold               Department of Computer Science
+;;  (217) 333-6733                   University of Illinois at Urbana-Champaign
+;;  reingold@cs.uiuc.edu             1304 West Springfield Avenue
+;;                                   Urbana, Illinois 61801
+
+;;; Code:
+
+;;(define-key calendar-mode-map 'button2 'calendar-mouse-2-date-menu)
+;;(define-key calendar-mode-map 'button2up 'ignore)
+
+(defconst calendar-popup-menu-3
+  '("Calendar"
+    ["Scroll forward" scroll-calendar-left-three-months t]
+    ["Scroll backward" scroll-calendar-right-three-months t]
+    ["Mark diary entries" mark-diary-entries t]
+    ["List holidays" list-calendar-holidays t]
+    ["Mark holidays" mark-calendar-holidays t]
+    ["Unmark" calendar-unmark t]
+    ["Lunar phases" calendar-phases-of-moon t]
+    ["Show diary" show-all-diary-entries t]
+    ["Exit calendar" exit-calendar t]
+    ))
+
+(defun calendar-popup-menu-3 (e)
+  (interactive "@e")
+  (popup-menu calendar-popup-menu-3))
+(define-key calendar-mode-map 'button3 'calendar-popup-menu-3)
+
+(defvar calendar-foobar nil)
+
+(defun calendar-popup-menu-2 (e)
+  (interactive "@e")
+  (setq calendar-foobar (calendar-event-to-date e t))
+  (let ((menu (list (format "Menu - %s" (calendar-date-string calendar-foobar) t t)
+	       "-----"
+	       ["Holidays" calendar-mouse-holidays t]
+	       ["Mark date" calendar-mouse-set-mark t]
+	       ["Sunrise/sunset" calendar-mouse-sunrise/sunset t]
+	       ["Other calendars" calendar-mouse-print-dates (calendar-event-to-date e)]
+	       ["Diary entries" calendar-mouse-view-diary-entries t]
+	       ["Insert diary entry" calendar-mouse-insert-diary-entry t]
+	       ["Other Diary file entries"
+		calendar-mouse-view-other-diary-entries
+		(calendar-cursor-to-date)]
+	       )))
+    (popup-menu menu)))
+(define-key calendar-mode-map 'button2 'calendar-popup-menu-2)
+
+(defconst calendar-scroll-menu
+  '("Scroll"
+    ["Forward 1 Month" scroll-calendar-left t]
+    ["Forward 3 Months" scroll-calendar-left-three-months t]
+    ["Forward 1 Year" (scroll-calendar-left-three-months 4) t]
+    ["Backward 1 Month" scroll-calendar-right t]
+    ["Backward 3 Months" scroll-calendar-right-three-months t]
+    ["Backward 1 Year" (scroll-calendar-right-three-months 4) t]))
+
+(defconst calendar-goto-menu
+  '("Goto"
+    ["Today" calendar-current-month t]
+    ["Beginning of week" calendar-beginning-of-week (calendar-cursor-to-date)]
+    ["End of week" calendar-end-of-week (calendar-cursor-to-date)]
+    ["Beginning of month" calendar-beginning-of-month (calendar-cursor-to-date)]
+    ["End of month" calendar-end-of-month (calendar-cursor-to-date)]
+    ["Beginning of year" calendar-beginning-of-year (calendar-cursor-to-date)]
+    ["End of year" calendar-end-of-year (calendar-cursor-to-date)]
+    ["Other date" calendar-goto-date t]
+    ["ISO date" calendar-goto-iso-date t]
+    ["Astronomical date" calendar-goto-astro-day-number t]
+    ["Hebrew date" calendar-goto-hebrew-date t]
+    ["Islamic date" calendar-goto-islamic-date t]
+    ["Julian date" calendar-goto-julian-date t]
+    ("Mayan date"
+     ["Next Tzolkin" calendar-next-tzolkin-date t]
+     ["Previous Tzolkin" calendar-previous-tzolkin-date t]
+     ["Next Haab" calendar-next-haab-date t]
+     ["Previous Haab" calendar-previous-haab-date t]
+     ["Next Round" calendar-next-calendar-round-date t]
+     ["Previous Round" calendar-previous-calendar-round-date t])
+    ["French date" calendar-goto-french-date t]))
+
+(defconst calendar-holidays-menu
+  '("Holidays"
+    ["One day" calendar-cursor-holidays (calendar-cursor-to-date)]
+    ["3 months" list-calendar-holidays t]
+    ["Mark" mark-calendar-holidays t]
+    ["Unmark" calendar-unmark t]))
+
+(defconst calendar-diary-menu
+  '("Diary"
+    ["Other file" view-other-diary-entries (calendar-cursor-to-date)]
+    ["Cursor date" view-diary-entries (calendar-cursor-to-date)]
+    ["Mark all" mark-diary-entries t]
+    ["Show all" show-all-diary-entries t]
+    ["Insert daily"insert-diary-entry t]
+    ["Insert weekly" insert-weekly-diary-entry (calendar-cursor-to-date)]
+    ["Insert monthly" insert-monthly-diary-entry (calendar-cursor-to-date)]
+    ["Insert yearly" insert-yearly-diary-entry (calendar-cursor-to-date)]
+    ["Insert anniversary" insert-anniversary-diary-entry (calendar-cursor-to-date)]
+    ["Insert block" insert-block-diary-entry (calendar-cursor-to-date)]
+    ["Insert cyclic" insert-cyclic-diary-entry (calendar-cursor-to-date)]
+    ["Insert Islamic" calendar-mouse-insert-islamic-diary-entry (calendar-cursor-to-date)]
+    ["Insert Hebrew" calendar-mouse-insert-hebrew-diary-entry (calendar-cursor-to-date)]))
+
+(defun calendar-add-menus ()
+  (set-buffer-menubar (copy-sequence current-menubar))
+  (if (assoc "Calendar" current-menubar)
+      nil
+    (add-submenu nil '("Calendar"))
+    (if (not (assoc "Scroll" current-menubar))
+	(add-submenu '("Calendar") calendar-scroll-menu))
+    (if (not (assoc "Goto" current-menubar))
+	(add-submenu '("Calendar") calendar-goto-menu))
+    (if (not (assoc "Holidays" current-menubar))
+	(add-submenu '("Calendar") calendar-holidays-menu))
+    (if (not (assoc "Diary" current-menubar))
+	(add-submenu '("Calendar") calendar-diary-menu))
+    (if (not (assoc "Moon" current-menubar))
+	(add-menu-button '("Calendar") ["Moon" calendar-phases-of-moon t]))))
+
+(defun calendar-event-to-date (event &optional error)
+  "Date of last event.
+If event is not on a specific date, signals an error if optional parameter
+ERROR is t, otherwise just returns nil."
+  (save-excursion
+    (goto-char (event-point event))
+    (calendar-cursor-to-date error)))
+
+(defun calendar-mouse-insert-hebrew-diary-entry (event)
+  "Pop up menu to insert a Hebrew-date diary entry."
+  (interactive "e")
+  (let ((menu (list (format "Hebrew insert menu - %s"
+			    (calendar-hebrew-date-string
+			     (calendar-cursor-to-date)))
+		    "-----"
+		    ["One time" insert-hebrew-diary-entry t]
+		    ["Monthly" insert-monthly-hebrew-diary-entry t]
+		    ["Yearly" insert-yearly-hebrew-diary-entry t])))
+    (popup-menu menu)))
+
+(defun calendar-mouse-insert-islamic-diary-entry (event)
+  "Pop up menu to insert an Islamic-date diary entry."
+  (interactive "e")
+  (let ((menu (list (format "Islamic insert menu - %s"
+			    (calendar-islamic-date-string
+			     (calendar-cursor-to-date)))
+		    "-----"
+		    ["One time" insert-islamic-diary-entry t]
+		    ["Monthly" insert-monthly-islamic-diary-entry t]
+		    ["Yearly" insert-yearly-islamic-diary-entry t])))
+    (popup-menu menu)))
+
+(defun calendar-mouse-sunrise/sunset ()
+  "Show sunrise/sunset times for mouse-selected date."
+  (interactive)
+  (save-excursion
+    (calendar-goto-date calendar-foobar)
+    (setq calendar-foobar nil)
+    (calendar-sunrise-sunset)))
+
+(defun calendar-mouse-holidays ()
+  "Show holidays for mouse-selected date."
+  (interactive)
+  (save-excursion
+    (calendar-goto-date calendar-foobar)
+    (setq calendar-foobar nil)
+    (calendar-cursor-holidays)))
+
+(defun calendar-mouse-view-diary-entries ()
+  "View diary entries on mouse-selected date."
+  (interactive)
+  (save-excursion
+    (calendar-goto-date calendar-foobar)
+    (setq calendar-foobar nil)
+    (view-diary-entries 1)))
+
+(defun calendar-mouse-view-other-diary-entries (event)
+  "View diary entries from alternative file on mouse-selected date."
+  (interactive "e")
+  (save-excursion
+    (calendar-goto-date calendar-foobar)
+    (call-interactively 'view-other-diary-entries)))
+
+(defun calendar-mouse-insert-diary-entry (event)
+  "Insert diary entry for mouse-selected date."
+  (interactive "e")
+  (save-excursion
+    (calendar-goto-date calendar-foobar)
+    (insert-diary-entry nil)))
+
+(defun calendar-mouse-set-mark ()
+  "Mark the date under the cursor."
+  (interactive)
+  (save-excursion
+    (calendar-goto-date calendar-foobar)
+    (setq calendar-foobar nil)
+    (calendar-set-mark nil)))
+
+(defun calendar-mouse-print-dates ()
+  "Pop up menu of equivalent dates to mouse selected date."
+  (interactive)
+  (let* ((menu (list (format "Date Menu - %s (Gregorian)"
+			     (calendar-date-string calendar-foobar))
+		     "-----"
+		     (calendar-day-of-year-string calendar-foobar)
+		     (format "ISO date: %s" (calendar-iso-date-string calendar-foobar))
+		     (format "Julian date: %s"
+			     (calendar-julian-date-string calendar-foobar))
+		     (format "Astronomical (Julian) date (before noon): %s"
+			     (calendar-astro-date-string calendar-foobar))
+		     (format "Hebrew date (before sunset): %s"
+			     (calendar-hebrew-date-string calendar-foobar))
+		     (let ((i (calendar-islamic-date-string calendar-foobar)))
+		       (if (not (string-equal i ""))
+			   (format "Islamic date (before sunset): %s" i)))
+		     (let ((f (calendar-french-date-string calendar-foobar)))
+		       (if (not (string-equal f ""))
+			   (format "French Revolutionary date: %s" f)))
+		     (format "Mayan date: %s" (calendar-mayan-date-string calendar-foobar)))))
+    (popup-menu menu))
+  (setq calendar-foobar nil))
+
+(run-hooks 'cal-xemacs-load-hook)
+
+(provide 'cal-xemacs)
+
+;;; cal-menu.el ends here
+;;; calendar.el --- Calendar functions.  -*-byte-compile-dynamic: t;-*-
+
+;;; Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994 Free Software
+;;; Foundation, Inc.
+
+;; Author: Edward M. Reingold <reingold@cs.uiuc.edu>
+;; Keywords: calendar
+;; Human-Keywords: calendar, Gregorian calendar, Julian calendar, 
+;;	Hebrew calendar, Islamic calendar, ISO calendar, Julian day number,
+;;	diary, holidays
+
+;; This file is part of XEmacs.
+
+;; XEmacs is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; XEmacs is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with XEmacs; see the file COPYING.  If not, write to the Free
+;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Commentary:
+
+;; This collection of functions implements a calendar window.  It
+;; generates a calendar for the current month, together with the previous
+;; and coming months, or for any other three-month period.  The calendar
+;; can be scrolled forward and backward in the window to show months in
+;; the past or future; the cursor can move forward and backward by days,
+;; weeks, or months, making it possible, for instance, to jump to the
+;; date a specified number of days, weeks, or months from the date under
+;; the cursor.  The user can display a list of holidays and other notable
+;; days for the period shown; the notable days can be marked on the
+;; calendar, if desired.  The user can also specify that dates having
+;; corresponding diary entries (in a file that the user specifies) be
+;; marked; the diary entries for any date can be viewed in a separate
+;; window.  The diary and the notable days can be viewed independently of
+;; the calendar.  Dates can be translated from the (usual) Gregorian
+;; calendar to the day of the year/days remaining in year, to the ISO
+;; commercial calendar, to the Julian (old style) calendar, to the Hebrew
+;; calendar, to the Islamic calendar, to the French Revolutionary calendar,
+;; to the Mayan calendar, and to the astronomical (Julian) day number.
+;; When floating point is available, times of sunrise/sunset can be displayed,
+;; as can the phases of the moon.  Appointment notification for diary entries
+;; is available.
+
+;; The following files are part of the calendar/diary code:
+
+;;       cal-menu.el                   Menu support
+;;       cal-x.el                      X-windows dedicated frame functions
+;;       diary-lib.el, diary-ins.el    Diary functions
+;;       holidays.el                   Holiday functions
+;;       cal-french.el                 French Revolutionary calendar
+;;       cal-mayan.el                  Mayan calendars
+;;       cal-dst.el                    Daylight savings time rules
+;;       solar.el                      Sunrise/sunset, equinoxes/solstices
+;;       lunar.el                      Phases of the moon
+;;       appt.el                       Appointment notification
+
+;; Comments, corrections, and improvements should be sent to
+;;  Edward M. Reingold               Department of Computer Science
+;;  (217) 333-6733                   University of Illinois at Urbana-Champaign
+;;  reingold@cs.uiuc.edu             1304 West Springfield Avenue
+;;                                   Urbana, Illinois 61801
+
+;; GNU Emacs users too numerous to list pointed out a variety of problems
+;; with earlier forms of the `infinite' sliding calendar and suggested some
+;; of the features included in this package.  Especially significant in this
+;; regard was the suggestion of mark-diary-entries and view-diary-entries,
+;; together ideas for their implementation, by
+;;  Michael S. Littman		     Cognitive Science Research Group
+;;  (201) 829-5155                   Bell Communications Research
+;;  mlittman@wind.bellcore.com       445 South St. Box 1961 (2L-331)
+;;                                   Morristown, NJ  07960
+
+;; The algorithms for the Hebrew calendar are those of the Rambam (Rabbi Moses
+;; Maimonides), from his Mishneh Torah, as implemented by
+;;  Nachum Dershowitz                Department of Computer Science
+;;  (217) 333-4219                   University of Illinois at Urbana-Champaign
+;;  nachum@cs.uiuc.edu               1304 West Springfield Avenue
+;;                                   Urbana, Illinois 61801
+
+;; Technical details of all the calendrical calculations can be found in
+
+;; ``Calendrical Calculations'' by Nachum Dershowitz and Edward M. Reingold,
+;; Software--Practice and Experience, Volume 20, Number 9 (September, 1990),
+;; pages 899-928.  ``Calendrical Calculations, Part II: Three Historical
+;; Calendars'' by E. M. Reingold,  N. Dershowitz, and S. M. Clamen,
+;; Software--Practice and Experience, Volume 23, Number 4 (April, 1993),
+;; pages 383-404.
+
+;; Hard copies of these two papers can be obtained by sending email to
+;; reingold@cs.uiuc.edu with the SUBJECT "send-paper-cal" (no quotes) and</