	   Features of Dandee Menu  V1.04


    1. Uses very little memory, takes about 160 bytes.
    2. Is Multi-User - some others are, some aren't, some only work with
       selected networks.
    3. Not a lot of Money
    4. No Royalties or any of that crap.
    5. Does not use Graphics - some terminals on multi-user systems dislike
       anything other then pure text mode.
    7. Can be maintained by the end user.
    8. Calculator - Calendar - Events
       When Menu starts up it will check to see if any events are scheduled
       and if so, will go to a reminder screen,with ringer.
    9. Alt E will pop up the event screen at any time, with a ringer for
       today's events.
   10. Alt D will pop up a calendar, with access to the event scheduler
   11. Alt C will pop up a calculator.
   12. Alt R will execute dos commands
   13. User definable parameters for Screen Blanking
   14. Passwords for Options - Menu Changes - Exit to Dos
       Default Password is    PASS    all caps
   15. PassWords for individual menu selections
   16. Returns to Last Menu after execution
   17. Variable paths for MenuFile - Mentitle - Dates - DDmenu.bat
   18. Screen Saver

Installation:

    Install it in any subdir you desire, it uses no path, looks where it is,
    or in the variable path setup.
    When you run it for the first time, you can setup your program drives and
    paths.

    The system relies on a batch file named DDMENU.BAT. If it is missing, type
    DANDEE and the program will create it for you.

    Other batch files A.BAT thru P.BAT and AA.BAT thru XX.BAT will be created
    as needed.

    Include the location of DDmenu.bat in your system Path so it can be found
    form any directory/Drive location.
    Your path may look like this in autoexec.bat
    Path=c:\dos;c:\windows;c:\menu     DDmenu.Bat may reside in c:\menu

    To Run, just type	DDmenu	 If it is missing just	Dandee

    There is on-line help using F1 that will explain how to set up your menu's.

 !! Multi User Systems !!

	Multi-User systems have a problem sharing batch files, so now you can
	put a copy of Dandee.exe - Control.Dat - D_rec.Dat - Pass.dat in a
	unique directory for each user, and the program will will either create
	the batch files A thru XX as needed, or you can copy a master set to
	each users directory.
	You can also share the same Menufile, Menu Titles, and Dates(Events)
	by setting the pathname variable to the directory where the files
	reside, or you can create new ones for each user, or copy in a master
	set to their directory, and customize them.

	To set the pathname variable for the above mentioned files, press
	ALT O from the Page 1 Menu screen.

	Example of variable paths.

  IMPORTANT NOTE: Include the location of ddmenu.bat in the user's path

		    Ŀ
		     Contains - Menufile.*  Mentitle.*	 Dates.*  Pass.*
 \Menu Ĵ *.Hlp and all the master *.bat *.exe Etc.		
  		     The Console might use this directory		
  		    
  		    Ŀ
  		     This directory may only contain Dandee.exe, Pass.Dat 
 \User1 Ĵ Control.Dat d_rec.Dat Dandee.Hlp and all the	   
  		     master *.bat files. This the user would be using	   
  		     all the menu defs form \menu. DDmenu.Bat can also	   
  		     be here, but will be created if it doesn't exit.	   
  		    
  		    Ŀ
  		     User 2 may be someone with very low access so	    
 \User2		     would only copy Dandee.Exe, D_rec.Dat, *.hlp Pass.dat 
		     and Control.dat to their directory. Make sure the	    
		     Variable path is set to nothing, and all the *.bat    
		     MenuFile.*, MenTitle.* and dates.* wil be created	    
		     automatically. You could also copy in the master	    
		     set and Edit them accordingly. You could also	    
		     point the menu title file to \menu and the	    
		     menufile to nothing, this would show all the	    
		     standard menu titles, but not the menu selections.    
		    							    
		     There are many more combinations.			    
		    

    There is on-line help using F1 that will explain how to set up your menu's.

    This is a live program, use it as you like. If you want to become
    registered user.
    Send $15.00 Check or Money Order to:
					Dan Scott
					8 Applewood Dr
					Ballston Lake, NY 12019

    Include your name, address, phone and your Company Name if applicable.



    Registered Version:

    Will allow you to change the Licensed To: Name, and also the
    Distributed By information on the intro screen will show your company
    information. There are no limitations or royalties or anything, distribute
    as many copies as you like. You can get the latest updates from my
    BBS free for 1 year.

    If you have any problems, give me a call (518) 899-2033 or on CIM Clarion
    forum  Daniel K. Scott 74170,1201

    Have Fun !!



   Dandee Menu, and associated programs & documentation are hereby released
   as SHAREWARE.  This gives you the right to use the software for your
   evaluation purposes.	 Sale or Inclusion with commercial or distributed
   software is not allowed as evaluation.  If you continue to use Dandee Menu
   please consider the remitance of the software registration fee and register
   the software.


	   NOTICE:
	   This software has NO WARRANTY, either express or implied.
	    Use it at your own risk.


			       Disclaimer
			      

Dan Scott, makes no warranties, either express or implied, including
the implied warranties of fitness for a particular purpose or mechantability,
and Dan Scott shall not be liable for tort, indirect, special or consequential
damages such as loss of profits or loss of good will from the use or inability
to use the software for any purpose.


     I have included the file defs for Dates.* in case you want to interface
     the Date file with some of your programs.
     I have also included the code for Ent_dates and Upd_dates in case you want
     to access the Dates file within your programs.


!! Dates Files	(events are stored here)

DATES	     FILE,name('dates'),PRE(DAT),CREATE,RECLAIM
DATE_KEY       KEY(DAT:DATE),DUP,NOCASE
MD_KEY	       KEY(DAT:MNTHDAY),DUP,NOCASE     ! keyed on month and day
NOTES	       MEMO(400)
RECORD	       RECORD
DATE		 LONG
EVENT		 STRING(30)	    ! desc of event
DURATION	 STRING(1)	    ! Always or Onetime
TIME		 STRING(5)	    ! Human Time Entry @p##-##p
LTIME		 LONG		    ! Clarion Time @d1
AP		 STRING(2)	    ! am/pm
TESTDAYS	 LONG		    ! Used to see if event should be displayed
MNTHDAY		 LONG		    ! Month(today()) & day(today())
	     . .
	     GROUP,OVER(DAT:NOTES)  ! notes about the event
DAT_MEMO_ROW   STRING(40),DIM(10)
	     .

!!! --- Included Code for dates Access ------ !!!

!! ----------------  Update the date file ---------------!!
	     MEMBER()
UPD_DATES    PROCEDURE
Screen	     SCREEN	  WINDOW(22,44),AT(3,18),PRE(Scr),HUE(15,4)
	       ROW(2,2)	  PAINT(9,42),HUE(15,1)
	       ROW(22,2)  PAINT(1,42),HUE(0,7)
	       ROW(11,4)  PAINT(1,4),HUE(14,0)
	       ROW(3,3)	  PAINT(7,8),HUE(14,1)
	       ROW(9,17)  PAINT(1,17),HUE(14,1)
	       ROW(7,15)  PAINT(1,14),HUE(14,1)
	       ROW(3,22)  PAINT(1,5),HUE(14,1)
	       ROW(3,37)  PAINT(1,5),HUE(14,1)
	       ROW(11,43) PAINT(10,1),HUE(15,1)
	       ROW(21,1)  PAINT(1,1),HUE(15,1)
	       ROW(11,2)  PAINT(10,1),HUE(15,1)
	       ROW(11,3)  PAINT(1,1),HUE(0,7)
	       ROW(21,2)  PAINT(1,42),HUE(14,1)
	       ROW(1,1)	  STRING('{42}'),HUE(8,1)
	       ROW(2,1)	  REPEAT(20);STRING(''),HUE(8,1) .
	       ROW(22,1)  STRING(''),HUE(8,1)
	       ROW(1,44)  STRING(''),HUE(15,1)
	       ROW(2,44)  REPEAT(20);STRING(''),HUE(15,1) .
	       ROW(22,2)  STRING('{42}'),HUE(15,1)
	       ROW(3,3)	  STRING('Date')
	       ROW(5,3)	  STRING('Event')
	       ROW(7,3)	  STRING('Keep')
	       ROW(9,3)	  STRING('Remind')
		 COL(10)  STRING('m'),HUE(14,1)
		 COL(11)  STRING('e'),HUE(14,1)
		 COL(17)  STRING('days before event')
	       ROW(11,2)  STRING('N'),HUE(15,1)
	       ROW(13,2)  STRING('O'),HUE(15,1)
	       ROW(15,2)  STRING('T'),HUE(15,1)
	       ROW(17,2)  STRING('E'),HUE(15,1)
	       ROW(19,2)  STRING('S'),HUE(15,1)
MESSAGE	       ROW(2,8)	  STRING(30),ENH
date	       ROW(6,8)	  STRING(@D1),HUE(1,1)
STIME		 COL(34)  STRING(@T3),HUE(1,1)
		 COL(41)  ENTRY,USE(?First_Field)
	       ROW(3,11)  STRING(':')
		 COL(12)  ENTRY(@D1),USE(DAT:DATE),HLP('DATEH'),INS
		 COL(22)  STRING('Time:')
		 COL(28)  ENTRY(@p##:##p),USE(DAT:TIME),HLP('TIM'),SEL(14,4),OVR
		 COL(34)  MENU(@S2),USE(DAT:AP),SEL(14,4)
		 COL(37)    STRING('AM')
		 COL(40)    STRING('PM')
			  .
	       ROW(5,11)  STRING(':')
		 COL(12)  ENTRY(@S30),USE(DAT:EVENT),HLP('EVENT'),OVR,UPR
	       ROW(7,11)  STRING(':')
		 COL(12)  MENU(@S1),USE(DAT:DURATION),HLP('DUR')
		 COL(15)    STRING('Always'),SEL(14,4)
		 COL(22)    STRING('OneTime'),SEL(14,4)
			  .
	       ROW(9,12)  STRING(' '),HUE(15,1)
		 COL(13)  ENTRY(@N3),USE(DAT:TESTDAYS),HLP('TEST'),INS
	       ROW(11,3)  TEXT(10,40),USE(DAT:NOTES),HLP('NOTE'),SEL(1,7),OVR,LFT,UPR
	       ROW(21,8)  PAUSE('ESCAPE to ReDo - ENTER to Record'),USE(?PAUSE_FIELD),HUE(26,1)
	       ROW(22,40) ENTRY,USE(?Last_Field)
	       ROW(22,40) ENTRY,USE(?delete_Field)
		 COL(40)  PAUSE(''),USE(?Pause)
	     .

TABLE	     TABLE,PRE(SAV)
SAVE_RECORD    GROUP;BYTE,DIM(SIZE(DAT:RECORD)).
SAVE_MEMO      GROUP;BYTE,DIM(SIZE(DAT:NOTES)).
	     .


  EJECT
  CODE
  OPEN(SCREEN)					 !OPEN THE SCREEN
  SETCURSOR					 !TURN OFF ANY CURSOR
  SAVE_RECORD = DAT:RECORD			 !SAVE THE ORIGINAL
  SAVE_MEMO   = DAT:NOTES			 !SAVE THE ORIGINAL
  ADD(TABLE,1)					 !STORE IN MEMORY TABLE
  IF ACTION = 5					 !AUTONUMBER ACTION
    DISK_ACTN# = 2				 !  SET FOR PHYSICAL ACTION
    ACTION = 1					 !  SET FOR LOGICAL ACTION
  ELSE						 !OTHERWISE
    DISK_ACTN# = ACTION				 !  SET ACTION FOR DISK WRITE
  .
  DISPLAY					 !DISPLAY THE FIELDS

  EXECUTE DISK_ACTN#				 !SET THE CURRENT RECORD POINTER
    POINTER# = 0				 !  NO RECORD FOR ADD
    POINTER# = POINTER(DATES)			 !  CURRENT RECORD FOR CHANGE
    POINTER# = POINTER(DATES)			 !  CURRENT RECORD FOR CHANGE
  .
  ACTION# = ACTION				 !STORE REQUIRED ACTION
  LOOP						 !LOOP THRU ALL THE FIELDS
    MEM:MESSAGE = CENTER(MEM:MESSAGE)		 !DISPLAY ACTION MESSAGE
    DO CALCFIELDS				 !CALCULATE DISPLAY FIELDS
    ALERT					 !RESET ALERTED KEYS
    ALERT(ACCEPT_KEY)				 !ALERT SCREEN ACCEPT KEY
    ALERT(REJECT_KEY)				 !ALERT SCREEN REJECT KEY
    ACCEPT					 !READ A FIELD
    IF KEYCODE() = REJECT_KEY THEN BREAK.	 !RETURN ON SCREEN REJECT KEY
    EXECUTE ACTION				 !SET MESSAGE
      MEM:MESSAGE = 'Record will be Added'	 !
      MEM:MESSAGE = 'Record will be Changed'	 !
      MEM:MESSAGE = 'Press Enter to Delete'	 !
    .
    IF KEYCODE() = ACCEPT_KEY			 !ON SCREEN ACCEPT KEY
      UPDATE					 !  MOVE ALL FIELDS FROM SCREEN
      SELECT(?)					 !  START WITH CURRENT FIELD
      SELECT					 !  EDIT ALL FIELDS
      CYCLE					 !  GO TO TOP OF LOOP
    .
    CASE FIELD()				 !JUMP TO FIELD EDIT ROUTINE
    OF ?FIRST_FIELD				 !FROM THE FIRST FIELD
      IF KEYCODE() = ESC_KEY THEN BREAK.	 !  RETURN ON ESC KEY
      IF ACTION = 3 THEN SELECT(?DELETE_FIELD).!    OR CONFIRM FOR DELETE

    OF ?DAT:TIME
      if keycode()=accept_key then select(?+1).

    OF ?DAT:AP
      scr:stime = dat:time&dat:ap;if dat:time > 1 then dat:ltime=scr:stime else dat:ltime=0;dat:ap=''.

      OF ?PAUSE_FIELD				 !ON PAUSE FIELD
	IF KEYCODE() <> ENTER_KEY|		 !IF NOT ENTER KEY
	AND KEYCODE() <> ACCEPT_KEY|		 !AND NOT CTRL-ENTER KEY
	AND KEYCODE() <> 0			 !AND NOT NONSTOP MODE
	  BEEP					 !  SOUND KEYBOARD ALARM
	  SELECT(?PAUSE_FIELD)			 !  AND STAY ON PAUSE FIELD
	.

    OF ?LAST_FIELD				 !FROM THE LAST FIELD
      IF KEYCODE() = 0				 !IF IN AUTO SELECT MODE
	DO CALCFIELDS				 !  DO CALCULATIONS
	SELECT(?)				 !  TURN IT OFF
      .
      IF ACTION = 2 OR ACTION = 3		 !IF UPDATING RECORD
	SAVE_RECORD = DAT:RECORD		 !  SAVE CURRENT CHANGES
	SAVE_MEMO   = DAT:NOTES			 !  SAVE CURRENT CHANGES
	ADD(TABLE,2)				 !  STORE IN MEMORY TABLE
	GET(TABLE,1)				 !  RETRIEVE ORIGINAL RECORD
	HOLD(DATES,.10)				 !  TRY TO HOLD FILE
	GET(DATES,POINTER#)			 !  RE-READ SAME RECORD
	IF ERRORCODE() = 43			 !  IF RECORD WAS ALREADY HELD
	  RECOVER(120)				 !    ARM RECOVER
	  HOLD(DATES)				 !    HOLD FILE
	  GET(DATES,POINTER#)			 !    RE-READ SAME RECORD
	  RECOVER()				 !    DISARM RECOVER
	.
	IF ERRORCODE() = 35			 !  IF RECORD WAS DELETED
	  IF DISK_ACTN# = 2			 !  IF TRYING TO UPDATE
	     DISK_ACTN# = 1			 !    THEN ADD IT BACK
	  ELSE					 !
	     RELEASE(DATES)			 !  RELEASE FILE
	     ACTION = 0				 !  TURN OFF ACTION
	  .
	ELSIF |					 !OTHERWISE
	  DAT:NOTES <> SAVE_MEMO OR |		 !  IF IT HAS BEEN CHANGED
	  DAT:RECORD <> SAVE_RECORD		 !    BY ANOTHER STATION
	  MEM:MESSAGE = 'CHANGED BY ANOTHER STATION' !INFORM USER
	  SELECT(2)				 !  GO BACK TO TOP OF FORM
	  BEEP					 !  SOUND ALARM
	  RELEASE(DATES)			 !  RELEASE FILE
	  SAVE_RECORD = DAT:RECORD		 !  SAVE RECORD
	  SAVE_MEMO = DAT:NOTES			 !  SAVE MEMO
	  DISPLAY				 !  DISPLAY THE FIELDS
	  PUT(TABLE)				 !  FREE SAVED CHANGES
	  CYCLE					 !  AND CONTINUE
	.
	GET(TABLE,2)				 !  READ CURRENT (CHANGED) REC
	DAT:RECORD = SAVE_RECORD		 !  MOVE RECORD
	DAT:NOTES = SAVE_MEMO			 !  MOVE MEMO
	DELETE(TABLE)				 !  DELETE MEMORY TABLE ITEM
      .
      EXECUTE DISK_ACTN#			 !  UPDATE THE FILE
	ADD(DATES)				 !    ADD NEW RECORD
	PUT(DATES)				 !    CHANGE EXISTING RECORD
	DELETE(DATES)				 !    DELETE EXISTING RECORD
      .
      IF ERRORCODE() = 40			 !  DUPLICATE KEY ERROR
	MEM:MESSAGE = ERROR()			 !    DISPLAY ERR MESSAGE
	SELECT(2)				 !    POSITION TO TOP OF FORM
	IF ACTION = 2 THEN RELEASE(DATES). !	      RELEASE HELD RECORD
	CYCLE					 !    GET OUT OF EDIT LOOP
      ELSIF ERROR()				 !  CHECK FOR UNEXPECTED ERROR
	EXECUTE ACTION				 !    BUILD AN ERROR MESSAGE
	  ERROR" = 'Error: ' & ERROR() & ' ' |	 !	FOR ADDING
		   & 'Adding to DATES'
	  ERROR" = 'Error: ' & ERROR() & ' ' |	 !	FOR CHANGE
		   & 'Changing DATES'
	  ERROR" = 'Error: ' & ERROR() & ' ' |	 !	FOR DELETING
		   & 'Deleting from DATES'
	.
	STOP(ERROR")				 !    HALT EXECUTION
      .
      IF ACTION = 1 THEN POINTER# = POINTER(DATES). !POINT TO RECORD
      SAVE_RECORD = DAT:RECORD			 !  NEW ORIGINAL
      SAVE_MEMO = DAT:NOTES			 !  NEW ORIGINAL
      ACTION = ACTION#				 !  RETRIEVE ORIGINAL OPERATION
      ACTION = 0				 !  SET ACTION TO COMPLETE
      BREAK					 !  AND RETURN TO CALLER

    OF ?DELETE_FIELD				 !FROM THE DELETE FIELD
      IF KEYCODE() = ENTER_KEY |		 !  ON ENTER KEY
      OR KEYCODE() = ACCEPT_KEY			 !  OR CTRL-ENTER KEY
	SELECT(?LAST_FIELD)			 !    DELETE THE RECORD
      ELSE					 !  OTHERWISE
	BEEP					 !    BEEP AND ASK AGAIN
  . . .
  FREE(TABLE)					 !  RELEASE MEMORY TABLE
  RETURN					 !  AND RETURN TO CALLER

CALCFIELDS   ROUTINE
  IF FIELD() > ?FIRST_FIELD			 !BEYOND FIRST_FIELD?
    IF KEYCODE() = 0 AND SELECTED() > FIELD() THEN EXIT. !GET OUT IF NOT NONSTOP
  .
  SCR:MESSAGE = MEM:MESSAGE
  SCR:DATE = dat:date;dat:mnthday=sub(scr:date,1,2)&sub(scr:date,4,2)
  SCR:STIME = dat:time&dat:ap;if dat:time > 1 then dat:ltime=scr:stime.
  DAT:LTIME = SCR:STIME

!! --------End of Upd_dates-------!!


!! --------------- Date Table -----------------!!
	     MEMBER()
ENT_DATES    PROCEDURE

SCREEN	     SCREEN	  WINDOW(21,57),AT(2,11),PRE(SCR),HLP('ENTDATES'),HUE(0,3)
	       ROW(6,4)	  PAINT(13,51),HUE(0,7)
	       ROW(6,9)	  PAINT(1,5),HUE(1,7)
	       ROW(1,1)	  STRING('{55}'),ENH
	       ROW(2,1)	  REPEAT(19);STRING(''),ENH .
	       ROW(21,1)  STRING(''),ENH
	       ROW(1,57)  STRING(''),HUE(15,3)
	       ROW(2,57)  REPEAT(19);STRING(''),HUE(15,3) .
	       ROW(21,2)  STRING('{55}'),HUE(15,3)
	       ROW(5,3)	  STRING('{51}'),HUE(8,7)
	       ROW(6,3)	  REPEAT(13);STRING(''),HUE(8,7) .
	       ROW(19,3)  STRING(''),HUE(8,7)
	       ROW(5,55)  STRING(''),HUE(15,7)
	       ROW(6,55)  REPEAT(13);STRING(''),HUE(15,7) .
	       ROW(19,4)  STRING('{51}'),HUE(15,7)
	       ROW(2,3)	  STRING('Locate By MM/DD:')
	       ROW(4,7)	  STRING('Date   Time   Event')
		 COL(41)  STRING('   F1 - '),HUE(1,3)
		 COL(49)  STRING('Help'),HUE(4,3)
	       ROW(20,6)  STRING('INS'),HUE(4,3)
		 COL(10)  STRING('Add'),HUE(1,3)
		 COL(17)  STRING('ENTER'),HUE(4,3)
		 COL(23)  STRING('Select'),HUE(1,3)
		 COL(33)  STRING('DEL'),HUE(4,3)
		 COL(36)  STRING(' Delete   '),HUE(1,3)
		 COL(46)  STRING('ESC'),HUE(4,3)
		 COL(50)  STRING('Exit'),HUE(1,3)
LOCATOR	       ROW(2,20)  STRING(4)
		 COL(24)  ENTRY,USE(?FIRST_FIELD)
		 COL(24)  ENTRY,USE(?PRE_POINT)
			  REPEAT(13),INDEX(Ndx)
	       ROW(6,4)	    POINT(1,50),USE(?POINT),ESC(?-1),SEL(11,4)
DATE		 COL(7)	    STRING(@p##-##p)
L2		 COL(12)    STRING(1),HUE(8,7)
TIME		 COL(13)    STRING(7),HUE(4,7)
L3		 COL(20)    STRING(1),HUE(8,7)
EVENT		 COL(21)    STRING(30),HUE(14,7)
	     .		  .

NDX	     BYTE				 !REPEAT INDEX FOR POINT AREA
ROW	     BYTE				 !ACTUAL ROW OF SCROLL AREA
COL	     BYTE				 !ACTUAL COLUMN OF SCROLL AREA
COUNT	     BYTE(13)				 !NUMBER OF ITEMS TO SCROLL
ROWS	     BYTE(13)				 !NUMBER OF ROWS TO SCROLL
COLS	     BYTE(50)				 !NUMBER OF COLUMNS TO SCROLL
FOUND	     BYTE				 !RECORD FOUND FLAG
NEWPTR	     LONG				 !POINTER TO NEW RECORD

TABLE	     TABLE,PRE(TBL)			 !TABLE OF RECORD DATA
PTR	       LONG				 !  POINTER TO FILE RECORD
DATE	       STRING(@p##-##p)
L2	       STRING(@s1)
TIME	       STRING(@s7)
L3	       STRING(@s1)
EVENT	       STRING(30)
MNTHDAY	       LONG
	     .

  EJECT
  CODE
  ACTION# = ACTION				 !SAVE ACTION
  OPEN(SCREEN)					 !OPEN THE SCREEN
  SETCURSOR					 !TURN OFF ANY CURSOR
  TBL:PTR = 1					 !START AT TABLE ENTRY
  NDX = 1					 !PUT SELECTOR BAR ON TOP ITEM
  ROW = ROW(?POINT)				 !REMEMBER TOP ROW AND
  COL = COL(?POINT)				 !LEFT COLUMN OF SCROLL AREA
  RECORDS# = TRUE				 !INITIALIZE RECORDS FLAG
  IF ACTION = 4					 !  TABLE LOOKUP REQUEST
    NEWPTR = POINTER(DATES)			 !  SET POINTER TO RECORD
    IF NOT NEWPTR				 !  RECORD NOT PASSED TO TABLE
      SET(DAT:MD_KEY,DAT:MD_KEY)		 !    POSITION TO CLOSEST RECORD
      NEXT(DATES)				 !    READ RECORD
      NEWPTR = POINTER(DATES)			 !    SET POINTER
    .
    DO FIND_RECORD				 !  POSITION FILE
  ELSE
    NDX = 1					 !  PUT SELECTOR BAR ON TOP ITEM
    DO FIRST_PAGE				 !  BUILD MEMORY TABLE OF KEYS
  .
  RECORDS# = TRUE				 !  ASSUME THERE ARE RECORDS
  LOOP						 !LOOP UNTIL USER EXITS
    ACTION = ACTION#				 !RESTORE ACTION
    ALERT					 !RESET ALERTED KEYS
    ALERT(REJECT_KEY)				 !ALERT SCREEN REJECT KEY
    ALERT(ACCEPT_KEY)				 !ALERT SCREEN ACCEPT KEY
    ACCEPT					 !READ A FIELD
    IF KEYCODE() = REJECT_KEY THEN BREAK.	 !RETURN ON SCREEN REJECT KEY

    IF	KEYCODE() = ACCEPT_KEY	  |		 !ON SCREEN ACCEPT KEY
    AND FIELD() <> ?POINT			 !BUT NOT ON THE POINT FIELD
      UPDATE					 !  MOVE ALL FIELDS FROM SCREEN
      SELECT(?)					 !  START WITH CURRENT FIELD
      SELECT					 !  EDIT ALL FIELDS
      CYCLE					 !  GO TO TOP OF LOOP
    .

    CASE FIELD()				 !JUMP TO FIELD EDIT ROUTINE

    OF ?FIRST_FIELD				 !FROM THE FIRST FIELD
      IF KEYCODE() = ESC_KEY   |		 !  RETURN ON ESC KEY
      OR RECORDS# = FALSE			 !  OR NO RECORDS
	BREAK					 !    EXIT PROGRAM
      .
    OF ?PRE_POINT				 !PRE POINT FIELD CONDITION
      IF KEYCODE() = ESC_KEY			 !  BACKING UP?
	SELECT(?-1)				 !    SELECT PREVIOUS FIELD
      ELSE					 !  GOING FORWARD
	SELECT(?POINT)				 !    SELECT MENU FIELD
      .
    IF KEYCODE() = ESC_KEY			 !  BACKING UP?
      SCR:LOCATOR = ''				 !    CLEAR LOCATOR
      SETCURSOR					 !    AND TURN CURSOR OFF
    ELSE					 !  GOING FORWARD
      LEN# = 0					 !    RESET TO START OF LOCATOR
      SETCURSOR(ROW(SCR:LOCATOR),COL(SCR:LOCATOR)) !  AND TURN CURSOR ON
    .
    OF ?POINT					 !PROCESS THE POINT FIELD
      IF RECORDS(TABLE) = 0			 !IF THERE ARE NO RECORDS
	CLEAR(DAT:RECORD)			 !  CLEAR RECORD AREA
	UPDATE					 !  UPDATE ALL FIELDS
	ACTION = 1				 !  SET ACTION TO ADD
	GET(DATES,0)				 !  CLEAR PENDING RECORD
	UPD_DATES				 !  CALL FORM FOR NEW RECORD
	NEWPTR = POINTER(DATES)			 !    SET POINTER TO NEW RECORD
	DO FIRST_PAGE				 !  DISPLAY THE FIRST PAGE
	IF RECORDS(TABLE) = 0			 !  IF THERE AREN'T ANY RECORDS
	  RECORDS# = FALSE			 !    INDICATE NO RECORDS
	  SELECT(?PRE_POINT-1)			 !    SELECT THE PRIOR FIELD
	.
	CYCLE					 !    AND LOOP AGAIN
      .
      IF KEYCODE() > 31		     |		 !THE DISPLAYABLE CHARACTERS
      AND KEYCODE() < 255			 !ARE USED TO LOCATE RECORDS
	IF LEN# < SIZE(SCR:LOCATOR)		 !  IF THERE IS ROOM LEFT
	  SCR:LOCATOR = SUB(SCR:LOCATOR,1,LEN#) & CHR(KEYCODE())
	  LEN# += 1				 !    INCREMENT THE LENGTH
	.
      ELSIF KEYCODE() = BS_KEY			 !BACKSPACE UNTYPES A CHARACTER
	IF LEN# > 0				 !  IF THERE ARE CHARACTERS LEFT
	  LEN# -= 1				 !    DECREMENT THE LENGTH
	  SCR:LOCATOR = SUB(SCR:LOCATOR,1,LEN#)	 !    ERASE THE LAST CHARACTER
	.
	ELSE					 !FOR ANY OTHER CHARACTER
	  LEN# = 0				 !  ZERO THE LENGTH
	  SCR:LOCATOR = ''			 !  ERASE THE LOCATOR FIELD
	.
	SETCURSOR(ROW(SCR:LOCATOR),COL(SCR:LOCATOR)+LEN#) !AND RESET THE CURSOR
	DAT:MNTHDAY = CLIP(SCR:LOCATOR)		 !    UPDATE THE KEY FIELD
	TIME# = CLOCK()				 !SAVE THE TIME
	LOOP UNTIL KEYBOARD()			 !WAIT FOR A KEYSTROKE
	  IF CLOCK() > TIME# + 50 THEN BREAK.	 !  BUT ONLY 1/2 OF A SECOND
	.
	IF KEYBOARD() > 31	       |	 !THE DISPLAYABLE CHARACTERS
	AND KEYBOARD() < 255	       |	 !ARE USED TO LOCATE RECORDS
	OR KEYBOARD() = BS_KEY			 !INCLUDE BACKSPACE
	  CYCLE
	.
	IF LEN# > 0				 !ON A LOCATOR REQUEST
	  DAT:MNTHDAY = CLIP(SCR:LOCATOR)	 !    UPDATE THE KEY FIELD
	  SET(DAT:MD_KEY,DAT:MD_KEY)		 !  POINT TO NEW RECORD
	  NEXT(DATES)				 !  READ A RECORD
	  IF (EOF(DATES) AND ERROR())		 !  IF EOF IS REACHED
	    SET(DAT:MD_KEY)			 !    SET TO FIRST RECORD
	    PREVIOUS(DATES)			 !    READ THE LAST RECORD
	  .
	  NEWPTR = POINTER(DATES)		 !  SET NEW RECORD POINTER
	  SKIP(DATES,-1)			 !  BACK UP TO FIRST RECORD
	  FREE(TABLE)				 !  CLEAR THE TABLE
	  DO NEXT_PAGE				 !  AND DISPLAY A NEW PAGE
	.
      CASE KEYCODE()				 !PROCESS THE KEYSTROKE

      OF INS_KEY				 !INS KEY
	CLEAR(DAT:RECORD)			 !  CLEAR RECORD AREA
	ACTION = 1				 !  SET ACTION TO ADD
	GET(DATES,0)				 !  CLEAR PENDING RECORD
	UPD_DATES				 !  CALL FORM FOR NEW RECORD
	IF ~ACTION				 !  IF RECORD WAS ADDED
	  NEWPTR = POINTER(DATES)		 !    SET POINTER TO NEW RECORD
	  DO FIND_RECORD			 !    POSITION IN FILE
	.
      OF ENTER_KEY				 !ENTER KEY
      OROF ACCEPT_KEY				 !CTRL-ENTER KEY
	DO GET_RECORD				 !  GET THE SELECTED RECORD
	IF ACTION = 4 AND KEYCODE() = ENTER_KEY!    IF THIS IS A LOOKUP REQUEST
	  ACTION = 0				 !    SET ACTION TO COMPLETE
	  BREAK					 !    AND RETURN TO CALLER
	.
	IF ~ERROR()				 !  IF RECORD IS STILL THERE
	  ACTION = 2				 !    SET ACTION TO CHANGE
	  UPD_DATES				 !    CALL FORM TO CHANGE REC
	  IF ACTION				 !    IF SUCCESSFUL RE-DISPLAY
	    ACTN# = 0 THEN CYCLE.
	.
	NEWPTR = POINTER(DATES)			 !    SET POINTER TO NEW RECORD
	DO FIND_RECORD				 !    POSITION IN FILE
      OF DEL_KEY				 !DEL KEY
	DO GET_RECORD				 !  READ THE SELECTED RECORD
	IF ~ERROR()				 !  IF RECORD IS STILL THERE
	  ACTION = 3				 !    SET ACTION TO DELETE
	  UPD_DATES				 !    CALL FORM TO DELETE
	  IF ~ACTION				 !    IF SUCCESSFUL
	    N# = NDX				 !	SAVE POINT INDEX
	    DO SAME_PAGE			 !	RE-DISPLAY
	    NDX = N#				 !	RESTORE POINT INDEX
	. .
      OF DOWN_KEY				 !DOWN ARROW KEY
	DO SET_NEXT				 !  POINT TO NEXT RECORD
	DO FILL_NEXT				 !  FILL A TABLE ENTRY
	IF FOUND				 !  FOUND A NEW RECORD
	  SCROLL(ROW,COL,ROWS,COLS,ROWS(?POINT)) !    SCROLL THE SCREEN UP
	  GET(TABLE,RECORDS(TABLE))		 !  GET RECORD FROM TABLE
	  DO FILL_SCREEN			 !  DISPLAY ON SCREEN
	.

      OF PGDN_KEY				 !PAGE DOWN KEY
	DO SET_NEXT				 !  POINT TO NEXT RECORD
	DO NEXT_PAGE				 !  DISPLAY THE NEXT PAGE

      OF CTRL_PGDN				 !CTRL-PAGE DOWN KEY
	DO LAST_PAGE				 !  DISPLAY THE LAST PAGE
	NDX = RECORDS(TABLE)			 !  POSITION POINT BAR

      OF UP_KEY					 !UP ARROW KEY
	DO SET_PREV				 !  POINT TO PREVIOUS RECORD
	DO FILL_PREV				 !  FILL A TABLE ENTRY
	IF FOUND				 !  FOUND A NEW RECORD
	  SCROLL(ROW,COL,ROWS,COLS,-(ROWS(?POINT)))! SCROLL THE SCREEN DOWN
	  GET(TABLE,1)				 !  GET RECORD FROM TABLE
	  DO FILL_SCREEN			 !  DISPLAY ON SCREEN
	.

      OF PGUP_KEY				 !PAGE UP KEY
	DO SET_PREV				 !  POINT TO PREVIOUS RECORD
	DO PREV_PAGE				 !  DISPLAY THE PREVIOUS PAGE

      OF CTRL_PGUP				 !CTRL-PAGE UP
	DO FIRST_PAGE				 !  DISPLAY THE FIRST PAGE
	NDX = 1					 !  POSITION POINT BAR
  . . .
  FREE(TABLE)					 !FREE MEMORY TABLE
  RETURN					 !AND RETURN TO CALLER

SAME_PAGE ROUTINE				 !DISPLAY THE SAME PAGE
  GET(TABLE,1)					 !  GET THE FIRST TABLE ENTRY
  DO FILL_RECORD				 !  FILL IN THE RECORD
  SET(DAT:MD_KEY,DAT:MD_KEY,TBL:PTR)		 !  POSITION FILE
  FREE(TABLE)					 !  EMPTY THE TABLE
  DO NEXT_PAGE					 !  DISPLAY A FULL PAGE

FIRST_PAGE ROUTINE				 !DISPLAY FIRST PAGE
  FREE(TABLE)					 !  EMPTY THE TABLE
  CLEAR(DAT:RECORD,-1)				 !  CLEAR RECORD TO LOW VALUES
  CLEAR(TBL:PTR)				 !  ZERO RECORD POINTER
  SET(DAT:MD_KEY)				 !  POINT TO FIRST RECORD
  LOOP NDX = 1 TO COUNT				 !  FILL UP THE TABLE
    DO FILL_NEXT				 !    FILL A TABLE ENTRY
    IF NOT FOUND THEN BREAK.			 !    GET OUT IF NO RECORD
  .
  NDX = 1					 !  SET TO TOP OF TABLE
  DO SHOW_PAGE					 !  DISPLAY THE PAGE

LAST_PAGE ROUTINE				 !DISPLAY LAST PAGE
  NDX# = NDX					 !  SAVE SELECTOR POSITION
  FREE(TABLE)					 !  EMPTY THE TABLE
  CLEAR(DAT:RECORD,1)				 !  CLEAR RECORD TO HIGH VALUES
  CLEAR(TBL:PTR,1)				 !  CLEAR PTR TO HIGH VALUE
  SET(DAT:MD_KEY)				 !  POINT TO FIRST RECORD
  LOOP NDX = COUNT TO 1 BY -1			 !  FILL UP THE TABLE
    DO FILL_PREV				 !    FILL A TABLE ENTRY
    IF NOT FOUND THEN BREAK.			 !    GET OUT IF NO RECORD
  .
  NDX = NDX#					 !  RESTORE SELECTOR POSITION
  DO SHOW_PAGE					 !  DISPLAY THE PAGE

FIND_RECORD ROUTINE				 !POSITION TO SPECIFIC RECORD
  SET(DAT:MD_KEY,DAT:MD_KEY,NEWPTR)		 !POSITION FILE
  IF NEWPTR = 0					 !NEWPTR NOT SET
    NEXT(DATES)					 !  READ NEXT RECORD
    NEWPTR = POINTER(DATES)			 !  SET NEWPTR
    SKIP(DATES,-1)				 !  BACK UP TO DISPLAY RECORD
  .
  FREE(TABLE)					 !  CLEAR THE RECORD
  DO NEXT_PAGE					 !  DISPLAY A PAGE

NEXT_PAGE ROUTINE				 !DISPLAY NEXT PAGE
  SAVECNT# = RECORDS(TABLE)			 !  SAVE RECORD COUNT
  LOOP COUNT TIMES				 !  FILL UP THE TABLE
    DO FILL_NEXT				 !    FILL A TABLE ENTRY
    IF NOT FOUND				 !    IF NONE ARE LEFT
      IF NOT SAVECNT#				 !	IF REBUILDING TABLE
	DO LAST_PAGE				 !	FILL IN RECORDS
	EXIT					 !	EXIT OUT OF ROUTINE
      .
      BREAK					 !    EXIT LOOP
  . .
  DO SHOW_PAGE					 !  DISPLAY THE PAGE

SET_NEXT ROUTINE				 !POINT TO THE NEXT PAGE
  GET(TABLE,RECORDS(TABLE))			 !  GET THE LAST TABLE ENTRY
  DO FILL_RECORD				 !  FILL IN THE RECORD
  SET(DAT:MD_KEY,DAT:MD_KEY,TBL:PTR)		 !  POSITION FILE
  NEXT(DATES)					 !  READ THE CURRENT RECORD

FILL_NEXT ROUTINE				 !FILL NEXT TABLE ENTRY
  FOUND = FALSE					 !  ASSUME RECORD NOT FOUND
  LOOP UNTIL EOF(DATES)				 !  LOOP UNTIL END OF FILE
    NEXT(DATES)					 !    READ THE NEXT RECORD
    FOUND = TRUE				 !    SET RECORD FOUND
    DO FILL_TABLE				 !    FILL IN THE TABLE ENTRY
    ADD(TABLE)					 !    ADD LAST TABLE ENTRY
    GET(TABLE,RECORDS(TABLE)-COUNT)		 !    GET ANY OVERFLOW RECORD
    DELETE(TABLE)				 !    AND DELETE IT
    EXIT					 !    RETURN TO CALLER
  .
PREV_PAGE ROUTINE				 !DISPLAY PREVIOUS PAGE
  LOOP COUNT TIMES				 !  FILL UP THE TABLE
    DO FILL_PREV				 !    FILL A TABLE ENTRY
    IF NOT FOUND THEN BREAK.			 !    GET OUT IF NO RECORD
  .
  DO SHOW_PAGE					 !  DISPLAY THE PAGE

SET_PREV ROUTINE				 !POINT TO PREVIOUS PAGE
  GET(TABLE,1)					 !  GET THE FIRST TABLE ENTRY
  DO FILL_RECORD				 !  FILL IN THE RECORD
  SET(DAT:MD_KEY,DAT:MD_KEY,TBL:PTR)		 !  POSITION FILE
  PREVIOUS(DATES)				 !  READ THE CURRENT RECORD

FILL_PREV ROUTINE				 !FILL PREVIOUS TABLE ENTRY
  FOUND = FALSE					 !  ASSUME RECORD NOT FOUND
  LOOP UNTIL BOF(DATES)				 !  LOOP UNTIL BEGINNING OF FILE
    PREVIOUS(DATES)				 !    READ THE PREVIOUS RECORD
    FOUND = TRUE				 !    SET RECORD FOUND
    DO FILL_TABLE				 !    FILL IN THE TABLE ENTRY
    ADD(TABLE,1)				 !    ADD FIRST TABLE ENTRY
    GET(TABLE,COUNT+1)				 !    GET ANY OVERFLOW RECORD
    DELETE(TABLE)				 !    AND DELETE IT
    EXIT					 !    RETURN TO CALLER
  .
SHOW_PAGE ROUTINE				 !DISPLAY THE PAGE
  NDX# = NDX					 !  SAVE SCREEN INDEX
  LOOP NDX = 1 TO RECORDS(TABLE)		 !  LOOP THRU THE TABLE
    GET(TABLE,NDX)				 !    GET A TABLE ENTRY
    DO FILL_SCREEN				 !    AND DISPLAY IT
    IF TBL:PTR = NEWPTR				 !    SET INDEX FOR NEW RECORD
      NDX# = NDX				 !    POINT TO CORRECT RECORD
  . .
  LOOP WHILE NDX <= COUNT			 !  FINISH BLANKING THE SCREEN
    BLANK(ROW(?POINT),COL(?POINT),ROWS(?POINT),COLS(?POINT))!BLANK A LINE
    NDX += 1					 !   INCREMENT NDX
  .
  NDX = NDX#					 !  RESTORE SCREEN INDEX
  NEWPTR = 0					 !  CLEAR NEW RECORD POINTER
  CLEAR(DAT:RECORD)				 !  CLEAR RECORD AREA

FILL_TABLE ROUTINE				 !MOVE FILE TO TABLE
  TBL:EVENT = DAT:EVENT
  TBL:MNTHDAY = DAT:MNTHDAY
  TBL:PTR = POINTER(DATES)			 !  SAVE RECORD POINTER
  TBL:DATE = dat:mnthday
  TBL:L2 = ''
  IF dat:ltime > 1				 !EVALUATE CONDITION
    TBL:TIME = format(dat:ltime,@t3)		 !  CONDITION IS TRUE
  ELSE						 !OTHERWISE
    TBL:TIME = ''				 !  CONDITION IS FALSE
  .
  TBL:L3 = ''

FILL_RECORD ROUTINE				 !MOVE TABLE TO FILE
  DAT:MNTHDAY = TBL:MNTHDAY

FILL_SCREEN ROUTINE				 !MOVE TABLE TO SCREEN
  SCR:DATE = TBL:DATE
  SCR:L2 = TBL:L2
  SCR:TIME = TBL:TIME
  SCR:L3 = TBL:L3
  SCR:EVENT = TBL:EVENT

GET_RECORD ROUTINE				 !GET SELECTED RECORD
  GET(TABLE,NDX)				 !  GET TABLE ENTRY
  GET(DATES,TBL:PTR)				 !  GET THE RECORD

!! ---- End of Entdates ----- !!
