diff --git a/lispusers/COMPAREDIRECTORIES b/lispusers/COMPAREDIRECTORIES
index ed76d956..5f201f88 100644
--- a/lispusers/COMPAREDIRECTORIES
+++ b/lispusers/COMPAREDIRECTORIES
@@ -1,12 +1,12 @@
 (DEFINE-FILE-INFO PACKAGE "INTERLISP" READTABLE "INTERLISP" BASE 10)
 
-(FILECREATED "30-Dec-2021 18:22:13" 
-{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>COMPAREDIRECTORIES.;116 100755 
+(FILECREATED "27-Jan-2022 17:47:36" 
+{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>COMPAREDIRECTORIES.;160 112621 
 
-      :CHANGES-TO (FNS CD-MENUFN)
+      :CHANGES-TO (FNS CD.COMMANDSELECTEDFN)
 
-      :PREVIOUS-DATE "25-Dec-2021 12:59:47" 
-{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>COMPAREDIRECTORIES.;114)
+      :PREVIOUS-DATE "26-Jan-2022 15:33:55" 
+{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>COMPAREDIRECTORIES.;159)
 
 
 (* ; "
@@ -19,11 +19,12 @@ Copyright (c) 1985-1988, 1990, 1994, 1998, 2018, 2020-2021 by Venue & Xerox Corp
        (
         (* ;; "Compare the contents of two directories.")
 
-        (FNS COMPAREDIRECTORIES COMPAREDIRECTORIES.INFOS COMPAREDIRECTORIES.INFOS.TYPE MATCHNAME 
-             CD.INSURECDVALUE CD.UPDATEWIDTHS)
+        (FNS COMPAREDIRECTORIES COMPAREDIRECTORIES.INFOS CDENTRIES.SELECT 
+             COMPAREDIRECTORIES.INFOS.TYPE MATCHNAME CD.INSURECDVALUE CD.UPDATEWIDTHS)
         (FNS CDFILES CDFILES.MATCH CDFILES.PATS)
-        (FNS CDPRINT CDPRINT.LINE CDPRINT.MAXWIDTHS CDPRINT.COLHEADERS CDPRINT.COLUMNS CDTEDIT)
-        (FNS CDMAP CDENTRY CDSUBSET)
+        (FNS CDPRINT CDPRINT.HEADER CDPRINT.LINE CDPRINT.MAXWIDTHS CDPRINT.COLHEADERS CDPRINT.COLUMNS
+             CDTEDIT)
+        (FNS CDMAP CDENTRY CDSUBSET CDMERGE CDMERGE.COMMON)
         (FNS BINCOMP EOLTYPE EOLTYPE.SHOW)
         (RECORDS CDVALUE CDENTRY CDINFO CDMAXNCHARS)
         
@@ -63,13 +64,10 @@ Copyright (c) 1985-1988, 1990, 1994, 1998, 2018, 2020-2021 by Venue & Xerox Corp
 
 (COMPAREDIRECTORIES
   [LAMBDA (DIR1 DIR2 SELECT INCLUDEDFILES EXCLUDEDFILES USEDIRECTORYDATE OUTPUTFILE ALLVERSIONS 
-                FIXDIRECTORYDATES)                           (* ; "Edited 23-Dec-2021 18:59 by rmk")
-                                                             (* ; "Edited 19-Dec-2021 20:07 by rmk")
-                                                             (* ; "Edited 30-Nov-2021 13:51 by rmk:")
-                                                             (* ; "Edited 23-Nov-2021 12:57 by rmk:")
-                                                             (* ; "Edited  6-Nov-2021 12:08 by rmk:")
-                                                             (* ; "Edited 31-Oct-2021 11:01 by rmk:")
-                                                             (* ; "Edited  7-Jan-2021 23:21 by rmk:")
+                FIXDIRECTORYDATES)                           (* ; "Edited 26-Jan-2022 13:33 by rmk")
+                                                             (* ; "Edited  4-Jan-2022 12:09 by rmk")
+                                                            (* ; "Edited 31-Oct-2021 11:01 by rmk:")
+                                                            (* ; "Edited  7-Jan-2021 23:21 by rmk:")
 
     (* ;; "Compare the contents of two directories, e.g., for change-control purposes.  Compares files matching FILEPATTERN (or *.*;) on DIR1 and DIR2, listing which is newer, or when one is not found on the other.  If SELECT is or contains SAME/=, BEFORE/<, AFTER/>, then files where DIR1 is the same as, earlier than, or later than DIR2 are selected. SELECT= NIL is the same as (<  >), T is the same as (< > =).  Also allows selection based on file-length criteria.")
 
@@ -96,8 +94,7 @@ Copyright (c) 1985-1988, 1990, 1994, 1998, 2018, 2020-2021 by Venue & Xerox Corp
                                                            (*- '*-)
                                                            (~= '~=)
                                                            (ERROR "UNRECOGNIZED SELECT PARAMETER" S]
-    (PROG (INFOS1 INFOS2 CANDIDATES CDENTRIES COMPAREDATE DEPTH1 DEPTH2 CDVALUE)
-          [SETQ COMPAREDATE (INTERSECTION SELECT '(< > =]
+    (PROG (INFOS1 INFOS2 CANDIDATES CDENTRIES DEPTH1 DEPTH2 CDVALUE (DATE (DATE)))
 
      (* ;; "DIRECTORYNAME here to get unrelativized specifications for header.")
 
@@ -117,8 +114,8 @@ Copyright (c) 1985-1988, 1990, 1994, 1998, 2018, 2020-2021 by Venue & Xerox Corp
               (PRINTOUT T "Fixing directory dates" T)
               (FIX-DIRECTORY-DATES DIR1)
               (FIX-DIRECTORY-DATES DIR2))
-          (PRINTOUT T "Comparing " DIR1 6 "vs. " DIR2 T "as of " (DATE)
-                 " selecting " SELECT " ... ")
+          (CDPRINT.HEADER DIR1 DIR2 SELECT DATE T)
+          (PRINTOUT T " ... ")
           (SETQ INFOS1 (COMPAREDIRECTORIES.INFOS (CDFILES DIR1 INCLUDEDFILES EXCLUDEDFILES 
                                                         ALLVERSIONS DEPTH1)
                               USEDIRECTORYDATE DIR1))
@@ -128,7 +125,7 @@ Copyright (c) 1985-1988, 1990, 1994, 1998, 2018, 2020-2021 by Venue & Xerox Corp
           (SETQ CDVALUE (CREATE CDVALUE
                                CDDIR1 _ DIR1
                                CDDIR2 _ DIR2
-                               CDCOMPAREDATE _ (DATE)
+                               CDCOMPAREDATE _ DATE
                                CDSELECT _ SELECT))
           (CL:UNLESS (OR INFOS2 INFOS1)
                  (RETURN CDVALUE))
@@ -166,58 +163,7 @@ Copyright (c) 1985-1988, 1990, 1994, 1998, 2018, 2020-2021 by Venue & Xerox Corp
 
      (* ;; "Do the SELECT filtering and insert the date relation.")
 
-          [SETQ CDENTRIES
-           (for C MATCHNAME INFO1 INFO2 IDATE1 IDATE2 DATEREL BINCOMP in CANDIDATES
-              eachtime (SETQ MATCHNAME (pop C))
-                    (SETQ INFO1 (pop C))
-                    (SETQ INFO2 (pop C))
-                    (if (AND INFO1 INFO2)
-                        then (SETQ IDATE1 (IDATE (fetch DATE of INFO1)))
-                             (SETQ IDATE2 (IDATE (fetch DATE of INFO2)))
-                             (SETQ DATEREL (if (IGREATERP IDATE1 IDATE2)
-                                               then '>
-                                             elseif (ILESSP IDATE1 IDATE2)
-                                               then '<
-                                             else '=))
-                      else 
-                           (* ;; "Just for printing--no comparison")
-
-                           (SETQ DATEREL '*))
-              when (if (AND INFO1 INFO2)
-                       then (CL:WHEN (OR (NULL COMPAREDATE)
-                                         (SELECTQ DATEREL
-                                             (> (MEMB '> SELECT))
-                                             (< (MEMB '< SELECT))
-                                             (= (MEMB '= SELECT))
-                                             (SHOULDNT)))
-                                (SETQ BINCOMP (BINCOMP (fetch (CDINFO FULLNAME) OF INFO1)
-                                                     (fetch (CDINFO FULLNAME) OF INFO2)
-                                                     T
-                                                     (fetch (CDINFO EOL) OF INFO1)
-                                                     (fetch (CDINFO EOL) OF INFO2)))
-
-                                (* ;; "We want the ~= test to reflect exact byte equivalence, including the same EOL.  We use the BINCOMP value below to indicate EOL differences, so we check it here.")
-
-                                [NOT (AND (MEMB '~= SELECT)
-                                          BINCOMP
-                                          (EQ (fetch (CDINFO EOL) OF INFO1)
-                                              (fetch (CDINFO EOL) OF INFO2])
-                     elseif INFO1
-                       then 
-                            (* ;; "OK if INFO2 is missing?")
-
-                            (MEMB '*- SELECT)
-                     else 
-                          (* ;; "OK if INFO1 is missing?")
-
-                          (MEMB '-* SELECT))
-              collect (create CDENTRY
-                             MATCHNAME _ MATCHNAME
-                             INFO1 _ INFO1
-                             DATEREL _ DATEREL
-                             INFO2 _ INFO2
-                             EQUIV _ (CL:UNLESS (EQ DATEREL '*)
-                                            BINCOMP]
+          (SETQ CDENTRIES (CDENTRIES.SELECT CANDIDATES SELECT))
           (PRINTOUT T (LENGTH CDENTRIES)
                  " entries" T)
           (REPLACE CDENTRIES OF CDVALUE WITH CDENTRIES)
@@ -227,37 +173,118 @@ Copyright (c) 1985-1988, 1990, 1994, 1998, 2018, 2020-2021 by Venue & Xerox Corp
           (RETURN (CDPRINT CDVALUE OUTPUTFILE NIL (MEMB 'AUTHOR SELECT])
 
 (COMPAREDIRECTORIES.INFOS
-  [LAMBDA (FILES USEDIRECTORYDATE DIR)                       (* ; "Edited 23-Dec-2021 18:59 by rmk")
+  [LAMBDA (FILES USEDIRECTORYDATE DIR)                       (* ; "Edited  4-Jan-2022 15:23 by rmk")
+                                                             (* ; "Edited 23-Dec-2021 18:59 by rmk")
                                                              (* ; "Edited 12-Dec-2021 22:50 by rmk")
                                                              (* ; "Edited 23-Nov-2021 12:27 by rmk:")
                                                              (* ; "Edited 13-Oct-2020 08:42 by rmk:")
 
     (* ;; "Value is a list of CDINFOS with the match-name consed on to the front")
 
-    (FOR FULLNAME TYPE LDATE (STARTPOS _ (ADD1 (NCHARS DIR))) IN FILES
+    (FOR FULLNAME TYPE LDATE STREAM (STARTPOS _ (ADD1 (NCHARS DIR))) IN FILES
        COLLECT 
 
              (* ;; "GDATE/IDATE in case Y2K")
-
-             (SETQ LDATE (OR (FILEDATE FULLNAME T)
-                             (FILEDATE FULLNAME)))           (* ; 
+                                                             (* ; 
                                             "Is it a Lisp file? Get it's internal filecreated date. ")
-             (CONS (MATCHNAME FULLNAME STARTPOS)
-                   (CREATE CDINFO
-                          FULLNAME _ FULLNAME
-                          DATE _ [GDATE (IDATE (IF USEDIRECTORYDATE
-                                                   THEN (GETFILEINFO FULLNAME 'CREATIONDATE)
-                                                 ELSEIF (OR LDATE (GETFILEINFO FULLNAME 
-                                                                         'CREATIONDATE]
-                          LENGTH _ (GETFILEINFO FULLNAME 'LENGTH)
-                          AUTHOR _ (GETFILEINFO FULLNAME 'AUTHOR)
-                          TYPE _ (COMPAREDIRECTORIES.INFOS.TYPE FULLNAME LDATE)
-                          EOL _ (EOLTYPE FULLNAME])
+             (SETQ STREAM (OPENSTREAM FULLNAME 'INPUT))      (* ; 
+                "So all the GETFILEINFO's, FILEDATES, etc. don't have to do the directory searching.")
+             (SETQ LDATE (OR (FILEDATE STREAM T)
+                             (FILEDATE STREAM)))
+             (PROG1 (CONS (MATCHNAME FULLNAME STARTPOS)
+                          (CREATE CDINFO
+                                 FULLNAME _ FULLNAME
+                                 DATE _ (GDATE (IDATE (IF (OR USEDIRECTORYDATE (NULL LDATE))
+                                                          THEN (GETFILEINFO STREAM 'CREATIONDATE)
+                                                        ELSE (SETFILEINFO STREAM 'CREATIONDATE LDATE)
+                                                             LDATE)))
+                                 LENGTH _ (GETFILEINFO STREAM 'LENGTH)
+                                 AUTHOR _ (GETFILEINFO STREAM 'AUTHOR)
+                                 TYPE _ (COMPAREDIRECTORIES.INFOS.TYPE STREAM LDATE)
+                                 EOL _ (EOLTYPE STREAM)))
+                    (CLOSEF? STREAM])
+
+(CDENTRIES.SELECT
+  [LAMBDA (CANDIDATES SELECT)                                (* ; "Edited  4-Jan-2022 21:31 by rmk")
+
+    (* ;; "Does the pairwise select filter and inserts the date relation")
+
+    (for C MATCHNAME INFO1 INFO2 IDATE1 IDATE2 DATEREL BINCOMP [COMPAREDATE
+                                                                _
+                                                                (INTERSECTION SELECT
+                                                                       '(< > =] in CANDIDATES
+       eachtime (SETQ MATCHNAME (pop C))
+             (SETQ INFO1 (pop C))
+             (SETQ INFO2 (pop C))
+             (if (AND INFO1 INFO2)
+                 then (SETQ IDATE1 (IDATE (fetch DATE of INFO1)))
+                      (SETQ IDATE2 (IDATE (fetch DATE of INFO2)))
+                      (SETQ DATEREL (if (IGREATERP IDATE1 IDATE2)
+                                        then '>
+                                      elseif (ILESSP IDATE1 IDATE2)
+                                        then '<
+                                      else '=))
+               else 
+                    (* ;; "Just for printing--no comparison")
+
+                    (SETQ DATEREL '*))
+       when (if (AND INFO1 INFO2)
+                then (CL:WHEN (OR (NULL COMPAREDATE)
+                                  (SELECTQ DATEREL
+                                      (> (MEMB '> COMPAREDATE))
+                                      (< (MEMB '< COMPAREDATE))
+                                      (= (MEMB '= COMPAREDATE))
+                                      (SHOULDNT)))
+                         (SETQ BINCOMP (BINCOMP (fetch (CDINFO FULLNAME) OF INFO1)
+                                              (fetch (CDINFO FULLNAME) OF INFO2)
+                                              T
+                                              (fetch (CDINFO EOL) OF INFO1)
+                                              (fetch (CDINFO EOL) OF INFO2)))
+                         (CL:WHEN (EQ T BINCOMP)
+
+                             (* ;; "Byte-equivalent files with different dates.  Presumably the earlier date is more accurate, move back the date of the later file and make DATEREL be =.  Perhaps we should do this even if there is only an EOL difference (BINCOMP non-NIL).;; Byte-equivalent files with different dates.  Presumably the earlier date is more accurate, move back the date of the earlier file and make DATEREL be =.  Perhaps we should do this even if there is only an EOL difference (BINCOMP non-NIL). ")
+
+                             (* ;; "We do this even if FIXDIRECTORYDATES is false, that addresses a property of individual Lisp source files.")
+
+                             (SELECTQ DATEREL
+                                 (> (SETFILEINFO (FETCH (CDINFO FULLNAME) OF INFO1)
+                                           'CREATIONDATE
+                                           (REPLACE (CDINFO DATE) OF INFO1 WITH (FETCH (CDINFO DATE)
+                                                                                   OF INFO2))))
+                                 (< (SETFILEINFO (FETCH (CDINFO FULLNAME) OF INFO2)
+                                           'CREATIONDATE
+                                           (REPLACE (CDINFO DATE) OF INFO2 WITH (FETCH (CDINFO DATE)
+                                                                                   OF INFO1))))
+                                 NIL)
+                             (SETQ DATEREL '=))
+
+                         (* ;; "We want the ~= test to reflect exact byte equivalence, including the same EOL.  We use the BINCOMP value below to indicate EOL differences, so we check it here.")
+
+                         [NOT (AND (MEMB '~= SELECT)
+                                   BINCOMP
+                                   (EQ (fetch (CDINFO EOL) OF INFO1)
+                                       (fetch (CDINFO EOL) OF INFO2])
+              elseif INFO1
+                then 
+                     (* ;; "OK if INFO2 is missing?")
+
+                     (MEMB '*- SELECT)
+              else 
+                   (* ;; "OK if INFO1 is missing?")
+
+                   (MEMB '-* SELECT))
+       collect (create CDENTRY
+                      MATCHNAME _ MATCHNAME
+                      INFO1 _ INFO1
+                      DATEREL _ DATEREL
+                      INFO2 _ INFO2
+                      EQUIV _ (CL:UNLESS (EQ DATEREL '*)
+                                     BINCOMP])
 
 (COMPAREDIRECTORIES.INFOS.TYPE
-  [LAMBDA (FULLNAME LDATE)                                   (* ; "Edited 12-Dec-2021 22:50 by rmk")
-    (IF (OR LDATE (FILEDATE FULLNAME T)
-            (FILEDATE FULLNAME))
+  [LAMBDA (FULLNAME LDATE)                                   (* ; "Edited  4-Jan-2022 13:10 by rmk")
+                                                             (* ; "Edited 12-Dec-2021 22:50 by rmk")
+    (IF LDATE
         THEN (CL:IF (MEMB (FILENAMEFIELD FULLNAME 'EXTENSION)
                           *COMPILED-EXTENSIONS*)
                  'COMPILED
@@ -318,9 +345,12 @@ Copyright (c) 1985-1988, 1990, 1994, 1998, 2018, 2020-2021 by Venue & Xerox Corp
 (DEFINEQ
 
 (CDFILES
-  [LAMBDA (DIR INCLUDEDFILES EXCLUDEDFILES ALLVERSIONS DEPTH)(* ; "Edited 23-Dec-2021 22:49 by rmk")
-                                                             (* ; "Edited  6-Nov-2021 12:08 by rmk:")
-                                                             (* ; "Edited 16-Oct-2020 13:42 by rmk:")
+  [LAMBDA (DIR INCLUDEDFILES EXCLUDEDFILES ALLVERSIONS DEPTH)(* ; "Edited 26-Jan-2022 15:25 by rmk")
+                                                             (* ; "Edited 21-Jan-2022 22:40 by rmk")
+                                                             (* ; "Edited  5-Jan-2022 15:07 by rmk")
+                                                             (* ; "Edited 23-Dec-2021 22:49 by rmk")
+                                                            (* ; "Edited  6-Nov-2021 12:08 by rmk:")
+                                                            (* ; "Edited 16-Oct-2020 13:42 by rmk:")
 
     (* ;; "Returns a list of fullnames for files that satisfy the criteria.  We generate all candidates that match INCLUDEDFILES but not EXCLUDEDFILES in DIR.")
 
@@ -338,7 +368,7 @@ Copyright (c) 1985-1988, 1990, 1994, 1998, 2018, 2020-2021 by Venue & Xerox Corp
 
     (* ;; "EXCLUDEDFILES is a filepattern with * meaning everything, COM means *.LCOM and *.DFASL")
 
-    [SETQ EXCLUDEDFILES `(.DS_Store
+    [SETQ EXCLUDEDFILES `(*>.DS_Store
                           ,@(MKLIST EXCLUDEDFILES]
     (CL:UNLESS (EQMEMB '.* INCLUDEDFILES)                    (* ; 
                                                    "Excluded dot files unless specifically asked for")
@@ -372,9 +402,14 @@ Copyright (c) 1985-1988, 1990, 1994, 1998, 2018, 2020-2021 by Venue & Xerox Corp
                (CL:UNLESS (OR (EQ SD '*)
                               (EQ SD (CAR P)))
                       (SETQ SD NIL)) FINALLY (CL:WHEN (EQ SD '*)
-                                                    (SETQ SD ""))
+                                                    (SETQ SD "")) 
+
+                                           (* ;; 
+   "If We don't prefix TOPDIR with <, then if TOPDIR contains a colon it is interpreted as a device.")
+
                                            (SETQ ENUMPAT (PACKFILENAME 'HOST HOST 'DIRECTORY
-                                                                (CONCAT TOPDIR ">" (OR SD ""))
+                                                                (CONCAT "<" TOPDIR ">"
+                                                                       (OR SD ""))
                                                                 'NAME N 'EXTENSION E 'VERSION
                                                                 (CL:IF ALLVERSIONS
                                                                     '*
@@ -387,48 +422,52 @@ Copyright (c) 1985-1988, 1990, 1994, 1998, 2018, 2020-2021 by Venue & Xerox Corp
          (* ;; "We enumerate all the files, checking to see that")
 
          (FOR FULLNAME NAME EXT SUBDIR UNPACK THISDEPTH (STARTPOS _ (ADD1 (NCHARS TOPDIR)))
-            IN (DIRECTORY ENUMPAT) EACHTIME (CL:WHEN (DIRECTORYNAMEP FULLNAME)
-                                                             (* ; "Skip directories")
-                                                (GO $$ITERATE))
-                                         (SETQ UNPACK (UNPACKFILENAME FULLNAME))
-                                         (SETQ NAME (LISTGET UNPACK 'NAME))
-                                         (SETQ EXT (LISTGET UNPACK 'EXTENSION))
-                                         (SETQ SUBDIR (SUBATOM (LISTGET UNPACK 'DIRECTORY)
-                                                             STARTPOS))
-                                         (CL:UNLESS NAME
-                                             (CL:WHEN EXT    (* ; ".XY")
-                                                 (SETQ NAME (PACK* "." EXT))
-                                                 (SETQ EXT NIL)))
-                                         (SETQ THISDEPTH (FOR I (CNT _ 1) FROM 1
-                                                            DO (SELCHARQ (NTHCHARCODE SUBDIR I)
-                                                                    ((> /) 
-                                                                         (ADD CNT 1))
-                                                                    (NIL (RETURN CNT))
-                                                                    NIL)))
+            IN (DIRECTORY ENUMPAT NIL NIL (CL:IF ALLVERSIONS
+                                              "*"
+                                              ""))
+            EACHTIME (SETQ UNPACK (UNPACKFILENAME FULLNAME))
+                  (SETQ NAME (LISTGET UNPACK 'NAME))
+                  (SETQ EXT (LISTGET UNPACK 'EXTENSION))
+                  (CL:UNLESS NAME
+                      (CL:WHEN EXT                           (* ; ".XY")
+                          (SETQ NAME (PACK* "." EXT))
+                          (SETQ EXT NIL)))
+                  (CL:UNLESS (OR NAME EXT)                   (* ; "Must have been a directory")
+                      (GO $$ITERATE))
+                  (SETQ SUBDIR (SUBATOM (LISTGET UNPACK 'DIRECTORY)
+                                      STARTPOS))
+                  (SETQ THISDEPTH (FOR I (CNT _ 1) FROM 1 DO (SELCHARQ (NTHCHARCODE SUBDIR I)
+                                                                  ((> /) 
+                                                                       (ADD CNT 1))
+                                                                  (NIL (RETURN CNT))
+                                                                  NIL)))
             WHEN (OR (NULL INCLUDES)
                      (CDFILES.MATCH SUBDIR NAME EXT THISDEPTH INCLUDES))
             UNLESS (CDFILES.MATCH SUBDIR NAME EXT THISDEPTH EXCLUDES) COLLECT FULLNAME])
 
 (CDFILES.MATCH
-  [LAMBDA (SUBDIR NAME EXT THISDEPTH PATTERNS)               (* ; "Edited 23-Dec-2021 21:47 by rmk")
+  [LAMBDA (SUBDIR NAME EXT THISDEPTH PATTERNS)               (* ; "Edited 26-Jan-2022 15:33 by rmk")
+                                                             (* ; "Edited 23-Dec-2021 21:47 by rmk")
 
     (* ;; "True if the components of the fullname match at least one of the patterns")
 
-    (THEREIS P IN PATTERNS SUCHTHAT (AND [OR (STRING.EQUAL NAME (CAR P))
+    (THEREIS P IN PATTERNS SUCHTHAT (AND [OR (STRING.EQUAL NAME (CAR P)
+                                                    FILEDIRCASEARRAY)
                                              (EQ '* (CAR P))
                                              (AND (EQ (CHARCODE %.)
                                                       (CHCON1 (CAR P)))
-                                                  (EQ (EQ (CHARCODE %.)
-                                                          (CHCON1 NAME)))
+                                                  (EQ (CHARCODE %.)
+                                                      (CHCON1 NAME))
                                                   (OR (STRING.EQUAL NAME (SUBATOM (CAR P)
                                                                                 2))
-                                                      (EQ (CHARCODE *1)
+                                                      (EQ (CHARCODE *)
                                                           (NTHCHARCODE (CAR P)
                                                                  2]
                                          (OR (STRING.EQUAL EXT (CADR P))
                                              (EQ '* (CADR P)))
                                          (OR (STRING.EQUAL SUBDIR (CADDR P))
-                                             (NULL (CADDR P)))
+                                             (NULL (CADDR P))
+                                             (EQ '* (CADDR P)))
                                          (ILEQ THISDEPTH (CADDDR P])
 
 (CDFILES.PATS
@@ -479,9 +518,10 @@ Copyright (c) 1985-1988, 1990, 1994, 1998, 2018, 2020-2021 by Venue & Xerox Corp
 (DEFINEQ
 
 (CDPRINT
-  [LAMBDA (CDVALUE FILE COLHEADINGS PRINTAUTHOR)             (* ; "Edited 19-Dec-2021 20:10 by rmk")
-                                                             (* ; "Edited 30-Nov-2021 20:59 by rmk:")
-                                                             (* ; "Edited 13-Oct-2020 08:38 by rmk:")
+  [LAMBDA (CDVALUE FILE COLHEADINGS PRINTAUTHOR)             (* ; "Edited 26-Jan-2022 13:43 by rmk")
+                                                             (* ; "Edited 19-Dec-2021 20:10 by rmk")
+                                                            (* ; "Edited 30-Nov-2021 20:59 by rmk:")
+                                                            (* ; "Edited 13-Oct-2020 08:38 by rmk:")
 
     (* ;; "Typically CDVALUE will have a provdenance header.  If not, we fake one up, at least for the directories and today's date.")
 
@@ -502,11 +542,7 @@ Copyright (c) 1985-1988, 1990, 1994, 1998, 2018, 2020-2021 by Venue & Xerox Corp
                          '(PROGN (CLOSEF? OLDVALUE])
               (LINELENGTH 1000 STREAM)                       (* ; "Don't wrap")
               (CL:WHEN (FETCH (CDVALUE CDDIR1) OF CDVALUE)
-                  (PRINTOUT STREAM "Comparing " (FETCH (CDVALUE CDDIR1) OF CDVALUE)
-                         6 "vs. " (FETCH (CDVALUE CDDIR2) OF CDVALUE)
-                         T "as of " (FETCH (CDVALUE CDCOMPAREDATE) OF CDVALUE))
-                  (CL:WHEN (FETCH (CDVALUE CDSELECT) OF CDVALUE)
-                      (PRINTOUT STREAM " selecting " (FETCH (CDVALUE CDSELECT) OF CDVALUE)))
+                  (CDPRINT.HEADER CDVALUE STREAM)
                   (PRINTOUT STREAM -2 (LENGTH (fetch CDENTRIES of CDVALUE))
                          " entries" T T))
               (if (fetch CDENTRIES of CDVALUE)
@@ -517,6 +553,27 @@ Copyright (c) 1985-1988, 1990, 1994, 1998, 2018, 2020-2021 by Venue & Xerox Corp
                 else (PRINTOUT T "CDVALUE is empty" T))
               (AND STREAM (CLOSEF? STREAM))))])
 
+(CDPRINT.HEADER
+  [LAMBDA (DIR1 DIR2 SELECT DATE STREAM)                     (* ; "Edited 26-Jan-2022 13:36 by rmk")
+    (CL:WHEN (LISTP DIR1)
+
+        (* ;; "A CDVALUE")
+
+        (CL:UNLESS STREAM (SETQ STREAM DIR2))
+        (SETQ DIR2 (FETCH CDDIR2 OF DIR1))
+        (SETQ SELECT (FETCH CDSELECT OF DIR1))
+        (SETQ DATE (FETCH CDCOMPAREDATE OF DIR1))
+        (SETQ DIR1 (FETCH CDDIR1 OF DIR1)))
+    (CL:WHEN DIR1
+        (PRINTOUT STREAM "Comparing ")
+        (PRINTOUT STREAM DIR1 %# (CL:WHEN (IGREATERP (IPLUS (NCHARS DIR1)
+                                                            (NCHARS DIR2))
+                                                 70)
+                                        (TAB 5))
+               " vs. " DIR2)
+        (PRINTOUT STREAM T 3 "as of " DATE)
+        (CL:WHEN SELECT (PRINTOUT STREAM " selecting " SELECT)))])
+
 (CDPRINT.LINE
   [LAMBDA (STREAM ENTRY PRINTAUTHOR DATE1POS ENDDATE1 NCHARSDIR1 NCHARSDIR2)
                                                             (* ; "Edited 22-Nov-2021 22:38 by rmk:")
@@ -752,6 +809,89 @@ Copyright (c) 1985-1988, 1990, 1994, 1998, 2018, 2020-2021 by Venue & Xerox Corp
                                                     (SETQ INFO2 (FETCH INFO2 OF CDE))
                                                     (SETQ EQUIV (FETCH EQUIV OF CDE))
                                               WHEN (APPLY* FN CDE) COLLECT CDE])
+
+(CDMERGE
+  [LAMBDA (CDVALUES)                                         (* ; "Edited 24-Jan-2022 17:01 by rmk")
+
+    (* ;; "This merges a collection of CDVALUES on different directories into a single CDVALUE with the union of the CDENTRIES, provided that they have the same selection criteria.  The merged directories will be the minimal common prefix of all of the entries on each side, and the residual of the directory will be packed onto all the names.")
+
+    (IF (CDR CDVALUES)
+        THEN
+        [LET
+         (CDSELECTS)
+
+         (* ;; "Group by selects")
+
+         (FOR CDV TMP IN CDVALUES
+            DO (PUSH [CDR (OR (SASSOC (FETCH CDSELECT OF CDV)
+                                     CDSELECTS)
+                              (CAR (PUSH CDSELECTS (CONS (FETCH CDSELECT OF CDV]
+                     CDV))
+
+         (* ;; "For each group, find the longest common directory prefixes")
+
+         (FOR CDS IDATE DIR1 DIR2 MERGEDENTRIES IN CDSELECTS
+            COLLECT (SETQ DIR1 (FETCH CDDIR1 OF (CADR CDS)))
+                  (SETQ DIR2 (FETCH CDDIR2 OF (CADR CDS)))
+                  [SETQ IDATE (IDATE (FETCH CDCOMPAREDATE OF (CADR CDS] 
+
+                  (* ;; "Calculate the common directory prefixes and latest date")
+
+                  [FOR CDV IN (CDDR CDS) DO (SETQ DIR1 (CDMERGE.COMMON DIR1 (FETCH CDDIR1
+                                                                               OF CDV)))
+                                            (SETQ DIR2 (CDMERGE.COMMON DIR2 (FETCH CDDIR2
+                                                                               OF CDV)))
+                                            (CL:WHEN (IGREATERP IDATE (IDATE (FETCH CDCOMPAREDATE
+                                                                                OF CDV)))
+                                                (SETQ IDATE (IDATE (FETCH CDCOMPAREDATE OF CDV))))] 
+
+                  (* ;; 
+                  "Merge the CDENTRIES with matchnames pulled back so that subdirectories show up")
+
+                  (SETQ MERGEDENTRIES
+                   (SORT [FOR CDV NC1 _ (ADD1 (NCHARS DIR1))
+                              NC2 _ (ADD1 (NCHARS DIR2)) IN (CDR CDS)
+                            JOIN (FOR CDE IN (FETCH CDENTRIES OF CDV)
+                                    COLLECT (CREATE CDENTRY
+                                               USING CDE MATCHNAME _
+                                                     (IF (FETCH INFO1 OF CDE)
+                                                         THEN (MATCHNAME (FETCH (CDINFO FULLNAME)
+                                                                            OF (FETCH INFO1
+                                                                                  OF CDE))
+                                                                     NC1)
+                                                       ELSE (MATCHNAME (FETCH (CDINFO FULLNAME)
+                                                                          OF (FETCH INFO2
+                                                                                OF CDE))
+                                                                   NC2]
+                         T))
+                  (CD.UPDATEWIDTHS (CREATE CDVALUE
+                                          CDDIR1 _ DIR1
+                                          CDDIR2 _ DIR2
+                                          CDCOMPAREDATE _ (GDATE IDATE)
+                                          CDSELECT _ (CAR CDS)
+                                          CDENTRIES _ MERGEDENTRIES]
+      ELSE CDVALUES])
+
+(CDMERGE.COMMON
+  [LAMBDA (DIRX DIRY)                                        (* ; "Edited 24-Jan-2022 16:40 by rmk")
+
+    (* ;; 
+    "Returns the longest common prefix of DIRX and DIRY, collapsing brackets, slashes, and case")
+
+    (FOR I CX CY (LASTDIRPOS _ 1) FROM 1 EACHTIME (SETQ CX (NTHCHARCODE DIRX I))
+                                               (SETQ CY (NTHCHARCODE DIRY I))
+                                               (CL:WHEN (MEMB CX (CHARCODE (< > /)))
+                                                   (SETQ CX (CHARCODE /)))
+                                               (CL:WHEN (MEMB CY (CHARCODE (< > /)))
+                                                   (SETQ CY (CHARCODE /)))
+                                               (CL:WHEN (AND (EQ CX (CHARCODE /))
+                                                             (EQ CY (CHARCODE /)))
+                                                      (SETQ LASTDIRPOS I))
+       UNLESS [AND CX CY (OR (EQ CX CY)
+                             (EQ (L-CASECODE CX)
+                                 (L-CASECODE CY] DO (RETURN (CL:IF (EQ I 1)
+                                                                ""
+                                                                (SUBSTRING DIRX 1 LASTDIRPOS))])
 )
 (DEFINEQ
 
@@ -827,40 +967,51 @@ Copyright (c) 1985-1988, 1990, 1994, 1998, 2018, 2020-2021 by Venue & Xerox Corp
                                        FINALLY (RETURN (OR EOLDIFF T]))])
 
 (EOLTYPE
-  [LAMBDA (FILE SHOWCONTEXT)                            (* ; "Edited 21-Feb-2021 20:34 by rmk:")
+  [LAMBDA (FILE SHOWCONTEXT)
 
-    (* ;; "Returns the EOLCONVENTION of FILE if it only sees one kind, NIL if it can't decide.")
+    (* ;; "Edited  4-Jan-2022 15:10 by rmk: Allow FILE to be an already open stream")
 
-    (* ;; "If SHOWCONTEXT, it is the number of bytes before and after an EOL inconsistency (e.g. seeing CR after having seen LF) that will be displayed on the TTY.  The position of the inconsistency will be marked with ##.")
+    (* ;; "Edited 21-Feb-2021 20:34 by rmk:")
+
+    (* ;; "Returns the EOLCONVENTION of FILE if it only sees one kind, NIL if it can't decide.")
+
+    (* ;; "If SHOWCONTEXT, it is the number of bytes before and after an EOL inconsistency (e.g. seeing CR after having seen LF) that will be displayed on the TTY.  The position of the inconsistency will be marked with ##.")
 
     (SELECTQ SHOWCONTEXT
         (NIL)
         (T (SETQ SHOWCONTEXT 100))
         (CL:UNLESS (FIXP SHOWCONTEXT)
                (ERROR "SHOWCONTEXT must be an integer" SHOWCONTEXT)))
-    (CL:WITH-OPEN-FILE
-     (STREAM FILE :DIRECTION :INPUT)
-     (SETFILEINFO STREAM 'ENDOFSTREAMOP (FUNCTION NILL))
-     (BIND EOLTYPE
-        DO (SELCHARQ (OR (\BIN STREAM)
-                             (RETURN EOLTYPE))
-                    (CR (IF (EQ (CHARCODE LF)
+    (RESETLST
+        (LET (STREAM)
+             [IF (GETSTREAM FILE 'INPUT T)
+                 THEN (SETQ STREAM FILE)
+                      [RESETSAVE NIL `(PROGN (SETFILEPTR ,STREAM ,(GETFILEPTR STREAM))
+                                             (STREAMPROP ,STREAM 'ENDOFSTREAMOP
+                                                    ',(STREAMPROP STREAM 'ENDOFSTREAMOP]
+                      (SETFILEPTR STREAM 0)
+               ELSE (RESETSAVE NIL `(CLOSEF? ,(SETQ STREAM (OPENSTREAM FILE 'INPUT]
+             (SETFILEINFO STREAM 'ENDOFSTREAMOP (FUNCTION NILL))
+             (BIND EOLTYPE
+                DO (SELCHARQ (OR (\BIN STREAM)
+                                 (RETURN EOLTYPE))
+                        (CR (IF (EQ (CHARCODE LF)
                                     (\PEEKBIN STREAM T))
-                            THEN (\BIN STREAM)
-                                  (IF (MEMB EOLTYPE '(LF CR))
-                                      THEN (CL:UNLESS (EOLTYPE.SHOW SHOWCONTEXT EOLTYPE
-                                                                 'LF STREAM)
-                                                      (RETURN NIL))
-                                    ELSE (SETQ EOLTYPE 'CRLF))
-                          ELSEIF (MEMB EOLTYPE '(LF CRLF))
-                            THEN (CL:UNLESS (EOLTYPE.SHOW SHOWCONTEXT EOLTYPE 'CR STREAM)
+                                THEN (\BIN STREAM)
+                                     (IF (MEMB EOLTYPE '(LF CR))
+                                         THEN (CL:UNLESS (EOLTYPE.SHOW SHOWCONTEXT EOLTYPE
+                                                                'LF STREAM)
+                                                     (RETURN NIL))
+                                       ELSE (SETQ EOLTYPE 'CRLF))
+                              ELSEIF (MEMB EOLTYPE '(LF CRLF))
+                                THEN (CL:UNLESS (EOLTYPE.SHOW SHOWCONTEXT EOLTYPE 'CR STREAM)
                                             (RETURN NIL))
-                          ELSE (SETQ EOLTYPE 'CR)))
-                    (LF (IF (MEMB EOLTYPE '(CR CRLF))
-                            THEN (CL:UNLESS (EOLTYPE.SHOW SHOWCONTEXT EOLTYPE 'LF STREAM)
+                              ELSE (SETQ EOLTYPE 'CR)))
+                        (LF (IF (MEMB EOLTYPE '(CR CRLF))
+                                THEN (CL:UNLESS (EOLTYPE.SHOW SHOWCONTEXT EOLTYPE 'LF STREAM)
                                             (RETURN NIL))
-                          ELSE (SETQ EOLTYPE 'LF)))
-                    NIL])
+                              ELSE (SETQ EOLTYPE 'LF)))
+                        NIL))))])
 
 (EOLTYPE.SHOW
   [LAMBDA (SHOWCONTEXT OLDTYPE NEWTYPE STREAM)          (* ; "Edited 21-Feb-2021 20:20 by rmk:")
@@ -1435,18 +1586,16 @@ Copyright (c) 1985-1988, 1990, 1994, 1998, 2018, 2020-2021 by Venue & Xerox Corp
 
 (CDBROWSER
   [LAMBDA (CDVALUE TITLE COLHEADINGS BROWSERPROPS SEPARATEDIRECTIONS MENUITEMS)
-                                                             (* ; "Edited 25-Dec-2021 12:50 by rmk")
-                                                             (* ; "Edited 16-Dec-2021 11:51 by rmk")
-                                                             (* ; "Edited 14-Dec-2021 21:41 by rmk")
-                                                             (* ; "Edited 10-Dec-2021 21:38 by rmk")
-                                                             (* ; "Edited 30-Nov-2021 15:03 by rmk:")
-                                                             (* ; "Edited 29-Nov-2021 14:18 by rmk:")
+
+    (* ;; "Edited 25-Jan-2022 13:05 by rmk: a table browser for the differences in CDVALUE.")
 
     (* ;; "Creates a table browser for the differences in CDVALUE.")
 
     (SETQ MENUITEMS (IF MENUITEMS
                         THEN (FOR I IN MENUITEMS COLLECT (OR (LISTP I)
                                                              (SASSOC I CDTABLEBROWSER.MENUITEMS)
+                                                             (AND (STREQUAL I "")
+                                                                  "")
                                                              (ERROR "UNKNOWN CDBROWSER MENU ITEM" I))
                                   )
                       ELSE CDTABLEBROWSER.MENUITEMS))
@@ -1466,8 +1615,8 @@ Copyright (c) 1985-1988, 1990, 1994, 1998, 2018, 2020-2021 by Venue & Xerox Corp
                                                                                       DEFAULTFONT]
              [SETQ REGION (GETREGION (PLUS TB.LEFT.MARGIN ITEMWIDTH (TIMES 2 WBorder)
                                            MENUWIDTH)
-                                 (TIMES [IMIN 15 (IMAX (IPLUS 4 (LENGTH STRINGS))
-                                                       (ADD1 (LENGTH MENUITEMS]
+                                 (TIMES (IMAX (IMIN 15 (LENGTH STRINGS))
+                                              (ADD1 (LENGTH MENUITEMS)))
                                         (FONTPROP DEFAULTFONT 'HEIGHT]
 
              (* ;; "Promptwindow seems to do its own thing, even if under construction.  So we preshrink the main window.")
@@ -1476,8 +1625,13 @@ Copyright (c) 1985-1988, 1990, 1994, 1998, 2018, 2020-2021 by Venue & Xerox Corp
                                                                               OF REGION)
                                                                       (FONTPROP DEFAULTFONT
                                                                              'HEIGHT]
-             (SETQ WINDOW (CREATEW REGION (OR TITLE "Compare directories")
+             (SETQ WINDOW (CREATEW REGION (OR TITLE (CONCAT "Compare directories       " (LENGTH
+                                                                                          STRINGS)
+                                                           " files"))
                                  NIL T))
+             [WINDOWADDPROP WINDOW 'CLOSEFN (FUNCTION (LAMBDA (W)
+                                                        (FOR W INSIDE (WINDOWPROP W 'SUBWINDOWS)
+                                                           DO (CLOSEW (WFROMDS W]
              (WINDOWPROP WINDOW 'UNDERCONSTRUCTION T)
 
              (* ;; "TABLEBROWSER is odd: USERDATA is a single recognized property.  But it allows for other unrecognized properties in the list, it pushes them on to a list USERPROPS...and then throws it away.  So here I'm using USERDATA to hold the directory lengths so they can be stripped off for display.  It may actually be better to have a field name in CDVALUE for all of the shared stuff in front of the entries, and keep it all.")
@@ -1610,105 +1764,153 @@ Copyright (c) 1985-1988, 1990, 1994, 1998, 2018, 2020-2021 by Venue & Xerox Corp
            'DON'T])
 
 (CD.COMMANDSELECTEDFN
-  [LAMBDA (MENUITEM MENU KEY)                                (* ; "Edited 25-Dec-2021 11:20 by rmk")
-                                                             (* ; "Edited 16-Dec-2021 13:45 by rmk")
-                                                             (* ; "Edited 13-Dec-2021 17:13 by rmk")
-                                                             (* ; "Edited  9-Dec-2021 21:36 by rmk")
-                                                             (* ; "Edited  8-Dec-2021 11:27 by rmk")
-                                                             (* ; "Edited  5-Dec-2021 13:28 by rmk")
-                                                             (* ; "Edited  3-Dec-2021 00:21 by rmk:")
-                                                             (* ; "Edited 29-Nov-2021 23:08 by rmk:")
+  [LAMBDA (MENUITEM MENU KEY)                                (* ; "Edited 27-Jan-2022 17:46 by rmk")
+                                                             (* ; "Edited 10-Jan-2022 22:51 by rmk")
+                                                             (* ; "Edited 25-Dec-2021 11:20 by rmk")
                                                              (* ; "Edited 12-Jan-87 12:57 by bvm:")
 
     (* ;; "Cobbled from FB.COMMANDSELECTEDFN.  But here we assume that the menu item is of the form (display-string FN . EXTRAS), we peel out the FN to apply, leave the rest alone.")
 
     (DECLARE (SPECVARS MENUITEM MENU KEY))
-    (RESETLST
-        [LET* [(WINDOW (WINDOWPROP (WFROMMENU MENU)
-                              'MAINWINDOW))
-               (PROMPTWINDOW (GETPROMPTWINDOW WINDOW))
-               (CDBROWSER (WINDOWPROP WINDOW 'TABLEBROWSER))
-               (USERDATA (TB.USERDATA CDBROWSER))
-               (CDVALUE (LISTGET USERDATA 'CDVALUE))
-               (FN (CADR (LISTP MENUITEM]
-              (DECLARE (SPECVARS WINDOW PROMPTWINDOW CDVALUE USERDATA))
-              (GIVE.TTY.PROCESS PROMPTWINDOW)
-              (TTYDISPLAYSTREAM PROMPTWINDOW)                (* ; "Pwindow")
-              (IF (EQ 0 (TB.NUMBER.OF.ITEMS CDBROWSER 'SELECTED))
-                  THEN (FLASHWINDOW PROMPTWINDOW)
-                       (PRIN3 "Please make a selection" T)
-                ELSE (TB.MAP.SELECTED.ITEMS CDBROWSER
-                            [FUNCTION (LAMBDA (CDBROWSER TBITEM)
-                                        (LET* ((CDENTRY (CADR (FETCH TIDATA OF TBITEM)))
-                                               (FILE1 (FETCH (CDINFO FULLNAME)
-                                                             (FETCH (CDENTRY INFO1) OF CDENTRY)))
-                                               (FILE2 (FETCH (CDINFO FULLNAME)
-                                                             (FETCH (CDENTRY INFO2) OF CDENTRY)))
-                                               (TYPE (FETCH (CDINFO TYPE) OF (FETCH (CDENTRY INFO1)
-                                                                                OF CDENTRY)))
-                                               (LABELS (APPLY* (OR (LISTGET USERDATA 'LABELFN)
-                                                                   (FUNCTION NILL))
-                                                              FILE1 FILE2 USERDATA))
-                                               (LABEL1 (OR (CAR LABELS)
-                                                           FILE1))
-                                               (LABEL2 (OR (CADR LABELS)
-                                                           FILE2)))
-                                              (DECLARE (SPECVARS . T))
+    (CL:UNLESS (STREQUAL MENUITEM "")                        (* ; "For blank lines")
+        (RESETLST
+            [LET* [(WINDOW (WINDOWPROP (WFROMMENU MENU)
+                                  'MAINWINDOW))
+                   (PWINDOW (GETPROMPTWINDOW WINDOW))
+                   (CDBROWSER (WINDOWPROP WINDOW 'TABLEBROWSER))
+                   (USERDATA (TB.USERDATA CDBROWSER))
+                   (CDVALUE (LISTGET USERDATA 'CDVALUE))
+                   (FN (CADR (LISTP MENUITEM]
+                  (DECLARE (SPECVARS WINDOW PWINDOW CDVALUE USERDATA))
+                  (GIVE.TTY.PROCESS PWINDOW)
+                  (TTYDISPLAYSTREAM PWINDOW)                 (* ; "Pwindow")
+                  (COND
+                     ((EQ 0 (TB.NUMBER.OF.ITEMS CDBROWSER 'SELECTED))
+                      (FLASHWINDOW PWINDOW)
+                      (PRIN3 "Please make a selection" T))
+                     (T (TB.MAP.SELECTED.ITEMS
+                         CDBROWSER
+                         [FUNCTION (LAMBDA (CDBROWSER TBITEM)
+                                     (LET* ((CDENTRY (CADR (FETCH TIDATA OF TBITEM)))
+                                            (FILE1 (FETCH (CDINFO FULLNAME)
+                                                          (FETCH (CDENTRY INFO1) OF CDENTRY)))
+                                            (FILE2 (FETCH (CDINFO FULLNAME)
+                                                          (FETCH (CDENTRY INFO2) OF CDENTRY)))
+                                            (TYPE (FETCH (CDINFO TYPE) OF (FETCH (CDENTRY INFO1)
+                                                                             OF CDENTRY)))
+                                            (LABELS (APPLY* (OR (LISTGET USERDATA 'LABELFN)
+                                                                (FUNCTION NILL))
+                                                           FILE1 FILE2 USERDATA))
+                                            (LABEL1 (OR (CAR LABELS)
+                                                        FILE1))
+                                            (LABEL2 (OR (CADR LABELS)
+                                                        FILE2)))
+                                           (DECLARE (SPECVARS . T))
 
                                  (* ;; "If USERDATA contains a LABELFN, then it is applied to the files and the rest of the USERDATA to produce abbreviated labels for titles and headers.")
 
-                                              (CLEARW T)
-                                              (CL:FUNCALL FN TBITEM MENUITEM CDBROWSER KEY]
-                            (FUNCTION NILL])])
+                                           (CLEARW T)
+                                           (CL:FUNCALL FN TBITEM MENUITEM CDBROWSER KEY]
+                         (FUNCTION NILL]))])
 
 (CD-MENUFN
-  [LAMBDA (TBITEM MENUITEM CDBROWSER KEY)                    (* ; "Edited 30-Dec-2021 18:21 by rmk")
-                                                             (* ; "Edited 20-Dec-2021 09:56 by rmk")
-                                                             (* ; "Edited 16-Dec-2021 13:30 by rmk")
-                                                             (* ; "Edited 13-Dec-2021 22:11 by rmk")
-                                                             (* ; "Edited 10-Dec-2021 21:42 by rmk")
-                                                             (* ; "Edited  9-Dec-2021 21:24 by rmk")
+  [LAMBDA (TBITEM MENUITEM CDBROWSER KEY)
+
+    (* ;; "Edited 25-Jan-2022 10:19 by rmk: FILELABELFN, if provided, can be used to calculate abbreviated labels for the file, for example, to strip off any long common prefixes.")
 
     (* ;; "The FILELABELFN, if provided, can be used to calculate abbreviated labels for the file, for example, to strip off any long common prefixes.")
 
     (* ;; "MENUITEM is of the form (display-atom <this function> . extrainfo).  The selector for the selectq is either the CAR of the extrainfo or the display atom.")
 
-    (SELECTQ (OR (CADDR MENUITEM)
-                 (CAR MENUITEM))
-        (Compare (IF (AND FILE1 FILE2)
-                     THEN (SELECTQ TYPE
-                              (SOURCE (CSBROWSER FILE1 FILE2 NIL LABEL1 LABEL2))
-                              (COMPILED (PRIN3 "Cannot compare compiled files" T))
-                              ((TEXT TEDIT) 
-                                            (* ;; 
+    (LET
+     (SUBWINDOWS)
+     (CL:WHEN (MEMB (OR (CADDR MENUITEM)
+                        (CAR MENUITEM))
+                    '(Compare See% right See% both See% left))
+         (FOR W IN (WINDOWPROP WINDOW 'SUBWINDOWS) WHEN (OPENWP W) DO (CLOSEW W)))
+     (SELECTQ (OR (CADDR MENUITEM)
+                  (CAR MENUITEM))
+         (Compare (IF (AND FILE1 FILE2)
+                      THEN [SETQ SUBWINDOWS
+                            (SELECTQ TYPE
+                                (SOURCE (CSBROWSER FILE1 FILE2 NIL LABEL1 LABEL2
+                                               (RELCREATEREGION
+                                                [FIXR (TIMES 0.75 (FETCH (REGION WIDTH)
+                                                                     OF (WINDOWPROP WINDOW
+                                                                               'REGION]
+                                                200
+                                                'LEFT
+                                                'TOP
+                                                `(,WINDOW 0.125)
+                                                (IPLUS (FETCH (REGION BOTTOM)
+                                                          OF (WINDOWPROP WINDOW 'REGION))
+                                                       20)
+                                                T)))
+                                (COMPILED (FLASHWINDOW T)
+                                          (PRIN3 "Cannot compare compiled files" T))
+                                ((TEXT TEDIT) 
+                                              (* ;; 
                                        "Works for TEDIT, but doesn't detect image object differences")
 
-                                   (COMPARETEXT FILE1 FILE2 'LINE NIL (LIST LABEL1 LABEL2)))
-                              (PROGN (PRIN3 "Unable to compare, showing both" T)
-                                     (TEDIT-SEE-VERSIONS FILE1 FILE2 LABEL1 LABEL2)))
-                   ELSE (PRIN3 "Only one file" T)))
-        (See% left (IF FILE1
-                       THEN (TEDIT-SEE FILE1 NIL NIL (CONCAT "SEE window for " LABEL1))
-                     ELSE (FLASHWINDOW T)
-                          (PRIN3 "No file to print" T)))
-        (See% right (IF FILE2
-                        THEN (TEDIT-SEE FILE2 NIL NIL (CONCAT "SEE window for " LABEL2))
+                                     (COMPARETEXT FILE1 FILE2 'LINE
+                                            (RELCREATEPOSITION `(,WINDOW 0.5)
+                                                   (IPLUS (FETCH (REGION BOTTOM)
+                                                             OF (WINDOWPROP WINDOW 'REGION))
+                                                          20))
+                                            (LIST LABEL1 LABEL2)))
+                                (PROGN (FLASHWINDOW T)
+                                       (PRIN3 "Unable to compare, showing both" T)
+                                       (TEDIT-SEE-VERSIONS FILE1 FILE2 LABEL1 LABEL2]
+                    ELSE (FLASHWINDOW T)
+                         (PRIN3 "Only one file" T)))
+         (See% left (IF FILE1
+                        THEN (SETQ SUBWINDOWS (TEDIT-SEE FILE1
+                                                     (RELCREATEREGION
+                                                      700 700 'RIGHT 'TOP `(,WINDOW 0.5)
+                                                      (IPLUS (FETCH (REGION BOTTOM)
+                                                                OF (WINDOWPROP WINDOW 'REGION))
+                                                             -1)
+                                                      T)
+                                                     NIL
+                                                     (CONCAT "SEE window for " LABEL1)))
                       ELSE (FLASHWINDOW T)
                            (PRIN3 "No file to print" T)))
-        (See% both (IF (AND FILE1 FILE2)
-                       THEN (EXAMINEFILES FILE1 FILE2 LABEL1 LABEL2)
-                     ELSE (PRIN3 "Only one file" T)))
-        (Copy% -> (LET [(DEST (COPYFILE FILE1 (PACKFILENAME 'VERSION NIL FILE2]
-                       (PRIN3 (CL:IF DEST
-                                  (CONCAT "Copied to " DEST)
-                                  (CONCAT FILE2 " could not be copied"))
-                              T)))
-        (Copy% <- (LET [(DEST (COPYFILE FILE2 (PACKFILENAME 'VERSION NIL FILE1]
-                       (PRIN3 (CL:IF DEST
-                                  (CONCAT "Copied to " DEST)
-                                  (CONCAT FILE1 " could not be copied"))
-                              T)))
-        (SHOULDNT])
+         (See% right (IF FILE2
+                         THEN (SETQ SUBWINDOWS (TEDIT-SEE FILE2
+                                                      (RELCREATEREGION
+                                                       700 700 'LEFT 'TOP `(,WINDOW 0.5)
+                                                       (IPLUS (FETCH (REGION BOTTOM)
+                                                                 OF (WINDOWPROP WINDOW 'REGION))
+                                                              -1)
+                                                       T)
+                                                      NIL
+                                                      (CONCAT "SEE window for " LABEL2)))
+                       ELSE (FLASHWINDOW T)
+                            (PRIN3 "No file to print" T)))
+         (See% both (IF (AND FILE1 FILE2)
+                        THEN (SETQ SUBWINDOWS (EXAMINEFILES FILE1 FILE2 LABEL1 LABEL2
+                                                     (RELCREATEREGION
+                                                      1400 700 'LEFT 'TOP `(,WINDOW 0.5 -701)
+                                                      (IPLUS (FETCH (REGION BOTTOM)
+                                                                OF (WINDOWPROP WINDOW 'REGION))
+                                                             -1)
+                                                      T)))
+                      ELSE (FLASHWINDOW T)
+                           (PRIN3 "Only one file" T)))
+         (Copy% -> (LET [(DEST (COPYFILE FILE1 (PACKFILENAME 'VERSION NIL FILE2]
+                        (PRIN3 (CL:IF DEST
+                                   (CONCAT "Copied to " DEST)
+                                   (PROGN (FLASHWINDOW T)
+                                          (CONCAT FILE2 " could not be copied")))
+                               T)))
+         (Copy% <- (LET [(DEST (COPYFILE FILE2 (PACKFILENAME 'VERSION NIL FILE1]
+                        (PRIN3 (CL:IF DEST
+                                   (CONCAT "Copied to " DEST)
+                                   (PROGN (FLASHWINDOW T)
+                                          (CONCAT FILE1 " could not be copied")))
+                               T)))
+         (SHOULDNT))
+     (FOR W INSIDE SUBWINDOWS DO (WINDOWADDPROP WINDOW 'SUBWINDOWS (WFROMDS W])
 )
 
 (RPAQQ CDTABLEBROWSER.MENUITEMS ((Compare CD-MENUFN)
@@ -1723,21 +1925,23 @@ Copyright (c) 1985-1988, 1990, 1994, 1998, 2018, 2020-2021 by Venue & Xerox Corp
 (PUTPROPS COMPAREDIRECTORIES COPYRIGHT ("Venue & Xerox Corporation" 1985 1986 1987 1988 1990 1994 1998
  2018 2020 2021))
 (DECLARE%: DONTCOPY
-  (FILEMAP (NIL (2418 17067 (COMPAREDIRECTORIES 2428 . 12186) (COMPAREDIRECTORIES.INFOS 12188 . 13867) (
-COMPAREDIRECTORIES.INFOS.TYPE 13869 . 14451) (MATCHNAME 14453 . 14983) (CD.INSURECDVALUE 14985 . 16599
-) (CD.UPDATEWIDTHS 16601 . 17065)) (17068 26728 (CDFILES 17078 . 23061) (CDFILES.MATCH 23063 . 24449) 
-(CDFILES.PATS 24451 . 26726)) (26729 41174 (CDPRINT 26739 . 29343) (CDPRINT.LINE 29345 . 31901) (
-CDPRINT.MAXWIDTHS 31903 . 36018) (CDPRINT.COLHEADERS 36020 . 36658) (CDPRINT.COLUMNS 36660 . 40539) (
-CDTEDIT 40541 . 41172)) (41175 44371 (CDMAP 41185 . 42617) (CDENTRY 42619 . 42928) (CDSUBSET 42930 . 
-44369)) (44372 51313 (BINCOMP 44382 . 48671) (EOLTYPE 48673 . 50638) (EOLTYPE.SHOW 50640 . 51311)) (
-51841 65048 (FIND-UNCOMPILED-FILES 51851 . 55494) (FIND-UNSOURCED-FILES 55496 . 58305) (
-FIND-SOURCE-FILES 58307 . 60011) (FIND-COMPILED-FILES 60013 . 62091) (FIND-UNLOADED-FILES 62093 . 
-62837) (FIND-LOADED-FILES 62839 . 63393) (FIND-MULTICOMPILED-FILES 63395 . 65046)) (65049 73251 (
-CREATED-AS 65059 . 69856) (SOURCE-FOR-COMPILED-P 69858 . 72556) (COMPILE-SOURCE-DATE-DIFF 72558 . 
-73249)) (73252 83558 (FIX-DIRECTORY-DATES 73262 . 76255) (FIX-EQUIV-DATES 76257 . 77782) (
-COPY-COMPARED-FILES 77784 . 79605) (COPY-MISSING-FILES 79607 . 81764) (COMPILED-ON-SAME-SOURCE 81766
- . 83556)) (83752 91440 (CDBROWSER 83762 . 88335) (CDBROWSER.STRINGS 88337 . 91438)) (91602 92874 (
-CD.TABLEITEM 91612 . 91832) (CD.TABLEITEM.PRINTFN 91834 . 92033) (CD.TABLEITEM.COPYFN 92035 . 92629) (
-CDTABLEBROWSER.HEADING.REPAINTFN 92631 . 92872)) (92875 100220 (CDTABLEBROWSER.WHENSELECTEDFN 92885 . 
-93353) (CD.COMMANDSELECTEDFN 93355 . 97161) (CD-MENUFN 97163 . 100218)))))
+  (FILEMAP (NIL (2497 19012 (COMPAREDIRECTORIES 2507 . 8956) (COMPAREDIRECTORIES.INFOS 8958 . 11078) (
+CDENTRIES.SELECT 11080 . 15766) (COMPAREDIRECTORIES.INFOS.TYPE 15768 . 16396) (MATCHNAME 16398 . 16928
+) (CD.INSURECDVALUE 16930 . 18544) (CD.UPDATEWIDTHS 18546 . 19010)) (19013 29285 (CDFILES 19023 . 
+25379) (CDFILES.MATCH 25381 . 27006) (CDFILES.PATS 27008 . 29283)) (29286 44371 (CDPRINT 29296 . 31641
+) (CDPRINT.HEADER 31643 . 32540) (CDPRINT.LINE 32542 . 35098) (CDPRINT.MAXWIDTHS 35100 . 39215) (
+CDPRINT.COLHEADERS 39217 . 39855) (CDPRINT.COLUMNS 39857 . 43736) (CDTEDIT 43738 . 44369)) (44372 
+52741 (CDMAP 44382 . 45814) (CDENTRY 45816 . 46125) (CDSUBSET 46127 . 47566) (CDMERGE 47568 . 51422) (
+CDMERGE.COMMON 51424 . 52739)) (52742 60280 (BINCOMP 52752 . 57041) (EOLTYPE 57043 . 59605) (
+EOLTYPE.SHOW 59607 . 60278)) (60808 74015 (FIND-UNCOMPILED-FILES 60818 . 64461) (FIND-UNSOURCED-FILES 
+64463 . 67272) (FIND-SOURCE-FILES 67274 . 68978) (FIND-COMPILED-FILES 68980 . 71058) (
+FIND-UNLOADED-FILES 71060 . 71804) (FIND-LOADED-FILES 71806 . 72360) (FIND-MULTICOMPILED-FILES 72362
+ . 74013)) (74016 82218 (CREATED-AS 74026 . 78823) (SOURCE-FOR-COMPILED-P 78825 . 81523) (
+COMPILE-SOURCE-DATE-DIFF 81525 . 82216)) (82219 92525 (FIX-DIRECTORY-DATES 82229 . 85222) (
+FIX-EQUIV-DATES 85224 . 86749) (COPY-COMPARED-FILES 86751 . 88572) (COPY-MISSING-FILES 88574 . 90731) 
+(COMPILED-ON-SAME-SOURCE 90733 . 92523)) (92719 100458 (CDBROWSER 92729 . 97353) (CDBROWSER.STRINGS 
+97355 . 100456)) (100620 101892 (CD.TABLEITEM 100630 . 100850) (CD.TABLEITEM.PRINTFN 100852 . 101051) 
+(CD.TABLEITEM.COPYFN 101053 . 101647) (CDTABLEBROWSER.HEADING.REPAINTFN 101649 . 101890)) (101893 
+112086 (CDTABLEBROWSER.WHENSELECTEDFN 101903 . 102371) (CD.COMMANDSELECTEDFN 102373 . 105764) (
+CD-MENUFN 105766 . 112084)))))
 STOP
diff --git a/lispusers/COMPAREDIRECTORIES.LCOM b/lispusers/COMPAREDIRECTORIES.LCOM
index 05661b70..3abba64c 100644
Binary files a/lispusers/COMPAREDIRECTORIES.LCOM and b/lispusers/COMPAREDIRECTORIES.LCOM differ
diff --git a/lispusers/COMPAREDIRECTORIES.TEDIT b/lispusers/COMPAREDIRECTORIES.TEDIT
index eb01c6c3..8915d21d 100644
--- a/lispusers/COMPAREDIRECTORIES.TEDIT
+++ b/lispusers/COMPAREDIRECTORIES.TEDIT
@@ -6,7 +6,8 @@ XEROX	COMPAREDIRECTORIES2
 
By:  Larry Masinter and Ron Kaplan
This document edited on
  December 2, 1987
  December 28, 1998 (Ron Kaplan)
  April 7, 2018 (Ron Kaplan)
  Rewritten December, 2021 (Ron Kaplan)

COMPAREDIRECTORIES compares the contents of two directories, identifying files according to their creation dates and lengths. It is called using the function
(COMPAREDIRECTORIES DIR1 DIR2 SELECT INCLUDEDFILES EXCLUDEDFILES  USEDIRECTORYDATES OUTPUTFILE ALLVERSIONS)    [Function]
Compares the creation dates of files with matching names in the lists that CDFILES returns for DIR1 and DIR2.  Collects or prints CDENTRIES for those files that meet the SELECT criteria.  May also collect or print entries for relevant files that exist in DIR1 or DIR2 but not both.
 SELECT specifies which the match/mismatch criteria for filtering the output. If SELECT is or contains
     AFTER or >:  select entries where file1 has a later date than  file2
     BEFORE or <: select entries where file1 has an earlier date than file2
     SAMEDATE or =: select entries where file1 and file2 have the same date
     -*: exclude entries where file1 does not exist
     *-: exclude entries where file2 does not exist
     ~=: exclude entries where file1 and file2 are byte-equivalent
SELECT = NIL is equivalent to (< >  -* *-). Excludes files with matching dates, a useful default for identifying files that may require further attention.
SELECT = T is equivalent to (= < >  -* *-).  Includes all files for processing by other functions or later filtering by CDSUBSET (below).
SELECT may also contain the token AUTHOR to indicate that authors should be provided in the printed output (see CDPRINT below).
Unless USEDIRECTORYDATES, the FILECREATED date is used for the date comparison of Lisp source and compiled files, otherwise the file-system CREATIONDATE is used. 
If OUTPUTFILE=NIL, then the value is a CDVALUE structure with fields (CDPARAMETERS . CDENTRIES). CDPARAMETERS records the parameters in the call to COMPAREDIRECTORIES and CDENTRIES is the list of per-file comparison results.  CDPARAMETERS has fields 
          CDDIR1 CDDIR2 CDCOMPAREDATE CDSELECT.
-CDENTRIES contains one entry for each of the file-comparisons that meets the SELECT criteria.  Each entry is a CDENTRY record with fields
   MATCHNAME INFO1 DATERULE INFO2 EQUIV
where MATCHNAME is the name.extension shared by the two files, and each file info is either NIL (for nonexistent files)  or a CDINFO record with fields
   (FULLNAME DATE LENGTH AUTHOR TYPE EOL)
TYPE is SOURCE for Lisp source (filecreated) files, COMPILED for Lisp compiled files, otherwise the PRINTFILETYPE (TEXT, TEDIT...) or NIL.  EOL is CR, LF, CRLF, or NIL.
When both files exist, the date relation is one of <, =, or >.  Otherwise, the date relation is * if only one file exists.  EQUIV is EQUIVALENT for files with different dates but exactly the same bytes, otherwise NIL.
If OUTPUTFILE is not NIL, then it is a filename or open stream on which selected entries will be printed (T for the terminal) by CDPRINT.  
COMPAREDIRECTORIES always sets the variable LASTCDVALUE to the CDVALUE data structure.  This is used by the functions below if their CDENTRIES is NIL. 

(CDPRINT CDVALUE FILE COLHEADINGS PRINTAUTHOR )  [Function]
Prints CDVALUE on FILE, with one line for each entry. The line for each entry is of the form
     FILE1 (AUTHOR) SIZE DATE DATEREL DATE  FILE2 (AUTHOR) SIZE
For example
ACE.;1 (Joe) 235 2-May-1985 18:03:54 < 30-Sep-1985 11:14:48 ACE.;3 (Sam) 396
The line for byte-equivalent files is prefixed with ==.  If the files are equivalent except for a difference in end-of-line conventions, the equivalence prefix will indicate the convention for each file (C for CR, L, for LF, 2 for CRLF). Thus C2 indicates that the files are equivalent except that file1 marks line ends with CR and file2 with CRLF.
+CDENTRIES contains one entry for each of the file-comparisons that meets the SELECT criteria.  Each entry is a CDENTRY record with fields
   MATCHNAME INFO1 DATERULE INFO2 EQUIV
where MATCHNAME is the name.extension shared by the two files, and each file info is either NIL (for nonexistent files)  or a CDINFO record with fields
   (FULLNAME DATE LENGTH AUTHOR TYPE EOL)
TYPE is SOURCE for Lisp source (filecreated) files, COMPILED for Lisp compiled files, otherwise the PRINTFILETYPE (TEXT, TEDIT...) or NIL.  EOL is CR, LF, CRLF, or NIL.
When both files exist, the date relation is one of <, =, or >.  Otherwise, the date relation is * if only one file exists.
+EQUIV is T for files that contain the same bytes. In that case, the date of the earlier file is assumed to be more accurate, it replaces the CREATIONDATE of the earlier file, and the date relation is changed to =.
If OUTPUTFILE is not NIL, then it is a filename or open stream on which selected entries will be printed (T for the terminal) by CDPRINT.  
COMPAREDIRECTORIES always sets the variable LASTCDVALUE to the CDVALUE data structure.  This is used by the functions below if their CDENTRIES is NIL. 

(CDPRINT CDVALUE FILE COLHEADINGS PRINTAUTHOR )  [Function]
Prints CDVALUE on FILE, with one line for each entry. The line for each entry is of the form
     FILE1 (AUTHOR) SIZE DATE DATEREL DATE  FILE2 (AUTHOR) SIZE
For example
ACE.;1 (Joe) 235 2-May-1985 18:03:54 < 30-Sep-1985 11:14:48 ACE.;3 (Sam) 396
The line for byte-equivalent files is prefixed with ==.  If the files are equivalent except for a difference in end-of-line conventions, the equivalence prefix will indicate the convention for each file (C for CR, L, for LF, 2 for CRLF). Thus C2 indicates that the files are equivalent except that file1 marks line ends with CR and file2 with CRLF.
 COLHEADINGS can be a pair (col1 col2) of strings to be printed as column headings.
Note that because COMPAREDIRECTORIES sets LASTCDVALUE, evaluating (CDPRINT) after COMPAREDIRECTORIES prints the results of the last comparision. 
For conciseness, authors are included only if PRINTAUTHOR or if AUTHOR is included in the CDSELECT parameter of CDVALUE. Also, redundant file-name hosts/directories are not printed. 
 
 (CDTEDIT CDVALUE TITLE COLHEADINGS PRINTAUTHOR)      [Function]
@@ -14,7 +15,9 @@ Produces the CDPRINT output in a read-only TEDIT window, with TITLE if given.
 
 (CDBROWSER CDVALUE TITLE COLHEADINGS BROWSERPROPS SEPARATEDIRECTIONS MENUITEMS PRINTAUTHOR)       [Function]
 Produce the CDPRINT output in a TABLEBROWSER window with menu commands for comparing the contents of individual files, viewing files in read-only TEDIT windows, copying files from one directory to another, etc.  Lisp source files are compared with COMPARESOURCES, text files with COMPARETEXT. If SEPARATEDIRECTIONS, the entry lines are grouped according to whether the date relation is < or >.
-(CDFILES DIR INCLUDEDFILES EXCLUDEDFILES ALLVERSIONS DEPTH)  [Function]
Returns a list of full filenames for files in directory DIR (NIL=T=the connected directory) that match the other file-name filtering criteria. Files are excluded if:
Their name does not match a pattern in INCLUDEDFILES (NIL = *.*). Dotted files are excluded unless FILEPATTERNS includes .* and files in subdirectories are excluded if the number of subdirectories exceeds DEPTH  (below).
They do not match patterns on the list EXCLUDEDFILES. *.* excludes all extensions, *.COM or just COM excludes extentsions on *COMPILED-EXTENSIONS*. EXCLUDEDFILES contains .* to suppress dotted files unless .* also appears in INCLUDEDFILES.
They are not the highest version unless ALLVERSIONS=T.
DEPTH controls the depth of subdirectory exploration.  T means all levels, NIL means no subdirectories.  Otherwise the maximum number of > or / characters below the starting DIR in the fullname of files.
(CDFILES) produces all the newest, undotted files in the immediate connected directory.

(CDMAP CDVALUE FN)  [Function]
(CDSUBSET CDVALUE FN)  [Function]
CDMAP applies FN to each CDENTRY in CDVALUE. CDSUBSET applies FN and also returns the subset of the entries for which FN is non-NIL and preserves in the value the parameters of CDVALUE. For convenience, at each invocation the variables MATCHNAME INFO1 DATEREL INFO2 and EQUIV are bound to the corresponding fields and can be used freely by FN.

USEFUL UTILITIES
(FIX-DIRECTORY-DATES FILES) [Function]
For every file included in or specified by FILES, if it is a Lisp source or compiled whose directory creation date is more than 30 seconds later than its internal filecreated date (presumably because of copying), then its directory date is reset to match the internal date.  FILES can be a list of file names or a pattern interpretable by FILDIR.  Returns a list of files whose dates have been changed.

(FIX-EQUIV-DATES CDVALUE)  [Function]
If there is an entry in CDVALUE whose files are EQUIVALENT but with different directory creation dates, the directory date of the file with the later date (presumably a copy) is reset to match the date of the earlier file.  In the end all equivalent files will have the same (earliest) date. Returns a list of files whose dates have been changed.

(COPY-MISSING-FILES CDVALUE TARGET MATCHNAMES)   [Function]
Target is 1 or 2, indicating the direction of potential copies.  If an entry with a source file but no target file has a matchname in MATCHNAMES, the source file is copied to the target directory.  All target-absent files are copied if MATCNAMES is NIL.  Source properties (including version number) are preserved in the target.

(COPY-COMPARED-FILES CDVALUE TARGET MATCHNAMES)   [Function]
TARGET is 1 or 2, indicating the direction of potential copies.  If an entry with both source and target files has a matchname in MATCHNAMES, the source file is copied to a new version of the target file.  All files are copied if MATCHNAMES is NIL.  

(COMPILED-ON-SAME-SOURCE CDVALUE)  [Function]
Returns the subset of entries with Lisp compiled files (dfasl or lcom) that are compiled on the same source, according to SOURCE-FOR-COMPILED-P below. Presumably one should be removed to avoid confusion.

(FIND-SOURCE-FILES CFILES SDIRS DFASLMARGIN)   [Function]
Returns (CFILE . SFILES) pairs where CFILE is a Lisp compiled file in CFILES and SFILES is list of files in SDIRS that CFILE was compiled on according to SOURCE-FOR-COMPILED-P. This suggests that at least one of SFILES should be copied to CFILE's location (or vice versa).

(FIND-COMPILED-FILES SFILES CDIRS DFASLMARGIN)   [Function]
Returns (CFILE . SFILES) pairs where SFILE is a Lisp source file in SFILES and CFILES are files in CDIRS that are compiled on SFILE according to SOURCE-FOR-COMPILED-P.  This suggests that at least one of CFILES should be copied to SFILE's location.  

(FIND-UNCOMPILED-FILES FILES DFASLMARGIN COMPILEXTS)  [Function]
Returns a list of elements each of which corresponds to a source file in FILES for which no appropriate compiled file can be found.   An appropriate compiled file is a file in the same location with extension in COMPILEEXTS (defaulting to *COMPILED-EXTENSIONS*) that satisfies SOURCE-FOR-COMPILED-P. Each element is a list of the form
    (sourcefile . cfiles)
cfiles contains compiled files that were compiled on a different version of sourcefile, NIL if no such files exist. Each cfile item is a pair (cfile  timediff) where timediff is the time difference (in minutes) between the creation date of the compiled-file's source and the creation date of sourcefile (positive if the cfile was compiled later, as should be the case). FILES can be an explicit list of files, or a file specification interpretable by FILDIR; in that case only the newest source-file versions are processed.  

(FIND-UNSOURCED-FILES CFILES DFASLMARGIN COMPILEXTS)  [Function]
Returns the subset of the compiled files specified by CFILES for which a corresponding source file according to SOURCE-FOR-COMPILED-P cannot be found in the same directory.  CFILES can be a list of files or a pattern that FILDIR can interpret.  COMPILEEXTS can be one or more explicit compile-file extensions, defaulting to *COMPILED-EXTENSIONS*.

(SOURCE-FOR-COMPILED-P SOURCE COMPILED DFASLMARGIN)  [Function]
Returns T if it can confirm that Lisp COMPILED file was compiled on Lisp SOURCE file.  SOURCE and COMPILED can be provided as CREATED-AS values, to avoid repetitive computation.  This compares the information in the filecreated expressions, original file names and original dates, and not the current directory names and dates.
It appears that the times in DFASL files may differ from the filecreated source dates by a few minutes.  The DFASLMARGIN can be provided to loosen up the date matching criterion.  DFASLMARGIN is a pair (max min) and a DFASL COMPILED is deemed to be compiled on SOURCE if the compiled's source date is no more than max and no less than min minutes after the source date.  A negative min allows for the possibility that the compiled-source date is earlier than the candidate source date.  DFASLMARGIN defaults to (20 0).  A single positive number x is coerced to (x 0).  A single negative number is coerced to (-x x) (compiled file is no more than x minutes later or earlier). T is infinity in either direction.  Examples:
 (T 0):  COMPILED compiled on source later than SOURCE
 (0 T):  COMPILED compiled on source earlier than SOURCE (odd)
+(CDFILES DIR INCLUDEDFILES EXCLUDEDFILES ALLVERSIONS DEPTH)  [Function]
Returns a list of full filenames for files in directory DIR (NIL=T=the connected directory) that match the other file-name filtering criteria. Files are excluded if:
Their name does not match a pattern in INCLUDEDFILES (NIL = *.*). Dotted files are excluded unless FILEPATTERNS includes .* and files in subdirectories are excluded if the number of subdirectories exceeds DEPTH  (below).
They do not match patterns on the list EXCLUDEDFILES. *.* excludes all extensions, *.COM or just COM excludes extentsions on *COMPILED-EXTENSIONS*. EXCLUDEDFILES contains .* to suppress dotted files unless .* also appears in INCLUDEDFILES.
They are not the highest version unless ALLVERSIONS=T.
DEPTH controls the depth of subdirectory exploration.  T means all levels, NIL means no subdirectories.  Otherwise the maximum number of > or / characters below the starting DIR in the fullname of files.
(CDFILES) produces all the newest, undotted files in the immediate connected directory.
(CDMERGE CDVALUES)  [Function]
+Merges all subsets of CDVALUES that have the same CDSELECT into a single CDVALUE with the union of their CDENTRIES.  The CDCOMPAREDATE of the merger will be the latest of the dates, and the directories and match names will be adjusted to reflect the original subdirectory sources.
+
(CDMAP CDVALUE FN)  [Function]
(CDSUBSET CDVALUE FN)  [Function]
CDMAP applies FN to each CDENTRY in CDVALUE. CDSUBSET applies FN and also returns the subset of the entries for which FN is non-NIL and preserves in the value the parameters of CDVALUE. For convenience, at each invocation the variables MATCHNAME INFO1 DATEREL INFO2 and EQUIV are bound to the corresponding fields and can be used freely by FN.

USEFUL UTILITIES
(FIX-DIRECTORY-DATES FILES) [Function]
For every file included in or specified by FILES, if it is a Lisp source or compiled whose directory creation date is more than 30 seconds later than its internal filecreated date (presumably because of copying), then its directory date is reset to match the internal date.  FILES can be a list of file names or a pattern interpretable by FILDIR.  Returns a list of files whose dates have been changed.

(FIX-EQUIV-DATES CDVALUE)  [Function]
If there is an entry in CDVALUE whose files are EQUIVALENT but with different directory creation dates, the directory date of the file with the later date (presumably a copy) is reset to match the date of the earlier file.  In the end all equivalent files will have the same (earliest) date. Returns a list of files whose dates have been changed.

(COPY-MISSING-FILES CDVALUE TARGET MATCHNAMES)   [Function]
Target is 1 or 2, indicating the direction of potential copies.  If an entry with a source file but no target file has a matchname in MATCHNAMES, the source file is copied to the target directory.  All target-absent files are copied if MATCNAMES is NIL.  Source properties (including version number) are preserved in the target.

(COPY-COMPARED-FILES CDVALUE TARGET MATCHNAMES)   [Function]
TARGET is 1 or 2, indicating the direction of potential copies.  If an entry with both source and target files has a matchname in MATCHNAMES, the source file is copied to a new version of the target file.  All files are copied if MATCHNAMES is NIL.  

(COMPILED-ON-SAME-SOURCE CDVALUE)  [Function]
Returns the subset of entries with Lisp compiled files (dfasl or lcom) that are compiled on the same source, according to SOURCE-FOR-COMPILED-P below. Presumably one should be removed to avoid confusion.

(FIND-SOURCE-FILES CFILES SDIRS DFASLMARGIN)   [Function]
Returns (CFILE . SFILES) pairs where CFILE is a Lisp compiled file in CFILES and SFILES is list of files in SDIRS that CFILE was compiled on according to SOURCE-FOR-COMPILED-P. This suggests that at least one of SFILES should be copied to CFILE's location (or vice versa).

(FIND-COMPILED-FILES SFILES CDIRS DFASLMARGIN)   [Function]
Returns (CFILE . SFILES) pairs where SFILE is a Lisp source file in SFILES and CFILES are files in CDIRS that are compiled on SFILE according to SOURCE-FOR-COMPILED-P.  This suggests that at least one of CFILES should be copied to SFILE's location.  

(FIND-UNCOMPILED-FILES FILES DFASLMARGIN COMPILEXTS)  [Function]
Returns a list of elements each of which corresponds to a source file in FILES for which no appropriate compiled file can be found.   An appropriate compiled file is a file in the same location with extension in COMPILEEXTS (defaulting to *COMPILED-EXTENSIONS*) that satisfies SOURCE-FOR-COMPILED-P. Each element is a list of the form
    (sourcefile . cfiles)
cfiles contains compiled files that were compiled on a different version of sourcefile, NIL if no such files exist. Each cfile item is a pair (cfile  timediff) where timediff is the time difference (in minutes) between the creation date of the compiled-file's source and the creation date of sourcefile (positive if the cfile was compiled later, as should be the case). FILES can be an explicit list of files, or a file specification interpretable by FILDIR; in that case only the newest source-file versions are processed.  

(FIND-UNSOURCED-FILES CFILES DFASLMARGIN COMPILEXTS)  [Function]
Returns the subset of the compiled files specified by CFILES for which a corresponding source file according to SOURCE-FOR-COMPILED-P cannot be found in the same directory.  CFILES can be a list of files or a pattern that FILDIR can interpret.  COMPILEEXTS can be one or more explicit compile-file extensions, defaulting to *COMPILED-EXTENSIONS*.

(SOURCE-FOR-COMPILED-P SOURCE COMPILED DFASLMARGIN)  [Function]
Returns T if it can confirm that Lisp COMPILED file was compiled on Lisp SOURCE file.  SOURCE and COMPILED can be provided as CREATED-AS values, to avoid repetitive computation.  This compares the information in the filecreated expressions, original file names and original dates, and not the current directory names and dates.
It appears that the times in DFASL files may differ from the filecreated source dates by a few minutes.  The DFASLMARGIN can be provided to loosen up the date matching criterion.  DFASLMARGIN is a pair (max min) and a DFASL COMPILED is deemed to be compiled on SOURCE if the compiled's source date is no more than max and no less than min minutes after the source date.  A negative min allows for the possibility that the compiled-source date is earlier than the candidate source date.  DFASLMARGIN defaults to (20 0).  A single positive number x is coerced to (x 0).  A single negative number is coerced to (-x x) (compiled file is no more than x minutes later or earlier). T is infinity in either direction.  Examples:
 (T 0):  COMPILED compiled on source later than SOURCE
 (0 T):  COMPILED compiled on source earlier than SOURCE (odd)
  12:   COMPILED compiled on source later than SOURCE by no more than 12 minutes  -12:     COMPILED compiled on source 12 minutes before or after SOURCE

(FIND-MULTICOMPILED-FILES FILES SHOWINFO)  [Function]
Returns a list of files in FILES that have more than one type of compiled file (e.g. LCOM and DFASL).  FILES is interpretable by FILDIR.  If SHOWINFO, then the value contains a list for each file of the form
   ÿÿï!ÿ(rootname loaded-version . CREATED-AS information for each compile-type)
 Otherwise just the rootname of the source is returns.

(CREATED-AS FILE)  [Function]
If FILE is a Lisp source or compiled file, returns a record of its original filename and filecreated dates, and for compiled files, also the original compiled-on name and date.  The return for a source file is a pair
     (sfullname sfilecreateddate)
The return for a compiled file is a quadruple
     (cfullname cfilecreated sfullname sfilecreateddate)
where sfullname and sourcefilecreated are extracted from the file's compiled-on information.  The return is (fullname NIL) for a non-Lisp file.

(EOLTYPE FILE SHOWCONTEXT)  [Function]
Returns the EOLTYPE of FILE  (CR, LF, CRLF) if the type is unmistakable: contains at least one instance of one type and no instances of any others.  Returns NIL if there is evidence of inconsistent types.  If SHOWCONTEXT is an integer, it is the number of bytes for EOLTYPE to display before and after an instance of an inconsistent type.  At each instance, the user is asked whether to continue scanning for other instances.  SHOWCONTEXT = T is interpreted as 100.

(BINCOMP FILE1 FILE2 EOLDIFFOK)   [Function]
Returns T if FILE1 and FILE2 are byte-identical.  If EOLDIFFOK and FILE1 and FILE2 differ only in their eol conventions, the value is a list of the form (EOL1 EOL2), e.g. (CR CRLF).  Otherwise the value is NIL.  



	



(LIST ((PAGE NIL (PAPERSIZE Letter FOLIOINFO (ARABIC) STARTINGPAGE# 1) (0 0 612 792) ((FOLIO NIL (PARALOOKS (QUAD CENTERED) CHARLOOKS (SUPERSCRIPT 0 INVISIBLE OFF SELECTPOINT OFF PROTECTED OFF SIZE 10 FAMILY MODERN OVERLINE OFF STRIKEOUT OFF UNDERLINE OFF EXPANSION REGULAR SLOPE REGULAR WEIGHT MEDIUM INVERTED OFF USERINFO NIL STYLE NIL) FORMATINFO (ARABIC)) (174 36 288 36) NIL) (HEADING NIL (HEADINGTYPE RUNNINGHEAD) (84 744 528 36) NIL) (TEXT NIL NIL (84 96 456 600) NIL))) (PAGE NIL (PAPERSIZE Letter FOLIOINFO (ARABIC)) (0 0 612 792) ((FOLIO NIL (PARALOOKS (QUAD CENTERED) CHARLOOKS (SUPERSCRIPT 0 INVISIBLE OFF SELECTPOINT OFF PROTECTED OFF SIZE 10 FAMILY MODERN OVERLINE OFF STRIKEOUT OFF UNDERLINE OFF EXPANSION REGULAR SLOPE REGULAR WEIGHT MEDIUM INVERTED OFF USERINFO NIL STYLE NIL) FORMATINFO (ARABIC)) (174 36 288 36) NIL) (HEADING NIL (HEADINGTYPE RUNNINGHEAD) (84 744 528 36) NIL) (TEXT NIL NIL (84 96 456 600) NIL))) (PAGE NIL (PAPERSIZE Letter FOLIOINFO (ARABIC)) (0 0 612 792) ((FOLIO NIL (PARALOOKS (QUAD CENTERED) CHARLOOKS (SUPERSCRIPT 0 INVISIBLE OFF SELECTPOINT OFF PROTECTED OFF SIZE 10 FAMILY MODERN OVERLINE OFF STRIKEOUT OFF UNDERLINE OFF EXPANSION REGULAR SLOPE REGULAR WEIGHT MEDIUM INVERTED OFF USERINFO NIL STYLE NIL) FORMATINFO (ARABIC)) (174 36 288 36) NIL) (HEADING NIL (HEADINGTYPE RUNNINGHEAD) (84 744 528 36) NIL) (TEXT NIL NIL (84 96 456 600) NIL)))))4ÈÈ4ÈÈ4ÈÈ4ÈÈ.4@È4ÈÈ.È.ŠŠ8.ŠŠ8JÈÈPAGEHEADINGRUNNINGHEAD.MODERNTERMINALMODERN
 TERMINAL
 MODERNMODERN
@@ -26,13 +29,13 @@ Produce the CDPRINT output in a TABLEBROWSER window with menu commands for compa
 HRULE.GETFNMODERN
 		HRULE.GETFNMODERN
 HRULE.GETFNMODERN#!'ŒoK
	Of@A?44C�m
-H	c'	.
	$	D(	o*&mÚ
+H	c'	.
	$	D(	o*&m{ˆ=
 ~?	
 <G@L].
	..@@
*m
ÌH=8k'
/^'
	

-!
(Ì	O"	 F4A'+c&
+!
(Ì	O"	 F4A'+c&
 !<†
 \	T=|
 Z
 .z=:
%<
&AI†%A64)*D@&
 ÀK<Üß		!&/65;
-$7Ù".9�'§.š-
	G"3öYzº
\ No newline at end of file
+$7Ù".9�'§.š-
	G"5¥czº
\ No newline at end of file
diff --git a/lispusers/COMPARESOURCES b/lispusers/COMPARESOURCES
index 7dfdcaf6..dc3e06a8 100644
--- a/lispusers/COMPARESOURCES
+++ b/lispusers/COMPARESOURCES
@@ -1,13 +1,10 @@
 (DEFINE-FILE-INFO PACKAGE "INTERLISP" READTABLE "INTERLISP" BASE 10)
 
-(FILECREATED " 3-Jan-2022 08:40:38" 
-{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>COMPARESOURCES.;106 42666  
+(FILECREATED "25-Jan-2022 16:05:14" {MM}<lispusers>COMPARESOURCES.;115 41781  
 
-      :CHANGES-TO (FNS CSOBJ.BUTTONEVENTINFN CSOBJ.COPYBUTTONEVENTINFN)
-                  (VARS COMPARESOURCESCOMS)
+      :CHANGES-TO (FNS CSOBJ.BUTTONEVENTINFN)
 
-      :PREVIOUS-DATE "27-Dec-2021 11:56:48" 
-{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>COMPARESOURCES.;105)
+      :PREVIOUS-DATE "24-Jan-2022 23:12:17" {MM}<lispusers>COMPARESOURCES.;113)
 
 
 (* ; "
@@ -143,15 +140,17 @@ Copyright (c) 1985-1988, 2018, 2020-2021 by Xerox Corporation.
                       'SAME])
 
 (\CS.COMPARE.MASTERS
-  [LAMBDA (BODYX BODYY DW?)                                  (* ; "Edited 19-Dec-2021 21:05 by rmk")
-                                                             (* ; "Edited  9-Dec-2021 23:26 by rmk")
-                                                             (* ; "Edited  4-Dec-2021 10:00 by rmk")
-                                                             (* ; "Edited  2-Dec-2021 14:25 by rmk:")
-                                                             (* ; "Edited 27-Nov-2021 12:31 by rmk:")
+  [LAMBDA (BODYX BODYY DW?)                                  (* ; "Edited 18-Jan-2022 22:00 by rmk")
+                                                             (* ; "Edited 19-Dec-2021 21:05 by rmk")
                                                              (* ; "Edited  5-Sep-2020 19:01 by rmk:")
                                                              (* ; "Edited 15-Apr-88 14:41 by bvm")
     (DECLARE (USEDFREE DIFFERENCES COMPARESTREAM))
     (LET (YTHING XTHING PRED DIFS TMP)
+         (SETQ BODYX (CL:REMOVE-IF (FUNCTION EDITDATE?)
+                            BODYX))                          (* ; 
+                                                             "We don't care about editdate comments")
+         (SETQ BODYY (CL:REMOVE-IF (FUNCTION EDITDATE?)
+                            BODYY))
          (SETQ BODYX (\CS.FIXFNS BODYX))
          (SETQ BODYY (\CS.FIXFNS BODYY))
          (CL:WHEN (AND (SETQ XTHING (ASSOC 'DEFINE-FILE-INFO BODYX))
@@ -555,50 +554,52 @@ Copyright (c) 1985-1988, 2018, 2020-2021 by Xerox Corporation.
                  ELSE (ADD LINELENGTH (CHARWIDTH C FONT])
 
 (CSOBJ.BUTTONEVENTINFN
-  [LAMBDA (OBJ WINDOW)                                       (* ; "Edited 26-Dec-2021 16:28 by rmk")
-                                                             (* ; "Edited 24-Dec-2021 14:09 by rmk")
-                                                             (* ; "Edited 20-Dec-2021 11:01 by rmk")
-                                                             (* ; "Edited 12-Dec-2021 21:30 by rmk")
-                                                             (* ; "Edited 10-Dec-2021 10:21 by rmk")
-                                                             (* ; "Edited  7-Dec-2021 17:49 by rmk")
-                                                             (* ; "Edited  4-Dec-2021 20:05 by rmk")
+  [LAMBDA (OBJ WINDOW)                                       (* ; "Edited 25-Jan-2022 16:04 by rmk")
+                                                             (* ; "Edited 23-Jan-2022 18:11 by rmk")
     (LET
      [(COMPAREDATA (IMAGEOBJPROP OBJ 'COMPAREDATA]
      (CL:WHEN (AND COMPAREDATA (MOUSESTATE LEFT)
                    (UNTILMOUSESTATE (NOT LEFT)))
-         [LET ((NAME (POP COMPAREDATA))
-               (TYPE (POP COMPAREDATA))
-               (DEF1 (POP COMPAREDATA))
-               (DEF2 (POP COMPAREDATA))
-               (TITLE1 (POP COMPAREDATA))
-               (TITLE2 (CAR COMPAREDATA)))
+         (LET
+          ((NAME (POP COMPAREDATA))
+           (TYPE (POP COMPAREDATA))
+           (DEF1 (POP COMPAREDATA))
+           (DEF2 (POP COMPAREDATA))
+           (TITLE1 (POP COMPAREDATA))
+           (TITLE2 (CAR COMPAREDATA)))
 
-              (* ;; "Move the cursor to just slightly below the current object, so that the edit windows are well aligned. We have to figure out the bottom of the current object, in screen coordinates.")
+          (* ;; "Move the cursor to just slightly below the current object, so that the edit windows are well aligned. We have to figure out the bottom of the current object, in screen coordinates.")
 
-              [LET ((OBJREGION (OBJ.FIND.REGION WINDOW OBJ)))
-                   (\CURSORPOSITION (IPLUS 20 LASTMOUSEX)
-                          (IPLUS (IDIFFERENCE (FETCH (REGION BOTTOM) OF (OBJ.FIND.REGION WINDOW OBJ))
-                                        (FETCH (REGION HEIGHT)
-                                               OBJREGION))
-                                 (FETCH (REGION TOP) OF (WINDOWREGION WINDOW]
-              (IF (IMAGEOBJPROP OBJ 'ONLYONE)
-                  THEN [SEDIT:SEDIT
-                        (OR DEF1 DEF2)
-                        `(:REGION ,(RELGETREGION 600 (CL:IF (ILESSP (COUNT (OR DEF1 DEF2))
-                                                                   100)
-                                                         150
-                                                         400)
-                                          'LEFT
-                                          'TOP NIL NIL T]
-                ELSE                                         (* ; "Spread the arguments")
-                     (EXAMINEDEFS NAME TYPE DEF1 DEF2 TITLE1 TITLE2
-                            (RELGETREGION 800 (CL:IF (ILESSP (IMAX (COUNT DEF1)
-                                                                   (COUNT DEF2))
-                                                            100)
-                                                  150
-                                                  400)
-                                   'LEFT
-                                   'TOP NIL NIL T])])
+          [LET ((OBJREGION (OBJ.FIND.REGION WINDOW OBJ)))
+               (\CURSORPOSITION (IPLUS 20 LASTMOUSEX)
+                      (IPLUS (IDIFFERENCE (FETCH (REGION BOTTOM) OF OBJREGION)
+                                    (FETCH (REGION HEIGHT) OF OBJREGION))
+                             (FETCH (REGION TOP) OF (WINDOWREGION WINDOW]
+          (LET
+           [EWINDOW (RELPOS (RELCREATEPOSITION `(,WINDOW 0.5)
+                                   `(,WINDOW 0 -2]
+           (CL:WHEN [WINDOWP (SETQ EWINDOW (WINDOWPROP WINDOW 'EXAMINEWINDOW]
+                  (CLOSEW EWINDOW))
+           (SETQ EWINDOW
+            (IF (IMAGEOBJPROP OBJ 'ONLYONE)
+                THEN
+                [SEDIT:GET-WINDOW
+                 (SEDIT:SEDIT (OR DEF1 DEF2)
+                        `(:REGION ,(RELCREATEREGION 600 (CL:IF (ILESSP (COUNT (OR DEF1 DEF2))
+                                                                      100)
+                                                            150
+                                                            400)
+                                          (CL:IF DEF1
+                                              'RIGHT
+                                              'LEFT)
+                                          'TOP RELPOS NIL T]
+              ELSE                                           (* ; "Spread the arguments")
+                   (EXAMINEDEFS NAME TYPE DEF1 DEF2 TITLE1 TITLE2 RELPOS)))
+           (WINDOWPROP WINDOW 'EXAMINEWINDOW EWINDOW)
+           (WINDOWADDPROP WINDOW 'CLOSEFN [FUNCTION (LAMBDA (W)
+                                                      (CLOSEW (WINDOWPROP W 'EXAMINEWINDOW]
+                  T)
+           EWINDOW)))])
 
 (CSOBJ.COPYBUTTONEVENTINFN
   [LAMBDA (OBJ WINDOW REGION)                                (* ; "Edited  3-Jan-2022 08:36 by rmk")
@@ -625,14 +626,14 @@ Copyright (c) 1985-1988, 2018, 2020-2021 by Xerox Corporation.
 (DEFINEQ
 
 (CSBROWSER
-  [LAMBDA (FILEX FILEY DW? LABEL1 LABEL2 REGION)             (* ; "Edited 26-Dec-2021 21:06 by rmk")
-                                                             (* ; "Edited 24-Dec-2021 22:48 by rmk")
-                                                             (* ; "Edited 20-Dec-2021 09:55 by rmk")
-                                                             (* ; "Edited 16-Dec-2021 12:38 by rmk")
-                                                             (* ; "Edited 10-Dec-2021 12:03 by rmk")
+  [LAMBDA (FILEX FILEY DW? LABEL1 LABEL2 REGION)
+
+    (* ;; "Edited 24-Jan-2022 23:11 by rmk: EXAMINE is non-NIL, we run the compare twice.  Once to get the TEDIT up as a kind of table of contents, and the second time to run through all of the SEDIT windows.")
 
     (* ;; "If EXAMINE is non-NIL, we run the compare twice.  Once to get the TEDIT up as a kind of table of contents, and the second time to run through all of the SEDIT windows.")
 
+    (* ;; "Returns browser window")
+
     (* ;; "Don't use the INFILEP value, because that might screw with capitalization that the caller prefers.  If the file can be found that way, then lower functions will find it.")
 
     (DECLARE (SPECVARS LABEL1 LABEL2))
@@ -651,24 +652,24 @@ Copyright (c) 1985-1988, 2018, 2020-2021 by Xerox Corporation.
                         " and "
                         (OR LABEL2 (PACKFILENAME 'HOST NIL 'DIRECTORY NIL 'BODY FILEY]
          (SELECTQ COMPARESOURCES-BROWSER-TYPE
-             (OBJECTWINDOW (LET [(WINDOW (OBJ.CREATEW 'VERTICAL NIL TITLE NIL T (FONTPROP
-                                                                                 DEFAULTFONT
-                                                                                 'HEIGHT]
+             (OBJECTWINDOW (LET [(WINDOW (OBJ.CREATEW 'VERTICAL REGION TITLE NIL T
+                                                (FONTPROP DEFAULTFONT 'HEIGHT]
                                 (WINDOWPROP WINDOW 'UNDERSCONTRUCTION T)
                                 (GETPROMPTWINDOW WINDOW T)
                                 (WINDOWPROP WINDOW 'UNDERSCONTRUCTION NIL)
-                                (PROG1 (COMPARESOURCES FILEX FILEY '(T 2WINDOWS)
-                                              DW? WINDOW)
-                                       (OPENW WINDOW))))
-             (TEDIT [LET ((TSTREAM (OPENTEXTSTREAM)))
+                                (COMPARESOURCES FILEX FILEY '(T 2WINDOWS)
+                                       DW? WINDOW)
+                                (OPENW WINDOW)
+                                WINDOW))
+             (TEDIT (LET ((TSTREAM (OPENTEXTSTREAM)))
                          (DSPFONT DEFAULTFONT TSTREAM)
-                         (PROG1 (COMPARESOURCES FILEX FILEY EXAMINE DW? TSTREAM)
-                             [TEDIT TSTREAM NIL NIL `(READONLY T WINDOWTYPE COMPARESOURCES-TEDIT 
-                                                            TITLE ,TITLE]
-                             (CL:WHEN NIL
-                                 EXAMINE
-                                 (COMPARESOURCES FILEX FILEY EXAMINE DW? (OPENSTREAM '{NULL}
-                                                                                'OUTPUT))))])
+                         (COMPARESOURCES FILEX FILEY EXAMINE DW? TSTREAM)
+                         [TEDIT TSTREAM REGION NIL `(READONLY T WINDOWTYPE COMPARESOURCES-TEDIT TITLE
+                                                           ,TITLE]
+                         (CL:WHEN NIL
+                             EXAMINE
+                             (COMPARESOURCES FILEX FILEY EXAMINE DW? (OPENSTREAM '{NULL} 'OUTPUT)))
+                         (WFROMDS TSTREAM)))
              (HELP])
 )
 
@@ -689,16 +690,16 @@ Copyright (c) 1985-1988, 2018, 2020-2021 by Xerox Corporation.
 )
 (PUTPROPS COMPARESOURCES COPYRIGHT ("Xerox Corporation" 1985 1986 1987 1988 2018 2020 2021))
 (DECLARE%: DONTCOPY
-  (FILEMAP (NIL (1920 27703 (COMPARESOURCES 1930 . 8443) (\CS.COMPARE.MASTERS 8445 . 16581) (
-\CS.COMPARE.TYPES 16583 . 19721) (\CS.EXAMINE 19723 . 23950) (\CS.FIXFNS 23952 . 25454) (
-\CS.SORT.DECLARES 25456 . 25799) (\CS.SORT.DECLARE1 25801 . 27221) (\CS.FILTER.GARBAGE 27223 . 27701))
- (27704 31684 (\CS.ISFNFORM 27714 . 27982) (\CS.COMPARE.FNS 27984 . 28226) (\CS.FNSID 28228 . 28372) (
-\CS.ISVARFORM 28374 . 28479) (\CS.COMPARE.VARS 28481 . 29143) (\CS.ISMACROFORM 29145 . 29283) (
-\CS.ISRECFORM 29285 . 29378) (\CS.ISCOURIERFORM 29380 . 29480) (\CS.ISTEMPLATEFORM 29482 . 29580) (
-\CS.COMPARE.TEMPLATES 29582 . 29947) (\CS.ISPROPFORM 29949 . 30104) (\CS.PROP.NAME 30106 . 30251) (
-\CS.COMPARE.PROPS 30253 . 30410) (\CS.ISADDVARFORM 30412 . 30505) (\CS.COMPARE.ADDVARS 30507 . 30672) 
-(\CS.ISFPKGCOMFORM 30674 . 30881) (\CS.COMPARE.FPKGCOMS 30883 . 31090) (\CS.COMPARE.DEFINE-FILE-INFO 
-31092 . 31682)) (31685 38243 (CSOBJ.CREATE 31695 . 32108) (CSOBJ.DISPLAYFN 32110 . 32863) (
-CSOBJ.IMAGEBOXFN 32865 . 35026) (CSOBJ.BUTTONEVENTINFN 35028 . 37993) (CSOBJ.COPYBUTTONEVENTINFN 37995
- . 38241)) (39107 42184 (CSBROWSER 39117 . 42182)))))
+  (FILEMAP (NIL (1768 27559 (COMPARESOURCES 1778 . 8291) (\CS.COMPARE.MASTERS 8293 . 16437) (
+\CS.COMPARE.TYPES 16439 . 19577) (\CS.EXAMINE 19579 . 23806) (\CS.FIXFNS 23808 . 25310) (
+\CS.SORT.DECLARES 25312 . 25655) (\CS.SORT.DECLARE1 25657 . 27077) (\CS.FILTER.GARBAGE 27079 . 27557))
+ (27560 31540 (\CS.ISFNFORM 27570 . 27838) (\CS.COMPARE.FNS 27840 . 28082) (\CS.FNSID 28084 . 28228) (
+\CS.ISVARFORM 28230 . 28335) (\CS.COMPARE.VARS 28337 . 28999) (\CS.ISMACROFORM 29001 . 29139) (
+\CS.ISRECFORM 29141 . 29234) (\CS.ISCOURIERFORM 29236 . 29336) (\CS.ISTEMPLATEFORM 29338 . 29436) (
+\CS.COMPARE.TEMPLATES 29438 . 29803) (\CS.ISPROPFORM 29805 . 29960) (\CS.PROP.NAME 29962 . 30107) (
+\CS.COMPARE.PROPS 30109 . 30266) (\CS.ISADDVARFORM 30268 . 30361) (\CS.COMPARE.ADDVARS 30363 . 30528) 
+(\CS.ISFPKGCOMFORM 30530 . 30737) (\CS.COMPARE.FPKGCOMS 30739 . 30946) (\CS.COMPARE.DEFINE-FILE-INFO 
+30948 . 31538)) (31541 37731 (CSOBJ.CREATE 31551 . 31964) (CSOBJ.DISPLAYFN 31966 . 32719) (
+CSOBJ.IMAGEBOXFN 32721 . 34882) (CSOBJ.BUTTONEVENTINFN 34884 . 37481) (CSOBJ.COPYBUTTONEVENTINFN 37483
+ . 37729)) (38595 41299 (CSBROWSER 38605 . 41297)))))
 STOP
diff --git a/lispusers/COMPARESOURCES.LCOM b/lispusers/COMPARESOURCES.LCOM
index 8b8d106d..8df19dbf 100644
Binary files a/lispusers/COMPARESOURCES.LCOM and b/lispusers/COMPARESOURCES.LCOM differ
diff --git a/lispusers/COMPARETEXT.LCOM b/lispusers/COMPARETEXT.LCOM
index 6933ec89..4cc7d40d 100644
Binary files a/lispusers/COMPARETEXT.LCOM and b/lispusers/COMPARETEXT.LCOM differ
diff --git a/lispusers/COMPARETEXT.TEDIT b/lispusers/COMPARETEXT.TEDIT
index 4c0ff822..bd59a01b 100644
Binary files a/lispusers/COMPARETEXT.TEDIT and b/lispusers/COMPARETEXT.TEDIT differ
diff --git a/lispusers/EXAMINEDEFS b/lispusers/EXAMINEDEFS
index b17c568b..31ab7fc0 100644
--- a/lispusers/EXAMINEDEFS
+++ b/lispusers/EXAMINEDEFS
@@ -1,22 +1,28 @@
 (DEFINE-FILE-INFO PACKAGE "INTERLISP" READTABLE "INTERLISP" BASE 10)
 
-(FILECREATED " 2-Jan-2022 23:15:58" 
-{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>EXAMINEDEFS.;19 6871   
+(FILECREATED "25-Jan-2022 10:20:31" 
+{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>EXAMINEDEFS.;31 11252  
 
       :CHANGES-TO (FNS EXAMINEFILES)
 
-      :PREVIOUS-DATE "30-Dec-2021 21:49:58" 
-{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>EXAMINEDEFS.;18)
+      :PREVIOUS-DATE "23-Jan-2022 17:41:43" 
+{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>EXAMINEDEFS.;30)
 
 
 (PRETTYCOMPRINT EXAMINEDEFSCOMS)
 
-(RPAQQ EXAMINEDEFSCOMS ((FNS EXAMINEDEFS EXAMINEFILES)
-                        (INITVARS (EXAMINEDEFS-PROCESS-LIST))))
+(RPAQQ EXAMINEDEFSCOMS ((FNS EXAMINEDEFS EXAMINEFILES TEDITDEF)
+                        (INITVARS (EXAMINEDEFS-PROCESS-LIST)
+                               (EXAMINEWITH 'COMPARETEXT))
+                        (FILES (SYSLOAD)
+                               COMPARETEXT)))
 (DEFINEQ
 
 (EXAMINEDEFS
-  [LAMBDA (NAME TYPE SOURCE1 SOURCE2 TITLE1 TITLE2 REGION)   (* ; "Edited 24-Dec-2021 22:39 by rmk")
+  [LAMBDA (NAME TYPE SOURCE1 SOURCE2 TITLE1 TITLE2 REGION)   (* ; "Edited 23-Jan-2022 17:40 by rmk")
+                                                             (* ; "Edited 18-Jan-2022 22:40 by rmk")
+                                                             (* ; "Edited 12-Jan-2022 17:29 by rmk")
+                                                             (* ; "Edited 24-Dec-2021 22:39 by rmk")
                                                              (* ; "Edited 20-Dec-2021 11:06 by rmk")
 
     (* ;; "This provides for side-by-side examination of separate but presumably related expressions.  The (LISTP) expressions can be provided directly as SOURCE1 and SOURCE2 or, if NAME is given the copies of the definitions of NAME as TYPE on the two sources are examined.")
@@ -30,6 +36,8 @@
                (ERROR SOURCE1 " cannot be examined"))
         (CL:UNLESS (LISTP SOURCE2)
                (ERROR SOURCE2 " cannot be examined")))
+    (CL:UNLESS TYPE
+        (SETQ TYPE 'FNS))
 
     (* ;; "TITLE1 and TITLE2 are optional strings that will be used to construct the titles of the SEDIT windows. We would like to know where GETDEF got the definition so we can use that, but there isn't an interface that provides that information (extended WHEREIS?)")
 
@@ -68,65 +76,124 @@
                           (* ;; 
      "Crude suggestions for height, width, position.  Suggest shorter window for  smaller structures")
 
-                          (CL:UNLESS (REGIONP REGION)
-                              (SETQ REGION (GETREGION)))
-                          (LET (W1 W2 HALFWIDTH)
-                               (SETQ HALFWIDTH (IQUOTIENT (FETCH (REGION WIDTH) OF REGION)
-                                                      2))
-                               [SETQ W1
-                                (SEDIT:GET-WINDOW (SEDIT:SEDIT DEF1
-                                                         `(:NAME ,(CONCAT NAME " from " TITLE1)
-                                                                 :REGION
-                                                                 ,(CREATE REGION
-                                                                     USING REGION WIDTH _ HALFWIDTH)
-                                                                 :DONT-KEEP-WINDOW-REGION T]
-                               [SETQ W2
-                                (SEDIT:GET-WINDOW
-                                 (SEDIT:SEDIT DEF2
-                                        `(:NAME ,(CONCAT NAME " from " TITLE2)
-                                                :REGION
-                                                ,(CREATE REGION USING REGION LEFT _
-                                                                      (IPLUS (FETCH (REGION LEFT)
-                                                                                OF REGION)
-                                                                             HALFWIDTH)
-                                                                      WIDTH _ HALFWIDTH)
-                                                :DONT-KEEP-WINDOW-REGION T]
+                          (SELECTQ EXAMINEWITH
+                              (SEDIT (CL:UNLESS (REGIONP REGION)
+                                         (SETQ REGION (GETREGION)))
+                                     [LET (R1 R2 HALFWIDTH W1 W2)
+                                          (SETQ HALFWIDTH (IQUOTIENT (FETCH (REGION WIDTH)
+                                                                        OF REGION)
+                                                                 2))
+                                          (SETQ R1 (CREATE REGION USING REGION WIDTH _ HALFWIDTH))
+                                          (SETQ R2 (CREATE REGION USING REGION LEFT _
+                                                                        (IPLUS (FETCH (REGION LEFT)
+                                                                                  OF REGION)
+                                                                               HALFWIDTH)
+                                                                        WIDTH _ HALFWIDTH))
+                                          [SETQ W1
+                                           (SEDIT:GET-WINDOW (SEDIT:SEDIT
+                                                              DEF1
+                                                              `(:NAME ,(CONCAT NAME " from " TITLE1)
+                                                                      :REGION
+                                                                      ,(CREATE REGION
+                                                                          USING REGION WIDTH _ 
+                                                                                HALFWIDTH)
+                                                                      R1 :DONT-KEEP-WINDOW-REGION T]
+                                          [SETQ W2
+                                           (SEDIT:GET-WINDOW (SEDIT:SEDIT
+                                                              DEF2
+                                                              `(:NAME ,(CONCAT NAME " from " TITLE2)
+                                                                      :REGION
+                                                                      ,R2 :DONT-KEEP-WINDOW-REGION T]
+                                          (ATTACHWINDOW W2 W1 'RIGHT 'JUSTIFY)
+                                          (MODERNWINDOW W2)
 
-                               (* ;; 
+                                          (* ;; 
    "So we can kill the processes on the next call, if they still exist after the windows are closed.")
 
-                               [PUSH EXAMINEDEFS-PROCESS-LIST (CONS W1 (WINDOWPROP W1 'PROCESS))
-                                     (CONS W2 (WINDOWPROP W2 'PROCESS]
-                               (ATTACHWINDOW W2 W1 'RIGHT 'JUSTIFY)
-                               (MODERNWINDOW W2)))
+                                          (PUSH EXAMINEDEFS-PROCESS-LIST (CONS W1 (WINDOWPROP
+                                                                                   W1
+                                                                                   'PROCESS))
+                                                (CONS W2 (WINDOWPROP W2 'PROCESS])
+                              (COMPARETEXT [LET (COMPARETEXT.ALLCHUNKS CTWINDOW
+                                                       (KEY (LIST NAME TYPE SOURCE1 SOURCE2 TITLE1 
+                                                                  TITLE2)))
+                                                (DECLARE (SPECVARS COMPARETEXT.ALLCHUNKS))
+                                                             (* ; "Reuse an existing CT graph window")
+                                                (OR [FIND W IN (OPENWINDOWS)
+                                                       SUCHTHAT (EQUAL KEY (WINDOWPROP W 
+                                                                                  'EXAMINEDEFS]
+                                                    (PROG1 (SETQ CTWINDOW
+                                                            (COMPARETEXT (TEDITDEF NAME DEF1 TYPE)
+                                                                   (TEDITDEF NAME DEF2 TYPE)
+                                                                   'LINE REGION (LIST TITLE1 TITLE2)
+                                                                   (CONCAT "Compare sources of " NAME
+                                                                          " as " TYPE)))
+                                                        (WINDOWPROP CTWINDOW 'EXAMINEDEFS
+                                                               (LIST NAME TYPE SOURCE1 SOURCE2 TITLE1
+                                                                     TITLE2)))])
+                              (SHOULDNT)))
              (PROGN (EDITE DEF1)
                     (EDITE DEF2])
 
 (EXAMINEFILES
-  [LAMBDA (FILE1 FILE2 TITLE1 TITLE2 REGION)                 (* ; "Edited  2-Jan-2022 23:15 by rmk")
+  [LAMBDA (FILE1 FILE2 TITLE1 TITLE2 REGION)                 (* ; "Edited 25-Jan-2022 10:08 by rmk")
+                                                             (* ; "Edited  2-Jan-2022 23:15 by rmk")
                                                              (* ; "Edited 30-Dec-2021 21:49 by rmk")
 
     (* ;; "We get a region, then split it in half.  Should we attach or at least co-move and co-close the 2 windows?")
 
     (CL:UNLESS REGION
         (SETQ REGION (GETREGION)))
-    (TEDIT-SEE FILE1 (RELCREATEREGION `(,REGION 0.5 -1)
-                            REGION
-                            'RIGHT
-                            'TOP
-                            `(,REGION 0.5)
-                            (FETCH (REGION TOP) OF REGION))
-           NIL TITLE1)
-    (TEDIT-SEE FILE2 (RELCREATEREGION `(,REGION 0.5 1)
-                            REGION
-                            'LEFT
-                            'TOP
-                            `(,REGION 0.5)
-                            (FETCH (REGION TOP) OF REGION))
-           NIL TITLE2])
+    (LIST (TEDIT-SEE FILE1 (RELCREATEREGION `(,REGION 0.5 -1)
+                                  REGION
+                                  'RIGHT
+                                  'TOP
+                                  `(,REGION 0.5)
+                                  (FETCH (REGION TOP) OF REGION))
+                 NIL TITLE1)
+          (TEDIT-SEE FILE2 (RELCREATEREGION `(,REGION 0.5 1)
+                                  REGION
+                                  'LEFT
+                                  'TOP
+                                  `(,REGION 0.5)
+                                  (FETCH (REGION TOP) OF REGION))
+                 NIL TITLE2])
+
+(TEDITDEF
+  [LAMBDA (NAME DEF TYPE READERENVIRONMENT)                  (* ; "Edited 12-Jan-2022 17:27 by rmk")
+    (LET ((TSTREAM (OPENTEXTSTREAM)))
+         (DSPFONT DEFAULTFONT TSTREAM)
+         (CL:WHEN (EQ (CAR DEF)
+                      'DEFINEQ)
+             (SETQ DEF (CADR DEF)))
+         (IF (EQ NAME (CAR DEF))
+             THEN (DSPFONT BOLDFONT TSTREAM)
+                  (PRINT NAME TSTREAM)
+                  (DSPFONT DEFAULTFONT TSTREAM)
+                  (SETQ DEF (CADR DEF))
+                  (PRINTDEF DEF 3 T NIL NIL TSTREAM)
+           ELSEIF (EQ NAME (CADR DEF))
+             THEN 
+                  (* ;; "Presumably a DEFUN.  Print the CAR, boldface the cadr")
+
+                  (PRINTOUT TSTREAM "(" .P2 (CAR DEF)
+                         " " .FONT BOLDFONT .P2 (CADR DEF)
+                         .FONT DEFAULTFONT " " .P2 (CADDR DEF)
+                         T 3)
+                  (PRINTDEF (CDDDR DEF)
+                         3 T T NIL TSTREAM)
+                  (PRIN3 ")" TSTREAM)
+           ELSE (PRINTDEF DEF 3 NIL NIL NIL TSTREAM))
+         TSTREAM])
 )
 
 (RPAQ? EXAMINEDEFS-PROCESS-LIST )
+
+(RPAQ? EXAMINEWITH 'COMPARETEXT)
+
+(FILESLOAD (SYSLOAD)
+       COMPARETEXT)
 (DECLARE%: DONTCOPY
-  (FILEMAP (NIL (510 6809 (EXAMINEDEFS 520 . 5811) (EXAMINEFILES 5813 . 6807)))))
+  (FILEMAP (NIL (662 11110 (EXAMINEDEFS 672 . 8791) (EXAMINEFILES 8793 . 9988) (TEDITDEF 9990 . 11108)))
+))
 STOP
diff --git a/lispusers/EXAMINEDEFS.LCOM b/lispusers/EXAMINEDEFS.LCOM
index d2963945..29be30c6 100644
Binary files a/lispusers/EXAMINEDEFS.LCOM and b/lispusers/EXAMINEDEFS.LCOM differ
diff --git a/lispusers/EXAMINEDEFS.TEDIT b/lispusers/EXAMINEDEFS.TEDIT
index ce966800..a0390404 100644
Binary files a/lispusers/EXAMINEDEFS.TEDIT and b/lispusers/EXAMINEDEFS.TEDIT differ
diff --git a/lispusers/GITFNS b/lispusers/GITFNS
new file mode 100644
index 00000000..010ed44e
--- /dev/null
+++ b/lispusers/GITFNS
@@ -0,0 +1,1143 @@
+(DEFINE-FILE-INFO PACKAGE "INTERLISP" READTABLE "INTERLISP" BASE 10)
+
+(FILECREATED "26-Jan-2022 22:53:49" {DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>GITFNS.;35 57074  
+
+      :CHANGES-TO (FNS GIT-COMPARE-WITH-MYMEDLEY)
+
+      :PREVIOUS-DATE "26-Jan-2022 22:40:03" 
+{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>GITFNS.;34)
+
+
+(PRETTYCOMPRINT GITFNSCOMS)
+
+(RPAQQ GITFNSCOMS
+       (
+        (* ;; "Set up")
+
+        (FILES (SYSLOAD FROM VALUEOF LISPUSERSDIRECTORIES)
+               COMPAREDIRECTORIES COMPARESOURCES COMPARETEXT PSEUDOHOSTS)
+        (INITVARS [GITMEDLEYDIR (OR (UNIX-GETENV "GITMEDLEYDIR")
+                                    (CONCAT "{UNIX}" (SLASHIT (PACKFILENAME 'HOST NIL 'BODY MEDLEYDIR
+                                                                     )
+                                                            T]
+               (MYMEDLEYHOST 'MM)
+               (GITMEDLEYHOST 'GIT))
+        (INITVARS (GIT-IGNORE-FILES '(EXPORTS.ALL RDSYS RDSYS.LCOM))
+               (GIT-IGNORE-DIRECTORIES '(LOADUPS PATCHES TMP FONTSOLD DELETED))
+               (GIT-MERGE-COMPARES T))
+        (P (PSEUDOHOST MYMEDLEYHOST MEDLEYDIR)
+           (PSEUDOHOST GITMEDLEYHOST GITMEDLEYDIR))
+        
+        (* ;; "")
+
+        
+        (* ;; "Lisp exec commands")
+
+        (COMMANDS gmc bbc prc cob b?)
+        
+        (* ;; "")
+
+        
+        (* ;; "File correspondents")
+
+        (FNS TOGIT FROMGIT GIT-DELETE-FILE MYMEDLEY-DELETE-FILES)
+        (FNS MEDLEYSUBDIR GITSUBDIR STRIPDIR STRIPHOST)
+        (FNS GFILE4MFILE MFILE4GFILE GIT-REPO-FILENAME)
+        (FNS MEDLEYSUBDIRS GITSUBDIRS)
+        (VARS (MEDLEYSUBDIRS (MEDLEYSUBDIRS))
+              (GITSUBDIRS (GITSUBDIRS)))
+        
+        (* ;; "")
+
+        
+        (* ;; "Git commands")
+
+        (FNS GIT-COMMIT GIT-PUSH GIT-PULL GIT-BRANCH-DIFF GIT-APPROVAL GIT-GET-FILE GIT-FILE-EXISTS?
+             GIT-REMOTE-UPDATE GIT-FILE-DATE)
+        
+        (* ;; "")
+
+        
+        (* ;; "Branches")
+
+        (FNS GIT-CHECKOUT GIT-WHICH-BRANCH GIT-MAKE-BRANCH GIT-BRANCHES GIT-BRANCH-EXISTS?)
+        
+        (* ;; "My branches")
+
+        (FNS GIT-MY-CURRENT-BRANCH GIT-MY-BRANCHP GIT-MY-NEXT-BRANCH GIT-MY-BRANCHES)
+        
+        (* ;; "")
+
+        
+        (* ;; "Worktrees")
+
+        (FNS GIT-ADD-WORKTREE GIT-REMOVE-WORKTREE GIT-LIST-WORKTREES WORKTREEDIR)
+        
+        (* ;; "")
+
+        
+        (* ;; "Comparisons")
+
+        (FNS GIT-GET-DIFFERENT-FILES GIT-COMPARE-BRANCHES GIT-COMPARE-WITH-MYMEDLEY 
+             GIT-COMPARE-WORKTREE GITCDOBJBUTTONFN GIT-CD-LABELFN GIT-CD-MENUFN)
+        
+        (* ;; "")
+
+        
+        (* ;; "Utilities")
+
+        (FNS CDGITDIR GIT-COMMAND GITORIGIN GIT-INITIALS)))
+
+
+
+(* ;; "Set up")
+
+
+(FILESLOAD (SYSLOAD FROM VALUEOF LISPUSERSDIRECTORIES)
+       COMPAREDIRECTORIES COMPARESOURCES COMPARETEXT PSEUDOHOSTS)
+
+(RPAQ? GITMEDLEYDIR (OR (UNIX-GETENV "GITMEDLEYDIR")
+                        (CONCAT "{UNIX}" (SLASHIT (PACKFILENAME 'HOST NIL 'BODY MEDLEYDIR)
+                                                T))))
+
+(RPAQ? MYMEDLEYHOST 'MM)
+
+(RPAQ? GITMEDLEYHOST 'GIT)
+
+(RPAQ? GIT-IGNORE-FILES '(EXPORTS.ALL RDSYS RDSYS.LCOM))
+
+(RPAQ? GIT-IGNORE-DIRECTORIES '(LOADUPS PATCHES TMP FONTSOLD DELETED))
+
+(RPAQ? GIT-MERGE-COMPARES T)
+
+(PSEUDOHOST MYMEDLEYHOST MEDLEYDIR)
+
+(PSEUDOHOST GITMEDLEYHOST GITMEDLEYDIR)
+
+
+
+(* ;; "")
+
+
+
+
+(* ;; "Lisp exec commands")
+
+
+(DEFCOMMAND gmc (SUBDIR . OTHERS)
+
+   (* ;; "Compares the specified local git-medley subdirectories against my working Medley.  ")
+
+    (GIT-COMPARE-WITH-MYMEDLEY (AND SUBDIR (CONS SUBDIR OTHERS))
+           NIL NIL NIL NIL T))
+
+(DEFCOMMAND bbc (BRANCH1 BRANCH2 LOCAL)
+
+   (* ;; "Compares 2 git branches.  Defaults to local/ if LOCAL, otherwise defaults to origin/.  BRANCH2 defaults to master (origin/ or local/ depending on LOCAL)")
+
+    (GIT-COMPARE-BRANCHES BRANCH1 BRANCH2 LOCAL))
+
+(DEFCOMMAND prc (REMOTEBRANCH)
+
+   (* ;; "Compares REMOTEBRANCH against origin/master, for pull-request assessment")
+
+    (CL:UNLESS REMOTEBRANCH (ERROR "PR branch not specified" ""))
+   (GIT-COMPARE-BRANCHES REMOTEBRANCH 'origin/master NIL))
+
+(DEFCOMMAND cob (BRANCH)
+
+   (* ;; "Switches to BRANCH. Defaults to my current branch, T means my next branch (under wherever we are now ")
+
+    (SELECTQ (U-CASE BRANCH)
+        (NIL (GIT-CHECKOUT (GIT-MY-CURRENT-BRANCH)))
+        ((T NEW) 
+             (GIT-MAKE-BRANCH))
+        (GIT-CHECKOUT BRANCH)))
+
+(DEFCOMMAND b? (BRANCH) (GIT-WHICH-BRANCH))
+
+
+
+(* ;; "")
+
+
+
+
+(* ;; "File correspondents")
+
+(DEFINEQ
+
+(TOGIT
+  [LAMBDA (MFILES)                                           (* ; "Edited 19-Jan-2022 23:35 by rmk")
+                                                             (* ; "Edited 18-Jan-2022 16:33 by rmk")
+                                                             (* ; "Edited 13-Jan-2022 15:47 by rmk")
+
+    (* ;; "Copies MFILES to {GIT}. We do a sanity check to make sure particular MFILE is the latest version--we may have created another one without revising the directory browser.")
+
+    (CL:WHEN (EQ 'master (GIT-WHICH-BRANCH))
+           (ERROR "Can't copy to the master branch"))
+    (FOR MF GF DEST INSIDE MFILES COLLECT (SETQ MF (OR (FINDFILE MF NIL MEDLEYSUBDIRS)
+                                                       (ERROR "FILE NOT FOUND" MF)))
+                                        (CL:UNLESS (STRING.EQUAL MF (INFILEP (PACKFILENAME
+                                                                              'VERSION NIL
+                                                                              'BODY MF))
+                                                          FILEDIRCASEARRAY)
+                                            (FLASHWINDOW T)
+                                            (PRIN3 (CONCAT MF " is not the latest version!")
+                                                   T)
+                                            (ERROR!))
+                                        (SETQ GF (GFILE4MFILE MF))
+                                        (PRIN3 (IF (SETQ DEST (COPYFILE MF GF))
+                                                   THEN (CONCAT "Copied to " GF)
+                                                 ELSE (FLASHWINDOW T)
+                                                      (CONCAT MF " cannot be copied"))
+                                               T)
+                                        DEST])
+
+(FROMGIT
+  [LAMBDA (GFILES)                                           (* ; "Edited 18-Jan-2022 16:31 by rmk")
+    (FOR GF MF DEST INSIDE GFILES COLLECT (SETQ GF (OR (FINDFILE GF NIL GITSUBDIRS)
+                                                       (ERROR "FILE NOT FOUND" GF)))
+                                        (SETQ MF (MFILE4GFILE GF))
+                                        (PRIN3 (IF (SETQ DEST (COPYFILE GF MF))
+                                                   THEN (CONCAT "Copied to " DEST)
+                                                        DEST
+                                                 ELSE (FLASHWINDOW T)
+                                                      (CONCAT GF " cannot be copied"))
+                                               T)
+                                        DEST])
+
+(GIT-DELETE-FILE
+  [LAMBDA (FILE)                                             (* ; "Edited 18-Jan-2022 23:07 by rmk")
+                                                             (* ; "Edited 19-Dec-2021 16:11 by rmk")
+                                                             (* ; "Edited 16-Dec-2021 13:00 by rmk")
+
+    (* ;; "This deletes a file in the local checkout git directory {UNIX}...  FILE has to already be a full file name, for safety.")
+
+    (* ;; "Since git files are on UNIX, we don't have to worry about older version numbers. ")
+
+    (* ;; "We could make this undoable by copying it to deleted/, but git also can restore.")
+
+    (CL:UNLESS (OR (EQ GITMEDLEYHOST (FILENAMEFIELD FILE 'HOST))
+                   (STRPOS GITMEDLEYDIR FILE 1 NIL T NIL FILEDIRCASEARRAY))
+           (ERROR "NOT A GIT-CLONE FILE" FILE))
+    (DELFILE FILE])
+
+(MYMEDLEY-DELETE-FILES
+  [LAMBDA (FILE)                                             (* ; "Edited 18-Jan-2022 23:02 by rmk")
+                                                             (* ; "Edited 19-Dec-2021 23:33 by rmk")
+
+    (* ;; "FILE is presumably the latest version of a file in the MyMedley directory, and we are presumably removing all versions of that file.  If we left older versions, we would really trash ourselves.")
+
+    (* ;; "But to guard against mistakes, %"deletion%" consists of moving all versions of the file from its current location to a deleted/ subdirectory of MEDLEYDIR, one that does not correspond to a git subdirectory.")
+
+    (SETQ FILE (CONTRACT.PH FILE MYMEDLEYHOST))
+    (CL:WHEN (EQ MYMEDLEYHOST (FILENAMEFIELD FILE 'HOST))
+        (FOR F IN (DREVERSE (FILDIR (PACKFILENAME 'VERSION '* 'BODY FILE)))
+           COLLECT 
+
+                 (* ;; 
+                 "Delete the earlier ones first, if it goes bad, you don't want them to persist")
+
+                 (CL:UNLESS (RENAMEFILE F (PACKFILENAME 'DIRECTORY (CONCAT "deleted>"
+                                                                          (FILENAMEFIELD F
+                                                                                 'DIRECTORY))
+                                                 'BODY F))
+                        (ERROR "Could not delete " F))
+                 F))])
+)
+(DEFINEQ
+
+(MEDLEYSUBDIR
+  [LAMBDA (SUBDIR STAR)                                      (* ; "Edited 21-Jan-2022 15:18 by rmk")
+                                                             (* ; "Edited 18-Jan-2022 16:19 by rmk")
+    (PACKFILENAME 'HOST MYMEDLEYHOST 'BODY (CONCAT SUBDIR (CL:IF STAR
+                                                              ">*"
+                                                              "")])
+
+(GITSUBDIR
+  [LAMBDA (SUBDIR STAR)                                      (* ; "Edited 21-Jan-2022 15:18 by rmk")
+                                                             (* ; "Edited 18-Jan-2022 16:19 by rmk")
+                                                            (* ; "Edited 30-Oct-2021 23:59 by rmk:")
+    (SLASHIT (PACKFILENAME 'HOST GITMEDLEYHOST 'BODY (CONCAT SUBDIR (CL:IF STAR
+                                                                        "/*"
+                                                                        "")])
+
+(STRIPDIR
+  [LAMBDA (FILE DIRECTORY)                                   (* ; "Edited 18-Jan-2022 16:09 by rmk")
+                                                             (* ; "Edited  8-Nov-2021 11:50 by rmk:")
+    (IF (STRPOS DIRECTORY FILE 1 NIL T NIL FILEDIRCASEARRAY)
+        THEN (SUBSTRING FILE (ADD1 (NCHARS DIRECTORY)))
+      ELSE FILE])
+
+(STRIPHOST
+  [LAMBDA (NAME)                                             (* ; "Edited 18-Jan-2022 15:37 by rmk")
+    (LET ((POS (STRPOS "}" NAME)))
+         (CL:IF POS
+             (SUBSTRING NAME (ADD1 POS))
+             NAME)])
+)
+(DEFINEQ
+
+(GFILE4MFILE
+  [LAMBDA (MFILE)                                            (* ; "Edited 18-Jan-2022 15:24 by rmk")
+    (SETQ MFILE (OR (FINDFILE MFILE NIL MEDLEYSUBDIRS)
+                    (ERROR "FILE NOT FOUND" MFILE)))
+    (SLASHIT [IF (EQ MYMEDLEYHOST (FILENAMEFIELD MFILE 'HOST))
+                 THEN (PACKFILENAME 'HOST GITMEDLEYHOST 'VERSION NIL 'BODY MFILE)
+               ELSE (PACKFILENAME 'VERSION NIL 'BODY (CONCAT GITMEDLEYDIR (SUBSTRING
+                                                                           MFILE
+                                                                           (ADD1 (NCHARS MEDLEYDIR]
+           T])
+
+(MFILE4GFILE
+  [LAMBDA (GFILE)                                            (* ; "Edited 18-Jan-2022 15:24 by rmk")
+    (UNSLASHIT (IF (EQ GITMEDLEYHOST (FILENAMEFIELD GFILE 'HOST))
+                   THEN (PACKFILENAME 'HOST MYMEDLEYHOST 'VERSION NIL 'BODY GFILE)
+                 ELSE (PACKFILENAME 'VERSION NIL 'BODY (CONCAT MEDLEYDIR (SUBSTRING
+                                                                          GFILE
+                                                                          (ADD1 (NCHARS GITMEDLEYDIR])
+
+(GIT-REPO-FILENAME
+  [LAMBDA (GFILE)                                            (* ; "Edited 18-Jan-2022 15:42 by rmk")
+
+    (* ;; "Returns the string that the repo expects for a file name.  {GIT} or GITMEDLEYDIR is stripped, brackets go to slashes, subdirectories are lower cased, and a final period is remove.")
+
+    (SETQ GFILE (SLASHIT (IF (EQ GITMEDLEYHOST (FILENAMEFIELD GFILE 'HOST))
+                             THEN (STRIPHOST GFILE)
+                           ELSE (STRIPDIR GFILE GITMEDLEYDIR))
+                       T))
+    (CL:WHEN (EQ (CHARCODE %.)
+                 (NTHCHARCODE GFILE -1))
+        (SETQ GFILE (SUBSTRING GFILE 1 -2)))
+    GFILE])
+)
+(DEFINEQ
+
+(MEDLEYSUBDIRS
+  [LAMBDA NIL                                                (* ; "Edited 26-Jan-2022 14:52 by rmk")
+                                                             (* ; "Edited 24-Jan-2022 17:28 by rmk")
+                                                             (* ; "Edited 18-Jan-2022 15:34 by rmk")
+                                                             (* ; "Edited 13-Jan-2022 20:16 by rmk")
+    (FOR F IN (FILDIR (PACKFILENAME 'HOST MYMEDLEYHOST 'BODY '*)) WHEN (DIRECTORYNAMEP F)
+       UNLESS (THEREIS SKIP IN GIT-IGNORE-DIRECTORIES SUCHTHAT (STRPOS SKIP (FILENAMEFIELD
+                                                                             F
+                                                                             'DIRECTORY)
+                                                                      1 NIL T NIL FILEDIRCASEARRAY))
+       COLLECT (UNSLASHIT F T])
+
+(GITSUBDIRS
+  [LAMBDA NIL                                                (* ; "Edited 26-Jan-2022 15:12 by rmk")
+                                                             (* ; "Edited 18-Jan-2022 14:57 by rmk")
+                                                             (* ; "Edited 13-Jan-2022 16:08 by rmk")
+                                                             (* ; "Edited  3-Jan-2022 11:12 by rmk")
+                                                            (* ; "Edited 30-Oct-2021 23:28 by rmk:")
+
+    (* ;; "We drive this with MEDLEYSUBDIRS instead of {GIT}* because GIT has lots of things that we don't want to see (.git directories, cltl2, rooms, etc...)")
+
+    (FOR D IN MEDLEYSUBDIRS COLLECT (IF (EQ MYMEDLEYHOST (FILENAMEFIELD D 'HOST))
+                                        THEN (SLASHIT (PACKFILENAME 'HOST GITMEDLEYHOST 'BODY D)
+                                                    T)
+                                      ELSE (SLASHIT (CONCAT GITMEDLEYDIR
+                                                           (L-CASE (SUBSTRING D (ADD1 (NCHARS 
+                                                                                            MEDLEYDIR
+                                                                                             ])
+)
+
+(RPAQ MEDLEYSUBDIRS (MEDLEYSUBDIRS))
+
+(RPAQ GITSUBDIRS (GITSUBDIRS))
+
+
+
+(* ;; "")
+
+
+
+
+(* ;; "Git commands")
+
+(DEFINEQ
+
+(GIT-COMMIT
+  [LAMBDA (FILES TITLE MESSAGE)                             (* ; "Edited 16-Nov-2021 08:06 by rmk:")
+                                                            (* ; "Edited  2-Nov-2021 21:26 by rmk:")
+
+    (* ;; "Commits files that are already in the (non-master) current git branch.")
+
+    (CL:WHEN (STREQUAL (GIT-WHICH-BRANCH)
+                    "master")
+           (ERROR "Cannot commit to the master branch"))
+    (LET (GFILES)
+         (SETQ GFILES (FOR F GF INSIDE FILES COLLECT (SETQ GF (INFILEP (GFILE4MFILE F])
+
+(GIT-PUSH
+  [LAMBDA (BRANCH)                                           (* ; "Edited  8-Dec-2021 22:32 by rmk")
+                                                             (* ; "Edited 16-Nov-2021 08:06 by rmk:")
+                                                             (* ; "Edited  2-Nov-2021 21:34 by rmk:")
+    (CL:UNLESS BRANCH
+        (SETQ BRANCH (GIT-WHICH-BRANCH)))
+    (CL:WHEN (STREQUAL "master" (GIT-WHICH-BRANCH))
+           (ERROR "Cannot push the master branch"))
+    (GIT-COMMAND (CONCAT "git push " BRANCH])
+
+(GIT-PULL
+  [LAMBDA (BRANCH)                                           (* ; "Edited  8-Dec-2021 22:47 by rmk")
+                                                             (* ; "Edited 16-Nov-2021 08:06 by rmk:")
+                                                             (* ; "Edited  2-Nov-2021 21:34 by rmk:")
+    (GIT-COMMAND (CONCAT "git pull " (OR BRANCH (GIT-WHICH-BRANCH])
+
+(GIT-BRANCH-DIFF
+  [LAMBDA (BRANCH1 BRANCH2)                                 (* ; "Edited 24-Nov-2021 16:30 by rmk:")
+                                                            (* ; "Edited 22-Nov-2021 09:07 by rmk:")
+                                                            (* ; "Edited 16-Nov-2021 08:41 by rmk:")
+    (CL:UNLESS BRANCH1 (SETQ BRANCH1 "origin/master"))
+    (CL:UNLESS BRANCH2 (SETQ BRANCH2 "origin/master"))
+    (GIT-REMOTE-UPDATE)
+    (LET ([MERGE (CAR (GIT-COMMAND (CONCAT "git merge-base " BRANCH1 " " BRANCH2]
+          FILES POS)
+         (CL:WHEN (STRPOS "fatal" MERGE)
+             (ERROR (CONCAT "merge-base failed for " (LIST BRANCH1 BRANCH2))))
+         (SETQ FILES (GIT-COMMAND (CONCAT "git diff  --name-only " MERGE " " BRANCH1)))
+         (CL:WHEN (SETQ POS (STRPOS "fatal: ambiguous argument '" (CAR FILES)
+                                   1 NIL T T))
+             (ERROR "Unknown branch " (IF (STRPOS BRANCH1 (CAR FILES)
+                                                 POS NIL T)
+                                          THEN BRANCH1
+                                        ELSE BRANCH2)))
+         FILES])
+
+(GIT-APPROVAL
+  [LAMBDA (BRANCH)                                          (* ; "Edited 19-Nov-2021 15:08 by rmk:")
+    (GIT-ADD-WORKTREE BRANCH T)
+    (GIT-ADD-WORKTREE "master" T])
+
+(GIT-GET-FILE
+  [LAMBDA (BRANCH GITFILE MEDLEYFILE)                        (* ; "Edited  3-Jan-2022 23:52 by rmk")
+                                                             (* ; "Edited 20-Nov-2021 20:28 by rmk:")
+
+    (* ;; "If  GITFILE in BRANCH exists, it is copied to MEDLEYFILE and MEDLEYFILE is returned.  If it doesn't exist, return value is NIL.  Maybe it should cause a FILENOTFOUND error?")
+
+    (CL:WHEN (GIT-FILE-EXISTS? BRANCH GITFILE)
+        (CL:WITH-OPEN-FILE (STREAM (OR MEDLEYFILE '{NODIRCORE)
+                                  :IF-EXISTS :NEW-VERSION :DIRECTION :IO)
+               (CL:WITH-OPEN-STREAM (s (CREATE-PROCESS-STREAM (CONCAT (CDGITDIR)
+                                                                     "git show " BRANCH ":" GITFILE))
+                                       )
+                      (SETFILEINFO s 'ENDOFSTREAMOP (FUNCTION NILL))
+                      (BIND C WHILE (SETQ C (\BIN s)) DO (\BOUT STREAM C)))
+               (SETFILEINFO STREAM 'CREATIONDATE (GIT-FILE-DATE GITFILE BRANCH))
+               STREAM))])
+
+(GIT-FILE-EXISTS?
+  [LAMBDA (BRANCH GITFILE)                                   (* ; "Edited 10-Dec-2021 21:30 by rmk")
+
+    (* ;; "T if GITFILE exists on BRANCH")
+
+    (CL:WITH-OPEN-FILE (STREAM '{NODIRCORE :DIRECTION :IO)
+           (CL:WITH-OPEN-STREAM (s (CREATE-PROCESS-STREAM (CONCAT (CDGITDIR)
+                                                                 "git show " BRANCH ":" GITFILE)))
+                  (SETFILEINFO s 'ENDOFSTREAMOP (FUNCTION NILL))
+                  (LET ((LINE (CL:READ-LINE s)))
+                       (NOT (OR (STREQUAL LINE (CONCAT "fatal: path '" GITFILE 
+                                                      "' does not exist in '" BRANCH "'"))
+                                (STREQUAL LINE (CONCAT "fatal: path '" GITFILE 
+                                                      "' exists on disk, but not in '" BRANCH "'"])
+
+(GIT-REMOTE-UPDATE
+  [LAMBDA (DOIT)                                             (* ; "Edited 16-Dec-2021 10:45 by rmk")
+                                                             (* ; "Edited  4-Dec-2021 21:49 by rmk")
+                                                             (* ; "Edited  2-Dec-2021 08:44 by rmk:")
+                                                             (* ; "Edited 24-Nov-2021 16:34 by rmk:")
+    (DECLARE (USEDFREE LAST-REMOTE-UPDATE-IDATE))
+
+    (* ;; "Because git hangs on this (and other things), do this no more than once a day")
+
+    (CL:WHEN [OR DOIT (NOT (BOUNDP 'LAST-REMOTE-UPDATE-IDATE))
+                 (IGREATERP (IDIFFERENCE (IDATE)
+                                   LAST-REMOTE-UPDATE-IDATE)
+                        (CONSTANT (TIMES 24 60 60 1000]
+        (PRINTOUT T "Updating from remote, local branch is " (GIT-WHICH-BRANCH)
+               T)
+        (PROG1 (GIT-COMMAND "git remote update origin")
+            (SETQ LAST-REMOTE-UPDATE-IDATE (IDATE))))])
+
+(GIT-FILE-DATE
+  [LAMBDA (GFILE BRANCH)                                     (* ; "Edited  3-Jan-2022 19:43 by rmk")
+    (LET [(DATE (CAR (GIT-COMMAND (CONCAT "git log -1 --pretty=%"format:%%cD%" "
+                                         (CL:IF BRANCH
+                                             (CONCAT BRANCH " -- ")
+                                             "")
+                                         (GIT-REPO-FILENAME GFILE T))
+                            NIL T]
+         DATE])
+)
+
+
+
+(* ;; "")
+
+
+
+
+(* ;; "Branches")
+
+(DEFINEQ
+
+(GIT-CHECKOUT
+  [LAMBDA (BRANCH)                                          (* ; "Edited  2-Nov-2021 22:40 by rmk:")
+    (CAR (GIT-COMMAND (CONCAT "git checkout " (OR BRANCH "master")
+                             "; git pull"])
+
+(GIT-WHICH-BRANCH
+  [LAMBDA NIL                                                (* ; "Edited 14-Dec-2021 23:39 by rmk")
+                                                             (* ; "Edited 12-Dec-2021 11:56 by rmk")
+                                                             (* ; "Edited  6-Nov-2021 12:11 by rmk:")
+                                                             (* ; "Edited  3-Oct-2021 15:32 by rmk:")
+
+    (* ;; "Returns the current (local) branch")
+
+    (MKATOM (CONCAT "local/" (CAR (GIT-COMMAND "git rev-parse --abbrev-ref HEAD"])
+
+(GIT-MAKE-BRANCH
+  [LAMBDA (NAME TITLESTRING)                                 (* ; "Edited 26-Jan-2022 12:12 by rmk")
+                                                             (* ; "Edited 19-Jan-2022 23:25 by rmk")
+                                                             (* ; "Edited  8-Jan-2022 09:48 by rmk")
+                                                            (* ; "Edited  2-Nov-2021 21:28 by rmk:")
+
+    (* ;; " The new branch is directly under the currently checked out branch.  Maybe it should always make it under master?")
+
+    (* ;; 
+    "This makes a new branch with name NAME: TITLESTRING, or just NAME if TITLESTRING is not given.")
+
+    (* ;; "(GIT-MAKE-BRANCH) makes and checks out the next initialsn branch.")
+
+    (CL:UNLESS NAME
+        (SETQ NAME (GIT-MY-NEXT-BRANCH)))
+    (CL:WHEN TITLESTRING
+        (SETQ NAME (CONCAT NAME (CONCAT ": " TITLESTRING))))
+    (LET [(UNDER (GIT-WHICH-BRANCH))
+          (RESULT (GIT-COMMAND (CONCAT "git checkout -b " NAME]
+         (IF (STREQUAL (CAR RESULT)
+                    (CONCAT "Switched to a new branch '" NAME "'"))
+             THEN (CONCAT (CAR RESULT)
+                         " under " UNDER)
+           ELSEIF (STREQUAL (CAR RESULT)
+                         (CONCAT "fatal: A branch named '" NAME "' already exists."))
+             THEN (ERROR NAME "already exists")
+           ELSE (HELP "Unexpected git result" RESULT])
+
+(GIT-BRANCHES
+  [LAMBDA (WHERE)                                            (* ; "Edited  8-Dec-2021 08:43 by rmk")
+                                                            (* ; "Edited 17-Nov-2021 18:20 by rmk:")
+                                                            (* ; "Edited 16-Nov-2021 09:21 by rmk:")
+
+    (* ;; 
+   "Strips of the %"* %" that indicates the current branch and the 2-space padding on other branches")
+
+    (LET [(LOCAL (CL:WHEN (MEMB WHERE '(NIL ALL LOCAL))
+                        (GIT-COMMAND "git branch")))
+          (REMOTE (CL:WHEN (MEMB WHERE '(NIL ALL REMOTE T))
+                         (GIT-COMMAND "git branch -r"]
+         (FOR B IN (APPEND LOCAL REMOTE) COLLECT (SUBATOM B 3])
+
+(GIT-BRANCH-EXISTS?
+  [LAMBDA (BRANCH WHERE NOERROR)                             (* ; "Edited 16-Dec-2021 08:50 by rmk")
+                                                             (* ; "Edited  8-Dec-2021 08:44 by rmk")
+                                                             (* ; "Edited 19-Nov-2021 15:13 by rmk:")
+                                                             (* ; "Edited 17-Nov-2021 18:24 by rmk:")
+
+    (* ;; "Returns the canonical name of the branch (xxx or origin/xxx) depending on whether BRANCH is local/xxx or origin/xxx")
+                                                             (* ; "Edited 16-Nov-2021 09:25 by rmk:")
+    (IF (STRPOS "origin/" BRANCH)
+        THEN (SETQ WHERE 'REMOTE)
+      ELSEIF (STRPOS "local/" BRANCH 1 NIL T)
+        THEN (SETQ WHERE 'LOCAL)
+             (SETQ BRANCH (SUBATOM BRANCH 7)))
+    (IF (CAR (MEMB (MKATOM BRANCH)
+                   (GIT-BRANCHES WHERE)))
+      ELSEIF (NOT NOERROR)
+        THEN (ERROR "Unknown branch" BRANCH])
+)
+
+
+
+(* ;; "My branches")
+
+(DEFINEQ
+
+(GIT-MY-CURRENT-BRANCH
+  [LAMBDA NIL                                                (* ; "Edited 19-Jan-2022 13:22 by rmk")
+    (CAR (LAST (GIT-MY-BRANCHES])
+
+(GIT-MY-BRANCHP
+  [LAMBDA (BRANCH)                                           (* ; "Edited 26-Jan-2022 11:41 by rmk")
+                                                             (* ; "Edited 19-Jan-2022 13:22 by rmk")
+
+    (* ;; "Returns n if BRANCH is INITIALSn (local or origin), possibly followed by a trailing comment after colon or space.")
+
+    (CL:UNLESS BRANCH
+        (SETQ BRANCH (GIT-WHICH-BRANCH)))
+    (LET* ((INITS (GIT-INITIALS))
+           (INC (NCHARS INITS))
+           (SPOS (ADD1 (OR (STRPOS "/" BRANCH)
+                           0)))
+           (EPOS))
+          (CL:WHEN (STRPOS INITS BRANCH SPOS NIL T NIL UPPERCASEARRAY)
+              (CL:WHEN (SETQ EPOS (\UPF.NEXTPOS (CHARCODE (%: SPACE))
+                                         BRANCH SPOS))
+                     (ADD EPOS -1))
+              (SUBATOM BRANCH (IPLUS SPOS INC)
+                     EPOS))])
+
+(GIT-MY-NEXT-BRANCH
+  [LAMBDA NIL                                                (* ; "Edited 19-Jan-2022 23:14 by rmk")
+                                                             (* ; "Edited  8-Jan-2022 09:43 by rmk")
+
+    (* ;; "Figures out what my next incremental branch would be.  ")
+
+    (PACK* (GIT-INITIALS)
+           (ADD1 (OR (GIT-MY-BRANCHP (GIT-MY-CURRENT-BRANCH))
+                     0])
+
+(GIT-MY-BRANCHES
+  [LAMBDA NIL                                                (* ; "Edited 19-Jan-2022 13:20 by rmk")
+                                                             (* ; "Edited  8-Jan-2022 09:53 by rmk")
+                                                             (* ; "Edited 12-Dec-2021 11:46 by rmk")
+
+    (* ;; "This returns only local branch names:  xyzn and not origin/xyzn or local/xyzn")
+
+    (* ;; "If INITIALS is xyz or xyz:, returns xyzn where xyzn is a branch and n is greater than m for all other branches xyzm.  xyzn may not be be the current branch.")
+
+    (* ;; "The return list is sorted so that lower n's come before later n's.  The last element is my current branch")
+
+    (FOR B (INITS _ (GIT-INITIALS))
+         INC IN (GIT-BRANCHES) FIRST (SETQ INC (NCHARS INITS))
+       WHEN (STRPOS INITS B 1 NIL T NIL UPPERCASEARRAY) COLLECT B
+       FINALLY (RETURN (SORT $$VAL (FUNCTION (LAMBDA (A B)
+                                               (ILESSP (SUBATOM A (ADD1 INC))
+                                                      (SUBATOM B (ADD1 INC])
+)
+
+
+
+(* ;; "")
+
+
+
+
+(* ;; "Worktrees")
+
+(DEFINEQ
+
+(GIT-ADD-WORKTREE
+  [LAMBDA (BRANCH REMOTEONLY)                                (* ; "Edited 12-Dec-2021 11:57 by rmk")
+                                                             (* ; "Edited 25-Nov-2021 08:45 by rmk:")
+                                                             (* ; "Edited 19-Nov-2021 19:01 by rmk:")
+                                                             (* ; "Edited 17-Nov-2021 18:25 by rmk:")
+    (SETQ BRANCH (GITORIGIN BRANCH (NOT REMOTEONLY)))
+    (CL:UNLESS (OR (GIT-BRANCH-EXISTS? BRANCH NIL T)
+                   (GIT-BRANCH-EXISTS? BRANCH T))
+           (ERROR BRANCH "is not a git branch"))
+    (CL:WHEN (STRING-EQUAL BRANCH (GIT-WHICH-BRANCH))
+           (ERROR BRANCH "is the current branch"))
+    (LET (LINES LOCALBRANCH)
+         [SETQ LINES (GIT-COMMAND (IF (EQ 1 (STRPOS "origin/" BRANCH))
+                                      THEN [SETQ LOCALBRANCH (SUBSTRING BRANCH
+                                                                    (CONSTANT (ADD1 (NCHARS "origin/"
+                                                                                           ]
+                                           (CONCAT "git worktree add --guess-remote " (WORKTREEDIR
+                                                                                       LOCALBRANCH)
+                                                  " " BRANCH)
+                                    ELSE (CONCAT "git worktree add " (WORKTREEDIR BRANCH)
+                                                " " BRANCH]
+         (CL:UNLESS (STRPOS "Preparing worktree" (CAR LINES)
+                           1 NIL T)
+                (ERROR "Could not create worktree for " BRANCH))
+         BRANCH])
+
+(GIT-REMOVE-WORKTREE
+  [LAMBDA (BRANCH)                                          (* ; "Edited 17-Nov-2021 10:02 by rmk:")
+    (GIT-BRANCH-EXISTS? BRANCH)
+    (LET ((DIR (WORKTREEDIR BRANCH))
+          LINES)
+         (SETQ LINES (GIT-COMMAND (CONCAT "git worktree remove " DIR)))
+         (CL:WHEN (STRPOS "fatal: " (CAR LINES)
+                         1 NIL T)
+                (ERROR "Could not remove worktree for " BRANCH))
+         (AND NIL (DELFILE (CONCAT PATH "/.DS_Store"))
+              (GIT-COMMAND (CONCAT "rmdir " DIR)))
+         BRANCH])
+
+(GIT-LIST-WORKTREES
+  [LAMBDA NIL                                                (* ; "Edited 12-Dec-2021 12:13 by rmk")
+                                                             (* ; "Edited 19-Nov-2021 18:53 by rmk:")
+
+    (* ;; "The git command tells us what the clone thinks about it, but then we look to see what is actually in our worktrees directory, to make sure that the subdirectory wasn't deleted in a wy that the clone didn't know about.")
+
+    (SORT (FOR L POS IN (GIT-COMMAND "git worktree list")
+             WHEN (AND (SETQ POS (STRPOS "/worktrees/" L NIL NIL NIL T))
+                       (STRPOS "(detached HEAD)" L)) COLLECT (SETQ L (SUBSTRING L POS))
+                                                           (SUBATOM L 1 (SUB1 (STRPOS " " L])
+
+(WORKTREEDIR
+  [LAMBDA (BRANCH)                                           (* ; "Edited 18-Jan-2022 15:02 by rmk")
+                                                             (* ; "Edited 25-Nov-2021 08:49 by rmk:")
+                                                             (* ; "Edited 19-Nov-2021 20:56 by rmk:")
+                                                             (* ; "Edited 17-Nov-2021 10:00 by rmk:")
+    (CONCAT GITMEDLEYDIR "../worktrees/" (IF BRANCH
+                                             THEN "/"
+                                           ELSE ""])
+)
+
+
+
+(* ;; "")
+
+
+
+
+(* ;; "Comparisons")
+
+(DEFINEQ
+
+(GIT-GET-DIFFERENT-FILES
+  [LAMBDA (BRANCH1 BRANCH2 DIR1 DIR2)                        (* ; "Edited 23-Jan-2022 21:45 by rmk")
+                                                             (* ; "Edited 11-Jan-2022 11:03 by rmk")
+                                                             (* ; "Edited  5-Jan-2022 08:01 by rmk")
+
+    (* ;; "Ask git for the files that differ between the branches, copy those files down to local DIR1 and DIR2, return the directories.")
+
+    (SETQ BRANCH1 (GIT-BRANCH-EXISTS? BRANCH1))
+    (SETQ BRANCH2 (GIT-BRANCH-EXISTS? BRANCH2))
+    (LET ([MERGE (CAR (GIT-COMMAND (CONCAT "git merge-base " BRANCH1 " " BRANCH2]
+          (DATE (DATE))
+          DIFFS)
+         (SETQ DIFFS (GIT-BRANCH-DIFF BRANCH1 MERGE))
+         (CL:WHEN DIFFS
+             (PSEUDOHOST 'FROMGIT (CONCAT "{core}<gitfiles>" DATE ">"))
+             (CL:UNLESS DIR1
+                 (SETQ DIR1 (CONCAT "{FROMGIT}<" (UNSLASHIT BRANCH1)
+                                   ">")))
+             (CL:UNLESS DIR2
+                 (SETQ DIR2 (CONCAT "{FROMGIT}<" (UNSLASHIT BRANCH2)
+                                   ">")))
+             [FOR GFILE MFILE IN DIFFS DO 
+                                          (* ;; "Unslash because CORE doesn't know about /. ")
+
+                                          (SETQ MFILE (UNSLASHIT (CONCAT DIR1 GFILE)))
+                                          (CL:WHEN (GIT-GET-FILE BRANCH1 GFILE MFILE)
+                                              (FIX-DIRECTORY-DATES (CONS MFILE)))
+                                          (SETQ MFILE (UNSLASHIT (CONCAT DIR2 GFILE)))
+                                          (CL:WHEN (GIT-GET-FILE MERGE GFILE MFILE)
+                                              (FIX-DIRECTORY-DATES (CONS MFILE)))]
+             (LIST DIR1 DIR2))])
+
+(GIT-COMPARE-BRANCHES
+  [LAMBDA (BRANCH1 BRANCH2 LOCAL)                            (* ; "Edited 26-Jan-2022 13:42 by rmk")
+                                                             (* ; "Edited 11-Jan-2022 11:10 by rmk")
+                                                             (* ; "Edited  6-Jan-2022 13:05 by rmk")
+                                                             (* ; "Edited  4-Jan-2022 22:52 by rmk")
+                                                             (* ; "Edited 22-Dec-2021 16:14 by rmk")
+                                                             (* ; "Edited 16-Dec-2021 11:18 by rmk")
+    (SETQ BRANCH1 (IF BRANCH1
+                      THEN (GITORIGIN BRANCH1 LOCAL)
+                    ELSE (GIT-WHICH-BRANCH)))
+    (SETQ BRANCH2 (GITORIGIN (OR BRANCH2 "master")
+                         LOCAL))
+    (PRINTOUT T "Comparing all subdirectories of " BRANCH1 " and " BRANCH2 T)
+    (LET (CDVALUE DIRS)
+         (PRINTOUT T "Fetching differences" T)
+         (SETQ DIRS (GIT-GET-DIFFERENT-FILES BRANCH1 BRANCH2))
+         (IF DIRS
+             THEN (TERPRI T)
+                  (SETQ CDVALUE (COMPAREDIRECTORIES (CAR DIRS)
+                                       (CADR DIRS)
+                                       '(> < ~= -* *-)
+                                       '*>*.*))
+                  (TERPRI T)
+                  (IF (FETCH (CDVALUE CDENTRIES) OF CDVALUE)
+                      THEN 
+                           (* ;; 
+                        "Lower case the directories.  Perhaps can be done when the files are gotten?")
+
+                           [FOR CDE INFO IN (FETCH (CDVALUE CDENTRIES) OF CDVALUE)
+                              DO (CL:WHEN (SETQ INFO (FETCH INFO1 OF CDE))
+                                     (CHANGE (FETCH (CDINFO FULLNAME) OF INFO)
+                                            (SLASHIT DATUM T)))
+                                 (CL:WHEN (SETQ INFO (FETCH INFO2 OF CDE))
+                                     (CHANGE (FETCH (CDINFO FULLNAME) OF INFO)
+                                            (SLASHIT DATUM T)))]
+                           (CDBROWSER CDVALUE (CONCAT "Compare " BRANCH1 " and " BRANCH2 "      "
+                                                     (LENGTH (FETCH (CDVALUE CDENTRIES) OF CDVALUE))
+                                                     " files")
+                                  (LIST BRANCH1 BRANCH2)
+                                  `(LABELFN GIT-CD-LABELFN BRANCH1 ,BRANCH1 BRANCH2 ,BRANCH2)
+                                  NIL
+                                  `(Compare "" (,(CONCAT "See " BRANCH1)
+                                                CD-MENUFN See% left)
+                                          (,(CONCAT "See " BRANCH2)
+                                           CD-MENUFN See% right)
+                                          See% both))
+                    ELSE "NO DIFFERENCES")
+           ELSE "NO DIFFERENCES"])
+
+(GIT-COMPARE-WITH-MYMEDLEY
+  [LAMBDA (SUBDIRS SELECT EXCLUDEDFILES TEDIT FIXDIRECTORYDATES UPDATE)
+
+    (* ;; 
+    "Edited 26-Jan-2022 22:53 by rmk: my medley subdirectories with the current local git branch.")
+
+    (* ;; "Compares my medley subdirectories with the current local git branch.")
+
+    (CL:WHEN UPDATE (GIT-REMOTE-UPDATE))                     (* ; "Doesn't matter if we are looking only at local files in the current branch.  We aren't fetching or checking out.")
+    (CL:WHEN (AND (LISTP SUBDIRS)
+                  (NULL (CDR SUBDIRS)))
+        (SETQ SUBDIRS (CAR SUBDIRS)))
+    (SETQ SUBDIRS (L-CASE SUBDIRS))
+    (PRINTOUT T "Comparing " (SELECTQ SUBDIRS
+                                 (nil (SETQ SUBDIRS '(sources library lispusers)))
+                                 (all (SETQ SUBDIRS MEDLEYSUBDIRS)
+                                      "ALL subdirectories")
+                                 SUBDIRS)
+           " of My Medley and "
+           (GIT-WHICH-BRANCH)
+           T)
+    (for SUBDIR TITLE CDVAL (BRANCH2 _ (GIT-WHICH-BRANCH)) INSIDE SUBDIRS
+       collect (TERPRI T)
+             (SETQ CDVAL (COMPAREDIRECTORIES (MEDLEYSUBDIR SUBDIR T)
+                                (GITSUBDIR SUBDIR T)
+                                (OR SELECT '(> < ~= -* *-))
+                                NIL GIT-IGNORE-FILES NIL NIL NIL FIXDIRECTORYDATES))
+             [FOR CDE IN (FETCH CDENTRIES OF CDVAL)
+                DO (CL:WHEN (FETCH INFO1 OF CDE)
+                       (CHANGE (FETCH (CDINFO FULLNAME) OF (FETCH INFO1 OF CDE))
+                              (UNSLASHIT DATUM T)))
+                   (CL:WHEN (FETCH INFO2 OF CDE)
+                       (CHANGE (FETCH (CDINFO FULLNAME) OF (FETCH INFO2 OF CDE))
+                              (SLASHIT DATUM T)))]
+             CDVAL
+       finally
+
+       (* ;; "Set up the browsers after everything has been done, otherwise if the user doesn't pay attention it might hang waiting for a region.")
+
+       (CL:WHEN (AND (CDR $$VAL)
+                     GIT-MERGE-COMPARES)
+           (SETQ $$VAL (CDMERGE $$VAL))
+           [SETQ SUBDIRS (CONCATLIST (FOR SUBDIR IN SUBDIRS COLLECT (CONCAT SUBDIR "  "])
+       (RETURN
+        (for CDVAL TITLE IN $$VAL as SUBDIR inside SUBDIRS
+           collect (SETQ TITLE (CONCAT "Compare  My Medley  and  " BRANCH2 "      " SUBDIR 
+                                      "         " (LENGTH (fetch (CDVALUE CDENTRIES) of CDVAL))
+                                      " files"))
+                 [if TEDIT
+                     then [CDTEDIT CDVAL TITLE `("My Medley" ,BRANCH2]
+                   else (CDBROWSER CDVAL TITLE `("My Medley" ,BRANCH2)
+                               `(BRANCH1 "My Medley" BRANCH2 ,BRANCH2 SUBDIR ,SUBDIR LABELFN 
+                                       GIT-CD-LABELFN)
+                               NIL
+                               `(Compare "" ("See My Medley" CD-MENUFN See% left)
+                                       (,(CONCAT "See " BRANCH2)
+                                        CD-MENUFN See% right)
+                                       See% both "" (Copy% <- GIT-CD-MENUFN)
+                                       (|Delete ALL <-| GIT-CD-MENUFN)
+                                       ,@(CL:UNLESS (STRPOS "master" BRANCH2)
+                                             '("" (Copy% -> GIT-CD-MENUFN)
+                                                  (Delete% -> GIT-CD-MENUFN)))]
+                 (CONS (CONCAT SUBDIR "/")
+                       (for CDENTRY in (fetch CDENTRIES of CDVAL) collect (fetch MATCHNAME
+                                                                             of CDENTRY)))
+           finally (TERPRI T])
+
+(GIT-COMPARE-WORKTREE
+  [LAMBDA (BRANCH DONTUPDATE)                               (* ; "Edited 25-Nov-2021 08:49 by rmk:")
+                                                            (* ; "Edited 19-Nov-2021 21:54 by rmk:")
+    (PRINTOUT T T "Comparing origin/" BRANCH " and origin/master" T)
+    (CL:UNLESS DONTUPDATE
+        (GIT-ADD-WORKTREE BRANCH T)
+        (GIT-ADD-WORKTREE "master" T))
+    (LET (ADDEDFILES DELETEDFILES SOURCEFILES COMPILEDFILES OTHERFILES)
+         (FOR FILE BFILE MFILE IN (GIT-BRANCH-DIFF BRANCH 'origin/master)
+            DO (SETQ BFILE (INFILEP (CONCAT (WORKTREEDIR BRANCH)
+                                           FILE)))
+               (SETQ MFILE (INFILEP (CONCAT (WORKTREEDIR 'master)
+                                           FILE)))
+               (IF (AND BFILE MFILE)
+                   THEN (IF (NOT (LISPSOURCEFILEP BFILE))
+                            THEN (PUSH OTHERFILES FILE)
+                          ELSEIF (MEMB (U-CASE (FILENAMEFIELD BFILE 'EXTENSION))
+                                       *COMPILED-EXTENSIONS*)
+                            THEN (PUSH COMPILEDFILES FILE)
+                          ELSE (PUSH SOURCEFILES FILE))
+                 ELSEIF BFILE
+                   THEN (PUSH ADDEDFILES FILE)
+                 ELSE (PUSH DELETEDFILES FILE)))
+         (CL:WHEN ADDEDFILES
+             (PRINTOUT T T "Added files: " T)
+             (FOR F IN (SORT ADDEDFILES) DO (PRINTOUT T 2 F T)))
+         (CL:WHEN DELETEDFILES
+             (PRINTOUT T T "Deleted files: " T)
+             (FOR F IN (SORT ADDEDFILES) DO (PRINTOUT T 2 F T)))
+         (CL:WHEN SOURCEFILES
+             (PRINTOUT T T "Changed Medley source files:" T)
+             (FOR FILETAIL FILE BFILE MFILE ON (SORT SOURCEFILES)
+                DO (SETQ FILE (CAR FILETAIL))
+                   (PRINTOUT T 2 FILE T)
+                   (SETQ FILE (CAR FILETAIL))
+                   (SETQ BFILE (INFILEP (CONCAT (WORKTREEDIR BRANCH)
+                                               FILE)))
+                   (SETQ MFILE (INFILEP (CONCAT (WORKTREEDIR 'master)
+                                               FILE)))
+                   (COMPARESOURCES-TEDIT BFILE MFILE)
+                   (TTY.PROCESS T)
+                   (CL:WHEN (OR OTHERFILES (CDR FILETAIL))
+                          (WAITFORINPUT))))
+         (CL:WHEN COMPILEDFILES
+             (PRINTOUT T T "Medley compiled files, no comparisons:")
+             (FOR F IN COMPILEDFILES DO (PRINTOUT T 2 F T)))
+         (CL:WHEN OTHERFILES
+             (PRINTOUT T T "Other changed files, using TEDIT-SEE")
+             (FOR FILETAIL FILE BFILE MFILE ON (SORT OTHERFILES)
+                DO (SETQ FILE (CAR FILETAIL))
+                   (PRINTOUT T 2 FILE)
+                   (SETQ FILE (CAR FILETAIL))
+                   (SETQ BFILE (INFILEP (CONCAT (WORKTREEDIR BRANCH)
+                                               FILE)))
+                   (SETQ MFILE (INFILEP (CONCAT (WORKTREEDIR 'master)
+                                               FILE)))
+                   (COMPARETEXT BFILE MFILE 'LINE)
+                   (AND NIL (TEDIT-SEE BFILE)
+                        (TEDIT-SEE MFILE))
+                   (TTY.PROCESS T)
+                   (CL:WHEN (CDR FILETAIL)
+                          (WAITFORINPUT))))])
+
+(GITCDOBJBUTTONFN
+  [LAMBDA (OBJ WINDOW)                                       (* ; "Edited 20-Dec-2021 09:57 by rmk")
+                                                             (* ; "Edited 15-Dec-2021 20:47 by rmk")
+                                                             (* ; "Edited 27-Nov-2021 12:19 by rmk:")
+                                                             (* ; "Edited 26-Nov-2021 08:51 by rmk:")
+                                                             (* ; "Edited 23-Nov-2021 12:39 by rmk:")
+                                                             (* ; "Edited  8-Nov-2021 08:46 by rmk:")
+    (LET
+     ([CDENTRY (CAR (IMAGEOBJPROP OBJ 'OBJECTDATUM]
+      (BRANCH1 (WINDOWPROP WINDOW 'BRANCH1))
+      (FONT (FONTCREATE 'TERMINAL 10))
+      COPYITEM COMPAREITEMS TYPE INFO1 INFO2)
+     (CL:WHEN (AND CDENTRY (CADR (IMAGEOBJPROP OBJ 'OBJECTDATUM))
+                   (EQ LASTKEYBOARD 0))
+         (SETQ INFO1 (FETCH (CDENTRY INFO1) OF CDENTRY))
+         (SETQ INFO2 (FETCH (CDENTRY INFO2) OF CDENTRY))
+         [IF (MOUSESTATE (ONLY LEFT))
+             THEN
+             [SETQ COMPAREITEMS
+              (IF (AND INFO1 INFO2)
+                  THEN [IF (EQ (SETQ TYPE (FETCH (CDINFO TYPE) OF INFO1))
+                               (FETCH (CDINFO TYPE) OF INFO2))
+                           THEN (SELECTQ TYPE
+                                    (SOURCE [LIST (LIST "Compare sources?" ''COMPARESOURCES)
+                                                  (LIST "Examine sources?" ''EXAMINE])
+                                    (COMPILED)
+                                    (TEXT (LIST (CONCAT "Compare text files?")
+                                                ''TEXT))
+                                    (IF (MEMB (U-CASE (FILENAMEFIELD (FETCH (CDINFO FULLNAME)
+                                                                        OF INFO1)))
+                                              '(TEXT TXT))
+                                        THEN [LIST (LIST "Compare text files?" (KWOTE TYPE)
+                                                         ''COMPARETEXT]
+                                      ELSE (LIST (LIST (CONCAT "See " TYPE " files?")
+                                                       (KWOTE TYPE]
+                ELSEIF (OR INFO1 INFO2)
+                  THEN (LIST (LIST "Show file?" ''TEDIT]
+           ELSEIF [AND (MOUSESTATE (ONLY MIDDLE))
+                       (NOT (WINDOWPROP WINDOW 'READONLY]
+             THEN (SETQ COPYITEM (CONS (SELECTQ (CADDR (IMAGEOBJPROP OBJ 'OBJECTDATUM))
+                                           (LEFT (LIST (CONCAT "Copy TO git " (GIT-WHICH-BRANCH)
+                                                              "?")
+                                                       ''TOGIT))
+                                           (RIGHT (LIST (CONCAT "Copy FROM git " (GIT-WHICH-BRANCH)
+                                                               "?")
+                                                        ''FROMGIT))
+                                           NIL]
+         (CL:WHEN (OR COPYITEM COMPAREITEMS)
+             (SELECTQ (MENU (CREATE MENU
+                                   TITLE _ (CONCAT (WINDOWPROP WINDOW 'SUBDIR)
+                                                  "/"
+                                                  (FETCH MATCHNAME OF CDENTRY))
+                                   ITEMS _ (APPEND COPYITEM COMPAREITEMS)
+                                   MENUFONT _ FONT
+                                   MENUTITLEFONT _ FONT))
+                 (TOGIT (CL:WHEN (TOGIT (FETCH (CDINFO FULLNAME) OF INFO1)
+                                        WINDOW)
+                            (IMAGEOBJPROP OBJ 'COPIED T)
+                            (REDISPLAYW WINDOW)
+                            (CDOBJ.DISPLAYFN OBJ WINDOW)))
+                 (FROMGIT (CL:WHEN (FROMGIT (FETCH (CDINFO FULLNAME) OF INFO2)
+                                          WINDOW)
+                              (IMAGEOBJPROP OBJ 'COPIED T)
+                              (AND NIL (REDISPLAYW WINDOW))))
+                 (COMPARESOURCES 
+                      (TTY.PROCESS T)
+                      (CSBROWSER (fetch (CDINFO FULLNAME) OF INFO1)
+                             (fetch (CDINFO FULLNAME) OF INFO2)))
+                 (COMPARETEXT (TTY.PROCESS T)
+                              (COMPARETEXT (FETCH (CDINFO FULLNAME) OF INFO1)
+                                     (FETCH (CDINFO FULLNAME) OF INFO2)
+                                     'PARA))
+                 (TEDIT (CL:WHEN INFO1
+                            (TEDIT-SEE (FETCH (CDINFO FULLNAME) OF INFO1)))
+                        (CL:WHEN INFO2
+                            (TEDIT-SEE (FETCH (CDINFO FULLNAME) OF INFO2))))
+                 NIL)))])
+
+(GIT-CD-LABELFN
+  [LAMBDA (FILE1 FILE2 USERDATA)                             (* ; "Edited  5-Jan-2022 15:10 by rmk")
+                                                             (* ; "Edited 16-Dec-2021 12:25 by rmk")
+                                                             (* ; "Edited 13-Dec-2021 22:13 by rmk")
+    (DECLARE (USEDFREE CDVALUE))
+    (LET (NC B LABEL1 LABEL2)
+         (CL:WHEN (SETQ NC (FETCH NCDIR OF (FETCH CDMAXNC1 OF CDVALUE)))
+             (SETQ LABEL1 (SLASHIT (SUBSTRING FILE1 (ADD1 NC))
+                                 T))
+             (CL:WHEN (SETQ B (LISTGET USERDATA 'BRANCH1))
+                 (SETQ LABEL1 (CONCAT B "/" LABEL1))))
+         (CL:WHEN (SETQ NC (FETCH NCDIR OF (FETCH CDMAXNC2 OF CDVALUE)))
+             (SETQ LABEL2 (SLASHIT (SUBSTRING FILE2 (ADD1 NC))
+                                 T))
+             (CL:WHEN (SETQ B (LISTGET USERDATA 'BRANCH2))
+                 (SETQ LABEL2 (CONCAT B "/" LABEL2))))
+         (LIST (OR LABEL1 FILE1)
+               (OR LABEL2 FILE2])
+
+(GIT-CD-MENUFN
+  [LAMBDA (TBITEM MENUITEM CDBROWSER KEY)                    (* ; "Edited 19-Dec-2021 23:28 by rmk")
+                                                             (* ; "Edited 16-Dec-2021 13:49 by rmk")
+                                                             (* ; "Edited 10-Dec-2021 08:52 by rmk")
+
+    (* ;; "MENUITEM is of the form (display-atom <this function> . extrainfo).  The selector for the selectq is either the CAR of the extrainfo or the display atom")
+
+    (DECLARE (USEDFREE FILE1 FILE2 LABEL2 TYPE CDENTRY))
+    (SELECTQ (OR (CADDR MENUITEM)
+                 (CAR MENUITEM))
+        (Copy% -> (CL:WHEN (CAR (TOGIT FILE1))
+                         (TB.DELETE.ITEM CDBROWSER TBITEM)))
+        (Copy% <- (CL:WHEN (CAR (FROMGIT FILE2))
+                         (TB.DELETE.ITEM CDBROWSER TBITEM)))
+        (Delete% -> (FLASHWINDOW PWINDOW)
+                    (IF FILE1
+                        THEN (PRIN3 "Use 'Delete BOTH' instead")
+                      ELSE (GIVE.TTY.PROCESS PWINDOW)
+                           (CL:WHEN (EQ 'Y (ASKUSER NIL 'N (CONCAT "Delete " LABEL2 " ? ")))
+                               (GIT-DELETE-FILE FILE2)
+                               (TB.DELETE.ITEM CDBROWSER TBITEM))))
+        (|Delete ALL <-| 
+             (FLASHWINDOW PWINDOW)
+             (IF FILE2
+                 THEN (PRIN3 "Use 'Delete BOTH' instead")
+               ELSE (GIVE.TTY.PROCESS PWINDOW)
+                    (CL:WHEN (EQ 'Y (ASKUSER NIL 'N (CONCAT "Delete ALL versions of "
+                                                           (NAMEFIELD LABEL1 T)
+                                                           " ? ")))
+                        (MYMEDLEY-DELETE-FILES FILE1)
+                        (TB.DELETE.ITEM CDBROWSER TBITEM))))
+        (Delete% BOTH (FLASHWINDOW PWINDOW)
+                      (GIVE.TTY.PROCESS PWINDOW)
+                      (CL:WHEN (EQ 'Y (ASKUSER NIL 'N (CONCAT 
+                                                             "Delete all Medley and git versions of "
+                                                             (NAMEFIELD LABEL1 T)
+                                                             " ? ")))
+                          (GIT-DELETE-FILE FILE2)
+                          (MYMEDLEY-DELETE-FILES FILE1)
+                          (TB.DELETE.ITEM CDBROWSER TBITEM)))
+        (SHOULDNT])
+)
+
+
+
+(* ;; "")
+
+
+
+
+(* ;; "Utilities")
+
+(DEFINEQ
+
+(CDGITDIR
+  [LAMBDA NIL                                                (* ; "Edited 18-Jan-2022 15:37 by rmk")
+                                                             (* ; "Edited 16-Nov-2021 10:16 by rmk:")
+                                                             (* ; "Edited  2-Nov-2021 21:12 by rmk:")
+
+    (* ;; "Strips off {UNIX}")
+
+    (CONCAT "cd " (STRIPHOST GITMEDLEYDIR)
+           "; "])
+
+(GIT-COMMAND
+  [LAMBDA (CMD ALL NOERROR)                                  (* ; "Edited  3-Jan-2022 10:47 by rmk")
+                                                             (* ; "Edited 24-Nov-2021 16:44 by rmk:")
+                                                             (* ; "Edited 16-Nov-2021 09:07 by rmk:")
+                                                             (* ; "Edited  2-Nov-2021 21:08 by rmk:")
+                                                             (* ; "Edited  7-Oct-2021 11:15 by rmk:")
+
+    (* ;; "Suppress .git lines unless ALL")
+
+    (CL:UNLESS (EQ 1 (STRPOS "git" CMD))
+        (SETQ CMD (CONCAT "git " CMD)))
+    [BIND LPOS WHILE (SETQ LPOS (STRPOS "local/" CMD))
+       DO (SETQ CMD (CONCAT (SUBSTRING CMD 1 (SUB1 LPOS))
+                           (SUBSTRING CMD (IPLUS LPOS (NCHARS "local/"]
+    (CL:WITH-OPEN-FILE (STREAM "{NODIRCORE}shell-dribble.txt" :DIRECTION :IO)
+           (ShellCommand (CONCAT (CDGITDIR)
+                                CMD)
+                  STREAM)
+           (SETFILEPTR STREAM 0)
+           (BIND LINE UNTIL (EOFP STREAM)
+              WHEN [PROGN (SETQ LINE (CL:READ-LINE STREAM :EOF-ERROR-P NIL :EOF-VALUE NIL))
+                          (OR ALL (NOT (STRPOS ".git" LINE 1 NIL T] COLLECT LINE
+              FINALLY (CL:UNLESS NOERROR
+                          (CL:WHEN (STRPOS "fatal" (CAR $$VAL))
+                              (ERROR (CONCAT "Git command %"" CMD "%" failed")
+                                     (CAR $$VAL))))])
+
+(GITORIGIN
+  [LAMBDA (BRANCH LOCAL)                                    (* ; "Edited 25-Nov-2021 08:47 by rmk:")
+                                                            (* ; "Edited 22-Nov-2021 17:29 by rmk:")
+
+    (* ;; "Insures origin/ unless LOCAL or local/ already")
+
+    (CL:UNLESS BRANCH (SETQ BRANCH "master"))
+    (IF (OR (STRPOS "origin/" BRANCH)
+            (STRPOS "local/" BRANCH))
+        THEN BRANCH
+      ELSE (CONCAT (CL:IF LOCAL
+                       "local/"
+                       "origin/")
+                  BRANCH])
+
+(GIT-INITIALS
+  [LAMBDA NIL                                                (* ; "Edited 19-Jan-2022 13:18 by rmk")
+    (OR (CL:IF (EQ (CHARCODE %:)
+                   (NTHCHARCODE INITIALS -1))
+            (SUBSTRING INITIALS 1 -2)
+            INITIALS)
+        (ERROR "INITIALS is not set"])
+)
+(DECLARE%: DONTCOPY
+  (FILEMAP (NIL (4688 9814 (TOGIT 4698 . 6617) (FROMGIT 6619 . 7478) (GIT-DELETE-FILE 7480 . 8374) (
+MYMEDLEY-DELETE-FILES 8376 . 9812)) (9815 11456 (MEDLEYSUBDIR 9825 . 10265) (GITSUBDIR 10267 . 10843) 
+(STRIPDIR 10845 . 11216) (STRIPHOST 11218 . 11454)) (11457 13394 (GFILE4MFILE 11467 . 12138) (
+MFILE4GFILE 12140 . 12693) (GIT-REPO-FILENAME 12695 . 13392)) (13395 15729 (MEDLEYSUBDIRS 13405 . 
+14373) (GITSUBDIRS 14375 . 15727)) (15856 22350 (GIT-COMMIT 15866 . 16444) (GIT-PUSH 16446 . 17002) (
+GIT-PULL 17004 . 17410) (GIT-BRANCH-DIFF 17412 . 18607) (GIT-APPROVAL 18609 . 18810) (GIT-GET-FILE 
+18812 . 19916) (GIT-FILE-EXISTS? 19918 . 20797) (GIT-REMOTE-UPDATE 20799 . 21841) (GIT-FILE-DATE 21843
+ . 22348)) (22395 26572 (GIT-CHECKOUT 22405 . 22646) (GIT-WHICH-BRANCH 22648 . 23232) (GIT-MAKE-BRANCH
+ 23234 . 24725) (GIT-BRANCHES 24727 . 25507) (GIT-BRANCH-EXISTS? 25509 . 26570)) (26602 29307 (
+GIT-MY-CURRENT-BRANCH 26612 . 26785) (GIT-MY-BRANCHP 26787 . 27706) (GIT-MY-NEXT-BRANCH 27708 . 28149)
+ (GIT-MY-BRANCHES 28151 . 29305)) (29353 33123 (GIT-ADD-WORKTREE 29363 . 31123) (GIT-REMOVE-WORKTREE 
+31125 . 31703) (GIT-LIST-WORKTREES 31705 . 32509) (WORKTREEDIR 32511 . 33121)) (33171 54106 (
+GIT-GET-DIFFERENT-FILES 33181 . 35051) (GIT-COMPARE-BRANCHES 35053 . 38191) (GIT-COMPARE-WITH-MYMEDLEY
+ 38193 . 42091) (GIT-COMPARE-WORKTREE 42093 . 45570) (GITCDOBJBUTTONFN 45572 . 50576) (GIT-CD-LABELFN 
+50578 . 51660) (GIT-CD-MENUFN 51662 . 54104)) (54152 57051 (CDGITDIR 54162 . 54594) (GIT-COMMAND 54596
+ . 56164) (GITORIGIN 56166 . 56743) (GIT-INITIALS 56745 . 57049)))))
+STOP
diff --git a/lispusers/GITFNS.LCOM b/lispusers/GITFNS.LCOM
new file mode 100644
index 00000000..32563473
Binary files /dev/null and b/lispusers/GITFNS.LCOM differ
diff --git a/lispusers/GITFNS.TEDIT b/lispusers/GITFNS.TEDIT
new file mode 100644
index 00000000..21ecd5e6
Binary files /dev/null and b/lispusers/GITFNS.TEDIT differ
diff --git a/lispusers/PSEUDOHOSTS b/lispusers/PSEUDOHOSTS
new file mode 100644
index 00000000..1bd602d9
--- /dev/null
+++ b/lispusers/PSEUDOHOSTS
@@ -0,0 +1,438 @@
+(DEFINE-FILE-INFO PACKAGE "INTERLISP" READTABLE "INTERLISP" BASE 10)
+
+(FILECREATED "27-Jan-2022 12:35:16" 
+{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>PSEUDOHOSTS.;119 22617  
+
+      :CHANGES-TO (VARS PSEUDOHOSTSCOMS)
+
+      :PREVIOUS-DATE "26-Jan-2022 23:33:17" 
+{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>PSEUDOHOSTS.;118)
+
+
+(PRETTYCOMPRINT PSEUDOHOSTSCOMS)
+
+(RPAQQ PSEUDOHOSTSCOMS
+       [
+        (* ;; "Public entries")
+
+        (FNS PSEUDOHOST PSEUDOHOSTP PSEUDOHOSTS TARGETHOST TRUEFILENAME)
+        
+        (* ;; "Internals")
+
+        (FNS EXPAND.PH CONTRACT.PH SLASHIT UNSLASHIT)
+        (FNS OPENFILE.PH GETFILENAME.PH DIRECTORYNAMEP.PH CLOSEFILE.PH REOPENFILE.PH DELETEFILE.PH 
+             OPENP.PH UNREGISTERFILE.PH REGISTERFILE.PH GENERATEFILES.PH GETFILEINFO.PH 
+             SETFILEINFO.PH NEXTFILEFN.PH FILEINFOFN.PH RENAMEFILE.PH)
+        (P (PSEUDOHOST 'LI LOGINHOST/DIR))
+        (DECLARE%: EVAL@COMPILE DONTCOPY (RECORDS PHDEVICE PHGENFILESTATE)
+               (MACROS PSEUDOHOST.NAME PSEUDOHOST.TARGETVAL)
+               (P (CL:UNLESS (GETP 'EXPORTS.ALL 'FILE)
+                      (LOAD 'EXPORTS.ALL))])
+
+
+
+(* ;; "Public entries")
+
+(DEFINEQ
+
+(PSEUDOHOST
+  [LAMBDA (HOST PREFIX)                                      (* ; "Edited 25-Jan-2022 09:58 by rmk")
+                                                             (* ; "Edited 23-Jan-2022 20:43 by rmk")
+                                                             (* ; "Edited 18-Jan-2022 13:08 by rmk")
+    (CL:WHEN (AND (LISTP HOST)
+                  (NULL PREFIX))
+        (SETQ PREFIX (CADR HOST))
+        (SETQ HOST (CAR HOST)))
+    (SETQ HOST (U-CASE (MKATOM HOST)))
+    (IF PREFIX
+        THEN (CL:UNLESS (FILENAMEFIELD PREFIX 'HOST)
+                 (SETQ PREFIX (UNSLASHIT (PACKFILENAME 'HOST 'DSK 'BODY PREFIX))))
+             (CL:UNLESS (MEMB (NTHCHARCODE PREFIX -1)
+                              (CHARCODE (> / <)))
+                 (SETQ PREFIX (CONCAT PREFIX (IF (STRPOS "/" PREFIX)
+                                                 THEN "/"
+                                               ELSE ">"))))
+             [LET (PREVIOUS TARGETHOST TARGETDEVICE)
+                  (CL:WHEN (SETQ PREVIOUS (PSEUDOHOSTP HOST))(* ; 
+                                                       "Redefining: first clear out the previous one")
+                      (PSEUDOHOST HOST NIL))
+                  [SETQ TARGETHOST (U-CASE (FILENAMEFIELD PREFIX 'HOST]
+
+                  (* ;; "We know about the directory separators for these particular devices.  Maybe there should be separate list of slash-hosts somewhere that we can use.")
+
+                  (SELECTQ TARGETHOST
+                      ((DSK CORE) 
+                           (SETQ PREFIX (UNSLASHIT PREFIX)))
+                      (UNIX (SETQ PREFIX (SLASHIT PREFIX)))
+                      NIL)
+                  (SETQ TARGETDEVICE (OR (\GETDEVICEFROMHOSTNAME TARGETHOST)
+                                         (ERROR "UNKNOWN TARGET HOST" TARGETHOST)))
+
+                  (* ;; "Save the last directory marker to pack on if needed.")
+
+                  (\DEFINEDEVICE HOST (CREATE FDEV
+                                         USING TARGETDEVICE DEVICENAME _ HOST FDEV1 _ TARGETDEVICE 
+                                               FDEV2 _ (CONS PREFIX (CL:IF (EQ (CHARCODE /)
+                                                                               (NTHCHARCODE PREFIX -1
+                                                                                      ))
+                                                                        '/
+                                                                        '<))
+                                               OPENFILE _ (FUNCTION OPENFILE.PH)
+                                               GETFILENAME _ (FUNCTION GETFILENAME.PH)
+                                               DIRECTORYNAMEP _ (FUNCTION DIRECTORYNAMEP.PH)
+                                               CLOSEFILE _ (FUNCTION CLOSEFILE.PH)
+                                               REOPENFILE _ (FUNCTION REOPENFILE.PH)
+                                               DELETEFILE _ (FUNCTION DELETEFILE.PH)
+                                               OPENP _ (FUNCTION OPENP.PH)
+                                               UNREGISTERFILE _ (FUNCTION UNREGISTERFILE.PH)
+                                               REGISTERFILE _ (FUNCTION REGISTERFILE.PH)
+                                               GENERATEFILES _ (FUNCTION GENERATEFILES.PH)
+                                               GETFILEINFO _ (FUNCTION GETFILEINFO.PH)
+                                               SETFILEINFO _ (FUNCTION SETFILEINFO.PH)
+                                               RENAMEFILE _ (FUNCTION RENAMEFILE.PH]
+      ELSEIF (PSEUDOHOSTP HOST)
+        THEN (UNINTERRUPTABLY
+                 
+                 (* ;; "\DEFINEDEVICE removes the name-mapping but doesn't remove the device.  Maybe that's on purpose for other devices, but not here.")
+
+                 (SETQ \FILEDEVICES (DREMOVE (\GETDEVICEFROMNAME HOST \FILEDEVICES)
+                                           \FILEDEVICES))
+                 (\DEFINEDEVICE HOST NIL))
+      ELSE (ERROR HOST "is not a pseudohost"))
+    HOST])
+
+(PSEUDOHOSTP
+  [LAMBDA (HOST)                                             (* ; "Edited 18-Jan-2022 11:29 by rmk")
+    (LET ((DEV (\GETDEVICEFROMNAME HOST T T)))
+         (CL:WHEN (AND DEV (TYPE? FDEV (FETCH (PHDEVICE TARGETDEV) OF DEV)))
+             (LIST HOST (FETCH (PHDEVICE PREFIX)
+                               DEV)))])
+
+(PSEUDOHOSTS
+  [LAMBDA NIL                                                (* ; "Edited 17-Jan-2022 18:15 by rmk")
+    (FOR DEV IN \FILEDEVICES WHEN (TYPE? FDEV (FETCH (PHDEVICE TARGETDEV) OF DEV))
+       COLLECT (LIST (FETCH (FDEV DEVICENAME) OF DEV)
+                     (FETCH (PHDEVICE PREFIX) OF DEV])
+
+(TARGETHOST
+  [LAMBDA (HOST)                                             (* ; "Edited 22-Jan-2022 09:00 by rmk")
+    (CL:WHEN (PSEUDOHOSTP HOST)
+        (FETCH (FDEV DEVICENAME) OF (FETCH (PHDEVICE TARGETDEV) OF (\GETDEVICEFROMNAME HOST))))])
+
+(TRUEFILENAME
+  [LAMBDA (FILE)                                             (* ; "Edited 26-Jan-2022 23:33 by rmk")
+                                                             (* ; "Edited 25-Jan-2022 08:47 by rmk")
+    (LET (FILENAME DEVICE)
+         (IF (STREAMP FILE)
+             THEN (SETQ FILENAME (FETCH (STREAM FULLFILENAME) OF FILE))
+                  (SETQ DEVICE (FETCH (STREAM DEVICE) OF FILE))
+           ELSE (SETQ FILENAME (\ADD.CONNECTED.DIR FILE))
+                (SETQ DEVICE (\GETDEVICEFROMNAME FILENAME)))
+         (CL:IF (TYPE? PHDEVICE DEVICE)
+             (EXPAND.PH FILENAME DEVICE)
+             FILENAME)])
+)
+
+
+
+(* ;; "Internals")
+
+(DEFINEQ
+
+(EXPAND.PH
+  [LAMBDA (FILENAME PHDEV)
+
+    (* ;; "Edited 26-Jan-2022 11:06 by rmk: that FILENAME contains }, because HOST was identified in it.  If FILENAME is a stream, expand its full name")
+
+    (* ;; "Assumes that FILENAME contains }, because HOST was identified in it.  If FILENAME is a stream, expand its full name")
+
+    (IF (TYPE? STREAM FILENAME)
+        THEN (CL:UNLESS PHDEV
+                 (SETQ PHDEV (FETCH (STREAM DEVICE) OF FILENAME)))
+             (SETQ FILENAME (FETCH (STREAM FULLNAME) OF FILENAME))
+      ELSEIF (NOT (TYPE? FDEV PHDEV))
+        THEN (SETQ PHDEV (\GETDEVICEFROMNAME PHDEV)))
+    (LET (SUFFIX SUFFIXPOS)
+         (CL:WHEN (SETQ SUFFIXPOS (STRPOS "}" FILENAME))
+             (SETQ SUFFIX (SUBSTRING FILENAME (ADD1 SUFFIXPOS)))
+             (CL:WHEN (FMEMB (CHCON1 SUFFIX)
+                             (CHARCODE (< > /)))
+                 (SETQ SUFFIX (SUBSTRING SUFFIX 2)))
+             (CONCAT (FETCH (PHDEVICE PREFIX) OF PHDEV)
+                    SUFFIX))])
+
+(CONTRACT.PH
+  [LAMBDA (NAME PHDEV)                                       (* ; "Edited 25-Jan-2022 09:44 by rmk")
+                                                             (* ; "Edited 20-Jan-2022 20:04 by rmk")
+                                                             (* ; "Edited 18-Jan-2022 22:54 by rmk")
+                                                             (* ; "Edited 16-Jan-2022 19:57 by rmk")
+                                                             (* ; "Edited 14-Jan-2022 00:03 by rmk")
+    (CL:UNLESS (TYPE? FDEV PHDEV)
+        (SETQ PHDEV (\GETDEVICEFROMNAME PHDEV)))
+    (CL:WHEN NAME
+        (LET* [(PREFIX (FETCH (PHDEVICE PREFIX) OF PHDEV))
+               (CONNECTOR (FETCH (PHDEVICE CONNECTOR) OF PHDEV))
+               (SUFFIX (SUBSTRING NAME (ADD1 (NCHARS PREFIX]
+              (IF (STRPOS PREFIX NAME 1 NIL T NIL FILEDIRCASEARRAY)
+                  THEN (CL:WHEN (STRPOS ">" SUFFIX 1 NIL NIL NIL FILEDIRCASEARRAY)
+
+                           (* ;; "Must be a subdirectory.  (CDR INFO) tells us whether to use / or > depending on what the prefix has")
+
+                           [SETQ SUFFIX (CONCAT CONNECTOR (IF (EQ CONNECTOR '/)
+                                                              THEN (SLASHIT SUFFIX)
+                                                            ELSE (UNSLASHIT SUFFIX])
+                       (PACK* '{ (FETCH (FDEV DEVICENAME) OF PHDEV)
+                              "}"
+                              (OR SUFFIX ""))
+                ELSE 
+                     (* ;; "If the target's NAME didn't begin with the prefix, then the caller must have jumped outside the pseudo root.  So just return the NAME")
+
+                     NAME)))])
+
+(SLASHIT
+  [LAMBDA (X LCASEDIRS)                                      (* ; "Edited 26-Jan-2022 15:08 by rmk")
+                                                             (* ; "Edited  3-Jan-2022 11:44 by rmk")
+                                                             (* ; "Edited 22-Dec-2021 20:18 by rmk")
+                                                            (* ; "Edited  2-Nov-2021 22:54 by rmk:")
+    (LET [LASTDIRPOS SLASHED (DIRPOS (ADD1 (OR (STRPOS "}" X)
+                                               0]
+         [SETQ SLASHED (CONCATCODES (FOR I C FROM DIRPOS WHILE (SETQ C (NTHCHARCODE X I))
+                                       COLLECT (SELCHARQ C
+                                                    ((< >) 
+                                                         (SETQ LASTDIRPOS I)
+                                                         (CHARCODE /))
+                                                    (/ (SETQ LASTDIRPOS I)
+                                                       C)
+                                                    C]
+         (CL:WHEN (AND LCASEDIRS LASTDIRPOS)
+             (SETQ LASTDIRPOS (ADD1 (IDIFFERENCE LASTDIRPOS DIRPOS)))
+             (SETQ SLASHED (CONCAT (L-CASE (SUBSTRING SLASHED 1 LASTDIRPOS))
+                                  (OR (SUBSTRING SLASHED (ADD1 LASTDIRPOS))
+                                      ""))))
+         (CL:IF (EQ DIRPOS 1)
+             SLASHED
+             (CONCAT (SUBSTRING X 1 (SUB1 DIRPOS))
+                    SLASHED))])
+
+(UNSLASHIT
+  [LAMBDA (X LCASEDIRS)                                      (* ; "Edited 26-Jan-2022 15:09 by rmk")
+                                                             (* ; "Edited 22-Dec-2021 20:18 by rmk")
+                                                            (* ; "Edited 21-Nov-2021 23:00 by rmk:")
+
+    (* ;; "Tricky to get the first one right.")
+
+    (LET [LASTDIRPOS UNSLASHED (DIRPOS (ADD1 (OR (STRPOS "}" X)
+                                                 0]
+         [SETQ UNSLASHED
+          (CONCATCODES (FOR I C LASTC FROM DIRPOS WHILE (SETQ C (NTHCHARCODE X I))
+                          COLLECT (PROG1 (SELCHARQ C
+                                              (/ (SETQ LASTDIRPOS I)
+                                                 (IF (AND LASTC (NEQ LASTC (CHARCODE })))
+                                                     THEN (CHARCODE >)
+                                                   ELSE (CHARCODE <)))
+                                              ((< >) 
+                                                   (SETQ LASTDIRPOS I)
+                                                   C)
+                                              C)
+                                         (SETQ LASTC C]
+         (CL:WHEN (AND LCASEDIRS LASTDIRPOS)
+             (SETQ LASTDIRPOS (ADD1 (IDIFFERENCE LASTDIRPOS DIRPOS)))
+             (SETQ UNSLASHED (CONCAT (L-CASE (SUBSTRING UNSLASHED 1 LASTDIRPOS))
+                                    (OR (SUBSTRING UNSLASHED (ADD1 LASTDIRPOS))
+                                        ""))))
+         (CL:IF (EQ DIRPOS 1)
+             UNSLASHED
+             (CONCAT (SUBSTRING X 1 (SUB1 DIRPOS))
+                    UNSLASHED))])
+)
+(DEFINEQ
+
+(OPENFILE.PH
+  [LAMBDA (FILE ACCESS RECOG OTHERINFO FDEV OLDSTRING)       (* ; "Edited 25-Jan-2022 08:45 by rmk")
+                                                             (* ; "Edited 18-Jan-2022 10:29 by rmk")
+    (LET ((STREAM (PSEUDOHOST.TARGETVAL OPENFILE (FILE ACCESS RECOG OTHERINFO FDEV OLDSTRING)
+                         FDEV)))
+         (CHANGE (FETCH (STREAM FULLFILENAME) OF STREAM)
+                (CONTRACT.PH DATUM FDEV))
+         (REPLACE (STREAM DEVICE) OF STREAM WITH FDEV)
+         STREAM])
+
+(GETFILENAME.PH
+  [LAMBDA (NAME RECOG FDEV)                                  (* ; "Edited 25-Jan-2022 22:56 by rmk")
+                                                             (* ; "Edited 16-Jan-2022 20:27 by rmk")
+    (PSEUDOHOST.NAME GETFILENAME (NAME RECOG FDEV])
+
+(DIRECTORYNAMEP.PH
+  [LAMBDA (DIRSPEC DEV CREATE?)                              (* ; "Edited 25-Jan-2022 22:56 by rmk")
+                                                             (* ; "Edited 18-Jan-2022 11:32 by rmk")
+
+    (* ;; "{FOO} by itself is always a legitimate directory--you should be able to connect to it when you are starting up")
+                                                             (* ; "Edited 16-Jan-2022 20:35 by rmk")
+    (OR (EQ (CHARCODE })
+            (NTHCHARCODE DIRSPEC -1))
+        (PSEUDOHOST.NAME DIRECTORYNAMEP (DIRSPEC DEV CREATE?)
+               DEV])
+
+(CLOSEFILE.PH
+  [LAMBDA (STREAM ABORTFLG)                                  (* ; "Edited 16-Jan-2022 15:38 by rmk")
+    (APPLY* (FETCH (FDEV CLOSEFILE) OF (FETCH (PHDEVICE TARGETDEV) OF (FETCH (STREAM DEVICE)
+                                                                         OF STREAM)))
+           STREAM ABORTFLG])
+
+(REOPENFILE.PH
+  [LAMBDA (FILE ACCESS RECOG OTHERINFO FDEV OLDSTREAM)       (* ; "Edited 25-Jan-2022 12:50 by rmk")
+                                                             (* ; "Edited 18-Jan-2022 11:41 by rmk")
+    (LET ((STREAM (PSEUDOHOST.TARGETVAL REOPENFILE (FILE ACCESS RECOG OTHERINFO FDEV OLDSTREAM)
+                         FDEV)))
+         (CHANGE (FETCH (STREAM FULLFILENAME) OF STREAM)
+                (CONTRACT.PH DATUM FDEV))
+         (REPLACE (STREAM DEVICE) OF STREAM WITH FDEV)
+         STREAM])
+
+(DELETEFILE.PH
+  [LAMBDA (FILENAME DEV)                                     (* ; "Edited 25-Jan-2022 22:56 by rmk")
+                                                             (* ; "Edited 18-Jan-2022 10:23 by rmk")
+    (PSEUDOHOST.NAME DELETEFILE (FILENAME DEV])
+
+(OPENP.PH
+  [LAMBDA (FILENAME ACCESS DEVICE)                           (* ; "Edited 18-Jan-2022 10:29 by rmk")
+    (PSEUDOHOST.TARGETVAL OPENP (FILENAME ACCESS DEVICE])
+
+(UNREGISTERFILE.PH
+  [LAMBDA (DEVICE STREAM)                                    (* ; "Edited 16-Jan-2022 16:47 by rmk")
+    (APPLY* (FETCH (FDEV UNREGISTERFILE) OF (FETCH (PHDEVICE TARGETDEV) OF DEVICE))
+           (FETCH (PHDEVICE TARGETDEV) OF DEVICE)
+           STREAM])
+
+(REGISTERFILE.PH
+  [LAMBDA (DEVICE STREAM)                                    (* ; "Edited 16-Jan-2022 16:46 by rmk")
+    (APPLY* (FETCH (FDEV REGISTERFILE) OF (FETCH (PHDEVICE TARGETDEV) OF DEVICE))
+           (FETCH (PHDEVICE TARGETDEV) OF DEVICE)
+           STREAM])
+
+(GENERATEFILES.PH
+  [LAMBDA (FDEV PATTERN DESIREDPROPS OPTIONS)                (* ; "Edited 17-Jan-2022 20:46 by rmk")
+
+    (* ;; "FDEV is the pseudohost. We will generate from the target directory using its GENFILESTATE, but fiddle the output so that it looks like it is coming from the pseudo host.")
+
+    (LET ((TARGETGENOBJ (APPLY* (FETCH (FDEV GENERATEFILES) OF (FETCH (PHDEVICE TARGETDEV)
+                                                                  OF FDEV))
+                               (FETCH (PHDEVICE TARGETDEV) OF FDEV)
+                               (EXPAND.PH PATTERN FDEV)
+                               DESIREDPROPS OPTIONS)))
+
+         (* ;; "The TARGETGENOBJ contains the targets functions as well as its GENFILESTATE.  We need the ph FDEV to contract the generated names")
+
+         (CREATE FILEGENOBJ
+                NEXTFILEFN _ (FUNCTION NEXTFILEFN.PH)
+                FILEINFOFN _ (FUNCTION FILEINFOFN.PH)
+                GENFILESTATE _ (LIST FDEV TARGETGENOBJ])
+
+(GETFILEINFO.PH
+  [LAMBDA (STREAM ATTRIBUTE DEVICE)                          (* ; "Edited 25-Jan-2022 12:43 by rmk")
+                                                             (* ; "Edited 17-Jan-2022 18:21 by rmk")
+    (PSEUDOHOST.TARGETVAL GETFILEINFO (STREAM ATTRIBUTE DEVICE])
+
+(SETFILEINFO.PH
+  [LAMBDA (STREAM ATTRIBUTE VALUE DEVICE)                    (* ; "Edited 25-Jan-2022 12:37 by rmk")
+    (PSEUDOHOST.TARGETVAL SETFILEINFO (STREAM ATTRIBUTE VALUE DEVICE])
+
+(NEXTFILEFN.PH
+  [LAMBDA (GENFILESTATE NAMEONLY)                            (* ; "Edited 17-Jan-2022 21:27 by rmk")
+    (LET* ((TARGETGENOBJ (CADR GENFILESTATE))
+           (TARGETGENFILESTATE (FETCH GENFILESTATE OF TARGETGENOBJ))
+           (FILENAME (APPLY* (FETCH NEXTFILEFN OF TARGETGENOBJ)
+                            TARGETGENFILESTATE NAMEONLY)))
+          (CL:WHEN FILENAME
+              (CL:UNLESS NAMEONLY
+                  (SETQ FILENAME (CONTRACT.PH FILENAME (CAR GENFILESTATE)))))
+          FILENAME])
+
+(FILEINFOFN.PH
+  [LAMBDA (GENFILESTATE ATTRIBUTE)                           (* ; "Edited 17-Jan-2022 20:52 by rmk")
+    (APPLY* (FETCH FILEINFOFN OF (CADR GENFILESTATE))
+           (FETCH GENFILESTATE OF (CADR GENFILESTATE))
+           ATTRIBUTE])
+
+(RENAMEFILE.PH
+  [LAMBDA (OLD-DEVICE OLD-NAME NEW-DEVICE NEW-NAME)          (* ; "Edited 18-Jan-2022 09:52 by rmk")
+    (LET ((OLDTARGETDEV (FETCH (PHDEVICE TARGETDEV) OF OLD-DEVICE))
+          (NEWTARGETDEV (FETCH (PHDEVICE TARGETDEV) OF NEW-DEVICE))
+          (NEWTARGETNAME NEW-NAME)
+          RESULT)
+         (CL:WHEN (TYPE? FDEV NEWTARGETDEV)                  (* ; "NEW-DEVICE is a pseudo host")
+             (SETQ NEWTARGETNAME (EXPAND.PH NEW-NAME NEW-DEVICE)))
+         (SETQ RESULT (APPLY* (FETCH (FDEV RENAMEFILE) OF OLDTARGETDEV)
+                             OLDTARGETDEV
+                             (EXPAND.PH OLD-NAME OLD-DEVICE)
+                             (OR NEWTARGETDEV NEW-DEVICE)
+                             NEWTARGETNAME))
+         (CL:WHEN (AND RESULT (NEQ NEWTARGETDEV NEW-DEVICE))
+             (SETQ RESULT (CONTRACT.PH RESULT NEW-DEVICE)))
+         RESULT])
+)
+
+(PSEUDOHOST 'LI LOGINHOST/DIR)
+(DECLARE%: EVAL@COMPILE DONTCOPY 
+(DECLARE%: EVAL@COMPILE
+
+(ACCESSFNS PHDEVICE [(PREFIX (CAR (FETCH (FDEV FDEV2) OF DATUM)))
+                     (TARGETDEV (FETCH (FDEV FDEV1) OF DATUM)
+                            (REPLACE (FDEV FDEV1) OF DATUM WITH NEWVALUE))
+                     (CONNECTOR (CDR (FETCH (FDEV FDEV2) OF DATUM]
+                    (TYPE? (FETCH (PHDEVICE PREFIX) OF DATUM)))
+
+(RECORD PHGENFILESTATE (PHDEVICE . TARGETGENFILESTATE))
+)
+
+(DECLARE%: EVAL@COMPILE 
+
+(PUTPROPS PSEUDOHOST.NAME MACRO
+          [TAIL (LET [(OPNAME (CAR TAIL))
+                      (ARGS (CADR TAIL))
+                      (DEV (OR (CADDR TAIL)
+                               (CAR (LAST (CADR TAIL]
+
+                     (* ;; 
+    "Assumes that the name is (CAR ARGS), the device is the last or args if not specified separately")
+
+                     `(CONTRACT.PH [APPLY* (FETCH (FDEV ,OPNAME) OF (FETCH (PHDEVICE TARGETDEV)
+                                                                       OF ,DEV))
+                                          (EXPAND.PH ,(CAR ARGS)
+                                                 ,DEV)
+                                          ,@(SUBST `(FETCH (PHDEVICE TARGETDEV) OF ,DEV)
+                                                   DEV
+                                                   (CDR ARGS]
+                             ,DEV])
+
+(PUTPROPS PSEUDOHOST.TARGETVAL MACRO
+          [TAIL (LET [(OPNAME (CAR TAIL))
+                      (ARGS (CADR TAIL))
+                      (DEV (OR (CADDR TAIL)
+                               (CAR (LAST (CADR TAIL]
+
+                     (* ;; "Assumes that the name is (CAR ARGS), the device is the last or args if not specified separately.  Unlike PSEUDOHOST.OP, this returns the target value, doesn't assume it is a name to be contracted.")
+
+                     `(APPLY* (FETCH (FDEV ,OPNAME) OF (FETCH (PHDEVICE TARGETDEV)
+                                                          OF ,DEV))
+                             (EXPAND.PH ,(CAR ARGS)
+                                    ,DEV)
+                             ,@(SUBST `(FETCH (PHDEVICE TARGETDEV) OF ,DEV)
+                                      DEV
+                                      (CDR ARGS])
+)
+
+
+(CL:UNLESS (GETP 'EXPORTS.ALL 'FILE)
+    (LOAD 'EXPORTS.ALL))
+)
+(DECLARE%: DONTCOPY
+  (FILEMAP (NIL (1205 7096 (PSEUDOHOST 1215 . 5418) (PSEUDOHOSTP 5420 . 5770) (PSEUDOHOSTS 5772 . 6129) 
+(TARGETHOST 6131 . 6405) (TRUEFILENAME 6407 . 7094)) (7124 13330 (EXPAND.PH 7134 . 8189) (CONTRACT.PH 
+8191 . 10010) (SLASHIT 10012 . 11580) (UNSLASHIT 11582 . 13328)) (13331 20121 (OPENFILE.PH 13341 . 
+13902) (GETFILENAME.PH 13904 . 14193) (DIRECTORYNAMEP.PH 14195 . 14819) (CLOSEFILE.PH 14821 . 15175) (
+REOPENFILE.PH 15177 . 15742) (DELETEFILE.PH 15744 . 16028) (OPENP.PH 16030 . 16206) (UNREGISTERFILE.PH
+ 16208 . 16513) (REGISTERFILE.PH 16515 . 16816) (GENERATEFILES.PH 16818 . 17858) (GETFILEINFO.PH 17860
+ . 18162) (SETFILEINFO.PH 18164 . 18363) (NEXTFILEFN.PH 18365 . 18907) (FILEINFOFN.PH 18909 . 19180) (
+RENAMEFILE.PH 19182 . 20119)))))
+STOP
diff --git a/lispusers/PSEUDOHOSTS.LCOM b/lispusers/PSEUDOHOSTS.LCOM
new file mode 100644
index 00000000..6bf39e06
Binary files /dev/null and b/lispusers/PSEUDOHOSTS.LCOM differ
diff --git a/lispusers/PSEUDOHOSTS.TEDIT b/lispusers/PSEUDOHOSTS.TEDIT
new file mode 100644
index 00000000..8bf8c4e7
Binary files /dev/null and b/lispusers/PSEUDOHOSTS.TEDIT differ
diff --git a/lispusers/REGIONMANAGER b/lispusers/REGIONMANAGER
index e411b43c..3d68fac5 100644
--- a/lispusers/REGIONMANAGER
+++ b/lispusers/REGIONMANAGER
@@ -1,12 +1,12 @@
 (DEFINE-FILE-INFO PACKAGE "INTERLISP" READTABLE "INTERLISP" BASE 10)
 
-(FILECREATED " 2-Jan-2022 16:01:26" 
-{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>REGIONMANAGER.;99 31663  
+(FILECREATED "27-Jan-2022 13:24:29" 
+{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>REGIONMANAGER.;106 34264  
 
-      :CHANGES-TO (FNS SET-TYPED-REGIONS \RELCREATEREGION.REF \RELCREATEREGION.SIZE)
+      :CHANGES-TO (FNS RELCREATEREGION \RELCREATEREGION.SIZE RELGETREGION)
 
-      :PREVIOUS-DATE " 1-Jan-2022 23:14:42" 
-{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>REGIONMANAGER.;95)
+      :PREVIOUS-DATE "25-Jan-2022 15:38:10" 
+{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>REGIONMANAGER.;105)
 
 
 (PRETTYCOMPRINT REGIONMANAGERCOMS)
@@ -30,7 +30,7 @@
         
         (* ;; "Relative regions")
 
-        (COMS (FNS RELCREATEREGION RELGETREGION)
+        (COMS (FNS RELCREATEREGION RELGETREGION RELCREATEPOSITION)
               (FNS \RELCREATEREGION.REF \RELCREATEREGION.SIZE))
         
         (* ;; "Composite application construction")
@@ -250,7 +250,11 @@
 (DEFINEQ
 
 (RELCREATEREGION
-  [LAMBDA (WIDTH HEIGHT CORNERX CORNERY REFX REFY ONSCREEN)  (* ; "Edited 30-Dec-2021 20:54 by rmk")
+  [LAMBDA (WIDTH HEIGHT CORNERX CORNERY REFX REFY ONSCREEN)  (* ; "Edited 27-Jan-2022 13:23 by rmk")
+                                                             (* ; "Edited 25-Jan-2022 15:29 by rmk")
+                                                             (* ; "Edited 23-Jan-2022 21:18 by rmk")
+                                                             (* ; "Edited 12-Jan-2022 17:50 by rmk")
+                                                             (* ; "Edited 30-Dec-2021 20:54 by rmk")
                                                              (* ; "Edited 27-Dec-2021 15:54 by rmk")
 
     (* ;; "The region is oriented so that he REFX and REFY are at the corner named by CORNERX/Y. ")
@@ -274,99 +278,129 @@
 
     (* ;; "")
 
-    (* ;; "Resolve the width and height, if based on a region or window ")
+    (* ;; "The arguments can be given as a list to be spread out, so that region relative region specifications can be passed through intermediate functions.  The test here is not very tight, if it is incorrect the recursive call will fail.")
 
-    (SETQ WIDTH (\RELCREATEREGION.SIZE WIDTH 'X))
-    (SETQ HEIGHT (\RELCREATEREGION.SIZE HEIGHT 'Y))
+    (IF (AND (LISTP WIDTH)
+             (NOT (REGIONP WIDTH))
+             (NULL HEIGHT)
+             (IGREATERP (LENGTH WIDTH)
+                    3))
+        THEN 
+             (* ;; "If less than 3, presumably a relative width")
 
-    (* ;; "Resolve the corner")
+             (APPLY (FUNCTION RELCREATEREGION)
+                    WIDTH)
+      ELSE 
+           (* ;; "Resolve the width and height, if based on a region or window ")
 
-    (CL:UNLESS CORNERX
-        (SETQ CORNERX 'LEFT))
-    (CL:UNLESS CORNERY
-        (SETQ CORNERY 'BOTTOM))
-    (CL:WHEN (AND (LISTP CORNERX)
-                  (NULL CORNERY))
-        (SETQ CORNERY (CADR CORNERX))
-        (SETQ CORNERX (CAR CORNERX)))
+           (SETQ WIDTH (\RELCREATEREGION.SIZE WIDTH 'X))
+           (SETQ HEIGHT (\RELCREATEREGION.SIZE HEIGHT 'Y)) 
 
-    (* ;; "Resolve the reference point")
+           (* ;; "Resolve the corner")
 
-    [IF (AND (POSITIONP REFX)
-             (NULL REFY))
-        THEN (SETQ REFY (FETCH (POSITION YCOORD) OF REFX))
-             (SETQ REFX (FETCH (POSITION XCOORD) OF REFX))
-      ELSE (GETMOUSESTATE)
-           (SETQ REFX (\RELCREATEREGION.REF REFX 'X))
-           (SETQ REFY (\RELCREATEREGION.REF REFY 'Y]
+           (CL:UNLESS CORNERX
+               (SETQ CORNERX 'LEFT))
+           (CL:UNLESS CORNERY
+               (SETQ CORNERY 'BOTTOM))
+           (CL:WHEN (AND (LISTP CORNERX)
+                         (NULL CORNERY))
+               (SETQ CORNERY (CADR CORNERX))
+               (SETQ CORNERX (CAR CORNERX))) 
 
-    (* ;; "Align the new-region corner with the reference point")
+           (* ;; "Resolve the reference point")
 
-    (LET* ((LEFT REFX)
-           (BOTTOM REFY)
-           (RIGHT (IPLUS LEFT WIDTH))
-           (TOP (IPLUS BOTTOM HEIGHT)))
-          (CL:WHEN (EQ 'RIGHT CORNERX)
-              (SETQ RIGHT LEFT)
-              (SETQ LEFT (IDIFFERENCE LEFT WIDTH)))
-          (CL:WHEN (EQ 'TOP CORNERY)
-              (SETQ TOP BOTTOM)
-              (SETQ BOTTOM (IDIFFERENCE BOTTOM HEIGHT)))
-          (CL:WHEN ONSCREEN                                  (* ; "Keep the region on the screen.  ")
-              (CL:WHEN (ILESSP LEFT 0)
-                  (ADD WIDTH LEFT)
-                  (SETQ LEFT 0))
-              (CL:WHEN (ILESSP BOTTOM 0)
-                  (ADD HEIGHT BOTTOM)
-                  (SETQ BOTTOM 0))
-              (CL:WHEN (IGREATERP RIGHT SCREENWIDTH)
-                  (ADD WIDTH (IDIFFERENCE SCREENWIDTH RIGHT)))
-              (CL:WHEN (IGREATERP TOP SCREENHEIGHT)
-                  (ADD HEIGHT (IDIFFERENCE SCREENHEIGHT TOP))))
-          (CREATEREGION LEFT BOTTOM WIDTH HEIGHT])
+           [IF (AND (POSITIONP REFX)
+                    (NULL REFY))
+               THEN (SETQ REFY (FETCH (POSITION YCOORD) OF REFX))
+                    (SETQ REFX (FETCH (POSITION XCOORD) OF REFX))
+             ELSE (GETMOUSESTATE)
+                  (SETQ REFX (\RELCREATEREGION.REF REFX 'X))
+                  (SETQ REFY (\RELCREATEREGION.REF REFY 'Y] 
+
+           (* ;; "Align the new-region corner with the reference point")
+
+           (LET* ((LEFT REFX)
+                  (BOTTOM REFY)
+                  (RIGHT (IPLUS LEFT WIDTH))
+                  (TOP (IPLUS BOTTOM HEIGHT)))
+                 (CL:WHEN (EQ 'RIGHT CORNERX)
+                     (SETQ RIGHT LEFT)
+                     (SETQ LEFT (IDIFFERENCE LEFT WIDTH)))
+                 (CL:WHEN (EQ 'TOP CORNERY)
+                     (SETQ TOP BOTTOM)
+                     (SETQ BOTTOM (IDIFFERENCE BOTTOM HEIGHT)))
+                 (CL:WHEN ONSCREEN                           (* ; "Keep the region on the screen.  Not clear whether we should keep the width and height and just move the left and bottom.  Here we allow some shrinkage")
+                     (CL:WHEN (ILESSP LEFT 0)
+                         (ADD WIDTH (IMIN 100 LEFT))
+                         (SETQ LEFT 0))
+                     (CL:WHEN (ILESSP BOTTOM 0)
+                         (ADD HEIGHT (IMIN 100 BOTTOM))
+                         (SETQ BOTTOM 0))
+                     (CL:WHEN (IGREATERP RIGHT SCREENWIDTH)
+                         (ADD WIDTH (IDIFFERENCE SCREENWIDTH RIGHT)))
+                     (CL:WHEN (IGREATERP TOP SCREENHEIGHT)
+                         (ADD HEIGHT (IDIFFERENCE SCREENHEIGHT TOP))))
+                 (CREATEREGION LEFT BOTTOM WIDTH HEIGHT])
 
 (RELGETREGION
-  [LAMBDA (WIDTH HEIGHT CORNERX CORNERY REFX REFY MINSIZE)   (* ; "Edited 28-Dec-2021 23:13 by rmk")
+  [LAMBDA (WIDTH HEIGHT CORNERX CORNERY REFX REFY MINSIZE)   (* ; "Edited 27-Jan-2022 13:24 by rmk")
+                                                             (* ; "Edited 25-Jan-2022 15:30 by rmk")
+                                                             (* ; "Edited 23-Jan-2022 21:20 by rmk")
+                                                             (* ; "Edited 28-Dec-2021 23:13 by rmk")
                                                              (* ; "Edited 10-Dec-2021 10:15 by rmk")
 
     (* ;; "Prompts for a relative region as created by RELCREATEREGION. Initially the anchored corner is fixed and the cursor is moved to the diagonally opposite corner.  If MINSIZE, the WIDTH and HEIGHT are taken to be the minimums that are acceptable, modulo the fact that the opposite corner is guaranteed to be visibleand, the size of the ghost region can only grow.  If not MINSIZE, we also allow the user to shrink the ghost region.")
 
-    (CL:WHEN (AND (LISTP CORNERX)
-                  (NULL CORNERY))
-        (SETQ CORNERY (CADR CORNERX))
-        (SETQ CORNERX (CAR CORNERX)))
-    (CL:UNLESS CORNERX
-        (SETQ CORNERX 'LEFT))
-    (CL:UNLESS CORNERY
-        (SETQ CORNERY 'BOTTOM))
-    (LET* ((REGION (OR (REGIONP WIDTH)
-                       (RELCREATEREGION WIDTH HEIGHT CORNERX CORNERY REFX REFY T)))
-           (BASEX (FETCH (REGION LEFT) OF REGION))
-           (BASEY (FETCH (REGION BOTTOM) OF REGION))
-           (RWIDTH (FETCH (REGION WIDTH) OF REGION))
-           (RHEIGHT (FETCH (REGION HEIGHT) OF REGION))
-           (OPPX (IPLUS BASEX RWIDTH))
-           (OPPY (IPLUS BASEY RHEIGHT)))
+    (COND
+       ((AND (LISTP WIDTH)
+             (NOT (REGIONP WIDTH))
+             (NULL HEIGHT)
+             (IGREATERP (LENGTH WIDTH)
+                    3))
+        (APPLY (FUNCTION RELGETREGION)
+               WIDTH))
+       (T (CL:WHEN (AND (LISTP CORNERX)
+                        (NULL CORNERY))
+              (SETQ CORNERY (CADR CORNERX))
+              (SETQ CORNERX (CAR CORNERX)))
+          (CL:UNLESS CORNERX
+              (SETQ CORNERX 'LEFT))
+          (CL:UNLESS CORNERY
+              (SETQ CORNERY 'BOTTOM))
+          (LET* ((REGION (OR (REGIONP WIDTH)
+                             (RELCREATEREGION WIDTH HEIGHT CORNERX CORNERY REFX REFY T)))
+                 (BASEX (FETCH (REGION LEFT) OF REGION))
+                 (BASEY (FETCH (REGION BOTTOM) OF REGION))
+                 (RWIDTH (FETCH (REGION WIDTH) OF REGION))
+                 (RHEIGHT (FETCH (REGION HEIGHT) OF REGION))
+                 (OPPX (IPLUS BASEX RWIDTH))
+                 (OPPY (IPLUS BASEY RHEIGHT)))
 
-          (* ;; "Default parameters assume the anchor is  (LEFT BOTTOM)")
+                (* ;; "Default parameters assume the anchor is  (LEFT BOTTOM)")
 
-          (CL:WHEN (EQ 'RIGHT CORNERX)
-                 (SWAP BASEX OPPX))
-          (CL:WHEN (EQ 'TOP CORNERY)
-                 (SWAP BASEY OPPY))
-          (\CURSORPOSITION OPPX OPPY)
-          (CL:UNLESS MINSIZE                                 (* ; "No minimum size constraint")
-              (SETQ RWIDTH NIL)
-              (SETQ RHEIGHT NIL))
-          (GETREGION RWIDTH RHEIGHT REGION NIL NIL (LIST BASEX BASEY OPPX OPPY])
+                (CL:WHEN (EQ 'RIGHT CORNERX)
+                       (SWAP BASEX OPPX))
+                (CL:WHEN (EQ 'TOP CORNERY)
+                       (SWAP BASEY OPPY))
+                (\CURSORPOSITION OPPX OPPY)
+                (CL:UNLESS MINSIZE                           (* ; "No minimum size constraint")
+                    (SETQ RWIDTH NIL)
+                    (SETQ RHEIGHT NIL))
+                (GETREGION RWIDTH RHEIGHT REGION NIL NIL (LIST BASEX BASEY OPPX OPPY])
+
+(RELCREATEPOSITION
+  [LAMBDA (REFX REFY)                                        (* ; "Edited 23-Jan-2022 17:08 by rmk")
+    (CREATEPOSITION (\RELCREATEREGION.REF REFX 'X)
+           (\RELCREATEREGION.REF REFY 'Y])
 )
 (DEFINEQ
 
 (\RELCREATEREGION.REF
-  [LAMBDA (REF WHICH)                                        (* ; "Edited  2-Jan-2022 11:01 by rmk")
+  [LAMBDA (REF WHICH)                                        (* ; "Edited 23-Jan-2022 20:20 by rmk")
+                                                             (* ; "Edited  2-Jan-2022 11:01 by rmk")
 
     (* ;; "REF can be NIL, an absolute screen position, the atom SCREEN, or a list of (anchor fraction adjustment) where anchor can be a region, window, or the atom SCREEN, fraction can be a number or atoms LEFT/RIGHT/BOTTOM/TOP as apropriate.")
-                                                             (* ; "Edited 30-Dec-2021 17:49 by rmk")
+                                                             (* ; "Edited 30-Dec-2021 17:49 by rmk")
     (LET (ANCHOR VAL SIZE FRACTION SPEC (BASE 0))
 
          (* ;; "Would be nice if the screen had a region")
@@ -386,7 +420,8 @@
            ELSEIF [AND (LISTP REF)
                        (SETQ ANCHOR (OR (REGIONP (CAR REF))
                                         (AND (WINDOWP (CAR REF))
-                                             (WINDOWREGION (CAR REF)))
+                                             (WINDOWPROP (CAR REF)
+                                                    'REGION))
                                         (AND (EQ (CAR REF)
                                                  'SCREEN)
                                              'SCREEN]
@@ -417,7 +452,7 @@
            ELSE (\ILLEGAL.ARG REF])
 
 (\RELCREATEREGION.SIZE
-  [LAMBDA (PARAM WHICH)                                      (* ; "Edited  2-Jan-2022 11:00 by rmk")
+  [LAMBDA (PARAM WHICH)                                      (* ; "Edited  2-Jan-2022 11:00 by rmk")
                                                              (* ; "Edited 30-Dec-2021 17:51 by rmk")
 
     (* ;; 
@@ -591,8 +626,9 @@
 )
 )
 (DECLARE%: DONTCOPY
-  (FILEMAP (NIL (1602 3789 (SET-TYPED-REGIONS 1612 . 3787)) (3790 10791 (RM-CREATEW 3800 . 6307) (
-RM-CLOSEW 6309 . 7710) (RM-GETREGION 7712 . 10298) (CLOSE-TYPED-W 10300 . 10789)) (11707 16778 (
-RELCREATEREGION 11717 . 14876) (RELGETREGION 14878 . 16776)) (16779 21898 (\RELCREATEREGION.REF 16789
- . 19646) (\RELCREATEREGION.SIZE 19648 . 21896)) (21951 31293 (RM-ATTACHWINDOW 21961 . 31291)))))
+  (FILEMAP (NIL (1612 3799 (SET-TYPED-REGIONS 1622 . 3797)) (3800 10801 (RM-CREATEW 3810 . 6317) (
+RM-CLOSEW 6319 . 7720) (RM-GETREGION 7722 . 10308) (CLOSE-TYPED-W 10310 . 10799)) (11717 19196 (
+RELCREATEREGION 11727 . 16350) (RELGETREGION 16352 . 18959) (RELCREATEPOSITION 18961 . 19194)) (19197 
+24499 (\RELCREATEREGION.REF 19207 . 22239) (\RELCREATEREGION.SIZE 22241 . 24497)) (24552 33894 (
+RM-ATTACHWINDOW 24562 . 33892)))))
 STOP
diff --git a/lispusers/REGIONMANAGER.LCOM b/lispusers/REGIONMANAGER.LCOM
index c2f03a9e..13abab87 100644
Binary files a/lispusers/REGIONMANAGER.LCOM and b/lispusers/REGIONMANAGER.LCOM differ
diff --git a/lispusers/REGIONMANAGER.TEDIT b/lispusers/REGIONMANAGER.TEDIT
index 70961946..916124ff 100644
--- a/lispusers/REGIONMANAGER.TEDIT
+++ b/lispusers/REGIONMANAGER.TEDIT
@@ -37,10 +37,12 @@ NIL: LASTMOUSEX/LASTMOUSEY
 natural number:  an absolute screen coordinate
 (anchor fraction adjustment) or just region/window/SCREEN: the quantity determined relative to the size of anchor (as above) is added to the anchors left/bottom produce the REFX/REFY coordinate. In this case, fractions specified as LEFT/BOTTOM/NIL are interpreted as 0 and RIGHT/TOP are interpreted as 1. For example, a specification  (<window> .4 -2) for REFY will produce a coordinate 2 points below the level that is 40% of the distance between the bottom and top of the window's region.
 For convenience, if REFX is a position and REFY is NIL, then the XCOORD and YCOORD of REFX are taken as absolute values for REFX and REFY.
+Also for convenience, if WIDTH is a potentially a list of RELCREATEREGION arguments, then the elements of that list are spread out in a recursive call.
 
 (RELGETREGION WIDTH HEIGHT CORNERX CORNERY REFX REFY MINSIZE)           [Function] 
 Calls GETREGION with an initial ghost region as created by RELCREATEREGION.  CORNERX and CORNERY determine the ghost region's fixed corner, and the cursor starts at the region's diagonally opposite corner. If MINSIZE is true, then WIDTH and HEIGHT are taken as the minimum sizes of the region, except for adjustments that may be needed to ensure that all corners of the ghost region are initially visible on the screen.
-
+(RELCREATEPOSITION REFX REFY)      [Function]
+Creates a position with X and Y coordinates specified by REFX and REFY references as above.
 Constellation regions
 Applications are often set up as a constellation of windows, a central or primary window surrounded by some number of satellites for menus, headers, prompts, and secondary outputs. The main panel of a file browser, for example, displays the list of files, but above it are carefully arranged windows for the column headers, summary information, and prompts, and off to the side is the menu of file browser commands.  FILEBROWSER interprets the screen region that the user sweeps out for a new browser as the region for the whole constellation,the smallest region that will enclose the central window and all of its satellites. Similarly, the screen region given to TEDIT and SEDIT is divided between the prompt window and the central editing window, again so that the whole constellation (a pair in these cases) fit within the provided region.
 Each of these applications is constructed by anticipating the subregions that the satellite windows will occupy after they are attached, decreasing the constellation region by their estimated (using WIDTHIFWINDOW HEIGHTIFWINDOW) or actual sizes, and then using remainder as the region for the central window. 
@@ -56,4 +58,4 @@ TIMESROMAN$TERMINALMODERNMODERN
 HRULE.GETFNMODERNHRULE.GETFNMODERN		(È„•‘}/	¯[	�Ch�T	Û
Á?	
 
 ;	3o)MA &MmJS-
-j/3t2C	ƒ"=	,	l¬™¤Ç
S~æ-4!U™Î(N!zº
\ No newline at end of file
+j/3t2C	ƒ"O=	,	l¬.9™¤Ç
S~æ-4!U™Î)o-zº
\ No newline at end of file
diff --git a/lispusers/TEDIT-PF-SEE b/lispusers/TEDIT-PF-SEE
index 1d2819e7..e1eec143 100644
--- a/lispusers/TEDIT-PF-SEE
+++ b/lispusers/TEDIT-PF-SEE
@@ -1,12 +1,12 @@
 (DEFINE-FILE-INFO PACKAGE "INTERLISP" READTABLE "INTERLISP" BASE 10)
 
-(FILECREATED " 2-Jan-2022 22:03:27" 
-{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>TEDIT-PF-SEE.;104 6489   
+(FILECREATED "12-Jan-2022 13:16:00" 
+{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>TEDIT-PF-SEE.;110 7695   
 
-      :CHANGES-TO (VARS TEDIT-PF-SEECOMS)
+      :CHANGES-TO (FNS PF-TEDIT)
 
-      :PREVIOUS-DATE "30-Dec-2021 23:17:58" 
-{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>TEDIT-PF-SEE.;103)
+      :PREVIOUS-DATE " 2-Jan-2022 22:03:27" 
+{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>TEDIT-PF-SEE.;104)
 
 
 (PRETTYCOMPRINT TEDIT-PF-SEECOMS)
@@ -22,7 +22,8 @@
 (DEFINEQ
 
 (PF-TEDIT
-  [LAMBDA (FN IFILES REPRINT)                                (* ; "Edited 30-Dec-2021 23:17 by rmk")
+  [LAMBDA (FN IFILES REPRINT)                                (* ; "Edited 12-Jan-2022 13:15 by rmk")
+                                                             (* ; "Edited 30-Dec-2021 23:17 by rmk")
 
     (* ;; "PF* to a read-only TEDIT window.  First argument is the function name, second if given is the input file.")
 
@@ -76,13 +77,27 @@
                                          THEN (SETFILEPTR ISTREAM (POP LOC))
                                               (SETQ EXPR (WITH-READER-ENVIRONMENT ENV (READ ISTREAM))
                                                )
-                                              (IF (EQ FN (CAR EXPR))
-                                                  THEN (DSPFONT BOLDFONT TSTREAM)
-                                                       (PRINT FN TSTREAM)
-                                                       (DSPFONT DEFAULTFONT TSTREAM)
-                                                       (SETQ EXPR (CADR EXPR))
-                                                       (PRINTDEF EXPR 3 NIL NIL NIL TSTREAM)
-                                                ELSE (PRINTDEF EXPR NIL NIL NIL NIL TSTREAM))
+                                              (WITH-READER-ENVIRONMENT ENV
+                                                  (IF (EQ FN (CAR EXPR))
+                                                      THEN (DSPFONT BOLDFONT TSTREAM)
+                                                           (PRINT FN TSTREAM)
+                                                           (DSPFONT DEFAULTFONT TSTREAM)
+                                                           (SETQ EXPR (CADR EXPR))
+                                                           (PRINTDEF EXPR 3 T NIL NIL TSTREAM)
+                                                    ELSEIF (EQ FN (CADR EXPR))
+                                                      THEN 
+                                                           (* ;; 
+                                              "Presumably a DEFUN.  Print the CAR, boldface the cadr")
+
+                                                           (PRINTOUT TSTREAM "(" .P2 (CAR EXPR)
+                                                                  " " .FONT BOLDFONT .P2 (CADR EXPR)
+                                                                  .FONT DEFAULTFONT " " .P2
+                                                                  (CADDR EXPR)
+                                                                  T 3)
+                                                           (PRINTDEF (CDDDR EXPR)
+                                                                  3 T T NIL TSTREAM)
+                                                           (PRIN3 ")" TSTREAM)
+                                                    ELSE (PRINTDEF EXPR 3 NIL NIL NIL TSTREAM)))
                                        ELSE (PFCOPYBYTES ISTREAM TSTREAM (POP LOC)
                                                    (POP LOC)))
                                      (TERPRI TSTREAM)
@@ -127,5 +142,5 @@
 (ADDTOVAR LAMA )
 )
 (DECLARE%: DONTCOPY
-  (FILEMAP (NIL (956 6010 (PF-TEDIT 966 . 6008)))))
+  (FILEMAP (NIL (947 7216 (PF-TEDIT 957 . 7214)))))
 STOP
diff --git a/lispusers/TEDIT-PF-SEE.LCOM b/lispusers/TEDIT-PF-SEE.LCOM
index 45be05d1..ee562f63 100644
Binary files a/lispusers/TEDIT-PF-SEE.LCOM and b/lispusers/TEDIT-PF-SEE.LCOM differ
diff --git a/lispusers/comparetext b/lispusers/comparetext
index b7804763..fd63f9cc 100644
--- a/lispusers/comparetext
+++ b/lispusers/comparetext
@@ -1,12 +1,12 @@
 (DEFINE-FILE-INFO PACKAGE "INTERLISP" READTABLE "INTERLISP" BASE 10)
 
-(FILECREATED "30-Dec-2021 21:22:01" 
-{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>comparetext.;100 48929  
+(FILECREATED "27-Jan-2022 13:20:38" 
+{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>comparetext.;109 49971  
 
       :CHANGES-TO (FNS COMPARETEXT.TEXTOBJ)
 
-      :PREVIOUS-DATE "27-Dec-2021 15:56:54" 
-{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>comparetext.;98)
+      :PREVIOUS-DATE "23-Jan-2022 20:22:06" 
+{DSK}<Users>kaplan>Local>medley3.5>my-medley>lispusers>comparetext.;108)
 
 
 (* ; "
@@ -33,11 +33,9 @@ Copyright (c) 1984-1985, 1993, 1998 by Xerox Corporation.
 (DEFINEQ
 
 (COMPARETEXT
-  [LAMBDA (FILE1 FILE2 HASH.TYPE REGION FILELABELS)          (* ; "Edited 22-Dec-2021 23:49 by rmk")
-                                                             (* ; "Edited 15-Dec-2021 16:23 by rmk")
-                                                             (* ; "Edited 13-Dec-2021 12:21 by rmk")
-                                                             (* ; "Edited  8-Nov-2021 08:44 by rmk:")
-                                                             (* mjs " 8-Jan-84 21:06")
+  [LAMBDA (FILE1 FILE2 HASH.TYPE REGION FILELABELS TITLE)    (* ; "Edited 12-Jan-2022 16:32 by rmk")
+                                                             (* ; "Edited  8-Nov-2021 08:44 by rmk")
+                                                             (* ; "Edited  8-Jan-84 21:06 by mjs")
 
     (* ;; "Compares the two files, and produces a graph showing their corresponding chunks.  The courseness of the 'chunking' is determined by HASH.TYPE, which may be PARA, LINE, or WORD.  HASH.TYPE = NIL defaults to PARA.  The file difference graph is displayed at REGION.  If REGION = NIL, the user is asked to specify a region.  If REGION = T, a standard region is used.")
 
@@ -45,8 +43,10 @@ Copyright (c) 1984-1985, 1993, 1998 by Xerox Corporation.
         ((PARA LINE WORD))
         (NIL (SETQ HASH.TYPE 'PARA))
         (ERROR (CONCAT "Unrecognize HASHTYPE " HASH.TYPE)))
-    (LET ((FULLFILE1 (FINDFILE FILE1 T))
-          (FULLFILE2 (FINDFILE FILE2 T)))
+    (LET [(FULLFILE1 (OR (GETSTREAM FILE1 'INPUT T)
+                         (FINDFILE FILE1 T)))
+          (FULLFILE2 (OR (GETSTREAM FILE2 'INPUT T)
+                         (FINDFILE FILE2 T]
          (CL:UNLESS (AND FULLFILE1 FULLFILE2)
              (ERROR "Can't find both files" (LIST FILE1 FILE2)))
          (IMCOMPARE.CHUNKS (create IMCOMPARE.CHUNK
@@ -55,17 +55,22 @@ Copyright (c) 1984-1985, 1993, 1998 by Xerox Corporation.
                 (create IMCOMPARE.CHUNK
                        FILENAME _ FULLFILE2
                        FILEPTR _ 0)
-                HASH.TYPE NIL FILELABELS])
+                HASH.TYPE REGION FILELABELS TITLE])
 
 (COMPARETEXT.WINDOW
-  [LAMBDA (GRAPH REGION)                                     (* ; "Edited 27-Dec-2021 13:47 by rmk")
-                                                             (* ; "Edited 25-Dec-2021 11:40 by rmk")
+  [LAMBDA (GRAPH REGION TITLE)                               (* ; "Edited 23-Jan-2022 18:18 by rmk")
+                                                             (* ; "Edited 12-Jan-2022 10:06 by rmk")
                                                              (* ; "Edited 22-Dec-2021 15:51 by rmk")
 
     (* ;; "Set up the graph WINDOW. If REGION isn't provided we prompt with a region that is wide enough for the graph and high enough for at least an initial segment.")
 
-    (LET [WINDOW GRAPHREGION GWIDTH (FILEPREFIX (CAR (GRAPHERPROP GRAPH 'FILELABELS]
-         [SETQ REGION
+    (LET [WINDOW GRAPHREGION WIDTH HEIGHT (FILEPREFIX (CAR (GRAPHERPROP GRAPH 'FILELABELS]
+         (SETQ GRAPHREGION (GRAPHREGION GRAPH))
+         (SETQ WIDTH (IPLUS (TIMES 2 WBorder)
+                            (FETCH (REGION WIDTH) OF GRAPHREGION)))
+         [SETQ HEIGHT (IMIN 200 (IPLUS (FETCH (REGION HEIGHT) OF GRAPHREGION)
+                                       (ITIMES 2 (FONTHEIGHT DEFAULTFONT]
+         (SETQ REGION
           (if (EQ REGION T)
               then (create REGION
                           LEFT _ 25
@@ -73,35 +78,38 @@ Copyright (c) 1984-1985, 1993, 1998 by Xerox Corporation.
                           WIDTH _ 500
                           HEIGHT _ 150)
             elseif (REGIONP REGION)
-            else (CLRPROMPT)
-                 (printout PROMPTWINDOW "Please specify a region for the comparison graph" T)
-                 (SETQ GRAPHREGION (GRAPHREGION GRAPH))
-                 (SETQ GWIDTH (FETCH (REGION WIDTH) OF GRAPHREGION)) 
+            elseif (POSITIONP REGION)
+              THEN 
+                   (* ;; 
+     "This is a reference position providing the horizontal midpoint of the graph region and the top")
+
+                   (RELCREATEREGION WIDTH HEIGHT 'LEFT 'TOP (IDIFFERENCE (FETCH (POSITION XCOORD)
+                                                                            OF REGION)
+                                                                   (IQUOTIENT WIDTH 2))
+                          (FETCH (POSITION YCOORD) OF REGION))
+            ELSE (CLEARW (GETPROMPTWINDOW WINDOW))
+                 (printout (GETPROMPTWINDOW WINDOW)
+                        "Please specify a region for the comparison graph" T) 
 
                  (* ;; "I don't know why the graphregion doesn't include the last line")
 
-                 (SETQ REGION (RELGETREGION (IPLUS (TIMES 2 WBorder)
-                                                   GWIDTH)
-                                     [IMIN 200 (IPLUS (FETCH (REGION HEIGHT) OF GRAPHREGION)
-                                                      (ITIMES 2 (FONTHEIGHT DEFAULTFONT]
-                                     'RIGHT
-                                     'TOP]
-         [SETQ WINDOW (CREATEW REGION (CONCAT "Compare text" (CL:IF FILEPREFIX
-                                                                 (CONCAT " of " FILEPREFIX)
-                                                                 "")
-                                             " showing "
-                                             (CL:IF (GRAPHERPROP GRAPH 'ALLCHUNKS)
-                                                 "all"
-                                                 "only different")
-                                             " chunks, hashed by "
-                                             (SELECTQ (GRAPHERPROP GRAPH 'HASH.TYPE)
-                                                 (PARA "paragraph")
-                                                 (LINE "line")
-                                                 (WORD "word")
-                                                 (SHOULDNT]
+                 (RELCREATEREGION WIDTH HEIGHT 'RIGHT 'TOP REGION)))
+         [SETQ WINDOW (CREATEW REGION (OR TITLE (CONCAT "Compare text" (CL:IF FILEPREFIX
+                                                                           (CONCAT " of " FILEPREFIX)
+                                                                           "")
+                                                       " showing "
+                                                       (CL:IF (GRAPHERPROP GRAPH 'ALLCHUNKS)
+                                                           "all"
+                                                           "only different")
+                                                       " chunks, hashed by "
+                                                       (SELECTQ (GRAPHERPROP GRAPH 'HASH.TYPE)
+                                                           (PARA "paragraph")
+                                                           (LINE "line")
+                                                           (WORD "word")
+                                                           (SHOULDNT]
          (GETPROMPTWINDOW WINDOW)
-         (CL:WHEN (EQ GWIDTH (FETCH (REGION WIDTH) OF (WINDOWREGION WINDOW)))
-             (WINDOWPROP WINDOW 'MAXSIZE (CONS GWIDTH MAX.SMALLP)))
+         (CL:WHEN (EQ WIDTH (FETCH (REGION WIDTH) OF (WINDOWREGION WINDOW)))
+             (WINDOWPROP WINDOW 'MAXSIZE (CONS WIDTH MAX.SMALLP)))
          (GETPROMPTWINDOW WINDOW)
          [WINDOWADDPROP WINDOW 'CLOSEFN (FUNCTION (LAMBDA (W)
                                                     (LET (TOBJ TWINDOW)
@@ -122,41 +130,37 @@ Copyright (c) 1984-1985, 1993, 1998 by Xerox Corporation.
          WINDOW])
 
 (COMPARETEXT.TEXTOBJ
-  [LAMBDA (NODE WINDOW INCOL1)                               (* ; "Edited 30-Dec-2021 21:21 by rmk")
+  [LAMBDA (NODE WINDOW INCOL1)                               (* ; "Edited 27-Jan-2022 13:14 by rmk")
+                                                             (* ; "Edited 23-Jan-2022 16:51 by rmk")
+                                                             (* ; "Edited 20-Jan-2022 22:29 by rmk")
+                                                             (* ; "Edited 19-Jan-2022 08:52 by rmk")
+                                                             (* ; "Edited 30-Dec-2021 21:21 by rmk")
                                                              (* ; "Edited 27-Dec-2021 15:56 by rmk")
 
     (* ;; "Returns the text object for the chunk column in the graphwindow WINDOW, on the left if INCOL1.  If the windows are automatic, they are lined up under the middle of WINDOW.")
 
     (DECLARE (USEDFREE COMPARETEXT.AUTOTEDIT))
-    (LET (TEXTOBJ TSTREAM TWINDOW REGION (NODEID (FETCH (GRAPHNODE NODEID) OF NODE)))
+    (LET (TEXTOBJ TSTREAM TWINDOW REGION REGIONARGS (NODEID (FETCH (GRAPHNODE NODEID) OF NODE)))
          (CL:UNLESS [AND [SETQ TEXTOBJ (WINDOWPROP WINDOW (CL:IF INCOL1
                                                               'COL1TEXTOBJ
                                                               'COL2TEXTOBJ)]
                          (OPENWP (WFROMDS (TEXTSTREAM TEXTOBJ]
-             (SETQ REGION (RELCREATEREGION 475 600 (CL:IF INCOL1
-                                                       'RIGHT
-                                                       'LEFT)
-                                 'TOP
-                                 (CL:IF INCOL1
-                                     `(,WINDOW 0.5 -1)
-                                     `(,WINDOW 0.5 1))
-                                 `(,WINDOW BOTTOM -2)
-                                 T))
+             (SETQ REGIONARGS (LIST 700 600 (CL:IF INCOL1
+                                                'RIGHT
+                                                'LEFT)
+                                    'TOP
+                                    `(,WINDOW 0.5 ,(CL:IF INCOL1
+                                                       -1
+                                                       1))
+                                    `(,WINDOW BOTTOM -2)
+                                    T))
+             (SETQ REGION (CL:IF COMPARETEXT.AUTOTEDIT
+                              (RELCREATEREGION REGIONARGS)
+                              (RELGETREGION REGIONARGS)))
              [SETQ TSTREAM (TEXTSTREAM (TEDIT (CL:IF (FIXP (CAR NODEID))
                                                   (FETCH (IMCOMPARE.CHUNK FILENAME) of NODEID)
                                                   NODEID)
-                                              (IF COMPARETEXT.AUTOTEDIT
-                                                  THEN 
-                                                       (* ;; 
-                                               "Just use it as created, don't prompt for adjustments")
-
-                                                       REGION
-                                                ELSE (RELGETREGION REGION NIL (CL:IF INCOL1
-                                                                                  'RIGHT
-                                                                                  'LEFT)
-                                                            'TOP))
-                                              NIL
-                                              `(READONLY T LEAVETTY T]
+                                              REGION NIL `(READONLY T LEAVETTY T]
              (SETQ TWINDOW (WFROMDS TSTREAM))
              (SETQ TEXTOBJ (TEXTOBJ TSTREAM))
              (WINDOWPROP WINDOW (CL:IF INCOL1
@@ -173,20 +177,24 @@ Copyright (c) 1984-1985, 1993, 1998 by Xerox Corporation.
                                                                                        WINDOWPOSITION
                                                                                           W)))
                                                              TOBJ TW)
-                                                            (CL:WHEN (SETQ TOBJ (WINDOWPROP
-                                                                                 W
-                                                                                 'COL1TEXTOBJ))
-                                                                (MOVEW (SETQ TW (WFROMDS (TEXTSTREAM
-                                                                                          TOBJ)))
-                                                                       (PTPLUS DELTA (WINDOWPOSITION
-                                                                                      TW))))
-                                                            (CL:WHEN (SETQ TOBJ (WINDOWPROP
-                                                                                 W
-                                                                                 'COL2TEXTOBJ))
-                                                                (MOVEW (SETQ TW (WFROMDS (TEXTSTREAM
-                                                                                          TOBJ)))
-                                                                       (PTPLUS DELTA (WINDOWPOSITION
-                                                                                      TW))))
+                                                            (CL:WHEN [AND (SETQ TOBJ
+                                                                           (WINDOWPROP W 
+                                                                                  'COL1TEXTOBJ))
+                                                                          (SETQ TW
+                                                                           (WFROMDS (TEXTSTREAM
+                                                                                     TOBJ]
+                                                                (MOVEW TW (PTPLUS DELTA (
+                                                                                       WINDOWPOSITION
+                                                                                         TW))))
+                                                            (CL:WHEN [AND (SETQ TOBJ
+                                                                           (WINDOWPROP W 
+                                                                                  'COL2TEXTOBJ))
+                                                                          (SETQ TW
+                                                                           (WFROMDS (TEXTSTREAM
+                                                                                     TOBJ]
+                                                                (MOVEW TW (PTPLUS DELTA (
+                                                                                       WINDOWPOSITION
+                                                                                         TW))))
                                                             NIL])
          TEXTOBJ])
 
@@ -246,7 +254,7 @@ Copyright (c) 1984-1985, 1993, 1998 by Xerox Corporation.
          (WINDOWPROP WINDOW 'LASTNODES (LIST NODE1 NODE2])
 
 (IMCOMPARE.CHUNKS
-  [LAMBDA (CHUNK1 CHUNK2 HASH.TYPE REGION FILELABELS)        (* ; "Edited 25-Dec-2021 13:02 by rmk")
+  [LAMBDA (CHUNK1 CHUNK2 HASH.TYPE REGION FILELABELS TITLE)  (* ; "Edited 12-Jan-2022 10:06 by rmk")
                                                              (* ; "Edited 23-Dec-2021 00:02 by rmk")
                                                              (* ; "Edited  8-Sep-1984 00:06 by rmk")
 
@@ -302,11 +310,13 @@ Copyright (c) 1984-1985, 1993, 1998 by Xerox Corporation.
 
          (* ;; "The file comparison is complete.  Format and display the file difference graph")
 
-         (IMCOMPARE.DISPLAYGRAPH CHUNK1 CHUNK2 HASH.TYPE REGION CHUNKLIST1 CHUNKLIST2 FILELABELS])
+         (IMCOMPARE.DISPLAYGRAPH CHUNK1 CHUNK2 HASH.TYPE REGION CHUNKLIST1 CHUNKLIST2 FILELABELS 
+                TITLE])
 
 (IMCOMPARE.COLLECT.HASH.CHUNKS
-  [LAMBDA (CHUNK HASH.TYPE)                                  (* ; "Edited 24-Dec-2021 22:30 by rmk")
-                                                             (* ; "Edited 13-Dec-2021 16:32 by rmk")
+  [LAMBDA (CHUNK HASH.TYPE)                                  (* ; "Edited 20-Jan-2022 23:09 by rmk")
+                                                             (* ; "Edited 24-Dec-2021 22:30 by rmk")
+                                                             (* ; "Edited 13-Dec-2021 16:32 by rmk")
                                                              (* ; "Edited 23-Dec-98 16:54 by rmk:")
                                                              (* mjs " 8-Jan-84 20:57")
 
@@ -338,11 +348,12 @@ Copyright (c) 1984-1985, 1993, 1998 by Xerox Corporation.
                                                       (fetch (IMCOMPARE.CHUNK CHUNKLENGTH)
                                                          of CHUNK)))
            WHILE (SETQ CHUNK (IMCOMPARE.HASH STREAM HASH.TYPE ENDPOS))
-           COLLECT (REPLACE FILENAME OF CHUNK WITH FILENAME)
+           COLLECT (REPLACE (IMCOMPARE.CHUNK FILENAME) OF CHUNK WITH FILENAME)
                  CHUNK))])
 
 (IMCOMPARE.DISPLAYGRAPH
-  [LAMBDA (CHUNK1 CHUNK2 HASH.TYPE REGION CHUNKLIST1 CHUNKLIST2 FILELABELS)
+  [LAMBDA (CHUNK1 CHUNK2 HASH.TYPE REGION CHUNKLIST1 CHUNKLIST2 FILELABELS TITLE)
+                                                             (* ; "Edited 12-Jan-2022 09:58 by rmk")
                                                              (* ; "Edited 27-Dec-2021 11:58 by rmk")
                                                              (* ; "Edited 23-Dec-2021 00:14 by rmk")
                                                              (* mjs "11-Jul-85 09:10")
@@ -459,7 +470,7 @@ Copyright (c) 1984-1985, 1993, 1998 by Xerox Corporation.
                                                   COL1X
                                                   ,COL1X COL2X ,COL2X ALLCHUNKS 
                                                   ,COMPARETEXT.ALLCHUNKS]
-         (SHOWGRAPH GRAPH (COMPARETEXT.WINDOW GRAPH REGION)
+         (SHOWGRAPH GRAPH (COMPARETEXT.WINDOW GRAPH REGION TITLE)
                 (FUNCTION IMCOMPARE.LEFTBUTTONFN)
                 (FUNCTION IMCOMPARE.MIDDLEBUTTONFN)
                 T NIL])
@@ -770,12 +781,12 @@ Copyright (c) 1984-1985, 1993, 1998 by Xerox Corporation.
 )
 (PUTPROPS COMPARETEXT COPYRIGHT ("Xerox Corporation" 1984 1985 1993 1998))
 (DECLARE%: DONTCOPY
-  (FILEMAP (NIL (1344 41549 (COMPARETEXT 1354 . 2933) (COMPARETEXT.WINDOW 2935 . 7132) (
-COMPARETEXT.TEXTOBJ 7134 . 12023) (COMPARETEXT.SETSEL 12025 . 12815) (CHUNKNODELABEL 12817 . 13938) (
-IMCOMPARE.BOXNODE 13940 . 14707) (IMCOMPARE.CHUNKS 14709 . 19062) (IMCOMPARE.COLLECT.HASH.CHUNKS 19064
- . 21842) (IMCOMPARE.DISPLAYGRAPH 21844 . 29570) (IMCOMPARE.HASH 29572 . 33759) (
-IMCOMPARE.MERGE.CONNECTED.CHUNKS 33761 . 37257) (IMCOMPARE.MERGE.UNCONNECTED.CHUNKS 37259 . 39214) (
-IMCOMPARE.SHOW.DIST 39216 . 39662) (IMCOMPARE.UPDATE.SYMBOL.TABLE 39664 . 41547)) (41550 47707 (
-IMCOMPARE.LEFTBUTTONFN 41560 . 44137) (IMCOMPARE.MIDDLEBUTTONFN 44139 . 47255) (IMCOMPARE.COPYBUTTONFN
- 47257 . 47705)) (47760 48451 (TAIL1 47770 . 48124) (TAIL2 48126 . 48449)))))
+  (FILEMAP (NIL (1345 42591 (COMPARETEXT 1355 . 2855) (COMPARETEXT.WINDOW 2857 . 7675) (
+COMPARETEXT.TEXTOBJ 7677 . 12786) (COMPARETEXT.SETSEL 12788 . 13578) (CHUNKNODELABEL 13580 . 14701) (
+IMCOMPARE.BOXNODE 14703 . 15470) (IMCOMPARE.CHUNKS 15472 . 19848) (IMCOMPARE.COLLECT.HASH.CHUNKS 19850
+ . 22767) (IMCOMPARE.DISPLAYGRAPH 22769 . 30612) (IMCOMPARE.HASH 30614 . 34801) (
+IMCOMPARE.MERGE.CONNECTED.CHUNKS 34803 . 38299) (IMCOMPARE.MERGE.UNCONNECTED.CHUNKS 38301 . 40256) (
+IMCOMPARE.SHOW.DIST 40258 . 40704) (IMCOMPARE.UPDATE.SYMBOL.TABLE 40706 . 42589)) (42592 48749 (
+IMCOMPARE.LEFTBUTTONFN 42602 . 45179) (IMCOMPARE.MIDDLEBUTTONFN 45181 . 48297) (IMCOMPARE.COPYBUTTONFN
+ 48299 . 48747)) (48802 49493 (TAIL1 48812 . 49166) (TAIL2 49168 . 49491)))))
 STOP
