Google
 

Trailing-Edge - PDP-10 Archives - decuslib20-07 - decus/20-0161/pantt.mac
There are no other files named pantt.mac in the archive.
;EDITS
;232	ADD COMPLETION DATE TO OUTPUT PATH-CHARACTER COMMAND
;233	CHANGE OUTPUT SCHEDULE TO ONLY INCLUDE INCOMPLETE TASKS
;234	MAKE SET SCHEDULE-DATE ANSWER PART OF DATABASE
;235	OUTPUT A WARNING IF SCHEDULE PASS NEEDED
;236	MARK CRITICAL PATHS CORRECTLY EVEN IF WEEKENDS COME BETWEEN TASKS
;237	[TEMP] DO NOT ROUND START DATES TO WORK DAYS (BREAKS CP
;	ANALYSIS)
;240	IF A PROJECT HAS ALREADY STARTED (HAS ACTUAL START DATE) AND
;	THERE IS A TIME-TO-DATE AND NO DEVELOPER, THE END DATE IS WRONG.
;241	STORE TSKLST INDEX IN TASK BLOCK. USE THE STORED VALUE TO SPEED
;	UP LPCHK,CKAV1A,FNDTKI
;242	PANTT DIES A HORRIBLE DEATH IF ANY STRING IS TOO LONG. ADD SOME
;	CODE TO DEFEND PANTT FROM LONG STRINGS.
;243	FIX PERT CHART BUG CAUSED BY EDIT 241
;244	PLOTTER SOFTWARE HAS A LIMIT OF 15 BITS WORTH OF X,Y DATA (BECAUSE
;	PDP-11 STORE X,Y AS SIGNED NUMBERS IN 16 BITS). OUTPUT WARNING IF
;	DATA WILL OVERFLOW.
;245	SPEED UP SCHEDULER BY REMEMBERING THAT THERE ARE NO LOOPS.
;246	ALLOW READING DATABASE IF WRITE ACCESS IS NOT ALLOWED.
;247	"?" TO NAME OF DATABASE FAILS
;250	START WORK ON ATTRIBUTES
;251	COMPLETE ATTRIBUTE CODE
;252	MAKE SURE THAT ATTRIBUTE CODE TESTS FOR VERSION 2 TASK BLOCKS

VMAJOR==4			;MAJOR VERSION NUMBER
VMINOR==3			;MINOR
VEDIT==252			;EDIT NUMBER
VWHO==0				;CUSTOMER EDIT
	TITLE PANTT - PROGRAM TO PRODUCE PERT AND GANTT CHARTS
	SUBTTL PETER M. HURLEY,  NOVEMBER 1,1977

	SEARCH MONSYM,MACSYM,PARUNV
	EXTERNAL PARSE
	.REQUIRE PARSE
	.REQUIRE SYS:MACREL

	SALL

VPANTT==<VWHO>B2+<VMAJOR>B11+<VMINOR>B17+VEDIT

	T1=1
	T2=2
	T3=3
	T4=4
	Q1=5
	Q2=6
	Q3=7
	P1=10
	P2=11
	P3=12
	P4=13
	P5=14
	P6=15
	CX=16
	P=17


;RANDOM VARIABLES

	MAXLEN==^D79		;MAXIMUM STRING LENGTH
	MAXLNW==MAXLEN/5+^D10	;NUMBER OF WORDS TO STORE MAX LENGTH STRING
				; PLUS A LARGE FUDGE FACTOR
	BOXLEN==^D10		;NUMBER OF LINES PER BOX
	GW==4			;WIDTH OF GANTT TASK 
	NGROW==6*GW		;NUMBER OF TASKS BETWEEN DATE LINES
	NOSLAK==400000,,0	;NO SLACK VALUE SET IN TKSLK
DEFINE ERRMES (TEXT) <
	JSP [	HRROI T1,[ASCIZ\? TEXT\]
		PSOUT
		HALTF
		JRST PANTT]>

DEFINE WARN (INST,TEXT) <
	JSP CX,[HRROI T1,[ASCIZ\
% TEXT
\]
		PSOUT
IFNB <INST>,<	INST>
		JRST .+1]>

DEFINE TYPE (AC,TEXT) <
	CALL [	MOVE CX,[[ASCIZ\TEXT\],,AC]
		CALLRET TYPRTN]>

DEFINE CHKTYP (TYP) <
	CAIE T1,.CM'TYP
	ERRMES (<UNEXPECTED TYPE CODE RETURNED FROM "PARSE">)>

DEFINE RETBAD (A,B) <
IFB <B>,<
IFB <A>,<	RET>
IFNB <A>,<	JRST [	MOVEI T1,A
			RET]>>
IFNB <B>,<	JRST [	B
			RETBAD (A)]>>

DEFINE PION <
	CALL PION.>

DEFINE PIOFF <
	CALL PIOFF.>

DEFINE LOCK (A) <>		;LOCK MACRO IS A NOP

DEFINE UNLOCK (A) <>

DEFINE SAVEQ <
	JSP CX,SAVQ>

DEFINE SAVEPQ <
	JSP CX,SAVPQ>

DEFINE SAVET <
	JSP CX,SAVT>

DEFINE SAVEP <
	JSP CX,SAVP>
;MACRO TO CHECK TO SEE IF A STRING IS TOO LONG. IF IT IS TOO LONG IT IS
; TRUNCATED.

DEFINE	TRUNC(LEN,MAX,TYPE,RTN,LNG,%A),<
	MOVE CX,LEN		;GET CURRENT LENGTH
	XLIST
	CAIG CX,MAX		;TOO LONG?
	JRST %A			;NO--LEAVE IT ALONE
	PUSH P,T1		;SAVE A JSYS AC
	TMSG <
% TYPE STRING TOO LONG AT RTN
>
	POP P,T1		;RESTORE AC
	MOVEI CX,MAX		;TRUNCATE THE STRING
	MOVEM CX,LEN		; ..
IFNB <LNG>,<
	JRST LNG		;DO SOMETHING SPECIAL
>
%A:!	LIST
>


;MACRO TO CHECK VERSION OF A BLOCK

DEFINE	CHKVER(VERSION,PTR,TO),<
	XLIST
	LOAD CX,BLKVER,PTR	;GET VERSION
	CAIGE CX,VERSION	;GOOD ENOUGH?
	JRST TO			;NO--GO AWAY
	LIST
>
;DATA STRUCTURES USED IN PANTT.DATA-BASE

DEFSTR (BLKTYP,-1,8,9)		;TYPE OF BLOCK
DEFSTR (BLKVER,-1,17,9)		;VERSION NUMBER OF FORMAT OF BLOCK
DEFSTR (BLKLEN,-1,35,18)	;LENGTH OF BLOCK
	.BLKLN==1		;LENGTH OF THE HEADER BLOCK

DEFSTR (PJNAM,0,35,36)		;PROJECT NAME
DEFSTR (PJDSC,1,35,36)		;PROJECT DESCRIPTION
DEFSTR (PJTKT,2,35,36)		;POINTER TO TASK TABLE
DEFSTR (PJDVL,3,35,36)		;POINTER TO DEVELOPER LIST
DEFSTR (PJFLG,4,35,36)		;PROJECT FLAGS
DEFSTR (PJPRF,5,35,36)		;PROJECT PREFERENCE CODE
	.PJLEN==10		;LENGTH OF A PROJECT BLOCK

DEFSTR (TKNAM,0,35,36)		;TASK NAME
DEFSTR (TKDSC,1,35,36)		;TASK DESCRIPTION
DEFSTR (TKPRJ,2,35,36)		;POINTER TO PROJECT BLOCK
DEFSTR (TKASD,3,35,36)		;ACTUAL STARTING DATE
DEFSTR (TKAFD,4,35,36)		;ACTUAL FINISH DATE
DEFSTR (TKESD,5,35,36)		;EARLIEST STARTING DATE
DEFSTR (TKEFD,6,35,36)		;EARLIEST FINISH DATE
DEFSTR (TKLSD,7,35,36)		;LATEST START DATE
DEFSTR (TKLFD,10,35,36)		;LATEST FINISH DATE
DEFSTR (TKELN,11,35,36)		;ESTIMATED TASK LENGTH
DEFSTR (TKALN,12,35,36)		;ACTUAL TASK LENGTH
DEFSTR (TKTTD,13,35,36)		;TIME SPENT ON TASK TO DATE
DEFSTR (TKTAD,14,35,36)		;DATE WHEN TIME-TO-DATE WAS SET
DEFSTR (TKDLP,15,35,36)		;BLOCKING TASK LIST POINTER
DEFSTR (TKBLP,16,35,36)		;BLOCKED TASK LIST POINTER
DEFSTR (TKDVL,17,35,36)		;POINTER TO DEVELOPER LIST
DEFSTR (TKFLG,20,35,36)		;TASK FLAGS
	TK%BKG==1B0		;BACKGROUND TASK
	TK%MIL==1B1		;MILESTONE
	TK%CP==1B2		;CRITICAL PATH
	TK%ADR==1B3		;ADD DEVELOPERS REQUIRED
MSKSTR (TKBKG,20,TK%BKG)
MSKSTR (TKMIL,20,TK%MIL)
MSKSTR (TKCP,20,TK%CP)
MSKSTR (TKADR,20,TK%ADR)
DEFSTR (TKPTC,20,35,7)		;PATH CHARACTER
DEFSTR (TKMSD,21,35,36)		;MINIMUM START DATE
DEFSTR (TKXCD,22,35,36)		;EXPECTED COMPLETION DATE
DEFSTR (TKXSD,23,35,36)		;EXPECTED STARTING DATE
DEFSTR (TKPRF,24,35,36)		;TASK PREFERENCE VALUE
DEFSTR (TKPL,25,35,36)		;PATH LIST
DEFSTR (TKSLK,26,35,36)		;SLACK
DEFSTR (TKRCD,27,35,36)		;REMEMBERED COMPLETION DATE
DEFSTR (TKRSD,30,35,36)		;REMEMBERED START DATE
DEFSTR (TKTKI,31,17,18)		;TASK LIST INDEX
DEFSTR (TKATR,32,35,36)		;POINTER TO ATTRIBUTE LIST
	.TKLEN==40		;LENGTH OF TASK BLOCK
DEFSTR (DVNAM,0,35,36)		;DEVELOPER'S NAME STRING
DEFSTR (DVRAT,1,35,36)		;RATE OF WORK ON THIS TASK
DEFSTR (DVHCR,2,35,36)		;HANDICAP RATING
DEFSTR (DVBKP,3,35,36)		;POINTER BACK TO TASK/PROJECT BLOCK
DEFSTR (DVLNK,4,35,36)		;POINTER TO NEXT DEVELOPER ON LIST
	.DVLEN==5		;LENGTH OF EACH DEVELOPER ENTRY

DEFSTR (DPTKP,0,35,36)		;POINTER TO BLOCKED TASK
DEFSTR (DPBTK,1,35,36)		;POINTER TO BLOCKING TASK
DEFSTR (DPDLP,2,35,36)		;BLOCKING TASK LIST POINTER
DEFSTR (DPBLP,3,35,36)		;BLOCKED LIST POINTER
	.DPLEN==4

DEFSTR (HOLSIZ,0,17,18)		;SIZE OF HOLTAB
DEFSTR (HOLUSE,0,35,18)		;NUMBER OF ENTRIES USED
	.HOLLN==^D100		;SIZE OF HOLTAB

	.PTHLN==<^D36+1+4>/5*5	;ROOM ENOUGH FOR ALL ALPHA-NUMERIC CHARS

;ATTRIBUTE BLOCKS
DEFSTR (ATRLK,0,35,36)		;POINTER TO NEXT ATTRIBUTE BLOCK
DEFSTR (ATRFL,1,35,36)		;FLAG WORD
	AT%LNG==1B0		;DESCRIPTION IS LONG
MSKSTR (ATRLG,1,AT%LNG)		;DESCRIPTION IS LONG
DEFSTR (ATRNM,2,35,36)		;POINTER TO NAME OF ATTRIBUTE
DEFSTR (ATRVL,3,35,36)		;POINTER TO VALUE OF ATTRIBUTE
	.ATRLN=4
;TYPE CODES FOR BLOCKS IN THE DATABASE
	.TYPJT==501		;TYPE CODE FOR PROJECT TABLE
	.TYTKT==502		;TYPE CODE FOR TASK TABLE
	.TYDSC==503		;TYPE CODE FOR A DESCRIPTION BLOCK
	.TYDEV==504		;TYPE CODE FOR A DELELOPER BLOCK
	.TYNAM==505		;TYPE CODE FOR A NAME BLOCK
	.TYTSK==506		;TYPE CODE FOR A TASK BLOCK
	.TYPRJ==507		;TYPE CODE FOR A PROJECT BLOCK
	.TYDEP==510		;TYPE CODE OF DEPENDENCY BLOCK
	.TYHOL==511		;TYPE CODE FOR HOLTAB
	.TYPTH==512		;TYPE CODE FOR PATH LIST
	.TYATR==513		;TYPE CODE FOR ATTRIBUTE LIST

	.VNPJT==1		;VERSION NUMBER FOR PROJECT TABLE
	.VNTKT==1		;VERSION NUMBER FOR TASK TABLE
	.VNDSC==1		;VERSION NUMBER FOR A DESCRIPTION BLOCK
	.VNDEV==1		;VERSION NUMBER FOR A DELELOPER BLOCK
	.VNNAM==1		;VERSION NUMBER FOR A NAME BLOCK
	.VNTSK==2		;VERSION NUMBER FOR A TASK BLOCK
	.VNPRJ==1		;VERSION NUMBER FOR A PROJECT BLOCK
	.VNDEP==1		;VERSION NUMBER OF DEPENDENCY BLOCK
	.VNHOL==1		;VERSION NUMBER OF HOLTAB
	.VNPTH==1		;VERSION NUMBER OF PATH LIST
	.VNATR==1		;VERSION NUMBER OF ATRIBUTE BLOCK

	TABINC==20		;EACH EXPANSION OF A TABLE GROWS THIS AMOUNT
;SCHEDULER BLOCKS
;THESE BLOCKS ARE USED TO SCHEDULE TASKS AND GENERATE GANTT CHARTS. THEY ARE
; POINTED TO BY DEVTAB. SCHEDULER BLOCKS ARE NOT PART OF THE DATABASE.
DEFSTR (SCHTK,0,35,36)		;TASK ADR
DEFSTR (SCHSD,1,35,36)		;START DATE
DEFSTR (SCHFD,2,35,36)		;FINISH DATE
DEFSTR (SCHRT,3,35,36)		;RATE
DEFSTR (SCHLN,4,35,36)		;LINK TO NEXT BLOCK
	.SCHLN==5
;STORAGE

;DATA BASE FILE DEFINITIONS

	NDBPAG==200		;NUMBER OF PAGES IN DATA BASE
	DBPAG==100		;PAGE 0 OF DATA BASE

;PAGE 0 OF THE DATA BASE FILE

	DBORG=DBPAG*1000	;ORIGIN OF WHERE TO MAP THIS FILE
	DBSIZ=DBORG+1		;NUMBER OF PAGES TO BE MAPPED
	FRSHDR=DBSIZ+1		;FREE STORAGE HEADER

	PRJTBL=FRSHDR+6		;POINTER TO THE PROJECT TABLE
	DEVTBP=PRJTBL+1		;POINTER TO DEVELOPER TABLE
	HOLTAB=DEVTBP+1		;POINTER TO HOLIDAY TABLE
	SKDITD=HOLTAB+1		;SCHEDULER DATE AND TIME
	NOLOOP=SKDITD+1		;-1 IF NO LOOPS IN DATA BASE

;FREE SPACE POOL WITHIN DATA BASE FILE

	FSP==DBPAG+1		;FIRST FREE SPACE PAGE
	NFSP==NDBPAG-1		;SIZE OF FREE SPACE POOL
	FSADR=FSP*1000		;FREE SPACE ADR
	FSLEN==NFSP*1000	;LENGTH OF FREE SPACE POOL
;LOCAL PROGRAM STORAGE ASSIGNMENTS

	MAXTSK==2000		;MAXIMUM NUMBER OF TASKS
	MAXDEV==200		;MAXIMUM NUMBER OF DEVELOPERS

DEFINE ASG (NAM,LEN) <
	NAM=ASGVAL
	ASGVAL==ASGVAL+LEN>

	ASGVAL==<DBPAG+NDBPAG>*1000

	PDLEN==1000+5*MAXTSK
ASG PDL,PDLEN			;PUSH DOWN LIST

ZERBEG==ASGVAL			;START ZEROING HERE ON INITIALIZATION

ASG TSKTBL,1			;POINTER TO THE CURRENT TASK TABLE

ASG DBJFN,1			;DATA BASE JFN 
ASG TLJFN,1			;TRANSACTION LOG JFN
ASG TRAFLG,1			;FLAG FOR THE FIRST TRANSACTION WRITE
ASG RONLY,1			;0: NORMAL  -1: READ ONLY
ASG PERTPA,1			;PERT PLACEMENT ALGORITHM
				;0: DEFAULT
				;1: ADVANCED

ASG SLOB,1			;IF NON-ZERO INHIBIT LOGGING

ASG LINCNT,1			;LINE COUNTER FOR USE DURING REPORTS

ASG COLUMN,1			;COLUMN COUNTER FOR TYPE OUT

	GTJBLN==16
ASG GTJBLK,GTJBLN		;BLOCK FOR LONG FORM GTJFN

	STRNGL==2000		;STRING TO HOLD DESCRIPTIONS
	STRNGC==STRNGL*5-1	;NUMBER OF CHARACTERS IN STRING
ASG STRING,STRNGL

	ANSWRL==200
ASG ANSWER,ANSWRL		;BLOCK TO RECEIVE PARSED COMMANDS
ASG CMDBUF,STRNGL+^D200*ANSWRL ;BLOCK TO HOLD THE COMMAND TEXT
ASG CMDPTR,1			;POINTER TO WHERE TO STORE THE COMMAND
ASG GANTSD,1			;START DATE OF GANTT CHART
ASG GNTRMX,1			;MAXIMUM GANTT ROW
ASG GNTCMX,1			;MAXIMUM GANNT COL

ZEREND==ASGVAL			;END OF AREA TO BE ZEROED

	NPW==^D15		;MAX WITDH IN PAGES OF GANTT CHART
	NCOL==^D132*NPW		;GANTT CHART SIZE
	NROW==^D200
	NROW==<NROW/NGROW>*NGROW	;MODULO DATE LINES
	ROWLEN==<NCOL+5>/6
	ROWSTL==NROW*ROWLEN

ASG ROWOFS,1			;OFFSET ROW NUMBER
ASG ROWSTG,ROWSTL
DEFINE BLDGST(A) <
ASG GST'A,<<NCOL+4>/5>>

	ZZ==0
REPEAT GW,<BLDGST(\ZZ)
	   ZZ==ZZ+1>

	NLVL==^D200			;MAX NUMBER OF LEVELS IN A PERT CHART
	SPCTBL==<NCOL+^D35>/^D36	;LENGTH OF A LINE IN THE SPACE TABLE
	SPCTBS==NLVL*SPCTBL

ASG SPCTAB,SPCTBS			;TABLE TO KEEP TRACK OF SPACE BTEWEEN BOXES


;STORAGE FOR PERT SELECTION FEATURE
ASG SELFLG,1			;-1 IF SELECTING PERT BOXES
				;0 IF NOT
ASG SELCNT,1			;NUMBER OF THINGS SELECTED
	MAXSEL==MAXTSK/8

;FIELDS WITHIN SELTAB
	DEFSTR(SLTTYP,SELTAB,17,9) ;TYPE OF THING SELECTED
	DEFSTR(SLTDAT,SELTAB,35,18) ;DATA FOR SELECTION
ASG SELTAB,MAXSEL		;TABLE OF THINGS SELECTED

;SCHEDULER STORAGE
SKDTBL==ASGVAL
ASG TSKLST,MAXTSK		;LIST OF TASKS
				;LH: USUALLY ZERO, -1 IN THE MIDDLE OF
				;    SCHEDULE PASS AND THIS TASK NOT PROCESSED
				;RH: ADDRESS OF TASK BLOCK
ASG TSKSDL,MAXTSK		;START DATES OF EACH TASK
ASG TSKFDL,MAXTSK		;FINISH DATE OF EACH TASK

;THE NEXT 5 TABLES ARE USED DURING PERT GENERATION
ASG TSKPOS,MAXTSK		;POSITION OF TASK BOX ON CHART
				;COL # OF LEFT END OF BOX, SET BY SETPOS
				; OFFSET BY FIXPOS
ASG TSKSVP,MAXTSK		;BEST VALUE OF TSKPOS (USED BY HDPLC) 
ASG TSKSKD,MAXTSK		;LEVEL # ,, COL #
				;LH: C(LH) * <BOXLEN+^D12> IS TOP OF BOX
				;    SET BY PERT0
				;RH: SEEMS UNUSED
ASG TSKWID,MAXTSK		;WIDTH OF TASK BOX
				;SET BY SETWID CALLING BOXWID
ASG TSKINV,MAXTSK		;INVISABLE TASK
				;0 MEANS PERT, -1 MEANS DON'T PERT
ASG AVLSST,MAXTSK		;SORTED SUM TABLE FOR PERT
				;FLOATING POINT AVERAGE POSITION OF ALL
				; THE BOXES CONNECTED TO THIS BOX. THIS
				; TABLE IS PARALLEL TO AVLTSK NOT TSKLST


;THE NEXT 5 TABLES ARE TEMP STORAGE FOR THE SCHEDULER AND THE PERT/GANTT
; ROUTINES. THEY DO NOT HOLD GLOBAL DATA FROM ONE FUNCTION TO THE NEXT
ASG AVLTSK,MAXTSK		;LIST OF AVAILABLE TASKS
				;THIS LIST HOLDS C(AVLCNT) TASKS. DURING
				; PERT IT HOLDS ONE ROW OF THE PERT CHART.
				;LH: SOMETIMES FLAGS BUT USUALLY ZERO
				;RH: TSKLST INDEX
ASG AVLSDL,MAXTSK		;START DATES OF AVAILABLE TASKS
ASG SKDLST,MAXTSK		;LIST OF TASKS IN SCHEDULER ORDER

ASG LVLTAB,MAXTSK		;LEVEL TABLE
ASG LVLCNT,MAXTSK		;COUNT OF CONFLICTS PER LEVEL

	BESTN==^D25		;MAX NUMBER OF PERT PLACEMENT CONFLICTS TO FIX
ASG BEST,BESTN			;BEST PLACEMENT

;DEVTAB IS A LIST OF DEVELOPERS IN TBLUK FORMAT. 
;	DEVTAB/ NUMBER OF DEVELOPERS,,NUMBER OF DEVELOPERS
;	DEVTAB+N/ ADDRESS OF ASCIZ DEVELOPER NAME,,POINTER TO FIRST SCHEDULER BLOCK
ASG DEVTAB,MAXDEV		;DEVELOPER TABLE
	SKDFRL==.SCHLN*6*MAXTSK
ASG SKDFRE,SKDFRL		;SCHEDULER FREE POOL
	SKDVAR==ASGVAL
ASG SKDFRP,1			;POINTER TO NEXT BLOCK IN SKDFRE POOL
ASG SKDFLG,1			;SCHEDULER FLAG, 0=NEED TO SCHEDULE
ASG SKDTAD,1			;TODAY'S DATE
ASG LSTSKT,1			;LAST SCHEDULED TASK
ASG SKTLST,1			;POINTER TO SCHEDULED TASK LIST

ASG TSKCNT,1			;COUNT OF TASKS IN TSKLST
ASG TSKPTR,1			;AOBJN POINTER TO TSKLST
ASG LVLPTR,1			;AOBJN POINTER TO LVLTAB
ASG SKDCNT,1			;COUNT OF SCHEDULED TASKS
ASG AVLCNT,1			;COUNT OF AVAILABLE TASKS
ASG OAVCNT,1			;OPTIMIZED AVAILABLE TASK COUNT
ASG BESTFD,1			;BEST FINISH DATE SO FAR
ASG BESTSK,1			;BEST LEVEL 0 TASK
ASG LVL0TK,1			;LEVEL 0 TASK ADR
ASG LVL0CT,1			;SKDCNT AT LEVEL 0
ASG NCNFLC,1			;NUMBER OF CONFLICTS SEEN
ASG MAXCFL,1			;MAX CONFLICTING LEVEL
ASG PASCNT,1			;COUNT OF THE NUMBER OF PASSES
ASG PAS0CT,1			;INITIAL VALUE OF PASCNT
ASG LEVEL,1			;CURRENT CONFLICT LEVEL
	NDEPTH==3		;DEPTH = 3*LEVEL
ASG DEPTH,1			;MAX SEARCH DEPTH
ASG COLMAX,1			;MAXIMUM COLUMN REACHED IN GANTT CHART
ASG AVWID,1			;AVERAGE WIDTH OF A LINE ON THE PERT CHART


SKDVRE==ASGVAL-1		;END OF SCHEDULER VARIABLES
SKDEND==ASGVAL-1		;LAST LOC ZEROED AT SCHED STARTUP

IFLE <770000-ASGVAL>,<PRINTX ? RAN OUT OF STORAGE SPACE>
	RELOC
;ENTRY VECTOR

ENTVEC:	JRST PANTT		;START ADR
	JRST REENT		;REENTER
	VPANTT			;VERSION NUMBER

;MAIN ROUTINE

PANTT:	MOVE P,[IOWD PDLEN,PDL]	;INIT THE PUSH DOWN STACK POINTER
	CALL UNMAP
	RESET			;RESET THE WORLD
	MOVE T1,[ZERBEG,,ZERBEG+1]
	SETZM ZERBEG		;ZERO THE FREE SPACE
	BLT T1,ZEREND-1
	MOVE T1,[SKDVAR,,SKDVAR+1]
	SETZM SKDVAR
	BLT T1,SKDVRE-1

;OPEN THE DATA BASE FILE

	HRROI T1,[ASCIZ/NAME OF DATA BASE FILE: /]
	CALL OPNFIL		;OPEN THE DATA BASE FILE
	 JSP ERROR		;FAILED
	MOVEM T1,DBJFN		;SAVE THE JFN OF TE DATA BASE FILE
	MOVEM T2,TLJFN		;SAVE THE JFN OF THE TRANSACTION LOG
	MOVEI T2,DBPAG		;NOW MAP THE FILE
	MOVEI T3,NDBPAG
	CALL MAPFIL		;MAP IT
	 ERRMES <DATA BASE FILE IS TOO LARGE TO BE MAPPED INTO CORE>
	MOVE T1,DBJFN		;NOW GO LOCK THE DATA BASE
	CALL ENQJFN		;LEAVE IT LOCKED TILL EXIT
	JRST LEVEL0

;REENTER ADR

REENT:	MOVE P,[IOWD PDLEN,PDL]
	JRST LEVEL0

;ENTRY POINT TO UPDATE THE TRANSACTION LOG AND THE DATA BASE

LOGLV0:	CALL UPDDB		;GO UPDATE THE DATA BASE
	JRST LEVEL0
;PARSE THE LEVEL 0 COMMAND

LEVEL0:	CALL INITRA		;INIT TRANSACTION AREA
	HRROI T1,[ASCIZ/

/]
	CALL COPCMD		;INITIALIZE EACH LINE WITH A CRLF
	HRROI T1,[ASCIZ/PANTT> /]
	MOVEI T2,LEV0CT		;GET ADR OF LEVEL 0 COMMAND TABLE
	MOVEI T3,ANSWER		;GET ADR OF ANSWER BLOCK
	CALL PARSE		;GO PARSE THIS COMMAND
	 ERRMES <ILLEGALLY FORMATTED COMMAND TABLE (LEVEL 1)>
	CALL COPCMD		;COPY THIS COMMAND TO THE BUFFER
	MOVEI P1,ANSWER		;SET UP A POINTER TO THE PARSED COMMAND
	HLRZ T1,(P1)		;GET THE FIRST FUNCTION CODE
	CAIE T1,.CMKEY		;MUST BE A KEY WORD
	ERRMES <UNKNOWN TYPE CODE RECEIVED FROM "PARSE">
	HRRZ T1,(P1)		;GET DISPATCH ADR
	AOJA P1,(T1)		;DISPATCH
;SET COMMAND

SET:	HLRZ T1,(P1)		;GET TYPE CODE
	CHKTYP (KEY)
	HRRZ T1,(P1)		;GET THE ADR OF THE ROUTINE TO GO TO
	AOJA P1,(T1)		;DISPATCH


;SET SCHEDULE-DATE COMMAND

SETDAT:	HLRZ T1,(P1)		;GET TYPE CODE
	CHKTYP (TAD)
	HRRZ T1,(P1)		;GET ADR OF DATE
	MOVE T1,ANSWER(T1)	;GET THE DATE
	CALL GETDAY		;CONVERT IT TO DAY,,0
	MOVEM T1,SKDITD		;SAVE THE INITIAL SCHEDULER TIME AND DATE
	JRST LEVEL0

;DELETE SCHEDULE-DATE COMMAND
DELDAT:	SETZM SKDITD		;CLEAR THE FLAG
	JRST LEVEL0		;THAT IS ALL

;SET PERT-PLACEMENT-ALGORITHM
SETPPA:	HLRZ T1,(P1)		;GET THE TYPE CODE
	CHKTYP (KEY)		;MUST BE A KEYWORD
	HRRZ T1,(P1)		;GET INDEX
	MOVEM T1,PERTPA		;SAVE PLACEMENT ALGORITHM
	JRST LEVEL0		;ALL DONE

;SET SLOPPY/SAFE
SETSAF:	TDZA T1,T1		;CLEAR FLAG
SETSLB:	SETO T1,		;SET FLAG
	MOVEM T1,SLOB		;STORE
	JUMPE T1,LEVEL0		;DONE IF SAVE
	TMSG <
%%WARNING: A system crash may destroy the database
>
	JRST LEVEL0		;ALL DONE
;SET HOLIDAY COMMNAD

SETHOL:	HLRZ T1,(P1)		;GET TYPE CODE
	CHKTYP (TAD)
	MOVE T1,HOLTAB		;GET TABLE ADR
	JUMPN T1,SETHO1		;ONE THERE?
	CALL BLDHOL		;NO, BUILD ONE
	 WARN (<JRST SETHO5>,<NO ROOM FOR A HOLIDAY TABLE>)
	MOVEM T1,HOLTAB		;STORE THE ADR
SETHO1:	HRRZ T1,(P1)		;GET THE DATE
	MOVE T1,ANSWER(T1)
	CALL GETDAY		;GET DAY,,0
	MOVE T3,T1
	MOVE T1,HOLTAB		;GET TABLE ADR
	LOAD T2,HOLUSE,(T1)	;GET NUMBER OF ENTRIES
	JUMPE T2,SETHO3		;IF NONE, GO ADD THIS ONE
	MOVNS T2		;SET UP AOBJN COUNTER
	HRLZS T2
	HRRI T2,1(T1)		;SKIP OVE HEADER WORD
SETHO2:	CAMN T3,(T2)		;FOUND THIS DATE?
	JRST SETHO4		;YES, DO NOT MAKE ANOTHER ENTRY
	AOBJN T2,SETHO2		;LOOP BACK LOOKING AT EACH ENTRY
SETHO3:	LOAD T2,HOLUSE,(T1)	;GET POINTER TO THE END
	LOAD T4,HOLSIZ,(T1)	;IS THERE ANY MORE ROOM?
	ADDI T2,1		;COUNT UP USE COUNT
	CAML T2,T4		;CHECK FOR ROOM
	WARN (<JRST SETHO5>,<NO MORE ROOM IN HOLIDAY TABLE>)
	STOR T2,HOLUSE,(T1)	;SAVE NEW COUNT
	ADD T2,T1		;GET POINTER TO NEW ENTRY
	MOVEM T3,(T2)		;STORE THE DATE INTO THE TABLE
SETHO4:	JRST LOGLV0		;GO LOG THIS COMMAND

SETHO5:	JRST LEVEL0		;FAILED, DO NOT LOG COMMAND


;ROUTINE TO BUILD A HOLIDAY TABLE

BLDHOL:	MOVEI T1,.HOLLN		;GET SIZE OF TABLE
	MOVEI T2,.TYHOL		;GET TYPE CODE
	MOVEI T3,.VNHOL		;AND VERSION NUMBER
	CALL ASGFRE		;GET ROOM
	 RET			;NONE
	SETZRO HOLUSE,(T1)	;INIT THE BLOCK
	MOVEI T2,.HOLLN
	STOR T2,HOLSIZ,(T1)	;SAVE LENGTH
	RETSKP			;RETURN WITH ADR IN T1

;REMEMBER (EXPECTED DATES FOR COMPARISON)

REMDAT:	CALL SCHCHK		;UPDATE ESTIMATED DATES IF NEDED
	MOVE T4,TSKPTR		;GET POINTER TO TSKLST
REMDT1:	HRRZ T3,TSKLST(T4)	;GET ADDRESS OF TASK BLOCK
	LOAD T1,BLKVER,(T3)	;GET VERSION
	CAIG T1,1		;MUST BE BIG BLOCK
	JRST VERERR		;NO--BITCH
	LOAD T1,TKEFD,(T3)	;COPY DATES
	LOAD T2,TKESD,(T3)	; ..
	STOR T1,TKRCD,(T3)	; ..
	STOR T2,TKRSD,(T3)	; ..
	AOBJN T4,REMDT1		;LOOP OVER ALL TASKS
	JRST LEVEL0		;ALL DONE

;HERE IF DATABASE HAS AN OLD BLOCK TYPE IN IT
VERERR:	HRROI T1,[ASCIZ "
% PANTT's internal database format does not support the 
% function you have requested. You need to rebuild the
% database with the following procedure:
%	PANTT>OUTPUT CONTROL-FILE foo.ctl
%	PANTT>EXIT
%	@SUBMIT foo.ctl
"]
	PSOUT
	JRST REENT		;RESET STACK AND PROMPT
;EXIT COMMAND

EXIT:	CALL UNMAP		;UNMAP THE DATA BASE FILE
	HRRZ T1,DBJFN		;NOW DEQ THE DATA BASE FILE
	CALL DEQJFN
	HRRZ T1,DBJFN		;NOW CLOSE THE DATA BASE FILE
	CLOSF
	 JSP ERROR
	HRRZ T1,TLJFN		;AND RELEASE THE TRANSACTION LOG JFN
	RLJFN
	 JFCL
	HALTF			;DONE
	JRST PANTT		;CONTINUE = START OVER AGAIN

;SCHEDULE COMMAND

SKDCMD:	CALL UPDEST		;GO UPDATE THE ESTIMATED DATES
	JRST LEVEL0		;DONE

;OUTPUT COMMAND

OUTPUT:	HLRZ T1,(P1)		;GET FUNCTION CODE
	CAIE T1,.CMKEY		;MUST BE ANOTHER KEYWORD
	ERRMES <UNKNOWN TYPE CODE RECEIVED FROM "PARSE">
	HRRZ T1,(P1)		;GET DISPATCH ADDRESS
	AOJA P1,(T1)		;DISPATCH


;ROUTINE TO OUTPUT A CONTROL FILE

DUMP:	HLRZ T1,(P1)		;GET THE TYPE CODE
	CHKTYP (OFI)
	HRRZ T1,(P1)		;GET THE JFN
	MOVE T1,ANSWER(T1)
	HRRZS Q1,T1		;RH ONLY
	MOVE T2,[070000,,OF%WR]	;OPEN IT FOR WRITE
	OPENF
	 WARN (<JRST LEVEL0>,<COULD NOT OPEN THE CONTROL FILE>)
	CALL OUTCTL		;OUTPUT THE CONTROL FILE
	MOVE T1,Q1		;GET THE JFN
	CLOSF			;CLOSE IT
	 WARN (,<COULD NOT CLOSE THE CONTROL FILE>)
	JRST LEVEL0		;DONE
;PLOT COMMAND

PLOT:	HLRZ T1,(P1)		;GET FUNCTION CODE
	CAIE T1,.CMKEY		;MUST BE ANOTHER KEYWORD
	ERRMES <UNKNOWN TYPE CODE RECEIVED FROM "PARSE">
	HRRZ T1,(P1)		;GET DISPATCH ADDRESS
	AOJA P1,(T1)		;DISPATCH

;LIST OVERALL DEVELOPERS

LSTDEV:	HLRZ T1,(P1)		;GET TYPE CODE
	CHKTYP (OFI)
	HRRZ T1,(P1)		;GET THE JFN
	MOVE T1,ANSWER(T1)
	MOVE T2,[070000,,OF%WR]	;OPEN IT FOR WRITE
	OPENF
	 JSP ERROR
	MOVE Q1,T1		;SAVE THE JFN
	MOVE T2,DEVTBP		;GET THE POINTER TO THE DEV LIST
	CALL TYPDEV		;GO TYPE OUT THE DEVELOPERS
	MOVE T1,Q1
	TYPE T1,<&>
	HRRZ T1,Q1		;GET THE JFN
	CLOSF			;CLOSE IT
	 JFCL
	JRST LEVEL0		;DONE
;THE LIST COMMAND

LSTCMD:	HLRZ T1,(P1)		;GET THE TYPE CODE
	CHKTYP (KEY)
	HRRZ T1,(P1)		;GET ADR
	AOJA P1,(T1)

;LIST PROJECT

LISTP:	HLRZ T1,(P1)		;GET TYPE CODE
	CHKTYP (KEY)
	HRRZ P2,(P1)		;SET UP PROJECT ADR
	HLRZ T1,1(P1)		;GET NEXT TYPE CODE
	CAIN T1,.CMCFM		;CONFIRM?
	JRST LISTP1		;YES, GO LIST THE WHOLE PROJECT
	CHKTYP (KEY)		;MUST BE A TASK
	HRRZ P3,1(P1)		;GET THE TASK BLOCK ADR
	CALL SCHWRN		;OUTPUT POSSIBLE WARNING
	MOVEI T1,.PRIOU		;GET OUTPUT JFN
	MOVE T2,P3		;GET TASK BLOCK ADR
	CALL TYPTSK		;TYPE THE TASK
	JRST LEVEL0

LISTP1:	CALL SCHWRN		;OUTPUT POSSIBLE WARNING
	MOVEI T1,.PRIOU		;OUTPUT TO THE TTY
	MOVE T2,P2		;GET PROJECT BLOCK ADR
	CALL TYPPRJ		;TYPE OUT THE PROJECT
	JRST LEVEL0
;PERT CHART GENERATOR

PERT:	TDZA T1,T1		;FLAG NORMAL PERT
SPERT:	SETOM T1		;FLAGE SELECTED PERT
	MOVEM T1,SELFLG		;SAVE THE FLAG
	HLRZ T1,(P1)		;GET TYPE CODE
	CHKTYP (OFI)
	HRRZ T1,(P1)		;GET THE JFN
	MOVE Q1,ANSWER(T1)
	MOVE T1,Q1		;OPEN THE JFN
	MOVE T2,[070000,,OF%WR]	;7 BIT BYTES
	OPENF
	 JSP ERROR
	SKIPE SELFLG		;WANT TO SELECT?
	CALL SELECT		;YES
	CALL SCHCHK		;UPDATE ESTIMATED DATES IF NEDED
	MOVE T1,Q1		;GET THE JFN
	HRROI T2,[ASCIZ/
PERT CHART  -  /]
	SETZ T3,
	SOUT
	SETO T2,		;GET TODAYS DATE
	ODTIM
	HRROI T2,[ASCIZ/

/]
	SOUT
	CALL INISPC		;INIT SPACE TABLE
	SETZ Q2,		;INIT ROW OFFSET
LPERT1:	MOVEI T1,0		;LPT
	MOVE T2,Q2		;GET THE ROW OFFSET
	CALL PERT0		;GO BUILD THE PERT
	MOVE Q3,T1		;SAVE THE ROW
	HRL Q3,T2		;AND THE COL
	MOVE T3,T2		;GET MAX COL
	HRRZ T2,Q3		;GET THE ROW
	SUBI T2,(Q2)		;MINUS THE OFFSET
	MOVE T1,Q1		;GET JFN
	HLRZ T4,Q2		;GET THE COL OFFSET
	CALL PRISTO		;PRINT ANSWER
	ADDI Q2,NROW		;STEP TO THE NEXT SECTION
	HRRZ T1,Q3		;GET MAX ROW
	SUBI T1,(Q2)		;GET NUMBER OF ROWS LEFT
	JUMPG T1,LPERT1		;IF MORE ROWS, GO DO THEM
	HLRZ T1,Q2		;GET COL OFFSET
	ADDI T1,^D132		;STEP TO NEXT PAGE
	HRLZM T1,Q2		;START AT THIS COL AND ROW 0
	HLRZ T2,Q3		;GET MAX COL
	CAML T1,T2		;DONE?
	JRST LPERT2		;YES
	MOVE T1,Q1		;GET JFN
	HRROI T2,[ASCIZ/
.
/]
	SETZ T3,
	SOUT
	MOVEI T2,14		;FORM FEED
	BOUT
	HRROI T2,[ASCIZ/


/]
	SOUT
	JRST LPERT1		;LOOP BACK FOR REST OF COLUMNS

LPERT2:	HLRZ T1,Q3		;GET COL MAX
	CAILE T1,NCOL		;WAS THERE TRUNCATION?
	WARN (,<% CAUTION: MAXIMUM WIDTH EXCEEDED, TRUNCATION OCCURED>)
	HRRZ T1,Q1		;DONE, NOW CLOSE THE JFN
	CLOSF
	 JFCL
	JRST LEVEL0		;DONE
;PERT CHART PLOTTER

PPLOT:	TDZA T1,T1		;FLAG NORMAL PERT
SPPLOT:	SETOM T1		;FLAG SELECTED PERT
	MOVEM T1,SELFLG		;SAVE FLAG
	HLRZ T1,(P1)		;GET TYPE CODE
	CHKTYP (OFI)
	HRRZ T1,(P1)		;GET THE JFN
	MOVE Q1,ANSWER(T1)
	MOVE T1,Q1		;OPEN THE JFN
	MOVE T2,[070000,,OF%WR]	;7 BIT BYTES
	OPENF
	 JSP ERROR
	SKIPE SELFLG
	CALL SELECT
	CALL SCHCHK		;UPDATE ESTIMATED DATES IF NEDED
	CALL INISPC		;INIT THE SPACE TABLE
	SETZ Q2,		;INIT THE ROW OFFSET
PPLOT1:	MOVEI T1,1		;PLOTTER
	MOVE T2,Q2		;GET THE ROW OFFSET
	CALL PERT0		;GO BUILD THE PERT
	MOVE Q3,T1		;SAVE THE MAX ROW
	HRL Q3,T2		;AND THE MAX COL
	MOVE T3,T2		;GET MAX COL
	HRRZ T2,Q3		;GET THE ROW
	SUB T2,Q2		;MINUS THE OFFSET
	MOVE T1,Q1		;GET JFN
	CALL PRIPLT		;OUTPUT THE TEXT TO THE PLOTTER FILE
	ADDI Q2,NROW		;STEP THE ROW OFFSET
	HRRZ T1,Q3		;GET THE MAX ROW
	SUB T1,Q2		;SEE IF THERE ARE ANY ROWS LEFT TO DO
	JUMPG T1,PPLOT1		;IF YES, GO DO THEM
	HLRZ T1,Q3		;GET COL MAX
	CAILE T1,NCOL		;WAS THERE TRUNCATION?
	WARN (,<% CAUTION: MAXIMUM WIDTH EXCEEDED, TRUNCATION OCCURED>)
	HRRZ T1,Q1		;GET THE JFN
	MOVE T2,SKDTAD		;GET DATE
	CALL DBOX		;DRAW THE BOXES
	HRRZ T1,Q1		;GET THE JFN
	CALL CBOX		;GO CONNECT THE BOXES
	HRRZ T1,Q1		;COPY JFN
	SKIPE SELFLG		;PLOTTING ONLY SOME STUFF
	CALL TICKS		;YES--PUT IN TICK MARKS
	HRRZ T1,Q1		;DONE, NOW CLOSE THE JFN
	CLOSF
	 JFCL
	JRST LEVEL0		;DONE
;ROUTINE TO PERT THE TASKS
;ACCEPTS IN T1/	0 = LPT, 1 = PLOTTER
;	    T2/	COL OFFSET,,ROW OFFSET
;RETURNS +1:	T1/	MAX ROW
;		T2/	MAX COL

PERT0:	SAVEQ
	MOVE Q3,T1		;SAVE THE OUTPUT TYPE
	MOVE Q1,T2		;SAVE FLAG
	HRRZ T1,T2		;GET THE ROW OFFSET
	CALL INISTO		;INITIALIZE THE STORAGE AREA
	JUMPN Q1,PERT5B		;SKIP PLACEMENT IF NOT FIRST CALL
	MOVE Q1,TSKPTR		;INIT THE TABLES
PERT1:	HRROS TSKLST(Q1)	;-1 IN LH MEANS NOT SCHEDULED
	SETZM TSKPOS(Q1)
	SETZM TSKWID(Q1)
	SETZM TSKSKD(Q1)
	SETZM TSKINV(Q1)	;MARK TASK AS VISIBLE
	MOVE T1,TSKLST(Q1)
	CALL PRTTSK		;WANT THIS TASK IN PERT?
	  SETOM TSKINV(Q1)	;NO
	AOBJN Q1,PERT1
	MOVEI Q1,0		;START AT LEVEL 0
PERT2:	SUBI Q1,1		;COUNT DOWN THE LEVEL NUMBER
	MOVEI T1,1		;DO A REVERSE SCAN OF THE AVAILABLE LIST
	CALL BLDPAV		;SET UP AVLTSK LIST
	 JRST PERT4		;NO MORE TO DO
	MOVN T1,AVLCNT		;SET UP LEVEL NUMBER FOR THESE TASKS
	HRLZS T1
PERT3:	HRRZ T2,AVLTSK(T1)	;GET TASK INDEX
	HRLZM Q1,TSKSKD(T2)	;SAVE THE LEVEL NUMBER
	HRRZS TSKLST(T2)	;MARK THIS TASK AS SCHEDULED
	AOBJN T1,PERT3
	JRST PERT2		;GO BACK TIL ALL TASKS ARE PLACED

PERT4:	MOVNS Q1		;NOW SHIFT THE LEVEL NUMBERS
	SUBI Q1,1		;SO THEY START AT 0
	MOVE T1,TSKPTR
PERT5:	SKIPE TSKINV(T1)
	JRST PERT5A
	HLRE T2,TSKSKD(T1)	;GET THE LEVEL NUMBER
	ADD T2,Q1		;TRANSPOSE IT
	HRLM T2,TSKSKD(T1)	;STORE IT BACK AGAIN
PERT5A:	AOBJN T1,PERT5
	MOVE T1,Q3		;GET THE OUTPUT DEVICE
	CALL SETWID		;SETUP TSKWID
	MOVE T1,PERTPA		;GET ALGROITHM
	XCT [CALL PLACE		;STANDARD PLACER
	     CALL HDPLC](T1)	;HIGH DENSITY PLACER
	JUMPE Q3,PERT5B		;OK. IF LPT
	CALL PLTOFL		;CHECK FOR OVERFLOW
PERT5B:	MOVE T1,Q3		;GET THE TYPE OF OUTPUT DEVICE
	CALL STOPRT		;GO STORE THE PERT BOXES
	RET			;DONE
;CHECK TO SEE IF PERT CHART WILL FIT IN PDP-11
;	CALL PLTOFL
;	RETURN HERE (WARNING TYPED IF NEEDED)
;
PLTOFL:	MOVE T1,TSKPTR		;GET POINTER TO LIST
PLTOF1:	HLRZ T2,TSKSKD(T1)	;GET LEVEL #
	SKIPN TSKINV(T1)	;IGNORE IF NOT IN PERT
	CAIG T2,^D36		;TOO BIG?
	AOBJN T1,PLTOF1		;NO--KEEP LOOKING
	JUMPG T1,PLTOF2		;ANYTHING FOUND?
	TMSG	<
? Plot is too tall for PDP-11 plotting software!
>
PLTOF2:	MOVE T1,TSKPTR		;GET POINTER TO LIST
PLTOF3:	MOVE T2,TSKPOS(T1)	;GET POSITION
	ADD T2,TSKWID(T1)	;GET MAX
	SKIPN TSKINV(T1)	;IGNORE IF NOT IN PERT
	CAIG T2,^D800		;OVER 13 FEET WIDE?
	AOBJN T1,PLTOF3		;NO KEEP LOOKING
	JUMPG T1,R		;RETURN IF NOTHING FOUND
	TMSG	<
? Plot is too wide for PDP-11 plotting software.
>
	RET
;ROUTINE TO STORE THE PERT BOXES
;ACCEPTS IN T1/	0 = LPT, 1 = PLOTTER
;RETURNS +1:	T1/	MAX ROW
;		T2/	MAX COL

STOPRT:	SAVEPQ
	MOVE P2,T1		;SAVE THE OUTPUT DEVICE
	SETZB Q2,Q3		;INIT ROW AND COL MAXIMUMS
	MOVE Q1,TSKPTR		;SET UP TO STORE ALL TASK BOXES
STOPR7: SKIPE TSKINV(Q1)
	JRST STOPR8
	HRRZ T1,Q1		;GET TASK INDEX
	MOVE T2,TSKPOS(T1)	;GET COL POSITION
	HLRZ T3,TSKSKD(T1)	;GET LEVEL #
	IMULI T3,<BOXLEN+^D12>	;GET ROW NUMBER (BOX LENGTH + BLANKS)
	MOVE T4,SKDTAD		;GET THE DATE
	XCT [	CALL STOBOX	;STORE THE BOX
		CALL PSTOBX](P2)
	CAMLE T1,Q3		;NEW MAX COL?
	MOVE Q3,T1		;YES
	CAMLE T2,Q2		;NEW MAX ROW?
	MOVE Q2,T2		;YES
	HLRZ T1,TSKSKD(Q1)	;GET THE LEVEL NUMBER
	HLRZ T2,TSKSKD(Q1)
	IMULI T2,<BOXLEN+^D12>	;GET THE ROW NUMBER
	ADDI T2,1		;GET TO THE FIRST FULL ROW
	CALL SETSPC		;GO MARK THE SPACE TABLE
STOPR8:	AOBJN Q1,STOPR7		;LOOP BACK FOR ALL BOXES
	DMOVE T1,Q2		;GET MAX ROW AND COL
	RET
;ROUTINE TO FIX UP TSKPOS TABLE TO ELIMINATE WHITE SPACE

FIXPOS:	SETZ T1,		;INIT COUNTER
FIXPS1:	HRLOI T2,377777		;START AT MAX POSITION
	MOVE T4,TSKPTR		;SET UP AOBJN POINTER
FIXPS2: SKIPE TSKINV(T4)
	JRST FIXPS3
	MOVE T3,TSKPOS(T4)	;GET POSITION
	ADD T3,TSKWID(T4)	;GET OTHER END OF THE BOX
	CAML T1,T3		;PAST THIS BOX?
	JRST FIXPS3		;YES, SKIP IT
	CAML T1,TSKPOS(T4)	;PAST THE START OF THE BOX?
	JRST [	MOVE T1,T3	;YES, SOMETHING IS WRONG
		JRST FIXPS1]
	CAMG T2,TSKPOS(T4)	;NEW LOW?
	JRST FIXPS3		;NO
	MOVE T2,TSKPOS(T4)	;YES, REMEMBER IT
FIXPS3:	AOBJN T4,FIXPS2		;LOOP BACK TILL LOWEST POS FOUND
	CAML T2,[377777,,777777]
	RET			;NONE FOUND, THEN DONE
	MOVE T3,T1		;GET THE AMOUNT OF SPACE TO DELETE
	SUB T3,T2
	MOVE T4,TSKPTR
FIXPS4:	SKIPE TSKINV(T4)
	JRST FXPS4A
	CAMGE T1,TSKPOS(T4)	;THIS POSITION NEED UPDATING
	ADDM T3,TSKPOS(T4)	;YES, TRANSLATE IT
FXPS4A:	AOBJN T4,FIXPS4		;LOOP BACK TIL TRANSLATING DONE
	MOVE T4,TSKPTR
	SETZ T2,		;NOW LOOK FOR NEXT WHITE SPACE
FIXPS5:	SKIPE TSKINV(T4)
	JRST FIXPS6
	CAMGE T1,TSKPOS(T4)	;FOUND A BOX IN THE RANGE?
	JRST FIXPS6		;NO
	MOVE T3,TSKPOS(T4)	;YES, GET THE END OF THE BOX
	ADD T3,TSKWID(T4)
	CAMGE T2,T3		;NEW HIGH?
	MOVE T2,T3		;YES, REMEMBER IT
FIXPS6:	AOBJN T4,FIXPS5		;LOOP BACK OVER ALL TASKS
	MOVE T1,T2		;USE THIS AS START OF WHITE SPACE
	JRST FIXPS1		;LOOP BACK TIL DONE
;ROUTINE TO SET THE BOX WIDTHS FOR ALL BOXES
;ACCEPTS IN T1/	0 = LPT, 1 = PLOTTER

SETWID:	SAVEQ
	MOVE Q3,T1		;SAVE THE OUTPUT DEVICE TYPE
	MOVE Q1,TSKPTR		;LOOP OVER ALL TASKS
SETWD1:	SKIPE TSKINV(Q1)
	JRST SETWD2
	HRRZ T1,Q1		;GET THE TASK INDEX
	XCT [	CALL BOXWID	;GET THE WIDTH OF THE BOX
		CALL PBXWID](Q3)
	MOVEM T1,TSKWID(Q1)	;SAVE THE WIDTH
SETWD2:	AOBJN Q1,SETWD1
	RET

;GANTT CHART GENERATOR

GANTT:	TDZA P4,P4		;LPT
GPLOT:	MOVEI P4,1		;PLOTTER
	HLRZ T1,(P1)		;GET THE TYPE CODE
	CHKTYP (KEY)		;MUST BE A KEY WORD
	HRRZ P2,(P1)		;GET INDEX - 0=DEVELOPERS, 1=TASKS, 2=MILESTONES
				;		4=ONLY-DEVELOPER
	AOS P1			;STEP TO NEXT ARG
	CAIE P2,4		;JUST WANT 1 DEVELOPER?
	JRST GNT1		;NO--SKIP THIS PART
	HLRZ T1,(P1)		;GET THE NEXT TYPE CODE
	CHKTYP (USR)		;USER NAME
	CALL SCHCHK		;DEVLUK REQUIRES THAT A SCHEDULE
				; PASS SETUP DEVTAB
	HRRZ T1,(P1)		;GET POINTER TO STRING
	HRROI T1,ANSWER+1(T1)	;POINTER TO NAME STRING
	CALL DEVLUK		;FIND HIME IN TABLE
	  WARN (<JRST LEVEL0>,<NO TASKS FOR THAT DEVELOPER>)
	HRROI Q2,-DEVTAB-1(T1)	;FAKE AOBJN POINTER
	CALL FINDSD		;FIND STARTING DATE
	  WARN (<JRST LEVEL0>,<ALL TASKS COMPLETE>)
	MOVEM T1,GANTSD		;SAVE STARTING DATE
	AOS P1			;BUMP POINTER
GNT1:	HLRZ T1,(P1)		;GET THE TYPE CODE
	CHKTYP (OFI)		;OUTPUT FILE SPEC?
	HRRZ T1,(P1)		;GET THE JFN
	MOVE Q1,ANSWER(T1)	;FROM ANSWER BLOCK
	MOVE T1,Q1		;GET JFN
	MOVE T2,[070000,,OF%WR]	;OPEN IT FOR WRITE
	OPENF
	 JSP ERROR		;FIALED TO OPEN IT
	CAIN P2,4		;ONLY 1 DEVELOPER?
	JRST GANTT0		;YES--ALREADY HAVE GOOD STARTING DATE
	HRROI T1,[ASCIZ/STARTING DATE OF GANTT CHART: /]
	MOVEI T2,DDATA		;GET ADR OF COMMAND TABLE
	MOVEI T3,ANSWER
	CALL PARSE		;GET START DATE
	 ERRMES <ILLEGALLY FORMATTED COMMAND TABLE>
	HLRZ T1,ANSWER		;GET TYPE CODE
	CHKTYP (TAD)
	HRRZ T1,ANSWER		;GET DATE
	MOVE T1,ANSWER(T1)
	MOVEM T1,GANTSD		;SAVE START DATE
	CALL SCHCHK		;UPDATE ESTIMATED DATES IF NEDED
	HLRZ Q2,DEVTAB		;GET LENGTH OF DEVELOPER TABLE
	JUMPE Q2,GANTT4		;IF NONE, THEN DONE
	MOVNS Q2		;SET UP AOBJN POINTER
	HRLZS Q2
	SKIPN SKTLST		;ANY TASKS ON LIST?
	JUMPN P2,GANTT4		;IF NONE, AND IF DOING TASKS, THEN DONE
GANTT0:	SETZB P3,GNTCMX		;INIT THE COL MAXIMUM
GANTT1:	MOVN Q3,TSKCNT		;SET UP POINTER TO TASK LIST
	HRLZS T1,Q3
	JUMPE Q3,GANTT4		;IF NO TASKS, THEN DONE
	HRROS TSKLST(T1)	;INIT TABLE
	AOBJN T1,.-1
	HRRZ T1,P3		;GET THE ROW OFFSET
	CALL INISTO		;INITIALIZE THE ANSWER ARRAY
	SETZM GNTRMX		;INIT THE ROW NUMBER
GANTT2:	MOVEI P1,0		;START AT COLUMN 0
	SETO Q3,		;FIND THE EARLIEST STARTER
	MOVE T1,TSKPTR
	HRLOI T2,377777		;START WITH HIGHEST POSSIBLE DATE
GANTT6:	SKIPL TSKLST(T1)	;HAS THIS ENTRY BEEN USED YET?
	JRST GANTT7		;YES, SKIP IT
	CAMG T2,TSKSDL(T1)	;IS THIS A NEW LOW START DATE
	JRST GANTT7		;NO
	MOVE T2,TSKSDL(T1)	;YES, REMEMBER IT
	HRRZ Q3,T1		;AND THE INDEX
GANTT7:	AOBJN T1,GANTT6		;LOOP BACK THRU ALL TASKS
	JUMPL Q3,GANTT5		;FOUND ANY?
	HRRZS TSKLST(Q3)	;YES, GO USE THIS TASK
GANTT3:	HRRZ T1,TSKLST(Q3)	;GET THE NEXT TASK
	LOAD T2,TKFLG,(T1)	;GET THE FLAGS OF THIS TASK
	TXNN T2,TK%MIL		;MILESTONE?
	CAIE P2,2		;NO, IS THIS A MILE STONE LIST?
	SKIPA
	JRST GANTT2		;SKIP TASKS THAT AREN'T MILESTONES
	HRRZ T2,DEVTAB+1(Q2)	;GET THIS DEVELOPER
	TRNE P2,3		;DOING TASKS?
	MOVE T2,SKTLST		;YES, GET POINTER TO TASK LIST
	HRLZ T3,P1		;GET COL
	HRR T3,GNTRMX		;ALWAYS START AT LAST USED ROW
	MOVE T4,GANTSD		;GET GANTT START DATE
	CALL STOGTK		;STORE THE TASK 
	 JRST GANTT2		;NONE FOUND
	JUMPL T3,GANTT2		;IF NOTHING STORED, DONT STORE ROW
	MOVEI T1,GW		;GET WIDTH OF ONE GANTT ROW
	ADDM T1,GNTRMX		;STEP TO NEXT FREE ROW
	CAMLE T3,GNTCMX		;NEW MAX COL?
	MOVEM T3,GNTCMX		;YES
	JRST GANTT2		;LOOP BACK FOR ALL TASKS
GANTT5:	JUMPN P3,GANTT8		;IF NOT FIRST TIME, DONT TYPE HEADER
	MOVE T1,Q1		;GET THE JFN
	HRROI T2,[ASCIZ/




.TEXTSIZE;0.12,0.14/]
	SETZ T3,
	SKIPE P4		;LPT?
	SOUT			;NO, GIVE PLOTTER COMMAND
	HRROI T2,[ASCIZ/
GANTT CHART FOR DEVELOPER /]
	TRNE P2,3		;DOING ALL TASKS?
	HRROI T2,[ASCIZ/
GANTT CHART FOR ALL TASKS/]
	CAIN P2,2		;MILESTONES?
	HRROI T2,[ASCIZ/
GANTT CHART OF MILESTONES/]
	SETZ T3,
	SOUT
	HLRO T2,DEVTAB+1(Q2)	;GET DEVELOPER
	TRNN P2,3		;UNLESS DOING ALL TASKS
	SOUT			;YES, OUTPUT IT
	HRROI T2,[ASCIZ/ ON /]
	SOUT
	SETO T2,
	ODTIM			;OUTPUT THE DATE AND TIME
	HRROI T2,[ASCIZ/


/]
	SETZ T3,
	SOUT
GANTT8:	MOVE T1,Q1		;GET THE JFN
	HLRZ T2,P3		;GET THE START COL
	HRRZ T3,GNTRMX		;GET MAX ROW
	SUBI T3,(P3)		;GET MAX ROW - OFFSET
	MOVE T4,GNTCMX		;GET MAX COL
	SUB T4,T2		;SEE IF IT NEEDS TRUNCATING
	SKIPN P4		;GOING TO THE PLOTTER?
	CAIG T4,^D132		;NO, WIDER THAN A PAGE?
	SKIPA			;NO
	MOVEI T4,^D132		;LIMIT TO ONE PAGE
	ADD T4,T2		;GET COL MAX
	HRL T3,T4
	MOVE T4,GANTSD		;GET START DATE
	XCT [	CALL PRIGNT	;PRINT THE GANTT CHART ON LPT OR PLOTTER
		CALL PLOGNT](P4)
	ADDI P3,NROW		;STEP TO NEXT SET OF ROWS
	HRRZ T1,GNTRMX		;SEE IF DONE
	SUBI T1,(P3)		;DONE ENOUGH?
	JUMPG T1,GANTT1		;IF MORE TO DO, GO DO THEM
	JUMPN P4,GANTT9		;IF PLOTTER, THEN DONE
	HLRZ T1,P3		;GET COL OFFSET
	ADDI T1,^D132		;STEP TO NEXT PAGE
	HRLZM T1,P3		;RESET ROW TO 0
	CAML T1,GNTCMX		;DONE?
	JRST GANTT9		;YES, GO DO OTHER DEVELOPERS
	MOVE T1,Q1		;JFN
	HRROI T2,[ASCIZ/
.
/]
	SETZ T3,
	SOUT
	MOVEI T2,14		;FORM FEED
	BOUT
	HRROI T2,[ASCIZ/



/]
	SOUT
	JRST GANTT1		;LOOP BACK TILL DONE ALL COL'S

GANTT9:	TRNE P2,3		;DOING DEVELOPERS?
	JRST GANTT4		;NO--ALL DONE
	HRRZ T1,Q1		;GET THE JFN
	MOVEI T2,14		;FORM FEED
	SKIPN P4		;LPT?
	BOUT			;YES, PUT A FORM FEED BETWEEN EACH DEV
	AOBJN Q2,GANTT0		;LOOP BACK FOR ALL DEVELOPERS
GANTT4:	HRRZ T1,Q1		;DONE, CLOSE THE JFN
	CLOSF
	 JFCL
	JRST LEVEL0		;ALL DONE
;SUBROUTINE TO FIGURE OUT A GOOD PLACE TO START A GANTT CHART
;CALL WITH:
;	T1/ ADDRESS OF DEVTAB ENTRY (NOT INDEX!)
;RETURNS	+1:	NO TASKS LEFT TO DO
;	+2:	T1/ STARTING DATE
;
FINDSD:	SAVEQ
	STKVAR <<FSDTMP,100>>
	HRRZ Q1,(T1)		;START OF CHAIN
	HRLOI Q2,377777		;LARGEST DATE
	MOVEI Q3,0		;FLAG
	JUMPE Q1,R		;SHOULD NEVER BE NULL LIST
;AC USE IN THIS LOOP
;	Q1/	CURRENT NODE IN TASK CHAIN
;	Q2/	EARLIEST STARTING DATE
;	Q3/	TASK WHICH STARTS THEN
FNDSD1:	LOAD T1,SCHTK,(Q1)	;POINTER TO TASK BLOCK
	LOAD T2,TKAFD,(T1)	;ACTUAL FINISH DATE
	JUMPN T2,FNDSD2		;IGNORE COMPLETED TASKS
	MOVEI T1,FSDTMP		;POINTER TO DUMMY STRING
	HRLI T1,(POINT 7,0)	;MAKE BYTE POINTER
	LOAD T2,SCHTK,(Q1)	;GET TASK BLOCK ADDRESS
	CALL GETPTS		;SEE HOW LONG HEADER IS
	HRLZ T1,T1		;PUT IN LEFT HALF
	LOAD T2,SCHSD,(Q1)	;GET THE START DATE FOR THE TASK
	SUB T2,T1		;BACKUP DATE TO START OF HEADER
	CAML T2,Q2		;NEW LOW?
	JRST FNDSD2		;NO--SKIP IT
	MOVE Q2,T2		;YES--SAVE DATE
	LOAD Q3,SCHTK,(Q1)	;SAVE TASK BLOCK ADDRESS ALSO
FNDSD2:	LOAD Q1,SCHLN,(Q1)	;STEP TO NEXT TASK
	JUMPN Q1,FNDSD1		;KEEP LOOPING
	JUMPE Q3,R		;ERROR RETURN IF NOTHING FOUND
	MOVE T1,Q2		;RETURN START DATE
	RETSKP
;ROUTINE TO STORE THE DATE STRING
;ACCEPTS IN T1/	COL
;	    T2/	ROW
;	    T3/	STRING POINTER

STODST:	SAVEQ
	DMOVE Q1,T1		;SAVE THE ARGS
	TLC T3,-1		;GET STRING POINTER
	TLCN T3,-1
	HRLI T3,(POINT 7,0)
	MOVE Q3,T3		;SAVE STRING POINTER
STODS1:	ILDB T1,Q3		;GET THE NEXT CHAR
	JUMPE T1,R		;IF NULL, THEN DONE
	MOVE T2,Q1		;GET THE COL
	MOVE T3,Q2		;GET THE ROW
	CALL STOCHA		;STORE THE CHAR
	 JFCL
	AOJA Q2,STODS1		;STEP TO THE NEXT ROW


;ROUTINE TO STORE A TASK ON THE GANTT CHART
;ACCEPTS IN T1/	TASK ADR
;	    T2/	DEVELOPER LIST
;	    T3/	FIRST AVAIL COL ,, START ROW
;	    T4/	GANTT START ADR

;RETURNS +1:	NONE FOUND
;	 +2:	T1/	0 = EXCEEDED STORAGE SPACE
;			-1 = OK
;		T2/	MAX ROW USED
;		T3/	MAX COL USED

STOGTK:	SAVEP
	STKVAR <STOGTN,STOGTL,STOGTC,<STOGTS,100>,<STOGTB,GW>>
	DMOVE P1,T1		;SAVE THE ARGS
	DMOVE P3,T3
	HLRZS P4,T4		;ONLY NEED THE DAY PART OF THE DATE
	HRROI T1,STOGTS		;GET THE NAME STRING
	MOVE T2,P1		;GET THE TASK ADR
	CALL GETPTS		;GET PROJECT/NAME STRING
	MOVEM T1,STOGTN		;SAVE THE LENGTH OF THE NAME STRING
	MOVEI T1,STOGTB		;NOW SET UP THE STRING POINTERS
	CALL INISTB
	MOVEI T1,STOGTB		;GET POINTER TO STRING BLOCK
	MOVE T2,P1		;GET TASK ADR
	MOVE T3,P2		;GET THE DEVELOPER LIST
	CALL GETGST		;GET THE TASK STRINGS SET UP
	 RET			;NONE FOUND
	MOVEM T1,STOGTL		;SAVE THE STRING LENGTH
	SUB T2,P4		;GET THE ACTUAL STARTING COL #
	HLRZ T3,P3		;GET STARTING COL
	ADD T2,T3		;GOT COL NUMBER
	SUB T2,STOGTN		;BACK UP OVER THE NAME STRING
	MOVEM T2,STOGTC		;SAVE THE COLUMN
	HRRZ T1,P3		;GET THE ROW NUMBER
	MOVE T3,STOGTN		;GET TOTAL LENGTH OF STRING
	ADD T3,STOGTL		;LENGTH = NAME + TASK STRING
	MOVEI T4,GW		;GET THE ROW INCREMENT
	CALL FNDROW		;FIND A FREE ROW
	 JRST [	SETZ T1,	;EXCEEDED SPACE
		SETZB T2,T3	;NO ROW OR COL USED
		RETSKP]
	HRRM T1,P3		;SAVE THE ROW
	HRL T1,STOGTC		;GET COL NUMBER FOR NAME
	HRR T1,P3		;GET THE ROW
	HRROI T2,STOGTS		;GET POINTER TO NAME STRING
	MOVE T3,P1		;GET THE TASK ADR
	MOVEI T4,GW		;GET ROW WIDTH
	CALL STOGNM		;STORE THE STRING
	MOVEI T1,STOGTB		;GET POINTER TO STRINGS
	CALL INISTB		;INIT POINTERS
	MOVSI P5,-GW		;NOW PUT STRINGS INTO BUFFER
	HRRI P5,STOGTB
STOGT1:	MOVE T1,STOGTC		;GET STARTING COL NUMBER
	ADD T1,STOGTN		;STEP OVER THE NAME STRING
	HRRZ T2,P3		;GET ROW
	ADDI P3,1		;STEP ROW
	MOVE T3,(P5)		;GET STRING POINTER
	CALL STOSTR		;STORE THE STRING
	AOBJN P5,STOGT1		;LOOP BACK FOR ALL STRINGS
	SETO T1,		;FINISHED OK
	HRRZ T2,P3		;RETURN ROW NUMBER
	MOVE T3,STOGTC		;GET COL MAXIMUM
	ADD T3,STOGTN		;ADD IN NAME
	ADD T3,STOGTL		;AND ADD IN THE TASK STRING LENGTH
	RETSKP
;ROUTINE TO FIND A FREE ROW
;ACCEPTS IN T1/	START ROW
;	    T2/	COL
;	    T3/	LENGTH OF STRING
;	    T4/	ROW INCREMENT

;RETURNS +1:	EXCEEDS THE TABLE SPACE
;	 +2:	T1/	ROW FOUND

FNDROW:	SAVEP
	DMOVE P1,T1		;SAVE THE ARGS
	DMOVE P3,T3
FNDRO1:	DMOVE T1,P1		;GET ROW AND COL
	MOVE T3,P3		;GET STRING LENGTH
	CALL CHKROW		;SEE IF THIS ROW IS FREE
	 RET			;EXCEEDED TABLE SPACE
	JUMPN T1,FNDRO2		;IF -1, THEN DONE
	ADD P1,P4		;STEP THE ROW
	JRST FNDRO1		;LOOP BACK TILL ROW FOUND

FNDRO2:	MOVE T1,P1		;RETURN THE ROW SELECTED
	RETSKP


;ROUTINE TO CHECK IF A SLOT IS FREE
;ACCEPTS IN T1/	ROW
;	    T2/	COL
;	    T3/	LENGTH OF THE STRING

;RETURNS +1:	EXCEEDED TABLE SPACE
;	 +2:	T1/	0 = IN USE, -1 = FREE

CHKROW:	SAVEQ
	DMOVE Q1,T1		;SAVE THE ARGS
	MOVE Q3,T3
CHKRO1:	MOVEI T1," "		;GET DUMMY CHAR
	MOVE T2,Q2		;GET THE COL
	MOVE T3,Q1		;GET THE ROW
	JUMPL T2,CHKRO2		;IF NEG COL, THEN OK
	CALL CHKCHR		;SEE IF THIS POSITION IS FREE
	 RET			;EXCEEDED TABLE SIZE
	JUMPE T1,RSKP		;NOT FREE
CHKRO2:	AOS Q2			;STEP COL
	SOJG Q3,CHKRO1		;LOOP BACK FOR WHOLE STRING
	SETO T1,		;ALL FREE
	RETSKP
;ROUTINE TO GET THE PROJECT/TASK STRING
;ACCEPTS IN T1/	STRING POINTER
;	    T2/	TASK ADR
;RETURNS +1:	T1/	LENGTH

GETPTS:	SAVEQ
	STKVAR <GETPTC,GETPTP>
	DMOVE Q1,T1		;SAVE THE ARGS
	LOAD T1,TKPRJ,(Q2)	;GET THE PROJECT ADR
	LOAD T1,PJNAM,(T1)	;GET THE ADR OF THE NAME
	HRLI T1,(POINT 7,0)	;BUILD A BYTE POINTER
	CALL CNTSTC		;COUNT CHARACTERS IN THE STRING
	MOVEM T1,GETPTC		;SAVE THE COUNT
	LOAD T1,TKNAM,(Q2)	;GET ADR OF TASK NAME
	HRLI T1,(POINT 7,0)
	CALL CNTSTC		;GET COUNT OF CHARS IN STRING
	CAMLE T1,GETPTC		;NEW HIGH?
	MOVEM T1,GETPTC		;YES, SAVE IT
	MOVE T1,Q2		;GET TASK ADR
	MOVE T2,Q1		;GET STRING POINTER
	CALL BLDNST		;GO BUILD THE NAME STRING
	CAMLE T1,GETPTC		;NEW HIGH LENGTH?
	MOVEM T1,GETPTC		;YES
	AOS T1,GETPTC		;GET THE LONGEST LENGTH PLUS 1 SPACE
	RET			;DONE


;ROUTINE TO COUNT THE CHARACTERS IN A STRING
;ACCEPTS IN T1/	STRING POINTER
;RETURNS +1:	T1/	COUNT

CNTSTC:	TLC T1,-1		;BYTE POINTER?
	TLCN T1,-1
	HRLI T1,(POINT 7,0)	;NO, MAKE A BYTE POINTER
	SETZ T4,		;INIT COUNT
CNTST1:	ILDB T2,T1		;GET NEXT CHAR
	SKIPE T2		;NULL?
	AOJA T4,CNTST1		;NO, LOOP BACK TIL DONE
	MOVE T1,T4		;GET THE COUNT
	RET			;DONE
;ROUTINE TO BUILD A TASK STRING
;ACCEPTS IN T1/	STRING BLOCK POINTER
;	    T2/	TASK ADR
;	    T3/	DEVELOPER LIST
;RETURNS +1:	NONE FOUND
;	 +2:	T1/	LENGTH OF STRING
;		T2/	START ADR

GETGST:	SAVEQ
	STKVAR <GETGSC,GETGSD,GETGSL,GETGSR,GETGSF,GETGSZ>
	SETZM GETGSZ		;INIT TASK ADR
	DMOVE Q1,T1		;SAVE THE ARGS
	MOVE Q3,T3
	SETZM GETGSC		;INIT COUNT
GETGS1:	LOAD T1,SCHTK,(Q3)	;FIND THE FIRST MATCHING TASK
	CAMN T1,Q2		;MATCH?
	JRST GETGS3		;YES
GETGS2:	LOAD Q3,SCHLN,(Q3)	;STEP TO NEXT DEV IN LIST
	JUMPN Q3,GETGS1		;LOOP BACK TILL FIRST TASK IS FOUND
	SKIPN Q3,GETGSZ		;WAS A TASK FOUND?
	RET			;NO
	JRST GETGS4		;YES

GETGS3:	LOAD T1,SCHSD,(Q3)	;GET START DATE
	HLRZM T1,GETGSD		;SAVE THE START DATE
	MOVEM Q3,GETGSZ		;SAVE ADR OF TASK
	LOAD T1,SCHRT,(Q3)	;GET RATE
	JUMPE T1,GETGS2		;IF 0, GO LOOK SOME MORE
GETGS4:	LOAD T2,SCHSD,(Q3)	;GET THE START DATE
	HLRZS T2
	LOAD T1,SCHFD,(Q3)	;GET FINISH DATE
	HLRZS T1
	MOVEM T1,GETGSF		;SAVE THE FINISH DATE
	SUB T1,T2		;CALCULATE THE TASK LENGTH
	MOVEM T1,GETGSL		;SAVE THE LENGTH
	LOAD T1,SCHRT,(Q3)	;GET THE RATE
	SKIPG GETGSL		;LONGER THAN 0?
	SETZ T1,		;NO, SET THE RATE TO 0
	MOVEM T1,GETGSR		;SAVE THE RATE
	MOVE T2,GETGSR		;GET THE RATE
	SKIPG T3,GETGSL		;IS THIS A ZERO LENGTH TASK?
	MOVEI T3,1		;YES, IT ALWAYS TAKES ONE SPACE
	ADDM T3,GETGSC		;SAVE THE LENGTH
	MOVE T1,Q1		;GET POINTER TO STRING BLOCK
	MOVE T4,Q3		;GET SCHED BLOCK ADR
	CALL STOGST		;STORE THE STRINGS
GETGS5:	LOAD Q3,SCHLN,(Q3)	;STEP TO THE NEXT TASK
	JUMPE Q3,GETGS6		;DONE
	LOAD T1,SCHTK,(Q3)	;GET TASK ADR
	CAME T1,Q2		;FOUND A MATCH?
	JRST GETGS5		;NO, LOOP BACK TILL ONE FOUND
	LOAD T1,SCHRT,(Q3)	;GET THE RATE
	JUMPE T1,GETGS5		;SKIP 0'S
	LOAD T1,SCHSD,(Q3)	;GET START DATE
	HLRZS T2,T1
	SUB T2,GETGSF		;GET THE DIF BETWEEN START AND LAST FIN
	SKIPLE T2		;IF NO DIFFERENCE, SKIP THIS
	ADDM T2,GETGSC		;UPDATE THE FINAL COUNT
	MOVE T1,Q1		;GET STRING BLOCK ADR
	CALL STODOT		;YES
	JRST GETGS4		;GO ADD THIS TASK TO STRING

GETGS6:	MOVE T1,Q1		;GET STRING POINTER
	CALL STONUL		;STORE NULL AT END OF STRING
	MOVE T1,GETGSC		;RETURN THE LENGTH OF THE STRING
	MOVE T2,GETGSD		;RETURN THE START COL
	RETSKP
;ROUTINE TO STORE A GANNT STRING
;ACCEPTS IN T1/	STRING BLOCK ADR
;	    T2/	RATE
;	    T3/	LENGTH OF TASK IN DAYS
;	    T4/	SCHED BLOCK ADR

STOGST:	SAVEPQ
	DMOVE Q1,T1		;SAVE THE ARGS
	MOVE Q3,T3
	MOVE P4,T4		;SAVE THE SCHED BLOCK ADR
	LOAD T4,SCHSD,(P4)	;GET THE START DATE
	HLRZ P1,T4		;GET START DAY INTO P1
	FMPR T2,[100.0]		;GET PERCENTAGE
	CALL STOFPT		;STORE THE RATE
	AOS P1			;COUNT UP DAY
STOGS1:	HRLZ T1,P1		;GET DATE
	CALL CHKHOL		;SEE IF IT IS A HOLIDAY
	 SKIPA			;NO
	JRST STOGS2		;YES
	MOVEI T2,">"
	LOAD T3,SCHTK,(P4)	;GET TASK ADR
	LOAD T3,TKAFD,(T3)	;GET FINISH DATE
	SKIPE T3		;TASK DONE?
	CAML T3,SKDTAD		;AND BEFORE TODAY'S DATE
	SKIPA			;NO
	MOVEI T2,"*"		;YES, MARK IT WITH AN ASTERISK
	SKIPG Q2		;ANY RATE?
	MOVEI T2,"."		;RATE = 0
	MOVEI T3,2(P1)		;SEE IF THIS IS A WEEKEND
	IDIVI T3,7
	CAIL T4,5		;MON - FRI?
STOGS2:	MOVEI T2,"."		;NO, NO WORK ON WEEKEND OR HOLIDAY
	SOJLE Q3,R		;ANY MORE TO DO?
	MOVE T1,Q1		;GET THE STRING BLOCK ADR
	CALL STOGCH		;YES, GO STORE THE CHAR
	AOJA P1,STOGS1		;LOOP BACK FOR REST OF DAYS


;ROUTINE TO STORE A FLOATING POINT NUMBER
;ACCEPTS IN T1/	STRING BLOCK ADR
;	    T2/	FLOATING POINT NUMBER

STOFPT:	SAVEQ
	STKVAR <<STOFPS,10>>
	DMOVE Q1,T1		;SAVE THE ARGS
	HRROI T1,STOFPS		;GET THE NUMBER TRANSLATED TO A STRING
	MOVE T3,[FL%ONE+<GW>B23]
	FLOUT
	 JFCL
	MOVEI T1,STOFPS
	HRLI T1,(POINT 7,0)	;GET POINTER TO THE NUMBER
	MOVSI T3,-GW		;GET POINTER TO STRINGS
	HRRI T3,(Q1)
STOFP1:	ILDB T2,T1		;COPY THE NUMBER TO THE STRING
	IDPB T2,(T3)
	AOBJN T3,STOFP1		;LOOP BACK FOR ALL DIGITS
	RET
;ROUTINE TO STORE THE NAME OF THE TASK IN THE GANTT CHART
;ACCEPTS IN T1/	COL ,, ROW
;	    T2/	STRING POINTER TO DEVELOPER STRING
;	    T3/	TASK ADR
;	    T4/	INCREMENT

STOGNM:	SAVEPQ
	DMOVE P1,T1		;SAVE THE ARGS
	DMOVE P3,T3
	LOAD T3,TKPRJ,(P3)	;GET PROJECT NAME
	LOAD T3,PJNAM,(T3)
	HRLI T3,(POINT 7,0)	;GET POINTER TO PROJECT NAME STRING
	HLRE T1,P1		;GET COL
	HRRE T2,P1		;GET ROW
	ADDI T2,-3(P4)		;PLUS THE RIGHT INCREMENT
	CALL STOSTR		;STORE THIS STRING
	LOAD T3,TKNAM,(P3)	;NOW DO THE TASK NAME
	HRLI T3,(POINT 7,0)
	HLRE T1,P1		;COL
	HRRE T2,P1		;ROW
	ADDI T2,-2(P4)		;PLUS INCREMENT
	CALL STOSTR		;STORE THE TASK NAME
	HLRE T1,P1		;COL
	HRRE T2,P1		;ROW
	ADDI T2,-1(P4)		;PLUS INCREMENT
	MOVE T3,P2		;GET STRING POINTER TO DEVELOPERS
	CALL STOSTR		;STORE THE STRING
	RET			;DONE
;ROUTINE TO STORE A GANTT CHAR
;ACCEPTS IN T1/	STRING BLOCK ADR
;	    T2/	CHAR

STOGCH:	MOVEI T3," "		;GET A SPACE
	MOVSI T4,-<GW-1>	;LOOP FOR ALL BUT THE LAST CHAR
	HRRI T4,(T1)		;GET POINTER TO FIRST STRING ADR
STOGC1:	IDPB T3,(T4)		;STORE THE SPACE
	AOBJN T4,STOGC1
	IDPB T2,(T4)		;STORE THE CHAR
	RET

;ROUTINE TO STORE A NULL IN EACH STRING OF GANNT ENTRY
;ACCEPTS IN T1/	STRING BLOCK ADR

STONUL:	MOVEI T3,0		;GET THE NULL
	MOVSI T4,-GW
	HRRI T4,(T1)		;SET UP AOBJN COUNTER
STONU1:	MOVE T2,(T4)		;GET BYTE POINTER
	IDPB T3,T2		;STORE NULL WITHOUT INCREMENTING BP
	AOBJN T4,STONU1		;LOOP BACK FOR REST
	RET


;ROUTINE TO STORE DOTS
;ACCEPTS IN T1/	STRING BLOCK ADR
;	    T2/	COUNT OF DOTS TO STORE

STODOT:	SAVEQ
	DMOVE Q1,T1		;SAVE THE ARGS
STODO1:	MOVE T1,Q1		;GET STRING BLOCK ADR
	MOVEI T2,"."		;GET THE DOT CHAR
	SOJL Q2,R		;ANY MORE TO DO?
	CALL STOGCH		;YES, STORE THE NEXT DOT
	JRST STODO1		;LOOP BACK FOR REST
;ROUTINE TO INIT A STRING BLOCK
;ACCEPTS IN T1/	STRING BLOCK ADR

INISTB:	MOVSI T4,-GW		;SET UP COUNTER
INIST1:	MOVE T2,INITAB(T4)	;GET STRING POINTER
	MOVEM T2,(T1)		;STORE IT IN THE BLOCK
	AOS T1
	AOBJN T4,INIST1		;LOOP BACK FOR THE REST
	RET

DEFINE BLDPNT(A) <
	POINT 7,GST'A>

	ZZ==0
INITAB:
	REPEAT GW,<BLDPNT(\ZZ)
		   ZZ==ZZ+1>
;ROUTINE TO CHECK IF A TASK WILL FIT ON A PARTICULAR COLLUMN
;ACCEPTS IN T1/	TASK BLOCK ADR
;	    T2/	SCHED LIST POINTER (DEVTAB)
;	    T3/	COLUMN #
;	    T4/	START DATE OF GANTT CHART
;RETURNS +1:	DID NOT FIT
;	 +2:	OK, T1/	MAX ROW STORED INTO

CHKGNT:	SAVEPQ
	MOVEI P5,0		;CHECK ONLY
	JRST CHKGN0

STOGNT:	SAVEPQ
	MOVEI P5,1		;STORE
CHKGN0:	HLRZS T4		;GET FIRST DAY OF GANTT CHART
	DMOVE P1,T1		;SAVE ARGS
	DMOVE P3,T3
	STKVAR <<CHKGNS,MAXLNW>,<CHKGNN,MAXLNW>,CHKGNL,CHKGNR,CHKGNF,CHKGND>
	GTAD			;GET DATE
	HLRZM T1,CHKGND		;SAVE TODAYS DATE
	SETZM CHKGNF		;INIT THE FINISH DATE
	SETZB T1,CHKGNR		;INIT THE MAX ROW
	JUMPE P2,RSKP		;IF NO DEVELOPER, THEN QUIT
	MOVE Q3,TSKPTR		;FIND THE TASK IN THE TASK LIST
	CAME P1,TSKLST(Q3)	;FOUND THE TASK YET?
	AOBJN Q3,.-1		;NO, CONTINUE LOOKING
	JUMPGE Q3,R		;IF NOT FOUND, THEN RETURN FAILURE
	MOVEI T4,11		;BUILD THE NAME STRING AND LENGTH
	MOVEI Q1,CHKGNN		;GET ADR OF NAME BLOCK
	HRLI Q1,(POINT 7,0)	;BUILD BYTE POINTER TO IT
	LOAD T1,TKPRJ,(P1)	;GET PROJECT NAME
	LOAD T1,PJNAM,(T1)
	HRLI T1,(POINT 7,0)
CHKGN1:	ILDB T2,T1		;COPY PROJECT NAME TO STRING
	JUMPE T2,CHKGN2
	IDPB T2,Q1
	TRUNC T4,MAXLEN,<PROJECT NAME>,CHKGN1,CHKGN2
	AOJA T4,CHKGN1		;COUNT THE # OF CHARACTERS IN NAME
CHKGN2:	MOVEI T2,"/"		;PUT A SLASH BETWEEN THE NAMES
	IDPB T2,Q1
	LOAD T1,TKNAM,(P1)	;GET THE TASK NAME
	HRLI T1,(POINT 7,0)
CHKGN3:	ILDB T2,T1		;COPY NAME TO STRING
	IDPB T2,Q1
	TRUNC T4,MAXLEN,<TASK NAME>,CHKGN3,CKGN3A
	SKIPE T2
	AOJA T4,CHKGN3		;COUNT UP CHARACTERS IN NAME
CKGN3A:	MOVEM T4,CHKGNL		;REMEMBER THE LENGTH
CHKGN4:	LOAD T1,SCHTK,(P2)	;GET THE TASK ADR FROM SCHED BLOCK
	CAME T1,P1		;IS IT THE ONE WE WANT?
	JRST CHKGN6		;NO
	LOAD Q1,SCHSD,(P2)	;YES, GET THE STARTING DATE
	LOAD Q2,SCHFD,(P2)	;AND THE FINISH DATE
	HLRZS Q1		;GET THE DAY
	HLRZS Q2
	HLRZ T2,TSKFDL(Q3)	;GET THE END DATE
	CAMGE Q2,T2		;IS THIS THE LAST PART OF THE TASK
	SUBI Q2,1		;NO, DO NOT SCHEDULE WORK ON LAST DAY
CHKGN5:	HRROI T1,CHKGNS		;GET STRING
	LOAD T3,TKAFD,(P1)	;IS THERE A FINAL DATE?
	HRROI T2,[ASCIZ/ * /]
	SKIPN T3		;IF NO FINAL DATE, PROJECT IS NOT DONE
	HRROI T2,[ASCIZ/ . /]	;NO FINAL DATE, TRY FOR START DATE
	LOAD T3,TKASD,(P1)	;HAS THE PROJECT BEEN STARTED?
	SKIPE T3
	CAML Q1,CHKGND		;IS THIS BEFORE TODAY?
	HRROI T2,[ASCIZ/   /]	;NO
	SETZ T3,
	SOUT
	LOAD T2,SCHRT,(P2)	;GET THE RATE
	HLRZ T3,TSKFDL(Q3)	;GET THE END DATE
	CAMN T3,Q1		;IS THIS THE END DATE?
	JRST [	HRROI T2,[ASCIZ/ END/]
		SETZ T3,
		SOUT
		JRST CHKGN7]
	MOVE T3,Q1		;GET CURRENT DATE
	ADDI T3,2		;SEE IF IT IS A WEEKEND
	IDIVI T3,7
	CAIL T4,5
	JRST [	HRROI T2,[ASCIZ/ -- /]
		SETZ T3,
		SOUT
		JRST CHKGN7]	;NO WORK IS SCHEDULED ON WEEKENDS
	MOVE T3,[FL%ONE!FL%PNT!1B23!2B29]
	CAML T2,[10.0]		;GREATER THAN 10?
	MOVE T3,[FL%ONE!FL%PNT!2B23!1B29]
	FLOUT			;OUTPUT THE RATE
	 JSP ERROR
	;..
	;..
CHKGN7:	MOVEI T2," "
	BOUT			;SPACE
	HRROI T2,SPACES
	HLRZ T3,TSKSDL(Q3)	;GET THE START DATE
	CAMN T3,Q1		;IS THIS THE START DATE?
	HRROI T2,CHKGNN		;YES, TYPE OUT THE TASK NAME
	HLRZ T4,TSKFDL(Q3)	;GET THE FINISH DATE
	CAMN T4,Q1		;END OF PROJECT?
	HRROI T2,CHKGNN		;YES, TYPE OUT TASK NAME
	SKIPL CHKGNF		;FIRST TIME FOR THIS SCHED BLOCK?
	CAMG Q1,CHKGNF		;YES, IS THERE A HOLE IN THE GANTT
	SKIPA			;NO
	HRROI T2,CHKGNN		;YES, TYPE OUT PROJECT NAME AGAIN
	SETOM CHKGNF		;MARK THAT NO LONGER THE FIRST TIME
	MOVN T3,CHKGNL
	ADDI T3,7		;GET LENGTH OF NAME STRING
	SOUT			;PUT NAME INTO STRING
	MOVE T1,P3		;GET COLUMN NUMBER
	MOVE T2,CHKGNL		;AND LENGTH OF STRING
	HRROI T3,CHKGNS		;GET POINTER TO THE STRING
	MOVE T4,Q1		;GET THE DATE
	SUB T4,P4		;GET THE ROW
	CAMLE T4,CHKGNR		;NEW MAXIMUM ROW?
	MOVEM T4,CHKGNR		;YES
	XCT [	CALL CHKFLD
		CALL STOFLD](P5) ;CHECK THIS STRING
	 RET			;FAILED TO FIT
	CAMGE Q1,Q2		;REACHED THE FINISH DATE YET?
	AOJA Q1,CHKGN5		;NO, LOOP BACK
	LOAD T1,SCHFD,(P2)
	HLRZM T1,CHKGNF		;STORE THE LAST DATE FOR THIS BLOCK
CHKGN6:	LOAD P2,SCHLN,(P2)	;GO TO NEXT TASK IN CHAIN
	JUMPN P2,CHKGN4		;LOOP TIL LIST IS ENDED
	MOVE T1,CHKGNR		;GET MAX ROW
	RETSKP			;OK RETURN


SPACES:
	XLIST
REPEAT ROWLEN,<ASCII/     />
	0
	LIST
;ROUTINE TO INITIALIZE THE GANTT DATA BASE
;ACCEPTS IN T1/	ROW OFFSET

INISTO:	MOVEM T1,ROWOFS		;SAVE THE ROW OFFSET
	MOVE T1,[ROWSTG,,ROWSTG+1]
	SETZM ROWSTG
	BLT T1,ROWSTG+ROWSTL-1
	SETZM COLMAX		;INIT MAX COLUMN
	RET

;ROUTINE TO STORE THE DATES IN THE DATA BASE
;ACCEPTS IN T1/	START DATE OF GANTT CHART

STODAT:	SAVEQ
	STKVAR <<STODAS,10>,STODAR>
	MOVEM T2,STODAR		;SAVE THE ROW
	MOVE Q1,T1		;SAVE THE START DATE
	MOVSI Q2,-NCOL
STODA1:	HRLZ T2,Q2		;GET THE DATE
	ADD T2,Q1
	SETZ T4,
	ODCNV
	HLRZ Q3,T3		;GET THE DAY OF THE MONTH
	AOS Q3
	TRNE Q2,-1		;FIRST TIME THRU?
	CAIN Q3,1		;NO, IS THIS THE FIRST OF THE MONTH?
	JRST STODA3		;YES, GO PRINT THE DATE
	HRROI T1,STODAS		;GET THE STRING ADR
	MOVE T2,Q3		;GET THE DAY OF THE MONTH
	MOVE T3,[NO%LFL!6B17!^D10]
	NOUT			;OUTPUT JUST THE DAY NUMBER
	 JSP ERROR
	HRROI T2,[ASCIZ/    /]
	SETZ T3,
	SOUT			;FILLER
STODA2:	HRRZ T1,Q2		;GET THE COL
	MOVE T2,STODAR		;GET ROW
	HRROI T3,STODAS		;GET STRING POINTER
	CALL STODST		;GO STORE THE DATE STRING
	AOBJN Q2,STODA1		;LOOP BACK FOR ALL DATES
	RET			;DONE

STODA3:	HRROI T1,STODAS		;GET FULL DATE
	HRLZ T2,Q2		;GET THE OFFSET
	ADD T2,Q1		;GET THE DATE
	MOVE T3,[OT%DAM!OT%SPA!OT%NTM]
	ODTIM
	HRROI T2,[ASCIZ/ /]
	SETZ T3,
	SOUT
	JRST STODA2
;ROUTINE TO CHECK IF A FIELD WILL FIT WITHOUT OVERLAPPING
;ACCEPTS IN T1/	COL #
;	    T2/	WIDTH OF FIELD
;	    T3/	POINTER TO STRING
;	    T4/	ROW #

CHKFLD:	SAVEQ
	SETZ Q1,		;CHECK ONLY
	JRST STOFL1

STOFLD:	SAVEQ
	MOVEI Q1,1		;STORE THE FIELD
STOFL1:	TLC T3,-1		;STRING POINTER
	TLCN T3,-1
	HRLI T3,(POINT 7,0)	;YES
	JUMPL T4,RSKP		;IF TOO EARLY, THEN DONE
	ASUBR <STOFLC,STOFLW,STOFLP,STOFLR>
	CAIL T4,NROW		;IS THE ROW TOO LARGE?
	RETSKP			;YES, OFF THE END
	CAIL T1,NCOL		;WITHIN BOUNDS?
	RETSKP			;NO
	ADD T1,T2		;DOES FIELD GO OFF THE END?
	CAIL T1,NCOL		;
	MOVEI T1,NCOL-1		;YES, JUST USE FIRST PART OF FIELD
	SUB T1,STOFLC		;GET UPDATED WIDTH
	MOVEM T1,STOFLW
STOFL2:	ILDB T1,STOFLP		;GET THE NEXT CHAR FROM THE FIELD
	JUMPE T1,RSKP		;IF NULL, THEN DONE
	MOVE T2,STOFLC		;GET COL NUMBER
	MOVE T3,STOFLR		;GET ROW NUMBER
	XCT [	CALL CHKCHR	;GO STORE/CHECK THIS CHAR
		CALL STOCHA](Q1)
	 RETSKP			;EXCEEDED TABLE SIZE
	JUMPE T1,R		;FAILED?
	AOS STOFLC		;NO, GO CHECK THE NEXT COL
	SOSLE STOFLW		;ANY MORE CHARACTERS?
	JRST STOFL2		;YES
	RETSKP			;NO, ALL DONE
;ROUTINE TO STORE A STRING
;ACCEPTS IN T1/	COL #
;	    T2/	ROW #
;	    T3/	STRING POINTER

STOSTR:	HRRES T1		;EXTEND THE SIGN IF HALF WORD GIVEN
	HRRES T2
	TLC T3,-1		;CONVERT TO BYTE POINTER
	TLCN T3,-1
	HRLI T3,(POINT 7,0)
	ASUBR <STOSTC,STOSTN,STOSTP>
STOST1:	ILDB T1,STOSTP		;GET THE NEXT CHARACTER
	JUMPE T1,R		;NULL IS THE END
	MOVE T2,STOSTC		;GET THE COLUMN #
	MOVE T3,STOSTN		;GET THE ROW #
	CALL STOCHA		;GO STORE IT ALWAYS
	 JFCL
	AOS STOSTC		;COUNT UP THE COLUMN
	JRST STOST1		;LOOP BACK TILL NULL
;ROUTINES TO STORE CHARACTERS INTO THE DATA BASE
;ACCEPTS IN T1/	CHAR
;	    T2/	COL #
;	    T3/	ROW #
;	CALL STOCHR
;RETURNS +1:	FAILED, EXCEEDED TABLE SIZE
;	 +2:	OK, T1/	0 = ALREADY A CHAR THERE, -1 = OK

STOCHA:	MOVEI T4,1		;STORE THE CHARACTER ALWAYS
	JRST STOCH1

CHKCHR:	TDZA T4,T4		;CHECK IF NO CHAR IN THIS COLLUMN
STOCHR:	SETO T4,		;STORE CHAR IF NONE THERE ALREADY
STOCH1:	HRRES T2		;EXTEND THE SIGN IF HALF WORD GIVEN
	HRRES T3
	ASUBR <STOCHV,STOCHC,STOCHN,STOCHF>
	SUB T3,ROWOFS		;REMOVE THE OFFSET FROM THE ROW
	JUMPL T2,R		;NEGATIVE COL IS WRONG
	JUMPL T3,R		;NEGATIVE ROW IS WRONG
	CAIGE T2,NCOL		;LEGAL COLUMN?
	CAIL T3,NROW		;YES, LEGAL ROW?
	RET			;NO
	JUMPE T4,STOCH3		;STORING?
	CAML T2,COLMAX		;YES, IS THIS A NEW MAXIMUM COLUMN?
	MOVEM T2,COLMAX		;YES, REMEMBER IT
STOCH3:	MOVEI T4,ROWLEN		;GET THE CHAR POSITION
	IMULI T4,0(T3)
	IDIVI T2,6		;GET WORD POSITION IN COLUMN
	ADD T4,T2		;GET WORD NUMBER WITHIN DATA BASE
	LDB T2,BPTAB(T3)	;GET THE APPROPRIATE BYTE
	SKIPE T2		;ANY CHAR THERE ALREADY?
	SKIPLE STOCHF		;YES, STORE IT ANY WAYS?
	SKIPA			;YES
	JRST STOCH2		;FAILED, CHARACTER ALREADY THERE
	CAIL T1,140		;LOWER CASE?
	SUBI T1,40		;YES, RAISE IT
	SUBI T1,40		;STORE SIXBIT CHAR
	SKIPE STOCHF		;DONT STORE THE CHAR?
	DPB T1,BPTAB(T3)	;NO, STORE IT
	SKIPA T1,[-1]		;FLAG SUCCESS
STOCH2:	SETZ T1,		;FAILED
	RETSKP

BPTAB:	POINT 6,ROWSTG(T4),5
	POINT 6,ROWSTG(T4),11
	POINT 6,ROWSTG(T4),17
	POINT 6,ROWSTG(T4),23
	POINT 6,ROWSTG(T4),29
	POINT 6,ROWSTG(T4),35
;ROUTINE TO PRINT THE GANTT CHART
;ACCEPTS IN T1/	0,,JFN = FIRST PASS, -1,,JFN = SECOND PPASS
;	    T2/	STARTING COL
;	    T3/	MAX COL ,, MAX ROW
;	    T4/	START DATE

PRIGNT:	SAVEPQ
	SETZ Q1,		;LPT
	JRST PRIGN0

PLOGNT:	SAVEPQ
	MOVEI Q1,1		;PLOTTER
PRIGN0:	STKVAR <<PRIGNS,NCOL>,PRIGNF>
	MOVEM Q1,PRIGNF		;SAVE THE DEVICE FLAG
	DMOVE P1,T1		;SAVE THE ARGS
	DMOVE P3,T3
	MOVE Q1,P2		;GET STARTING COL
PRIGN1:	SETZ Q2,		;SET ROW TO 0
	HRROI T1,PRIGNS		;GET THE DATE LINE
	MOVE T2,P4		;START DATE
	MOVE T3,Q1		;COL
	HLL T3,P3		;GET MAX COL
	MOVE T4,PRIGNF		;GET FLAG (LPT OR PLOTTER)
	CALL PRIGDT		;GET DATE LINES
PRIGN2:	MOVEI Q3,NGROW		;GE NUMBER OF ROWS TO DO
PRIGN3:	MOVE T1,P1		;GET JFN
	MOVEI T2," "		;IF PLOTTING, LEAVE A SPACE IN COL 1
	SKIPE PRIGNF		;PLOTTING?
	BOUT			;YES, THIS KEEPS "TXT2P" FROM GETTING LOST
	MOVE T2,Q1		;GET COL
	MOVE T3,Q2		;GET ROW
	HLRZ T4,P3		;GET MAX COL
	CALL PRIGCL		;GO PRINT THIS ROW
	AOS Q2			;STEP ROW
	HRRZ T1,P3		;GET MAX ROW
	CAIL T1,NROW		;BEYOND END OF TABLE?
	MOVEI T1,NROW		;YES, STOP HERE
	CAML Q2,T1		;REACHED THE END?
	JRST PRIGN4		;YES
	SOJG Q3,PRIGN3		;LOOP BACK FOR MORE ROWS
	MOVE T1,P1		;TIME TO OUTPUT THE DATE LINES
	HRROI T2,PRIGNS		;GET POINTER TO STRING
	SETZ T3,
	SOUT
	JRST PRIGN2		;LOOP BACK FOR NEXT SET OF ROWS

PRIGN4:	MOVE T1,P1		;TIME TO OUTPUT THE DATE LINES
	HRROI T2,PRIGNS		;GET POINTER TO STRING
	SETZ T3,
	SOUT
	RET			;DONE
;ROUTINE TO OUTPUT A ROW
;ACCEPTS IN T1/	JFN
;	    T2/	COL OFFSET
;	    T3/	ROW
;	    T4/	MAX COL

PRIGCL:	SAVEP
	STKVAR <<PRIGCS,ROWLEN>>
	JUMPL T2,R		;NEGATIVE IS NOT ALLOWED
	JUMPL T3,R
	CAIL T3,NROW		;LEGAL ROW?
	RET			;NO
	CAIL T4,NCOL		;MAX COL?
	MOVEI T4,NCOL-1		;NO, MAKE IT LEGAL
	DMOVE P1,T1		;SAVE THE ARGS
	DMOVE P3,T3
	MOVEI T4,ROWLEN		;GET POINTER TO THE ROW
	IMULI T4,(P3)
	ADDI T4,ROWSTG
	HRLI T4,(POINT 6,0)
	MOVE T2,P2		;GET COL OFFSET
	ADJBP T2,T4		;GET CORRECT COL STARTING POINT
	MOVE T4,T2		;SAVE POINTER IN T4
	MOVE T3,P4		;GET MAX COL
	SUB T3,P2		;GET NUMBER OF COLS TO OUTPUT
	JUMPL T3,R		;IF NONE, THEN DONE
	MOVEI T1,PRIGCS		;GET POINTER TO TEMP STRING
	HRLI T1,(POINT 7,0)
PRIGC1:	ILDB T2,T4		;GET NEXT CHAR
	ADDI T2,40		;SIXBIT TO ASCII
	CAIN T2,"\"		;PLACE HOLDER?
	MOVEI T2," "		;YES, PRINT IT AS SPACE
	IDPB T2,T1		;STORE THE CHARACTER IN THE TEMP STRING
	SOJG T3,PRIGC1		;LOOP BACK FOR ALL CHARS IN ROW
	MOVEI T2,15		;CR
	IDPB T2,T1		;STORE THE CHARACTER IN THE TEMP STRING
	MOVEI T2,12		;LF
	IDPB T2,T1		;STORE THE CHARACTER IN THE TEMP STRING
	MOVEI T2,0		;PUT A NUL AT THE END
	IDPB T2,T1
	MOVE T1,P1		;GET THE JFN
	HRROI T2,PRIGCS		;GET POINTER TO THE STRING
	SETZ T3,
	SOUT			;OUTPUT THE LINE
	RET			;DONE
;ROUTINE TO BUILD THE DATE LINES
;ACCEPTS IN T1/	STRING POINTER
;	    T2/	START DATE
;	    T3/	MAX COL ,, STARTING COL
;	    T4/	0 = LPT, 1 = PPLOTTER

PRIGDT:	SAVEPQ
	STKVAR <<PRIGDS,10>>
	MOVE P5,T4		;SAVE FLAG
	HLRZ T4,T3		;T4 = MAX COL
	HRRZS T3		;T3 = STARTING COL
	DMOVE P1,T1		;SAVE THE ARGS
	DMOVE P3,T3
	SUB P4,P3		;GET THE NUMBER OF CHARS TO OUTPUT
	JUMPL P4,R		;IF NONE, RETURN
	HRROI T2,[ASCIZ/

/]
	SETZ T3,
	SOUT			;START WITH A CR-LF
	MOVEI T2," "		;PUT IN A SPACE IF PLOTTER
	SKIPE P5		;PLOTTER?
	BOUT			;YES
	HRLZ T2,P3		;GET STARTING COL
	ADDM T2,P2		;STEP THE DATE TO THE RIGHT SPOT
	HLRZ T3,P2		;GET DAY
	ADDI T3,2		;SEE IF IT IS A MONDAY
	IDIVI T3,7
	MOVE Q3,P4		;GET COUNT OF COLS TO DO
	MOVEI T2," "		;SPACE
	JUMPE T4,PRIGD2		;IF MONDAY, SKIP OVER INITIAL SPACES
	MOVNS T4		;GET NUMBER OF DAYS TIL MONDAY
	ADDI T4,7
PRIGD1:	BOUT			;OUTPUT SPACE
	SOJLE Q3,PRIGD3		;COUNT DOWN COLS
	SOJG T4,PRIGD1		;LOOP BACK UNTIL MONDAY
PRIGD2:	MOVEI T2,"!"
	BOUT
	SOJLE Q3,PRIGD3		;DONE?
	SUBI Q3,3
	JUMPL Q3,PRIGD3		;ENOUGH ROOM FOR THE DATE?
	MOVEI T2," "
	BOUT
	MOVEM T1,P1		;SAVE THE STRING POINTER
	MOVE T2,P4		;GET CURRENT DATE...
	SUBI T2,4(Q3)		;GET OFFSET
	HRLZS T2
	ADD T2,P2		;GET TODAY'S DATE
	SETZ T4,
	ODCNV
	HLRZ T2,T3		;GET DAY OF THE MONTH
	ADDI T2,1		;PLUS ONE SINCE FIRST DAY = 0
	MOVE T1,P1		;GET JFN
	MOVE T3,[NO%ZRO+2B17+12]
	NOUT
	 MOVE T1,P1
	SUBI Q3,3		;ENOUGH ROOM FOR SPACES
	JUMPLE Q3,PRIGD3
	HRROI T2,[ASCIZ/   /]
	SETZ T3,
	SOUT
	JRST PRIGD2

PRIGD3:	HRROI T2,[ASCIZ/
/]
	SETZ T3,
	SOUT
	MOVEI T2," "		;PUT A SPACE AT START OF LINE IF PLOTTER
	SKIPE P5		;PLOTTER?
	BOUT			;YES, ADD A SPACE
	HLRZ T3,P2		;GET START DATE
	ADDI T3,2
	IDIVI T3,7		;GET NUMBER OF DAYS FROM MONDAY
	ADJBP T4,[POINT 7,[ASCIZ/M.W.F..M.W.F../]]
	MOVE Q1,T4		;SAVE THE BYTE POINTER
	MOVE Q3,P4		;GET THE COUNT OF COLS TO DO
PRIGD4:	MOVE T3,Q1		;GET THE BYTE POINTER
	MOVEI T4,7		;DO 7 DAYS
PRIGD5:	ILDB T2,T3		;GET NEXT CHAR
	BOUT
	SOJLE Q3,PRIGD6		;DONE?
	SOJG T4,PRIGD5		;NO, DO REST OF THE WEEK
	JRST PRIGD4		;LOOP BACK FOR ANOTHER 7 DAYS

PRIGD6:	HRROI T2,[ASCIZ/
/]
	SETZ T3,
	SOUT
	MOVEI T2," "		;PUT A SPACE AT START OF LINE IF PLOTTER
	SKIPE P5		;PLOTTER?
	BOUT			;YES, ADD A SPACE
	MOVE Q3,P4		;GET COL COUNT
	MOVE Q2,P2		;GET STARTING DATE
PRIGD7:	MOVEM T1,P1		;SAVE THE STRING POINTER
	MOVE T2,Q2		;GET DATE
	SETZ T4,
	ODCNV			;THIS THE FIRST OF THE MONTH?
	MOVE T1,P1		;RESTORE THE STRING POINTER
	TLNN T3,-1		;DAY 0?
	JRST PRIGD8		;YES
	MOVE T1,P1		;GET THE JFN
	MOVEI T2," "
	BOUT
	SOJLE Q3,PRIGD9		;DONE?
	MOVSI T2,1		;STEP TO NEXT DAY
	ADDM T2,Q2
	JRST PRIGD7		;LOOP BACK UNTIL 1ST OF THE MONTH

PRIGD8:	MOVEI T2,"!"
	BOUT
	MOVEM T1,P1		;SAVE THE STRING POINTER
	SOJLE Q3,PRIGD9		;DONE?
	SUBI Q3,7		;ENOUGH ROOM FOR MONTH?
	JUMPL Q3,PRIGD9
	HRROI T1,PRIGDS		;GET THE DATE
	MOVE T2,Q2		;DATE
	MOVE T3,[OT%SPA!OT%NTM]
	ODTIM
	MOVE T1,P1		;GET THE JFN
	MOVEI T2,PRIGDS		;GET POINTER TO STRING
	HRLI T2,(POINT 7,0,13)	;STEP OVER THE DAY FIELD
	SETZ T3,
	SOUT			;OUTPUT THE MONTH AND YEAR
	MOVSI T2,^D8		;STEP DATE
	ADDM T2,Q2
	JRST PRIGD7		;LOOP BACK TIL DONE

PRIGD9:	MOVE T1,P1		;GET THE JFN
	HRROI T2,[ASCIZ/

/]
	SETZ T3,
	SOUT
	RET
;ROUTINE TO PRINT THE STORED DATA BASE
;ACCEPTS IN T1/	JFN
;	    T2/	MAX ROW TO BE PRINTED
;	    T3/	MAXIMUM COLUMN TO BE PRINTED
;	    T4/	COLUMN OFFSET

PRISTO:	SAVEPQ
	STKVAR <PRISTA,PRISTB,PRISTC,PRISTD,<PRISTS,ROWLEN>>
	MOVEM T1,PRISTA		;SAVE THE ARGS
	MOVEM T2,PRISTB
	MOVEM T3,PRISTC
	MOVEM T4,PRISTD
	DVCHR			;GET CHARACTERISTICS OF DEVICE
	LDB Q3,[POINT 9,T2,17]	;GET DEVICE TYPE
	MOVE T1,PRISTA		;GET BACK THE JFN
	MOVE T2,PRISTB		;GET ROW
	MOVE T3,PRISTC		;GET COL
	CAIL T2,NROW		;ABOVE MAXIMUM ROW?
	MOVEI T2,NROW		;YES
	MOVNS T2
	CAIL T3,NCOL		;ABOVE THE MAX COLUMN?
	MOVEI T3,NCOL-1		;YES
	MOVE P3,PRISTD		;INIT COL COUNTER
	HRLZ P1,T2		;GET ROW COUNTER INTO P1
	AOS P2,T3		;P2 = MAXIMUM COLUMN
PRIST0:	MOVE Q1,P1		;SET UP ROW COUNTER
PRIST1:	MOVEI T4,^D132		;SET UP COLUMN COUNTER FOR THIS SECTION
	CAML T4,P2		;REACHED THE END?
	MOVE T4,P2		;YES, ONLY PRINT UP TO COLMAX
	MOVNS T4		;SET UP AOBJN POINTER
	HRLZ Q2,T4		;SET UP COLUMN COUNT
	HRR Q2,P3		;SET UP STARTING COLUMN
	MOVEI T4,ROWLEN		;GET POINTER TO CORRECT ROW
	IMULI T4,(Q1)
	ADDI T4,ROWSTG		;GET CORRECT POSITION IN DATA BASE
	HRLI T4,(POINT 6,0)	;GET BYTE POINTER TO FIRST CHAR IN ROW
	MOVEI T2,(Q2)		;ADVANCE BYTE POINTER TO CORRECT SPOT
	ADJBP T2,T4
	MOVE T4,T2		;LEAVE ADJUSTED BYTE POINTER IN T4
	MOVEI T1,PRISTS		;SET UP POINTER TO TEMP STRING
	HRLI T1,(POINT 7,0)
PRIST2:	ILDB T2,T4		;GET NEXT CHAR
	ADDI T2,40		;SIXBIT TO ASCIZ
	CAIN T2,"\"		;PLACE HOLDER?
	MOVEI T2," "		;YES, PRINT IT AS SPACE
	IDPB T2,T1		;STORE THE CHARACTER IN THE TEMP STRING
	AOBJN Q2,PRIST2		;NO, LOOP BACK FOR ALL CHARACTERS IN ROW
	MOVEI T2,15		;OUTPUT A CR-LF
	IDPB T2,T1		;STORE THE CHARACTER IN THE TEMP STRING
	MOVEI T2,12
	CAIE Q3,.DVTTY		;IS THIS A TTY?
	MOVEI T2,"S"-100	;NO, THEN PUT OUT A DC3 INSTEAD
	IDPB T2,T1		;STORE THE CHARACTER IN THE TEMP STRING
	MOVEI T2,0		;END WITH A NUL
	IDPB T2,T1
	MOVE T1,PRISTA		;GET THE JFN
	HRROI T2,PRISTS		;GET POINTER TO THE TEMP STRING
	SETZ T3,
	SOUT			;OUTPUT THIS LINE
	AOBJN Q1,PRIST1		;LOOP BACK FOR ALL ROWS
	RET			;DONE
;ROUTINE TO PRINT OUT THE PLOTTER DATA 
;ACCEPTS IN T1/	JFN
;	    T2/	MAX ROW
;	    T3/	MAX COL

PRIPLT:	SAVEQ
	STKVAR <PRIPLJ,<PRIPLS,<NCOL+5/6>>>
	MOVEM T1,PRIPLJ		;SAVE THE JFN
	CAIL T2,NROW		;LEGAL ROW?
	MOVEI T2,NROW-1		;NO, TRUNCATE IT
	CAIL T3,NCOL		;LEGAL COL?
	MOVEI T3,NCOL-1		;NO, TRUNCATE IT
	DMOVE Q2,T2		;SAVE ROW AND COL
	HRROI T2,[ASCIZ/.TEXTSIZE;0.12 X
.SIZE;1,/]
	SETZ T3,
	SOUT
	MOVEI T2,1(Q3)		;GET MAX COL
	MOVEI T3,^D10
	NOUT
	 JFCL
	HRROI T2,[ASCIZ/C,0
/]
	SETZ T3,
	SOUT
	SETZ Q1,		;START AT ROW 0
PRIPL1:	MOVEI T4,ROWLEN		;GET ADR OF FIRST WORD OF ROW
	IMULI T4,(Q1)
	ADDI T4,ROWSTG
	HRLI T4,(POINT 6,0)	;GET BYTE POINTER TO ROW
	SETZ T3,		;START AT FIRST COL
	MOVEI T1,PRIPLS		;SET POINTER TO TEMP STRING
	HRLI T1,(POINT 7,0)
PRIPL2:	ILDB T2,T4		;GET NEXT CHAR
	ADDI T2,40		;SIXBIT TO ASCIZ
	CAIN T2,"\"		;PLACE HOLDER?
	MOVEI T2," "		;YES, PRINT IT AS SPACE
	IDPB T2,T1		;PUT CHAR IN THE STRING
	CAMGE T3,Q3		;FINISHED WITH ROW?
	AOJA T3,PRIPL2		;NOT YET
	MOVEI T2,0		;END WITH A NUL
	IDPB T2,T1
	MOVE T1,PRIPLJ		;GET JFN
	HRROI T2,PRIPLS		;GET POINTER TO STRING
	SETZ T3,
	SOUT			;OUTPUT THE STRING
	HRROI T2,[ASCIZ/
/]
	SETZ T3,		;OUTPUT CRLF
	SOUT
	CAMGE Q1,Q2		;AT THE LAST ROW?
	AOJA Q1,PRIPL1		;NO, GO DO THE NEXT ROW
	RET			;DONE
;ROUTINE TO DRAW A BOX AROUND EACH TASK
;ACCEPTS IN T1/	JFN
;	    T2/	DATE

DBOX:	SAVEQ
	MOVE Q1,T1		;SAVE THE JFN
	MOVE Q3,T2		;SAVE TODAY'S DATE
	MOVE Q2,TSKPTR		;GET POINTER TO THE LIST
DBOX1:	SKIPE TSKINV(Q2)	;WANT THIS IN PERT?
	JRST DBOX2		;NO--SKIP IT
	MOVE T1,Q1		;GET THE JFN
	HRRZ T2,Q2		;GET THE TASK INDEX
	CALL DLINI		;DRAW THE BOX
	 JFCL			;FAILED
	HRRZ T4,TSKLST(Q2)	;GET TASK ADR
	LOAD T3,TKAFD,(T4)	;GET ACTUAL FINISH DATE
	JUMPE T3,DBOX2		;IF NONE, THEN NOT DONE
	CAML Q3,TSKFDL(Q2)	;FINISH IN THE FUTURE?
	CAMLE T3,Q3		;OR TASK ALREADY FINISHED?
	JRST DBOX2		;TASK IS NOT DONE
	MOVE T1,Q1		;GET THE JFN
	HRRZ T2,Q2		;GET THE TASK INDEX
	CALL DLINO		;DRAW OUTER BOX
	 JFCL
DBOX2:	AOBJN Q2,DBOX1		;LOOP BACK FOR ALL BOXES
	RET
;ROUTINE TO DRAW THE INSIDE BOX
;ACCEPTS IN T1/	JFN
;	    T2/	TASK INDEX
;RETURNS +1:	FAILED
;	 +2:	OK

DLINI:	SAVEQ
	MOVE Q1,T2		;SAVE THE TASK INDEX
	HRROI T2,[ASCIZ/.AMOVE;/]
	SETZ T3,
	SOUT
	MOVE T2,TSKPOS(Q1)	;GET START OF BOX
	ADDI T2,2		;STEP OVER INITIAL SPACES
	MOVEI T3,^D10
	NOUT
	 RET
	HRROI T2,[ASCIZ\.9C,-\]
	SETZ T3,
	SOUT
	HLRZ T2,TSKSKD(Q1)	;GET THE LEVEL #
	IMULI T2,<BOXLEN+^D12>	;GET THE Y COORD
	ADDI T2,1		;STEP OVER THE FIRST LINE
	MOVEI T3,^D10
	NOUT
	 RET
	HRROI T2,[ASCIZ\.9C
.RLINE;0.0,-6.5C/\]
	SETZ T3,
	SOUT
	MOVE T2,TSKWID(Q1)	;GET BOX WIDTH
	SUBI T2,6		;MINUS FILLER
	MOVEI T3,^D10
	NOUT
	 RET
	HRROI T2,[ASCIZ\.1C,0.0C/0.0C,6.5C/-\]
	SETZ T3,
	SOUT
	MOVE T2,TSKWID(Q1)	;GET WIDTH AGAIN
	SUBI T2,6
	MOVEI T3,^D10
	NOUT
	 RET
	HRROI T2,[ASCIZ\.1C,0.0C
\]
	SETZ T3,
	SOUT
	RETSKP
;ROUTINE TO DRAW THE OUTSIDE BOX
;ACCEPTS IN T1/	JFN
;	    T2/	TASK INDEX
;RETURNS +1:	FAILED
;	 +2:	OK

DLINO:	SAVEQ
	CALL TOBOX		;.AMOVE OVER TO BOX
	  RET			;FAILED
	MOVE Q1,T2
	HRROI T2,[ ASCIZ \.RLINE;0.0,-7.5C/\]
	SETZ T3,
	SOUT
	MOVE T2,TSKWID(Q1)	;GET BOX WIDTH
	SUBI T2,5		;MINUS FILLER
	MOVEI T3,^D10
	NOUT
	 RET
	HRROI T2,[ASCIZ\.9C,0.0C/0.0C,7.5C/-\]
	SETZ T3,
	SOUT
	MOVE T2,TSKWID(Q1)	;GET WIDTH AGAIN
	SUBI T2,5
	MOVEI T3,^D10
	NOUT
	 RET
	HRROI T2,[ASCIZ\.9C,0.0C
\]
	SETZ T3,
	SOUT
	RETSKP
;ROUTINE TO CONNECT THE BOXES TOGETHER
;ACCEPTS IN T1/	JFN

CBOX:	SAVEPQ
	STKVAR <<CBOXST,2000>>
	MOVE P4,T1		;SAVE THE JFN
	SETZ Q1,		;START AT LEVEL 0
CBOX1:	MOVE Q2,TSKPTR		;SET UP POINTER TO TASK LIST
	SETZ Q3,		;INIT COUNT OF TASKS FOUND
CBOX2:	SKIPE TSKINV(Q2)
	JRST CBOX5
	HLRZ T1,TSKSKD(Q2)	;GET LEVEL #
	CAME T1,Q1		;IS THIS A DESIRED LEVEL?
	JRST CBOX5		;NO
	AOS Q3			;COUNT UP TASKS FOUND AT THIS LEVEL
	HRRZ P1,TSKLST(Q2)	;GET ADR OF TASK
	LOAD P2,TKBLP,(P1)	;SEE IF IT IS BLOCKING ANYTHING
	JUMPE P2,CBOX5
CBOX3:	LOAD T1,DPTKP,(P2)	;GET ADR OF BLOCKED TASK
	LOAD T1,TKTKI,(T1)	;GET ITS TASK LIST INDEX
	MOVE T3,T1		;GET INDEX OF DESTINATION BOX
	HRRZ T2,Q2		;GET INDEX OF SOURCE BOX
	HRROI T1,CBOXST		;GET POINTER TO STRING
	CALL CBOXI		;DRAW THE LINES
	 JRST CBOX4		;FAILED
	HRROI T2,CBOXST		;OUTPUT LINE COMMAND TO JFN
	SETZ T3,
	MOVE T1,P4		;GET THE JFN
	SOUT
CBOX4:	LOAD P2,DPBLP,(P2)	;STEP TO NEXT BLOCKED TASK
	JUMPN P2,CBOX3		;IF THERE ARE ANY LEFT
CBOX5:	AOBJN Q2,CBOX2		;LOOP BACK FOR THIS LEVEL
	JUMPE Q3,R		;IF NONE FOUND, THEN DONE
	AOJA Q1,CBOX1		;LOOP BACK FOR THE NEXT LEVEL
;ROUTINE TO SET UP FOR DRAWING THE LINES
;ACCEPTS IN T1/	STRING POINTER
;	    T2/	INDEX OF FIRST TASK
;	    T3/	INDEX OF SECOND TASK

CBOXI:	SAVEQ
	MOVE Q1,T1		;SET UP FOR DLINE
	DMOVE Q2,T2		;SAVE THE ARGS
	SKIPN TSKINV(T2)	;WANT FIRST TASK
	SKIPE TSKINV(T3)	;AND SECOND TASK
	RET			;NO
	MOVE T1,TSKPOS(Q2)	;GET POSITION OF FIRST TASK
	MOVE T2,TSKWID(Q2)	;ADD IN HALF THE WIDTH
	LSH T2,-1
	ADDI T1,-1(T2)		;WIDTH INCLUDES SOME BLANKS TO SKIP OVER
	HLRZ T2,TSKSKD(Q2)	;GET LEVEL #
	MOVE T3,TSKPOS(Q3)	;GET ADR OF SECOND BOX
	MOVE T4,TSKWID(Q3)
	LSH T4,-1
	ADDI T3,-1(T4)		;ADD IN HALF THE WIDTH
	HLRZ T4,TSKSKD(Q3)	;GET THE LEVEL #
	CALL DLINE		;DRAW THE LINES
	 RET
	RETSKP
;ROUTINE TO DRAW A LINE FROM ONE BOX TO ANOTHER
;ACCETPS IN T1/	START ADR
;	    T2/	LEVEL # OF FIRST BOX
;	    T3/	END ADR
;	    T4/	LEVEL # OF SECOND BOX
;	    Q1/	STRING POINTER TO RECEIVE THE ANSWER
;	CALL DLINE
;RETURNS +1:	FAILED
;	 +2:	SUCCESS

DLINE:	ASUBR <DLINS,DLINL1,DLINF,DLINL2>
	MOVE T1,Q1		;GET POINTER TO STRING
	HRROI T2,[ASCIZ/.AMOVE;/]
	SETZ T3,
	SOUT			;START BY MOVING TO THE START ADR
	MOVE T2,DLINS		;GET START ADR
	MOVEI T3,^D10
	NOUT
	 RET
	HRROI T2,[ASCIZ/.4C,-/]	;NOW DO THE Y COORD
	SETZ T3,
	SOUT
	MOVE T2,DLINL1		;GET THE LEVEL #
	IMULI T2,<BOXLEN+^D12>	;GET Y COORD
	ADDI T2,BOXLEN-2		;GET BOTTOM OF THE BOX
	MOVEI T3,^D10
	NOUT
	 RET
	HRROI T2,[ASCIZ/.4C
.RLINE;0.0C,-1.0C
.ALINE;/]
	SETZ T3,
	SOUT
	MOVE Q1,T1		;SET UP FOR CALL TO DLINE0
	MOVE T1,DLINS
	MOVE T2,DLINL1
	MOVE T3,DLINF
	MOVE T4,DLINL2
	CALL DLINE0		;GO DRAW THE LINES TO THE END BOX
	 RET			;FAILED
	RETSKP			;OK

;ROUTINE TO DRAW LINES (CALLED RECURSIVELY)
;ACCEPTS SAME ARGS AS DLINE

DLINE0:	ASUBR <DLST,DLL1,DLEND,DLL2>
	CAIG T4,1(T2)		;AT THE END?
	JRST DLINE1		;YES
	MOVE T1,DLST		;GET THE START ADR
	MOVE T2,DLEND
	MOVE T3,DLL1		;GET THE LEVEL NUMBER
	ADDI T3,1		;GET LEVEL NUMBER OF NEXT SET OF BOXES
	CALL FNDHOL		;FIND THE APPROPRIATE HOLE
	 RET			;NONE FOUND
	MOVEM T1,DLST		;SAVE THE NEW X COORD
	MOVE T2,T1		;GET X COORD INTO T2
	MOVE T1,Q1		;GET STRING POINTER
	MOVEI T3,^D10
	NOUT			;OUTPUT X COORD OF THE HOLE
	 RET
	HRROI T2,[ASCIZ/.4C,-/]
	SETZ T3,
	SOUT
	AOS T2,DLL1		;GET THE LEVEL NUMBER OF NEXT LEVEL
	IMULI T2,<BOXLEN+^D12>
	MOVEI T3,^D10
	NOUT
	 RET
	HRROI T2,[ASCIZ\.65C/\]
	SETZ T3,
	SOUT
	MOVE T2,DLST		;GET X COORD AGAIN
	MOVEI T3,^D10
	NOUT
	 RET
	HRROI T2,[ASCIZ/.4C,-/]
	SETZ T3,
	SOUT
	MOVE T2,DLL1		;GET Y COORD
	IMULI T2,<BOXLEN+^D12>
	ADDI T2,BOXLEN-1
	MOVEI T3,^D10
	NOUT
	 RET
	HRROI T2,[ASCIZ\.4C/\]
	SETZ T3,
	SOUT
	MOVE Q1,T1		;SET UP FOR RECURSION
	MOVE T1,DLST		;GET BACK THE ARGS
	MOVE T2,DLL1
	MOVE T3,DLEND
	MOVE T4,DLL2
	CALL DLINE0		;GO DO REST OF THE LINES
	 RET
	RETSKP			;DONE

;COME HERE ON LAST LINE

DLINE1:	MOVE T1,Q1		;GET THE STRING POINTER
	MOVE T2,DLEND		;GET X COORD OF FINAL POSITION
	MOVEI T3,^D10
	NOUT
	 RET
	HRROI T2,[ASCIZ/.4C,-/]
	SETZ T3,
	SOUT
	MOVE T2,DLL2		;GET THE Y COORD
	IMULI T2,<BOXLEN+^D12>
	ADDI T2,1		;DRAW LINE TO THE BOX
	MOVEI T3,^D10
	NOUT
	 RET
	HRROI T2,[ASCIZ/.4C
.RLINE;0.0C,-0.5C
/]
	SETZ T3,
	SOUT
	RETSKP			;DONE
;ROUTINE TO FIND A FREE HOLE BETWEEN BOXES AND THEN PLUG IT
;ACCEPTS IN T1/	START X ADR
;	    T2/	END X ADR
;	    T3/	LEVEL # TO LOOK AT
;	CALL FNDHOL
;RETURNS +1:	NONE FOUND
;	 +2:	T1/	ADR OF THE HOLE
;			HOLE FILLED WITH 1

FNDHOL:	SAVEQ
	SETZ Q1,		;INIT COL COUNTER
	SETO Q2,		;NO SPACES SEEN YET
	IMULI T3,SPCTBL		;GET INDEX INTO SPACE TABLE
	ADDI T3,SPCTAB
	HRLI T3,(POINT 1,0)	;BUILD POINTER TO ROW
FNDHL1:	CAIL Q1,NCOL		;AT THE END OF THE ROW?
	JRST [	JUMPL Q2,R	;IF NONE FOUND, RETURN
		JRST FNDHL3]	;GO USE THE LAST HOLE FOUND
	ILDB T4,T3		;GET NEXT CHAR
	SKIPE T4		;FOUND A SPACE?
	AOJA Q1,FNDHL1		;NO, LOOP BACK
	CAML Q1,T1		;BEYOND WHERE WE WANT?
	JRST FNDHL2		;YES, GO USE THIS HOLE
	MOVE Q2,Q1		;SAVE THIS HOLE
	MOVE Q3,T3		;SAVE THE BYTE POINTER ALSO
	AOJA Q1,FNDHL1		;LOOP BACK FOR A MOR OPTIMUM HOLE

FNDHL2:	CAMN Q1,T1		;EXACTLY THE RIGHT SPOT?
	JRST FNDHL4		;YES, GO USE THIS ONE
	CAMLE T1,T2		;BACKWARDS LINE OR FORWARD LINE?
	JUMPGE Q2,FNDHL3	;BACKWARDS, USE LAST HOLE FOUND
FNDHL4:	MOVEI T4,1		;GET PLUG CHARACTER
	DPB T4,T3		;STORE IT
	MOVE T1,Q1		;GET THE X COORD
	RETSKP			;DONE

FNDHL3:	MOVEI T4,1		;GET PLUG CHARACTER
	DPB T4,Q3		;STORE IT
	MOVE T1,Q2		;GET X COORD
	RETSKP			;DONE
;ROUTINE TO INIT THE SPACE TABLE

INISPC:	SETZM SPCTAB		;ZERO THE FIRST WORD IN TABLE
	MOVE T1,[SPCTAB,,SPCTAB+1]
	BLT T1,SPCTBS-1+SPCTAB	;ZERO THE REST
	RET


;ROUTINE TO MARK USED COLUMNS
;ACCEPTS IN T1/	LEVEL #
;	    T2/	ROW #

SETSPC:	SUB T2,ROWOFS		;GET POINTER TO ROW
	JUMPL T2,R		;IF NEGATIVE ROW, DONT DO ANYTHING
	MOVEI T4,NCOL		;SET UP COUNTER
	IMULI T1,SPCTBL		;GET OFFSET INTO SPACE TABLE
	ADDI T1,SPCTAB
	HRLI T1,(POINT 1,0)	;GET POINTER TO THIS LINE
	IMULI T2,ROWLEN
	ADDI T2,ROWSTG
	HRLI T2,(POINT 6,0)
SETSP1:	ILDB T3,T2		;GET THE NEXT CHAR
	ADDI T3,40		;SIXBIT TO ASCIZ
	CAIN T3," "		;SPACE?
	TDZA T3,T3		;YES, MARK THIS AS FREE
	MOVEI T3,1		;NO, THIS SPOT IS IN USE
	IDPB T3,T1		;STORE THIS IN THE SPACE TABLE
	SOJG T4,SETSP1		;LOOP BACK FOR THE ENTIRE LINE
	RET
;SUBROUTINE TO MARK BOXES WHICH HAVE "OFF PERT" CONNECTIONS
;CALL WITH:
;	T1/ JFN
;	CALL TICKS
;	RETURN HERE
TICKS:	SAVEPQ
	MOVE P4,T1		;SAVE JFN
	MOVE Q1,TSKPTR		;MAKE AOBJN POINTER
TICKS1:	SKIPE TSKINV(Q1)	;IS THIS TASK IN THE PERT?
	JRST TICKS7		;NO--IGNORE IT
	HRRZ P1,TSKLST(Q1)	;ADDRESS OF TASK BLOCK
	LOAD P2,TKBLP,(P1)	;LIST OF TASKS WE ARE BLOCKING
	JUMPE P2,TICKS4		;JUMP IF NOT BLOCKING ANYTHING
TICKS2:	LOAD T1,DPTKP,(P2)	;POINTER TO ITS TASK BLOCK
	LOAD T1,TKTKI,(T1)	;GET TSKLST INDEX
	SKIPN TSKINV(T1)	;IN PERT?
	JRST TICKS3		;YES--LOOK AT NEXT BLOCKED TASK
	HRRZ T2,Q1		;COPY TASK INDEX
	MOVE T1,P4		;COPY JFN
	CALL DNTICK		;SOMETHING NOT IN THE PERT NEEDS US
	JRST TICKS4		;SEE IF WE NEED AN UPTICK
TICKS3:	LOAD P2,DPBLP,(P2)	;STEP DOWN THE LIST
	JUMPN P2,TICKS2		;KEEP LOOKING DOWN THE LIST

;NOW SEE IF AN UPTICK IS NEEDED
TICKS4:	LOAD P2,TKDLP,(P1)	;DO WE DEPEND ON ANYTHING?
	JUMPE P2,TICKS7		;NO--ALL DONE WITH THIS BOX
TICKS5:	LOAD T1,DPBTK,(P2)	;POINTER TO TASK BLOCK
	LOAD T1,TKTKI,(T1)	;GET TSKLST INDEX
	SKIPN TSKINV(T1)	;IN PERT?
	JRST TICKS6		;YES--LOOK AT NEXT ITEN
	MOVE T1,P4		;COPY JFN
	HRRZ T2,Q1		;COPY TASK INDEX
	CALL UPTICK		;PUT IN THE LINE
	JRST TICKS7		;ALL DONE WITH THIS BOX
TICKS6:	LOAD P2,DPDLP,(P2)	;SCAN DOWN THE LIST
	JUMPN P2,TICKS5		;LOOK AT EVERYTHING WE DEPEND ON
TICKS7:	AOBJN Q1,TICKS1		;LOOK AT ALL BOXES
	RET			;ALL DONE!
;SUBROUTINES TO DRAW THE TICK MARKS
;CALL WITH:
;	T1/ JFN
;	T2/ TSKLST INDEX OF BOX
;	CALL UPTICK OR DNTICK
;	RETURN HERE
UPTICK:	CALL TOBOX		;MOVE OVER TO BOX
	  RET			;FAILED
	HRRZ T4,TSKLST(T2)	;GET POINTER TO TASK BLOCK
	LOAD T3,TKAFD,(T4)	;GET ACTUAL FINISH DATE
	HRROI T2,[ASCIZ ".RMOVE;0.9C,-0.5C
"]
	SKIPN T3		;DONE?
	SOUT			;NO--MOVE TO INNER BOX
	HRROI T2,[ASCIZ ".RLINE;-2C,2C/0C,2C/0.5C,-0.5C
.RMOVE;-1.0C,0C
.RLINE;0.5C,0.5C
"]
	SETZ T3,
	SOUT
	RET
DNTICK:	SAVEQ
	MOVE Q1,T2		;SAVE INDEX
	HRROI T2,[ASCIZ ".AMOVE;"]
	SETZ T3,
	SOUT
	MOVE T2,TSKPOS(Q1)	;GET POSITION
	ADD T2,TSKWID(Q1)	;MOVE TO OTHER CORNER
	SUBI T2,3		;FUDGE
	MOVEI T3,^D10
	NOUT
	  RET
	HRROI T2,[ASCIZ ".9C,-"]
	SETZ T3,
	SOUT
	HLRZ T2,TSKSKD(Q1)	;GET LEVEL
	IMULI T2,<BOXLEN+^D12>	;CONVERT TO COORDINATE
	ADDI T2,^D8		;BOTTOM OF BOX
	MOVEI T3,^D10		;RADIX
	NOUT
	  RET
	HRROI T2,[ASCIZ ".9C
"]
	MOVEI T3,0
	SOUT
	HRRZ T4,TSKLST(Q1)	;GET POINTER TO TASK BLOCK
	LOAD T3,TKAFD,(T4)	;GET ACTUAL FINISH DATE
	HRROI T2,[ASCIZ ".RMOVE;-0.9C,0.5C
"]
	SKIPN T3		;DONE?
	SOUT			;NO--MOVE TO INNER BOX
	HRROI T2,[ASCIZ ".RLINE;2C,-2C/0C,-2C/0.5C,0.5C
.RMOVE;-1C,0C
.RLINE;0.5C,-0.5C
"]
	SETZ T3,
	SOUT
	RET
;SUBROUTINE TO MOVE OVER TO A BOX
;CALL WITH:
;	T1/ JFN
;	T2/ TSKLST INDEX
;	CALL TOBOX
;	  FAILED
;	OK
;***NOTE: ALL AC'S ARE PRESERVED***
TOBOX:	SAVEQ
	MOVE Q1,T2		;SAVE THE TASK INDEX
	HRROI T2,[ASCIZ/.AMOVE;/]
	SETZ T3,
	SOUT
	MOVE T2,TSKPOS(Q1)	;GET START OF BOX
	ADDI T2,2		;STEP OVER INITIAL SPACES
	MOVEI T3,^D10
	NOUT
	 RET
	HRROI T2,[ASCIZ\.0C,-\]
	SETZ T3,
	SOUT
	HLRZ T2,TSKSKD(Q1)	;GET THE LEVEL #
	IMULI T2,<BOXLEN+^D12>	;GET THE Y COORD
	ADDI T2,1		;STEP OVER THE FIRST LINE
	MOVEI T3,^D10
	NOUT
	 RET
	HRROI T2,[ASCIZ\.4C
\]
	SETZ T3,
	SOUT
	MOVE T2,Q1		;RESTORE T2
	RETSKP
;ROUTINE TO LIST ALL TASKS

LSTTSK:	HLRZ T1,1(P1)		;GET TYPE CODE
	CHKTYP (OFI)
	HRRZ T1,1(P1)		;GET POINTER TO JFN
	MOVE Q1,ANSWER(T1)	;GET JFN
	MOVE T1,Q1		;OPEN THE JFN
	MOVE T2,[070000,,OF%WR]
	OPENF
	 JSP ERROR
	HLRZ T1,(P1)		;GET TYPE CODE
	CHKTYP (KEY)
	HRRZ Q2,(P1)		;GET DISPATCH ADDRESS
	CALL SCHCHK		;UPDATE ESTIMATED DATES IF NEDED
	MOVE T1,Q1		;GET THE JFN
	CALL (Q2)		;GO LIST
	HRRZ T1,Q1		;GET THE JFN AGAIN
	CLOSF			;CLOSE IT
	 JFCL
	JRST LEVEL0		;DONE


;ROUTINE TO LIST TASKS SORTED BY PROJECT
;ACCEPTS IN T1/	JFN

LSTTKP:	SAVEQ
	MOVE Q1,T1		;SAVE THE JFN
	MOVE T2,PRJTBL		;GET ADR OF PROJECT TABLE
	HLRZ T3,0(T2)		;GET LENGTH OF TABLE
	MOVNS T3		;SET UP AN AOBJN POINTER
	JUMPE T3,LSTTP2		;IF NONE, THEN DONE
	HRLZ Q2,T3
	HRRI Q2,1(T2)		;GET ADR OF FIRST ENTRY IN TABLE
LSTTP1:	MOVE T1,Q1		;GET JFN
	HRRZ T2,0(Q2)		;GET ADR OF NEXT PROJECT BLOCK
	CALL TYPPRJ		;GO OUTPUT THIS PROJECT
	AOBJN Q2,LSTTP1		;LOOP BACK FOR ALL PROJECTS
LSTTP2:	RET
;ROUTINE TO PRINT ALL TASKS SORTED BY START DATES
;ACCEPTS IN T1/	JFN

LSTTKE:	TDZA T2,T2		;EARLIEST START DATE
LSTTKL:	MOVEI T2,1		;LATEST START DATE
	SAVEQ
	MOVE Q1,T1		;SAVE THE JFN
	MOVE Q3,T2		;SAVE FLAG
	CALL PRITKH		;PRINT THE HEADER
	MOVE Q2,TSKPTR		;SET UP POINTER TO THE TASK LIST
LSTTS1:	HRRZS TSKLST(Q2)	;CLEAR THE LH OF TASK LIST
	AOBJN Q2,LSTTS1
LSTTS2:	SETZ T4,		;INIT THE INDEX VALUE
	HRLOI T3,377777		;HIGHEST DATE SO FAR
	MOVE Q2,TSKPTR
LSTTS3:	SKIPGE T1,TSKLST(Q2)	;SEE IF THIS ONE HAS NOT BEEN USED
	JRST LSTTS4		;ALREADY PRINTED, GO ON TO NEXT ONE
	XCT [	LOAD T2,TKESD,(T1)
		LOAD T2,TKLSD,(T1)](Q3)
	CAMG T3,T2		;FOUND A NEW LOW?
	JRST LSTTS4		;NO
	MOVE T3,T2		;YES, REMEMBER IT
	MOVE T4,Q2		;AND THE INDEX INTO TSKLST
LSTTS4:	AOBJN Q2,LSTTS3		;LOOP THROUGH THE WHOLE TSKLST
	JUMPE T4,R		;IF NONE FOUND, RETURN
	HRROS TSKLST(T4)	;MARK THAT THIS ONE WAS PRINTED
	MOVE T1,Q1		;GET THE JFN
	HRRZ T2,TSKLST(T4)	;GET THE TASK BLOCK ADDRESS
	CALL PRITSK		;PRINT THE TASK
	JRST LSTTS2		;LOOP BACK FOR THE REST OF THE TASKS
;ROUTINE TO PRINT THE HEADER
;ACCEPTS IN T1/	JFN

PRITKH:	HRROI T2,[ASCIZ/
Task Name         Length   Start    Finish   Developers      Blocking Tasks                   Blocked Tasks

/]
	SETZ T3,
	SOUT
	RET


;ROUTINE TO PRINT A TASK
;ACCEPTS IN T1/	JFN
;	    T2/	TASK BLOCK ADDRESS

PRITSK:	SAVEPQ
	DMOVE Q1,T1		;SAVE THE ARGS
	LOAD T3,TKPRJ,(Q2)	;GET ADR OF PROJECT BLOCK
	LOAD T2,PJNAM,(T3)	;GET ADR OF PROJECT NAME BLOCK
	HRLI T2,(POINT 7,0)
	MOVEI T4,1		;COUNT UP THE LENGTH OF THE NAME
PRITS1:	ILDB T3,T2		;GET NEXT CHAR IN NAME
	SKIPE T3		;FOUND THE END YET?
	AOJA T4,PRITS1		;NO
	LOAD T2,TKNAM,(Q2)	;YES, NOW GET TASK NAME
	HRLI T2,(POINT 7,0)
PRITS5:	ILDB T3,T2		;GET NEXT CHAR
	AOS T4			;COUNT IT
	JUMPN T3,PRITS5
	LOAD T2,TKPRJ,(Q2)	;NOW PRINT THE NAME
	LOAD T2,PJNAM,(T2)
	HRLI T2,(POINT 7,0)
	SETZ T3,
	SOUT			;PROJECT NAME
	MOVEI T2,"/"
	BOUT			; "/"
	LOAD T2,TKNAM,(Q2)
	HRLI T2,(POINT 7,0)
	SOUT			;TASK NAME
	SUBI T4,^D20		;NOW FILL WITH SPACES
	MOVNS T4
	JUMPG T4,PRITS2		;UNLESS TOO LONG
	MOVEI T2,15		;THEN PUT IN A CRLF
	BOUT
	MOVEI T2,12
	BOUT
	;..
	;..
	MOVEI T4,^D19
PRITS2:	MOVEI T2," "		;PAD WITH SPACES
	BOUT
	SOJG T4,PRITS2		;LOOP BACK TILL PADDING IS DONE
	LOAD T2,TKALN,(Q2)	;GET LENGTH
	SKIPN T2		;IF SET YET
	LOAD T2,TKELN,(Q2)	;IF NOT, GET THE ESTIMATED LENGTH
	FIXR T2,T2		;FIX THE NUMBER OF DAYS
	MOVE T3,[NO%LFL!5B17!^D10]
	NOUT
	 JSP ERROR
	MOVEI T2," "
	BOUT
	LOAD T2,TKESD,(Q2)	;GET EARLIEST START DATE
	CALL PRIDAT
	MOVE T1,Q1		;RESTORE JFN
	MOVEI T2," "
	BOUT
	LOAD T2,TKEFD,(Q2)	;GET THE EARLIEST FINISH DATE
	CALL PRIDAT
	MOVE T1,Q1		;RESTORE JFN
	MOVEI T2," "
	BOUT
REPEAT 0,<
	LOAD T2,TKLSD,(Q2)	;GET LATEST START DATE
	CALL PRIDAT
	MOVE T1,Q1
	MOVEI T2," "
	BOUT
	LOAD T2,TKLFD,(Q2)	;GET THE LATEST FINISH DATE
	CALL PRIDAT
	MOVE T1,Q1
	MOVEI T2," "
	BOUT
	LOAD T2,TKLSD,(Q2)	;NOW GET THE SLACK
	LOAD T1,TKESD,(Q2)
	CAMGE T2,T1		;POSITIVE SLACK?
	EXCH T1,T2		;NO
	CALL GETNWD		;GET NUMBER OF WORKING DAYS
	LOAD T2,TKLSD,(Q2)
	LOAD T3,TKESD,(Q2)
	CAMGE T2,T3		;NEGATIVE SLACK?
	MOVNS T1		;YES
	MOVE T2,T1		;PRINT THE SLACK
	MOVE T1,Q1
	MOVE T3,[NO%LFL!4B17!^D10]
	NOUT
	 JSP ERROR
	MOVEI T2," "
	BOUT
>
	;..
	;..
	LOAD P1,TKDVL,(Q2)	;GET POINTER TO DEVELOPER LIST
	LOAD T2,TKPRJ,(Q2)	;GET PROJECT ADR
	SKIPN P1		;ANY DEVELOPERS ON TASK?
	LOAD P1,PJDVL,(T2)	;NO, GET THE PROJECT DEVELOPER LIST
	SKIPN P1		;IS THERE A LIST?
	MOVE P1,DEVTBP		;NO, GET THE OVERALL LIST
	LOAD P2,TKDLP,(Q2)	;GET POINTER TO DEPENDENT LIST
	LOAD P3,TKBLP,(Q2)	;GET POINTER TO BLOCKED LIST
PRITS3:	MOVEI T4,SPACES		;PRINT DEVELOPER NAME IF ANY
	SKIPE P1		;ANY THERE?
	LOAD T4,DVNAM,(P1)	;YES
	HRLI T4,(POINT 7,0)
	MOVEI T3,^D15		;LENGTH OF NAME
PRITS4:	ILDB T2,T4		;GET THE NEXT CHARACTER
	JUMPE T2,PRITS6		;IF NULL, THEN GO PAD WITH SPACES
	BOUT			;OUTPUT THE CHAR
	SOJG T3,PRITS4
PRITS6:	AOS T3			;PUT A SPACE AT THE END
	MOVEI T2," "
	BOUT
	SOJG T3,.-1		;PAD WITH SPACES
	SKIPE T2,P2		;GET BLOCKING TASK (IF ANY)
	LOAD T2,DPBTK,(P2)
	CALL PRITNM		;GO PRINT THE NAME
	SKIPE T2,P3		;GET THE BLOCKED TASK (IF ANY)
	LOAD T2,DPTKP,(P3)
	CALL PRITNM
	HRROI T2,[ASCIZ/
/]
	SETZ T3,
	SOUT
	SKIPE P1		;STEP TO NEXT DEVELOPER
	LOAD P1,DVLNK,(P1)
	SKIPE P2		;STEP TO NEXT BLOCKING TASK
	LOAD P2,DPDLP,(P2)
	SKIPE P3		;STEP TO NEXT BLOCKED TASK
	LOAD P3,DPBLP,(P3)
	MOVE T2,P1		;SEE IF THERE IS MORE TO BE DONE
	IOR T2,P2
	IOR T2,P3
	JUMPE T2,R		;IF NO MORE, THEN EXIT
	HRROI T2,SPACES
	MOVNI T3,^D45		;SPACE OUT TO DEVELOPER LIST
	SOUT
	JRST PRITS3		;LOOP BACK TIL LIST IS DONE
;OUTPUT SCHEDULE

LSTSKD:	HLRZ T1,(P1)		;GET TYPE CODE
	CHKTYP (OFI)		;MUST BE OUTPUT FILE
	HRRZ T1,(P1)		;ADDRESS OF JFN
	MOVE Q1,ANSWER(T1)	;GET THE JFN
	MOVE T1,Q1		;COPY JFN
	MOVX T2,7B5+OF%WR	;ASCII OUTPUT
	OPENF
	  WARN (<JRST LEVEL0>,<CAN NOT OPEN OUTPUT FILE>)
	SETZM LINCNT		;ZERO OUT LINE COUNTER
	CALL SCHCHK		;UPDATE ESTIMATED DATES IF NEDED
	MOVE T1,TSKPTR		;POINTER TO TASK LIST
	HRRZS TSKLST(T1)	;CLEAR FLAG
	AOBJN T1,.-1		;IN ALL ENTRIES
LSSKD1:	SETZ T4,		;INIT INDEX
	HRLOI T3,377777		;HIGHEST DATE SEEN
	MOVE Q2,TSKPTR		;POINTER TO TASK LIST
LSSKD2:	SKIPG T1,TSKLST(Q2)	;HAVE WE USED THIS ENTRY YET?
	JRST LSSKD3		;YES.
	LOAD T2,TKESD,(T1)	;NO--GET START DATE
	CAMG T3,T2		;FOUND A NEW LOW?
	JRST LSSKD3		;NO--SKIP IT
	MOVE T3,T2		;COPY DATE
	MOVE T4,Q2		;COPY INDEX
LSSKD3:	AOBJN Q2,LSSKD2		;LOOP OVER ALL TASKS
	JUMPE T4,LSSKD4		;NONE FOUND--DONE
	HRROS TSKLST(T4)	;MARK THAT THIS ONE WAS PRINTED
	MOVE T1,Q1		;COPY JFN
	HRRZ T2,TSKLST(T4)	;GET TASK BLOCK ADDRESS
	LOAD T3,TKEFD,(T2)	;GET COMPLETION DATE
	CAMLE T3,SKDTAD		;MUST BE IN THE FUTURE
	CALL PRISCH		;PRINT THE SCHEDULE
	MOVE T3,LINCNT		;GET THE LINE COUNTER
	CAIGE T3,^D50		;TOO MANY?
	JRST LSSKD1		;PRINT ALL TASKS
	MOVE T1,Q1		;GET THE JFN
	MOVEI T2,"L"-100	;FORM FEED
	BOUT			;SKIP TO NEW PAGE
	SETZM LINCNT		;RESET COUNTER
	JRST LSSKD1		;LOOP BACK FOR ALL TASKS

LSSKD4:	MOVE T1,TSKPTR		;GET TASK POINTER
	HRRZS TSKLST(T1)	;CLEAR FLAG
	AOBJN T1,.-1
	MOVE T1,Q1
	CLOSF
	  WARN (<JRST LEVEL0>,<CAN NOT CLOSE REPORT FILE>)
	JRST LEVEL0
;SUBROUTINE TO PRINT TASKS IS CALENDAR ORDER
;	T1/ JFN
;	T2/ TASK BLOCK
;
PRISCH:	SAVEP
	DMOVE P1,T1		;COPY ARGUMENTS
	LOAD T2,TKESD,(T2)	;GET START DATE
	CALL PRIDAT		;PRINT IT
	TYPE P1,< TO >
	MOVE T1,P1		;COPY JFN
	LOAD T2,TKEFD,(P2)	;GET END DATE
	CALL PRIDAT
	TYPE P1,<	>
	DMOVE T1,P1		;PUT ARGUMENTS BACK
	CALL PRITNM		;PRINT TASK NAME
	TYPE P1,<&	PROJECT DESCRIPTION:&>
	MOVE T1,P1		;COPY JFN
	LOAD T2,TKPRJ,(P2)	;GET PROJECT BLOCK ADDRESS
	LOAD T2,PJDSC,(T2)	;GET PROJECT DESCRIPTION
	CALL TYPDSC		;TYPE THE DESCRIPTION
	TYPE T1,<&	TASK DESCRIPTION:&>
	LOAD T2,TKDSC,(P2)	;ADDRESS OF STRING
	CALL TYPDSC		;PRINT IT
	TYPE P1,<&&>		;ADD SOME WHITE SPACE
	MOVEI T1,6		;PRINTED 6 LINES
	ADDM T1,LINCNT		;COUNT IT
	RET
;SUBROUTINE TO TYPE A TASK/PRODUCT DESCRIPTION
;CALL WITH:
;	T1/ JFN
;	T2/ STRING ADDRESS
;	CALL TYPDSC
;
TYPDSC:	STKVAR	<STRPTR>
	HRLI T2,(POINT 7,0)	;MAKE BYTE POINTER
	MOVEM T2,STRPTR		;BYTE POINTER TO STRING
TYDSC0:	ILDB T2,STRPTR		;GET A BYTE
	JUMPE T2,R		;STOP ON NULL
	CAIG T2," "		;REAL TEXT?
	JRST TYDSC0		;NO--STRIP IT OFF
	MOVEI T2,"	"	;PRINT A TAB
	BOUT
	LDB T2,STRPTR		;PRINT TEXT
	BOUT
TYDSC1:	ILDB T2,STRPTR		;GET THE NEXT BYTE
	JUMPE T2,TYDSC4		;ADD CRLF AND QUIT ON NULL
	CAIGE T2," "		;REAL CHARACTER
	JRST TYDSC3		;NO--SPECIAL HACK
TYDSC2:	BOUT			;TYPE IT
	JRST TYDSC1		;LOOP BACK FOR MORE

TYDSC3:	TYPE T1,<&>		;ADD CRLF
	AOS LINCNT		;COUNT LINES
	JRST TYDSC0		;STRIP JUNK

TYDSC4:	TYPE T1,<&>		;ADD CRLF
	AOS LINCNT		;COUNT LINES
	RET			;AND RETURN
;ROUTINE TO PRINT A TASK NAME
;ACCEPTS IN T1/	JFN
;	    T2/	0 OR POINTER TO TASK BLOCK

PRITNM:	ASUBR <PRITNJ,PRITNT>
	JUMPE T2,PRITN1		;IF 0, PRINT BLANKS
	LOAD T4,TKPRJ,(T2)	;GET POINTER TO PROJECT
	LOAD T4,PJNAM,(T4)	;GET POINTER TO PROJECT NAME
	HRLI T4,(POINT 7,0)
	MOVEI T3,^D32
PRITN2:	ILDB T2,T4		;GET THE NEXT CHAR
	JUMPE T2,PRITN3		;IF DONE, GO PAD WITH SPACES
	BOUT			;OUTPUT THE NEXT CHAR
	SOJG T3,PRITN2		;LOOP BACK TIL DONE
	JRST PRITN5		;GO ADD FINAL SPACE

PRITN3:	MOVEI T2,"/"		;SLASH BETWEEN PROJECT AND TASK
	BOUT
	SOJLE T3,PRITN5		;COUNT DOWN CHAR COUNT
	MOVE T4,PRITNT		;GET TASK BLOCK ADR AGAIN
	LOAD T4,TKNAM,(T4)	;GET POINTER TO TASK NAME
	HRLI T4,(POINT 7,0)
PRITN4:	ILDB T2,T4		;GET NEXT CHAR OF TASK NAME
	JUMPE T2,PRITN5		;IF DONE, GO PAD WITH SPACES
	BOUT
	SOJG T3,PRITN4		;LOOP BACK THRU NAME
PRITN5:	MOVEI T2," "		;OUTPUT SPACES
	BOUT
	SOJGE T3,PRITN5
	RET

PRITN1:	HRROI T2,SPACES		;PRINT SPACES
	MOVNI T3,^D33
	SOUT
	RET
;ROUTINE TO PRINT OUT A DATE
;ACCEPTS IN T1/	JFN OR STRING POINTER
;	    T2/	DATE  (GMT ADJUSTED TIME)

PRIDAT:	STKVAR <PRIDTJ>
	JUMPE T2,PRIDT1		;IF NO DATE, SAY "UNKNOWN"
	MOVEM T1,PRIDTJ		;SAVE THE JFN
	MOVX T4,IC%UTZ		;DONT PRINT THE TIME
	ODCNV			;NORMALIZE THE DATE
	SETZ T4,
	IDCNV
	 JSP ERROR
	MOVE T1,PRIDTJ		;GET BACK THE JFN
	MOVE T3,[OT%NTM]
	ODTIM
	RET

PRIDT1:	HRROI T2,[ASCIZ/ UNKNOWN /]
	SETZ T3,
	SOUT
	RET
;ROUTINE TO STORE A BOX IN THE OUTPUT TABLES
;ACCEPTS IN T1/	INDEX INTO TSKLST
;	    T2/	COL #
;	    T3/	ROW #
;	    T4/	DATE
;	CALL STOBOX
;RETURNS +1:	ALWAYS, T1/	MAX COL USED
;			T2/	MAX ROW USED

PBXWID:	SAVEPQ
	SETO P1,		;NO BOX CHAR
	JRST PBXWD1

BOXWID:	SAVEPQ
	SETZ P1,		;PRINT THE BOX
PBXWD1:	MOVEI P5,1		;ONLY WANT THE WIDTH OF THE BOX
	SETZB T2,T3		;INIT OTHER PARAMETERS
	SETZ T4,
	JRST STOBX0

PSTOBX:	SAVEPQ
	SETO P1,		;NO BOX CHAR
	JRST PSTOB1

STOBOX:	SAVEPQ
	SETZ P1,		;DO BOX CHARS
PSTOB1:	MOVEI P5,0		;STORE THE BOX
STOBX0:	STKVAR <STOBXC,STOBXA,STOBXI,<STOBXP,MAXLNW>,<STOBXL,MAXLNW>,<STOBXT,MAXLNW>,<STOBXD,MAXLNW>,<STOBXB,MAXLNW>,<STOBXS,MAXLNW>,<STOBXN,200>,STOBXF,STOBXV,STOBXQ>
	MOVEM T4,STOBXQ		;SAVE THE DATE
	MOVEM P1,STOBXF		;SAVE BOX CHAR FLAG
	DMOVE Q2,T2		;SAVE COL AND ROW
	MOVE Q1,TSKLST(T1)	;GET TASK ADR
	LOAD T3,TKFLG,(Q1)	;GET FLAGS
	MOVEI T2,"#"		;GET CRITICAL PATH BOX CHARACTER
	TXNN T3,TK%CP		;IS THIS TASK ON THE CRITICAL PATH?
	MOVEI T2,"%"		;NO, USE A DIFERENT CHAR
	LOAD T3,TKAFD,(Q1)	;GET ACTUAL FINISH DATE
	JUMPE T3,BOXWD0		;IF NOT SET, THEN NOT DONE
	CAML T4,TSKFDL(T1)	;IS PROJECT ALREADY DONE?
	CAMLE T3,T4		;ALREADY PAST COMPLETION DATE?
	SKIPA			;NO, NOT COMPLETE
	MOVEI T2,"*"		;YES, USE DIFFERENT CHAR
BOXWD0:	SKIPE STOBXF		;PLOTTING?
	MOVEI T2,"\"		;DO NOT PUT OUT BOX CHARS
	LOAD T3,TKFLG,(Q1)	;GET FLAGS AGAIN
	TXNE T3,TK%CP		;ON CRITICAL PATH?
	SKIPN STOBXF		;AND DRAWING BOXES?
	SKIPA			;NO
	MOVEI T2,"+"		;YES, GET CRITICAL PATH CHARACTER
	MOVEM T2,STOBXA		;SAVE BOX CHAR
	MOVEM T1,STOBXI		;SAVE INDEX
	CALL CHKDAT		;SEE IF THIS IS A RESONABLE DATE
	 JRST BOXWD7		;YES
	MOVEI T1,"?"		;NO, MARK THE BOX A QUESTIONABLE
	LOAD T3,TKAFD,(Q1)	;GET ACTUAL FINISH DATE
	JUMPE T3,BOXWD6		;NOT DONE, SET "?"
	MOVE T2,STOBXI		;GET INDEX
	MOVE T4,STOBXQ		;GET DATE
	CAML T4,TSKFDL(T2)	;ALREADY DONE?
	CAMLE T3,T4		;AND PAST COMPLETION DATE
BOXWD6:	MOVEM T1,STOBXA		;STORE THE NEW CHARACTER
BOXWD7:	MOVEI T1,BOXLEN		;MINIMUM BOX SIZE
	MOVEM T1,STOBXC
	LOAD T1,TKPRJ,(Q1)	;GET PROJECT BLOCK
	LOAD T1,PJNAM,(T1)	;GET ADR OF PROJ NAME
	MOVEI T2,STOBXP		;COPY NAME TO STRING AREA
	CALL BLDBNM
	CAMLE T1,STOBXC		;NEW COL MAX?
	MOVEM T1,STOBXC		;YES
	LOAD T1,TKNAM,(Q1)	;COPY TASK NAME STRING
	MOVEI T2,STOBXT
	CALL BLDBNM
	CAMLE T1,STOBXC		;NEW MAX COL?
	MOVEM T1,STOBXC		;YES
	MOVE T1,Q1		;GET TASK ADR
	MOVEI T2,STOBXD
	CALL BLDBDT		;BUILD THE DEPENDENCY LIST
	SKIPE STOBXF		;PLOTTING
	SETZB T1,STOBXD		;YES, NO DEPENDENCY LINE
	CAMLE T1,STOBXC		;NEW MAX COL?
	MOVEM T1,STOBXC		;YES
	MOVE T1,Q1		;NOW BUILD THE BLOCKED TASK LIST
	MOVEI T2,STOBXB
	CALL BLDBBT
	SKIPE STOBXF		;PLOTTING?
	SETZB T1,STOBXB		;YES, NO DEPENDENCY LINE
	CAMLE T1,STOBXC		;NEW MAX COL?
	MOVEM T1,STOBXC		;YES
	MOVE T1,Q1		;GET TASK ADR
	HRROI T2,STOBXN		;GET STRING ADR FOR NAMES
	CALL BLDNST		;BUILD THE NAME STRING
	CAMLE T1,STOBXC		;NEW MAXIMUM?
	MOVEM T1,STOBXC		;YES
	MOVE T1,Q1		;GET THE TASK ADR
	CALL GETPRF		;GET THE PREFERENCE VALUE
	MOVEM T1,STOBXV		;SAVE THE PREFERENCE VALUE
	HRROI T1,STOBXL		;GET THE LENGTH OF THE TASK
	SKIPE STOBXF		;PLOTTING?
	JRST BOXWD2		;YES, DONT PUT IN TASK NUMBER
	MOVE T2,STOBXI		;GET INDEX OF TASK
	MOVEI T3,^D10		;OUTPUT IT
	NOUT
	 JSP ERROR
	MOVEI T2," "		;END WITH A SPACE
	BOUT
BOXWD2:	LOAD T2,TKALN,(Q1)	;GET THE ACTUAL LENGTH
	SKIPN T2		;SET?
	LOAD T2,TKELN,(Q1)	;NO, USE THE ESTIMATED LENGTH
	SETZ T3,
	FLOUT
	 JSP ERROR
	MOVEI T2,"d"		;END WITH "D" FOR DAYS
	IDPB T2,T1
	SKIPN STOBXV		;IS THERE A PREFERENCE VALUE SET?
	JRST BOXWD5		;NO
	HRROI T2,[ASCIZ/ PV=/]
	SETZ T3,
	SOUT
	MOVE T2,STOBXV		;GET THE PREFERENCE VALUE
	SETZ T3,
	FLOUT			;OUTPUT THE PREFERENCE VALUE
	 JSP ERROR
BOXWD5:	LOAD T4,TKPL,(Q1)	;GET POINTER TO PATH LIST
	JUMPE T4,BOXWD3		;IF ANY
	HRLI T4,(POINT 7,0)
	ILDB T3,T4		;IS THERE ANY LIST?
	JUMPE T3,BOXWD3		;...
	HRROI T2,[ASCIZ/ CP=/]
	SETZ T3,
	SOUT
	LOAD T2,TKPL,(Q1)	;GET PATH LIST
	HRLI T2,(POINT 7,0)
	SOUT
BOXWD3:	LOAD T3,TKSLK,(Q1)	;GET THE SLACK
	CAMN T3,[NOSLAK]	;ANY SET?
	JRST BOXWD4		;NO
	HRROI T2,[ASCIZ/ SLK=/]
	SETZ T3,
	SOUT
	LOAD T2,TKSLK,(Q1)	;GET SLACK AGAIN
	MOVEI T3,^D10
	NOUT			;OUTPUT IT AS DECIMAL NUMBER
	 JSP ERROR
BOXWD4:	MOVEI T2,0		;END WITH A NUL
	IDPB T2,T1
	HRROI T1,STOBXL		;GET LENGTH OF STRING
	CALL GETCHC
	CAMLE T1,STOBXC		;NEW MAX?
	MOVEM T1,STOBXC		;YES, REMEMBER IT
	JUMPN P5,BOXWD1		;NOW HAVE WIDTH IF THATS ALL THAT IS WANTED
	MOVEI T1,STOBXD		;NOW START THE BOX
	HRLZ T2,Q2		;COL NUMBER
	HRRI T2,0(Q3)		;ROW
	MOVE T3,STOBXC		;BOX WIDTH
	MOVE T4,STOBXA		;BOX CHAR
	CALL STOBX1		;OUTPUT THE DEPENDENCY LINE
	HRLZ T2,Q2		;COL
	HRRI T2,1(Q3)		;ROW
	MOVE T3,STOBXC		;WIDTH
	MOVE T4,STOBXA		;BOX CHAR
	CALL STOBX2		;PRINT TOP OF BOX
	MOVEI T1,STOBXL		;OUTPUT THE TASK NUMBER
	HRLZ T2,Q2		;COL
	HRRI T2,2(Q3)		;ROW
	MOVE T3,STOBXC		;WIDTH
	MOVE T4,STOBXA		;BOX CHAR
	CALL STOBX3
	MOVEI T1,STOBXP		;PROJECT NAME
	HRLZ T2,Q2		;COL
	HRRI T2,3(Q3)		;ROW
	MOVE T3,STOBXC		;WIDTH
	MOVE T4,STOBXA		;BOX CHAR
	CALL STOBX3
	MOVEI T1,STOBXT		;TASK NAME
	HRLZ T2,Q2
	HRRI T2,4(Q3)
	MOVE T3,STOBXC
	MOVE T4,STOBXA
	CALL STOBX3
	MOVE T1,STOBXI		;GET START DATE
	MOVE T2,TSKSDL(T1)
	HRROI T1,STOBXS
	CALL PRIDAT		;GET DATE INTO STOBXS
	MOVEI T1,STOBXS		;STORE START DATE IN BOX
	HRLZ T2,Q2		;COL
	HRRI T2,5(Q3)		;ROW
	MOVE T4,STOBXA		;BOX CHAR
	LOAD T3,TKASD,(Q1)	;HAS THIS TASK STARTED YET?
	SKIPE T3
	HRLI T4,"*"		;YES, FLAG IT
	MOVE T3,STOBXC		;WIDTH
	CALL STOBX3
	MOVE T1,STOBXI		;GET FINISH DATE
	MOVE T2,TSKFDL(T1)
	HRROI T1,STOBXS
	CALL PRIDAT
	MOVEI T1,STOBXS		;OUTPUT FINISH DATE
	HRLZ T2,Q2
	HRRI T2,6(Q3)
	MOVE T3,STOBXC
	MOVE T4,STOBXA
	CALL STOBX3
	MOVEI T1,STOBXN		;PRINT THE NAMES
	HRLZ T2,Q2		;COL
	HRRI T2,7(Q3)		;ROW
	MOVE T3,STOBXC
	MOVE T4,STOBXA
	CALL STOBX3
	HRLZ T2,Q2		;NOW DO CLOSING BOX LINE
	HRRI T2,10(Q3)
	MOVE T3,STOBXC
	MOVE T4,STOBXA
	CALL STOBX2		;OUTPUT BOX LINE
	MOVEI T1,STOBXB		;GET LIST OF BLOCKED TASKS
	HRLZ T2,Q2
	HRRI T2,11(Q3)
	MOVE T3,STOBXC
	MOVE T4,STOBXA
	CALL STOBX1		;OUTPUT BLOCKED TASKS
BOXWD1:	MOVE T1,Q2		;GET MAX COL USED
	ADD T1,STOBXC		;ADD IN THE WIDTH
	ADDI T1,8		;PLUS THE OVERHEAD
	MOVE T2,Q3		;GET THE ROW
	ADDI T2,BOXLEN-1	;PLUS THE LENGTH OF A BOX
	RET
;ROUTINE TO STORE THE DEPENDENCY LINE
;ACCEPTS IN T1/	STRING ADR
;	    T2/	COL,,ROW
;	    T3/	WIDTH
;	    T4/ BOX CHAR

STOBX1:	SAVEQ
	STKVAR <<STOB1S,MAXLNW>>
	TRUNC T3,MAXLEN,DEPENDENCY,STOBX1
	HRLI T1,(POINT 7,0)
	DMOVE Q2,T2		;SAVE ARGS
	MOVEI T2,STOB1S		;GET POINTER TO SCRATCH STRING
	HRLI T2,(POINT 7,0)
	MOVEI T3," "
	IDPB T3,T2		;SPACE
	IDPB T3,T2		;SPACE
	IDPB T3,T2		;SPACE
	IDPB T3,T2		;SPACE
STOB11:	ILDB T4,T1		;GET NEXT CHAR
	JUMPE T4,STOB12		;NULL?
	IDPB T4,T2		;NO, STORE IT
	SOJG Q3,STOB11		;LOOP BACK FOR THE REST OF THE CHARS
STOB12:	IDPB T3,T2		;END WITH SPACES
	SOJGE Q3,STOB12
	IDPB T3,T2
	IDPB T3,T2
	IDPB T3,T2
	SETZ T3,
	IDPB T3,T2
	HLRZ T1,Q2		;GET COL
	HRRZ T2,Q2		;AND ROW
	HRROI T3,STOB1S		;AND STRING POINTER
	CALL STOSTR
	RET			;DONE
;ROUTINE TO STORE THE BOX LINE
;ACCEPTS IN T2/	COL,,ROW
;	    T3/	WIDTH
;	    T4/	BOX CHAR

STOBX2:	SAVEQ
	TRUNC T3,MAXLEN,<BOX TEXT>,STOBX2
	DMOVE Q2,T2		;SAVE THE ARGS
	STKVAR <<STOB2S,MAXLNW>>
	MOVEI T1,STOB2S		;GET ADR OF SCRATCH STRING
	HRLI T1,(POINT 7,0)
	ADDI Q3,4		;FINAL WIDTH
	MOVEI T2," "
	IDPB T2,T1
	IDPB T2,T1
STOB21:	IDPB T4,T1		;STORE BOX CHAR
	SOJG Q3,STOB21		;FOR FULL WIDTH
	IDPB T2,T1		;SPACE
	IDPB T2,T1		;SPACE
	SETZ T2,
	IDPB T2,T1		;NULL
	HLRZ T1,Q2		;COL
	HRRZ T2,Q2		;ROW
	HRROI T3,STOB2S		;STRING
	CALL STOSTR
	RET			;DONE
;ROUTINE TO OUTPUT AN INNER LINE OF THE BOX
;ACCEPTS IN T1/	STRING ADDRESS
;	    T2/	COL,,ROW
;	    T3/	WIDTH
;	    T4/	FLAG CHAR ,, BOX CHAR

STOBX3:	SAVEP
	STKVAR <<STOB3S,MAXLNW>>
	TRUNC T3,MAXLEN,<INNER BOX LINE>,STOBX3
	HRLI T1,(POINT 7,0)
	MOVE P1,T1		;SAVE BYTE POINTER
	HLRZ P2,T2		;GET COL
	HRRZ P3,T2		;GET ROW
	DMOVE P4,T3		;GET WIDTH AND BOX CHAR
	MOVEI T1,STOB3S		;BUILD THE FULL STRING
	HRLI T1,(POINT 7,0)
	MOVEI T2," "
	IDPB T2,T1		;  * STRING *  
	IDPB T2,T1
	IDPB P5,T1
	HLRZ T2,P5		;GET FLAG CHARACTER
	SKIPN T2		;ANY THERE
	MOVEI T2," "		;NO, USE A SPACE
	IDPB T2,T1
	MOVEI T2," "		;FINISH WITH SPACES
STOB31:	ILDB T3,P1		;NOW OUTPUT THE STRING
	JUMPE T3,STOB32		;NULL?
	IDPB T3,T1		;NO, STOR THE CHAR
	SOJG P4,STOB31		;LOOP BACK TIL STRING DONE
STOB32:	IDPB T2,T1		;FOLLOWED BY A SPACE
	SOJGE P4,STOB32		;PAD WITH SPACES
	IDPB P5,T1		;END OF BOX
	IDPB T2,T1		;SPACE
	IDPB T2,T1		;SPACE
	SETZ T2,
	IDPB T2,T1		;NULL
	MOVE T1,P2		;COL
	MOVE T2,P3		;ROW
	HRROI T3,STOB3S		;STRING
	CALL STOSTR		;STORE THE STRING
	RET			;DONE



;ROUTINE TO COUNT CHARACTERS IN A STRING

;ACCEPTS IN T1/	STRING POINTER

GETCHC:	TLC T1,-1		;STRING POINTER?
	TLCN T1,-1
	HRLI T1,(POINT 7,0)
	SETZ T4,		;INIT COUNT
GETCH1:	ILDB T2,T1		;GET NEXT CHAR
	SKIPE T2
	AOJA T4,GETCH1		;COUNT UP THE CHAR
	MOVE T1,T4		;RETURN THE ANSWER
	RET
;ROUTINE TO BUILD A BOX NAME LINE
;ACCEPTS IN T1/	NAME STRING ADR
;	    T2/	ADR OF DESTINATION STRING
;RETURNS +1:	ALWAYS,	T1/	LENGTH OF STRING

BLDBNM:	HRLI T2,(POINT 7,0)	;SET UP DESTINATION BYTE POINTER
	HRLI T1,(POINT 7,0)	;SET UP SOURCE BYTE POINTER
	SETZ T4,		;INIT CHAR COUNT
BLDBN1:	ILDB T3,T1		;GET NEXT CHAR
	IDPB T3,T2		;PUT IN THE OUTPUT STRING
	TRUNC T4,MAXLEN,NAME,BLDBNM,BLDBN2
	SKIPE T3		;NULL?
	AOJA T4,BLDBN1		;NO, LOOP BACK
BLDBN2:	MOVE T1,T4		;GET CHAR COUNT
	RET			;DONE


;ROUTINE TO BUILD A LIST OF NAMES
;ACCEPTS IN T1/	TASK ADR
;	    T2/	STRING POINTER
;RETURNS +1:	T1/	NUMBER OF CHARS IN STRING

BLDNST:	SAVEPQ
	STKVAR <BLDNSP>
	TLC T2,-1		;GET A BYTE POINTER
	TLCN T2,-1
	HRLI T2,(POINT 7,0)
	DMOVE P1,T1		;SAVE THE ARGS
	SETZ T3,		;STORE A NULL AT END OF STRING
	IDPB T3,T2		;IN CASE WE EXIT EARLY
	MOVEM P2,BLDNSP		;SAVE THE INITIAL STRING POINTER
	SETZM (T2)		;INIT FIRST WORD TO 0
	HRLI T2,(POINT 7,0)	;SET UP STRING POINTER
	MOVE Q1,T1		;SAVE TASK ADR
	HLRZ Q2,DEVTAB		;BUILD POINTER TO DEVTAB
	MOVNS Q2
	HRLZS Q2
	SETO Q3,		;INIT THE CHAR COUNT
BLDNS1:	HRRZ P3,DEVTAB+1(Q2)	;GET NEXT DEVELOPER LIST
	JUMPE P3,BLDNS4		;IF NONE, SKIP IT
	SETZ Q1,		;INIT DAY COUNT
BLDNS2:	LOAD T1,SCHTK,(P3)	;GET TASK ADR
	CAME T1,P1		;FOUND A MATCH?
	JRST BLDNS3		;NO
	LOAD T1,SCHSD,(P3)	;GET THE START DATE
	LOAD T2,SCHFD,(P3)	;GET THE END DATE
	CALL GETNWD		;GET NUMBER OF WORKING DAYS
	LOAD T2,SCHRT,(P3)	;GET THE RATE
	FLTR T1,T1		;GET DAYS
	FMPR T1,T2		;GET THE NUMBER OF DAYS SPENT
	FADR Q1,T1		;ADD IT TO THE TOTAL
BLDNS3:	LOAD P3,SCHLN,(P3)	;STEP TO THE NEXT TASK IN LIST
	JUMPN P3,BLDNS2		;LOOP BACK TIL DONE
	JUMPE Q1,BLDNS4		;IF NO DAYS, SKIP THIS TASK
	MOVEI T1,","		;ADD A COMMA TO NAME
	AOSE Q3			;UNLESS THIS IS THE FIRST TIME
	IDPB T1,P2		;STORE THE COMMA
	HLRZ T1,DEVTAB+1(Q2)	;GET POINTER TO NAME STRING
	HRLI T1,(POINT 7,0)
BLDNS5:	ILDB T3,T1		;GET NEXT CHAR IN NAME
	JUMPE T3,BLDNS6		;DONE?
	IDPB T3,P2		;NO, STORE THE CHAR
	AOJA Q3,BLDNS5		;LOOP BACK TIL DONE
BLDNS6:	MOVEI T2,"("		;NOW PUT IN THE DAYS SPENT
	IDPB T2,P2
	MOVE T1,P2		;GET STRING POINTER
	MOVE T2,Q1		;GET NUMBER OF DAYS
	MOVE T3,[FL%ONE!FL%PNT!FL%OVL]
	MOVEI T4,1		;CALCULATE THE ROUNDING
	CAML T2,[1.0]
	AOS T4
	CAML T2,[10.0]
	AOS T4
	CAML T2,[100.0]
	AOS T4
	CAML T2,[1000.0]
	AOS T4
	CAML T2,[10000.0]
	AOS T4
	CAML T2,[100000.0]
	AOS T4
	HRLZS T4
	TDO T3,T4		;SET WHERE TO ROUND AT
	FLOUT			;OUTPUT IT
	 MOVE T1,P2
	MOVE P2,T1		;PUT BACK THE STRING POINTER
	MOVEI T2,")"
	IDPB T2,P2		;CLOSE OUT THE DAYS
	MOVEI T3,0		;END WITH A NULL
	MOVE T4,P2
	IDPB T3,T4
BLDNS4:	MOVE T1,BLDNSP		;GET STRING POINTER
	CALL CNTSTC		;COUNT THE CHARACTERS IN THE STRING
	TRUNC T1,MAXLEN,<DEVELOPER LIST>,BLDNST,R
	AOBJN Q2,BLDNS1		;STEP TO NEXT DEVELOPER IN DEVTAB
	RET
;ROUTINE TO BUILD THE DEPENDENCY LIST
;ACCEPTS IN T1/	TASK ADR
;	    T2/	STRING ADR FOR OUTPUT
;RETURNS +1:	ALWAYS, T1/	LENGTH OF STRING

BLDBBT:	TDZA T4,T4		;BUILD BLOCKED LIST
BLDBDT:	MOVEI T4,1		;BUILD BLOCKING LIST
	SAVEPQ
	MOVE P1,T4		;SAVE THE INDEX
	HRLI T2,(POINT 7,0)	;SET UP THE DESTINATION BYTE POINTER
	MOVE Q2,T2		;SAVE THE BYTE POINTER
	MOVE Q3,Q2		;SAVE A COPY OF THE ORIGINAL BYTE PNTR
	XCT [	LOAD Q1,TKBLP,(T1)
		LOAD Q1,TKDLP,(T1)](P1)
	JUMPE Q1,BLDBD2		;IF NO DEPENDENCY LIST, THEN DONE
BLDBD1:	XCT [	LOAD T1,DPTKP,(Q1)
		LOAD T1,DPBTK,(Q1)](P1)
	LOAD T1,TKTKI,(T1)	;GET TSKLST INDEX
	MOVE T2,T1		;NOW ADD THIS NUMBER TO THE LIST
	MOVE T1,Q2		;GET THE STRING POITER
	MOVEI T3,^D10		;DECIMAL NUMBER
	NOUT
	 JSP ERROR
	MOVE Q2,T1		;SAVE THE UPDATED STRING POINTER
	XCT [	LOAD Q1,DPBLP,(Q1)
		LOAD Q1,DPDLP,(Q1)](P1)
	JUMPE Q1,BLDBD2		;ANY MORE TASKS ON LIST?
	MOVEI T1,","		;YES, PUT A COMMA BETWEEN NUMBERS
	IDPB T1,Q2
	MOVEI T1," "		;AND A SPACE
	IDPB T1,Q2
	JRST BLDBD1		;LOOP BACK FOR REST OF TASKS ON LIST

BLDBD2:	SETZ T1,		;COUNT UP THE CHARACTERS
BLDBD3:	CAMN Q2,Q3		;REACHED THE END OF THE STRING?
	JRST BLDBD4		;YES
	IBP Q3			;STEP TO NEXT CHAR
	AOJA T1,BLDBD3		;LOOP BACK TILL END IS FOUND

BLDBD4:	MOVEI T2,0		;END WITH A NULL
	IDPB T2,Q2
	RET			;DONE
;ROUTINE TO CHECK FOR A QUESTIONABLE TASK
;ACCEPTS IN T1/	TASK INDEX
;RETURNS +1:	DATE IS OK
;	 +2:	DATE IS QUESTIONABLE

CHKDAT:	SAVEQ
	HRRZ Q1,TSKLST(T1)	;GET THE ADR OF THE TASK BLOCK
	LOAD Q3,TKXSD,(Q1)	;GET THE START DATE OF THIS TASK
	LOAD T1,TKESD,(Q1)	;GET EARLIEST START DATE
	CAMGE Q3,T1		;SEE WHICH IS LATER
	MOVE Q3,T1
	LOAD T1,TKASD,(Q1)	;GET ACTUAL START
	SKIPE T1		;SET YET?
	MOVE Q3,T1		;YES, USE IT
	LOAD Q2,TKDLP,(Q1)	;GET POINTER TO BLOCKING LIST
	JUMPE Q2,R		;IF NONE, THEN DONE
CHKDA1:	LOAD T1,DPBTK,(Q2)	;GET THE BLOCKING TASK
	LOAD T2,TKXCD,(T1)	;SEE WHEN IT FINISHES
	LOAD T3,TKLFD,(T1)	;GET LATEST FINISH DATE
	CAMGE T2,T3		;GET THE LATEST
	MOVE T2,T3
	LOAD T3,TKAFD,(T1)	;GET THE ACTUAL FINISH DATE
	SKIPE T3		;IF ANY
	MOVE T2,T3
	CAMLE T2,Q3		;IS THERE AN OVERLAP?
	RETSKP			;YES, QUESTINABLE DATE
	LOAD Q2,DPDLP,(Q2)	;STEP TO NEXT TASK IN THE LIST
	JUMPN Q2,CHKDA1		;IF ANY MORE, LOOP BACK
	RET			;IF NOT, THEN DONE
;ROUTINE TO SORT THE AVLTSK LIST BY FINISH DATE

BLDSPA:	SAVEQ
	MOVN Q1,AVLCNT		;SET UP AOBJN POINTER
	HRLZS Q1
	SETZ Q2,		;INIT COL NUMBER
	MOVE T1,Q1		;GET AOBJN POINTER
	HRROS AVLTSK(T1)	;INIT THE TABLE
	AOBJN T1,.-1
BLDSP1:	HRLOI T3,377777		;GET THE LARGEST DATE
	MOVE T2,Q1		;GET AOBJN POINTER
BLDSP2:	SKIPL T1,AVLTSK(T2)	;THIS BEEN LOOKED AT YET?
	JRST BLDSP3		;YES
	CAMLE T3,TSKFDL(T1)	;NO, IS THIS A NEW LOW FINISH DATE
	MOVE T3,TSKFDL(T1)	;YES
BLDSP3:	AOBJN T2,BLDSP2		;LOOP BACK FOR ALL TASKS
	CAML T3,[377777,,777777] ;FOUND ANY?
	RET			;NO, THEN ALL DONE
	MOVE T2,Q1		;SET UP POINTER AGAIN
BLDSP4:	SKIPL T1,AVLTSK(T2)	;LOOKED AT THIS ONE YET?
	JRST BLDSP5		;YES, SKIP IT
	CAML T3,TSKFDL(T1)	;FOUND ONE OF THE ONES TO SCHEDULE?
	HRLM Q2,AVLTSK(T2)	;YES, STORE THE ROW OFFSET
BLDSP5:	AOBJN T2,BLDSP4		;LOOP BACK FOR ALL TASKS
	AOJA Q2,BLDSP1		;LOOP BACK TILL ALL TASKS ARE SCHEDULED
;SUBROUTINE TO PLACE PERT BOXES ON THE PERT CHART
;CALL WITH:
;	CALL PLACE
;RETURNS +1 HAVING SET TSKPOS
;
PLACE:	SAVEPQ			;SAVE P AND Q REGS
;AC USAGE
; Q1/ LEVEL NUMBER
; Q2/ FLAG. 0 MEANS FORWARD SCAN, 1 MEANS BACKWARD
; Q3/ HIGHEST LEVEL SEEN IN FORWARD SCAN
; P1/ LOWEST LEVEL SEEN IN REVERSE SCAN
; P3/ FLAG. 0 MEANS ALLOW REORGANIZATION, 1 MEANS DON'T
; P4/ PASS COUNTER
	SETOB Q3,P1		;INIT MAX LEVEL SEEN SO FAR
	SETO P4,		;SET PASS COUNT
PLACE2:	JUMPG P4,PLACE6		;AFTER SEVERAL PASSES, THEN DONE
	MOVEI Q1,0		;GET LEVEL TO START WITH
	SETZ Q2,		;START IN THE FORWARD DIRECTION
PLACE3:	SETZM AVLCNT		;BUILD AVLTSK TABLE
	MOVE T1,TSKPTR		;SCAN TASK TABLES FOR THIS LEVEL
PLACE4:	SKIPE TSKINV(T1)
	JRST PLACE5
	HLRZ T2,TSKSKD(T1)	;GET LEVEL
	CAME T2,Q1		;THE ONE WE WANT?
	JRST PLACE5		;NO
	AOS T2,AVLCNT		;COUNT UP AVLCNT
	HRRZM T1,AVLTSK-1(T2)	;STORE TASK INDEX
PLACE5:	AOBJN T1,PLACE4
	SKIPG AVLCNT		;ANY FOUND?
	JRST [	SETOB Q3,P1	;DO FINAL FORWARD SCAN
		AOJA P4,PLACE2]
	MOVE T1,Q2		;GET SCAN DIRECTION
	SETZB T2,P3		;ALLOW REORGANIZATION
	SKIPN Q2		;GOING FORWARD?
	CAMLE Q1,Q3		;YES, AT NEW HIGH?
	SKIPA			;YES, OK TO REORGANIZE
	SETOB T2,P3		;NO, DO NOT REORGANIZE BOXES
	SKIPE Q2		;REVERSE?
	CAMGE Q1,P1		;YES, AT NEW LOW?
	SKIPA			;YES, CAN REORGANIZE
	SETOB T2,P3		;NO, DO NOT REORGANIZE THE BOXES
	SKIPL P4		;IN FIRST PASS?
	SETOB T2,P3		;NO, DO NOT ALLOW REORGANIZATION
	CALL SRTAVL		;GO SORT THE LIST
	; ..
	; ..
	CALL SETPOS		;SET UP TSKPOS FOR THESE TASKS
	 CALL [	JUMPLE P1,R	;IF MIN = 0, THEN GO UP TO NEXT LEVEL
		JUMPE P3,[TRC Q2,1 ;IF REORG ALLOWED, THEN CHANGE Q2
			RET]
		SKIPN Q2	;FORWARD?
		CAMGE Q1,Q3	;YES, AT HIGH POINT?
		RET		;NO, GO TO HIGH POINT BEFORE SWITCHING
		MOVEI Q2,1	;GO IN REVERSE DIRECTION
		CALL FIXPOS	;GET OUT WHITE SPACE
		RET]
	CAMGE Q1,P1		;NEW LOW?
	MOVE P1,Q1		;YES, REMEMBER IT
	SKIPE Q2		;GOING IN REVERSE?
	SOSA Q1			;YES, GO UP ONE LEVEL
	AOS Q1			;NO, GO DOWN A LEVEL
	JUMPL Q1,PLACE2		;IF AT 0, THEN TURN AROUND
	JUMPN Q2,PLACE3		;IF IN REVERSE, CONTINUE ON DOWN
	CAMG Q1,Q3		;NEW HIGH?
	JRST PLACE3		;NO
	MOVE Q3,Q1		;YES, REMEMBER IT
	MOVE P1,Q1		;START WITH A NEW MINIMUM
	JRST PLACE3		;GO CONTINUE ON
PLACE6:	CALL FIXPOS		;SQUEEZE OUT WHITE SPACE FROM PERT CHART
	RET			;ALL DONE
;SUBROUTINE TO PLACE PERT BOXES ON THE PERT CHART AT MAXIMUM DENSITY
;CALL WITH:
;	CALL HDPLC
;RETURNS +1 HAVING SET TSKPOS
;
HDPLC:	SAVEPQ			;SAVE P AND Q REGS
	CALL GETPAS		;GET NUMBER OF PASSES
	CAIGE T1,2		;AT LEAST 2?
	MOVEI T1,2		;FORCE 2
	MOVE P3,T1		;SAVE FOR LATER
	CALL ADJLVL		;ADJUST LEVEL NUMBERS
;AC USAGE
; Q1/ LEVEL NUMBER
; Q2/ FLAG. 1 MEANS FORWARD SCAN, -1 MEANS BACKWARD
; Q3/ PREVIOUS VALUE OF P2
; P1/ PASS COUNTER
; P2/ GLOBAL SCORE
; P3/ NUMBER OF PASSES
	HRLOI Q3,377777		;MAKE OLD VALUE HUGE
	MOVEI P1,1		;FIRST PASS
	MOVEI Q2,1		;START GOING FORWARD
	MOVEI Q1,0		;GET LEVEL TO START WITH
HDPLC2:	MOVEI P2,0		;ZERO SCORE
HDPLC3:	SETZM AVLCNT		;BUILD AVLTSK TABLE
	MOVE T1,TSKPTR		;SCAN TASK TABLES FOR THIS LEVEL
HDPLC4:	SKIPE TSKINV(T1)
	JRST HDPLC5
	HLRZ T2,TSKSKD(T1)	;GET LEVEL
	CAME T2,Q1		;THE ONE WE WANT?
	JRST HDPLC5		;NO
	AOS T2,AVLCNT		;COUNT UP AVLCNT
	HRRZM T1,AVLTSK-1(T2)	;STORE TASK INDEX
HDPLC5:	AOBJN T1,HDPLC4
	SKIPG AVLCNT		;ANY FOUND?
	JRST HDPLC6		;NO--THINK ABOUT TURNING AROUND
	MOVE T1,[EXP 1,0,0](Q2)	;GET DIRECTION
	MOVEI T2,0		;ALLOW MIXING
	CALL SRTAVL		;GO SORT THE LIST
	CALL SETPOS		;SET UP TSKPOS FOR THESE TASKS
	  JFCL
	CALL ASCORE		;SCORE ENTIRE AVLTSK LIST
	ADD P2,T1		;TOTAL UP SCORE
	ADD Q1,Q2		;STEP TO NEXT LEVEL
	JUMPGE Q1,HDPLC3	;KEEP GOING
HDPLC6:	TMSG <[PLACEMENT PASS >
	MOVEI T1,.PRIOU
	MOVE T2,P1
	MOVEI T3,^D10
	NOUT
	  ERJMP .
	TMSG < WITH SCORE >
	MOVEI T1,.PRIOU
	MOVE T2,P2
	MOVEI T3,^D10
	NOUT
	  ERJMP .
	TMSG <]
>

	MOVNS Q2		;CHANGE DIRECTION
	ADD Q1,Q2		;STEP BACK INTO PERT
	CAMG Q3,P2		;DID THINGS GET BETTER?
	JRST HDPLC7		;NO--TRY ANOTHER PASS
	MOVE Q3,P2		;SET NEW BEST SCORE
	MOVE T1,[TSKPOS,,TSKSVP] ;SAVE POSITIONS
	BLT T1,TSKSVP+MAXTSK-1	; ..
HDPLC7:	CAMGE P1,P3		;ENOUGH PASSES?
	AOJA P1,HDPLC2		;KEEP LOOPING
	MOVE T1,[TSKSVP,,TSKPOS]
	BLT T1,TSKPOS+MAXTSK-1	;PUT BACK BEST NUMBER
	CALL FIXPOS		;SQUEEZE OUT WHITE SPACE FROM PERT CHART
	RET			;ALL DONE
;ROUTINE TO SORT AVLTSK BY LEAST NUMBER OF CROSSED LINES
;ACCEPTS IN T1/	0 = FORWARD SCAN, 1 = REVERSE SCAN
;	    T2/	0 = ALLOW REORGANIZATION, -1 = DO NOT REORGANIZE

SRTAVL:	SAVEPQ
	DMOVE P1,T1		;SAVE INDEX AND FLAG
	MOVN Q1,AVLCNT		;SET UP POINTER TO THE LIST
	HRLZS Q1
SRTAV1:	SETZ Q2,		;INIT COL COUNTER
	MOVE P3,P1		;SET UP INITIAL INDEX
	HRRZ T1,AVLTSK(Q1)	;GET TASK INDEX
	HRRZ T1,TSKLST(T1)	;GET TASK ADR
	XCT [	LOAD Q3,TKDLP,(T1) ;GET POINTER TO LIST
		LOAD Q3,TKBLP,(T1)](P3)
	SKIPN Q3		;ANY TASKS?
	TRC P3,1		;NO, TRY THE OTHER DIRECTION
	SKIPN Q3		;ANY TASKS?
	XCT [	LOAD Q3,TKDLP,(T1) ;GET POINTER TO LIST
		LOAD Q3,TKBLP,(T1)](P3)
	JUMPE Q3,SRTAV5		;IF NONE, THEN SKIP TO NEXT TASK
SRTAV3:	XCT [	LOAD T1,DPBTK,(Q3)	;GET THE ADR OF THE TASK
		LOAD T1,DPTKP,(Q3)](P3)
	LOAD T1,TKTKI,(T1)	;GET TSKLST INDEX
	HLRE T2,TSKLST(T1)	;GET THE COLUMN LEVEL
	JUMPL T2,SRTAV4		;UNLESS IT IS NOT SET YET
	MOVE T3,TSKWID(T1)	;GET THE WIDTH OF THE BOX
	LSH T3,-1		;DIVIDE BY 2
	ADD Q2,T3		;ADD IN HALF THE WIDTH OF THE BOX
	ADD Q2,TSKPOS(T1)	;COUNT UP ITS POSITION
	ADD Q2,[1,,0]		;COUNT UP THE # OF ADDITIONS
SRTAV4:	XCT [	LOAD Q3,DPDLP,(Q3)	;STEP TO NEXT TASK IN THE LIST
		LOAD Q3,DPBLP,(Q3)](P3)
	JUMPN Q3,SRTAV3		;ANY MORE?
SRTAV5:	HRRZ T1,Q2		;GET THE SUM
	HLRZ T2,Q2		;GET THE # OF ADDITIONS
	FLTR T1,T1
	FLTR T2,T2
	FDVR T1,T2		;GET COL POSITION AVERAGE
	MOVE T3,AVLTSK(Q1)	;GET TASK INDEX
	SKIPN T1		;ANYTHING THERE?
	FLTR T1,TSKPOS(T3)	;NO, GET FROM LAST PASS
	MOVEM T1,AVLSST(Q1)	;SAVE THE SUM
	AOBJN Q1,SRTAV1		;LOOP BACK FOR ALL TASKS
	SKIPE PERTPA		;ADVANCED PLACER?
	RET			;YES--DO NOT SORT
	;..
	;..
	JUMPN P2,SRTA11		;IF NO REORGANIZATION, GO SORT TSKPOS
SRTAV6:	MOVN Q1,AVLCNT		;SET UP TO SORT THE LIST
	HRLZS Q1
	SETZ Q2,		;INIT THE COUNTER OF ITEMS SWITCHED
SRTAV7:	AOBJP Q1,SRTAV8		;STEP TO NEXT TASK
	MOVE T1,AVLSST-1(Q1)	;GET PREVIOUS ITEM
	CAMG T1,AVLSST(Q1)	;IS PREVIOUS ONE GREATER THAN THIS ONE
	JRST SRTAV7		;NO
	EXCH T1,AVLSST(Q1)	;YES, SWITCH THEM
	MOVEM T1,AVLSST-1(Q1)
	MOVE T1,AVLTSK-1(Q1)	;AND SWITCH AVLTSK LIST ALSO
	EXCH T1,AVLTSK(Q1)
	MOVEM T1,AVLTSK-1(Q1)
	AOJA Q2,SRTAV7		;LOOP BACK

SRTAV8:	JUMPG Q2,SRTAV6		;IF ANY WERE SWITCHED, LOOP BACK
	RET			;DONE

SRTA11:	MOVN Q1,AVLCNT		;SORT BY TSKPOS
	HRLZS Q1
	SETZ Q2,		;INIT SWITCH COUNT
SRTA12:	AOBJP Q1,SRTA13		;STEP TO NEXT TASK
	HRRZ T1,AVLTSK-1(Q1)	;GET TASK INDEX
	HRRZ T2,AVLTSK(Q1)	;  OF FIRST AND SECOND TASKS
	MOVE T3,TSKPOS(T1)	;GET POSITION OF FIRST TASK
	CAMG T3,TSKPOS(T2)	;OUT OF ORDER?
	JRST SRTA12		;NO
	MOVE T1,AVLSST-1(Q1)	;YES, SWITCH THE ORDER
	EXCH T1,AVLSST(Q1)
	MOVEM T1,AVLSST-1(Q1)
	MOVE T1,AVLTSK-1(Q1)	;SWITCH AVLSST AND AVLTSK
	EXCH T1,AVLTSK(Q1)
	MOVEM T1,AVLTSK-1(Q1)
	AOJA Q2,SRTA12		;MARK THAT A SWITCH WAS MADE

SRTA13:	JUMPG Q2,SRTA11		;LOOP BACK TILL NO MORE SWITCHING
	RET			;DONE
;ROUTINE TO SET THE POSITION FOR ALL TASKS IN AVLTSK LIST
;RETURNS +1:	POSITION OF SOME TASK CHANGED
;	 +2:	NO POSITIONS CHANGED

SETPOS:	SKIPE PERTPA		;DEFAULT PLACER?
	JRST ASPOS		;NO--CALL ADVANCED ROUTINE
	SAVEPQ
	SETZB P3,P4		;INIT REGS
	MOVN Q1,AVLCNT		;SET UP POINTER TO THE LIST
	HRLZS Q1
SETPO1:	MOVEI Q2,0		;INIT WIDTH
	MOVE Q3,Q1		;START SCAN HERE
	MOVEI P1,1		;START WITH A COUNT OF ONE
SETPO2:	HRRZ T1,AVLTSK(Q3)	;GET THE TASK INDEX
	ADD Q2,TSKWID(T1)	;SUM THE WIDTHS
	MOVE T1,AVLSST(Q3)	;GET THE DESIRED POSITION
	AOBJP Q3,SETPO3		;STEP TO NEXT TASK
	CAMN T1,AVLSST(Q3)	;SAME AS LAST ONE?
	AOJA P1,SETPO2		;YES, LOOP BACK
SETPO3:	EXCH Q1,Q3		;GET START OF SCAN AGAIN
	FLTR T2,Q2		;GET WIDTH
	FDVR T2,[2.0]		;GET OFFSET
	FSBR T1,T2		;GET START OF THIS BLOCK OF BOXES
	FIX T1,T1		;GET THE COL #
	SKIPGE T1		;NEGATIVE NUMBER?
	MOVEI T1,0		;YES, MAKE IT BE 0
	CAMG T1,P3		;TOO LOW?
	MOVE T1,P3		;YES, USE THE HIGHER POSITION
SETPO4:	HRRZ T2,AVLTSK(Q3)	;GET INDEX INTO TSKLST
	CAME T1,TSKPOS(T2)	;NOT MOVING?
	SETO P4,		;NO, MARK THAT IT MOVED
	MOVEM T1,TSKPOS(T2)	;SAVE THIS POSITION
	ADD T1,TSKWID(T2)	;STEP TO START OF NEXT BOX
	MOVE P3,T1		;SAVE START OF NEXT FREE SPOT
	AOBJP Q3,SETPO5		;DONE?
	CAME Q3,Q1		;DONE?
	JRST SETPO4		;DEFAULT PLACE ALWAYS GOES RIGHT
	JUMPL Q1,SETPO1		;GO GET REST OF TASKS
SETPO5:	JUMPN P4,R		;ANY CHANGES?
	RETSKP			;NO
;ROUTINE TO SET THE POSITION FOR ALL TASKS IN AVLTSK LIST
;RETURNS +1: POSITION OF SOME TASK CHANGED
;	 +2: NO POSITIONS CHANGED

ASPOS:	SAVEPQ			;SAVE SOME AC'S
	MOVN Q1,AVLCNT		;POINTER TO AVLTSK
	HRLZ Q1,Q1		;MAKE AOBJN FORMAT
	MOVEI Q2,0		;CONFLICT GROUP NUMBER
	MOVEI P4,0		;COUNT OF POSITIONS CHANGED
ASPOS1:	HRRZ T2,Q1		;COPY INDEX
	CALL CMPPOS		;COMPUTE DESIRED POSITION
	CALL CHKOVL		;ANY OVERLAP?
	  JRST [ HRROS T2,AVLTSK(T2) ;NO--FLAG CORRECTLY PLACED
	         CAME T1,TSKPOS(T2) ;SAME PLACE?
		 ADDI P4,1	;NO--POSITION CHANGED
		 MOVEM T1,TSKPOS(T2) ;STORE POSITION
		 JRST ASPOS2]	;LOOK AT NEXT TASK
	MOVE T4,AVLTSK(T3)	;GET INDEX OF OVERLAPPING TASK
	HLLM T4,AVLTSK(T2)	;MAKE PART OF THAT GROUP
	JUMPG T4,ASPOS2		;OK IF ALREADY SET
	HRLM Q2,AVLTSK(T3)	;START A NEW GROUP
	HRLM Q2,AVLTSK(T2)	; ..
	ADDI Q2,1		;GET READY FOR NEXT GROUP
ASPOS2:	AOBJN Q1,ASPOS1		;LOOP OVER ALL TASKS
	JUMPE Q2,[JUMPE P4,RSKP	;SKIP RETURN IF NOTHING HAPPENED
		  RET]		;ALL TASK FIT WHERE THEY WANT TO GO
	MOVEI Q3,0		;LEVEL TO COLLECT
ASPOS3:	MOVN Q1,AVLCNT		;LOOP OVER LIST AGAIN
	HRLZ Q1,Q1
	MOVEI P1,0		;COUNT OF MATCHES
ASPOS4:	HLRZ P2,AVLTSK(Q1)	;GET GROUP NUMBER
	CAMN P2,Q3		;THE ONE WE WANT?
	JRST [	HRRZ T1,Q1	;GET AVLTSK INDEX
		MOVEM T1,LVLTAB(P1) ;STORE IN TEMP
		AOJA P1,.+1]	;BUMP INDEX AND CONTINUE
	AOBJN Q1,ASPOS4		;COLLECT ALL MATCHES
	MOVN T1,P1		;STORE AOBJN POINTER TO GROUP
	HRLZM T1,LVLPTR		; ..
	CALL POSGRP		;SET POSITION FOR GROUP
	  ADDI P4,1		;SOMETHING MOVED
	ADDI Q3,1		;BUMP POINTER
	CAME Q2,Q3		;ALL DONE?
	JRST ASPOS3		;NO--KEEP LOOKING
	JUMPE P4,RSKP		;NOTHING MOVED
	RET			;SOMETHING MOVED
;SUBROUTINE TO SET POSITIONS FOR A GROUP OF BOXES THAT ALL WANT TO GO
; IN THE SAME PLACE
;CALL:	LVLPTR/ AOBJN POINTER TO LVLTAB
;	LVLTAB/ LIST OF AVLTSK INDICES FOR TASKS TO PLACE
;RETURNS +1: SOME POSITION CHANGED
;	 +2: NOTHING HAPPENED
;
POSGRP:	SAVEPQ
	MOVEI P5,^D1000		;LIMIT THE NUMBER OF TRIES
				; (NOT REALLY NEEDED BUT...)
	MOVEI P4,0		;NUMBER OF THINGS THAT MOVED
	MOVE P1,LVLPTR		;POINTER TO CONFLICT LIST
	CAMG P1,[-BESTN,,0]	;TOO MANY TO TRY ALL?
	CALLRET EXCGRP		;YES--TRY ALL POSSIBLE SWAPS
	CALL PRMINI		;INIT PERMUTATION TABLE
	HRLOI P1,377777		;BEST SCORE YET
PSGRP1:	CALL PLCGRP		;PLACE THIS GROUP
	  ADDI P4,1		;SOMETHING MOVED
	CALL SCORE		;EVALUATE PLACEMENT
	CAMG P1,T1		;BETTER PLACEMENT?
	JRST PSGRP3		;NO--KEEP LOOKING
	MOVE P1,T1		;REMEMBER THE NEW SCORE
	MOVE P2,[LVLTAB,,BEST]	;COPY THE LIST
	BLT P2,BEST+BESTN-1	; ..
PSGRP3:	CALL PERM		;PREMUTE LVLTAB
	  SOJG P5,PSGRP1	;KEEP LOOKING
	MOVE P2,[BEST,,LVLTAB]	;COPY THE BEST BACK
	BLT P2,LVLTAB+BESTN-1	; ..
	MOVE Q1,P4		;COPY FLAG
	CALLRET EXCGRP		;TRY TO DO SOME SWAPS
;SUBROUTINE TO LOOP THROUGH ALL PERMUATIONS OF LVLTAB
;THIS ROUTINE USES LVLCNT AS A TEMP
;TO USE:
;	CALL PRMINI		;INIT ALGORITHM
;THEN:
;	CALL PERM		;SWAP 2 ELEMENTS
;RETURNS +1:	NOT DONE YET
;        +2:	DONE
;
;SEE CACM ALGORITHM 115 BY H. F. TROTTER
;
PRMINI:	MOVSI T1,1		;INIT DIRECTION TO 1 (FORWARD)
	MOVEM T1,LVLCNT		; AND POSITION TO ZERO
	MOVE T1,[LVLCNT,,LVLCNT+1]
	BLT T1,LVLCNT+BESTN-1
	RET

PERM:	SETZB T1,T2		;ZERO OUT ARGUMENTS FOR FIRST CALL
PERM0:	SAVEP			;RECURSIVE WORK SPACE
	DMOVE P1,T1		;SAVE ARGUMENTS
	HLRE P5,LVLPTR		;NEGATIVE COUNT
	MOVM P5,P5		;POSITIVE COUNT
	SUBI P5,1		;MAXIMUM INDEX
	CAMLE P1,P5		;ARGUMENT IN RANGE?
	RETSKP			;NO--ALL DONE
	HRRZ P3,LVLCNT(P1)	;GET LOCATION ELEMENT
	HLRE P4,LVLCNT(P1)	;GET DIRECTION
	MOVE T1,P5		;UPPER LIMIT
	SUB T1,P1		;ADJUST
	CAIE P4,1		;GOING UP?
	MOVEI T1,0		;NO--SET LOWER LIMIT
	CAMN T1,P3		;UP AGAINST LIMIT?
	JRST PERM1		;YES--GO DO SOMETHING ABOUT THAT
	MOVE T1,P3		;UPDATE RELATIVE LIMIT
	ADD T1,P4		;+/- 1
	HRRM T1,LVLCNT(P1)	;STORE FOR NEXT CALL
	ADD P2,P3		;MAKE ABSOLUTE LIMIT
	ADD P4,P2		; ..
	MOVE T1,LVLTAB(P2)	;EXACHANGE TWO ELEMENTS
	EXCH T1,LVLTAB(P4)	; ..
	MOVEM T1,LVLTAB(P2)	; ..
	RET

;HERE IF WE HIT AN END
PERM1:	MOVN T1,P4		;CHANGE DIRECTION
	HRLM T1,LVLCNT(P1)	; ..
	MOVE T2,P2		;COPY OFFSET
	CAIN P4,1		;GOING UP?
	AOS T2,P2		;YES--BUMP OFFSET
	AOS T1,P1		;BUMP INDEX
	CALL PERM0		;TRY AGAIN
	  RET			;KEEP GOING
	RETSKP			;STOP
;SUBROUTINE TO SET POSITIONS FOR A GROUP OF BOXES THAT ALL WANT TO GO
; IN THE SAME PLACE
;CALL:	LVLPTR/ AOBJN POINTER TO LVLTAB
;	LVLTAB/ LIST OF AVLTSK INDICES FOR TASKS TO PLACE
;RETURNS +1: SOME POSITION CHANGED
;	 +2: NOTHING HAPPENED
;
EXCGRP:	MOVEI P5,^D1000		;LIMIT THE NUMBER OF TRIES
	MOVEI P4,0		;NUMBER OF THINGS THAT MOVED
	CALL EXCINI		;INIT PERMUTATION TABLE
	CALL PLCGRP		;POSITION FIRST TRY
	  ADDI P4,1		;SOMETHING CHANGED
	CALL SCORE		;EVALUATE PLACEMENT
	MOVE P1,T1		;ASSUME IT IS THE BEST
EXGRP1:	CALL DOEXCH		;SWAP TWO BOXES
	  SETOM P5		;RAN OUT OF TRIES
	CALL PLCGRP		;PLACE THIS GROUP
	  ADDI P4,1		;SOMETHING MOVED
	CALL SCORE		;EVALUATE PLACEMENT
	CAMG P1,T1		;BETTER PLACEMENT?
	JRST EXGRP3		;NO--KEEP LOOKING
	MOVE P1,T1		;REMEMBER NEW SCORE
	CALL EXCINI		;RESTART SWAP LIST
	SOJG P5,EXGRP1		;LOOP BACK TO TRY A SWAP
	JRST EXGRP4		;TOO MANY TRIES
EXGRP3:	CALL UNEXCH		;SWAP THE BOXES BACK
	SOJG P5,EXGRP1		;KEEP TRYING SWAPS
EXGRP4:	MOVE Q1,P4		;COPY FLAG
	JRST EXGRP6		;GO DO THE FINAL PLACEMENT

;CALLED FROM ABOVE TO DO THE REAL WORK
PLCGRP:	MOVEI Q1,0		;ASSUME NOTHING MOVED
EXGRP6:	MOVE Q2,LVLPTR		;GET AOBJN POINTER TO LVLTAB
EXGRP7:	HRRZ T2,LVLTAB(Q2)	;GET AVLTSK INDEX
	CALL CMPPOS		;COMPUTE DESIRED POSITION
	HRRZ T2,Q2		;COPY LVLTAB INDEX
	CALL ADJPOS		;ADJUST TO ELIMINATE OVERLAP
	HRRZ T2,LVLTAB(Q2)	;GET AVLTSK INDEX
	HRRZ T3,AVLTSK(T2)	;GET TSKLST INDEX
	CAME T1,TSKPOS(T3)	;NEW POSITION SAME AS OLD
	ADDI Q1,1		;NO--SOMETHING MOVED
	MOVEM T1,TSKPOS(T3)	;STORE (NEW) POSITION
	AOBJN Q2,EXGRP7		;LOOP OVER WHOLE LIST
	JUMPE Q1,RSKP		;SKIP RETURN IF NOTHING MOVED
	RET			;ELSE NON-SKIP RETURN
;TEMP STORAGE FOR EXCHANGE ROUTINES
	EXCH.I==LVLCNT+0
	EXCH.J==LVLCNT+1
	EXCH.N==LVLCNT+2
	EXCH.S==LVLCNT+3	;ALSO USES +4

;INIT THE ROUTINE
EXCINI:	SETZM EXCH.I		;I=0
	MOVEI T1,1		;J=1
	MOVEM T1,EXCH.J		; ..
	HLRE T1,LVLPTR		;N=SIZE OF LIST
	MOVMM T1,EXCH.N		; ..
	SOS EXCH.N		;ADJUST SO IT IS MAX INDEX
	RET

;EXCHANGE LVLTAB(I) WITH LVLTAB(J)
DOEXCH:	DMOVE T1,EXCH.I		;SAVE I AND J IN CASE
	DMOVEM T1,EXCH.S	; WE WANT TO UNSWAP
	MOVE T3,LVLTAB(T1)	;GET FIRST ENTRY
	EXCH T3,LVLTAB(T2)	;SWAP WITH SECOND ENTRY
	MOVEM T3,LVLTAB(T1)	;STUFF NEW FIRST ENTRY BACK
	AOS EXCH.J		;BUMP TO POINTER
	CAME T2,EXCH.N		;AT END?
	RETSKP			;NO--ALL OK
	AOS T1,EXCH.I		;BUMP EXCH.I
	MOVEI T2,1(T1)		;RESET J TO I+1
	MOVEM T2,EXCH.J		; ..
	CAME T1,EXCH.N		;LOOKING AT LAST ENTRY
	RETSKP			;NO--ALL OK
	RET			;YES--GIVE UP

;ROUTINE TO UNSWAP TWO ENTRIES
UNEXCH:	DMOVE T1,EXCH.S		;GET SAVED PARAMETERS
	MOVE T3,LVLTAB(T1)	;GET FIRST ENTRY
	EXCH T3,LVLTAB(T2)	;SWAP WITH SECOND ENTRY
	MOVEM T3,LVLTAB(T1)	;PUT NEW FIRST ENTRY BACK
	RET
;SUBROUTINE TO EVALUATE A PLACEMENT
;RETURNS +1: T1/ SCORE (SMALLER IS BETTER)
ASCORE:	SAVEP
	MOVEI P6,1		;SCORE WHOLE AVLTSK LIST
	MOVN P1,AVLCNT		;BUILD AOBJN POINTER
	HRLZ P1,P1		; TO AVLTSK
	JRST SCORE0		;GO DO IT

SCORE:	SAVEP			;SAVE VITAL REGS
	MOVEI P6,0		;JUST DO LVLTAB
	MOVE P1,LVLPTR		;POINTER TO LIST
SCORE0:	MOVEI P2,0		;INITIAL SCORE
SCORE1:	HRRZ P3,LVLTAB(P1)	;LVLTAB HAS AVLTSK INDEX
	SKIPE P6		;DOING LVLTAB?
	HRRZ P3,P1		;NO--JUST COPY INDEX
	HRRZ P3,AVLTSK(P3)	;AVLTSK HAS TSKLST INDEX
	HRRZ P4,TSKLST(P3)	;TSKLST HAS TASK BLOCK
				; ADDRESS
	LOAD P5,TKBLP,(P4)	;LIST OF LINES GOING DOWN
	JUMPE P5,SCORE3		;DONE IF BOTTOM BOX
SCORE2:	LOAD T1,DPTKP,(P5)	;ADDRESS OF TASK BLOCK
	CALL SCORE6		;COMPUTE DELTA
	LOAD P5,DPBLP,(P5)	;FOLLOW CHAIN
	JUMPN P5,SCORE2		;COUNT UP ALL LINES
SCORE3: LOAD P5,TKDLP,(P4)	;NOW LOOK AT LINES GOING UP
	JUMPE P5,SCORE5		;QUIT IF TOP BOX
SCORE4:	LOAD T1,DPBTK,(P5)	;ADDRESS OF TASK BLOCK
	CALL SCORE6		;COMPUTE DELTA
	LOAD P5,DPDLP,(P5)	;STEP TO NEXT BOX
	JUMPN P5,SCORE4		;LOOP OVER ALL LINES
SCORE5:	AOBJN P1,SCORE1		;LOOP OVER ALL CONFLICTS
	MOVE T1,P2		;COPY ANSWER
	RET			;DONE

;COMMON CODE TO COMPUTE DELTA 
SCORE6:	LOAD T1,TKTKI,(T1)	;TASK LIST INDEX
	FLTR T2,TSKWID(T1)	;TARGET WIDTH
	FDVR T2,[2.0]		;DIVIDE BY 2
	FIXR T2,T2		;CONVERT
	ADD T2,TSKPOS(T1)	;TARGET POSITION
	FLTR T3,TSKWID(P3)	;OUR WIDTH
	FDVR T3,[2.0]		;DIVIDE BY 2
	FIXR T3,T3		;CONVERT
	ADD T3,TSKPOS(P3)	;OUR POSITION
	SUB T2,T3		;GET OFFSET
	MOVM T2,T2		;DON'T CARE ABOUT DIRECTION
	ADD P2,T2		;ACCUMULATE SKEW
	RET			;DONE
;ROUTINE TO COMPUTE THE DESIRED POSITION FOR A TASK
;CALL WITH: T2/AVLTSK INDEX
;RETURN +1: T1/POSTION
;
CMPPOS:	SAVEQ
	HRRZ Q1,AVLTSK(T2)	;GET TSKLST INDEX
	MOVE Q2,AVLSST(T2)	;GET SORTED SUM
	FLTR Q3,TSKWID(Q1)	;GET WIDTH
	FDVR Q3,[2.0]		;DIVIDE IN HALF
	FSBR Q2,Q3		;ADJUST
	FIXR T1,Q2		;MAKE INTEGER
	JUMPGE T1,R		;DONE IF GOOD POSITION
	MOVEI T1,0		;ELSE MAKE ZERO
	RET
;SUBROUTINE TO ADJUST POSITION SO THAT NOTHING OVERLAPS
;CALL WITH:
;	T1/ DESIRED POSITION
;	T2/ LVLTAB INDEX
;	CALL ADJPOS
;RETURNS +1 WITH NEW POSITION IN T1
;
ADJPOS:	CALL CKLOVL		;ANY OVERLAP NOW?
	  RET			;NO--ALL DONE
	STKVAR <GOAL,LFTPOS>	;SETUP SOME TEMPS
	MOVEM T1,GOAL		;SAVE ORIGINAL GOAL
	SETOM LFTPOS		;ASSUME MOSTLY FULL
	HRRZ T3,LVLTAB(T2)	;CONVERT LVLTAB INDEX TO AVLTSK INDEX
	HRRZ T3,AVLTSK(T3)	;CONVERT AVLTSK INDEX TO TSKLST INDEX
ADJPS1: HRRZ T1,LVLTAB(T2)	;GET AVLTSK INDEX
	HRRZ T1,AVLTSK(T1)	;GET TSKLST INDEX
	MOVN T1,TSKWID(T1)	;WIDTH OF TASK TO INSERT
	ADD T1,TSKPOS(T3)	;BACK OFF TO STARTINGING POINT
	JUMPL T1,ADJPS2		;STOP AT MARGIN
	CALL CKLOVL		;DOES IT FIT NOW?
	  JRST [ MOVEM T1,LFTPOS ;SAVE THIS POSITION
		 JRST ADJPS2]	;TRY GOING THE OTHER WAY
	HRRZ T3,AVLTSK(T3)	;CONVERT AVLTSK INDEX TO TSKLST INDEX
	JUMPG T1,ADJPS1		;NO--KEEP MOVING LEFT
ADJPS2:	MOVE T1,GOAL		;RESTORE STARTING POSITION
ADJPS3:	MOVE T1,TSKPOS(T3)	;GET POSITION OF TASK
	ADD T1,TSKWID(T3)	;WHERE IT ENDS
	CALL CKLOVL		;DOES IT FIT YET?
	  JRST ADJPS4		;YES--AT LAST
	HRRZ T3,AVLTSK(T3)	;CONVERT AVLTSK INDEX TO TSKLST INDEX
	JRST ADJPS3		;NO--KEEP MOVING RIGHT

ADJPS4:	SKIPGE LFTPOS		;WAS THERE ARE ANYPLACE TO THE LEFT
	RET			;NO JUST RETURN
	MOVE T3,T1		;COPY NEW LOCATION
	SUB T3,GOAL		;COMPUTE ERROR
	MOVE T4,GOAL		;ORIGINAL TARGET
	SUB T4,LFTPOS		;ERROR GOING THAT WAY
	CAML T4,T3		;WAS IT BETTER TO GO RIGHT?
	RET			;YES--ALL DONE
	MOVE T1,LFTPOS		;NO--GO LEFT
	RET			;DONE
;SUBROUTINE TO CHECK FOR OVERLAP
;CALL WITH:
;	T1/ DESIRED POSITION
;	T2/ AVLTSK INDEX
;RETURNS: +1 IF BOX FITS
;	  +2 IF SOME OVERLAP EXISTS
;		T3/ TSKLST INDEX OF OFFENDING BOX
;
CHKOVL:	JUMPE T2,R		;THE FIRST BOX ALWAYS FITS
	SAVEP
	HRRZ P1,AVLTSK(T2)	;GET TSKLST INDEX
	MOVE P2,TSKWID(P1)	;GET WIDTH
	ADD P2,T1		;LOCATION OF RIGHT EDGE
	MOVN P1,T2		;JUST LOOK AT BOXES ALREADY PLACED
	HRLZ P1,P1		;MAKE AOBJN POINTER
CHKOV1:	HRRZ P3,AVLTSK(P1)	;GET TSKLST INDEX FOR TARGET
	MOVE P4,TSKPOS(P3)	;POSITION OF ALREADY PLACED BOX
	CAML P4,P2		;NEW BOX TO THE LEFT OF OLD?
	JRST CHKOV2		;YES--NO OVERLAP
	ADD P4,TSKWID(P3)	;GET TO OTHER SIDE OF OLD
	CAML T1,P4		;NEW BOX TO THE RIGHT OF OLD?
	JRST CHKOV2		;YES--NO OVERLAP
	HRRZ T3,P1		;COPY AVLTSK INDEX
	RETSKP			;RETURN OVERLAP
CHKOV2:	AOBJN P1,CHKOV1		;LOOP OVER ALL BOXES ALREADY PLACED
	RET
;SAME FUNCTION EXCEPT T2/ LVLTAB INDEX
CKLOVL:	SAVEP
	HRRZ P1,LVLTAB(T2)	;GET AVLTSK INDEX
	HRRZ P1,AVLTSK(P1)	;GET TSKLST INDEX
	MOVE P2,TSKWID(P1)	;GET WIDTH
	ADD P2,T1		;LOCATION OF RIGHT EDGE
	MOVN P1,AVLCNT		;LOOK AT ALL OF AVLTSK
	HRLZ P1,P1		;MAKE AOBJN POINTER
CKLOV1:	HRRZ P3,AVLTSK(P1)	;GET TSKLST INDEX FOR TARGET
	MOVE P4,TSKPOS(P3)	;POSITION OF ALREADY PLACED BOX
	CAML P4,P2		;NEW BOX TO THE LEFT OF OLD?
	JRST CKLOV2		;YES--NO OVERLAP
	ADD P4,TSKWID(P3)	;GET TO OTHER SIDE OF OLD
	CAML T1,P4		;NEW BOX TO THE RIGHT OF OLD?
	JRST CKLOV2		;YES--NO OVERLAP
	HRRZ T3,P1		;COPY AVLTSK INDEX
;IGNORE OVERLAP IF ITEM IS AHEAD IN LVLTAB
	HRR P6,T2		;MAKE AN AOBJN POINTER
	HRL P6,T2		; FOR THE REST OF THE LIST
	ADD P6,LVLPTR		; ..
	JUMPGE P6,RSKP		;DONE IF POSITIVE
	CAME T3,LVLTAB(P6)	;IS IT IN TABLE?
	AOBJN P6,.-1		;NOT YET--KEEP LOOKING
	JUMPL P6,CKLOV2		;IGNORE OVERLAP IF FOUND
	RETSKP			;RETURN OVERLAP
CKLOV2:	AOBJN P1,CKLOV1		;LOOP OVER ALL BOXES ALREADY PLACED
	RET
;SUBROUTINE TO ADJUST LEVEL NUMBERS TO MAKE PERT LOOK BETTER
;CALL 	CALL ADJLVL
;	RETURN HERE ALWAYS

ADJLVL:	MOVE T1,TSKPTR		;GET NUMBER OF TASKS
	HRROS TSKLST(T1)	;SET LH=-1 AS A FLAG
	AOBJN T1,.-1		;FLAG ALL TASKS
ADJLV1:	CALL LVLWID		;SETUP LVLTAB
	CALL MOVEND		;MOVE UP TERMINAL BOXES
	  JRST ADJLV1		;SOMETHING MOVED
	CALL FLTUP		;FLOAT UP A MAJOR GROUP
	  JRST ADJLV1		;SOMETHING MOVED
	CALL SPLIT		;BREAKUP FULL LINES
	  JRST ADJLV1		;SOMETHING MOVED
	MOVE T1,TSKPTR		;TASK COUNT
	HRRZS TSKLST(T1)	;CLEAR FLAG
	AOBJN T1,.-1		;LOOP OVER ALL TASKS
	SETZM LVLTAB		;ZERO OUT LEVEL TABLE
	MOVE T1,[LVLTAB,,LVLTAB+1]
	BLT T1,LVLTAB+MAXTSK-1	;ZAP!
	MOVE T4,TSKPTR		;POINTER TO TASK LIST
ADJLV2:	SKIPE TSKINV(T4)	;WANT THIS IN PERT?
	JRST ADJLV3		;NO--SKIP IT
	HLRZ T1,TSKSKD(T4)	;GET LEVEL
	MOVE T2,LVLTAB(T1)	;GET CURRENT POSITION FOR THAT LEVEL
	MOVEM T2,TSKPOS(T4)	;INITIAL POSITION
	ADD T2,TSKWID(T4)	;UPDATE POSITION
	MOVEM T2,LVLTAB(T1)	;SAVE FOR NEXT GUY
ADJLV3:	AOBJN T4,ADJLV2
	RET			;EVERYTHING STOPPED MOVING
;SUBROUTINE TO SETUP SOME TABLES FOR  PERT PLACER
;	CALL LVLWID
;	RETURN HERE ALWAYS
;
;SETUP THE FOLLOWING STUFF
;LVLTAB/	1B0 IF THIS LEVEL IS VERY FULL
;		1B1 IF THIS LEVEL IS VERY EMPTY
;	RH: NUMBER OF BOXES IN THIS LEVEL
;LVLCNT/	WIDTH OF THIS LEVEL
;AVWID/	AVERAGE WIDTH OF A PERT LINE
;
LVLWID:	SAVEQ
	MOVE T1,[LVLTAB,,LVLTAB+1] ;ZERO OUT TABLES
	SETZM LVLTAB
	BLT T1,LVLTAB+MAXTSK-1
	MOVE T1,[LVLCNT,,LVLCNT+1]
	SETZM LVLCNT
	BLT T1,LVLCNT+MAXTSK-1
	MOVE T4,TSKPTR		;AOBJN POINTER TO TSKLST
	SETZB Q1,Q2		;CLEAR COUNTERS
LVLWI1:	SKIPE TSKINV(T4)	;WANT THIS TASK IN PERT?
	JRST LVLWI2		;NO--SKIP TO NEXT TASK
	HLRZ T3,TSKSKD(T4)	;GET LEVEL NUMBER
	AOS LVLTAB(T3)		;COUNT USE AT THIS LEVEL
	MOVE T1,TSKWID(T4)	;GET WIDTH
	ADDM T1,LVLCNT(T3)	;ADD TO THIS LEVEL
	ADD Q1,T1		;ADD TO TOTAL
	CAMGE Q2,T3		;REMEMBER MAX LEVEL
	MOVE Q2,T3		; ..
LVLWI2:	AOBJN T4,LVLWI1		;LOOP OVER ALL TASKS
	ADDI Q2,1		;NUMBER OF LEVELS
	FLTR T1,Q1		;TOTAL WIDTH
	FLTR T2,Q2		;TOTAL NUMBER OF LEVELS
	FDVR T1,T2		;AVERAGE WIDTH
	FIXR T1,T1		;FIX AND ROUND
	MOVEM T1,AVWID
	MOVN T4,Q2		;NUMBER OF LEVELS
	HRLZ T4,T4		;AOBJN POINTER TO LVLTAB
	MOVEM T4,LVLPTR		;SAVE AOBJN POINTER
;NOW GO MARK FULL LEVELS
	SETOM T1		;PRESET MAX
LVLWI3:	CAMGE T1,LVLCNT(T4)	;NEW HIGH
	JRST [	MOVE T1,LVLCNT(T4)	;UPDATE MAX
		MOVE T3,T4	;REMEMBER HIGH
		JRST .+1]	;CONTINUE
	AOBJN T4,LVLWI3		;LOOP OVER ALL TASKS
	MOVSI T2,(1B0)		;MARK WIDEST LEVEL AS FULL
	IORM T2,LVLTAB(T3)	; ..

	MOVE Q1,AVWID		;GET WIDTH
	ASH Q1,-1		;DIVIDE BY 2
	MOVE Q2,AVWID		;GET WIDTH AGAIN
	ASH Q2,1		;DOUBLE IT
	MOVSI T2,(1B0)		;FULL LEVEL FLAG
	MOVSI T3,(1B1)		;EMPTY LEVEL FLAG
LVLWI4:	MOVE T1,LVLCNT(T4)	;WIDTH OF THIS LEVEL
	CAMGE T1,Q1		;LESS THAN HALF AVERAGE?
	IORM T3,LVLTAB(T4)	;YES--MARK AS VERY EMPTY
	CAMLE T1,Q2		;MORE THAN TWICE AVERAGE?
	IORM T2,LVLTAB(T4)	;YES--MARK AS VERY FULL
	AOBJN T4,LVLWI4
	RET			;ALL DONE
;SUBROUTINE TO MOVE TERMINAL BOXES OFF THE BOTTOM LINE
;CALL WITH:
;	CALL MOVEND
;	  RETURN HERE IF SOMETHING MOVED
;	RETURN HERE WHEN DONE
MOVEND:	SAVEP
	MOVE P1,TSKPTR		;SETUP FOR LOOP
MVEND1:	MOVE P2,TSKLST(P1)	;GET POINTER TO A TASK
	LOAD P3,TKBLP,(P2)	;GET BLOCKING LIST POINTER
	JUMPE P3,MVEN1B		;JUMP IF TERMINAL BOX
MVEN1A:	LOAD T1,DPTKP,(P3)	;GET TASK POINTER
	LOAD T1,TKTKI,(T1)	;GET TSKLST INDEX
	SKIPN TSKINV(T1)	;WANT IN PERT?
	JRST MVENDX		;YES--THEN NOT TERMINAL BOX
	LOAD P3,DPBLP,(P3)	;FOLLOW LIST
	JUMPN P3,MVEN1A		;LOOP OVER ALL BOXES -- OK
				;IF ALL ARE INVISIBLE
MVEN1B:	LOAD P3,TKDLP,(P2)	;SEE WHO IS BLOCKING US
	JUMPE P3,MVEND5		;SINGLE FLOATING BOX
	MOVEI P4,0		;MAX LEVEL
MVEND2:	LOAD T1,DPBTK,(P3)	;POINTER TO BLOCKING TASK
	LOAD T1,TKTKI,(T1)	;GET TSKLST INDEX
	HLRZ T1,TSKSKD(T1)	;GET LEVEL NUMBER
	CAMLE T1,P4		;NEW MAX?
	MOVE P4,T1		;YES REMEMBER THAT
	LOAD P3,DPDLP,(P3)	;FOLLOW LIST
	JUMPN P3,MVEND2		;LOOP OVER ALL TASKS
	ADDI P4,1		;BUMP TO NEXT LEVEL
	HLRZ P2,TSKSKD(P1)	;GET CURRENT LEVEL
;NOW WE WANT TO PUT THE BOX ON A NON-FULL LEVEL CLOSE TO THE TARGET
MVEND3:	CAMN P2,P4		;WHERE WE SHOULD BE?
	JRST MVENDX		;YES--TRY NEXT
	SKIPL LVLTAB(P4)	;HOW ABOUT THIS LEVEL?
	JRST MVEND4		;SOLD!
	ADDI P4,1		;NO--BUMP LEVEL
	JRST MVEND3		;LOOP BACK
MVEND4:	HRLM P4,TSKSKD(P1)	;NO--STORE NEW LEVEL
	JRST MVEND7		;PRINT MESSAGE AND RETURN

MVEND5:	HLRZ T1,TSKSKD(P1)	;GET CURRENT LEVEL
	MOVSI T2,(1B1)		;FLAG FOR EMPTY LEVEL
	TDNE T2,LVLTAB(T1)	;ON EMPTY LEVEL NOW?
	JRST MVENDX		;YES--LEAVE ALONE
MVEND6:	TDNN T2,LVLTAB(T1)	;IS THIS AN EMPTY LEVEL
	SOJGE T1,MVEND6		;NO--KEEP LOOKING
	JUMPLE T1,MVENDX	;NOPLACE TO GO
	HRLM T1,TSKSKD(P1)	;MOVE BOX UP
MVEND7:	HRRZ T1,P1		;COPY INDEX
	CALL MOVMSG		;INDICATE SOMETING HAPPENED
	RET			;TRY AGAIN

MVENDX:	AOBJN P1,MVEND1		;LOOP OVER ALL TASKS
	RETSKP			;NOTHING MOVED
;SUBROUTINE TO MOVE THINGS UP FROM A FULL PART OF THE PERT
; TO AN EMPTY PART OF THE PERT
;CALL WITH:
;	CALL FLTUP
;RETURNS +1 IS SOMETHING MOVED
;	 +2 IFNOTHING MOVED
;
FLTUP:	SAVEQ
	CALL MAYFLT		;FIND SOMETHING TO FLOAT
	  JRST FLTUP2		;NOTHING FOUND
	MOVE Q1,T1		;SAVE TSKLST INDEX
	CALL MOVMSG		;OUTPUT MESSAGE
	HLRZ Q3,TSKSKD(Q1)	;GET CURRENT LEVEL
	SUBI Q3,2		;FIRST POSSIBLE PLACE TO PUT IT
	MOVSI T1,(1B1)		;FLAG FOR EMPTY LEVEL
	TDNN T1,LVLTAB(Q3)	;HOW ABOUT HERE?
	SOJGE Q3,.-1		;NO--KEEP MOVING UP
	SKIPGE Q3		;SOMEPLACE FOUND?
	ERRMES <FLTUP: LVLTAB MESSED UP>
	ADDI Q3,1		;ADVANCE ONE LEVEL
	HRLM Q3,TSKSKD(Q1)	;SAVE ADJUSTED LEVEL
	SUBI Q3,1		;BACK TO EMPTY LEVEL
	HRRZS Q2,TSKLST(Q1)	;GET ADR OF TASK BLOCK
	LOAD Q2,TKDLP,(Q2)	;GET POINTER TO DEP LIST
	JUMPN Q2,FLTUP1		;MAKE SURE IT IS THERE
	ERRMES <MAYFLT LIES>
FLTUP1:	LOAD T1,DPBTK,(Q2)	;POINTER TO BLOCKING TASK
	LOAD T1,TKTKI,(T1)	;GET TSKLST INDEX
	HRLM Q3,TSKSKD(T1)	;STORE NEW LEVEL NUMBER
	HRRZS TSKLST(T1)	;CLEAR FLAG
	LOAD Q2,DPDLP,(Q2)	;FOLLOW LIST
	JUMPN Q2,FLTUP1		;MOVE ALL BOXES UP
	RET

FLTUP2:	MOVEI T1,0		;START AT THE TOP
FLTU2A:	CALL FFLVL		;FIND A GOOD PLACE TO DO A FLOAT
	  RETSKP		;NONE FOUND!
	HRRZ Q1,T1		;SAVE SOURCE
	HRRZ Q2,T2		;SAVE DESTINATION
	MOVE Q3,TSKCNT		;SCAN TSKLST BACKWARDS
	SUBI Q3,1		; ..
FLTUP3:	HLRZ T2,TSKSKD(Q3)	;GET LEVEL NUMBER
	CAME T2,Q1		;THE ONE WE WANT?
	JRST FLTUP4		;NO--KEEP LOOKING
	HRRZ T1,Q3		;COPY TSKLST INDEX
	HRRZ T2,Q2		;COPY TARGET LEVEL
	CALL LGLFLT		;IS THIS A LEGAL MOVE?
	  JRST FLTUP4		;NO!
	HRRZ T1,Q3		;SETUP FOR MOVMSG
	CALL MOVMSG		;INDICATE WE ARE DOING THE MOVE
	HRRZS TSKLST(Q3)	;SET FLAG
	HRLM Q2,TSKSKD(Q3)	;MOVE THE BOX
	RET			;DO ANALYSIS AGAIN
FLTUP4:	SOJGE Q3,FLTUP3		;LOOP OVER ALL TASKS
	MOVEI T1,1(Q1)		;ADJUST TARGET
	JRST FLTU2A		;KEEP TRYING
;ROUTINE TO FIND A PAIR OF LEVELS FOR MOTION
;RETURNS +1:	NOTHING FOUND
;	 +2:	T1/ SOURCE LEVEL T2/ DESTINATON LEVEL

FFLVL:	HRL T1,T1		;MAKE XWD
	ADD T1,LVLPTR		;GET POINTER TO LVLTAB
FFLVL1:	SKIPL LVLTAB(T1)	;IS THIS LEVEL FULL?
FFLVL2:	AOBJN T1,FFLVL1		;NO--KEEP LOOKING
	JUMPG T1,R		;NOTHING FOUND
	HRREI T2,-1(T1)		;TARGET LEVEL
	JUMPL T2,FFLVL2		;DO NOT MOVE OFF TOP
	MOVEI T3,5		;MAXIMUM MOTION
	MOVE T4,LVLCNT(T1)	;WIDTH OF THIS LEVEL
	ASH T4,-1		;DIVIDE BY 2
FFLVL3:	CAMLE T4,LVLCNT(T2)	;TARGET EMPTY ENOUGH?
	RETSKP			;YES
	SOJL T2,FFLVL2		;REDUCE TARGET. 
	SOJG T3,FFLVL3		;KEEP LOOPING
	JRST FFLVL2		;KEEP LOOKING
;ROUTINE TO CHECK FOR A LEGAL FLOAT
;CALL WITH:	
;	T1/ TSKLST INDEX
;	T2/ TARGET
;RETURNS +1:	NOT LEGAL
;	 +2:	LEGAL

LGLFLT:	SAVEQ
	HRRZ Q2,T2		;SAVE TARGET
	HRRZ T4,TSKLST(T1)	;GET ADDRESS OF TASK BLOCK
	LOAD T3,TKBLP,(T4)	;GET POINTER TO HIGHER LEVELS
	JUMPE T3,LGLFL1		;JUMP IF BOTTOM BOX
	LOAD T3,DPBLP,(T3)	;SEE IF MORE BOXES
	JUMPN T3,R		;MAX OF 1 LINE DOWN
LGLFL1:	LOAD Q1,TKDLP,(T4)	;GET POINTER TO BOXES UP
LGLFL2:	JUMPE Q1,RSKP		;OK IF NONE ABOVE
	LOAD T1,DPBTK,(Q1)	;GET TASK ADDRESS
	LOAD T1,TKTKI,(T1)	;GET TSKLST INDEX
	HLRZ T2,TSKSKD(T1)	;GET ITS LEVEL
	CAML T2,Q2		;ABOVE TARGET?
	RET			;NO--LINES MAY NOT GO UP
	LOAD Q1,DPDLP,(Q1)	;LOOK AT NEXT TASK
	JRST LGLFL2		;LOOP
MOVMSG:	RET			;PATCH TO JFCL TO PRINT MESSAGE
	MOVE T4,T1		;SAVE TSKLST INDEX
	TMSG <[MOVING UP >	;SAY WHAT WE ARE DOING
	HRRZ T1,TSKLST(T4)	;GET ADDRES OF TASK BLOCK
	CALL TYPTNM		;TYPE TASK NAME
	TMSG<]
>
	RET			;RETURN
;SUBROUTINE TO FIND A GROUP OF BOXES TO FLOAT UP
;	CALL MAYFLT
;RETURNS +1: IF NOTHING TO MOVE
;	 +2: T1/ TSKLST INDEX OF ROOT
MAYFLT:	MOVE T4,TSKPTR		;USUAL AOBJN POINTER
MAYFL1:	SKIPE TSKINV(T4)	;IS THIS TASK IN THE PERT?
	JRST MAYFL4		;NO--SKIP IT
	HLRZ T1,TSKSKD(T4)	;GET LEVEL
	CAIGE T1,2		;ANY HOPE OF REDUCING
	JRST MAYFL4		;NO--LOOK ON
	MOVE T2,LVLTAB-1(T1)	;LOOK AT PREVIOUS LEVEL
	HLRE T3,TSKLST(T4)	;GET FLAG
	XCT [	TLNE T2,(1B1)	;NOT ON EMPTY LEVEL AND NEVER MOVED
		TLNN T2,(1B0)]+1(T3) ; OR MOVED TO A FULL LEVEL
	JRST MAYFL4		;NO--LOOK ON
	MOVSI T2,(1B1)		;EMPTY LEVEL FLAG
	SUBI T1,2		;PLACE TO STRAT LOOKING
	TDNN T2,LVLTAB(T1)	;LOOK FOR EMPTY LEVEL
	SOJGE T1,.-1		;LOOP OVER ALL LEVELS
	JUMPL T1,MAYFL4		;LOOK ON IF NONE
	HRRZ T1,TSKLST(T4)	;GET POINTER TO TASK BLOCK
	LOAD T2,TKDLP,(T1)	;POINTER TO BLOCKING LIST
	MOVEI T3,0
MAYFL2:	JUMPE T2,MAYFL3		;STOP AT END OF LIST
	LOAD T1,DPBTK,(T2)	;GET BLOCKING TASK
	LOAD T1,TKDLP,(T1)	;GET IT DEP LIST
	JUMPN T1,MAYFL4		;CAN ONLY DO ONE LEVEL NOW
	LOAD T2,DPDLP,(T2)	;FOLLOW LIST
	AOJA T3,MAYFL2		;COUNT BOXES
MAYFL3:	CAIGE T3,3		;WORTH MOVING?
	JRST MAYFL4		;NO.
	HRRZ T1,T4		;YES--GO MOVE IT
	RETSKP
MAYFL4:	AOBJN T4,MAYFL1		;LOOP OVER ALL TASKS
	RET			;NOTHING WORTH MOVING
;SUBROUTINE TO BREAK FULL LEVELS INTO TWO LEVELS
;CALL:	CALL SPLIT
;RETURNS: +1 IF SOMETHING MOVED
;	  +2 IF NOTHING MOVED
SPLIT:	RETSKP			;NOT TONIGHT
;SUBROUTINE TO DO THE SELECTION DIALOGUE
;	CALL SELECT
;	RETURN HERE WITH SELTAB SETUP
;
SELECT:	SAVEPQ			;SAVE SOME AC'S
	CALL SELINI		;INIT THE DATA BASE
SELNXT:	HRROI T1,[ASCIZ /SELECT: /]
	MOVEI T2,SEL
	MOVEI T3,ANSWER
	CALL PARSE
	  ERRMES (<TABLES ARE MESSED UP>)
	MOVEI P1,ANSWER		;POINT TO ANSWER BLOCK
	HLRZ T1,(P1)		;GET TYPE
	CHKTYP (KEY)		;MUST BE KEYWORD
	HRRZ T1,(P1)		;POINTER TO DISPATCH
	AOJA P1,(T1)		;GO DO FUNCTION

;
;	HERE ON INCLUDE COMMAND
;
SELIP:	HLRZ T1,(P1)		;CHECK FOR KEYWORD
	CHKTYP (KEY)
	HRRZ T1,(P1)		;POINTER TO DISPATCH
	AOJA P1,(T1)		;GO DISPATCH

;
;	HERE ON INCLUDE PROJECT
;
SELIPR:	HLRZ T1,(P1)		;CHECK THE TYPE CODE
	CHKTYP (KEY)
	HRRZ T1,(P1)		;GET POINTER TO PROJ BLOCK
	HRLI T1,.TYPRJ		;FLAG IT AS A PROJECT
	HLRZ P2,1(P1)		;GET TYPE OF NEXT ITEM
	CAIN P2,.CMCFM		;WAS IT JUST CR?
	JRST SLIPR1		;YES--WHOLE PROJECT
	MOVE T1,P2		;COPY TYPE
	CHKTYP (KEY)		;BETTER BE A KEYWORD
	MOVSI T1,.TYTSK		;GET POINTER TO TASK BLOCK
	HRR T1,1(P1)		; ..
SLIPR1:	CALL SELSTO		;STORE INTO SELTAB
	JRST SELNXT		;GET NEXT COMMAND

;
;	HERE WHEN DONE
;
SELFI:	RET
;SUBROUTINE TO INIT SELECTION DATABASE
;	CALL SELINI
;	RETURN HERE ALWAYS
;
SELINI:	SETZM SELCNT		;CLEAR COUNTER
	RET			;ALL SET

;SUBROUTINE TO STORE INTO SELTAB
;CALL WITH:
;	T1/ TYPE,,DATA
;	CALL SELSTO
;	RETURN HERE
SELSTO:	AOS T2,SELCNT		;BUMP COUNTER
	CAILE T2,MAXSEL		;ROOM?
	  WARN (<SOS T2,SELCNT>,<Selection table full>)
	MOVEM T1,SELTAB-1(T2)	;STORE
	RET
;SUBROUTINE TO DECIDE IF A TASK SHOULD BE PERTED
;CALL WITH:
;	T1/ TASK BLOCK
;	CALL PRTTSK
;	  RETURN HERE IF NO
;	RETURN HERE IF YES
;
PRTTSK:	SKIPN SELFLG		;ANY SELECTIONS DONE?
	RETSKP			;NO--ALWAYS PERT
	SAVEPQ			;SAVE SOME AC'S
	MOVN Q1,SELCNT		;NUMBER OF THINGS SELECTED
	HRLZ Q1,Q1		;AOBJN'IZE
	LOAD Q2,TKPRJ,(T1)	;ADDRESS OF PROJ BLOCK
	HRLI Q2,.TYPRJ		;FLAG AS PROJECT
	MOVE Q3,T1		;COPY POINTER TO TASK BLOCK
	HRLI Q3,.TYTSK		;FLAG AS TASK
PRTSK1:	CAME Q2,SELTAB(Q1)	;MATCH EITHER PROJECT
	CAMN Q3,SELTAB(Q1)	; OR TASK
	RETSKP			;YES--STUFF IT IN PERT
	AOBJN Q1,PRTSK1		;SCAN WHOLE TABLE
	RET			;EXCLDE IF NOT THERE
;ADD COMMAND

ADDCMD:	HLRZ T1,(P1)		;GET FUNCTION CODE
	CHKTYP (KEY)
	HRRZ T1,(P1)		;GET DISPATCH ADR
	AOJA P1,(T1)		;DISPATCH

;ADD PROJECT

ADDP:	HLRZ T1,(P1)		;CHECK THE CODE
	CHKTYP (FLD)
	HRRZ T1,(P1)		;GET ADR OF PROJECT NAME
	ADDI T1,ANSWER
	CALL ADDPRJ		;ADD THE PROJECT NAME TO THE TABLE
	 WARN (<JRST LEVEL0>,<COULD NOT ADD THIS NAME TO THE PROJECT LIST>)
	MOVE P2,T1		;SET UP THE ADR OF THE PROJECT BLOCK
	CAMN T2,PRJTBL		;IS THERE A NEW PROJECT TABLE?
	JRST LOGPRJ		;NO, GO GET THE NEXT COMMAND
	MOVE T1,PRJTBL		;YES, RELEASE THE OLD ONE
	MOVEM T2,PRJTBL		;STORE THE NEW ONE
	CALL RELFRE
	JRST LOGPRJ		;GO GET NEXT COMMAND

;ADD TASK

ADDT:	HLRZ T1,(P1)		;CHECK THE TYPE CODE
	CHKTYP (FLD)
	HLRZ T1,1(P1)		;NOW CHECK THE SECOND FIELD
	CHKTYP (KEY)
	HRRZ T1,0(P1)		;GET POINTER TO TASK NAME
	ADDI T1,ANSWER
	HRRZ T2,1(P1)		;GET POINTER TO PROJECT BLOCK
	LOAD T3,PJTKT,(T2)	;GET ADR OF TASK TABLE
	CALL ADDTSK		;ADD THIS TASK TO THE TABLE
	 WARN (<JRST LEVEL0>,<COULD NOT ADD THIS TASK NAME TO THE TASK TABLE>)
	MOVE P3,T1		;SET UP POINTER TO TASK BLOCK
	LOAD P2,TKPRJ,(P3)	;AND THE POINTER TO THE PROJECT BLOCK
	LOAD T1,PJTKT,(P2)	;GET THE TASK LIST ADDRESS
	CAMN T1,T2		;IS THERE A NEW TASK LIST ADDRESS?
	JRST LOGTSK		;NO, GO GET NEXT COMMAND
	STOR T2,PJTKT,(P2)	;YES, STORE THE NEW ADDRESS
	CALL RELFRE		;RELEASE THE OLD BLOCK
	JRST LOGTSK		;GO GET NEXT COMMAND
;DELETE COMMAND

DELETE:	HLRZ T1,(P1)		;CHECK THE CODE
	CHKTYP (KEY)
	HRRZ T1,(P1)		;GET THE DISPATCH ADDRESS
	AOJA P1,(T1)		;DISPATCH

;DELETE OVERALL DEVELOPER

DELODV:	HLRZ T1,(P1)		;GET TYPE CODE
	CHKTYP (USR)
	HRRZ T1,(P1)
	HRROI T1,ANSWER+1(T1)	;GET A POINTER TO THE DEVELOPER NAME
	MOVE T2,DEVTBP		;GET POINTER TO DEVELOPER LIST
	CALL DELDEV		;DELETE THE DEVELOPER
	 WARN (<JRST LEVEL0>,<COULD NOT DELETE THIS DEVELOPER FROM THE LIST>)
	MOVEM T1,DEVTBP		;SAVE THE NEW POINTER
	CALL UPDDB		;UPDATE THE DATA BASE
	JRST LEVEL0
;DELETE PROJECT

DELPRJ:	HLRZ T1,(P1)		;GET TYPE CODE
	CHKTYP (KEY)
	HRRZ P2,(P1)		;GET ADR OF PROJECT BLOCK
DELPR1:	LOAD T1,PJTKT,(P2)	;GET ADR OF TASK TABLE
	HLRZ T2,(T1)		;GET NUMBER OF ENTRIES IN TABLE
	JUMPE T2,DELPR2		;IF NONE, THEN DONE
	HRRZ T1,1(T1)		;GET FIRST ENTRY IN TABLE
	CALL DELT		;DELETE THIS TASK
	JRST DELPR1		;LOOP BACK TILL ALL TASKS DELETED

DELPR2:	MOVE T1,PRJTBL		;GET ADR OF PROJECT TABLE
	LOAD T2,PJNAM,(P2)	;GET ADR OF NAME BLOCK
	HRLI T2,(POINT 7,0)
	TBLUK			;LOOK UP THIS PROJECT
	 ERJMP DELPR3		;FAILED
	TXNN T2,TL%EXM		;MUST FIND AN EXACT MATCH
DELPR3:	WARN (<JRST LOGLV0>,<COULD NOT COMPLETELY DELETE PROJECT>)
	MOVE T2,T1		;GET ADR OF ENTRY IN TABLE
	MOVE T1,PRJTBL		;GET ADR OF TABLE
	TBDEL			;DELETE THE ENTRY
	 ERJMP DELPR3
	LOAD T1,PJNAM,(P2)	;GET THE NAME STRING
	CALL RELFRE		;RELEASE IT
	LOAD T1,PJDSC,(P2)		;RELEASE THE DESCRIPTION BLOCK
	CALL RELFRE
	LOAD T1,PJTKT,(P2)	;NOW RELEASE THE TASK TABLE
	CALL RELFRE
DELPR4:	LOAD Q1,PJDVL,(P2)	;NOW RELEASE THE DEVELOPER LIST
	JUMPE Q1,DELPR6		;IF THERE IS ONE
DELPR5:	MOVE T1,Q1		;GET ADR OF THIS BLOCK
	LOAD Q1,DVLNK,(Q1)	;GET ADR OF NEXT ONE
	CALL RELDEV		;RELEASE THE BLOCK
	JUMPN Q1,DELPR5		;LOOP BACK FOR THE OTHER BLOCKS
DELPR6:	MOVE T1,P2		;FINALLY, RELEASE THE PROJECT BLOCK
	CALL RELFRE
	JRST LOGLV0		;DONE
;ROUTINE TO DELETE A TASK

DELTSK:	HLRZ T1,(P1)		;GET TYPE CODE
	CHKTYP (KEY)
	HRRZ P2,(P1)		;SET UP POINTER TO PROJECT BLOCK
	HLRZ T1,1(P1)		;GET SECOND TYPE CODE
	CHKTYP (KEY)
	HRRZ T1,1(P1)		;SET UP POINTER TO TASK BLOCK
	CALL DELT		;GO DELETE THE TASK
	JRST LOGLV0
;ROUTINE TO DELETE A TASK BLOCK
;ACCEPTS IN T1/	TASK BLOCK ADR

DELT:	SAVEPQ
	MOVE P3,T1		;GET ADR OF TASK INTO P3
	LOAD P2,TKPRJ,(P3)	;GET ADR OF PROJECT BLOCK INTO P2
	LOAD T1,PJTKT,(P2)	;GET THE ADR OF THE TASK TABLE
	LOAD T2,TKNAM,(P3)	;GET A POINTER TO THE NAME STRING
	HRLI T2,(POINT 7,0)	;SET UP A BYTE POINTER TO NAME
	TBLUK			;LOOK UP THE NAME IN THE TABLE
	 ERJMP DELT1		;FAILED TO FIND IT
	TXNN T2,TL%EXM		;FOUND AN EXACT MATCH?
DELT1:	WARN (<RET>,<FAILED TO DELETE THIS TASK>)
	MOVE T2,T1		;SAVE ADR OF THE ENTRY TO BE DELETED
	LOAD T1,PJTKT,(P2)	;GET ADR OF TASK TABLE
	TBDEL			;DELETE THIS ENTRY
	 ERJMP DELT1		;FAILED
	LOAD T1,TKNAM,(P3)	;NOW RETURN THE NAME STRING
	SKIPE T1
	CALL RELFRE
	LOAD T1,TKDSC,(P3)	;RELEASE DESCRIPTION BLOCK
	SKIPE T1
	CALL RELFRE
DELT1A:	LOAD T1,TKDLP,(P3)	;GET POINTER TO DEPENDENCY LIST
	JUMPE T1,DELT1B		;IF NONE, GO ON TO BLOCKED LIST
	CALL RELDEP		;RELEASE THIS DEPENDENCY BLOCK
	JRST DELT1A		;LOOP BACK TIL LIST IS EMPTY

DELT1B:	LOAD T1,TKBLP,(P3)	;NOW EMPTY THE BLOCKED LIST
	JUMPE T1,DELT1C		;STOP WHEN LIST IS EMPTY
	CALL RELDEP		;RELEASE THIS BLOCK
	JRST DELT1B		;LOOP BACK TILL LIST IS EMPTY

DELT1C:	LOAD Q1,TKDVL,(P3)	;NOW RELEASE DEVELOPER LIST
	JUMPE Q1,DELT3		;UNLESS ALREADY EMPTY
DELT2:	MOVE T1,Q1		;RELEASE THIS BLOCK
	LOAD Q1,DVLNK,(Q1)	;GET POINTER TO NEXT BLOCK
	CALL RELDEV		;RELEASE THIS ONE
	JUMPN Q1,DELT2		;LOOP BACK IF MORE TO BE DONE
DELT3:	MOVE T1,P3		;FINALY, RELEASE TASK BLOCK
	CALL RELFRE
	RET			;DONE
;DEVELOPER COMMAND

L0DEV:	HLRZ T1,(P1)		;GET TYPE CODE
	CHKTYP (USR)
	HLRZ T1,1(P1)		;GET SECOND TYPE CODE
	CHKTYP (FLT)
	HLRZ T1,2(P1)		;GET THIRD TYPE CODE
	CHKTYP (FLT)
	HRRZ T1,0(P1)		;NOW GET THE USER NUMBER
	HRROI T1,ANSWER+1(T1)	;GET POINTER TO NAME STRING
	HRRZ T2,1(P1)		;AND GET THE RATE
	MOVE T2,ANSWER(T2)
	HRRZ T3,2(P1)		;GET THE HANDICAP
	MOVE T3,ANSWER(T3)
	MOVE T4,DEVTBP		;GET POINTER TO OVERALL LIST
	CALL BLDDEV		;GO ADD THE DEVELOPER
	 WARN (<JRST L0DEV2>,<L0DEV: COULD NOT ADD THIS DEVELOPER>)
	JUMPN T2,L0DEV1		;CHANGED FIRST BLOCK?
	MOVE T2,DEVTBP		;YES
	STOR T2,DVLNK,(T1)	;PUT NEXT POINTER INTO THE LIST
	MOVEM T1,DEVTBP		;PUT THIS BLOCK ON FRONT OF LIST
L0DEV1:	CALL UPDDB		;UPDATE THE DATA BASE
L0DEV2:	JRST LEVEL0		;DONE
;UPDATE COMMAND

UPDATE:	HLRZ T1,(P1)		;CHECK THE TYPE CODE
	CHKTYP (KEY)
	HRRZ P2,(P1)		;SET UP POINTER TO PROJECT BLOCK
	HLRZ T1,1(P1)		;CHECK CODE OF NEXT ITEM
	CAIN T1,.CMCFM		;ID USER UPDATING PROJECT BLOCK?
	JRST LOGPRJ		;YES
	CHKTYP (KEY)
	HRRZ P3,1(P1)		;UPDATING THE TASK BLOCK
	JRST LOGTSK

;ROUTINES TO UPDATE A TASK OR PROJECT BLOCK

LOGPRJ:	CALL UPDDB		;UPDATE THE DATA BASE
	JRST UPDPRJ

LOGTSK:	CALL UPDDB		;GO UPDATE THE DATA BASE
	JRST UPDTSK

UPDTSK:	CALL INITRA		;INIT TRANSACTION AREA
	HRROI T1,[ASCIZ/TASK DATA: /]
	MOVEI T2,DATA		;GET POINTER TO COMMAND TABLE
	JRST UPDPR1		;ENTER COMMON CODE

UPDPRJ:	CALL INITRA		;GO INITIALIZE THE TRANSACTION AREA
	HRROI T1,[ASCIZ/PROJECT DATA: /]
	MOVEI T2,PDATA
UPDPR1:	MOVEI T3,ANSWER		;GO PARSE THE NEXT LINE
	CALL PARSE
	 ERRMES (<ILLEGALLY FORMATTED COMMAND TABLE>)
	CALL COPCMD		;COPY COMMAND TO CMDBLK
	MOVEI P1,ANSWER		;SET UP POINTER TO ANSWER BLOCK
	HLRZ T1,(P1)		;CHECK TYPE CODE
	CHKTYP (KEY)
	HRRZ T1,(P1)		;GET DISPATCH ADR
	AOJA P1,(T1)		;DISPATCH
;ROUTINE TO GET THE DESCRIPTION OF A PROJECT

PRJDSC:	HRROI T1,[ASCIZ/PROJECT DESCRIPTION: /]
	CALL GETDSC		;GET A DESCRIPTIO
	 WARN (<JRST UPDPRJ>,<FAILED TO GET DESCRIPTION BLOCK>)
	LOAD T2,PJDSC,(P2)	;SEE IF THERE IS ALREADY A DESCRIPTION
	STOR T1,PJDSC,(P2)	;STORE THE NEW DESCRIPTION
	SKIPE T1,T2		;WAS THERE AN OLD ONE?
	CALL RELFRE		;YES, RELEASE ITS SPACE
	JRST LOGPRJ		;GO BACK FOR THE NEXT COMMAND


;ROUTINE TO ADD A DEVELOPER TO A PROJECT 

PRJDEV:	HLRZ T1,(P1)		;GET TYPE CODE
	CHKTYP (USR)
	HLRZ T1,1(P1)		;GET SECOND TYPE CODE
	CHKTYP (FLT)
	HLRZ T1,2(P1)		;GET THIRD TYPE CODE
	CHKTYP (FLT)
	HRRZ T1,0(P1)		;NOW GET THE USER NUMBER
	HRROI T1,ANSWER+1(T1)	;GET POINTER TO NAME STRING
	HRRZ T2,1(P1)		;AND GET THE RATE
	MOVE T2,ANSWER(T2)
	HRRZ T3,2(P1)		;GET THE HANDICAP
	MOVE T3,ANSWER(T3)
	LOAD T4,PJDVL,(P2)	;GET POINTER TO FIRST ELEMENT IN LIST
	CALL BLDDEV		;GO BUILD A DEVELOPER BLOCK
	 WARN (<JRST UPDPRJ>,<COULD NOT ADD THIS DEVELOPER TO THE PROJECT>)
	JUMPN T2,PRJDV1		;IF NOT NEW BLOCK, THEN DONE
	STOR P2,DVBKP,(T1)	;PUT THE BACK POINTER INTO THE BLOCK
	LOAD T2,PJDVL,(P2)	;NOW ADD THIS BLOCK TO THE LIST
	STOR T2,DVLNK,(T1)	;MAKE THIS BLOCK POINT DOWN THE LIST
	STOR T1,PJDVL,(P2)	;MAKE THE PROJECT BLOCK POINT TO THIS BLOCK
PRJDV1:	JRST LOGPRJ		;DONE
;PROJECT DELETE COMMAND

PRJDEL:	HLRZ T1,(P1)		;GET TYPE CODE
	CHKTYP (KEY)
	HRRZ T1,0(P1)		;GET DISPATCH ADR
	AOJA P1,(T1)		;GO DISPATCH

;ROUTINE TO DELETE A DEVELOPER FROM A PROJECT

PRJDLD:	HLRZ T1,(P1)		;GET THE TYPE CODE
	CHKTYP (USR)
	HRRZ T1,0(P1)		;GET ADR OF USER CODE
	HRROI T1,ANSWER+1(T1)	;GET POINTER TO NAME STRING
	LOAD T2,PJDVL,(P2)	;GET ADR OF FIRST BLOCK IN LIST
	CALL DELDEV		;GO DELETE THE DEVELOPER
	 WARN (<JRST UPDPRJ>,<COULD NOT DELETE THIS DEVELOPER>)
	STOR T1,PJDVL,(P2)	;STORE THE UPDATED BLOCK POINTER
	JRST LOGPRJ		;DONE


;ROUTINE TO FINISH UPDATING PROJECT DATA

PRJFIN:	JRST LOGLV0		;GO BACK TO LEVEL 0


;PROJECT PREFERENCE VALUE

PRJPRF:	HLRZ T1,(P1)		;GET THE TYPE CODE
	CHKTYP (FLT)
	HRRZ T1,(P1)		;GET POINTER TO VALUE
	MOVE T1,ANSWER(T1)	;GET VALUE
	STOR T1,PJPRF,(P2)	;SAVE IT
	JRST LOGPRJ
;ROUTINE TO LIST A PROJECT

PRJLST:	MOVEI T1,.PRIOU		;TYPE OUT THE PROJECT
	MOVE T2,P2		;GET ADR OF PROJECT BLOCK
	CALL TYPPRJ		;OUTPUT THE PROJECT
	JRST UPDPRJ		;DONE

;ROUTINE TO TYPE OUT A PROJECT
;ACCEPTS IN T1/	OUTPUT JFN
;	    T2/	ADR OF THE PROJECT BLOCK

TYPPRJ:	SAVEPQ
	MOVE P1,T1		;SAVE THE JFN
	MOVE P2,T2		;GET THE PROJECT BLOCK ADR
	TYPE T1,<&PROJECT: >
	LOAD T2,PJNAM,(P2)	;GET PROJECT NAME
	CALL TYPSTR
	TYPE T1,<&PROJECT DESCRIPTION: >
	LOAD T2,PJDSC,(P2)	;GET PROJECT DESCRIPTION
	CALL TYPSTR
	LOAD T2,PJPRF,(P2)	;GET PREFERENCE
	JUMPE T2,TYPPR0		;IF NONE, SKIP THIS
	TYPE T1,<&	PREFERENCE VALUE: >
	CALL TYPFLT
TYPPR0:	LOAD T2,PJDVL,(P2)	;GET POINTER TO DEVELOPER LIST
	CALL TYPDEV		;TYPE OUT DEVELOPERS
	TYPE T1,<&>
	LOAD T2,PJTKT,(P2)	;GET POINTER TO TASK LIST
	MOVEI Q1,1(T2)		;GET POINTER TO FIRST TASK IN LIST
	HLRZ T2,0(T2)		;GET LENGTH OF TABLE
	MOVNS T2
	JUMPE T2,TYPPR2		;IF NONE, THEN DONE
	HRL Q1,T2		;FINISH MAKING AN AOBJN POINTER
TYPPR1:	HRRZ T2,0(Q1)		;GET NEXT TASK BLOCK ADR
	MOVE T1,P1		;GET JFN
	CALL TYPTSK		;TYPE OUT THIS TASK
	AOBJN Q1,TYPPR1		;LOOP BACK FOR ALL TASKS
TYPPR2:	RET			;DONE
;ROUTINE TO GET A DESCRIPTION 
;ACCEPTS IN T1/	POINTER TO THE PROMPT STRING
;	CALL GETDSC
;RETURNS +1:	FAILED
;	 +2:	OK,	T1/	ADDRESS OF DESCRIPTION BLOCK

GETDSC:	STKVAR <GETDSA>
	HRROI T2,STRING		;GET DESCRIPTION HERE
	MOVEI T3,STRNGC
	CALL GETSTR		;GET A STRING
	 RET
	MOVEI T2,.TYDSC		;NOW GET A BLOCK FOR IT
	MOVEI T3,.VNDSC		;THE NUMBER OF WORDS IS ALREADY IN T1
	CALL ASGFRE
	 RET			;FAILED TO GET SPACE
	MOVEM T1,GETDSA		;SAVE THE ADR
	HRLI T1,(POINT 7,0)	;SET UP A BYTE POINTER
	HRROI T2,STRING
	SETZ T3,
	SOUT			;COPY STRING INTO DESCRIPTION BLOCK
	MOVE T1,GETDSA		;RETURN ADR OF BLOCK IN T1
	RETSKP
;ROUTINE TO ENTER THE COMPLETION DATE

TKCD:	HLRZ T1,(P1)		;CHECK FOR DATE
	CHKTYP (TAD)
	HRRZ T1,(P1)		;GET POINTER TO THE DATE
	MOVE T1,ANSWER(T1)	;GET DATE
	CALL GETDAY		;GET THE CORRECTED DATE
	STOR T1,TKAFD,(P3)	;STORE ACTUAL FINISH DATE IN BLOCK
	JRST LOGTSK		;LOOP BACK FOR NEXT COMMAND


;ADD DEVELOPER TO TASK DATA BASE

TKDV:	HLRZ T1,(P1)		;GET TYPE CODE OF USER NAME
	CHKTYP (USR)
	HLRZ T1,1(P1)		;GET TYPE CODE OF RATE
	CHKTYP (FLT)
	HLRZ T1,2(P1)		;GET TYPE CODE OF HANDICAP
	CHKTYP (FLT)
	HRRZ T1,0(P1)		;GET USER NAME STRING
	HRROI T1,ANSWER+1(T1)
	HRRZ T2,1(P1)		;GET RATE
	MOVE T2,ANSWER(T2)
	HRRZ T3,2(P1)		;GET HANDICAP
	MOVE T3,ANSWER(T3)
	LOAD T4,TKDVL,(P3)	;GET ADR OF FIRST ADR IN LIST
	CALL BLDDEV		;GO BUILD A DEVELOPER BLOCK
	 WARN (<JRST UPDTSK>,<COULD NOT ADD THIS USER NAME TO TASK>)
	JUMPN T2,TKDV1		;IF NOT NEW, DONT ADD TO LIST AGAIN
	STOR P3,DVBKP,(T1)	;SAVE POINTER TO TASK
	LOAD T2,TKDVL,(P3)	;GET POINTER TO LIST
	STOR T2,DVLNK,(T1)	;MAKE THIS BLOCK POINT DOWN THE LIST
	STOR T1,TKDVL,(P3)	;MAKE TASK POINT TO THIS BLOCK
TKDV1:	JRST LOGTSK		;DONE
;ADD A DEPENDENCY TO A TASK

TKDP:	HLRZ T1,0(P1)		;GET TYPE CODE OF PROJECT NAME
	CHKTYP (KEY)
	HLRZ T1,1(P1)		;GET TYPE CODE OF TASK NAME
	CHKTYP (KEY)
	HRRZ Q2,0(P1)		;GET ADR OF PROJECT BLOCK
	HRRZ Q3,1(P1)		;GET ADR OF TASK BLOCK
	MOVE T1,P3		;NOW FIND OUT IF THIS DEPENDENCY 
	MOVE T2,Q3		;  ALREADY EXISTS
	CALL FNDDEP		;GO SCAN THE LIST
	 SKIPA			;NOT FOUND
	JRST TKDP1		;ALREADY THERE, DO NOTHING
	MOVEI T1,.DPLEN		;NOW GET SPACE FOR A DEPENDENCY BLOCK
	MOVEI T2,.TYDEP
	MOVEI T3,.VNDEP
	CALL ASGFRE
	 WARN (<JRST TKDP1>,<COULD NOT GET SPACE FOR DEPENDENCY BLOCK>)
	MOVE Q1,T1		;SAVE THE BLOCK ADDRESS
	STOR P3,DPTKP,(Q1)	;SAVE POINTER TO DEPENDENT TASK
	STOR Q3,DPBTK,(Q1)	;SAVE THE ADR OF THE BLOCKING TASK
	LOAD T1,TKDLP,(P3)	;NOW ADD THIS TO THE DEPENDENT LIST
	STOR T1,DPDLP,(Q1)	;MAKE THIS BLOCK POINT DOWN LIST
	STOR Q1,TKDLP,(P3)	;MAKE TASK BLOCK POINT TO THIS BLOCK
	LOAD T1,TKBLP,(Q3)	;GET HEAD OF BLOCKED TASK LIST 
	STOR T1,DPBLP,(Q1)	;MAKE DEP BLOCK POINT DOWN BLOCKED LIST
	STOR Q1,TKBLP,(Q3)	;ADD THIS BLOCK TO BLOCKED LIST
	SETZM NOLOOP		;MAY HAVE JUST CREATED A LOOP
TKDP1:	JRST LOGTSK		;DONE


;ESTIMATED TASK LENGTH

TKEL:	LDB T1,[POINT 9,0(P1),17]
	CHKTYP (NUM)
	HRRZ T1,(P1)		;GET THE LENGTH
	FLTR T1,ANSWER(T1)
	STOR T1,TKELN,(P3)	;SAVE THE TIME LENGTH
	JRST LOGTSK		;DONE


;FINALIZE THE CHANGES

TKFC:	JRST LOGLV0		;GO UPDATE THE DATA BASE
;STARTING DATE

TKSD:	HLRZ T1,(P1)		;GET TYPE CODE OF DATE
	CHKTYP (TAD)
	HRRZ T1,(P1)		;GET DATE
	MOVE T1,ANSWER(T1)
	CALL GETDAY		;GET THE CORRECTED DATE
	STOR T1,TKASD,(P3)	;STORE ACTUAL STARTING DATE
	JRST LOGTSK


;EXPECTED DATES

TKXD:	HLRZ T1,(P1)		;CHECK THE CODE
	CHKTYP (KEY)
	HRRZ Q1,(P1)		;GET INDEX VALUE
	HLRZ T1,1(P1)		;GET TYPE CODE OF SECOND ARGUMENT
	CHKTYP (TAD)
	HRRZ T1,1(P1)		;GET INDEX OF DATE
	MOVE T1,ANSWER(T1)	;GET DATE
	CALL GETDAY		;CONVERT IT TO DAY,,0
	XCT [	STOR T1,TKXCD,(P3)
		STOR T1,TKXSD,(P3)](Q1)
	JRST LOGTSK


;MINIMUM STARTING DATE

TKMD:	HLRZ T1,(P1)		;GET TYPE CODE OF DATE
	CHKTYP (TAD)
	HRRZ T1,(P1)		;GET DATE
	MOVE T1,ANSWER(T1)
	CALL GETDAY		;GET THE CORRECTED DATE
	STOR T1,TKMSD,(P3)	;STORE MINIMUM STARTING DATE
	JRST LOGTSK


;TASK DESCRIPTION

TKTD:	HRROI T1,[ASCIZ/TASK DESCRIPTION: /]
	CALL GETDSC		;GET A DESCRIPTION
	 WARN (<JRST UPDTSK>,<FAILED TO GET A DESCRIPTION BLOCK>)
	LOAD T2,TKDSC,(P3)	;SEE IF THERE ALREADY IS A DESCRIPTION
	STOR T1,TKDSC,(P3)	;STORE THE NEW DESCRIPTION
	SKIPE T1,T2
	CALL RELFRE		;IF ONE WAS THERE BEFORE, RELEASE IT
	JRST LOGTSK		;DONE
;TASK TIME-TO-DATE

TKTI:	LDB T1,[POINT 9,0(P1),17]
	CHKTYP (NUM)
	HLRZ T1,1(P1)		;GET TYPE CODE OF DATE
	CHKTYP (TAD)
	HRRZ T1,0(P1)		;GET TIME
	FLTR T1,ANSWER(T1)
	STOR T1,TKTTD,(P3)	;SAVE TIME TO DATE
	HRRZ T1,1(P1)		;GET THE DATE
	MOVE T1,ANSWER(T1)
	CALL GETDAY		;CONVERT IT TO DAY NUMBER ,, 0
	STOR T1,TKTAD,(P3)	;SAVE DATE
	JRST LOGTSK		;DONE


;MILESTONE

TKMI:	SETONE TKMIL,(P3)	;MARK THIS TASK AS A MILESTONE
	JRST LOGTSK

;ALL-DEVELOPERS-REQUIRED

TKAR:	SETONE TKADR,(P3)	;MARK SPECIAL SCHEDULING
	JRST LOGTSK

;TASK PREFERENCE VALUE


TKPF:	HLRZ T1,(P1)		;GET TYPE CODE
	CHKTYP (FLT)
	HRRZ T1,(P1)
	MOVE T1,ANSWER(T1)	;GET VALUE
	STOR T1,TKPRF,(P3)	;SAVE THE PREFERENCE VALUE
	JRST LOGTSK
;PATH-CHARACTER COMMAND

TKPTH:	HLRZ T1,(P1)		;GET TYPE CODE
	CHKTYP (FLD)
	HRRZ T1,(P1)		;GET POINTER TO ANSWER WORD
	MOVE T1,ANSWER(T1)	;GET FIRST WORD OF ANSWER
	ROT T1,7		;GET FIRST CHAR
	TLNE T1,774000		;DID USER GIVE MORE THAN ONE CHAR?
	JRST TKPTH1		;YES, ERROR
	ANDI T1,177		;CLEAR ALL BUT THE CHAR
	CAIL T1,"0"		;IS IT ALPHA-NUMERIC?
	CAILE T1,"Z"
	JRST TKPTH1
	CAILE T1,"9"
	CAIL T1,"A"
	SKIPA
	JRST TKPTH1		;NOT AN ALPHA NUMERIC CHAR
	STOR T1,TKPTC,(P3)	;STORE THE PATH CHAR
	JRST LOGTSK		;DONE

TKPTH1:	WARN (,<PATH CHARACTER MUST BE A SINGLE ALPHA-NUMERIC CHARACTER>)
	JRST UPDTSK
;ADD AN ATTRIBUTE
TKAT:	TDZA Q3,Q3		;SHORT ATTRIBUTE
TKLA:	MOVX Q3,AT%LNG		;ATTRIBUTE IS LONG
	CALL ATFLD		;GET ATTRIBUTE FROM FIELD
	  WARN (<JRST UPDTSK>,<ATTRIBUTE NAME CAN NOT BE NULL>)
	MOVE Q1,T1		;SAVE ADDRESS OF NAME
	TXNN Q3,AT%LNG		;LONG ATTRIBUTE?
	AOJA P1,[CALL ATFLD	;GET ATTRIBUTE OUT OF ANSWER BLOCK
		   WARN (<JRST UPDTSK>,<ATTRIBUTE VALUE CAN NOT BE NULL>)
		 MOVE Q2,T1	;SAVE ANSWER
		 JRST TKAT1]	;JOIN COMMON CODE
	HRROI T1,[ASCIZ "VALUE OF ATTRIBUTE (<ESC> WHEN DONE)"]
	CALL GETDSC		;GET THE TEXT
	  WARN (<JRST UPDTSK>,<CAN NOT CREATE BLOCK FOR ATTRIBUTE VALUE>)
	MOVE Q2,T1		;SAVE ADDRESS OF BLOCK
TKAT1:	CHKVER .VNTSK,(P3),VERERR
	MOVE T1,P3		;ADDRESS OF TASK BLOCK
	MOVE T2,Q1		;ATTRIBUTE NAME
	CALL FNDATR		;FIND THE ATTRIBUTE BLOCK
	  JRST TKAT2		;NOT FOUND--CREATE A NEW ONE
	LOAD T2,ATRVL,(T1)	;GET OLD VALUE
	STOR Q2,ATRVL,(T1)	;STORE NEW VALUE
	STOR Q3,ATRFL,(T1)	;SAVE FLAGS
	SKIPE T1,T2		;FREE UP STORAGE
	CALL RELFRE
	MOVE T1,Q1		;FREE UP NAME
	CALL RELFRE		; ..
	JRST LOGTSK		;ALL DONE

TKAT2:	MOVEI T1,.ATRLN
	MOVEI T2,.TYATR
	MOVEI T3,.VNATR
	CALL ASGFRE
	  WARN (<JRST UPDTSK>,<CAN NOT CREATE ATTRIBUTE BLOCK>)
	SETZRO ATRLK,(T1)	;CLEAR LINK
	STOR Q2,ATRVL,(T1)	;SAVE ATTRIBUTE VALUE
	STOR Q1,ATRNM,(T1)	;SAVE ATTRIBUTE NAME
	STOR Q3,ATRFL,(T1)	;SAVE FLAGS
	LOAD T2,TKATR,(P3)	;POINTER TO FIRST ATR BLOCK
	JUMPE T2,[		;IF NONE YET
		  STOR T1,TKATR,(P3) ;STORE THIS GUY
		  JRST LOGTSK]	;ALL DONE
TKAT3:	LOAD T3,ATRLK,(T2)	;GET LINK TO NEXT BLOCK
	JUMPE T3,[
		  STOR T1,ATRLK,(T2) ;POINT TO NEW BLOCK
		  JRST LOGTSK]	;ALL DONE
	MOVE T2,T3		;STEP TO NEXT BLOCK
	JRST TKAT3		;AND TRY AGAIN
;SUBROUTINE TO TAKE A FIELD AND STORE IT IN THE DATABASE
;CALL WITH:
;	P1/ INDEX TO ANSWER
;	CALL ATFLD
;	  FAILED
;	OK--ADDRESS IN T1
ATFLD:	SAVEPQ
	HLRZ T1,(P1)		;MAKE SURE WE HAAVE A FIELD
	CHKTYP (FLD)
	HRRZ Q1,(P1)		;POINTER TO ASCIZ STRING
	ADDI Q1,ANSWER		; ..
	MOVSI T2,(POINT 7,0)	;BYTE POINTER TO STRING
	ADD T2,Q1		; ..
	MOVEI T1,0		;LENGTH OF STRING
	ILDB T3,T2		;GET A BYTE
	SKIPE T3		;DONE?
	AOJA T1,.-2		;NO--SCAN STRING
	SKIPN T1		;MUST BE SOME
	RET			;NAME CAN NOT BE NULL
	IDIVI T1,5		;CONVERT TO WORDS
	ADDI T1,1		;ROUND UP
	MOVEI T2,.TYDSC		;CREATE A BLOCK
	MOVEI T3,.VNDSC		;VERSION NUMBER
	CALL ASGFRE		;ASSIGN THE SPACE
	  RET
	MOVE Q2,T1		;SAVE ADDRESS
	HRLI T1,(POINT 7,0)	;MAKE BYTE POINTER
	HRRO T2,Q1		;POINTER TO SOURCE
	SETZ T3,
	SOUT
	MOVE T1,Q2		;RETURN ADDRESS
	RETSKP
;SUBROUTINE TO FIND AN ATTRIBUTE
;CALL WITH:
;	T1/ ADDRESS OF TASK BLOCK
;	T2/ NAME OF ATTRIBUTE
;RETURNS:
;	+1 ATTRIBUTE NOT FOUND
;	+2 WITH T1/ ADDRESS OF ATTRIBUTE BLOCK
;
FNDATR:	SAVEQ
	DMOVE Q1,T1		;SAVE ARGUMENTS
	LOAD Q3,TKATR,(Q1)	;FIRST NAME
FNATR1:	JUMPE Q3,R		;NOT FOUND IF NULL
	LOAD T1,ATRNM,(Q3)	;THIS ATR'S NAME
	TLO T1,(POINT 7,0)	;MAKE BYTE POINTER
	HRRO T2,Q2		;WHAT WE ARE LOOKING FOR
	STCMP			;COMPARE
	JUMPE T1,[MOVE T1,Q3	;RETURN ADDRESS
		  RETSKP]	;SKIP
	LOAD Q3,ATRLK,(Q3)	;FOLLOW CHAIN
	JRST FNATR1		;LOOP BACK
;THE DELETE COMMAND

TKDL:	HLRZ T1,(P1)		;CHECK THE TYPE CODE
	CHKTYP (KEY)
	HRRZ T1,(P1)		;GET THE DISPATCH ADR
	AOJA P1,(T1)		;DISPATCH

;ROUTINE TO DELETE A DEVELOPER FROM A TASK LIST

TKDLD:	HLRZ T1,(P1)		;CHECK THE TYPE CODE
	CHKTYP (USR)
	HRRZ T1,(P1)		;GET USER NUMBER
	HRROI T1,ANSWER+1(T1)	;GET POINTER TO NAME STRING
	LOAD T2,TKDVL,(P3)	;GET THE FIRST ADR IN DEVELOPER LIST
	CALL DELDEV		;DELETE THIS DEVELOPER
	 WARN (<JRST UPDTSK>,<COULD NOT DELETE THIS DEVELOPER FROM LIST>)
	STOR T1,TKDVL,(P3)	;STORE THE UPDATED LIST POINTER
	JRST LOGTSK		;DONE


;ROUTINE TO DELETE A DEPENDENCY

TKDDP:	HLRZ T1,(P1)		;GET TYPE CODE
	CHKTYP (KEY)
	HLRZ T1,1(P1)		;SECOND ARG
	CHKTYP (KEY)
	HRRZ T2,1(P1)		;GET ADR OF TASK
	MOVE T1,P3		;GET ADR OF THIS TASK
	CALL FNDDEP		;FIND THE DEPENDENCY BLOCK
	 JRST TKDDP1		;NOT FOUND
	CALL RELDEP		;GO RELEASE THE BLOCK
TKDDP1:	JRST LOGTSK		;DONE
;DELETE COMPLETION DATE

TKDCD:	SETZRO TKAFD,(P3)		;ZERO COMPLETION DATE
	JRST LOGTSK


;DELETE ESTIMATED LENGTH

TKDEL:	SETZRO TKELN,(P3)
	JRST LOGTSK


;DELETE EXPECTED DATES

TKDXD:	HLRZ T1,(P1)		;GET TYPE CODE
	CHKTYP (KEY)
	HRRZ T1,(P1)		;GET THE INDEX VALUE
	XCT [	SETZRO TKXCD,(P3)
		SETZRO TKXSD,(P3)](T1)
	JRST LOGTSK


;DELETE MINIMUM STARTING DATE

TKDMD:	SETZRO TKMSD,(P3)
	JRST LOGTSK


;DELETE PREFERENCE VALUE

TKDPF:	SETZRO TKPRF,(P3)
	JRST LOGTSK


;DELETE STARTING DATE

TKDSD:	SETZRO TKASD,(P3)
	JRST LOGTSK


;DELETE TIME TO DATE

TKDTI:	SETZRO TKTTD,(P3)
	SETZRO TKTAD,(P3)
	JRST LOGTSK


;DELETE PATH-CHARACTER

TKDPC:	SETZRO TKPTC,(P3)	;ZERO THE PATH CHARACTER
	JRST LOGTSK
;ROUTINE TO LIST INFO ABOUT A TASK

TKLS:	CALL SCHWRN		;WARN HIM IF DATES ARE BAD
	MOVEI T1,.PRIOU		;OUTPUT TASK LIST TO TTY
	MOVE T2,P3		;GET ADR OF TASK BLOCK
	CALL TYPTSK		;GO TYPE OUT THE TASK INFO
	JRST UPDTSK		;DONE

;ROUTINE TO TYPE OUT A TASK
;ACCEPTS IN T1/	OUTPUT JFN
;	    T2/	ADR OF TASK BLOCK

TYPTSK:	SAVEP
	MOVE P3,T2		;SAVE THE TASK BLOCK ADR
	LOAD P2,TKPRJ,(P3)	;SET UP THE PROJECT BLOCK ADR
	MOVE P1,T1		;SAVE THE JFN
	TYPE T1,<&>
	LOAD T2,PJNAM,(P2)	;GET PROJECT NAME
	CALL TYPSTR		;TYPE IT
	TYPE T1,</>
	LOAD T2,TKNAM,(P3)	;GET ADR OF TASK NAME
	CALL TYPSTR
	TYPE T1,<&	TASK DESCRIPTION: >
	LOAD T2,TKDSC,(P3)	;GET ADR OF TASK DESCRIPTION
	CALL TYPSTR
	LOAD T2,TKFLG,(P3)	;GET THE FLAGS
	TXNE T2,TK%CP		;THIS TASK ON THE CRITICAL PATH?
	TYPE T1,<&	THIS TASK IS ON THE OVERALL CRITICAL PATH>
	LOAD T2,TKPTC,(P3)	;PATH CHAR?
	JUMPE T2,TKLS6
	TYPE T1,<&	PATH CHARACTER: >
	BOUT
TKLS6:	LOAD T3,TKPL,(P3)	;GET POINTER TO PATH LIST
	JUMPE T3,TKLS8		;IF ANY
	HRLI T3,(POINT 7,0)
	ILDB T2,T3		;GET FIRST CHAR
	JUMPE T2,TKLS8		;IF ANY
	TYPE T1,<&	CRITICAL PATHS: >
TKLS7:	BOUT			;OUTPUT THE PATH THIS TASK IS ON
	ILDB T2,T3		;GET NEXT PATH CHAR
	JUMPE T2,TKLS8		;IF NONE, THEN DONE
	TYPE T1,<, >
	JRST TKLS7		;LOOP BACK FOR REST OF CHARS
	; ..
	; ..
TKLS8:	LOAD T2,TKFLG,(P3)
	TXNE T2,TK%MIL		;MILESTONE?
	TYPE T1,<&	MILESTONE>
	LOAD T2,TKFLG,(P3)	;ALL-DEVELOPERS-REQUIRED?
	TXNE T2,TK%ADR
	TYPE T1,<&	ALL-DEVELOPERS-REQUIRED>
	LOAD T2,TKPRF,(P3)	;GET THE PREFERENCE VALUE
	JUMPE T2,TKLS5		;IF NONE, SKIP IT
	TYPE T1,<&	PREFERENCE VALUE: >
	CALL TYPFLT
TKLS5:	LOAD T2,TKSLK,(P3)	;GET THE SLACK
	CAMN T2,[NOSLAK]	;ANY SET?
	JRST TKLS9		;NO
	TYPE T1,<&	SLACK: >
	MOVEI T3,^D10		;DECIMAL
	CALL TYPNUM		;OUTPUT THE SLACK
TKLS9:	TYPE T1,<&	ACTUAL STARTING DATE: >
	LOAD T2,TKASD,(P3)	;GET STARTING DATE
	CALL TYPDAT
	TYPE T1,<&	ACTUAL COMPLETION DATE: >
	LOAD T2,TKAFD,(P3)	;GET COMPLETION DATE
	CALL TYPDAT
	TYPE T1,<&	MINIMUM STARTING DATE: >
	LOAD T2,TKMSD,(P3)	;GET MINIMUM START DATE
	CALL TYPDAT
	LOAD T2,TKXSD,(P3)	;GET EXPECTED START
	JUMPE T2,TKLS3		;IF NONE, SKIP IT
	TYPE T1,<&	EXPECTED STARTING DATE: >
	CALL TYPDAT
TKLS3:	LOAD T2,TKXCD,(P3)	;GET EXPECTED COMPLETION DATE
	JUMPE T2,TKLS4		;IF NONE, SKIP IT
	TYPE T1,<&	EXPECTED COMPLETION DATE: >
	CALL TYPDAT
TKLS4:	TYPE T1,<&	ESTIMATED STARTING DATE: >
	LOAD T2,TKESD,(P3)	;GET ESTIMATED STARTING DATE
	CALL TYPDAT
	TYPE T1,<&	ESTIMATED COMPLETION DATE: >
	LOAD T2,TKEFD,(P3)	;GET ESTIMATED COMPLETION DATE
	CALL TYPDAT
	TYPE T1,<&	ESTIMATED TASK LENGTH (IN DAYS): >
	LOAD T2,TKELN,(P3)	;GET ESTIMATED TASK LENGTH
	CALL TYPFLT
	; ..
	; ..
	LOAD T2,TKALN,(P3)	;GET ACTUAL LENGTH
	SKIPE T2		;IF NOT SET, DONT TYPE IT
	TYPE T1,<&	ACTUAL TASK LENGTH: >
	LOAD T2,TKALN,(P3)	;GET ACTUAL TASK LENGTH
	SKIPE T2
	CALL TYPFLT
	LOAD T2,TKTAD,(P3)	;GET DATE
	JUMPE T2,[TYPE T1,<&	TIME SPENT ON TASK: 0>
		JRST TKLS0]
	TYPE T1,<&	TIME SPENT ON TASK UP TO >
	LOAD T2,TKTAD,(P3)	;GET CURRENT DATE
	CALL TYPDAT
	TYPE T1,< WAS: >
	LOAD T2,TKTTD,(P3)	;GET TIME TO DATE
	CALL TYPFLT
TKLS0:	MOVE T2,P3		;COPY POINTER
	CALL TYPATR		;TYPE OUT THE ATTRIBUTES
	LOAD T2,TKDLP,(P3)	;GET POINTER TO DEPENDENCY LIST
	JUMPE T2,TKLS1		;IF NONE, SKIP THIS PART
	TYPE T1,<&	TASKS BLOCKING THIS TASK: >
	LOAD T2,TKDLP,(P3)	;GET POINTER TO DEPENDENCY LIST
	CALL TYPDEP		;TYPE OUT DEPENDENCIES
TKLS1:	LOAD T2,TKBLP,(P3)	;SEE IF THIS TASK IS BLOCKING OTHERS
	JUMPE T2,TKLS2		;IF NO, DONT TYPE ANYTHING
	TYPE T1,<&	TASKS BEING BLOCKED BY THIS TASK: >
	LOAD T2,TKBLP,(P3)
	CALL TYPBLK		;TYPE OUT NAMES
TKLS2:	LOAD T2,TKDVL,(P3)	;GET POINTER TO DEVELOPER LIST
	CALL TYPDEV		;TYPE OUT DEVELOPERS
	TYPE T1,<&>
	RET			;DONE
;SUBROUTINE TO TYPE OUT ALL THE ATTRIBUTES FOR A TASK
;CALL WITH:
;	T1/ JFN
;	T2/ ADDRESS OF TASK BLOCK
;	CALL TYPATR
;
TYPATR:	SAVEQ
	DMOVE Q1,T1		;SAVE ARGUMENTS
	CHKVER .VNTSK,(Q2),R	;NONE IF OLD DATA BASE
	LOAD Q3,TKATR,(Q2)	;START OF CHAIN
TYATR1:	JUMPE Q3,R		;EXIT AT END OF CHAIN
	TYPE Q1,<&	>	;LEAD OFF WITH CRLF TAB
	MOVE T1,Q1		;COPY JFN
	LOAD T2,ATRNM,(Q3)	;ATTRIBUTE NAME
	CALL TYPSTR		;TYPE IT
	TYPE Q1,<:>		;ADD A COLON
	LOAD T3,ATRFL,(Q3)	;GET FLAGS
	MOVE T2,[POINT 7,[ASCIZ "	"]]
	TXNE T3,AT%LNG		;LONG ATTRIBUTE
	MOVE T2,[POINT 7,[ASCIZ "
"]]
	CALL TYPSTR
	LOAD T2,ATRVL,(Q3)	;POINTER TO VALUE
	CALL TYPSTR
	LOAD Q3,ATRLK,(Q3)	;FOLLOW CHAIN
	JRST TYATR1		;LOOP BACK
;ROUTINE TO BUILD A DEVELOPER BLOCK
;ACCEPTS IN T1/	USER NAME STRING POINTER
;	    T2/	RATE
;	    T3/	HANDICAP
;	    T4/	ADR OF FIRST DEVELOPER BLOCK IN THE LIST
;	CALL BLDDEV
;RETURNS +1:	FAILED
;	 +2:	T1/	ADR OF DEVELOPER BLOCK
;		T2/	0 = NEW BLOCK, -1 = EXISTED BEFORE

BLDDEV:	SAVEQ
	STKVAR <BLDDVF,BLDDVR,BLDDVH,BLDDVP,<BLDDVS,11>,BLDDVC,BLDDVA>
	MOVEM T2,BLDDVR		;SAVE THE RATE
	MOVEM T3,BLDDVH		;SAVE THE HANDICAP
	MOVEM T4,BLDDVA		;SAVE ADR OF FIRST ITEM IN LIST
	SETOM BLDDVF		;INITIALIZE THE FLAG WORD
	HRROI T2,BLDDVS		;GET POINTER TO NAME STRING SPACE
	SETZ T3,
	SIN			;COPY NAME TO BLDDVS
	IBP T2			;CALCULATE THE STRING LENGTH
	HRRZS T2
	SUBI T2,BLDDVS		;INCLUDING THE NULL
	AOS T2			;PLUS ONE FOR FIRST WORD
	MOVEM T2,BLDDVC		;SAVE COUNT
	HRROI T1,BLDDVS		;GET POINTER TO NAME STRING
	MOVE T2,BLDDVA		;GET ADR OF FIRST ITEM IN LIST
	CALL CHKDEV		;SEE IF THIS NAME IS ALREADY IN LIST
	 SKIPA T1,BLDDVC	;NO, GO ADD IT TO LIST
	JRST BLDDV1		;YES, JUST GO UPDATE THE DATA
	MOVEI T2,.TYNAM		;NOW GET A BLOCK FOR THE NAME
	MOVEI T3,.VNNAM
	CALL ASGFRE
	 WARN (<RET>,<COULD NOT GET SPACE FOR USER NAME>)
	MOVE Q1,T1		;SAVE THE NAME BLOCK ADDRESS
	HRLI T1,(POINT 7,0)	;BUILD A STRING POINTER TO THE BLOCK
	HRROI T2,BLDDVS
	SETZ T3,
	SOUT			;COPY NAME STRING INTO NAME BLOCK
	MOVEI T1,.DVLEN		;NOW GET THE DEVELOPER BLOCK
	MOVEI T2,.TYDEV
	MOVEI T3,.VNNAM
	CALL ASGFRE
	 WARN (<MOVE T1,Q1	;RETURN THE NAME BLOCK
		CALL RELFRE
		RET>,<COULD NOT GET SPACE FOR DEVELOPER BLOCK>)
	STOR Q1,DVNAM,(T1)	;STORE NAME STRING
	SETZM BLDDVF		;MARK THAT A NEW BLOCK WAS MADE
	;..
	;..
BLDDV1:	MOVE T2,BLDDVR		;GET RATE
	STOR T2,DVRAT,(T1)	;SAVE RATE
	MOVE T2,BLDDVH		;GET HANDICAP
	STOR T2,DVHCR,(T1)	;SAVE HANDICAP
	MOVE T2,BLDDVF		;RETURN FLAG IN T2
	RETSKP			;DONE


;ROUTINE TO SEE IF A NAME IS ON THE LIST ALREADY
;ACCEPTS IN T1/	STRING POINTER TO THE NAME
;	    T2/	ADR OF FIRST BLOCK IN THE LIST
;	CALL CHKDEV
;RETURNS +1:	NOT IN LIST
;	 +2:	T1/	ADR OF DEV BLOCK OF MATCHING USER
;		T2/	ADR OF PREVIOUS BLOCK OR
;			0 IF THIS WAS THE FIRST ON THE LIST

CHKDEV:	SAVEQ
	DMOVE Q1,T1		;SAVE ARGUMENTS
	SETZ Q3,		;INIT THE PREVIOUS BLOCK ADR
CHKDV1:	JUMPE Q2,R		;IF NO MORE IN LIST, THEN NOT FOUND
	LOAD T1,DVNAM,(Q2)	;GET ADR OF NAME STRING
	HRLI T1,(POINT 7,0)
	MOVE T2,Q1		;GET POINTER TO ARGUMENT STRING
	STCMP			;COMPARE THEM
	JUMPE T1,CHKDV2		;IF A MATCH, GO RETURN ADR OF BLOCK
	MOVE Q3,Q2		;SAVE THE ADR OF THE PREVIOUS BLOCK
	LOAD Q2,DVLNK,(Q2)	;STEP TO NEXT ITEM IN LIST
	JRST CHKDV1

CHKDV2:	MOVE T1,Q2		;RETURN ADR OF BLOCK IN T1
	MOVE T2,Q3		;GET ADR OF PREVIOUS BLOCK
	RETSKP
;ROUTINE TO ADD A PROJECT TO THE DATA BASE
;ACCEPTS IN T1/	ADR OF PROJECT NAME STRING
;	CALL ADDPRJ
;RETURNS +1:	COULD NOT ADD IT
;	 +2:	OK, T1/	ADR OF PROJECT BLOCK
;			T2/	NEW ADDRESS OF PROJECT TABLE

ADDPRJ:	STKVAR <ADDPRN,ADDPRB,ADDPRT,ADDPRD,ADDPRP,ADDPPT>
	MOVEM T1,ADDPRN		;SAVE THE ADR OF THE NAME STRING
	MOVE T4,0(T1)		;CHECK FOR NULL STRING
	TLNN T4,774000
	RET			;NUL NAME IS NOT ALLOWED
	MOVE T2,PRJTBL		;GET ADDRESS OF THE TABLE
	CALL CHKTAB		;SEE IF THIS PROJECT IS ALREADY IN TABLE
	 JRST ADDPR1		;IT ISNT
	WARN (<RET>,<PROJECT ALREADY EXISTS>)
ADDPR1:	HRROI T1,[ASCIZ/PROJECT DESCRIPTION: /]
	CALL GETDSC		;GET THE DESCRIPTION
	 RET			;FAILED
	MOVEM T1,ADDPRD		;SAVE ADR OF DESCRIPTION STRING
	MOVEI T1,TABINC		;NOW CREATE AN EMPTY TASK TABLE
	MOVEI T2,.TYTKT
	MOVEI T3,.VNTKT
	CALL CRTTAB		;GO CREATE THE TASK TABLE
	 RET			;FAILED
	MOVEM T1,ADDPRT		;SAVE THE TASK TABLE ADR
	MOVEI T1,.PJLEN		;NOW GET THE PROJECT BLOCK
	MOVEI T2,.TYPRJ
	MOVEI T3,.VNPRJ
	CALL ASGFRE
	 RET
	MOVEM T1,ADDPRP		;SAVE THE PROJECT BLOCK ADR
	MOVE T2,ADDPRD		;GET ADR OF DESCRIPTION
	STOR T2,PJDSC,(T1)	;SAVE IT IN PROJECT BLOCK
	MOVE T2,ADDPRT		;GET TASK TABLE
	STOR T2,PJTKT,(T1)	;SAVE IT THE PROJECT BLOCK
	MOVE T1,ADDPRN		;GET NAME BLOCK ADR
	MOVE T2,ADDPRP		;GET ADR OF PROJECT BLOCK
	MOVE T3,PRJTBL		;GET ADR OF PROJECT TABLE
	CALL ADDNAM		;ADD THIS PROJECT TO THE TABLE
	 RET			;FAILED TO ADD IT
	MOVEM T1,ADDPPT		;SAVE THE ADR OF THE PROJECT TABLE
	MOVE T1,ADDPRP		;GET ADR OF PROJECT BLOCK
	STOR T2,PJNAM,(T1)	;STORE POINTER TO NAME BLOCK
	MOVE T2,ADDPPT		;GET ADR OF PROJECT BLOCK
	RETSKP			;ALL DONE
;ROUTINE TO ADD A TASK TO A TASK TABLE
;ACCEPTS IN T1/	ADR OF TASK NAME STRING
;	    T2/	ADR OF PROJECT BLOCK
;	    T3/	ADR OF TASK TABLE
;	CALL ADDTSK
;RETURNS +1:	COULD NOT ADD IT
;	 +2:	OK, T1/	ADR OF TASK BLOCK
;		T2/	NEW ADR OF TASK TABLE

ADDTSK:	STKVAR <ADDTKN,ADDTKB,ADDTKT,ADDTKD,ADDTKP,ADDTKJ>
	MOVEM T1,ADDTKN		;SAVE THE ADR OF THE NAME STRING
	MOVEM T2,ADDTKJ		;SAVE ADR OF PROJECT BLOCK
	MOVEM T3,ADDTKT		;SAVE THE ADR OF THE TASK TABLE
	MOVE T4,0(T1)		;CHECK FOR NULL STRING
	TLNN T4,774000
	RET			;NUL NAME IS NOT ALLOWED
	MOVE T2,ADDTKT		;GET ADR OF TASK TABLE
	CALL CHKTAB		;SEE IF THIS TASK ALREADY EXISTS
	 JRST ADDTK1		;IT DOESNT
	WARN (<RET>,<TASK ALREADY EXISTS>)
ADDTK1:	HRROI T1,[ASCIZ/TASK DESCRIPTION: /]
	CALL GETDSC		;GET THE DESCRIPTION
	 RET			;FAILED
	MOVEM T1,ADDTKD		;SAVE ADR OF DESCRIPTION STRING
	MOVEI T1,.TKLEN		;NOW GET THE TASK BLOCK
	MOVEI T2,.TYTSK
	MOVEI T3,.VNTSK
	CALL ASGFRE
	 RET
	MOVEM T1,ADDTKP		;SAVE THE TASK BLOCK ADR
	SETZRO TKDLP,(T1)	;INIT DEPENDENCY LIST POINTER
	SETZRO TKBLP,(T1)	;AND BLOCKED LIST
	MOVE T2,ADDTKJ		;GET ADR OF PROJECT BLOCK
	STOR T2,TKPRJ,(T1)	;SAVE IT IN THE TASK BLOCK
	MOVE T2,ADDTKD		;GET ADR OF DESCRIPTION
	STOR T2,TKDSC,(T1)	;SAVE IT IN TASK BLOCK
	MOVE T1,ADDTKN		;GET NAME BLOCK ADR
	MOVE T2,ADDTKP		;GET ADR OF TASK BLOCK
	MOVE T3,ADDTKT		;GET ADR OF TASK TABLE
	CALL ADDNAM		;ADD THIS TASK TO THE TABLE
	 RET			;FAILED TO ADD IT
	MOVEM T1,ADDTKT		;SAVE THE ADR OF THE TASK TABLE
	MOVE T1,ADDTKP		;GET ADR OF TASK BLOCK
	STOR T2,TKNAM,(T1)	;STORE POINTER TO TASK NAME
	MOVE T2,ADDTKT		;GET NEW ADR OF TASK TABLE
	RETSKP			;ALL DONE
;ROUTINE TO OPEN THE DATA BASE FILE
;ACCEPTS IN T1/	POINTER TO THE PROMPT STRING
;	CALL OPNFIL
;RETURNS +1:	FAILED, ERROR CODE IN T1
;	 +2:	DONE - 	T1/	JFN OF DATA BASE FILE
;			T2/	JFN OF TRANSACTION LOG FILE

OPNFIL:	STKVAR <OPNFIJ,OPNFIE,<OPNFIS,20>>
	MOVE T2,[GTJBLK,,GTJBLK+1]
	SETZM GTJBLK		;INITIALIZE GTJFN BLOCK
	BLT T2,GTJBLK+GTJBLN-1
	MOVEM T1,GTJBLK+.GJRTY	;SAVE PROMPT IN ^R BUFFER
OPNFI1:	PSOUT			;TYPE OUT THE PROMPT
	PBIN			;GET BYTE FROM TTY
	CAIN T1,"?"		;DOES HE WANT HELP
	JRST OPNHLP		;YES--HELP HIM
	MOVX T1,.PRIIN		;NO--BACKUP JFN
	BKJFN
	HRROI T1,[ASCIZ/PANTT/]	;SET UP DEFAULT FILE NAME
	MOVEM T1,GTJBLK+.GJNAM	; TO BE "PANTT.DATA-BASE"
	HRROI T1,[ASCIZ/DATA-BASE/]
	MOVEM T1,GTJBLK+.GJEXT
	MOVEI T1,GTJBLN-.GJF2-1	;SET UP EXTENDED GTJFN BLOCK
	MOVEM T1,GTJBLK+.GJF2
	MOVX T1,GJ%CFM!GJ%XTN	;SET UP FLAGS
	MOVEM T1,GTJBLK+.GJGEN
	MOVE T1,[.PRIIN,,.PRIOU]
	MOVEM T1,GTJBLK+.GJSRC	;SET UP TO GET INPUT FROM TTY
	SETZ T2,		;NO MAIN STRING POINTER
	MOVEI T1,GTJBLK
	GTJFN			;GET A JFN ON THE DATA BASE FILE
	 RET			;FAILED
	MOVEM T1,OPNFIJ		;SAVE THE JFN
	MOVE T2,[440000,,OF%RD!OF%WR!OF%THW!OF%DUD]
	OPENF			;OPEN THE DATA BASE FILE
	 JRST [ CAIN T1,OPNX4	;NEED TO BE ABLE TO WRITE?
		JRST OPNRED	;YES--TRY TO OPEN READ ONLY
		MOVEM T1,OPNFIE	;FAILED, SAVE THE ERROR CODE
		MOVE T1,OPNFIJ	;GET BACK THE JFN
		RLJFN		;RELEASE IT
		 JFCL
		MOVE T1,OPNFIE	;GET BACK ERROR CODE
		RET]
	HRROI T1,[ASCIZ/TRANSACTION-LOG/]
	MOVEM T1,GTJBLK+.GJEXT	;SET UP EXT OF TRANSACTION LOG FILE
	MOVE T1,[377777,,377777]
	MOVEM T1,GTJBLK+.GJSRC	;GET FILE NAME FROM STRING ONLY
	HRROI T1,OPNFIS		;NOW GET THE FILE NAME
	MOVE T2,OPNFIJ		;FROM THE DATA BASE JFN
	MOVE T3,[111000,,1]	;GET STR:<DIR>NAME
	JFNS
	MOVEI T1,GTJBLK		;NOW GET JFN ON TRANSACTION LOG FILE
	HRROI T2,OPNFIS
	GTJFN
	 WARN (<MOVEI T1,0>,<COULD NOT OPEN TRANSACTION LOG FILE>)
	MOVE T2,T1		;RETURN JFN IN T2
	MOVE T1,OPNFIJ		;AND DATA BASE JFN IN T1
	SETZM TRAFLG		;MARK THAT THIS IS FIRST TIME THRU
	RETSKP			;DONE

OPNRED:	MOVE T1,OPNFIJ		;GET JFN
	MOVX T2,OF%RD		;JUST WANT TO READ
	OPENF			;OPEN THE FILE
	  RET			;FAILED
	TMSG <
% File is READ-ONLY. No changes will update the database.

>
	SETOM RONLY		;FLAG READ ONLY
	SETOM SLOB		;NO NEED TO DO UFPGS
	MOVE T1,OPNFIJ		;GET JFN
	MOVX T2,.NULIO		;NO LOG NEEDED.
	RETSKP

OPNHLP:	TMSG <
Enter the name of an existing PANTT data base or a new
data dase you want to create.
>
	MOVE T1,GTJBLK+.GJRTY	;POINTER TO PROMPT
	JRST OPNFI1		;TRY AGAIN
;ROUTINE TO MAP IN THE DATA BASE FILE
;ACCEPTS IN T1/	JFN OF THE DATA BASE FILE
;	    T2/	PAGE NUMBER OF WHERE TO MAP THE FIRST PAGE
;	    T3/	MAXIMUM NUMBER OF PAGES TO MAP
;	CALL MAPFIL
;RETURNS +1:	FILE TOO LARGE TO FIT IN DESIGNATED AREA
;	 +2:	OK

MAPFIL:	STKVAR <MAPFLJ,MAPFLC>
	MOVEM T1,MAPFLJ		;SAVE THE JFN
	MOVEM T3,MAPFLC		;SAVE THE COUNT OF PAGES
	HRLZS T1		;SET UP FOR PMAP
	HRLI T2,.FHSLF
	HRLI T3,(PM%CNT!PM%RD!PM%WR)
	SKIPE RONLY		;READ ONLY
	TXC T3,PM%WR!PM%CPY	;YES--CLEAR WRITE AND SET COPY-ON-WRITE
	PMAP			;MAP IN THE FILE
	HRR T1,MAPFLC		;GET THE COUNT AGAIN
	HRL T1,MAPFLJ		;AND THE JFN
	FFUFP			;SEE IF THERE ARE ANY PAGES AFTER HERE
	CAIE T1,FFUFX3		;THE DESIRED ERROR CODE IF NONE LEFT
	RET			;THERE WERE MORE PAGES IN THE FILE
	HRLZ T1,MAPFLJ		;SEE IF THE FIRST PAGE OF THE FILE EXISTS
	RPACS
	TXNE T2,PA%PEX
	RETSKP			;FIRST PAGE EXISTS, DO NOT INITIALIZE
	MOVEI T1,DBORG		;SET UP PAGE 0 WORDS
	MOVEM T1,DBORG
	MOVEI T1,NDBPAG		;NUMBER OF PAGES IN DATA BASE
	MOVEM T1,DBSIZ
	CALL FSHDR		;NEW DATA BASE FILE, GO INIT FREE POOL
	MOVEI T1,TABINC		;AND BUILD AN EMPTY PROJECT TABLE
	MOVEI T2,.TYPJT		;BLOCK TYPE IS "PROJECT TABLE"
	MOVEI T3,.VNPJT
	CALL CRTTAB		;CREATE A NEW TABLE
	 ERRMES (<COULD NOT INITIALIZE THE DATA BASE FILE>)
	MOVEM T1,PRJTBL		;SAVE THE POINTER TO THE PROJECT TABLE
	HRROI T1,[ASCIZ/[NEW DATA BASE FILE INITIALIZED]
/]
	PSOUT
	RETSKP			;THE WHOLE FILE IS MAPPED


;ROUTINE TO UNMAP THE DATA BASE FILE

UNMAP:	SETO T1,		;UNMAP THE WHOLE DATA BASE AREA
	MOVE T2,[.FHSLF,,DBPAG]
	MOVE T3,[PM%CNT+NDBPAG]
	PMAP
	RET			;RETURN +1 ALWAYS
;ROUTINE TO ADD A NAME TO A TABLE
;THIS ROUTINE WILL EXPAND THE TABLE IF NECESSARY
;ACCEPTS IN T1/	ADDRESS OF THE NAME STRING
;	    T2/	DATA FOR THE RH OF TABLE ENTRY
;	    T3/	ADDRESS OF THE TABLE
;	CALL ADDNAM
;RETURNS +1:	COULD NOT EXPAND THE TABLE
;	 +2:	OK, T1/	NEW ADDRESS OF THE TABLE
;			T2/	ADDRESS OF NAME BLOCK

ADDNAM:	STKVAR <ADDNMS,ADDNMT,ADDNMD,ADDNMF>
	MOVEM T1,ADDNMS		;SAVE ADR OF NAME STRING
	MOVEM T2,ADDNMD		;SAVE THE DATA
	MOVEM T3,ADDNMT		;SAVE THE ADR OF THE TABLE
	HRLI T1,(POINT 7,0)	;SET UP A BYTE POINTER TO THE STRING
	SETZ T2,		;INITIALIZE COUNT OF CHARACTERS IN NAME
ADDNM1:	ILDB T3,T1		;COUNT THE CHARACTERS IN THE NAME
	AOS T2
	JUMPN T3,ADDNM1		;IF NOT AT END, LOOP BACK TILL NULL
	IDIVI T2,5		;GET NUMBER OF WORDS IN NAME STRING
	SKIPE T3		;ANY REMAINDER?
	AOS T2			;YES, COUNT THE EXTRA WORD
	MOVE T1,T2		;NOW GET SOME FREE SPACE FOR NAME
	MOVEI T2,.TYNAM		;THIS IS A NAME BLOCK
	MOVEI T3,.VNNAM		;VERSION NUMBER
	CALL ASGFRE		;GET A BLOCK
	 RET			;NO MORE ROOM
	MOVEM T1,ADDNMF		;REMEMBER ADR OF FREE BLOCK
	HRLI T1,(POINT 7,0)	;NOW COPY THE NAME STRING INTO THE BLOCK
	HRRO T2,ADDNMS		;GET A POINTER TO THE STRING
	SETZ T3,
	SOUT			;COPY STRING TO FREE BLOCK
	MOVE T1,ADDNMT		;NOW ADD THE ENTRY TO THE TABLE
	CALL CHKTBS		;FIRST SEE IF TABLE NEEDS EXPANDING
	 JRST ADDNM2		;COULD NOT EXPAND THE TABLE
	MOVEM T1,ADDNMT		;SAVE NEW ADR OF TABLE
	HRLZ T2,ADDNMF		;SET UP THE ENTRY IN THE TABLE
	HRR T2,ADDNMD		;ADD IN THE RH OF THE ENTRY
	TBADD			;ADD THIS ENTRY TO THE TABLE
	 ERJMP ADDNM2		;FAILED
	MOVE T1,ADDNMT		;RETURN THE ADDRESS OF THE TABLE
	MOVE T2,ADDNMF		;GET POINTER TO NAME STRING IN T2
	RETSKP			;ALL DONE

ADDNM2:	MOVE T1,ADDNMF		;RELEASE THE FREE BLOCK
	CALL RELFRE		;...
	RET			;GIVE FAILURE RETURN
;ROUTINE TO CHECK IF A TABLE NEEDS EXPANDING
;ACCEPTS IN T1/	THE TABLE ADDRESS
;	CALL CHKTBS
;RETURNS +1:	FAILED TO EXPAND THE TABLE
;	 +2:	OK, T1/	ADDRESS OF TABLE AFTER EXPANSION

CHKTBS:	ASUBR <CHKTBO,CHKTBN>
	HRRZ T2,0(T1)		;GET LENGTH OF THE TABLE
	HLRZ T3,0(T1)		;GET THE NUMBER OF WORDS USED IN TABLE
	CAMGE T3,T2		;ANY MORE ROOM FOR ANOTHER ENTRY?
	RETSKP			;YES
	LOAD T3,BLKVER,(T1)	;NO, MUST EXPAND THE TABLE
	LOAD T2,BLKTYP,(T1)	;GET A BIGGER FREE BLOCK FOR TABLE
	HRRZ T1,0(T1)		;GET LENGTH OF OLD TABLE
	ADDI T1,TABINC+1	;INCREMENT THE SIZE OF THE TABLE
	CALL ASGFRE		;GET SPACE FOR NEW TABLE
	 RET			;FAILED
	MOVEM T1,CHKTBN		;SAVE ADR OF NEW TABLE
	HRLZ T2,CHKTBO		;NOW COPY THE OLD TABLE TO THE NEW
	HRR T2,CHKTBN
	MOVE T3,CHKTBO		;GET THE SIZE OF THE OLD TABLE
	HLRZ T3,0(T3)		;ONLY COPY THE USED ENTRIES
	ADD T3,CHKTBN		;GET THE ENDING ADDRESS OF THE TABLE
	BLT T2,0(T3)		;MOVE THE TABLE (INCLUDING THE 1ST WORD)
	MOVEI T2,TABINC		;NOW UPDATE THE LENGTH OF THE TABLE
	ADDM T2,0(T1)		;IN THE RH OF THE 1ST WORD OF THE TABLE
	MOVE T1,CHKTBN		;RETURN THE NEW ADDRESS OF THE TABLE
	RETSKP
;ROUTINE TO CHECK IF A NAME IS ALREADY IN A TABLE
;ACCEPTS IN T1/	ADR OF NAME STRING
;	    T2/	ADR OF TABLE
;RETURNS +1:	NOT IN TABLE
;	 +2:	IN TABLE, T1/	ADR OF ENTRY IN TABLE

CHKTAB:	EXCH T1,T2		;SET UP FOR TBLUK
	HRLI T2,(POINT 7,0)	;SET UP BYTE POINTER
	TBLUK			;LOOK UP THIS ENTRY
	 ERJMP R		;NOT IN THE TABLE
	TXNN T2,TL%EXM		;MUST BE AN EXACT MATCH
	RET			;NOT IN THE TABLE
	RETSKP


;ROUTINE TO FIND A DEPENDENCY BLOCK
;ACCEPTS IN T1/	ADR OF DEPENDENT TASK
;	    T2/	ADR OF BLOCKING TASK
;	CALL FNDDEP
;RETURNS +1:	NO DEPENDENCY FOUND
;	 +2:	THERE IS A DEPENDENCY, T1/	ADR OF DEPENDENCY BLOCK

FNDDEP:	LOAD T3,TKDLP,(T1)	;GET ADR OF FIRST DEPENDENT BLOCK
FNDDP1:	JUMPE T3,R		;IF NO MORE, THEN RETURN +1
	LOAD T4,DPBTK,(T3)	;GET ADR OF BLOCKING TASK
	CAMN T2,T4		;FOUND A MATCH?
	JRST FNDDP2		;YES
	LOAD T3,DPDLP,(T3)	;STEP DOWN THE LIST
	JRST FNDDP1		;LOOP BACK TIL END REACHED

FNDDP2:	MOVE T1,T3		;RETURN THE ADR OF THE DEPENDENCY BLOCK
	RETSKP
;ROUTINE TO CREATE A NEW TABLE
;ACCEPTS IN T1/	INITIAL SIZE OF THE TABLE
;	    T2/	TYPE CODE OF TABLE
;	    T3/	VERSION NUMBER OF TABLE
;	CALL CRTTAB
;RETURNS +1:	FAILED
;	 +2:	OK, T1/	ADR OF TABLE

CRTTAB:	ASUBR <CRTTBS>
	CALL ASGFRE		;GET SPACE FOR THE TABLE
	 RET			;FAILED TO GET SPACE
	MOVE T2,CRTTBS		;GET SIZE BACK
	SUBI T2,1		;SIZE IS NOT INCLUSIVE OF 1ST WORD
	MOVEM T2,0(T1)		;STORE FIRST WORD IN TABLE
	RETSKP			;RETURN


;ROUTINE TO SET UP THE PROJECT TABLE ADDRESS IN PDB
;ACCEPTS IN T1/	ADR OF PDB
;	CALL SETPRJ		;CALLED FROM PARSE
;RETURNS +1:	ALWAYS

SETPRJ:	MOVE T2,PRJTBL		;GET THE CURRENT ADR OF THE PROJECT TABLE
	MOVEM T2,.CMDAT(T1)	;STORE IT IN THE PDB
	RET


;ROUTINE TO SET UP THE ADR OF A TASK BLOCK IN THE PDB

SETTSK:	MOVE T2,TSKTBL		;GET THE ADR OF THE CURRENT TASK TABLE
	MOVEM T2,.CMDAT(T1)	;STORE IT IN THE PDB
	RET


;ROUTINE TO STORE THE ADR OF THE CURRENT TASK TABLE
;ACCEPTS IN T1/	FUNCTION
;	    T2/	DATA FROM PARSE

STOTSK:	HRRZ T2,(T2)		;GET THE ADR OF THE PROJECT TABLE
	LOAD T2,PJTKT,(T2)	;GET THE ADR OF THE TASK TABLE
	MOVEM T2,TSKTBL		;SAVE IT FOR NEXT LEVEL OF COMMAND
	RET
;ROUTINE TO GET A YES OR NO ANSWER
;ACCEPTS IN T1/	POINTER TO THE PROMPT STRING
;	CALL YESNO
;RETURNS +1:	ANSWER IS "NO"
;	 +2:	ANSWER IS "YES"

YESNO:	STKVAR <<YNBLK,20>>
	MOVEI T2,YNCT		;GET ADDRESS OF THE YESNO COMMAND TABLE
	MOVEI T3,YNBLK
	CALL PARSE		;GO GET THE ANSWER
	 ERRMES <ILLEGALLY FORMATTED YES/NO COMMAND TABLE>
	CALL COPCMD		;COPY THIS TO CMDBLK
	HLRZ T1,YNBLK		;GET TYPE CODE
	CAIE T1,.CMKEY		;IS IT WHAT WE WANT
	ERRMES <UNKNOWN TYPE CODE RECEIVED FROM "PARSE">
	HRRZ T1,YNBLK
	JUMPE T1,R		;0 = NO
	RETSKP			;1 = YES


;ROUTINE TO GET A STRING FROM THE TTY:
;ACCEPTS IN T1/	POINTER TO THE PROMPT
;	    T2/	POINTER TO THE STRING TO RECEIVE THE ANSWER
;	    T3/	NUMBER OF CHARACTERS IN STRING
;	CALL GETSTR
;RETURNS +1:	FAILED
;	 +2:	OK, T1/	COUNT OF WORDS IN STRING

GETSTR:	ASUBR <GETSTA,GETSTB,GETSTC>
	PSOUT			;OUTPUT THE PROMPT
	MOVE T1,GETSTB		;GET THE POINTER TO THE ANSWER STRING
	MOVE T2,GETSTC		;GET THE CHAR COUNT
	HRLI T2,(RD%BRK)
	MOVE T3,GETSTA		;GET THE PROMPT STRING POINTER
	RDTTY
	 RET
	TXNN T2,RD%BTM		;ENDED CORRECTLY?
	RET			;NO
	MOVEM T1,GETSTA		;SAVE T1
	MOVE T1,GETSTB		;GET POINTER TO ANSWER STRING
	MOVEM T2,GETSTB		;SAVE T2
	CALL COPCMD		;COPY THIS COMMAND TO CMDBUF
	MOVE T1,GETSTA		;RESTORE T1
	MOVE T2,GETSTB		;AND T2
	MOVEI T3,0		;OVERWRITE THE TERMINATOR WITH A NULL
	DPB T3,T1
	HRRZS T2		;GET UPDATED COUNT
	MOVE T1,GETSTC		;GET THE ORIGINAL COUNT
	SUB T1,T2		;GET THE COUNT OF CHARS TYPED
	IDIVI T1,5		;GET WORDS USED
	SKIPE T2		;PLUS PARTIAL WORD
	AOS T1
	RETSKP
;ROUTINE TO COMPARE TODAY'S EXPECTED DATES WITH REMEMBERED DATES

CMPDAT:	HLRZ T1,(P1)		;GET TYPE CODE
	CHKTYP (OFI)		;MAKE SURE IT IS A FILE
	HRRZ T1,(P1)		;GET JFN
	MOVE T1,ANSWER(T1)
	HRRZS Q1,T1		;RH ONLY
	MOVE T2,[070000,,OF%WR]	;OPEN FOR WRITE
	OPENF
	  WARN (<JRST LEVEL0>,<COULD NOT OPEN REPORT FILE>)
	CALL SCHCHK		;
	SETOM P1		;HEADER FLAG
	MOVE Q3,TSKPTR		;POINTER TO TASK LIST
CMPDT1:	HRRZ Q2,TSKLST(Q3)	;ADDRESS OF TASK BLOCK
	LOAD T1,BLKVER,(Q2)	;GET VERSION
	CAIG T1,1		;IS IT 2 OR BETTER?
	JRST VERERR		;NO--VERSION ERROR
	LOAD T1,TKEFD,(Q2)	;GET DATES
	LOAD T2,TKESD,(Q2)	; ..
	LOAD T3,TKRCD,(Q2)	; ..
	LOAD T4,TKRSD,(Q2)	; ..
	JUMPE T4,CMPDT4		;SKIP IF NOTHING REMEMBERED
	CAME T2,T4		;SAME STARTING DATE?
	JRST CMPDT2		;NO--DUMP OUT MESSAGE
	CAMN T1,T3		;SAME ENDING DATE?
	JRST CMPDT4		;YES--STEP TO NEXT LINE
CMPDT2:	AOJN P1,CMPDT3		;ANY HEADING NEEDED?
	TYPE Q1,<
                                    STARTING DATE                      ENDING DATE
PROJECT/TASK                        OLD        NEW       DIF         OLD        NEW       DIF
---------------------            ---------  ---------   ----      ---------  ---------   ----
>
CMPDT3:	DMOVE T1,Q1		;COPY ARGUMENTS
	CALL PRITNM		;OUTPUT TASK NAME
	LOAD T2,TKRSD,(Q2)	;GET REMEMBERED START DATE
	CALL PRIDAT		;OUTPUT THAT
	TYPE T1,<  >
	LOAD T2,TKESD,(Q2)	;GET NEW ESTIMATE
	CALL PRIDAT		;OUTPUT THAT
	TYPE T1,<  >
	LOAD T2,TKRSD,(Q2)	;ORIGINAL DATE
	LOAD T3,TKESD,(Q2)	;NEW ESTIMATE
	SUB T2,T3		;IMPROVEMENT
	HLRE T2,T2		;JUST DATE
	MOVX T3,NO%SGN+NO%LFL+NO%OOV+5B17+^D10
	NOUT
	  ERJMP .
	TYPE T1,<      >
	; ..
	; ..
	LOAD T2,TKRCD,(Q2)	;GET REMEMBERED END DATE
	CALL PRIDAT		;OUTPUT THAT
	TYPE T1,<  >
	LOAD T2,TKEFD,(Q2)	;GET NEW ESTIMATE
	CALL PRIDAT		;OUTPUT THAT
	TYPE T1,<  >
	LOAD T2,TKRCD,(Q2)	;ORIGINAL DATE
	LOAD T3,TKEFD,(Q2)	;NEW ESTIMATE
	SUB T2,T3		;IMPROVEMENT
	HLRE T2,T2		;JUST DATE
	MOVX T3,NO%SGN+NO%LFL+NO%OOV+5B17+^D10
	NOUT
	  ERJMP .
	TYPE T1,<&>
CMPDT4:	AOBJN Q3,CMPDT1		;LOOP OVER ALL TASKS
	HRRZ T1,Q1		;COPY JFN
	CLOSF			;CLOSE IT
	  WARN (,<COULD NOT CLOSE FILE>)
	JRST LEVEL0		;DO NEXT COMMAND
LPATHC:	HLRZ T1,(P1)		;MAKE SURE WE HAVE A FILE
	CHKTYP (OFI)		; ..
	HRRZ T1,(P1)		;GET JFN
	MOVE T1,ANSWER(T1)	; ..
	HRRZS Q1,T1		;RH ONLY
	MOVX T2,7B5+OF%WR
	OPENF
	  WARN (<JRST LEVEL0>,<COULD NOT OPEN REPORT FILE>)
	CALL SCHWRN		;OUTPUT WARNING
	TYPE Q1,<
PATH	COMPLETION
CHAR	   DATE		PROJECT/TASK
----	----------	------------

>
	MOVE Q2,[-200+40,,40]
LPTHC1:	HRRZ T1,Q1
	HRRZ T2,Q2
	CALL PTHPRJ
	AOBJN Q2,LPTHC1
	MOVE T1,Q1		;COPY JFN
	CLOSF
	  WARN (<JRST LEVEL0>,<ERROR CLOSING REPORT FILE>)
	JRST LEVEL0
;SUBROUTINE TO TYPE OUT THE TASK(S) WITH A GIVEN PATH CHARACTER
;	T1/ JFN
;	T2/ CHARACTER
;
PTHPRJ:	SAVEP
	DMOVE P1,T1		;SVE ARGUMENTS
	SKIPN T1,PRJTBL		;ADDRESS OF PROJECT TABLE
	RET			;SHOULD BE ONE
	HLRZ P4,(T1)		;GET COUNT
	JUMPE P4,R		;MAKE SURE THERE ARE SOME
	MOVN P4,P4		;MAKE NEGATIVE
	HRLZ P4,P4
	HRRI P4,1(T1)		;AOBJN POINTER TO LIST
PTPRJ1:	MOVE T1,P1
	HRRZ T2,(P4)
	MOVE T3,P2		;PATH CHARACTER
	CALL PTHTSK
	AOBJN P4,PTPRJ1
	RET

;HERE TO CHECK ONE PROJECT
; T1/ JFN T2/ PROJECT BLOCK T3/ PATH CHARACTER
;
PTHTSK:	SAVEP
	DMOVE P1,T1		;SAVE ARGUMENTS
	MOVE P4,T3		;PATH CHAR
	LOAD T1,PJTKT,(P2)	;ADDRESS OF TASK TABLE
	HLRZ P3,(T1)		;GET TASK COUNT
	JUMPE P3,R		;SKIP IF NONE
	MOVN P3,P3		;MAKE NEGATIVE
	HRLZ P3,P3		;PUT IN LEFT HALF
	HRRI P3,1(T1)		;MAKE AOBJN POINTER
PTHTK1:	HRRZ P5,(P3)		;POINTER TO TASK BLOCK
	LOAD T1,TKPTC,(P5)	;GET PATH CHARACTER
	CAME T1,P4		;MATCH?
	JRST PTHTK2		;NO--SKIP THIS TASK
	MOVE T1,P1		;GET JFN
	MOVE T2,P4		;PATH CHARACTER
	BOUT
	TYPE T1,<	>	;ADD A TAB
	LOAD T2,TKEFD,(P5)	;GET THE DATE
	CALL TYPDAT		;TYPE IT OUT
	TYPE T1,<	>	;ADD A TAB
	LOAD T2,TKPRJ,(P5)	;PROJECT BLOCK
	LOAD T2,PJNAM,(T2)	;NAME STRING
	HRLI T2,(POINT 7,0)	;MAKE BYTE POINTER
	CALL TYPSTR
	TYPE P1,</>
	LOAD T2,TKNAM,(P5)	;TASK NAME
	MOVE T1,P1		;COPY JFN
	CALL TYPSTR
	TYPE P1,<&>		;ADD CRLF
PTHTK2:	AOBJN P3,PTHTK1		;LOOP OVER ALL TASKS
	RET
;LIST A GIVEN CRITICAL PATH
OUTCP:	HLRZ T1,(P1)		;GET THE TYPE CODE
	CHKTYP (KEY)		;MUST BE A PROJECT
	ADDI P1,1		;STEP TO TASK BLOCK ADDRESS
	HLRZ T1,(P1)		;GET THE NEXT TYPE CODE
	CHKTYP (KEY)		;MUST BE A KEYWORD
	HRRZ P2,(P1)		;ADDRESS OF TASK BLOCK
	ADDI P1,1		;BUMP P1
	HLRZ T1,(P1)		;GET TYPE
	CHKTYP (OFI)		;MUST BE OUTPUT FILE
	HRRZ P1,(P1)		;GET THE JFN
	HRRZ P1,ANSWER(P1)	; ..
	MOVE T1,P1		;SETUP FOR OPENF
	MOVX T2,7B5+OF%WR	;WANT TO WRITE
	OPENF
	  WARN (<JRST LEVEL0>,<COULD NOT OPEN OUTPUT FILE>)
	CALL SCHWRN		;INDICATE DATES MAY BE WRONG
	DMOVE T1,P1		;COPY JFN AND TASK
	MOVEI T3,0		;PRESET LEVEL
	CALL CPLOOK		;FOLLOW THE CHAIN
	MOVE T1,P1		;GET JFN
	CLOSF
	  WARN (<JRST LEVEL0>,<FILE DID NOT GET PROPERLY CLOSED>)
	JRST LEVEL0		;ALL DONE
;SUBROUTINE TO FOLLOW THE CRITICAL PATH
;CALL WITH:
;	T1/ JFN
;	T2/ TASK BLOCK ADDRESS
;	T3/ LEVEL #
;	CALL CPLOOK
;	RETURN HERE
CPLOOK:	ASUBR <CPJFN,CPTSK,CPLVL>
	SAVEP
	MOVE T1,CPJFN		;GET JFN
	MOVEI T2," "		;GET A SPACE
	SKIPE T3,CPLVL		;GET LEVEL -- NO OUTPUT IF ZERO
	BOUT			;TYPE THE SPACE
	SOJG T3,.-1		;TYPE "N" SPACES
	MOVE P1,CPJFN		;COPY JFN
	MOVE P2,CPTSK		;TASK BLOCK ADDRESS
	LOAD T2,TKPRJ,(P2)	;PROJECT BLOCK
	LOAD T2,PJNAM,(T2)	;NAME STRING
	HRLI T2,(POINT 7,0)	;MAKE BYTE POINTER
	CALL TYPSTR
	TYPE P1,</>
	LOAD T2,TKNAM,(P2)	;TASK NAME
	MOVE T1,P1		;COPY JFN
	CALL TYPSTR
	LOAD T2,TKESD,(P2)
	LOAD T3,TKEFD,(P2)
	CAMN T2,T3
	JRST [TYPE P1,<  ON:>
	      JRST CPLK0]
	TYPE P1,<  START: >
	LOAD T2,TKESD,(P2)	;START DATE
	CALL PRIDAT		;PRINT IT
	TYPE P1,<  END: >
CPLK0:	LOAD T2,TKEFD,(P2)	;GET ENDING DATE
	CALL PRIDAT		;PRINT THAT
	TYPE P1,<&>		;ADD CRLF
	LOAD P1,TKDLP,(P2)	;GET BLOCKING LIST POINTER
	JUMPE P1,R		;RETURN IF TOP-LEVEL TASK
	MOVEI P3,0		;LATEST TASK TO START
CPLK1:	LOAD T2,DPBTK,(P1)	;GET BLOCKING TASK
	LOAD T3,TKEFD,(T2)	;GET BLOCKING FINISH DATE
	CAMGE P3,T3		;NEW LATEST TASK?
	MOVE P3,T3		;YES--REMEMBER THE DATE
	LOAD P1,DPDLP,(P1)	;GET NEXT TASK
	JUMPN P1,CPLK1		;LOOP OVER ALL TASKS
	LOAD P1,TKDLP,(P2)	;GET POINTER
CPLK1A:	LOAD T2,DPBTK,(P1)	;ADDRESS OF BLOCKING TASK
	LOAD T3,TKEFD,(T2)	; ..
	CAMGE T3,P3		;ON CRITICAL PATH?
	JRST CPLK2		;NO--LOOK AT NEXT TASK
	MOVE T1,CPJFN		;GET JFN
	MOVE T3,CPLVL		;GET LEVEL
	ADDI T3,1		;BUMP LEVEL
	CALL CPLOOK		;FOLLOW THE PATH
CPLK2:	LOAD P1,DPDLP,(P1)	;STEP TO NEXT TASK
	JUMPN P1,CPLK1A		;JUMP IF MORE TASKS
	RET			;END OF PATH
;ROUTINE TO INIT THE TRANSACTION AREA

INITRA:	MOVE T1,[POINT 7,CMDBUF]
	MOVEM T1,CMDPTR		;INITIALIZE THE POINTER TO CMDBUF
	RET


;ROUTINE TO COPY A COMMAND TO THE TRANSACTION LOG BUFFER (CMDBUF)
;ACCEPTS IN T1/	POINTER TO COMMAND
;	CALL COPCMD
;RETURNS +1:	ALWAYS

COPCMD:	MOVE T2,CMDPTR		;GET POINTER TO COMMAND BUFFER AREA
	SETZ T3,
	SIN			;COPY COMMAND INTO BUFFER
	MOVEM T2,CMDPTR		;UPDATE POINTER TO END OF COMMAND
	RET			;DONE
;ROUTINE TO UPDATE THE DATA BASE

UPDDB:	STKVAR <<UPDDBS,40>,UPDDBU>
	SKIPE SLOB		;WANT SAFE MODE?
	JRST UPDDB3		;NO--SKIP THE UPDATE
	SKIPN T1,TLJFN		;GET TRANSACTION JFN
	JRST UPDDB2		;NONE
	MOVE T2,[070000,,OF%APP] ;OPEN IT FOR APPEND
	OPENF
	 WARN (<JRST UPDDB2>,<COULD NOT OPEN THE TRANSACTION LOG FILE>)
	SKIPE TRAFLG		;FIRST TIME THRU?
	JRST UPDDB1		;NO, DONT PUT IN TIME STAMP
	SETO T1,		;YES, GET USER NAME
	HRROI T2,UPDDBU
	MOVEI T3,.JIUNO		;GET USER NUMBER
	GETJI
	 JRST UPDDB1		;FAILED
	HRROI T1,UPDDBS		;NOW BUILD TIME STAMP
	HRROI T2,[ASCIZ/

; UPDATED BY /]
	SETZ T3,
	SOUT
	MOVE T2,UPDDBU		;NAOW ADD IN USER NAME
	DIRST
	 JRST UPDDB1		;FAILED
	HRROI T2,[ASCIZ/ ON /]
	SOUT
	SETO T2,		;AND THEN THE CURENT DATE
	ODTIM
	HRROI T2,[ASCIZ/

/]
	SOUT
	MOVE T1,TLJFN		;AND NOW COPY IT TO TLOG FILE
	HRROI T2,UPDDBS
	SOUT
	SETOM TRAFLG		;MARK THAT NO LONGER FIRST TIME THRU
UPDDB1:	MOVE T1,TLJFN		;GET TLOG JFN
	MOVE T2,[POINT 7,CMDBUF]
	SETZ T3,
	SOUT			;COPY COMMAND TO TLOG
	TXO T1,CO%NRJ		;DONT RELEASE THE JFN
	CLOSF			;CLOSE THE TLOG FILE
	 JFCL
UPDDB2:	HRLZ T1,DBJFN		;NOW UPDATE THE DATA BASE
	MOVEI T2,NDBPAG
	UFPGS
	 WARN (<JRST .+1>,<COULD NOT UPDATE THE DATA BASE>)
UPDDB3:	SETZM SKDFLG		;MARK THAT SCHEDULING MUST BE DONE
	RET			;DONE
;TYPE OUT ROUTINES USED BY THE "LIST" COMMANDS

;ROUTINE TO TYPE OUT THE DEVELOPERS ON A TASK/PROJECT
;ACCEPTS IN T1/	OUTPUT JFN
;	    T2/	ADR OF FIRST BLOCK IN LIST
;RETURNS +1:	ALWAYS

TYPDEV:	SAVET
	SAVEQ
	MOVE Q1,T2		;SAVE THE ADR OF THE BLOCK
	JUMPE Q1,R		;IF 0, THEN DONE
	TYPE T1,<&	DEVELOPER          RATE      HANDICAP>
TYPDV1:	TYPE T1,<&	>
	LOAD T2,DVNAM,(Q1)	;GET NAME OF DEVELOPER
	CALL TYPSTR
	MOVEI T2,^D28		;SKIP TO COLUMN 20
	CALL TYPSPA
	LOAD T2,DVRAT,(Q1)	;GET RATE
	CALL TYPFLT
	MOVEI T2,^D38		;SKIP TO COLUMN 30
	CALL TYPSPA
	LOAD T2,DVHCR,(Q1)	;GET HANDICAP
	CALL TYPFLT
	LOAD Q1,DVLNK,(Q1)	;STEP TO NEXT DEVELOPER BLOCK
	JUMPN Q1,TYPDV1		;LOOP BACK FOR REST OF DEVELOPERS
	RET
;ROUTINE TO TYPE OUT THE DEPENDENCY LIST OR BLOCKED LIST
;ACCEPTS IN T1/	OUTPUT JFN
;	    T2/	ADR OF FIRST ITEM IN LIST
;	CALL TYPDEP  OR  CALL TYPBLK
;RETURNS +1:	ALWAYS

TYPDEP:	SAVET
	MOVEI T3,0		;DEPENDENCY LIST
	JRST TYPBL0

TYPBLK:	SAVET
	MOVEI T3,1		;BLOCKED LIST
TYPBL0:	SAVEQ
	DMOVE Q1,T2		;SAVE ARGUMENTS IN Q1, Q2
TYPBL1:	JUMPE Q1,R		;IF NO MORE, RETURN
	TYPE T1,<&		>
	XCT [	LOAD Q3,DPBTK,(Q1)
		LOAD Q3,DPTKP,(Q1)](Q2)
	LOAD T2,TKPRJ,(Q3)	;GET PROJECT BLOCK ADR
	LOAD T2,PJNAM,(T2)	;GET ADR OF PROJECT NAME
	CALL TYPSTR		;TYPE OUT THE PROJECT NAME
	TYPE T1,</>
	LOAD T2,TKNAM,(Q3)	;GET ADR OF TASK NAME BLOCK
	CALL TYPSTR		;TYPE PRJ/TASK
	JUMPN Q2,TYPBL2		;ONLY INCLUDE ON BLOCKING
				;TASK LIST
	TYPE T1,<	>
	LOAD T2,TKEFD,(Q3)	;GET DONE DATE
	CALL TYPDAT
TYPBL2:	XCT [	LOAD Q1,DPDLP,(Q1)
		LOAD Q1,DPBLP,(Q1)](Q2)
	JUMPE Q1,R		;IF NO MORE, RETURN
	JRST TYPBL1		;GO TYPE OUT REST OF LIST
;ROUTINE TO OUTPUT A CONTROL FILE
;ACCEPTS IN T1/	JFN

OUTCTL:	SAVEQ
	STKVAR <OUTCTJ>
	MOVEM T1,OUTCTJ		;SAVE THE JFN
	HRROI T2,[ASCIZ/
RENAME /]
	SETZ T3,
	SOUT			;RENAME THE DATA BASE FILE FIRST
	MOVE T2,DBJFN		;GET DATA BASE NAME
	MOVE T3,[1B8]
	JFNS
	HRROI T2,[ASCIZ/.DATA-BASE.* /]
	SETZ T3,
	SOUT
	MOVE T2,DBJFN		;RENAME IT TO .BACKUP-DATA-BASE
	MOVE T3,[1B8]
	JFNS
	HRROI T2,[ASCIZ/.BACKUP-DATA-BASE

PANTT
/]
	SETZ T3,
	SOUT			;START THE PROGRAM
	MOVE T2,DBJFN		;GET NAME OF DATA BASE FILE
	MOVE T3,[1B8]
	JFNS			;OUTPUT DATABASE NAME
	HRROI T2,[ASCIZ/
SET SLOPPY-BUT-FAST-UPDATE-MODE
/]
	SETZ T3,
	SOUT
	HRROI T2,[ASCIZ /
SET SCHEDULE-DATE /]
	SETZ T3,
	SKIPE SKDITD
	SOUT
	MOVE T2,SKDITD
	MOVX T3,OT%NTM
	SKIPE SKDITD
	CALL OUTDAT
	HRROI T2,[ASCIZ "
"]
	SETZ T3,
	SOUT
	CALL OUTHOL		;OUTPUT THE HOLIDAYS
	MOVE T1,OUTCTJ		;GET THE JFN
	MOVE T2,DEVTBP		;GET POINTER TO DEVELOPER LIST
	CALL OUTADV		;OUTPUT THE DEVELOPERS
	SKIPN T1,PRJTBL		;NOW DO THE PROJECTS
	JRST OUTCT3		;NONE
	HLRZ Q1,(T1)		;GET COUNT
	MOVNS Q1
	JUMPE Q1,OUTCT3		;CHECK IF ANY
	HRLZS Q1
	HRRI Q1,1(T1)		;SET UP POINTER TO THE PROJECT LIST
OUTCT1:	MOVE T1,OUTCTJ		;GET THE JFN
	HRRZ T2,0(Q1)		;GET THE NEXT PROJECT
	CALL OUTPRJ		;OUTPUT THE PROJECT
	AOBJN Q1,OUTCT1		;LOOP BACK FOR ALL PROJECTS
	SKIPN T1,PRJTBL		;NOW DO THE DEPENDENCIES
	JRST OUTCT3		;NONE
	HLRZ Q1,(T1)		;GET COUNT
	MOVNS Q1
	JUMPE Q1,OUTCT3		;CHECK IF ANY
	HRLZS Q1
	HRRI Q1,1(T1)		;SET UP POINTER TO THE PROJECT LIST
OUTCT2:	MOVE T1,OUTCTJ		;GET THE JFN
	HRRZ T2,0(Q1)		;GET THE NEXT PROJECT
	CALL OUTPDP		;OUTPUT THE PROJECT DEPENDENCIES
	AOBJN Q1,OUTCT2		;LOOP BACK FOR ALL PROJECTS
OUTCT3:	MOVE T1,OUTCTJ		;GET THE JFN
	HRROI T2,[ASCIZ/EXIT
/]
	SETZ T3,
	SOUT			;EXIT
	RET			;DONE


;ROUTINE TO OUTPUT THE HOLIDAYS
;ACCEPTS IN T1/	JFN

OUTHOL:	SAVEQ
	MOVEM T1,Q1
	SKIPN T2,HOLTAB		;IS THERE A HOLIDAY LIST?
	RET			;NO
	LOAD Q2,HOLUSE,(T2)	;YES, GET NUMBER OF ENTRIES
	JUMPE Q2,R		;CHECK IF ANY
	MOVNS Q2		;SET UP POINTER
	HRLZS Q2
	HRRI Q2,1(T2)
OUTHO1:	MOVE T1,Q1		;GET THE JFN
	HRROI T2,[ASCIZ/SET HOLIDAY /]
	SETZ T3,
	SOUT
	MOVE T2,(Q2)		;GET THE NEXT DATE
	CALL OUTDAT		;OUTPUT IT
	MOVE T1,Q1
	HRROI T2,[ASCIZ/
/]
	SETZ T3,
	SOUT
	AOBJN Q2,OUTHO1		;LOOP BACK FOR REST OF DATES
	RET			;DONE


;ROUTINE TO OUTPUT A PROJECT
;ACCEPTS IN T1/	JFN
;	    T2/	ADR OF PROJECT BLOCK

OUTPRJ:	SAVEQ
	DMOVE Q1,T1		;SAVE THE ARGS
	HRROI T2,[ASCIZ/ADD PROJECT /]
	SETZ T3,
	SOUT
	LOAD T2,PJNAM,(Q2)	;GET THE PROJECT NAME
	HRLI T2,(POINT 7,0)
	SOUT			;OUTPUT THE PROJECT NAME
	HRROI T2,[ASCIZ/
/]
	SOUT
	LOAD T2,PJDSC,(Q2)	;NOW OUTPUT THE DESCRIPTION
	HRLI T2,(POINT 7,0)
	SOUT
	MOVEI T2,33		;FOLLOWED BY AN ALTMODE
	BOUT
	HRROI T2,[ASCIZ/
/]
	SOUT
	LOAD T2,PJDVL,(Q2)	;OUTPUT THE DEVELOPER LIST
	CALL OUTDEV
	MOVE T1,Q1		;GET THE JFN
	LOAD T2,PJPRF,(Q2)	;GET THE PREFERENCE VALUE
	CALL OUTPRF
	MOVE T1,Q1
	HRROI T2,[ASCIZ/FINISHED

/]
	SETZ T3,
	SOUT
	LOAD T2,PJTKT,(Q2)	;GET ADR OF TASK LIST
	HLRZ Q3,(T2)		;GET COUNT OF TASKS
	MOVNS Q3
	JUMPE Q3,OUTPR2		;ANY TASKS?
	HRLZS Q3
	HRRI Q3,1(T2)		;BUILD POINTER TO TASK LIST
OUTPR1:	MOVE T1,Q1		;GET THE JFN
	HRRZ T2,0(Q3)		;GET TASK ADR
	CALL OUTTSK		;OUTPUT THE TASK
	AOBJN Q3,OUTPR1		;LOOP BACK FOR ALL TASKS
OUTPR2:	RET


;ROUTINE TO OUTPUT THE DEPENDENCIES
;ACCEPTS IN T1/	JFN
;	    T2/	PROJECT ADR

OUTPDP:	SAVEQ
	DMOVE Q1,T1		;SAVE THE ARGS
	LOAD T2,PJTKT,(Q2)	;GET ADR OF TASK LIST
	HLRZ Q3,(T2)		;GET COUNT OF TASKS
	MOVNS Q3
	JUMPE Q3,OUTPD2		;ANY TASKS?
	HRLZS Q3
	HRRI Q3,1(T2)		;BUILD POINTER TO TASK LIST
OUTPD1:	MOVE T1,Q1		;GET THE JFN
	HRRZ T2,0(Q3)		;GET TASK ADR
	CALL OUTTDP		;OUTPUT THE TASK DEPENDENCIES
	AOBJN Q3,OUTPD1		;LOOP BACK FOR ALL TASKS
OUTPD2:	RET


;ROUTINE TO OUTPUT TASK DEPENDENCIES
;ACCEPTS IN T1/	JFN
;	    T2/	TASK ADR

OUTTDP:	SAVEQ
	DMOVE Q1,T1		;SAVE THE ARGS
	LOAD T2,TKDLP,(Q2)	;IS THERE A DEPENDENCY LIST?
	JUMPE T2,R		;...
	HRROI T2,[ASCIZ/UPDATE (PROJECT) /]
	SETZ T3,
	SOUT
	LOAD T2,TKPRJ,(Q2)	;GET PROJECT NAME
	LOAD T2,PJNAM,(T2)
	HRLI T2,(POINT 7,0)	;SET UP POINTER TO PROJECT NAME
	SOUT
	HRROI T2,[ASCIZ/ (TASK) /]
	SOUT
	LOAD T2,TKNAM,(Q2)	;GET TASK NAME
	HRLI T2,(POINT 7,0)
	SOUT
	HRROI T2,[ASCIZ/
/]
	SOUT
	LOAD T2,TKDLP,(Q2)	;GET POINTER TO THE DEPENDENCY LIST
	CALL OUTDEP		;OUTPUT THE DEPENDENCIES
	MOVE T1,Q1		;GET THE JFN
	HRROI T2,[ASCIZ/FINISHED

/]
	SETZ T3,
	SOUT
	RET			;DONE


;ROUTINE TO OUTPUT A DEVELOPER LIST
;ACCEPTS IN T1/	JFN
;	    T2/	DEVELOPER LIST POINTER

OUTADV:	SAVEQ
	SETOM Q3		;MARK THIS AS NEEDING AN "ADD"
	JRST OUTDV0

OUTDEV:	SAVEQ
	SETZ Q3,		;NO "ADD" NEEDED
OUTDV0:	DMOVE Q1,T1		;SAVE THE ARGS
OUTDV1:	JUMPE Q2,R		;ANY THERE?
	MOVE T1,Q1		;YES, GET THE JFN
	HRROI T2,[ASCIZ/ADD /]
	SETZ T3,
	SKIPE Q3		;NEED AN "ADD"?
	SOUT			;YES
	HRROI T2,[ASCIZ/DEVELOPER /]
	SETZ T3,
	SOUT
	LOAD T2,DVNAM,(Q2)	;GET DEVELOPER NAME
	HRLI T2,(POINT 7,0)
	SOUT
	HRROI T2,[ASCIZ/ (RATE) /]
	SOUT
	LOAD T2,DVRAT,(Q2)	;GET THE RATE
	FLOUT
	 JFCL
	HRROI T2,[ASCIZ/ (HANDICAP) /]
	SOUT
	LOAD T2,DVHCR,(Q2)	;GET THE HANDICAP
	FLOUT
	 JFCL
	HRROI T2,[ASCIZ/
/]
	SOUT
	LOAD Q2,DVLNK,(Q2)	;STEP TO THE NEXT IN THE LIST
	JRST OUTDV1		;LOOP BACK FOR ALL DEVELOPERS


;ROUTINE TO OUTPUT THE PREFERENCE VALUE
;ACCEPTS IN T1/	JFN
;	    T2/	PREFERENCE VALUE

OUTPRF:	SAVEQ
	DMOVE Q1,T1		;SAVE THE ARGS
	HRROI T2,[ASCIZ/PREFERENCE-VALUE /]
	SETZ T3,
	SOUT
	MOVE T2,Q2		;GET THE VALUE
	FLOUT
	 JFCL
	HRROI T2,[ASCIZ/
/]
	SOUT
	RET


;ROUTINE TO OUTPUT A TASK
;ACCEPTS IN T1/	JFN
;	    T2/	TASK ADR

OUTTSK:	SAVEQ
	DMOVE Q1,T1		;SAVE THE ARGS
	HRROI T2,[ASCIZ/ADD TASK /]
	SETZ T3,
	SOUT
	LOAD T2,TKNAM,(Q2)	;GET THE TASK NAME
	HRLI T2,(POINT 7,0)
	SOUT
	HRROI T2,[ASCIZ/ (TO PROJECT) /]
	SOUT
	LOAD T2,TKPRJ,(Q2)	;GET PROJECT BLOCK
	LOAD T2,PJNAM,(T2)	;GET PROJECT NAME
	HRLI T2,(POINT 7,0)
	SOUT
	HRROI T2,[ASCIZ/
/]
	SOUT
	LOAD T2,TKDSC,(Q2)	;GET THE DESCRIPTION
	HRLI T2,(POINT 7,0)
	SOUT
	MOVEI T2,33		;FOLLOWED WITH AN ALTMODE
	BOUT
	HRROI T2,[ASCIZ/
/]
	SOUT
	LOAD T2,TKASD,(Q2)	;GET THE STARTING DATE
	JUMPE T2,OUTTS1		;IF ANY
	HRROI T2,[ASCIZ/STARTING-DATE /]
	SETZ T3,
	SOUT
	LOAD T2,TKASD,(Q2)	;GET STARTING DATE
	CALL OUTDAT
	HRROI T2,[ASCIZ/
/]
	SETZ T3,
	SOUT
OUTTS1:	LOAD T2,TKAFD,(Q2)	;GET THE COMPLETION DATE
	JUMPE T2,OUTTS2		;IF ANY
	HRROI T2,[ASCIZ/COMPLETION-DATE /]
	SETZ T3,
	SOUT
	LOAD T2,TKAFD,(Q2)	;GET DATE AGAIN
	CALL OUTDAT		;OUTPUT IT
	HRROI T2,[ASCIZ/
/]
	SETZ T3,
	SOUT
OUTTS2:	HRROI T2,[ASCIZ/ESTIMATED-PROJECT-LENGTH /]
	SETZ T3,
	SOUT
	LOAD T2,TKELN,(Q2)	;GET THE ESTIMATED LENGTH
	FLOUT
	 JFCL
	HRROI T2,[ASCIZ/
/]
	SETZ T3,
	SOUT
	LOAD T2,TKTAD,(Q2)	;TIME TO DATE?
	JUMPE T2,OUTTS3
	HRROI T2,[ASCIZ/TIME-TO-DATE /]
	SETZ T3,
	SOUT
	LOAD T2,TKTTD,(Q2)	;GET TIME
	FLOUT
	 JFCL
	HRROI T2,[ASCIZ/ (AT DATE) /]
	SETZ T3,
	SOUT
	LOAD T2,TKTAD,(Q2)	;GET DATE
	CALL OUTDAT
	HRROI T2,[ASCIZ/
/]
	SETZ T3,
	SOUT
OUTTS3:	MOVE T1,Q1		;COPY JFN
	MOVE T2,Q2		;COPY TASK BLOCK ADDRESS
	CALL OUTATR		;OUTPUT ATTRIBUTES
	MOVE T1,Q1		;GET JFN
	LOAD T2,TKDVL,(Q2)	;GET DEVELOPER LIST
	CALL OUTDEV		;OUTPUT THE DEVELOPERS
	MOVE T1,Q1		;GET THE JFN
	LOAD T2,TKXSD,(Q2)	;GET EXPECTED STARTING DATE
	JUMPE T2,OUTTS4		;IF ANY
	HRROI T2,[ASCIZ/EXPECTED STARTING-DATE /]
	SETZ T3,
	SOUT
	LOAD T2,TKXSD,(Q2)	;GET STARTING DATE AGAIN
	CALL OUTDAT
	HRROI T2,[ASCIZ/
/]
	SETZ T3,
	SOUT
OUTTS4:	MOVE T1,Q1		;GET THE JFN
	LOAD T2,TKXCD,(Q2)	;GET THE EXPECTED COMPLETION DATE
	JUMPE T2,OUTTS5		;IF ANY
	HRROI T2,[ASCIZ/EXPECTED COMPLETION-DATE /]
	SETZ T3,
	SOUT
	LOAD T2,TKXCD,(Q2)	;GET DATE AGAIN
	CALL OUTDAT
	HRROI T2,[ASCIZ/
/]
	SETZ T3,
	SOUT
OUTTS5:	MOVE T1,Q1		;GET THE JFN
	LOAD T2,TKMSD,(Q2)	;GET THE MINIMUM STARTING DATE
	JUMPE T2,OUTTS6		;IF ANY
	HRROI T2,[ASCIZ/MINIMUM-STARTING-DATE /]
	SETZ T3,
	SOUT
	LOAD T2,TKMSD,(Q2)	;GET THE DATE AGAIN
	CALL OUTDAT
	HRROI T2,[ASCIZ/
/]
	SETZ T3,
	SOUT
OUTTS6:	MOVE T1,Q1		;GET THE JFN
	LOAD T2,TKPRF,(Q2)	;GET THE PREFERENCE VALUE
	CALL OUTPRF
	MOVE T1,Q1		;GET THE JFN
	HRROI T2,[ASCIZ/MILESTONE
/]
	SETZ T3,
	LOAD T4,TKFLG,(Q2)	;GET THE FLAGS
	TXNE T4,TK%MIL		;IS THIS A MILESTONE?
	SOUT			;YES, SAY SO
	MOVE T1,Q1		;GET THE JFN
	HRROI T2,[ASCIZ/ALL-DEVELOPERS-REQUIRED
/]
	SETZ T3,
	LOAD T4,TKFLG,(Q2)	;GET THE FLAGS
	TXNE T4,TK%ADR		;IS THIS ALL-DEVELOPERS-REQUIRED?
	SOUT			;YES, SAY SO
	LOAD T2,TKPTC,(Q2)	;GET THE PATH CHARACTER
	JUMPE T2,OUTTS7		;IF ANY
	HRROI T2,[ASCIZ/PATH-CHARACTER /]
	SETZ T3,
	SOUT
	LOAD T2,TKPTC,(Q2)	;GET THE PATH CHARACTER
	BOUT
	HRROI T2,[ASCIZ/
/]
	SOUT
OUTTS7:	HRROI T2,[ASCIZ/FINISHED

/]
	SETZ T3,
	SOUT
	RET			;DONE


;ROUTINE TO OUTPUT A DEPENDENCY LIST
;ACCEPTS IN T1/	JFN
;	    T2/	DEPENDENCY LIST

OUTDEP:	SAVEQ
OUTDP1:	DMOVE Q1,T1		;SAVE THE ARGS
	JUMPE T2,R		;IF NO LIST, THEN DONE
	HRROI T2,[ASCIZ/DEPENDENCY /]
	SETZ T3,
	SOUT
	LOAD Q3,DPBTK,(Q2)	;GET TASK ADR OF BLOCKING TASK
	LOAD T2,TKPRJ,(Q3)	;GET ITS PROJECT 
	LOAD T2,PJNAM,(T2)	;AND THE PROJECT NAME
	HRLI T2,(POINT 7,0)
	SETZ T3,
	SOUT
	HRROI T2,[ASCIZ/ /]
	SOUT
	LOAD T2,TKNAM,(Q3)	;GET THE TASK NAME
	HRLI T2,(POINT 7,0)
	SOUT
	HRROI T2,[ASCIZ/
/]
	SOUT
	LOAD T2,DPDLP,(Q2)	;STEP TO THE NEXT NAME IN THE LIST
	JRST OUTDP1		;LOOP BACK TIL THE LIST IS DONE
;SUBROUTINE TO OUTPUT ALL THE ATTRIBUTES FOR A TASK TO CONTROL FILE
;CALL WITH:
;	T1/ JFN
;	T2/ ADDRESS OF TASK BLOCK
;	CALL OUTATR
;
OUTATR:	SAVEQ
	DMOVE Q1,T1		;SAVE ARGUMENTS
	CHKVER .VNTSK,(Q2),R	;NONE IF OLD DATA BASE
	LOAD Q3,TKATR,(Q2)	;START OF CHAIN
OUATR1:	JUMPE Q3,R		;EXIT AT END OF CHAIN
	MOVE T1,Q1		;COPY JFN
	LOAD T3,ATRFL,(Q3)	;GET FLAGS
	MOVE T2,[POINT 7,[ASCIZ "ATTRIBUTE "]]
	TXNE T3,AT%LNG		;LONG ATTRIBUTE
	MOVE T2,[POINT 7,[ASCIZ "LONG-ATTRIBUTE "]]
	CALL TYPSTR
	LOAD T2,ATRNM,(Q3)	;ATTRIBUTE NAME
	CALL TYPSTR		;TYPE IT
	MOVE T2,[POINT 7,[ASCIZ " "]]
	TXNE T3,AT%LNG		;LONG ATTRIBUTE
	MOVE T2,[POINT 7,[ASCIZ "
"]]
	CALL TYPSTR
	LOAD T2,ATRVL,(Q3)	;POINTER TO VALUE
	CALL TYPSTR
	MOVE T2,[POINT 7,[BYTE (7)33,15,12,0]]
	TXNE T3,AT%LNG		;LONG ATTRIBUTE?
	CALL TYPSTR		;YES--ADD ESCAPE
	TYPE Q1,<&>		;ADD A CRLF
	LOAD Q3,ATRLK,(Q3)	;FOLLOW CHAIN
	JRST OUATR1		;LOOP BACK
;ROUTINE TO DELETE A DELVELOPER BLOCK
;ACCEPTS IN T1/	USER NAME STRING POINTER
;	    T2/	ADR OF FIRST BLOCK IN LIST
;	CALL DELDEV
;RETURNS +1:	FAILED TO FIND THE BLOCK
;	 +2:	T1/	UPDATED ADR OF FIRST BLOCK IN LIST

DELDEV:	STKVAR <<DELDVS,11>,DELDVL,DELDVT>
	MOVEM T2,DELDVL		;SAVE ADR OF LIST
	HRROI T2,DELDVS		;COPY NAME STRING INTO STKVAR
	SETZ T3,
	SIN
	HRROI T1,DELDVS		;GET POINTER TO NAME STRING
	MOVE T2,DELDVL		;GET ADR OF FIRST BLOCK IN LIST
	CALL CHKDEV		;GO FIND THE BLOCK
	 RET			;NOT FOUND
	MOVEM T1,DELDVT		;SAVE ADR OF TASK BLOCK
	JUMPE T2,DELDV2		;IS THIS THE FIRST ONE ON THE LIST
	LOAD T3,DVLNK,(T1)	;NO, REMOVE IT FROM THE LIST
	STOR T3,DVLNK,(T2)	;MAKE PREVIOUS BLOCK POINT TO NEXT ONE
DELDV1:	LOAD T1,DVNAM,(T1)	;GET ADR OF NAME STRING
	CALL RELFRE		;RELEASE IT
	MOVE T1,DELDVT		;GET ADR OF TASK BLOCK AGAIN
	CALL RELFRE		;RELEASE THE DEVELOPER BLOCK
	MOVE T1,DELDVL		;RETURN THE UPDATED START OF LIST
	RETSKP

DELDV2:	LOAD T2,DVLNK,(T1)	;GET THE NEXT BLOCK IN THE LIST
	MOVEM T2,DELDVL		;THIS IS THE NEW HEAD OF THE LIST
	JRST DELDV1		;GO DELETE THE BLOCK
;ROUTINE TO RELEASE A DEVELOPER STRING
;ACCEPTS IN T1/	ADR OF DEVELOPER BLOCK
;RETURNS +1:	ALWAYS

RELDEV:	ASUBR <RELDVP>
	LOAD T1,DVNAM,(T1)	;GET THE NAME BLOCK
	CALL RELFRE		;RELEASE IT
	MOVE T1,RELDVP		;GET ADR OF BLOCK AGAIN
	CALL RELFRE		;RELEASE IT
	RET			;DONE


;ROUTINE TO RELEASE A DEPENDENCY BLOCK
;ACCEPTS IN T1/	POINTER TO THE DEPENDENCY BLOCK
;RETURNS +1:	ALWAYS

RELDEP:	LOAD T4,DPBTK,(T1)	;GET BLOCKED TASK ADR
	LOAD T2,TKBLP,(T4)	;LOOK FOR THIS BLOCK ON THE TASK LIST
	JUMPE T2,RELDP3		;IF NO LIST, GO ON
	CAMN T1,T2		;FOUND IT?
	JRST RELDP2		;YES, GO DELETE IT
RELDP1:	MOVE T3,T2		;REMEMBER THE LAST BLOCK SCANNED
	LOAD T2,DPBLP,(T3)	;GET ADR OF NEXT BLOCK
	JUMPE T2,RELDP3		;IF NOT FOUND, GO ON
	CAME T1,T2		;FOUND THE BLOCK?
	JRST RELDP1		;NO, LOOP BACK TIL FOUND
	LOAD T2,DPBLP,(T2)	;FOUND, GET POINTER TO NEXT BLOCK
	STOR T2,DPBLP,(T3)	;MAKE LAST BLOCK POINT TO NEXT BLOCK
	JRST RELDP3		;GO DO DEPENDENCY LIST

RELDP2:	LOAD T2,DPBLP,(T2)	;GET POINTER TO NEXT BLOCK
	STOR T2,TKBLP,(T4)	;MAKE TASK BLOCK POINT TO IT
RELDP3:	LOAD T4,DPTKP,(T1)	;GET POINTER TO DEPENDENT TASK
	LOAD T2,TKDLP,(T4)	;GET POINTER TO DEPENDENT BLOCK
	JUMPE T2,RELDP6
	CAMN T1,T2		;FOUND OUR BLOCK YET?
	JRST RELDP5		;YES
RELDP4:	MOVE T3,T2		;SAVE ADR OF LAST BLOCK
	LOAD T2,DPDLP,(T3)	;GET ADR OF NEXT BLOCK
	JUMPE T2,RELDP6		;NOT FOUND?
	CAME T1,T2		;HAVE A MATCH YET?
	JRST RELDP4		;NO, CONTINUE LOOKING
	LOAD T2,DPDLP,(T2)	;GET POINTER TO NEXT BLOCK
	STOR T2,DPDLP,(T3)	;MAKE LAST BLOCK POINT TO NEXT ONE
	JRST RELDP6

RELDP5:	LOAD T2,DPDLP,(T2)	;GET ADR OF NEXT BLOCK
	STOR T2,TKDLP,(T4)	;SAVE IT IN TASK BLOCK
RELDP6:	CALL RELFRE		;RELEASE THE BLOCK
	RET			;DONE
;UPDATE ALL ESTIMATED DATES IF NEEDED
SCHCHK:	SKIPN SKDFLG		;IS AN UPDATE NEEDED?
	CALL UPDEST		;YES--DO THE UPDATE
	RET

;OUTPUT A WARNING IF A SCHEDULE PASS IS NEEDED (BUT DON'T SCHEDULE)
SCHWRN:	SKIPE SKDFLG		;IS AN UPDATE NEEDED?
	RET			;NO--ALL DONE
	TMSG <% Some dates may be wrong. Use SCHEDULE command to update all dates
>
	RET
;SCHEDULING ROUTINES

;ROUTINE TO UPDATE THE ESTIMATED START AND FINISH DATES OF ALL TASKS

UPDEST:	SAVEPQ
	STKVAR <<UPDESS,20>,UPDESL,UPDESD>
	CALL GETLVL		;GET LOOK AHEAD LEVEL
	MOVEM T1,UPDESL		;SAVE THE LEVEL NUMBER
	MOVEM T2,UPDESD		;SAVE THE DEPTH
	SKIPN T1,SKDITD		;IS THERE AN INITIAL DATE SET
	GTAD			;NO, GET TODAY'S DATE
	CALL GETDAY		;GET CONVERTED DATE
	MOVEM T1,SKDTAD
	SKIPN SKDITD		;FUNNY TIME SET?
	JRST UPDST0		;NO--SKIP WARNING
	MOVEI T1,.PRIOU
	TYPE T1,<[Virtual date set to >
	MOVE T2,SKDTAD		;GET INTERNAL FORM
	CALL TYPDAT		;PRINT IT
	TYPE T1,< by SET SCHEDULE-DATE command]
>
UPDST0:	CALL LPCHK		;MAKE SURE THERE ARE NO LOOPS
	CALL CLRCP		;CLEAR THE CRITICAL PATH BITS
	MOVEI T1,0		;START WITH A PASS OF 0
	MOVEI T2,0		;DEPTH 0 ALSO
	CALL BLDTAB		;BUILD THE TABLES
	CALL UPDEDT		;UPDATE THE ESTIMATED DATES
	CALL SETCP		;SET THE CRITICAL PATH TASKS
	MOVE T1,UPDESL		;GET THE LEVEL NUMBER
	MOVE T2,UPDESD		;GET THE DEPTH
	CALL BLDTAB		;GO BUILD THE SCHED TABLES
	MOVE T2,T1		;GET NUMBER OF CONFLICTS
;	HRROI T1,UPDESS
;	MOVEI T3,^D10
;	NOUT			;GET ASCIZ STRING
;	 JSP ERROR
;	MOVEI T1,.PRIOU		;OUTPUT THIS ON THE TTY
;	TYPE T1,<&THE NUMBER OF UNRESOLVED CONFLICTS WAS >
;	HRROI T2,UPDESS
;	CALL TYPSTR		;OUTPUT THE NUMBER OF CONFILCTS
;	TYPE T1,<&>
	TMSG <[>
	MOVEI T1,.PRIOU		;OUTPUT ON TERMINAL
	HLRZ T2,DEVTAB		;GET NUMBER OF DEVELOPERS
	MOVEI T3,^D10		;IN DECIMAL
	NOUT
	  JSP ERROR
	TMSG < DEVELOPERS SCHEDULED]
>
	CALL UPDEDT		;GO UPDATE ESTIMATED DATES
	CALL SETCP		;GO SET THE CRITICAL PATH BITS
	CALL BLDSTL		;GO BUILD THE TASK LIST
	SETOM SKDFLG		;MARK THAT SCHEDULING IS NOT NEEDED
	MOVE Q1,TSKPTR		;POINTER TO TASK LIST
UPDST1:	HRRZ T1,Q1		;COPY INDEX
	CALL CHKDAT		;CHECK DATES
	  JRST UPDST2		;LOOK OK
	TMSG <% >		;START WARNING
	HRRZ T1,TSKLST(Q1)	;OUTPUT TASK NAMES
	CALL TYPTNM		; ..
	TMSG < HAS QUESTIONABLE DATES
>
UPDST2:	AOBJN Q1,UPDST1		;LOOK AT ALL TASKS
	MOVE T2,TSKCNT
	CAIGE T2,^D100
	RET
	TMSG <[>
	MOVEI T1,.PRIOU
	MOVEI T3,^D10
	NOUT
	  JFCL
	TMSG < TASKS SCHEDULED]
>
	RET			;DONE
;SUBROUTINE TO CHECK FOR LOOPS IN DEPENDANCY LIST
LPCHK:	SKIPGE T1,NOLOOP	;ANY CHANGES SINCE LAST CHECK
	AOJE T1,R		;NO--JUST RETURN
	SAVEPQ
	MOVE T1,PRJTBL		;ADR OF PROJECT TABLE
	MOVEI P1,1(T1)		;POINTER TO FIRST TASK
	HLRZ P2,(T1)		;NUMBER OF PROJECTS
	JUMPN P2,LPCHK1		;NO PROJECTS--NO LOOPS
	ERRMES (<NO PROJECTS DEFINED>)
LPCHK1:	HRRZ P3,(P1)		;ADDRESS OF NEXT PROJECT
				;BLOCK
	LOAD T1,PJTKT,(P3)	;ADDRESS OF TASK TABLE
	MOVEI P4,1(T1)		;ADDRESS OF FIRST TASK
	HLRZ P5,(T1)		;GET NUMBER OF TASKS IN
				;PROJECT
	JUMPN P5,LPCHK2		;JUMP IF SOME
	TMSG <% NO TASKS IN PROJECT >
	LOAD T1,PJNAM,(P3)	;ADDRESS OF NAME
	HRLI T1,(POINT 7,0)	;MAKE BYTE POINTER
	PSOUT			;TYPE THE NAME
	TMSG <
>
	JRST LPCHK3		;SKIP TO NEXT PROJECT
LPCHK2:	MOVSI T1,-1		;PRESET LIST TO FIRST TASK
	MOVEM T1,LVLPTR		; ..
	HRRZ T1,(P4)		;ADDRESS OF TASK BLOCK
	MOVEM T1,LVLTAB		;SAVE IN LIST
	CALL MKTASK		;CHECK FOR LOOPS
	ADDI P4,1		;BUMP POINTER
	SOJG P5,LPCHK2		;CHECK ALL TASKS IN THIS
				;PROJECT
LPCHK3:	ADDI P1,1		;BUMP POINTER
	SOJG P2,LPCHK1		;CHECK ALL PROJECTS
	SETOM NOLOOP		;FLAG THAT NO LOOPS EXIST
	RET
;RECURSIVE ROUTINE TO CHECK FOR LOOPS IN DEPENDANCY LIST
;CALL WITH:
;	T1/ TASK BLOCK ADDRESS
;	LVLPTR/ AOBJN POINTER TO TASKS ALREADY FOUND
;	CALL MKTASK
;	RET
MKTASK:	SAVEQ
	MOVE Q1,T1		;COPY TASK BLOCK ADDRESS
	LOAD Q2,TKDLP,(Q1)	;BLOCKING LIST POINTER
	JUMPE Q2,MKTSK5		;TOP LEVEL TASK
MKTSK1:	LOAD Q3,DPBTK,(Q2)	;ADDRESS OF BLOCKING TASK
	MOVE T1,LVLPTR		;SEE IF IN LIST ALREADY
	CAME Q3,LVLTAB(T1)	;MATCH
	AOBJN T1,.-1		;NO--KEEP LOOKING
	JUMPG T1,MKTSK4		;IF POSITIVE THEN NO LOOP
	TMSG <? LOOP DETECTED IN THE TASK DEPENDENCY LIST
? BLOCKED TASK:  >
	MOVE T1,Q1		;COPY FIRST TASK
	CALL TYPTNM		;TYPE TASK NAME
	TMSG <
? BLOCKING TASK: >
	MOVE T1,Q3		;COPY SECOND TASK
	CALL TYPTNM		;TYPE TASK NAME
	TMSG <
? TASKS IN LOOP:
>
	MOVE Q1,LVLPTR		;POINTER TO LIST
MKTSK2:	SKIPG LVLTAB(Q1)	;VALID ENTRY?
	JRST MKTSK3		;NO--SKIP IT
	TMSG <?	>
	HRRZ T1,LVLTAB(Q1)	;ADDRESS OF TASK BLOCK
	CALL TYPTNM		;TYPE IT OUT
	TMSG <
>
MKTSK3:	AOBJN Q1,MKTSK2		;LOOK OVER WHOLE LIST
	JRST REENT		;PUNT BIG

MKTSK4:	MOVE T1,LVLPTR		;GET POINTER
	SKIPL LVLTAB(T1)	;LOOK FOR FREE ENTRY
	AOBJN T1,.-1		;LOOP OVER TABLE
	MOVEM Q3,LVLTAB(T1)	;STORE IN LIST
	MOVSI T2,-1		;UPDATE POINTER
	SKIPL T1		;ALLOCATE SLOT IF OFF END OF TABLE
	ADDM T2,LVLPTR		;SCAN UP THE LIST
	MOVE T1,Q3		;CLIMB THE TREE
	CALL MKTASK		; ..
	LOAD Q2,DPDLP,(Q2)	;FOLLOW CHAIN
	JUMPN Q2,MKTSK1		;CHECK ALL ABOVE
MKTSK5:	MOVE T1,LVLPTR		;POINTER TO LIST
MKTSK6:	CAMN Q1,LVLTAB(T1)	;FIND TASK IN LIST
	SETCMM LVLTAB(T1)	;DELETE IT
	AOBJN T1,MKTSK6		;LOOP OVER WHOLE LIST
	RET
;ROUTINE TO COPY START AND FINISH DATES TO DATA BASE

UPDEDT:	SAVEQ			;SAVE REGS
	MOVE Q1,TSKPTR		;NOW SET UP THE ESTIMATED DATES
	JUMPE Q1,R		;IF NO TASKS, RETURN
UPDES1:	MOVE Q2,TSKLST(Q1)	;GET NEXT TASK
	MOVE T1,TSKSDL(Q1)	;GET THE START DATE
	TLNN T1,-1		;ANYTHING THERE?
	MOVE T1,TSKFDL(Q1)	;IF NONE, USE THE FINISH DATE
;	CAMN T1,TSKFDL(Q1)	;ONLY ONE DATE?
;	JRST UPDES4		;YES--MAKE SURE THEY STAY THE SAME
;UPDES2:	CALL CHKWD		;WORKING DAY?
;	  JRST [MOVSI T2,1	;NO--PUSH IT UP
;		ADD T1,T2	; ..
;		JRST UPDES2]	;AND TRY AGAIN
	STOR T1,TKESD,(Q2)	;STORE IN THE DATA BASE
	STOR T1,TKLSD,(Q2)	;*** TEMP LATEST START DATE
	MOVE T1,TSKFDL(Q1)	;GET THE FINISH DATE
;UPDES3:	CALL CHKWD		;WORKING DAY?
;	  JRST [MOVSI T2,1	;NO--MOVE IT BACK
;		SUB T1,T2	; ..
;		JRST UPDES3]	;AND TRY AGAIN
	STOR T1,TKEFD,(Q2)	;STORE IT IN THE DATA BASE
	STOR T1,TKLFD,(Q2)	;*** TEMP LATEST FINISH DATE
;	JRST UPDES5		;LOOP OVER ALL TASKS
;UPDES4:	CALL CHKWD		;MAKE SURE WE HAVE A WEEKDAY
;	  JRST [MOVSI T2,1	;ONE DAY
;		SUB T1,T2	;BACK UP DATE
;		JRST UPDES4]	;KEEP TRYING
;	STOR T1,TKLFD,(Q2)	;STORE ANSWER
;	STOR T1,TKEFD,(Q2)	; ..
;	STOR T1,TKLSD,(Q2)	; ..
;	STOR T1,TKESD,(Q2)	; ..
UPDES5:	AOBJN Q1,UPDES1		;LOOP BACK FOR ALL TASKS
	RET			;DONE
;ROUTINE TO GET THE LEVEL OF LOOK AHEAD
;	CALL GETLVL
;RETURNS +1:	ALWAYS,	T1/	NUMBER OF LOOK AHEAD
;			T2/	DEPTH OF SEARCH

GETPAS:	SKIPA T1,[POINT 7,[ASCIZ "NUMBER OF PLACEMENT PASSES: "]]
GETLVL:	HRROI T1,[ASCIZ/SCHEDULER LOOK AHEAD VALUE: /]
	MOVEI T2,SDATA		;GET THE ADR OF THE COMMAND TABLE
	MOVEI T3,ANSWER
	CALL PARSE		;GO GET THE VALUE FROM USER
	 ERRMES <ILLEGALLY FORMATTED SCHEDULER COMMAND TABLE>
	LDB T1,[POINT 9,ANSWER,17] ;GET TYPE CODE
	CHKTYP (NUM)
	HRRZ T1,ANSWER		;GET ADR OF VALUE
	MOVE T1,ANSWER(T1)	;GET THE NUMBER
	MOVE T2,T1		;GET DEPTH
	IMULI T2,NDEPTH		;CALCULATE THE DEPTH VALUE
	RET			;DONE
;ROUTINE TO BUILD THE SCHEDULER TABLES
;ACCEPTS IN T1/	LOOK AHEAD LEVEL NUMBER
;	    T2/	DEPTH
;RETURNS +1:	ALWAYS, T1/	NUMBER OF CONFLICTS ENCOUNTERED

BLDTAB:	SAVEPQ
	CAILE T1,MAXTSK		;ABOVE THE MAX LEVEL?
	MOVEI T1,MAXTSK		;YES, LIMIT IT
	ASUBR <BLDTBL,BLDTBD,BLDTBC>
	SETZM BLDTBC		;ZERO THE NUMBER OF CONFLICTS SEEN
	MOVE T1,[SKDVAR,,SKDVAR+1]
	SETZM SKDVAR		;ZERO DATA BASE FIRST
	BLT T1,SKDVRE
	SKIPN T1,SKDITD		;IS THERE AN INITIAL DATE SET
	GTAD			;NO, GET TODAY'S DATE
	CALL GETDAY		;GET CONVERTED DATE
	MOVEM T1,SKDTAD
	SETOM PASCNT		;FIRST TIME THRU
BLDTB0:	HRLOI T1,377777		;INIT THE BEST FINISH DATE
	MOVEM T1,BESTFD		;TO THE BIGGEST DATE
	SETZM DEPTH		;INIT DEPTH
	MOVE Q1,PASCNT		;GET CURRENT VALUE OF PASCNT
	CALL BLDTKT		;BUILD THE TASK TABLE
	SKIPG BLDTBL		;DOING MULTIPLE PASSES?
	JRST BLDTB1		;NO
	MOVEI T1,.PRIOU		;PRINT OUT THE PASSES
	HRROI T2,[ASCIZ/REMAINING SCHEDULER PASSES: /]
	SKIPL Q1		;FIRST TIME THRU?
	HRROI T2,[ASCIZ/, /]	;NO, TYPE A COMMA
	SETZ T3,
	SOUT
	MOVE T2,TSKCNT		;GET POSSIBLE PASSES
	SUB T2,PASCNT
	MOVEI T3,^D10		;DECIMAL
	NOUT
	 JFCL
BLDTB1:	CALL BLDTKT		;GO BUILD THE TASK TABLE
	MOVE P1,PASCNT		;SET UP LEVEL 0 COUNT
	MOVEM P1,LVL0CT
	SUB P1,PAS0CT		;GET COUNT MINUS INITIAL COUNT
	MOVNS P1
	HRLZS P1		;GET AOBJN POINTER
	HRR P1,PAS0CT		;STARTING AFTER THE INITIAL TASKS
BLDTB2:	MOVE T1,SKDCNT		;GET CURRENT COUNT OF SCHEDULED TASKS
	SETZM LVLCNT(T1)	;INIT LEVEL COUNT FOR THIS LEVEL
	CALL BLDAVL		;GO GET THE AVAILABLE TASKS
	 JRST BLDTB5		;NONE LEFT
	CALL BLDOAL		;GET OPTIMIZED AVAILABLE LIST
	JUMPL P1,BLDTB3		;NEED TO SCHEDULE ANY TASKS FIRST?
	CALL GETMS		;GET ANY MILESTONES THAT ARE MET
	 JRST BLDTB7		;NONE FOUND
	MOVE T3,T1		;GET INDEX INTO AVLTSK LIST INTO T3
	MOVE T2,AVLSDL(T1)	;GO SCHEDULE THIS ONE NOW
	CALL SKDAVL		;GO SCHEDULE THE TASK
	JRST BLDTB2		;LOOP BACK FOR THE OTHER TASKS
BLDTB3:	SKIPL T1,SKDLST(P1)	;IS THIS A GROUP OR A SINGLE TASK
	JRST [	CALL SKDTG	;GROUP, GO SCHEDULE IT
		JRST BLDTB9]
	TLNE T1,(1B1)		;IS THIS A TSKLST TASK?
	JRST [	MOVE T2,AVLSDL(T1)	;SINGLE TASK
		CALL SKDAVL		;GO SCHEDULE THE TASK
		JRST BLDTB9]	;DONE
	MOVE T2,TSKSDL(T1)	;GET START ADR FROM TSKLST
	CALL SKDTSK		;SCHEDULE THE TASK
BLDTB9:	AOBJN P1,.+1		;STEP TO NEXT ITEM IN SKDLST
	JRST BLDTB2		;LOOP BACK FOR OTHER TASKS

BLDTB7:	CALL FNDAVD		;FIND ANY AVAILABLE DEVELOPERS
	 SKIPA T1,LEVEL		;NONE FOUND
	JRST BLDTB8		;ONE FOUND, GO SCHEDULE IT
	AOS T1
	MOVE T2,DEPTH		;GET CURRENT DEPTH
	CAMGE T2,BLDTBD		;REACHED THE MAX DEPTH?
	CAML T1,BLDTBL		;NO, AT THE MAXIMUM LEVEL?
	JRST [	AOS T1,NCNFLC	;AN UNRESOLVED CONFLICT WAS FOUND
		CAMLE T1,BLDTBC	;IS THIS A NEW HIGH FOR CONFLICTS?
		MOVEM T1,BLDTBC	;YES, REMEMBER IT
		JRST BLDTB4]	;GO CHOSE THE LONGEST TASK
	MOVE T2,SKDCNT		;LEVEL 0, REMEMBER THIS POINT
	MOVEM T2,MAXCFL		;SAVE THE MAXIMUM LEVEL ATAINED
	MOVE T3,OAVCNT		;GET OPTIMIZED COUNT
	MOVEM T3,LVLCNT(T2)	;SAVE THE COUNT FOR THIS LEVEL
	AOS DEPTH		;COUNT UP THE DEPTH OF THE SEARCH
	AOSN LEVEL		;NO, STEP TO NEXT LEVEL
	MOVEM T2,LVL0CT		;NEXT PASS WILL SKIP PAST THIS LEVEL
	MOVE T1,SKDCNT		;GET CURRENT LEVEL
	MOVE T1,LVLTAB(T1)	;GET THE NEXT TASK TO SCHEDULE
	AOS T1			;START GROUP NUMBER ONE HIGHER
	SKIPN LEVEL		;LEVEL 0?
	MOVEM T1,LVL0TK		;REMEMBER THIS DATA
	CALL SKDTG		;GO SCHEDULE THE GROUP
	JRST BLDTB2		;LOOP BACK FOR REST OF TASKS

BLDTB4:	MOVE T1,SKDTAD		;GET START DATE OF SCHEDULE PASS
	MOVE T2,LSTSKT		;GET LAST SCHEDULED TASK
	SETO T3,		;CHOSE ANY TASK
	CALL GETLFT		;GET LATEST COMPLETION TASK
	 SETZ T1,		;FAILED, GO SCHEDULE THE FIRST ON THE LIST
	HLRZ T1,AVLTSK(T1)	;GET THE GROUP NUMBER
	CALL SKDTG		;SCHEDULE THE WHOLE GROUP
	JRST BLDTB2		;DONE

BLDTB8:	MOVE T2,AVLSDL(T1)	;GET ITS START DATE
	CALL SKDAVL		;GO SCHEDULE THIS TASK
	JRST BLDTB2		;LOOP BACK FOR OTHER TASKS
BLDTB5:	CALL CHKLOP		;GO SEE IF THERE IS A LOOP
	 ERRMES (<LOOP DETECTED IN THE TASK DEPENDENCY LIST>)
	CALL CHKBST		;SEE IF THIS IS A NEW BEST
BLDTB6:	MOVE T1,MAXCFL		;NOW STEP THE LEVEL CHOICE
	AOS T2,LVLTAB(T1)
	CAMGE T2,LVLCNT(T1)	;REACHED END OF THE LEVEL?
	JRST BLDTB1		;NO, GO BACK AND TRY THIS CHOICE
	SETZM LVLTAB(T1)	;YES, INIT TABLE
	SETZM LVLCNT(T1)
	SOSL MAXCFL		;GO BACK TO PREVIOUS LEVEL
	JRST BLDTB6		;LOOP BACK FOR OTHER CHOICES
	MOVE T1,BLDTBC		;GET MAX NUMBER OF CONFLICTS SEEN
	SKIPLE BLDTBL		;IF LEVEL = 0, THEN ONE PASS IS ENOUGH
	SKIPG NCNFLC		;ANY CONFLICTS STILL?
	RET			;NO, DONE
	MOVE T1,BESTSK		;GET THE BEST LEVEL 0 TASK
	MOVE T2,LVL0CT		;GET COUNT
	MOVEM T1,SKDLST(T2)	;SAVE POINTER TO BEST TASK
	ADDI T2,1		;SKIP TO HERE ON NEXT PASS
	CAML T2,TSKCNT		;GONE THRU ALL PASSES?
	RET			;YES, DONE
	MOVEM T2,PASCNT
	JRST BLDTB0		;GO TRY AGAIN AT NEXT PASCNT
;ROUTINE TO SCHEDULE THOSE TASKS THAT HAVE A COMMON SET
;  OF DEVELOPERS AND THE SAME DEPENDENT TASKS.  

;ACCEPTS IN T1/	INDEX INTO AVLTSK OF TASK TO BE SCHEDULED
;	CALL SKDCOM
;RETURNS +1:	ALWAYS

SKDCOM:	SAVEQ
	STKVAR <SKDCMC>
	HRRZ Q1,T1		;SAVE TASK INDEX
	MOVE Q2,AVLTSK(Q1)	;GET THE TASK ADDRESS
	HLRZM Q2,SKDCMC		;SAVE THE GROUP NUMBER
	MOVE Q2,TSKLST(Q2)
	LOAD Q2,TKBLP,(Q2)	;GET THE POINTER TO THE BLOCKED TASKS
	MOVN Q3,AVLCNT		;GET POINTER TO TABLE
	HRLZS Q3
	MOVE T1,Q3		;INIT TABLE
	MOVSI T2,(1B0)
SKDCM0:	ANDCAM T2,AVLTSK(T1)	;CLEAR FLAG BIT
	AOBJN T1,SKDCM0		;IN EACH ENTRY
SKDCM1:	MOVE T1,AVLTSK(Q3)	;GET TASK ADR
	MOVE T1,TSKLST(T1)
	LOAD T1,TKBLP,(T1)	;GET BLOCKED TASK LIST
	CAMN Q2,T1		;DO THEY MATCH?
	JRST SKDCM5		;YES, THEN GO MARK THIS TASK
	JUMPE Q2,SKDCM4		;IF NO DEPENDENCIES, THEN NO MATCH
	JUMPE T1,SKDCM4		;IF NONE, MARK IT AS SUCH
SKDCM2:	MOVE T2,Q2		;GET LIST POINTER FOR MAIN TASK
	LOAD T3,DPTKP,(T1)	;GET TASK ADR OF BLOCKED TASK
SKDCM3:	LOAD T4,DPTKP,(T2)	;GET NEXT TASK ADR OF BLOCKED TASK
	CAMN T3,T4		;FOUND A MATCH?
	JRST SKDCM5		;YES
	LOAD T2,DPBLP,(T2)	;NO, STEP TO NEXT ELEMENT IN LIST
	JUMPN T2,SKDCM3		;LOOP BACK FOR REST OF LIST
SKDCM4:	JRST SKDCM6		;GO LOOP BACK THROUGH REST OF TASKS
SKDCM5:	JUMPE Q2,SKDC13		;IF THERE ARE NO DEPENDENCIES, THEN DONE
	LOAD T1,DPBLP,(T1)	;STEP TO NEXT TASK IN PRIMARY LIST
	JUMPN T1,SKDCM2		;LOOP BACK TO CHECK ALL TASKS IN LISTS
SKDC13:	MOVSI T1,(1B0)		;SET THE FLAG BIT
	IORM T1,AVLTSK(Q3)
SKDCM6:	AOBJN Q3,SKDCM1		;LOOP BACK FOR THE REST OF AVLTSK'S
	MOVN Q3,AVLCNT		;GET POINTER TO LIST AGAIN
	HRLZS Q3
	MOVE Q2,AVLTSK(Q1)	;GET TASK ADR
	MOVE Q2,TSKLST(Q2)
	LOAD T1,TKPRJ,(Q2)	;GET POINTER TO PROJECT BLOCK
	LOAD Q2,TKDVL,(Q2)	;GET POINTER TO DEVELOPER LIST
	SKIPN Q2		;IS THERE ANY?
	LOAD Q2,PJDVL,(T1)	;NO, GET THE PROJECT DEVELOPER LIST
	SKIPN Q2		;IS THERE A LIST?
	MOVE Q2,DEVTBP		;NO, GET THE OVERALL LIST
	JUMPE Q2,SKDC11		;IF NONE, GO CLEAN UP AND EXIT
SKDCM7:	MOVE T2,Q2		;GET POINTER TO DEVELOPER LIST
	CAIN Q1,(Q3)		;IS THIS THE SAME AS THE MAIN TASK?
	JRST SKDCM8		;YES, SKIP IT
	SKIPL T1,AVLTSK(Q3)	;IS THIS ONE OF THE GROUP
	JRST [	CALL CHKNDV	;NO, SEE IF NO DEVELOPERS MATCH
		 JRST SKDC11	;DEVELOPER MATCHES, CANNOT SCHEDULE
		JRST SKDCM8]	;GO LOOP BACK FOR OTHER TASKS
	CALL CHKMDV		;SEE IF ALL DEVELOPERS MATCH
	 JRST SKDC11		;NO, THEN CANNOT SCHEDULE ANY
SKDCM8:	AOBJN Q3,SKDCM7		;LOOP BACK TO CHECK ALL TASKS
	MOVN Q3,AVLCNT		;NOW SET THE CODE FOR EACH TASK
	HRLZS Q3
	MOVE T1,SKDCMC		;GET GROUP NUMBER
SKDCM9:	SKIPGE AVLTSK(Q3)	;IS THIS A MEMBER OF THE GROUP?
	HRLM T1,AVLTSK(Q3)	;YES, STORE THE GROUP NUMBER
	AOBJN Q3,SKDCM9
SKDC11:	MOVN Q3,AVLCNT		;CLEAN UP
	HRLZS Q3		;CLEAR THE FLAG BIT IN EACH WORD
	MOVSI T1,(1B0)
SKDC12:	ANDCAM T1,AVLTSK(Q3)	;CLEAR THE FLAG
	AOBJN Q3,SKDC12
	RET
;ROUTINE TO CHECK IF ALL DEVELOPERS MATCH MAIN TASK
;ACCEPTS IN T1/	TASK INDEX
;	    T2/	ADR OF FIRST ITEM IN DEVELOPER LIST
;	CALL CHKMDV
;RETURNS +1:	NOT ALL DEVELOPERS MATCH
;	 +2:	ALL DEVELOPERS MATCH MAIN TASK LIST

CHKMDV:	SAVEQ
	JUMPE T2,R		;IF NO LIST, THEN NO MATCH
	MOVE T1,TSKLST(T1)	;GET TASK ADDRESS
	DMOVE Q1,T1		;SAVE ARGUMENTS
	LOAD T1,TKPRJ,(Q1)	;GET ADR OF PROJECT BLOCK
	LOAD Q3,TKDVL,(Q1)	;GET TASK DEVELOPER LIST
	SKIPN Q3		;ANY THERE?
	LOAD Q3,PJDVL,(T1)	;NO, USE THE PROJECT LIST
	SKIPN Q3		;IS THERE A LIST?
	MOVE Q3,DEVTBP		;NO, GET THE OVERALL LIST
	JUMPE Q3,R		;IF NONE, THEN NO MATCH
	SETZB T3,T4		;SEE IF THERE ARE THE SAME NUMBER OF PEOPLE
	MOVE T1,Q3		;COUNT UP FIRST LIST
CHKMD4:	AOS T3			;COUNT DEVELOPER
	LOAD T1,DVLNK,(T1)	;STEP TO NEXT ITEM
	JUMPN T1,CHKMD4		;IF MORE, GO COUNT THEM
	MOVE T1,Q2		;NOW DO SECOND LIST
CHKMD5:	AOS T4			;COUNT ITEM
	LOAD T1,DVLNK,(T1)	;STEP TO NEXT ITEM
	JUMPN T1,CHKMD5
	CAME T3,T4		;THE SAME?
	RET			;NO, NO MATCH
CHKMD1:	MOVE Q1,Q3		;INIT POINTER TO START OF LIST
CHKMD2:	LOAD T1,DVNAM,(Q2)	;GET POINTER TO DEVELOPER NAME
	LOAD T2,DVNAM,(Q1)	;GET POINTER TO SECOND NAME
	CALL CHKMNM		;SEE IF THE NAMES MATCH
	 SKIPA			;THEY DIDNT MATCH
	JRST CHKMD3		;MATCHED
	LOAD Q1,DVLNK,(Q1)	;STEP TO NEXT DEVELOPER
	JUMPN Q1,CHKMD2		;IF MORE IN LIST, LOOP BACK
	RET			;DID NOT FIND A MATCH FOR DEVELOPER

CHKMD3:	LOAD Q2,DVLNK,(Q2)	;STEP TO NEXT ITEM IN THE LIST
	JUMPN Q2,CHKMD1		;LOOP BACK FOR ALL TASKS
	RETSKP			;ALL NAMES MATCHED
;ROUTINE TO CHECK IF NO DEVELOPERS MATCH THE MAIN TASK
;ACCEPTS IN T1/	TASK INDEX
;	    T2/	DEVELOPER LIST
;	CALL CHKNDV
;RETURNS +1:	FOUND A DEVELOPER MATCH
;	 +2:	NO DEVELOPERS MATCH IN THE LISTS

CHKNDV:	SAVEQ
	JUMPE T2,RSKP		;IF NO LIST, THEN NO MATCH
	MOVE T1,TSKLST(T1)	;GET TASK ADDRESS
	DMOVE Q1,T1		;SAVE ARGS
	LOAD T1,TKPRJ,(Q1)	;GET THE PROJECT BLOCK ADDRESS
	LOAD Q3,TKDVL,(Q1)	;GET POINTER TO DEVELOPER LIST
	SKIPN Q3		;ANY THERE?
	LOAD Q3,PJDVL,(T1)	;NO, USE PROJECT LIST
	SKIPN Q3		;IS THERE A LIST?
	MOVE Q3,DEVTBP		;NO, GET THE OVERALL LIST
	JUMPE Q3,RSKP		;IF NONE, THEN NO MATCH
CHKND1:	MOVE Q1,Q3		;GET POINTER TO MAIN LIST
CHKND2:	LOAD T1,DVNAM,(Q2)	;GET POINTERS TO NAMES
	LOAD T2,DVNAM,(Q1)
	CALL CHKMNM		;SEE IF THEY MATCH
	 SKIPA			;NO MATCH
	RET			;A MATCH WAS FOUND, CAN EXIT NOW
	LOAD Q1,DVLNK,(Q1)	;STEP TO NEXT DEVELOPER IN LIST
	JUMPN Q1,CHKND2		;LOOP BACK TO CHECK THIS DEVELOPER
	LOAD Q2,DVLNK,(Q2)	;STEP TO NEXT ITEM IN SECOND LIST
	JUMPN Q2,CHKND1		;LOOP BACK FOR ALL OF THESE NAMES
	RETSKP			;NO MATCHES FOUND IN BOTH LISTS


;ROUTINE TO COMPARE TWO NAMES
;ACCEPTS IN T1/	ADR OF FIRST NAME
;	    T2/	ADR OF SECOND NAME
;	CALL CHKMNM
;RETURNS +1:	NAMES DID NOT MATCH
;	 +2:	NAMES MATCHED EXACTLY

CHKMNM:	MOVE T3,(T1)		;GET NEXT WORD FROM NAME 1
	CAME T3,(T2)		;DOES IT MATCH NAME 2?
	RET			;NO, NO MATCH
	TRNN T3,377		;YES, REACHED THE END OF THE STRING?
	RETSKP			;YES, THEN THE NAMES MATCH
	AOS T1			;STEP TO NEXT WORD IN NAMES
	AOJA T2,CHKMNM		;LOOP BACK FOR REST OF WORDS IN NAMES
;ROUTINE TO SCHEDULE ALL TASKS THAT HAVE A START DATE ALREADY

SKDSKD:	SAVEQ
	STKVAR <<SKDSKA,5>,SKDSKL,SKDSKF,SKDSKS>
	MOVE Q1,TSKPTR		;GET AOBJN POINTER TO TASK LIST
SKDSK1:	MOVE Q2,TSKLST(Q1)	;GET TASK ADR
	MOVE T1,Q2		;GET THE TASK ADR
	CALL GETSFD		;GET THE START AND FINISH DATE
	 JRST SKDSK4		;NONE
	MOVEM T1,SKDSKF		;SAVE THE FINISH DATE
	MOVEM T2,SKDSKS		;SAVE START DATE
	LOAD Q3,TKDVL,(Q2)	;SCHEDULE THIS TASK
	LOAD T2,TKPRJ,(Q2)	;GET POINTER TO PROJECT BLOCK
	SKIPN Q3		;IS THERE A DEVELOPER LIST FOR THIS TASK
	LOAD Q3,PJDVL,(T2)	;NO, USE THE PROJECT LIST
	SKIPN Q3		;IS THERE A LIST?
	MOVE Q3,DEVTBP		;NO, GET THE OVERALL LIST
	JUMPE Q3,SKDSK3		;UNLESS THERE ARE NO DEVELOPERS LISTED
	SETZM SKDSKL		;INIT LENGTH OF TASK
SKDSK2:	LOAD T1,DVNAM,(Q3)	;GET DEVELOPER NAME
	MOVEM T1,SKDSKA		;BUILD ARG BLOCK
	MOVE T1,SKDSKS		;GET THE START DATE
	MOVE T2,SKDSKF		;GET FINISH DATE
	MOVEM T2,2+SKDSKA
	SKIPN T1		;IS THERE A START DATE?
	MOVE T1,T2		;NO, USE THE FINISH DATE
	MOVEM T1,1+SKDSKA
	CALL GETNWD		;GET THE NUMBER OF WORKING DAYS
	FLTR T1,T1		;FLOAT IT
	LOAD T2,DVHCR,(Q3)	;GET HANDICAP
	LOAD T3,DVRAT,(Q3)	;GET RATE OF DEVELOPER
	MOVEM T3,3+SKDSKA
	FMPR T1,T2		;GET ACTUAL NUMBER OF DAYS OF TASK
	FMPR T1,T3		;DAYS * RATE * HANDICAP
	FADRM T1,SKDSKL		;ADD INTO THE SUM OF TIME SPENT
	MOVEM Q2,4+SKDSKA	;PUT TASK ADR IN ARG BLOCK
	MOVEI T1,SKDSKA		;GET ADR OF ARG BLOCK
	CALL SCHDEV		;GO SCHEDULE THIS DEVELOPER
	LOAD Q3,DVLNK,(Q3)	;STEP TO NEXT DEVELOPER
	JUMPN Q3,SKDSK2		;LOOP BACK FOR ALL DEVELOPERS
	MOVE T1,SKDSKL		;GET PROJECT LENGTH
	STOR T1,TKALN,(Q2)	;STORE THE CALCULATED LENGTH
	;..
	;..
SKDSK3:	MOVE T1,SKDSKF		;GET THE FINISH DATE
	MOVEM T1,TSKFDL(Q1)	;SAVE THE FINISH DATE
	MOVE T2,SKDSKS		;GET THE START DATE
	TLNN T2,-1		;ANY START DATE?
	MOVE T2,T1		;NO, USE THE FINISH DATE
	MOVEM T2,TSKSDL(Q1)	;SAVE ITS START DATE
	AOS T2,SKDCNT		;COUNT THE NUMBER OF SCHEDULED TASKS
	HRRZM Q1,SKDLST-1(T2)	;SAVE THE INDEX INTO TSKLST IN SKDLST
SKDSK4:	AOBJN Q1,SKDSK1		;LOOP BACK FOR ALL TASKS
	MOVE Q1,TSKPTR		;NOW LOOK FOR STARTED BUT NOT ENDED TASKS
SKDSK5:	MOVE T1,TSKLST(Q1)	;GET TASK ADR
	LOAD T2,TKAFD,(T1)	;GET FINISH DATE
	LOAD T3,TKXCD,(T1)	;GET THE COMPLETION DATE
	IOR T2,T3		;MERGE IT
	JUMPN T2,SKDSK6		;IF ANY DATE SET, SKIP THIS TASK
	LOAD T2,TKASD,(T1)	;GET THE ACTUAL START DATE
	LOAD T3,TKXSD,(T1)	;GET EXPECTED START DATE
	TLNN T2,-1		;IS THERE AN ACTUAL START DATE?
	MOVE T2,T3		;NO, USE THE EXPECTED
	JUMPE T2,SKDSK6		;IF NONE, SKIP TASK
	MOVEM T2,TSKSDL(Q1)	;SAVE ACTUAL START DATE
	HRRZ T1,Q1		;GET INDEX INTO TSKLST
	CALL SKDTSK		;GO SCHEDULE THIS TASK
SKDSK6:	AOBJN Q1,SKDSK5		;LOOP BACK FOR ALL TASKS
	RET			;DONE


;ROUTINE TO INITIALIZE THE SCHEDULER DATA BASE

BLDINI:	SETOM LEVEL		;START AT GROUND LEVEL
	SETZM NCNFLC		;NO CONFILCTS YET
	SETZM MAXCFL		;INIT THE MAXIMUM CONFLICT LEVEL
	SETZM LSTSKT		;INIT LAST SCHEDULED TASK
	MOVEI T1,MAXDEV-1	;SET UP THE TBLUK FORMAT
	MOVEM T1,DEVTAB		;NO ENTRIES YET
	SETZM SKDFRE		;INIT THE FREE POOL
	MOVEI T1,SKDFRE
	MOVEM T1,SKDFRP		;MAKE THE FREE POOL POINTER GOOD
	SETZM SKDCNT		;NONE SCHEDULED YET
	RET			;DONE
;ROUTINE TO GET THE START AND FINISH DATES OF A TASK
;ACCEPTS IN T1/	TASK ADR
;RETURNS +1:	NO FINISH DATE SPECIFIED
;	 +2:	T1/	FINISH DATE
;		T2/	START DATE

GETSFD:	SAVEQ
	SETZB Q1,Q2		;INIT ANSWER
	MOVE Q3,T1		;SAVE THE TASK ADR
	LOAD T1,TKAFD,(Q3)	;IS THERE AN ACTUAL FINISH DATE
	SKIPN T1
	LOAD T1,TKXCD,(Q3)	;NO, TRY FOR AN EXPECTED DATE
	SKIPN Q1,T1		;ANY FINISH DATE?
	RET			;NO, RETURN
	LOAD T1,TKASD,(Q3)	;NOW LOOK FOR A START DATE
	SKIPN T1
	LOAD T1,TKXSD,(Q3)	;IF NO START DATE, TRY EXPECTED START
	SKIPE Q2,T1		;ANY THERE?
	JRST GETSF1		;YES
	LOAD T1,TKDVL,(Q3)	;GET THE POINTER TO THE DEVELOPER LIST
	CALL GETDVR		;GET THE SUM OF THE RATES
	 JRST GETSF2		;NONE FOUND OR 0
	LOAD T2,TKELN,(Q3)	;GET THE ESTIMATED LENGTH
	MOVE T3,Q1		;GET THE FINISH DATE
	CALL GETSD		;GET THE START DATE GIVEN THE FINISH
	MOVEM T1,Q2		;SAVE THE START DATE
GETSF1:	DMOVE T1,Q1		;GET THE ANSWER DATES
	RETSKP			;RETURN

GETSF2:	MOVE T1,Q1		;GET FINISH DATE
	MOVE T2,Q1		;USE THE SAME DATE FOR START
	RETSKP


;ROUTINE TO SUM THE RATES IN A DEVELOPER LIST
;ACCEPTS IN T1/	DEVELOPER LIST
;RETURNS +1:	NO RATE
;	 +2:	T1/	RATE

GETDVR:	JUMPE T1,R		;IF NO LIST, RETURN+1
	SETZ T4,		;INIT ANSWER
GETDV1:	LOAD T2,DVRAT,(T1)	;GET THE RATE
	FADR T4,T2		;ADD IT TO THE SUM
	LOAD T1,DVLNK,(T1)	;STEP TO THE NEXT DEVELOPER
	JUMPN T1,GETDV1		;LOOP BACK FOR ALL DEVELOPERS
	SKIPG T1,T4		;ANY RATE FOUND?
	RET			;NO
	RETSKP			;YES
;ROUTINE TO GET A START DATE GIVEN FINISH AND LENGTH
;ACCEPTS IN T1/	RATE
;	    T2/	LENGTH OF TASK
;	    T3/	FINISH DATE
;RETURNS +1:	T1/	START DATE

GETSD:	SAVEQ
	FDVR T2,T1		;GET NUMBER OF DAYS FOR TASK
	FIXR T2,T2
	DMOVE Q1,T2		;Q1 = LENGTH, Q2 = FINISH DATE
	MOVE T1,Q2		;GET FINISH DATE
	HRLZ T2,Q1		;GET LENGTH
	SUB T1,T2		;GET FIRST STAB AT START DATE
	MOVEM T1,Q3		;STORE START DATE
GETSD1:	MOVE T1,Q3		;GET START DATE
	MOVE T2,Q2		;GET FINISH DATE
	CALL GETNWD		;GET NUMBER OF DAYS BETWEEN DATES
	SUB T1,Q1		;SEE IF THE LENGTHS MATCH
	JUMPE T1,GETSD2		;IF 0, THEN DONE
	HRLZS T1
	ADDM T1,Q3		;CORRECT THE START DATE AND TRY AGAIN
	JRST GETSD1		;LOOP BACK TILL CORRECT DATE FOUND

GETSD2:	MOVE T1,Q3		;GET START DATE
	RET			;RETURN
;ROUTINE TO BUILD THE TASK TABLE

BLDTKT:	SAVEPQ
	CALL BLDINI		;INIT THE DATA BASE
	SKIPL PASCNT		;FIRST TIME THRU?
	JRST BLDTK4		;NO
	MOVSI P6,-1		;CONSTANT
	SETZM TSKCNT		;INIT COUNT OF TASKS
	SETZM TSKPTR		;CLEAR POINTER
	MOVE T1,PRJTBL		;GET ADR OF PROJECT TABLE
	MOVSI P1,-MAXTSK	;SET UP POINTER TO TABLES
	MOVEI Q1,1(T1)		;GET POINTER TO FIRST PROJECT
	HLRZ Q2,0(T1)		;GET NUMBER OF PROJECTS IN LIST
	JUMPLE Q2,R		;IF NONE, THEN DONE
BLDTK1:	HRRZ Q3,(Q1)		;GET ADR OF NEXT PROJECT BLOCK
	LOAD T4,PJTKT,(Q3)	;GET ADR OF TASK TABLE
	HLRZ T3,0(T4)		;GET NUMBER OF TASKS IN TABLE
	MOVEI T4,1(T4)		;GET ADR OF FIRST ENTRY IN TASK TABLE
	JUMPLE T3,BLDTK3	;IF NO TASKS, GO TO NEXT PROJECT
BLDTK2:	HRRZ T1,(T4)		;GET NEXT TASK BLOCK ADR
	AOS TSKCNT		;COUNT UP NUMBER OF TASKS ON LIST
	ADDM P6,TSKPTR		;KEEP AOBJN POINTER UP TO DATE
	STOR P1,TKTKI,(T1)	;SAVE TASK LIST INDEX IN TASK BLOCK
	MOVEM T1,TSKLST(P1)	;SAVE TASK ADR ON TASK LIST
	SETZM TSKFDL(P1)	;INIT FINISH DATE
	SETZM TSKSDL(P1)	;AND START DATE
	SETZM LVLTAB(P1)	;INIT LEVEL TABLE
	SETZM LVLCNT(P1)
	AOBJP P1,[WARN (<JRST BLDT3A>,<RAN OUT OF ROOM IN TASK LIST FOR ALL TASKS>)]
	AOS T4			;STEP TO NEXT TASK IN TABLE
	SOJG T3,BLDTK2		;LOOP BACK FOR ALL TASKS
BLDTK3:	AOS Q1			;STEP TO NEXT PROJECT
	SOJG Q2,BLDTK1		;LOOP BACK FOR ALL PROJECTS
BLDT3A:	CALL SKDSKD		;GO SCHEDULE ALREADY SCHEDULED TASKS
	MOVE T1,SKDCNT		;INITIALIZE PASCNT TO CURRENT POSITION
	SKIPGE PASCNT		;ONLY DO THIS ON THE FIRST PASS
	MOVEM T1,PASCNT
	MOVEM T1,PAS0CT		;SAVE THE LEVEL 0 COUNT
	RET			;DONE


BLDTK4:	MOVE T1,TSKPTR		;INIT TABLES
BLDTK5:	SETZM TSKFDL(T1)
	SETZM TSKSDL(T1)
	AOBJN T1,BLDTK5
	CALL SKDSKD		;GO SCHEDULE ALREADY STARTED TASKS
	RET

;ROUTINE TO SCHEDULE A TASK
;ACCEPTS IN T1/	INDEX INTO TSKLST TABLE
;	    T2/	EARLIEST START DATE
;	CALL SKDTSK
;RETURNS +1:	ALWAYS,	T1/	FINISH DATE
;			T2/	START DATE

SKDAVL:	MOVE T3,AVLTSK(T1)	;GET THE TASK INDEX
	HRROS T1		;FLAG THAT THIS IS AN AVLTSK INDEX
	JRST SKDTK0

SKDTSK:	MOVE T3,T1		;SET UP TASK ADR
	HRLI T1,(1B0)		;FLAG THAT THIS IS A TSKLST INDEX
SKDTK0:	STKVAR <SKDTKI,SKDTKT>
	MOVEM T1,SKDTKI		;SAVE THE INDEX VALUE
	MOVEM T3,SKDTKT		;SAVE THE TASK ADDRESS
	HRRZ T1,TSKLST(T3)	;GET THE ADR OF THE TASK
	MOVEM T1,LSTSKT		;SAVE THE ADR OF THE LAST TASK SCHEDULED
	MOVE T3,T1		;TASK ADR INTO T3
	LOAD T4,TKDVL,(T1)	;GET THE DEVELOPER LIST
	JUMPN T4,SKDTS1		;IF ONE THERE, SKIP
	LOAD T4,TKPRJ,(T1)	;NONE, GET GENERAL PROJECT LIST
	LOAD T4,PJDVL,(T4)
	SKIPN T4		;IS THERE A LIST?
	MOVE T4,DEVTBP		;NO, GET THE OVERALL LIST
SKDTS1:	MOVE T1,T4		;GET ADR OF FIRST DEVELOPER BLOCK
	CALL SCHED		;GO SCHEDULE THE TASK
	AOS T4,SKDCNT		;COUNT UP THE NUMBER OF SCHEDULED TASKS
	MOVE T3,SKDTKI		;GET INDEX INTO TSKLST
	MOVEM T3,SKDLST-1(T4)	;SAVE POINTER TO THIS SCHEDULED TASK
	MOVE T3,SKDTKT		;GET INDEX
	TLNN T2,-1		;IS THERE A START DATE?
	MOVE T2,T1		;NO, USE THE FINISH DATE
	MOVEM T1,TSKFDL(T3)	;SAVE THE FINISH DATE
	MOVEM T2,TSKSDL(T3)	;SAVE THE START DATE
	RET			;DONE, FINISH DATE IS IN T1
;ROUTINE TO BUILD THE AVAILABLE TASK LIST
;ACCEPTS IN T1/	0 = FORWARD SCAN, 1 = REVERSE SCAN

BLDPAV:	SAVEQ
	MOVEI Q3,1		;BUILD PERT AVAILABLE LIST
	HRL Q3,T1		;SAVE INDEX
	JRST BLDAV0

BLDAVL:	SAVEQ
	MOVEI Q3,0		;BUILD REGULAR AVILABLE LIST
BLDAV0:	SETZM AVLCNT		;INIT COUNT OF AVAIL TASKS
	MOVSI Q1,-MAXTSK
	MOVN T1,TSKCNT		;SET UP AOBJN POINTER TO TSKLST
	HRLZ Q2,T1
BLDAV1:	HRRZ T1,TSKLST(Q2)	;GET ADR OF NEXT TASK
	JUMPE Q3,BLDA1A		;SKIP IF NOT PERT
	SKIPE TSKINV(Q2)	;WANT THIS IN PERT?
	 JRST BLDAV2		;NO--SKIP IT
BLDA1A:	HRRZ T2,Q3		;GET INDEX VALUE
	HLRZ T3,Q3		;GET SCAN DIRECTION
	XCT [	SKIPN TSKFDL(Q2) ;HAS IT BEEN SCHEDULED?
		SKIPGE TSKLST(Q2)](Q3)
	CALL CHKAVL		;NO, SEE IF IT IS AVAILABLE
	 JRST BLDAV2		;NO, STEP TO NEXT TASK
	HRRZ T2,Q2		;GET TASK INDEX
	MOVEM T2,AVLTSK(Q1)	;SAVE TASK INDEX
	MOVEM T1,AVLSDL(Q1)	;SAVE THE START DATE
	AOS AVLCNT		;COUNT UP THE NUMBER OF AVAILABLE TASKS
	AOBJP Q1,RSKP		;IF REACHED MAXIMUM, RETURN
BLDAV2:	AOBJN Q2,BLDAV1		;LOOP BACK FOR REST OF TASKS
	SKIPG AVLCNT		;FOUND ANY?
	RET			;NO, GIVE +1 RETURN
	RETSKP			;YES, GIVE +2 RETURN


;ROUTINE TO OPTIMIZE THE AVAILABLE TASK LIST

BLDOAL:	SAVEQ
	MOVEI Q2,0		;INIT THE GROUP COUNTER
	MOVN Q1,AVLCNT		;GET POINTER TO AVLTSK
	HRLZS Q1
BLDOA1:	MOVE T1,Q1		;GET INDEX
	MOVE T2,AVLTSK(T1)	;GET TSKLST INDEX
	TLNE T2,-1		;THIS BEEN SCHEDULED YET?
	JRST BLDOA2		;YES, SKIP IT
	AOS Q2			;STEP COUNTER
	HRLM Q2,AVLTSK(T1)	;NO, STORE GROUP NUMBER
	CALL SKDCOM		;SCHEDULE THIS TASK
BLDOA2:	AOBJN Q1,BLDOA1		;LOOP BACK FOR ALL AVAILABLE TASKS
	MOVEM Q2,OAVCNT		;STORE COUNT
	RET
;ROUTINE TO CHECK THE AVAILABILITY OF A TASK
;ACCEPTS IN T1/	ADR OF TASK BLOCK
;	    T2/	INDEX FOR TYPE OF CHECK TO BE MADE
;	    T3/	0 = FORWARD SCAN, 1 = REVERSE SCAN
;	CALL CHKAVL
;RETURNS +1:	NOT AVAILABLE YET
;	 +2:	T1/	EARLIEST START DATE

CHKAVL:	SAVEPQ
	HRRZ Q3,T2		;SAVE THE INDEX VALUE
	HRRZ P1,T3		;SAVE THE SCAN DIRECTION
	LOAD Q1,TKMSD,(T1)	;GET THE MINIMUM START DATE
	CAMGE Q1,SKDTAD		;IS IT AFTER TODAYS DATE?
	MOVE Q1,SKDTAD		;NO, INIT START DATE TO TODAY'S DATE
	XCT [	LOAD T2,TKDLP,(T1)	;GET DEPENDENCY LIST
		LOAD T2,TKBLP,(T1)](P1)
	JUMPE T2,CHKAV4		;IF NO DEPENDENCIES, RETURN +2
CHKAV0:	XCT [	LOAD T3,DPBTK,(T2)	;GET POINTER TO BLOCKING TASK
		LOAD T3,DPTKP,(T2)](P1)
	LOAD Q2,TKTKI,(T3)	;GET TASK LIST INDEX
	SKIPE TSKINV(Q2)	;WANT TASK IN PERT?
	JRST CHKAV3		;NO--SKIP IT
	XCT [	SKIPN TSKFDL(Q2) ;IS THERE A FINISH DATE
		SKIPGE TSKLST(Q2)](Q3)
	RET			;IF NONE YET, THEN NOT AVAILABLE
	CAMGE Q1,TSKFDL(Q2)	;IS THIS A NEW LATEST FINISH DATE
	MOVE Q1,TSKFDL(Q2)	;YES, REMEMBER IT
CHKAV3:	XCT [	LOAD T2,DPDLP,(T2)	;STEP TO NEXT DEPENDENCY
		LOAD T2,DPBLP,(T2)](P1)
	JUMPN T2,CHKAV0		;LOOP BACK FOR OTHERS
CHKAV4:	MOVE T1,Q1		;RETURN THE EARLIEST START DATE
	RETSKP


;ROUTINE TO FIND ANY MILESTONES (0 LENGTH TASKS)
;RETURNS +1:	NONE FOUND
;	 +2:	T1/	INDEX INTO AVLTSK LIST

GETMS:	MOVN T1,AVLCNT		;SET UP AOBJN POINTER
	HRLZS T1
GETMS1:	MOVE T2,AVLTSK(T1)	;GET INDEX INTO TASK TABLE
	MOVE T2,TSKLST(T2)	;GET TASK ADR
	LOAD T2,TKELN,(T2)	;GET TASK LENGTH
	JUMPE T2,GETMS2		;IF 0, THEN FOUND ONE
	AOBJN T1,GETMS1		;SEARCH ALL OF AVAILABLE TASKS
	RET			;NONE FOUND

GETMS2:	HRRZS T1		;RETURN INDEX INTO AVLTSK LIST
	RETSKP
;ROUTINE TO LOOK FOR A FREE DEVELOPER
;RETURNS +1:	ALL DEVELOPERS HAVE MORE THAN ONE PROJECT
;	 +2:	T1/	INDEX INTO AVLTSK

FNDAVD:	SAVEQ
	MOVN Q1,AVLCNT		;GET AOBJN POINTER TO LIST
	HRLZS Q1
FNDAV1:	MOVN Q2,AVLCNT		;GET AOBJN POINTER TO TASK LIST
	HRLZS Q2
FNDAV2:	AOBJP Q2,FNDAV3		;LOOK FOR A MATCH
FNDAV9:	CAMN Q1,Q2		;ARE WE AT THE SAME TASK?
	JRST [	AOBJP Q2,FNDAV4
		JRST FNDAV9]	;YES, SKIP IT
	MOVE T1,AVLTSK(Q1)	;GET POINTER TO DEVELOPER STRING
	MOVE T1,TSKLST(T1)	;GET TASK ADR
	LOAD T2,TKPRJ,(T1)	;GET PROJECT LIST ADDRESS
	LOAD Q3,TKDVL,(T1)	;GET TASK DEVELOPER LIST
	SKIPN Q3		;ANY THERE?
	LOAD Q3,PJDVL,(T2)	;NO, GET PROJECT LIST
	SKIPN Q3		;IS THERE A LIST?
	MOVE Q3,DEVTBP		;NO, GET THE OVERALL LIST
	JUMPE Q3,FNDAV3		;IF NO LIST, GO SCHEDULE THIS ONE
FNDAV8:	MOVE T1,AVLTSK(Q2)	;NOW GET THE SECOND TASK'S DEVELOPER LIST
	MOVE T1,TSKLST(T1)	;GET TASK ADR
	LOAD T2,TKPRJ,(T1)	;GET ADR OF PROJECT BLOCK
	LOAD T4,TKDVL,(T1)	;GET TASK DEVELOPER LIST
	SKIPN T4		;ANY THERE?
	LOAD T4,PJDVL,(T2)	;NO, GET PROJECTS LIST
	SKIPN T4		;IS THERE A LIST?
	MOVE T4,DEVTBP		;NO, GET THE OVERALL LIST
	JUMPE T4,FNDAV5		;IF NONE, THEN NO MATCH
FNDAV7:	LOAD T1,DVNAM,(Q3)	;GET ADR OF NAME STRING
	LOAD T2,DVNAM,(T4)	;GET SECOND NAME STRING
FNDAV6:	MOVE T3,(T1)		;GET NEXT WORD IN STRING
	CAME T3,(T2)		;MATCH?
	JRST FNDAV5		;NO, GO ON TO NEXT DEVELOPER
	TRNN T3,377		;REACHED END OF NAME STRING?
	JRST FNDAV4		;YES, FOUND A MATCH
	AOS T1			;NOT AT END, STEP TO NEXT WORD
	AOJA T2,FNDAV6		;LOOP BACK FOR REST OF STRING COMPARE

FNDAV5:	LOAD T4,DVLNK,(T4)	;STEP TO NEXT DEVELOPER IN LIST
	JUMPN T4,FNDAV7		;IF MORE, GO COMPARE THESE NAMES
	LOAD Q3,DVLNK,(Q3)	;STEP TO NEXT DEVELOPER IN OTHER LIST
	JUMPN Q3,FNDAV8		;IF MORE, GO COMPARE THEM
	JRST FNDAV2		;NO MATCHES HERE, GO TRY OTHER TASKS

FNDAV4:	AOBJN Q1,FNDAV1		;YES, GO LOOK AT THE OTHER TASKS
	RET			;NO FREE DEVELOPERS

FNDAV3:	HRRZ T1,Q1		;RETURN THE INDEX FOR THIS TASK
	RETSKP
;ROUTINE TO SCHEDULE AN ENTIRE TASK GROUP
;ACCEPTS IN T1/	GROUP NUMBER
;	CALL SKDTG
;RETURNS +1:	DONE

SKDTG:	SAVEQ
	STKVAR <SKDTGI>
	AOS T4,SKDCNT		;STEP SKDCNT
	HRRZM T1,SKDLST-1(T4)	;SAVE GROUP NUMBER IN SKDLST
	MOVE Q1,T1		;SAVE GROUP NUMBER
	MOVN Q2,AVLCNT		;SET UP POINTER TO LIST
	HRLZS Q2
	MOVE Q3,Q2		;Q3 = AOBJN POINTER
SKDTG1:	MOVSI T1,(1B0)		;CLEAR SCHEDULE FLAG
	ANDCAM T1,AVLTSK(Q3)
	AOBJN Q3,SKDTG1
	MOVE Q3,Q2		;SET UP POINTER AGAIN
SKDTG2:	MOVE T1,SKDTAD		;GET SCHEDULER START DATE
	SETZ T2,		;NO LAST TASK SCHEDULED
	MOVE T3,Q1		;GET GROUP NUMBER
	CALL GETLFT		;GET NEXT TASK TO SCHEDULE
	 JRST SKDTG3		;NO MORE TASKS TO DO
	MOVSI T2,(1B0)		;SCHEDULE THIS ONE
	IORM T2,AVLTSK(T1)
	MOVE T2,AVLSDL(T1)	;GET THE START DATE
	HRRZ T1,AVLTSK(T1)	;GET THE TASK ADDRESS
	HRRZ T3,TSKLST(T1)
	MOVEM T1,SKDTGI		;SAVE INDEX INTO TSKLST
	LOAD T1,TKDVL,(T3)	;GET POINTER TO DEVELOPER LIST
	LOAD T4,TKPRJ,(T3)	;GET POINTER TO PROJECT BLOCK
	SKIPN T1		;IS THERE A TASK LIST
	LOAD T1,PJDVL,(T4)	;NO, GET THE PROJECT LIST
	SKIPN T1		;ANY THERE YET?
	MOVE T1,DEVTBP		;NO, GET THE OVERALL LIST POINTER
	CALL SCHED		;GO SCHEDULE THEM
	MOVE T3,SKDTGI		;GET INDEX INTO TSKLST
	TLNN T2,-1		;IS THERE A START DATE?
	MOVE T2,T1		;NO, USE THE FINISH DATE
	MOVEM T1,TSKFDL(T3)	;SAVE THE FINISH DATE
	MOVEM T2,TSKSDL(T3)	;SAVE THE START DATE
	AOBJN Q3,SKDTG2		;LOOP BACK FOR ALL TASKS
SKDTG3:	MOVSI T1,(1B0)		;CLEAR THE FLAGS
	ANDCAM T1,AVLTSK(Q2)
	AOBJN Q2,SKDTG3
	RET
;ROUTINE TO GET THE LATEST FINISHING TASK
;ACCEPTS IN T1/	SCHEDULER START DATE
;	    T2/	ADR OF LAST TASK SCHEDULED
;	    T3/	-1 = FREE CHOICE, N = GROUP NUMBER
;	CALL GETLFT
;RETURNS +1:	NO MORE TASKS IN THIS GROUP
;	 +2:	T1/	INDEX INTO AVLTSK LIST


;RULES FOR CHOOSING A FREE TASK
;1)	IF THERE IS A GROUP NUMBER SPECIFIED, THEN THE
;		TASK MUST BE FROM THAT GROUP.
;2)	THE TASK MUST HAVE THE HIGHEST PREFERENCE VALUE
;		FOUND WITHIN THE GROUP.
;3)	IF THERE WAS A "LAST TASK" SPECIFIED, THEN USE A TASK
;		FROM THE SAME PROJECT AS LAST TASK (IF ANY).
;4)	CHOSE THE TASK THAT CAN BE STARTED AT THE EARLIEST
;		POSSIBLE TIME.
;5)	IF MULTIPLE CHOICE STILL REMAINS, CHOSE THE LONGEST TASK.

GETLFT:	SAVEPQ
	DMOVE Q1,T1		;SAVE THE ARGS
	MOVE Q3,T3
	MOVE T1,Q3		;GET THE GROUP NUMBER
	CALL GETHPV		;GET THE HIGHEST PREFERENCE VALUE
	 RET			;NONE FOUND
	MOVEM T1,P2		;SAVE THE PREFERENCE VALUE
	MOVE T1,Q3		;GET THE GROUP NUMBER
	MOVE T2,P2		;GET THE PREFERENCE VALUE
	SKIPE T3,Q2		;ANY "LAST TASK" SPECIFIED?
	LOAD T3,TKPRJ,(Q2)	;YES, GET THE PROJECT ADR
	MOVE T4,Q1		;GET THE SCHEDULER START DATE
	CALL GETLTA		;GET THE LONGEST TASK 
	 SKIPA			;NOT FOUND
	RETSKP			;DONE
	MOVE T1,Q3		;TRY AGAIN FOR ANY TASK
	MOVE T2,P2		;PREFERENCE VALUE
	SETZ T3,		;NO "LAST TASK" THIS TIME
	MOVE T4,Q1		;START DATE
	CALL GETLTA		;GET LONGEST TASK
	 RET			;NONE
	RETSKP			;FOUND IT
;ROUTINE TO GET THE HIGHEST PREFERENCE VALUE WITHIN A GROUP
;ACCEPTS IN T1/	GROUP # OR -1 IF NONE
;RETURNS +1:	NONE FOUND
;	 +2:	T1/	PREFERENCE VALUE

GETHPV:	SAVEQ
	MOVE Q1,T1		;SAVE THE GROUP NUMBER
	MOVSI Q2,(1B0)		;GET THE LOWEST NEG NUMBER
	MOVN Q3,AVLCNT		;SET UP TO SCAN AVLTSK LIST
	HRLZS Q3
GETHP1:	HLRZ T1,AVLTSK(Q3)	;GET THE GROUP NUMBER
	CAME T1,Q1		;A MATCH?
	JUMPGE Q1,GETHP2	;NO, SKIP IT UNLESS NO GROUP NUMBER
	HRRZ T1,AVLTSK(Q3)	;GET TASK ADR
	MOVE T1,TSKLST(T1)
	CALL GETPRF		;GET THE PREFERENCE VALUE OF THIS TASK
	CAMLE T1,Q2		;GOT A NEW HIGH?
	MOVEM T1,Q2		;YES, SAVE IT
GETHP2:	AOBJN Q3,GETHP1		;LOOP BACK FOR ALL TASKS IN LIST
	MOVE T1,Q2		;GET THE ANSWER
	CAMG T1,[1B0]		;DID WE FIND ANY AT ALL?
	RET			;NO
	RETSKP			;YES



;ROUTINE TO GET THE PREFERENCE VALUE OF A TASK
;ACCEPTS IN T1/	TASK ADR
;RETURNS +1:	T1/	PREFERENCE VALUE

GETPRF:	LOAD T2,TKPRJ,(T1)	;GET PROJECT ADR
	LOAD T2,PJPRF,(T2)	;GET THE PROJECT PREFERENCE VALUE
	LOAD T1,TKPRF,(T1)	;GET THE TASK PREFERENCE VALUE
	FADR T1,T2		;SUM THEM
	RET			;RETURN THE ANSWER
;ROUTINE TO GET THE LONGEST TASK
;ACCEPTS IN T1/	GROUP # OR -1 IF NONE
;	    T2/	PREFERENCE VALUE
;	    T3/	PROJECT ADR OR 0 IF NONE
;	    T4/	SCHEDULER START DATE
;RETURNS +1:	NONE FOUND
;	 +2:	T1/	INDEX INTO AVLTSK LIST

GETLTA:	SAVEPQ
	STKVAR <GETLTL,GETLTC,GETLTT>
	DMOVE P1,T1		;SAVE THE ARGS
	DMOVE P3,T3
	SETOM GETLTC		;ASSUME A CRITICAL PATH TO START
	CALL CHKCP		;GO SEE IF THERE ARE ANY CRITICAL TASKS
	 SETZM GETLTC		;NONE FOUND
	DMOVE T1,P1		;GET ARGS
	DMOVE T3,P3
	CALL GETETA		;GET THE EARLIEST STARTING DATE
	 RET			;NONE FOUND
	CAMGE T1,P4		;BEFORE SCHEDULER START DATE?
	MOVE T1,P4		;YES, USE SCHEDULER START DATE
	MOVEM T1,Q1		;SAVE THE START DATE
	SETO Q2,		;INIT TASK ADR
	SETOM GETLTT		;INIT TASK ADR BACKUP (IF OPTIMUM NOT FOUND)
	SETZM GETLTL		;INIT LONGEST TASK FINISH DATE
	MOVN Q3,AVLCNT		;SET UP POINTER TO AVLTSK
	HRLZS Q3
GETLT1:	HLRZ T1,AVLTSK(Q3)	;GET THE GROUP NUMBER
	CAME T1,P1		;A MATCH?
	JUMPGE P1,GETLT2	;NO, UNLESS NO GROUP # SPECIFIED
	HRRZ T1,AVLTSK(Q3)	;GET TASK ADR
	MOVE T1,TSKLST(T1)
	LOAD T3,TKFLG,(T1)	;CHECK THE CRITICAL PATH
	TXNN T3,TK%CP		;IS THIS A CRITICAL TASK
	SKIPN GETLTC		;NO, DOES IT HAVE TO BE ONE?
	SKIPA			;NO, OK
	JRST GETLT2		;NOT CRITICAL, GO TO NEXT TASK
	LOAD T2,TKPRJ,(T1)	;GET THE PROJECT ADR
	CAME T2,P3		;FOUND A MATCH?
	JUMPG P3,GETLT2		;NO, UNLESS NONE SPECIFIED
	CALL GETPRF		;GET PREFERENCE VALUE
	CAME T1,P2		;HIGH ENOUGH?
	JRST GETLT2		;NO
	HRRZM Q3,GETLTT		;REMEMBER THIS ONE IN CASE OPTIMUM NOT FOUND
	MOVE T2,AVLSDL(Q3)	;GET THE START DATE
	CAMLE T2,Q1		;EARLY ENOUGH?
	JRST GETLT2		;NO
	HRRZ T1,AVLTSK(Q3)	;GET INDEX INTO TSKLST
	CALL GETFD		;GET FINISH DATE
	CAMG T1,GETLTL		;IS THIS A NEW LONGEST?
	JRST GETLT2		;NO
	MOVEM T1,GETLTL		;YES, SAVE IT
	HRRZ Q2,Q3		;AND ALSO REMEMBER THE INDEX INTO AVLTSK
GETLT2:	AOBJN Q3,GETLT1		;LOOP BACK FOR ALL TASKS IN LIST
	SKIPGE T1,Q2		;FOUND ANY?
	SKIPL T1,GETLTT		;WAS A BACKUP ADR FOUND?
	RETSKP			;YES
	RET			;NONE AT ALL
;ROUTINE TO GET THE EARLIEST STARTING TASK
;ACCEPTS IN T1/	GROUP # OR -1 IF NONE
;	    T2/	PREFERENCE VALUE
;	    T3/	PROJECT ADR OR 0 IF NONE
;RETURNS +1:	NONE FOUND
;	 +2:	T1/	INDEX INTO AVLTSK LIST

GETETA:	SAVEPQ
	DMOVE P1,T1		;SAVE THE ARGS
	DMOVE P3,T3
	HRLOI Q1,377777		;INIT EARLIEST DATE
	MOVN Q3,AVLCNT		;SET UP POINTER TO AVLTSK
	HRLZS Q3
GETET1:	HLRZ T1,AVLTSK(Q3)	;GET THE GROUP NUMBER
	CAME T1,P1		;A MATCH?
	JUMPGE P1,GETET2	;NO, UNLESS NO GROUP # SPECIFIED
	HRRZ T1,AVLTSK(Q3)	;GET TASK ADR
	MOVE T1,TSKLST(T1)
	LOAD T2,TKPRJ,(T1)	;GET THE PROJECT ADR
	CAME T2,P3		;FOUND A MATCH?
	JUMPG P3,GETET2		;NO, UNLESS NONE SPECIFIED
	CALL GETPRF		;GET PREFERENCE VALUE
	CAME T1,P2		;HIGH ENOUGH?
	JRST GETET2		;NO
	MOVE T2,AVLSDL(Q3)	;GET THE START DATE
	CAMGE T2,Q1		;NEW EARLIEST DATE?
	MOVEM T2,Q1		;YES, SAVE IT
GETET2:	AOBJN Q3,GETET1		;LOOP BACK FOR ALL TASKS IN LIST
	MOVE T1,Q1		;GET DATE
	CAMN T1,[377777,,777777] ;FOUND ANY?
	RET			;NO
	RETSKP			;YES


;ROUTINE TO CHECK FOR CRITICAL PATH TASKS
;ACCEPTS IN T1/	GROUP # OR -1 IF NONE
;	    T2/	PREFERENCE VALUE
;	    T3/	PROJECT ADR OR 0 IF NONE
;RETURNS +1:	NONE FOUND
;	 +2:	THERE IS AT LEAST ONE CRITICAL PATH TASK

CHKCP:	SAVEPQ
	DMOVE P1,T1		;SAVE THE ARGS
	DMOVE P3,T3
	MOVN Q3,AVLCNT		;SET UP POINTER TO AVLTSK
	HRLZS Q3
CHKCP1:	HLRZ T1,AVLTSK(Q3)	;GET THE GROUP NUMBER
	CAME T1,P1		;A MATCH?
	JUMPGE P1,CHKCP2	;NO, UNLESS NO GROUP # SPECIFIED
	HRRZ T1,AVLTSK(Q3)	;GET TASK ADR
	MOVE T1,TSKLST(T1)
	LOAD T2,TKPRJ,(T1)	;GET THE PROJECT ADR
	CAME T2,P3		;FOUND A MATCH?
	JUMPG P3,CHKCP2		;NO, UNLESS NONE SPECIFIED
	CALL GETPRF		;GET PREFERENCE VALUE
	CAME T1,P2		;HIGH ENOUGH?
	JRST CHKCP2		;NO
	HRRZ T1,AVLTSK(Q3)	;GET TASK INDEX
	MOVE T1,TSKLST(T1)	;GET TASK ADR
	JN TKCP,(T1),RSKP	;IF CRITICAL PATH, RETURN IMMEDIATELY
CHKCP2:	AOBJN Q3,CHKCP1		;LOOP BACK FOR ALL TASKS IN LIST
	RET			;NONE FOUND


;ROUTINE TO GET THE FINISHING DATE OF A TASK
;ACCEPTS IN T1/	INDEX INTO TSKLST
;	    T2/	START DATE
;	CALL GETFD
;RETURNS +1:	ALWAYS, T1/	FINISH DATE

GETFD:	MOVE T1,TSKLST(T1)	;GET ADR OF TASK
	MOVE T3,T1		;T3 = TASK ADR
	LOAD T4,TKDVL,(T1)	;GET ADR OF DEVELOPER LIST
	JUMPN T4,GETFD1		;ONE THERE?
	LOAD T4,TKPRJ,(T1)	;NO, GET PROJECT LIST
	LOAD T4,PJDVL,(T4)
	SKIPN T4		;IS THERE A LIST?
	MOVE T4,DEVTBP		;NO, GET THE OVERALL LIST
GETFD1:	MOVE T1,T4		;SET UP ADR OF FIRST DEVELOPER BLOCK
	CALL NSCHED		;GO GET FINISH DATE
	RET
;ROUTINE TO CHECK IF A LOOP HAS BEEN FOUND IN THE DEPENDENCY LIST

CHKLOP:	MOVE T1,TSKPTR		;GET POINTER TO TASK LIST
CHKLP1:	SKIPN TSKFDL(T1)	;BEEN SCHEDULED?
	RET			;NO, THEN A LOOP EXISTS
	AOBJN T1,CHKLP1		;LOOP BACK FOR ALL TASKS
	RETSKP			;EVERY TASK HAS BEEN SCHEDULED


;ROUTINE TO CHECK IF A NEW BEST RUN WAS MADE

CHKBST:	MOVE T1,TSKPTR		;SET UP TO SCAN TSKLST
	MOVEI T2,0		;INIT ENDING DATE
CHKBS1:	CAMGE T2,TSKFDL(T1)	;FOUND A NEW END DATE?
	MOVE T2,TSKFDL(T1)	;YES, REMEMBER IT
	AOBJN T1,CHKBS1		;LOOP THRU ALL TASKS
	CAML T2,BESTFD		;FOUND A NEW BEST?
	RET			;NO
	MOVEM T2,BESTFD		;REMEMBER THE NEW BEST FINISH DATE
	MOVE T1,LVL0TK		;AND THE TASK ADR
	MOVEM T1,BESTSK
	RET
;ROUTINE TO SCHEDULE A LIST OF DEVELOPERS
;ACCEPTS IN T1/	ADR OF FIRST DEVELOPER BLOCK IN CHAIN
;	    T2/	START DATE
;	    T3/	ADR OF TASK BLOCK
;	CALL SCHED	OR	CALL NSCHED (FOR FINISH DATE ONLY)
;RETURNS +1:	ALWAYS, T1/	FINISH DATE
;			T2/	START DATE

NSCHED:	TDZA T4,T4		;DO NOT SCHEDULE THE DEVELOPERS
SCHED:	SETO T4,		;SCHEDULE
	SAVEPQ			;SAVE SOME AC'S
;***WARNING*** TRVAR USES P6 FOR THE FRAME POINTER
	TRVAR	<SCHEDA,SCHEDD,SCHEDS,SCHEDL,<SCHEDQ,MAXDEV>,SCHEDF,<SCHEDB,5>,SCHEDT,<SCHDVB,.DVLEN>,<SCHTKB,.TKLEN>,SCHEDR,SCHEDP,SCHEDV,SCHEDC>
	DMOVE P1,T1		;COPY ARGUMENTS
	DMOVE P3,T3		; ..
	MOVEM T3,SCHEDR
	JUMPE T1,SCHEDX		;SPECIAL IF NO DEVELOPERS
	LOAD Q1,TKADR,(P3)	;ALL-DEVELOPERS-REQUIRED?
	JUMPE Q1,SCHEDX		;NO--DO STANDARD THING
	LOAD Q1,DVLNK,(P1)	;SEE IF ONLY ONE DEVELOPER
	JUMPE Q1,SCHEDX		;JUST DO THAT IF TRUE
	LOAD Q1,TKELN,(P3)	;ESTIMATED LENGTH
	JUMPE Q1,SCHEDX		;MUST BE NON-ZERO

;COPY TASK BLOCK
	HRL T1,P3		;SOURCE OF BLT
	HRRI T1,SCHTKB		;DESTINATION
	MOVEI T2,-1+SCHTKB	;WHERE TO STOP
	ADDI T2,.TKLEN		; ..
	BLT T1,(T2)		;COPY THE BLOCK
;SUM ALL DEVELOPERS
	MOVEI P5,0		;INITIAL SUM
	MOVE T2,P1		;FIRST DEVELOPER
XSCH1:	LOAD T3,DVRAT,(T2)	;GET RATE
	FADR P5,T3		;ADD TO SUM
	LOAD T2,DVLNK,(T2)	;STEP TO NEXT BLOCK
	JUMPN T2,XSCH1		;LOOP OVER ALL DEVELOPERS
	MOVEM P4,SCHEDP		;SAVE THE SCHED/NSCHED FLAG
	SETZ P4,		;AND MARK AS NSCHED
	MOVEM P1,SCHEDV		;SAVE LIST OF DEVELOPERS
XSCH2:	MOVE P1,SCHEDV		;RESET TO TOP OF LIST
	CALL XSCH3		;FIND LATEST STARTING DATE
	  JRST XSCH2		;SOMETHING GOT LATER
	SKIPN P4,SCHEDP		;REALY WANT TO SCHEDULE?
	RET			;NO--WE HAVE THE DATES
	MOVE P1,SCHEDV		;RESET TO TOP OF LIST
	CALL XSCH3		;YES--GO DO IT AGAIN
	  ERRMES <BUG IN CODE AT XSCH2 -- CALL DON LEWINE>
	RET			;ALL DONE
;NOW DO EACH DEVELOPER ACCORDING TO HIS ABILITY
XSCH3:	HRLOI Q2,377777		;MAX START DATE
	MOVEI Q1,0		;MIN END DATE
XSCH4:	MOVEI T2,SCHDVB		;ADDRESS OF DUMMY BLOCK
	LOAD T1,DVNAM,(P1)	;COPY PARAMETERS
	STOR T1,DVNAM,(T2)
	LOAD T1,DVRAT,(P1)
	STOR T1,DVRAT,(T2)
	LOAD T1,DVHCR,(P1)
	STOR T1,DVHCR,(T2)
	MOVE T1,P3
	STOR T1,DVBKP,(T2)
	SETZRO DVLNK,(T2)	;NO LINK
	LOAD T1,DVRAT,(T2)	;GET THIS RATE
	FDVR T1,P5		;FRACTION OF TOTAL
	MOVEI T4,SCHTKB
	LOAD T2,TKELN,(P3)	;GET ESTIMATED LENGTH
	FMPR T2,T1		;SCALE FOR THIS DEVELOPER
	STOR T2,TKELN,(T4)	;ONLY SCHEDULE PART
	LOAD T2,TKTTD,(P3)	;ALSO SCALE TIME TO DATE
	FMPR T2,T1
	STOR T2,TKTTD,(T4)
	MOVEI T1,SCHDVB		;FAKE DEVELOPER BLOCK
	MOVE T2,P2		;START DATE
	MOVEI T3,SCHTKB		;FAKE TASK BLOCK
	MOVE T4,P4		;FLAG
	CALL SCHEDX		;GO DO IT
	CAMLE T2,P2		;DID START GET LATER?
	JRST [	MOVE P2,T2	;YES--ADJUST START
		RET]		;DO WHOLE THING OVER
	CAMGE T2,Q2		;EARLIER START DATE?
	MOVE Q2,T2		;YES--REMEMBER THAT
	CAMLE T1,Q1		;LATER END DATE?
	MOVE Q1,T1		;YES--REMEMBER THAT
	LOAD P1,DVLNK,(P1)	;STEP TO NEXT DEVELOPER
	JUMPN P1,XSCH4		;LOOP OVER ALL DEVELOPERS
	DMOVE T1,Q1		;COPY DATES
	RETSKP			;ALL DONE
;SUBROUTINE OF SCHED. CALLED ONLY FROM ABOVE (USES SCHED TRVAR'S)
SCHEDX:	SAVEPQ
	MOVEM T1,SCHEDA		;SAVE ADR OF DEVELOPER LIST
	MOVEM T2,SCHEDD		;SAVE STARTING DATE
	SETZM SCHEDS		;INIT START DATE ANSWER
	MOVEM T3,SCHEDT		;SAVE TASK ADR
	MOVEM T3,LSTSKT		;REMEMBER THE LAST TASK SCHEDULED
	MOVEM T4,SCHEDF		;SAVE FLAG
	LOAD T2,TKAFD,(T3)	;IS THERE A FINISH DATE?
	LOAD T4,TKALN,(T3)	;GET THE ACTUAL LENGTH
	SKIPN T2
	LOAD T4,TKELN,(T3)	;NOT FINISHED, USE THE ESTIMATED LENGTH
	JUMPE T2,SCHED0		;IS THERE A FINISH DATE?
	SKIPN T3,SCHEDD		;YES, IS THERE A START DATE?
	MOVEM T2,SCHEDD		;NO, SAVE FINISH DATE AS START DATE
	SKIPN T3		;WAS THERE A START DATE?
	SETZ T4,		;NO, MAKE THE TASK LENGTH BE 0
SCHED0:	MOVEM T4,SCHEDL		;SAVE LENGTH
	MOVE T4,SCHEDT		;GET TASK BLOCK ADR
	LOAD T3,TKTTD,(T4)	;GET THE TIME-TO-DATE
	MOVNS T3		;NEGATE IT
	FADRM T3,SCHEDL		;DECREMENT LENGTH BY WHAT SPENT SO FAR
	MOVE T3,SCHEDL		;GET REMAINING AMOUNT
	JUMPE T1,SCHED4		;IF NO DEVELOPER, SPECIAL CASE
SCHED1:	MOVEI Q1,-1+SCHEDQ	;SET UP POINTER TO QUEUE
	HRLI Q1,-MAXDEV
	HRLOI Q2,377777		;INIT TO LATEST DATE
	MOVE Q3,SCHEDA		;GET ADR OF DEVELOPER LIST
	SETZB P1,P4		;INIT COUNTS
SCHED2:	LOAD T1,DVNAM,(Q3)	;GET DEVELOPER NAME
	MOVE T2,SCHEDD		;GET START DATE
	MOVE T3,SCHEDT		;GET THE TASK ADR
	CALL FNDCHG		;FIND WHEN THE NEXT CHANGE HAPPENS
	CAMGE T1,Q2		;FOUND A NEW LOW?
	MOVE Q2,T1		;YES
	LOAD T3,DVRAT,(Q3)	;GET RATE OF PROGRESS
	CAMLE T3,T2		;GET MIN OF REMAINING AND ALLOWED RATES
	MOVE T3,T2		;USE THE REMAINING RATE FOR THIS USER
	PUSH Q1,T3		;SAVE IT
	AOS P4			;REMEMBER THE COUNT
	LOAD T4,DVHCR,(Q3)	;GET HANDICAP
	FMPR T3,T4		;GET REAL RATE OF PROGRESS
	FADR P1,T3		;SUM THE RATES
	LOAD Q3,DVLNK,(Q3)	;STEP TO NEXT DEVELOPER
	JUMPN Q3,SCHED2		;IF ANOTHER, GO GET RATE
	; ..
	; ..
	MOVE T2,Q2		;GET DATE OF CHANGE
	MOVE T1,SCHEDD		;GET NUMBER OF DAYS TO BE SPENT
	CALL GETNWD		;GET NUMBER OF WORKING DAYS BETWEEN DATES
	FLTR T2,T1		;FLOAT NUMBER OF DAYS
	FMPR T2,P1		;GET NUMBER OF DAYS COMPLETED THIS PERIOD
	CAMLE T2,SCHEDL		;ENOUGH TO COVER THE REMAINING TIME?
	MOVE T2,SCHEDL		;YES
	MOVE T3,SCHEDL		;GET REMAINING TIME ON TASK
	FSBR T3,T2		;CALCULATE THE DIFFERENCE
	MOVEM T3,SCHEDL		;REMEMBER THE REMAINING TIME
	FDVR T2,P1		;INCLUDE THE RATE SKEW
	FIXR T2,T2		;GET INTEGER DAYS
	MOVE P2,SCHEDD		;GET START DATE
	MOVE T1,SCHEDD		;GET FINISH DATE GIVEN THE NUMBER OF DAYS
	CALL GETNFD
	MOVEM T1,SCHEDD		;SAVE THE NEW FINISH DATE
	SKIPE T3,SCHEDL		;FINISHED YET?
	MOVEM Q2,SCHEDD		;NO, THEN NEW FINISH DATE IS CHANGE DATE
	SKIPE SCHEDL		;DONE?
	JUMPE P1,SCHED1		;NO, IF RATE WAS ZERO, DONT SCHEDULE 
	SKIPN SCHEDS		;IS THIS THE FIRST START DATE FOUND?
	MOVEM P2,SCHEDS		;YES, REMEMBER THIS ONE
	MOVEI Q1,SCHEDQ		;GET POINTER TO START OF QUEUE
	MOVE Q3,SCHEDA		;GET ADR OF DEVELOPER LIST AGAIN
SCHED3:	LOAD T1,DVNAM,(Q3)	;GET DEVELOPER NAME
	MOVEM T1,0+SCHEDB	;SAVE IT IN ARG BLOCK
	MOVEM P2,1+SCHEDB	;SAVE START DATE IN ARG BLOCK
	MOVE T1,SCHEDD		;GET FINISH DATE
	MOVEM T1,2+SCHEDB	;SAVE FINISH DATE IN ARG BLOCK
	MOVE T1,(Q1)		;GET RATE
	MOVEM T1,3+SCHEDB	;SAVE RATE
	MOVE T1,SCHEDR		;GET TASK ADR
	MOVEM T1,4+SCHEDB
	MOVEI T1,SCHEDB		;GET ADR OF TASK BLOCK
	SKIPE SCHEDF		;SCHEDULE?
	CALL SCHDEV		;YES, GO SCHEDULE THIS DEVELOPER
	LOAD Q3,DVLNK,(Q3)	;STEP TO NEXT DEVELOPER
	AOS Q1
	SOSLE P4		;ANY MORE TO BE DONE?
	JUMPN Q3,SCHED3		;YES, LOOP BACK FOR REST
	SKIPLE SCHEDL		;ANY MORE MORE TO BE DONE?
	JRST SCHED1		;YES, GO SCHEDULE IT
SCHED5:	MOVE T1,SCHEDD		;RETURN THE FINAL FINISH DATE
	SKIPN T2,SCHEDS		;GET START DATE
	MOVE T2,T1		;IF NONE, USE THE FINISH DATE
	RET
SCHED4:	MOVE T1,SCHEDD		;GET FINISH DATE
	FIXR T2,T3		;GET NUMBER OF WORK DAYS
	MOVE T4,SCHEDT		;GET ADDRESS OF TASK BLOCK
	LOAD T3,TKTTD,(T4)	;GET TIME TO DATE
	SKIPE T3		;OK IF ZERO
	LOAD T1,TKTAD,(T4)	;ELSE ASSUME STARTED AT TIME-TO-DATE
				;DATE
	MOVEM T1,SCHEDC		;SAVE FOR LATER
	CALL GETNFD		;GET THE FINISH DATE
	MOVE Q1,T1		;SAVE FINISH DATE
	MOVEI T1,[ASCIZ/UNKNOWN/]
	MOVE T2,SCHEDC		;SCHEDULE TASK TO "UNKNOWN" DEVELOPER
	MOVE T3,Q1		;GET FINISH DATE
	MOVSI T4,(1.0)		;RATE = 1.0
	MOVEM T1,0+SCHEDB	;SET UP ARG BLOCK - DEV NAME
	MOVEM T2,1+SCHEDB	;START DATE
	MOVEM T3,2+SCHEDB	;FINISH DATE
	MOVEM T4,3+SCHEDB	;RATE
	MOVE T1,SCHEDR		;TASK BLOCK ADR
	MOVEM T1,4+SCHEDB
	MOVEI T1,SCHEDB		;GET ADR OF ARG BLOCK
	SKIPE SCHEDF		;SCHEDULE?
	CALL SCHDEV		;YES
	MOVE T1,Q1		;RETRUN FINISH DATE
	MOVE T2,SCHEDD		;RETURN START DATE IN T2
	RET
;ROUTINE TO FIND WHEN THE NEXT RATE CHANGE HAPPENS
;ACCEPTS IN T1/	ADR OF NAME STRING
;	    T2/	START DATE
;	    T3/	TASK ADR
;	CALL FNDCHG
;RETURNS +1:	ALWAYS,	T1/	DATE OF NEXT CHANGE
;			T2/	FRACTIONAL RATE REMAINING TO BE USED

FNDCHG:	SAVEQ
	STKVAR <FNDCHN,FNDCHD,FNDCHP,FNDCHF>
	SETZM FNDCHF		;INIT THE FLAG
	LOAD T4,TKTAD,(T3)	;IS THERE AN INTERMEDIARY DATE?
	CAMGE T2,T4		;THAT IS GREATER THAN THE START DATE?
	JRST FNDCH6		;YES, GO USE IT
	LOAD T4,TKPRJ,(T3)	;GET THE PROJECT ADR
	MOVEM T4,FNDCHP		;SAVE IT
	HRLI T1,(POINT 7,0)	;GET BYTE POINTER TO NAME STRING
	MOVEM T1,FNDCHN		;SAVE POINTER TO NAME STRING
	MOVEM T2,FNDCHD		;SAVE THE START DATE
	MOVSI Q1,(1.0)		;GET INITIAL RATE
	MOVSI Q2,(1.0)		;START PROJECT ALLOTMENT AT 1.0
	LOAD T4,TKDVL,(T3)	;GET POINTER TO TASK DEVELOPER LIST
	JUMPN T4,FNDCH0		;IF ANY, THEN NO PROBLEM
	MOVE T4,FNDCHP		;GET PROJECT ADR
	LOAD Q3,PJDVL,(T4)	;GET POINTER TO DEV LIST FOR PROJECT
	MOVEM Q3,FNDCHF		;SAVE POINTER TO PROJECT LIST IF ANY
	SKIPN Q3		;IS THERE A LIST?
	MOVE Q3,DEVTBP		;NO, GET THE OVERALL LIST
	JUMPE Q3,FNDCH0		;IF NONE, THEN DONE
FNDCH4:	HRRZ T1,FNDCHN		;GET THE POINTER TO THE NAME STRING
	LOAD T2,DVNAM,(Q3)	;GET ADR OF NAME STRING
FNDCH7:	MOVE T3,(T1)		;GET NEXT WORD TO COMPARE
	MOVE T4,(T2)
	CAME T3,T4		;MATCH?
	JRST FNDCH5		;NO
	AOS T2			;STEP TO NEXT WORD
	TRNE T3,377		;AT END OF NAME
	AOJA T1,FNDCH7		;NO, LOOP BACK FORREST OF WORDS
	LOAD Q2,DVRAT,(Q3)	;YES, GET ITS RATE
	JRST FNDCH0		;DONE
FNDCH5:	LOAD Q3,DVLNK,(Q3)	;STEP TO NEXT DEVELOPER
	JUMPN Q3,FNDCH4		;LOOP BACK IF ANY MORE TO DO
FNDCH0:	MOVE T1,FNDCHN		;GET POINTER TO NAME STRING
	HRLOI Q3,377777		;GET LATEST DATE
	CALL DEVLUK		;LOOKUP THIS DEVELOPER
	 JRST FNDCH3		;NOT FOUND, ASSUME AVAILABLE FULL TIME
	HRRZ T1,(T1)		;GET POINTER TO DEVELOPER SCHEDULE
FNDCH1:	LOAD T2,SCHFD,(T1)	;GET FINISH DATE
	CAMLE T2,FNDCHD		;END AFTER START DATE?
	JRST FNDCH2		;YES, FOUND FIRST POSSIBLE CONFLICT
	LOAD T1,SCHLN,(T1)	;STEP TO NEXT ITEM
	JUMPN T1,FNDCH1		;IF MORE, LOOP BACK
	JRST FNDCH3		;IF NO MORE, THEN DEVELOPER AVAILABLE

FNDCH2:	CAMGE T2,Q3		;FOUND A NEW CHANGE DATE?
	MOVE Q3,T2		;YES, REMEMBER IT
	LOAD T2,SCHSD,(T1)	;GET STARTING DATE
	CAMLE T2,FNDCHD		;IS START DATE AFTER OUR START DATE?
	JRST [	CAMGE T2,Q3	;YES, IS THIS A NEW CHANGE DATE
		MOVE Q3,T2	;YES
		JRST FNDCH3]	;GO RETURN ANSWER
	LOAD T2,SCHRT,(T1)	;GET RATE ON THIS TASK
	FSBR Q1,T2		;GET REMAINDER FOR THIS DEVELOPER
	LOAD T3,SCHTK,(T1)	;GET THE TASK ADR
	LOAD T3,TKPRJ,(T3)	;GET THE PROJECT ADR
	SKIPE FNDCHF		;IF NO PROJECT LIST, THEN COUNT UP THIS
	CAMN T3,FNDCHP		;THIS BELONG TO THIS PROJECT?
	FSBR Q2,T2		;YES
	LOAD T1,SCHLN,(T1)	;STEP TO NEXT TASK IN LIST
	JUMPN T1,FNDCH1		;LOOP BACK TILL CORRECT POSITION FOUND
FNDCH3:	MOVE T1,Q3		;RETURN DATE OF NEXT CHANGE
	MOVE T2,Q1		;GET REMAINING RATE
	CAMLE Q1,Q2		;GET THE LOWEST RATE REMAINING
	MOVE T2,Q2
	SKIPGE T2		;NEGATIVE RATE?
	MOVEI T2,0		;YES, LEAVE IT AT ZERO
	RET

FNDCH6:	LOAD T1,TKTAD,(T3)	;CHANGE DATE IS AS SPECIFIED
	MOVE T2,[0.0000001]	;GIVE A VERY SMALL BUT NON-ZERO TIME FOR IT
	RET
;ROUTINE TO SCHEDULE A DEVELOPER
;ACCEPTS IN T1/	ADR OF ARG BLOCK
;WHERE	ARG+0/	ADR OF NAME STRING
;	ARG+1/	START DATE
;	ARG+2/	FINISH DATE
;	ARG+3/	RATE
;	ARG+4/	TASK BLOCK ADR
;CALL SCHDEV
;RETURNS +1:	ALWAYS

SCHDEV:	SAVEQ
	STKVAR <SCHDVN,SCHDVS,SCHDVF,SCHDVR,SCHDVT>
	MOVE T2,0(T1)		;GET ADR OF NAME STRING
	HRLI T2,(POINT 7,0)	;GET BYTE POINTER TO NAME STRING
	MOVEM T2,SCHDVN		;SAVE NAME STRING POINTER
	MOVE T2,1(T1)		;GET START DATE
	MOVEM T2,SCHDVS
	MOVE T2,2(T1)		;GET FINISH DATE
	MOVEM T2,SCHDVF
	MOVE T2,3(T1)		;GET RATE
	MOVEM T2,SCHDVR
	MOVE T2,4(T1)		;GET TASK ADR
	MOVEM T2,SCHDVT
	MOVEI T1,.SCHLN		;CREATE A BLOCK FOR THIS ENTRY
	CALL ASGSCH		;GET FREE SPACE FOR IT
	 ERRMES (<RAN OUT OF SCHEDULER FREE SPACE>)
	MOVE Q1,T1		;SAVE ADR OF FREE SPACE BLOCK
	MOVE T2,SCHDVS		;GET START DATE
	STOR T2,SCHSD,(Q1)	;SET UP BLOCK
	MOVE T2,SCHDVF		;GET FINISH DATE
	STOR T2,SCHFD,(Q1)
	MOVE T2,SCHDVR		;GET RATE
	STOR T2,SCHRT,(Q1)
	MOVE T2,SCHDVT		;GET TASK BLOCK ADR
	STOR T2,SCHTK,(Q1)	;SAVE IT IN THE BLOCK
	MOVE T1,SCHDVN		;GET POINTER TO NAME STRING
	CALL DEVLUK		;LOOKUP NAME IN TABLE
	 JRST SCHDV4		;NOT THERE, GO ADD IT
	HRRZ T2,0(T1)		;GET POINTER TO FIRST ITEM IN LIST
	LOAD T3,SCHSD,(T2)	;SEARCH FOR PLACE TO PUT THIS ONE
	CAML T3,SCHDVS		;KEEP LIST IN CHRONOLOGICAL ORDER
	JRST SCHDV3		;ENTRY BELONGS AS FIRST ONE
SCHDV1:	MOVE T1,T2		;SAVE POINTER
	LOAD T2,SCHLN,(T1)	;GET POINTER TO NEXT ITEM
	JUMPE T2,SCHDV2		;NO MORE
	LOAD T3,SCHSD,(T2)	;GET START DATE OF NEXT ONE
	CAMGE T3,SCHDVS		;FOUND THE RIGHT PLACE?
	JRST SCHDV1		;NO, LOOP BACK TIL FOUND
SCHDV2:	STOR T2,SCHLN,(Q1)	;YES, STORE THE ITEM HERE
	STOR Q1,SCHLN,(T1)	;MAKE PREVIOUS ONE POINT HERE
	RET			;DONE
SCHDV3:	STOR T2,SCHLN,(Q1)	;PUT THIS ONE AT FRONT OF LIST
	HRRM Q1,0(T1)
	RET

SCHDV4:	MOVE T1,SCHDVN		;GET POINTER TO THE NAME STRING
	SETZRO SCHLN,(Q1)	;MAKE THIS BE THE ONLY ENTRY
	MOVE T2,Q1		;GET SCHED ENTRY TO BE ADDED
	CALL ADDDEV		;GO ADD THIS DEVELOPER TO THE LIST
	 ERRMES (<COULD NOT ADD A DEVELOPER TO THE SCHEDULE LIST>)
	RET			;DONE
;ROUTINE TO MARK THE CRITICAL PATH TASKS

SETCP:	SAVEQ
	STKVAR <<SETCPT,MAXTSK>>
	CALL CLRCP		;CLEAR THE CRITICAL PATH BITS
	CALL SETSLK		;SET THE SLACK VALUES
	MOVE Q1,TSKPTR		;SET UP AOBJN POINTER
	SETZ Q2,		;SCAN FOR THE LATEST FINISH DATE
SETCP1:	HRRZ T1,TSKLST(Q1)	;GET THE TASK ADDRESS
	LOAD T2,TKEFD,(T1)	;GET THE EXPECTED FINISH DATE
	HLLZS T2		;ONLY NEED THE DAY
	CAMLE T2,Q2		;FOUND A NEW HIGH?
	MOVE Q2,T2		;YES, REMEMBER IT
	AOBJN Q1,SETCP1		;LOOP BACK OVER ALL TASKS
	MOVE Q1,TSKPTR		;NOW GO MARK THE CRITICAL PATH
SETCP2:	HRRZ T1,TSKLST(Q1)	;GET TASK ADDRESS
	LOAD T2,TKEFD,(T1)	;GET THE FINISH DATE
	HLLZS T2
	CAMGE T2,Q2		;IS THIS ONE OF THE LAST FINISHING TASKS
	JRST SETCP5		;NO
	MOVEI T1,SETCPT		;YES, ZERO THE ANSWER BLOCK
	ADDI T1,1
	HRLI T1,SETCPT
	SETZM SETCPT
	MOVEI T2,SETCPT
	ADD T2,TSKCNT		;END OF BLOCK TO BE ZEROED
	BLT T1,-1(T2)
	HRRZ T1,TSKLST(Q1)	;GET TASK ADDRESS
	MOVEI T2,SETCPT		;GET ADR OF ANSWER BLOCK
	CALL FNDCP		;GO FIND CRITICAL PATH TASKS
	MOVE T1,TSKPTR		;NOW SET THE BIT FOR EACH TASK ON C.P.
SETCP3:	HRRZ T2,TSKLST(T1)	;GET TASK ADR
	MOVEI T3,SETCPT		;GET ADR OF ANSWER BLOCK
	ADDI T3,(T1)		;GET ADR OF TASK WITHIN THE BLOCK
	SKIPN (T3)		;IS THIS TASK ON THE CRITICAL PATH?
	JRST SETCP4		;NO
	SETONE TKCP,(T2)	;YES, MARK IT
SETCP4:	AOBJN T1,SETCP3		;LOOP BACK FOR ALL TASKS
SETCP5:	AOBJN Q1,SETCP2		;LOOP BACK FOR ALL TASKS
	MOVE Q1,TSKPTR		;GET POINTER TO TASKS
SETCP6:	HRRZ T1,TSKLST(Q1)	;GET TASK ADR
	LOAD Q3,TKPTC,(T1)	;GET THE PATH CHAR
	JUMPE Q3,SETCP9		;IF NONE, THEN SKIP THIS TASK
	MOVEI T1,SETCPT		;YES, ZERO THE ANSWER BLOCK
	ADDI T1,1
	HRLI T1,SETCPT
	SETZM SETCPT
	MOVEI T2,SETCPT
	ADD T2,TSKCNT		;END OF BLOCK TO BE ZEROED
	BLT T1,-1(T2)
	HRRZ T1,TSKLST(Q1)	;GET TASK ADDRESS
	MOVEI T2,SETCPT		;GET ADR OF ANSWER BLOCK
	CALL FNDCP		;GO FIND CRITICAL PATH TASKS
	MOVE Q2,TSKPTR		;NOW LOOP THRU TO SET UP PATHS
SETCP7:	HRRZ T1,TSKLST(Q2)	;GET THE TASK ADR
	MOVE T2,Q3		;GET THE PATH CHAR TO USE
	MOVEI T3,SETCPT		;GET ADR OF TABLE
	ADDI T3,(Q2)		;INDEX INTO THE TABLE
	SKIPN (T3)		;IS THIS TASK ON THE CRITICAL PATH?
	JRST SETCP8		;NO
	CALL MRKPTH		;YES, GO MARK IT
	 WARN (,<COULD NOT MARK THE CRITICALITY OF A TASK>)
SETCP8:	AOBJN Q2,SETCP7		;LOOP BACK FOR ALL TASKS IN LIST
SETCP9:	AOBJN Q1,SETCP6		;LOOP BACK FOR MORE PATHS TO SET UP
	RET			;DONE


;ROUTINE TO MARK A TASK AS BEING ON A CRITICAL PATH
;ACCEPTS IN T1/	TASK ADR
;	    T2/	PATH CHAR
;RETURNS +1:	FAILED
;	 +2:	OK

MRKPTH:	SAVEQ
	DMOVE Q1,T1		;SAVE THE ARGS
	LOAD T1,TKPL,(Q1)	;GET POINTER TO PATH LIST
	JUMPN T1,MRKPT1		;ANY THERE?
	MOVEI T1,.PTHLN		;NO, GET A BLOCK OF FREE SPACE
	MOVEI T2,.TYPTH
	MOVEI T3,.VNPTH
	CALL ASGFRE		;GET A BLOCK FOR THE PATH LIST
	 RET			;FAILED
	STOR T1,TKPL,(Q1)	;SAVE THE POINTER TO THE BLOCK
MRKPT1:	LOAD T1,TKPL,(Q1)	;GET THE PATH LIST
	HRLI T1,(POINT 7,0)	;SET UP A POINTER TO IT
	MOVEI T4,.PTHLN*5-2	;GET MAX COUNT OF CHARS IN LIST
MRKPT2:	ILDB T2,T1		;GET THE NEXT PATH LIST ELEMENT
	JUMPE T2,MRKPT3		;REACHED END OF LIST?
	CAMN T2,Q2		;IS THIS THE CHAR?
	RETSKP			;IF YES, DONT ADD IT TWICE
	SOJG T4,MRKPT2		;LOOP BACK TILL END OF LIST
	RET			;RAN OUT OF ROOM

MRKPT3:	DPB Q2,T1		;STORE THE PATH CHAR
	IDPB T2,T1		;STORE A NULL AT THE END
	RETSKP			;DONE
;ROUTINE TO CLEAR THE "CRITICAL PATH" BIT FOR EACH TASK

CLRCP:	MOVE T1,TSKPTR		;GET AOBJN POINTER TO TSKLST
CLRCP1:	MOVE T2,TSKLST(T1)	;GET TASK ADR
	SETZRO TKCP,(T2)	;ZERO THE BIT
	LOAD T3,TKPL,(T2)	;GET THE PATH LIST POINTER
	SKIPE T3		;ANY THERE?
	SETZM (T3)		;YES, CLEAR THE LIST
	AOBJN T1,CLRCP1		;LOOP BACK FOR ALL TASKS
	RET			;DONE


;ROUTINE TO FIND THE CRITICAL PATH TASKS FOR A GIVEN TASKS (RECURSIVE)
;ACCEPTS IN T1/	TASK ADR
;	    T2/	ANSWER BLOCK	(MAXTSK IN LENGTH)
;	CALL FNDCP
;RETURNS +1:	0 = NOT C.P.,  -1 = ON C.P.

FNDCP:	SAVEQ
	DMOVE Q1,T1		;SAVE THE ARGS
	LOAD T1,TKTKI,(T1)	;GET TSKLST INDEX
	MOVE T2,Q2		;GET ANSWER BLOCK
	MOVE T3,T2		;GET ADR OF THIS TASK IN ANSWER BLOCK
	ADD T3,T1		;ADD IN THE INDEX
	SETOM (T3)		;THIS TASK IS ON THE CRITICAL PATH
	SETZ Q2,		;INIT THE DATE
	LOAD Q3,TKDLP,(Q1)	;GET POINTER TO BLOCKING TASKS
	JUMPE Q3,R		;IF NONE, THEN DONE
FNDCP1:	LOAD T1,DPBTK,(Q3)	;GET ADR OF BLOCKING TASK
;T1/ ADR OF BLOCKING TASK, Q1/ ADR OF BLOCKED TASK
	CALL [	SAVET		;SAVE T1 TO T4
		LOAD T1,TKEFD,(T1) ;GET BLOCKING FINISH DATE
		LOAD T2,TKESD,(Q1) ;GET BLOCKED START DATE
		CAML T1,T2	;POSITIVE SLACK
		RET		;NO--ON CRITICAL PATH
		CALL GETNWD	;GET NUMBER OF DAYS BETWEEN TASKS
		SOJLE T1,R	;ASSUME CRITICAL PATH IF 1 OR FEWER
		RETSKP]		;YES--NOT OR CRITICAL PATH
	  CALL FNDCP		;GO TRACE ITS CRITICAL PATH
	LOAD Q3,DPDLP,(Q3)	;STEP TO THE NEXT TASK IN THE LIST
	JUMPN Q3,FNDCP1		;LOOP BACK FOR REST OF LIST
	RET			;DONE
;ROUTINE TO SET THE SLACK FOR ALL TASKS

SETSLK:	SAVEQ
	MOVE Q1,TSKPTR		;SET UP TO LOOP THROUGH ALL TASKS
	JUMPE Q1,R		;IF NONE, THEN DONE
SETSL1:	HRRZ T1,TSKLST(Q1)	;GET TASK ADR
	CALL TSKSLK		;GO SET ITS SLACK
	AOBJN Q1,SETSL1		;LOOP FOR ALL TASKS
	RET			;DONE


;ROUTINE TO SET THE SLACK OF A TASK
;ACCEPTS IN T1/	TASK ADR
;RETURNS +1:	ALWAYS

TSKSLK:	SAVEQ
	MOVE Q1,T1		;SAVE THE TASK ADR
	MOVE Q3,[377777,,777777] ;INIT ANSWER
	LOAD Q2,TKBLP,(Q1)	;GET THE BLOCKED LIST POINTER
	JUMPE Q2,TSKSL2		;IF NONE, THEN DONE
TSKSL1:	LOAD T1,TKEFD,(Q1)	;GET THE FINISH DATE
	LOAD T3,DPTKP,(Q2)	;GET ADR OF DEPENDENT TASK
	LOAD T2,TKESD,(T3)	;GET ITS START DATE
	CAMLE T1,T2		;NEGATIVE SLACK?
	JRST [	EXCH T1,T2	;YES
		CALL GETNWD	;GET NUMBER OF DAYS BETWEEN THEM
		MOVNS T1	;NEGATE IT
		JRST TSKSL3]
	CALL GETNWD		;GET THE NUMBER OF DAYS BETWEEN THEM
TSKSL3:	CAMGE T1,Q3		;NEW LOW?
	MOVE Q3,T1		;YES, REMEMBER IT
	LOAD Q2,DPBLP,(Q2)	;STEP TO NEXT DEPENDENT TASK
	JUMPN Q2,TSKSL1		;LOOP BACK FOR ALL DEPENDENT TASKS
TSKSL2:	CAMN Q3,[377777,,777777] ;ANY FOUND?
	MOVE Q3,[NOSLAK]	;NO, SIGNIFY NONE
	STOR Q3,TKSLK,(Q1)	;SET THE SLACK
	RET			;DONE
;ROUTINE TO BUILD THE SCHEDLUED TASK LIST

BLDSTL:	SAVEPQ
	SETZM SKTLST		;INIT POINTER TO LIST
	MOVN P1,TSKCNT		;SET UP A POINTER TO THE TASKS
	JUMPE P1,R		;IF NONE, THEN DONE
	HRLZS P1
BLDST0:	MOVE P3,TSKFDL(P1)	;GET FINISH DATE OF TASK
	MOVE P4,TSKSDL(P1)	;GET THE START DATE
	TLNN P4,-1		;ANY THERE?
	MOVE P4,P3		;NO, USE FINISH DATE WHEN THERE IS NO START DATE
	MOVE Q1,P3		;INITIALIZATION
BLDST1:	CAMGE P3,P4		;DONE?
	JRST BLDST4		;YES, GO ON TO NEXT TASKS
	MOVE Q2,Q1		;REMEMBER THE FINISH DATE
	MOVE T1,TSKLST(P1)	;GET TASK ADDRESS
	MOVE T2,P3		;GET DATE
	CALL GETTRT		;GET RATE FOR THIS TASK ON THIS DATE
	MOVEM T1,Q3		;REMEMBER STARTING RATE
BLDST2:	MOVE Q1,P3		;GET STARTING DATE OF THIS SECTION
	SUB P3,[1,,0]		;GO BACK TO PREVIOUS DAY
	CAMGE P3,P4		;GONE PAST START DATE OF TASK?
	JRST BLDST3		;YES, THEN DONE
	MOVE T1,TSKLST(P1)	;GET TASK ADDRESS
	MOVE T2,P3		;GET DATE
	CALL GETTRT		;SEE IF THE RATE HAS CHANGED
	CAMN T1,Q3		;DID IT CHANGE?
	JRST BLDST2		;NO, KEEP MOVING BACK THRU DATES
BLDST3:	MOVEI T1,.SCHLN		;GET A BLOCK TO STORE THIS IN
	CALL ASGSCH
	 ERRMES (<RAN OUT OF SCHEDULER FREE SPACE>)
	MOVE T2,TSKLST(P1)	;GET TASK ADDRESS FOR BLOCK
	STOR T2,SCHTK,(T1)	;STORE THE TASK ADDRESS
	STOR Q1,SCHSD,(T1)	;STORE THE START DATE
	STOR Q2,SCHFD,(T1)	;STORE THE FINISH DATE
	STOR Q3,SCHRT,(T1)	;STORE THE RATE
	MOVE T2,SKTLST		;NOW ADD THIS BLOCK TO THE LIST
	STOR T2,SCHLN,(T1)	;MAKE THIS TASK POINT TO LAST NEXT ONE
	MOVEM T1,SKTLST		;MAKE THE LIST POINT TO THIS ONE
	JRST BLDST1		;LOOP BACK TILL THIS TASK IS SCHEDULED

BLDST4:	AOBJN P1,BLDST0		;LOOP BACK FOR ALL TASKS
	RET			;ALL DONE
;ROUTINE TO COUNT UP THE COMBINED RATE FOR A TASK ON A GIVEN DATE
;ACCEPTS IN T1/	TASK BLOCK ADDRESS
;	    T2/	DATE
;	CALL GETTRT
;RETURNS +1:	ALWAYS,	T1/	RATE

GETTRT:	SAVEQ
	DMOVE Q1,T1		;SAVE THE ARGS
	SETZ T1,		;INIT THE ANSWER
	HLRZ Q3,DEVTAB		;SET UP POINTER TO DEVELOPER LIST
	JUMPE Q3,R		;IF NONE, THEN DONE
	MOVNS Q3
	HRLZS Q3
GETTR1:	HRRZ T2,DEVTAB+1(Q3)	;GET POINTER TO LIST
	JUMPE T2,GETTR4		;IF NONE, THEN DONE
GETTR2:	LOAD T3,SCHTK,(T2)	;GET TASK ADR
	CAME T3,Q1		;FOUND THE ONE WE WANT?
	JRST GETTR3		;NO
	LOAD T3,SCHSD,(T2)	;GET ITS START DATE
	LOAD T4,SCHFD,(T2)	;AND ITS FINISH DATE
	CAMG T3,Q2		;IS START BEFORE THE DESIRED DATE?
	CAMG T4,Q2		;AND FINISH AFTER THE DESIRED DATE?
	JRST GETTR3		;NO, SKIP THIS BLOCK
	LOAD T3,SCHRT,(T2)	;YES, GET THE RATE
	FADR T1,T3		;ADD IT TO THE ANSWER
GETTR3:	LOAD T2,SCHLN,(T2)	;STEP TO NEXT TASK BLOCK
	JUMPN T2,GETTR2		;LOOP BACK IF MORE TO BE DONE
GETTR4:	AOBJN Q3,GETTR1		;LOOP BACK FOR ALL DEVELOPERS
	RET			;DONE
;ROUTINE TO LOOKUP A DEVELOPER IN THE TABLE
;ACCEPTS IN T1/	POINTER TO THE NAME STRING
;	CALL DEVLUK
;RETURNS +1:	NOT FOUND
;	 +2:	T1/	ADR OF TABLE ITEM

DEVLUK:	MOVE T2,T1		;GET ADR OF NAME INTO T2
	MOVEI T1,DEVTAB		;GET ADR OF TABLE
	TBLUK
	 ERJMP R		;NOT FOUND
	TXNN T2,TL%EXM		;EXACT MATCH?
	RET			;NO
	RETSKP			;YES


;ROUTINE TO ADD A DEVELOPER TO THE TABLE
;ACCEPTS IN T1/	ADR OF THE NAME STRING
;	    T2/	ADR OF THE DEVELOPER BLOCK
;	CALL ADDDEV
;RETURNS +1:	FAILED
;	 +2:	SUCCESS

ADDDEV:	HRL T2,T1		;BUILD THE ENTRY
	MOVEI T1,DEVTAB		;GET ADR OF TABLE
	TBADD
	 ERJMP R		;FAILED
	RETSKP


;ROUTINE TO ASSIGN SPACE IN THE SCHED POOL
;RETURNS +1:	FAILED
;	 +2:	T1/	ADR OF BLOCK

ASGSCH:	MOVE T1,SKDFRP		;GET POINTER TO NEXT FREE BLOCK
	MOVEI T2,.SCHLN		;GET LENGTH
	ADDB T2,SKDFRP		;UPDATE THE POINTER
	CAILE T2,SKDFRE+SKDFRL	;BEYOND THE END?
	RET			;YES, NO MORE ROOM
	HRLZ T2,T1		;ZERO THE BLOCK
	HRRI T2,1(T1)
	MOVEI T3,.SCHLN-1(T1)	;GET END OF BLOCK
	SETZM (T1)
	BLT T2,(T3)
	RETSKP			;NO
; ROUTINE TO ASSIGN SPACE IN FREE STORAGE REGION
; CALL:	T1		;SIZE OF BLOCK NEEDED
;	T2		;TYPE CODE OF THE BLOCK
;	T3		;VERSION NUMBER OF THE DATA IN THE BLOCK
;	CALL ASGFRE
; RETURNS: +1	ERROR, NOT ENOUGH SPACE
;	   +2	SUCCESS, T1/ LOCATION OF THE BLOCK
; CLOBBERS T1, T2, T3, AND T4
; FREE STORAGE HEADER FORMAT:
;	0		;LH POINTS TO FIRST FREE BLOCK
;	1		;SPACE COUNTER
;	2		;MOST COMMON BLOCK SIZE
;	3		;LH HAS MAX TOP OF FREE STORAGE,
;			; RH HAS MINIMUM BOTTOM
;	4		;TEMPORARY 2
;	5		;TEMPORARY 3

ASGFRE:	ASUBR <ASGFRS,ASGFRT,ASGFRV>
	ADDI T1,.BLKLN		;ADD ON THE LENGTH OF THE HEADER
	CALL GETFRE		;GET THE BLOCK
	 RET			;FAILED
	ADDI T1,.BLKLN		;POINT TO FIRST WORD BEYOND HEADER
	MOVE T2,ASGFRS		;GET SIZE OF BLOCK
	ADDI T2,.BLKLN		;PLUS HEADER
	STOR T2,BLKLEN,(T1)	;STORE LENGTH
	MOVE T2,ASGFRT		;GET TYPE OF BLOCK
	STOR T2,BLKTYP,(T1)
	MOVE T2,ASGFRV		;GET VERSION NUMBER
	STOR T2,BLKVER,(T1)
	RETSKP
GETFRE:	MOVE T2,T1		;GET SIZE INTO T2
	MOVEI T1,FRSHDR		;GET ADDRESS OF FREE SPACE HEADER
	PIOFF			;LOCK UP THE LOCKS
	LOCK FRELOK
	CALL GETFR0		;GO GET SPACE
	 RETBAD (,<UNLOCK FRELOK
			PION>)	;NO MORE SPACE
	UNLOCK FRELOK		;UNLOCK THE LOCKS
	PION
	RETSKP

GETFR0:	CAMLE T2,1(T1)		;ANY POSSIBILITY OF SUCCESS?
	RET			;NO, RETURN IMMEDIATELY
	PUSH P,T2		;SAVE DESIRED BLOCK SIZE
	PUSH P,[0]		;BIGGEST BLOCK SEEN SO FAR
	HRLOI T2,377777
	MOVEM T2,4(T1)		;INITIAL BEST BLOCK SIZE
	SETZM 5(T1)		;INITIAL LOCATION OF BEST BLOCK
	MOVE T2,T1		;START WITH THE HEADER WORD
GETFR1:	HLRZ T3,0(T2)		;GET POINTER TO NEXT FREE BLOCK
	JUMPE T3,GETFR2		;NO MORE FREE BLOCKS TO EXAMINE
	HRRZ T4,0(T3)		;GET SIZE OF THE BLOCK
	CAMLE T4,0(P)	
	MOVEM T4,0(P)
	CAMN T4,-1(P)		;IS IT THE RIGHT SIZE?
	JRST GETFR3		;YES, USE IT
	CAML T4,-1(P)		;TOO SMALL?
	CAML T4,4(T1)		;OR BIGGER THAN THE BEST?
	JRST GETFR4		;YES, IGNORE IT
	MOVEM T4,4(T1)		;THIS ONE IS BETTER
	MOVEM T2,5(T1)
GETFR4:	MOVE T2,T3		;STEP TO THE NEXT BLOCK
	JRST GETFR1		;AND REPEAT
GETFR2:	SKIPN T2,5(T1)		;DID WE FIND ANYTHING?
	JRST [	POP P,T2	;NO, FLUSH TEMP
		POP P,T2	;MAKE TRANSPARENT TO T2 ON ERROR
		RETBAD]
	MOVE T4,-1(P)		;GET DESIRED SIZE
	HLRZ T3,0(T2)		;GET POINTER TO BLOCK TO BE USED
	HRRM T4,0(T3)		;CONVERT TO DESIRED SIZE
	ADD T4,T3		;POINTER TO REMAINDER OF BLOCK
	HRLM T4,0(T2)		;POINT PREVIOUS TO REMAINDER
	HLLZ T2,0(T3)		;GET NEXT
	HLLM T2,0(T4)		;POINT REMAINDER TO IT
	MOVE T2,4(T1)	
	SUB T2,-1(P)		;SIZE OF REMAINDER
	HRRM T2,0(T4)		;TO HEADER OF REMAINDER
GETFR5:	SUB P,[1,,1]		;GET LOCATION BELOW TOP-OF-STACK
	MOVN T2,0(P)
	ADDM T2,1(T1)		;REDUCE COUNT OF SPACE LEFT
	MOVEI T1,0(T3)		;GET ORIGIN OF BLOCK
	HRROS (T1)		;SET LH TO ONES
	CAMN T2,[-1]		;IS THIS A BLOCK OF ONE WORD?
	JRST GETFR6		;YES, DON'T ZERO ANYTHING THEN
	HRRZ T2,(T1)		;GET RH
	HRRZI T3,2(T1)
	SETZM -1(T3)		;ZERO FIRST WORD BEFORE SETTING LEFT HALF INDEX
	HRLI T3,1(T1)
	ADD T2,T1
	HRRZS T2
	CAILE T2,(T3)
	BLT T3,-1(T2)		;ZERO THE BLOCK
GETFR6:	POP P,T2		;RESTORE T2
	RETSKP			;RETURN

GETFR3:	HLL T4,0(T3)
	HLLM T4,0(T2)		;POINT PREDECESSOR TO SUCCESSOR
	JRST GETFR5
; ROUTINE TO RELEASE FREE STORAGE BLOCK
; LIFTED FROM MONITOR MODULE FREE, ROUTINE RELFRE
; CALL:	T1/ LOCATION OF THE BLOCK TO BE RETURNED
;	CALL RELFRE
; RETURNS: +1	SUCCESS, BLOCK RELEASED
; CLOBBERS T2, T3, AND T4

RELFRE:	JUMPE T1,R		;IF NONE, JUST RETURN
	MOVEI T2,-.BLKLN(T1)	;GET ADR OF BLOCK INTO T2
	LOAD T1,BLKLEN,(T1)	;GET THE ACTUAL LENGTH OF THE BLOCK
	MOVEM T1,0(T2)		;STORE IT IN THE FIRST WORD OF THE BLOCK
	MOVEI T1,FRSHDR		;GET ADR OF FREE SPACE HEADER
	PIOFF
	LOCK FRELOK		;LOCK UP
	CALL RELFRW		;GO DO THE WORK
	 JRST [	HRROI T1,[ASCIZ/
% PROBLEM ENCOUNTERED WHILE RELEASING A BLOCK TO THE FREE POOL
/]
		PSOUT
		JRST .+1]
	UNLOCK FRELOK		;UNLOCK THE LOCKS
	PION
	RET

RELFRW:	PUSH P,T1		;SAVE LOCATION OF FREE STG HDR
	HRRZ T4,0(T1)
	HLRZ T4,3(T1)
	HRRZ T1,3(T1)
	CAILE T4,0(T2)
	CAILE T1,0(T2)
	JRST RLFRX1		;ERROR - OUT OF RANGE
	MOVE T1,0(P)
RELFR0:	PUSH P,T2		;SAVE LOCATION OF BLOCK TO FREE
	HRLI T2,0		;SOME FIX NEEDED HERE TO KEEP OUT OF SEC 0!!!!
	HLLM T2,0(P)
	MOVE T2,-1(P)
RELFR1:	HLRZ T3,0(T2)		;GET LOCATION OF NEXT BLOCK
	JUMPE T3,RELFR2		;END OF LIST
	CAML T3,0(P)
	JRST RELFR2		;OR ABOVE BLOCK BEING RETURNED
	MOVE T2,T3
	JRST RELFR1

RLFRX1:	POP P,T1		;ERROR, BLOCK OUT OF RANGE
	RETBAD			;RETURN
RELFR2:	CAMN T3,0(P)		;RELEASING A BLOCK ALREADY RELEASED?
	JSP CX,RLFRX2		;YES, ERROR
	CAIN T1,0(T2)		;THIS FIRST BLOCK ON FREE LIST?
	JRST RELFR6		;YES
	HRRZ T4,0(T2)		;COMPUTE END OF PREVIOUS BLOCK
	ADD T4,T2
	CAMLE T4,0(P)		;PREVIOUS BLOCK OVERLAPS ONE BEING RELEASED?
	JSP CX,RLFRX2		;YES, ERROR
RELFR6:	JUMPE T3,RELFR7		;AT END OF FREE LIST?
	HRRZ T4,0(P)		;COMPUTE END OF THIS BLOCK
	ADD T4,@0(P)
	CAMLE T4,T3		;OVERLAPS NEXT BLOCK ON FREE LIST?
	JSP CX,RLFRX2		;YES, ERROR
RELFR7:	HRRZ T4,@0(P)
	ADDM T4,1(T1)		;AUGMENT COUNT OF REMAINING FREE SPACE
	ADD T4,0(P)		;GET END OF BLOCK BEING RETURNED
	CAIE T4,0(T3)		;SAME AS FOLLOWING BLOCK LOCATION?
	JRST RELFR3		;NO
	HRRZ T4,0(T3)		;GET LENGTH OF FOLLOWING BLOCK
	ADDM T4,@0(P)		;AUGMENT LENGTH OF BLOCK BEING RETURNED
	HLLZ T4,0(T3)		;GET LOC OF SUCCESSOR OF SUCCESSOR
	HLLM T4,@0(P)
RELFR5:	MOVE T3,0(P)
	HRLM T3,0(T2)
	HRRZ T4,0(T2)		;LENGTH OF PREDECESSOR
	ADD T4,T2		;END OF PREDECESSOR
	CAME T4,T3		;SAME AS NEW BLOCK
	JRST RELFR4		;NO, DONE
	MOVE T3,0(T3)
	HLLM T3,0(T2)
	HRRZS T3
	ADDM T3,0(T2)
RELFR4:	POP P,T2
	POP P,T1
	RETSKP			;GOOD RETURN

RELFR3:	HRLM T3,@0(P)		;POINT RETURNED BLOCK TO SUCCESSOR
	JRST RELFR5

RLFRX2:	POP P,T2		;ERROR, BAD BLOCK BEING RELEASED
	POP P,T1
	RETBAD			;GIVE ERROR RETURN
; ROUTINE TO BUILD FREE SPACE HEADER AT INITIALIZATION
;  FOR CALLS TO ASGFRE AND RELFRE
;
;	CALL FSHDR
; RETURNS: +1	ALWAYS

FSHDR:	MOVEI T1,FSADR		;START ADR OF FREE SPACE
	HRLOM T1,FRSHDR
	MOVEI T1,FSLEN		;SET UP LENGTH OF FIRST BLOCK
	MOVEM T1,FSADR		;MAKE THE FIRST BLOCK CONTAIN ALL SPACE
	MOVEM T1,FRSHDR+1	;SET UP LENGTH
	MOVE T1,[FSADR+FSLEN,,FSADR]
	MOVEM T1,FRSHDR+3	;SET UP BOUNDS
	RET
;ROUTINE TO ENQ A JFN
;ACCEPTS IN T1/	JFN

ENQJFN:	STKVAR <<ENQJFB,5>,<ENQJFS,3>,<ENQJFU,10>>
	HRRZM T1,.ENQLV+ENQJFB	;SAVE THE JFN 
	MOVE T1,[1,,5]		;SET UP ENQ BLOCK
	MOVEM T1,.ENQLN+ENQJFB
	SETZM .ENQID+ENQJFB	;ID = 0
	MOVX T1,5B2
	MOVEM T1,.ENQUC+ENQJFB	;UNIQUE CODE = 0
	SETZM .ENQRS+ENQJFB	;EXCLUSIVE LOCK
	MOVEI T1,.ENQAA		;ASK FOR LOCK
	MOVEI T2,ENQJFB
	ENQ
	 SKIPA			;NOT AVAILABLE
	RET			;GOT IT LOCKED
	CAIE T1,ENQX6		;ALREADY IN USE?
	JSP ERROR		;NO, ERROR
	MOVEI T1,.ENQCS		;NOW GET JOB NUMBER OF OWNER
	MOVEI T2,ENQJFB
	MOVEI T3,ENQJFS		;GET ADR OF STATUS BLOCK
	ENQC			;GET STATUS INFO
	 JSP ERROR		;FAILED
	HRRZ T1,ENQJFS		;GET JOB NUMBER OF OWNER
	HRROI T2,T4		;GET USER NUMBER OF JOB
	MOVEI T3,.JIUNO
	GETJI
	 JSP ERROR		;FAILED
	MOVEI T1,.PRIOU
	TYPE T1,<&THE DATA BASE IS IN USE BY >
	HRROI T1,ENQJFU		;GET USER NAME
	MOVE T2,T4		;GET USER NUMBER
	DIRST
	 SKIPA T2,[-1,,[ASCIZ/USER/]]
	HRROI T2,ENQJFU		;GET USER NAME STRING
	MOVEI T1,.PRIOU
	CALL TYPSTR		;OUTPUT THE USER NAME STRING
	TYPE T1,< ON JOB >
	HRRZ T2,ENQJFS		;NOW OUTPUT THE JOB NUMBER
	MOVEI T3,^D10		;IN DECIMAL
	CALL TYPNUM
	TYPE T1,<, WAITING...>
	MOVEI T1,.ENQBL		;NOW DO A BLOCKING ENQ
	MOVEI T2,ENQJFB
	ENQ
	 JSP ERROR
	MOVEI T1,.PRIOU
	TYPE T1,< OK, DATA BASE IS LOCKED.&>
	RET
;ROUTINE TO DEQ A JFN
;ACCEPTS IN T1/	JFN

DEQJFN:	STKVAR <<DEQJFB,5>>
	HRRZM T1,.ENQLV+DEQJFB	;SAVE JFN
	MOVE T1,[1,,5]
	MOVEM T1,.ENQLN+DEQJFB	;SET UP HEADER
	SETZM .ENQID+DEQJFB
	MOVX T1,5B2
	MOVEM T1,.ENQUC+DEQJFB	;UNIQUE CODE = 0
	SETZM .ENQRS+DEQJFB
	MOVEI T1,.DEQDR		;DEQ THE RESOURCE
	MOVEI T2,DEQJFB
	DEQ
	 JSP ERROR
	RET



;ROUTINES TO TURN OFF AND ON THE INTERRUPT SYSTEM
;ALL ACS ARE PRESERVED

PIOFF.:	PUSH P,T1		;SAVE ALL ACS
	MOVEI T1,.FHSLF		;THIS FORK
	DIR			;DISABLE INTERRUPT SYSTEM
	POP P,T1		;RESTORE AC
	RET			;AND RETURN

PION.:	PUSH P,T1		;SAVE ALL ACS
	MOVEI T1,.FHSLF		;THIS FORK
	EIR			;ENABLE INTERRUPTS AGAIN
	POP P,T1		;RESTORE AC
	RET			;AND RETURN
;TYPE OUT ROUTINES

TYPRTN:	PUSH P,T1
	PUSH P,T2
	PUSH P,T3
	PUSH P,T4
	HRRZ T1,(CX)		;GET OUTPUT JFN
	HLRZ T4,CX		;GET ADR OF ASCIZ STRING
	HRLI T4,(POINT 7,0)	;TURN IT INTO A BYTE POINTER
TYPRT1:	ILDB T2,T4		;GET NEXT CHAR IN STRING
	JUMPE T2,TYPRT3		;IF NULL, THEN DONE
	CAIN T2,"&"		;CRLF?
	JRST TYPRT2		;YES
	CALL TYPCHR		;OUTPUT THE CHAR
	JRST TYPRT1		;LOOP BACK FOR REST

TYPRT2:	MOVEI T2,15		;CR
	CALL TYPCHR
	MOVEI T2,12		;LF
	CALL TYPCHR
	JRST TYPRT1		;LOOP BACK FOR REST

TYPRT3:	POP P,T4
	POP P,T3
	POP P,T2
	POP P,T1
	RET


;ROUTINE TO TYPE A CHARACTER

TYPCHR:	CAIN T2,15		;CR?
	SETZM COLUMN		;YES, ZERO COLUMN COUNTER
	CAIL T2," "		;PRINTING CHARACTER?
	AOS COLUMN		;YES, COUNT COL UP BY ONE
	CAIN T2,11		;TAB?
	JRST [	EXCH T2,COLUMN	;YES
		LSH T2,-3	;UPDATE COLUMN TO NEXT TAB STOP
		LSH T2,3
		ADDI T2,8
		EXCH T2,COLUMN
		JRST .+1]
	BOUT			;OUTPUT THE CHAR
	RET
;ROUTINE TO TYPE OUT SPACES TO THE SPECIFIED COLUMN
;ACCEPTS IN T1/	OUTPUT JFN
;	    T2/	COLUMN POSITION

TYPSPA:	SAVET
	MOVE T3,T2		;GET COLUMN POS INTO T3
	SUB T3,COLUMN		;GET NUMBER OF SPACES TO TYPE
	MOVEI T2," "
	CALL TYPCHR		;TYPE OUT AT LEAST ONE
	SOJG T3,.-1		;LOOP BACK TILL AT DESIRED COLUMN
	RET


;ROUTINE TO TYPE OUT A FLOATING POINT NUMBER

TYPFLT:	SAVET
	STKVAR <<TYPFLS,10>,TYPFLJ>
	MOVEM T1,TYPFLJ		;SAVE THE JFN
	HRROI T1,TYPFLS		;GET ADR OF STRING
	SETZ T3,		;NORMAL FORMAT
	FLOUT
	 JRST ERROR
	MOVE T1,TYPFLJ		;GET JFN AGAIN
	HRROI T2,TYPFLS		;NOW TYPE OUT THE ANSWER
	CALLRET TYPSTR


;ROUTINE TO TYPE OUT AN INTEGER
;ACCEPTS IN T1/	OUTPUT JFN
;	    T2/	NUMBER
;	    T3/	RADIX

TYPNUM:	SAVET
	STKVAR <<TYPNUS,10>,TYPNUJ>
	MOVEM T1,TYPNUJ		;SAVE JFN
	HRROI T1,TYPNUS		;GET ADR OF STRING
	NOUT
	 JRST ERROR
	MOVE T1,TYPNUJ		;GET JFN AGAIN
	HRROI T2,TYPNUS		;NOW OUTPUT THE NUMBER
	CALLRET TYPSTR
;ROUTINE TO TYPE OUT A STRING

TYPSTR:	SAVET
	MOVE T3,T2		;GET BYTE POINTER
	TLC T3,-1
	TLNE T2,-1		;LH = 0?
	TLCN T3,-1		;OR LH = -1?
	HRLI T3,(POINT 7,0)	;YES, SET UP BYTE POINTER
TYPST1:	ILDB T2,T3		;GET NEXT CHAR TO BE OUTPUT
	JUMPE T2,R		;IF NULL, DONE
	CALL TYPCHR		;TYPE IT OUT
	JRST TYPST1		;LLOP BACK FOR REST OF CHARS


;ROUTINE TO TYPE THE DATE

OUTDAT:	SAVET
	MOVX T3,OT%NTM		;OUTPUT JUST THE DATE WITHOUT THE DAY
	JRST TYPDT1

TYPDAT:	SAVET
	MOVX T3,OT%NTM!OT%DAY	;OUTPUT THE DAY AND DATE
TYPDT1:	STKVAR <<TYPDTS,10>,TYPDTJ,TYPDTF>
	MOVEM T3,TYPDTF		;SAVE THE FLAGS FOR THE ODTIM
	MOVEM T1,TYPDTJ		;SAVE THE JFN
	SKIPN T2		;ANY DATE SPECIFIED?
	JRST [	HRROI T2,[ASCIZ/NOT SPECIFIED/]
		CALLRET TYPSTR]
	MOVX T4,IC%UTZ		;CONVERT DATE TO THIS TIME ZONE
	ODCNV
	SETZ T4,		;USE DEFAULT TIMEZONE
	IDCNV
	 JSP ERROR
	HRROI T1,TYPDTS		;GET ADR OF STRING
	MOVE T3,TYPDTF		;GET THE FLAGS TO BE USED
	ODTIM
	MOVE T1,TYPDTJ		;GET BACK THE JFN
	HRROI T2,TYPDTS		;NOW OUTPUT THE DATE
	CALLRET TYPSTR
;TYPE OUT THE NAME OF A TASK
;	T1/ TASK BLOCK ADDRESS
;	CALL TYPTNM
;	RETURN HERE
TYPTNM:	MOVE T4,T1		;COPY ADDRESS
	LOAD T1,TKPRJ,(T4)	;PROJECT BLOCK
	LOAD T1,PJNAM,(T1)	;NAME STRING
	HRLI T1,(POINT 7,0)	;MAKE BYTE POINTER
	PSOUT
	MOVEI T1,"/"
	PBOUT
	LOAD T1,TKNAM,(T4)	;TASK NAME
	HRLI T1,(POINT 7,0)	;MAKE BYTE POINTER
	PSOUT
	RET
;ROUTINE TO GET THE CONVERTED DATE
;ACCEPTS IN T1/	INTERNAL DATE AND TIME
;RETURNS +1:	ALWAYS, T1/	DAY,,0

GETDAY:	MOVE T2,T1		;GET DATE INTO T2
	MOVEI T4,0
	ODCNV			;GET DAYS, MONTHS, YEARS
	LDB T2,[POINT 6,T4,17]	;GET TIME ZONE
	TRNE T2,40		;POSITIVE?
	IOR T2,[777777,,777700]	;NO, EXTEND THE SIGN
	IMULI T2,<777777/^D24>	;GET DIFERENCE SINCE GREENWICH TIME
	ADD T1,T2		;OFFSET TO GRENWICH TIME
	HLLZS T1		;GET DAY,,0
	RET


;ROUTINE TO GET THE # OF WORKING DAYS BETWEEN TWO DATES
;ACCEPTS IN T1/	START DATE
;	    T2/	FINISH DATE
;	CALL GETNWD
;RETURNS +1:	ALWAYS,	T1/	NUMBER OF WORKING DAYS

GETNWD:	SAVEQ
	DMOVE Q1,T1		;SAVE ARGS
	CALL CNTHOL		;COUNT THE DAYS THAT ARE HOLIDAYS
	 SETZ T1,		;NONE
	MOVE Q3,T1		;REMEMBER THE NUMBER
	DMOVE T1,Q1		;GET BACK ARGS
	HLRZS T1		;GET DAYS
	HLRZS T2
	CAMN T1,T2		;THE SAME?
	JRST [	MOVEI T1,0	;YES, THE ANSWER IS 0
		RET]
	ADDI T1,2		;ADD IN OFFSET SO MONDAY IS 0 MODULO 7
	ADDI T2,2
	ASUBR <GETNWS,GETNWF>
	MOVE T3,T2		;SET UP FOR DIVIDE
	IDIVI T1,7		;GET THE NUMBER OF WEEKS
	CAIN T2,5		;SATURDAY?
	AOSA GETNWS		;YES, UPDATE START TO MONDAY
	CAIN T2,6		;SUNDAY?
	AOS GETNWS		;YES, UPDATE START TO MONDAY
	IDIVI T3,7		;GET WEEKS FOR END DATE
	CAIN T4,6		;SUNDAY?
	SOS GETNWF		;YES, PUSH FINISH BACK TO FRIDAY
	MOVE T1,GETNWS		;GET START DATE
	IDIVI T1,7		;GET WEEKS AGAIN
	MOVE T3,GETNWF		;GET FINISH DATE
	IDIVI T3,7		;GET WEEKS AGAIN
	SUB T3,T1		;GET WEEKS ON TASK
	IMULI T3,5		;GET DAYS ON TASK
	SUB T3,T2		;SUBTRACT DAYS USED IN START WEEK
	ADD T3,T4		;ADD IN DAYS IN FINISH WEEK
	MOVE T1,T3		;GET ANSWER INTO T1
	SUB T1,Q3		;SUBTRACT OUT THE HOLIDAYS
	RET


REPEAT 0,<	SAVEQ
	HLRZS T1		;GET DAYS
	HLRZS T2
	SUB T2,T1		;GET NUMBER OF DAYS
	DMOVE Q1,T1		;SAVE THE START DAY
	SETZ Q3,		;INIT COUNTER
	JUMPE Q2,GETNW2		;IF NO DAYS, GO RETURN 0
GETNW1:	HRLZ T1,Q1		;GET DATE
	CALL CHKWD		;SEE IF IT IS A WORKING DAY
	 SKIPA			;NO
	AOS Q3			;COUNT UP ANSWER
	AOS Q1			;STEP DAY
	SOJG Q2,GETNW1		;LOOP BACK FOR EACH DAY
GETNW2:	MOVE T1,Q3		;RETURN THE ANSWER
	RET
>


;ROUTINE TO CHECK IF A DAY IS A WORKING DAY
;ACCEPTS IN T1/	DATE
;RETURNS +1:	NOT A WORKING DAY
;	 +2:	A WORKING DAY

CHKWD:	HLRZ T2,T1		;GET DAY
	ADDI T2,2		;SEE IF IT IS A WEEKEND
	IDIVI T2,7
	CAIL T3,5		;MON  - FRI?
	RET			;NO
	CALL CHKHOL		;SEE IF IT IS A HOLIDAY
	 RETSKP			;NO, THEN IT IS A WORKING DAY
	RET			;YES, NOT A WORKING DAY


;ROUTINE TO CHECK IF A DAY IS A HOLIDAY
;ACCEPTS IN T1/	DATE
;RETURNS +1:	NOT A HOLIDAY
;	 +2:	A HOLIDAY

CHKHOL:	HLLZS T1
	MOVE T2,HOLTAB		;GET ADR OF HOLIDAY TABLE
	JUMPE T2,R		;IF NONE, THEN DONE
	LOAD T3,HOLUSE,(T2)	;GET USE COUNT
	JUMPE T3,R
	MOVNS T3
	HRLZS T3
	HRRI T3,1(T2)		;GET AOBJN POINTER TO TABLE
CHKHO1:	CAMN T1,(T3)		;FOUND A MATCH?
	RETSKP			;YES, THEN DONE
	AOBJN T3,CHKHO1		;NO, LOOP BACK FOR OTHER ENTRIES
	RET			;NOT A HOLIDAY


;ROUTINE TO COUNT THE HOLIDAYS BETWEEN TWO DATES
;ACCEPTS IN T1/	START DATE
;	    T2/	FINISH DATE
;RETURNS +1:	NONE
;	 +2:	T1/	COUNT

CNTHOL:	SAVEQ
	HLLZS T1
	HLLZS T2
	CAMG T2,T1		;FINISH DATE AFTER START DATE?
	RET			;NO
	DMOVE Q1,T1		;SAVE THE ARGS
	SETZ Q3,		;INIT THE COUNT
	MOVE T4,HOLTAB		;GET POINTER TO THE TABLE
	JUMPE T4,R		;IF NONE, THEN DONE
	LOAD T1,HOLUSE,(T4)	;GET USE COUNT
	JUMPE T1,R
	MOVNS T1
	HRLZS T1
	HRRI T1,1(T4)		;GET POINTER TO TABLE
CNTHO1:	MOVE T2,(T1)		;GET NEXT DATE
	CAML T2,Q1		;IS THIS DATE WITHIN THE RANGE
	CAML T2,Q2
	JRST CNTHO2		;NO
	ADDI T2,2		;SEE IF DAY IS DURING THE WEEK
	IDIVI T2,7
	CAIGE T3,5		;SAT OR SUN?
	AOS Q3			;NO, COUNT UP COUNT
CNTHO2:	AOBJN T4,CNTHO1		;LOOP BACK FOR ALL DATES IN THE TABLE
	MOVE T1,Q3		;GET ANSWER
	RETSKP
;ROUTINE TO GET FINISH DATE GIVEN START DATE AND # OF WORK DAYS
;ACCEPTS IN T1/	START DATE
;	    T2/	# OF WORK DAYS
;	CALL GETNFD
;RETURNS +1:	ALWAYS, T1/	NEW FINISH DATE

GETNFD:	SAVEQ
	JUMPLE T2,R		;IF NO WORKING DAYS, THEN DONE
	DMOVE Q1,T1		;SAVE ARGS
GETNF1:	MOVE T1,Q1		;GET DATE
	CALL CHKWD		;SEE IF IT IS A WORKING DAY
	 SKIPA			;IT ISNT
	SOS Q2			;COUNT DOWN # OF WORK DAYS LEFT
	ADD Q1,[1,,0]		;STEP TO NEXT DAY
	JUMPG Q2,GETNF1		;IF MORE WORK DAYS LEFT, LOOP BACK
	MOVE T1,Q1		;GET FINISH DAY
	RET

	JUMPLE T2,R		;IF NO DAYS, RETURN SAME DATE
	HLRZ T3,T1		;GET DAYS
	ADDI T3,2		;TRANSLATE SO MONDAY = 0 MODULO 7
	IDIVI T3,7		;GET REMAINDER OF DAYS IN WEEK
	CAIN T4,5		;SATURDAY?
	ADD T1,[2,,0]		;YES, START ON MONDAY
	CAIN T4,6		;SUNDAY?
	ADD T1,[1,,0]		;YES
	HLRZ T3,T1		;GET DAY OF WEEK AFTER FIRST UPDATE
	ADDI T3,2
	IDIVI T3,7
	IDIVI T2,5		;GET WEEKS OF WORK DONE
	IMULI T2,7		;GET REAL WEEKS OF WORK DONE
	ADD T2,T3		;PLUS DAYS OF WEEK
	ADD T4,T3		;SEE IF THIS WRAPS AROUND ANOTHER WEEK
	CAIL T4,5		;NEED TO SKIP A WEEKEND?
	ADDI T2,2		;YES
	HRLZS T2		;GET DAYS IN LH
	ADD T1,T2		;ADD TO START DATE
	HLRZ T2,T1		;SEE IF THIS ENDED ON A WEEKEND
	ADDI T2,2
	IDIVI T2,7		;GET DAY OF WEEK
	CAIN T3,5		;SATURDAY?
	ADD T1,[2,,0]		;YES, MAKE IT BE THE NEXT MONDAY
	CAIN T3,6		;SUNDAY?
	ADD T1,[1,,0]		;YES
	RET			;DONE
;ROUTINE TO TYPE OUT AN ERROR MESSAGE

ERROR:	HRROI T1,[ASCIZ/
? FATAL ERROR: /]
	PSOUT
	MOVEI T1,.PRIOU		;GET OUTPUT JFN
	HRLOI T2,.FHSLF
	SETZ T3,
	ERSTR			;OUTPUT THE ERROR MESSAGE
	 JFCL
	 JFCL
	HALTF
	JRST PANTT
;SAVE ROUTINES

SAVT:	PUSH P,T1
	PUSH P,T2
	PUSH P,T3
	PUSH P,T4
	CALL 0(CX)
	 SKIPA
	AOS -4(P)
	POP P,T4
	POP P,T3
	POP P,T2
	POP P,T1
	RET

SAVQ:	PUSH P,Q1
	PUSH P,Q2
	PUSH P,Q3
	CALL (CX)
	 SKIPA
	AOS -3(P)
	POP P,Q3
	POP P,Q2
	POP P,Q1
	RET

SAVPQ:	PUSH P,Q1
	PUSH P,Q2
	PUSH P,Q3
	PUSH P,P1
	PUSH P,P2
	PUSH P,P3
	PUSH P,P4
	PUSH P,P5
	PUSH P,P6
	CALL 0(CX)
	 SKIPA
	AOS -11(P)
	POP P,P6
	POP P,P5
	POP P,P4
	POP P,P3
	POP P,P2
	POP P,P1
	POP P,Q3
	POP P,Q2
	POP P,Q1
	RET
SAVP:	PUSH P,P1
	PUSH P,P2
	PUSH P,P3
	PUSH P,P4
	PUSH P,P5
	PUSH P,P6
	CALL 0(CX)
	 SKIPA
	AOS -6(P)
	POP P,P6
	POP P,P5
	POP P,P4
	POP P,P3
	POP P,P2
	POP P,P1
	RET
;COMMAND TREES

LEV0CT:	$INIT (LEV0C1)		;LEVEL 0 COMMAND FIELD
LEV0C1:	$KEYDSP (LEV0TB)
LEV0TB:	$STAB
	DSPTAB (LEV0CA,ADDCMD,<ADD>)
	DSPTAB (LEV0CD,DELETE,<DELETE>)
	DSPTAB (CRLF,EXIT,<EXIT>)
	DSPTAB (LEV0L,LSTCMD,<LIST>)
	DSPTAB (LEV0CO,OUTPUT,<OUTPUT>)
	DSPTAB (LEV0CP,PLOT,<PLOT>)
	DSPTAB (LEV0RM,REMDAT,<REMEMBER>)
	DSPTAB (CRLF,SKDCMD,<SCHEDULE>)
	DSPTAB (LV0ST1,SET,<SET>)
	DSPTAB (LEV0CU,UPDATE,<UPDATE>)
	$ETAB


LEV0RM:	$NOISE (CRLF,<ESTIMATED DATES FOR FUTURE COMPARISON>)

LV0ST1:	$KEYDSP (LV0ST2)
LV0ST2:	$STAB
	DSPTAB (LV0SH1,SETHOL,<HOLIDAY>)
	DSPTAB (LV0SP1,SETPPA,<PERT-PLACEMENT-ALGORITHM>)
	DSPTAB (CRLF,SETSAF,<SAFE-UPDATE-MODE>)
	DSPTAB (LV0SD1,SETDAT,<SCHEDULE-DATE>)
	DSPTAB (CRLF,SETSLB,<SLOPPY-BUT-FAST-UPDATE-MODE>)
	$ETAB

LV0SH1:	$NOISE (LV0SH2,<DATE>)
LV0SH2:	$DATE (CRLF)

LV0SD1:	$NOISE (LV0SD2,<TO>)
LV0SD2:	$DATE (CRLF)

LV0SP1:	$NOISE (LV0SP2,<TO THE>)
LV0SP2:	$KEYDSP (LV0SP3)
LV0SP3:	$STAB
	DSPTAB (LV0SP4,0,<DEFAULT>)
	DSPTAB (LV0SP4,1,<HIGH-DENSITY>)
	$ETAB
LV0SP4:	$NOISE (CRLF,<PLACEMENT ALGORITHM>)

LEV0CA:	$KEYDSP (LEV1A)
LEV1A:	$STAB
	DSPTAB (DATDV,L0DEV,<DEVELOPER>)
	DSPTAB (LEV1AP,ADDP,<PROJECT>)
	DSPTAB (LEV1AT,ADDT,<TASK>)
	$ETAB

LEV1AP:	$NOISE (LEV2P1,<PROJECT NAME>)
LEV2P1:	$FIELD (CRLF,<NAME OF PROJECT TO BE ADDED TO THE PROJECT LIST>)

LEV1AT:	$NOISE (LEV2T1,<TASK NAME>)
LEV2T1:	$FIELD (LEV2T2,<NAME OF THE TASK TO BE ADDED TO THE TASK LIST>)
LEV2T2:	$NOISE (LEV2T3,<TO PROJECT>)
LEV2T3:	PDBDEF (.CMKEY,,,,,,CRLF,,STOTSK,SETPRJ)

LEV0CD:	$KEYDSP (LEV1D)
LEV1D:	$STAB
	DSPTAB (DATDLD,DELODV,<DEVELOPER>)
	DSPTAB (LEV1DP,DELPRJ,<PROJECT>)
	DSPTAB (CRLF,DELDAT,<SCHEDULE-DATE>)
	DSPTAB (LEV1DT,DELTSK,<TASK>)
	$ETAB

LEV1DP:	$NOISE (LEV2D1,<PROJECT NAME>)
LEV2D1:	PDBDEF (.CMKEY,,,,,,CRLF,,STOTSK,SETPRJ)

LEV1DT:	$NOISE (LEV2D2,<FROM PROJECT>)
LEV2D2:	PDBDEF (.CMKEY,,,,,,LEV2D3,,STOTSK,SETPRJ)
LEV2D3:	$NOISE (LEV2D4,<TASK NAME>)
LEV2D4:	PDBDEF (.CMKEY,,,,,,CRLF,,,SETTSK)

LEV0L:	$KEYDSP (LEV1L)
LEV1L:	$STAB
	DSPTAB (LEV1L1,LISTP,<PROJECT>)
	$ETAB

LEV1L1:	PDBDEF (.CMKEY,,,,,,LEV1L2,,STOTSK,SETPRJ)
LEV1L2:	$NOISE (LEV1L3,<TASK>)
LEV1L3:	PDBDEF (.CMKEY,,,,,CRLF,CRLF,,,SETTSK)

LEV0CO:	$KEYDSP (LEV1OT)
LEV1OT:	$STAB
	DSPTAB (LEV1O,CMPDAT,<CHANGES-IN-ESTIMATED-DATES>)
	DSPTAB (LEV1O,DUMP,<CONTROL-FILE>)
	DSPTAB (LEV1CP,OUTCP,<CRITICAL-PATH>)
	DSPTAB (LEV1O,LSTDEV,<DEVELOPER-LIST>)
	DSPTAB (LEVOG,GANTT,<GANTT-CHART>)
	DSPTAB (LEV1O,LPATHC,<PATH-CHARACTER-LIST>)
	DSPTAB (LEV1O,PERT,<PERT-CHART>)
	DSPTAB (LEV1O,LSTSKD,<SCHEDULE>)
	DSPTAB (LEV1O,SPERT,<SELECTED-PERT-BOXES>)
	DSPTAB (LV1OT1,LSTTSK,<TASK-LIST>)
	$ETAB

LV1OT1:	$NOISE (LV1OT2,<SORTED BY>)
LV1OT2:	$KEYDSP (LV1OT3)
LV1OT3:	$STAB
	DSPTAB (LEV1O,LSTTKE,<EARLIEST-START-DATE>)
;	DSPTAB (LEV1O,LSTTKL,<LATEST-START-DATE>)
	DSPTAB (LEV1O,LSTTKP,<PROJECT>)
	$ETAB


LEVOG:	$NOISE (LEVOG1,<OF>)
LEVOG1:	$KEYDSP (LEVOGT)
LEVOGT:	$STAB
	DSPTAB (LEV1O,0,<DEVELOPERS>)
	DSPTAB (LEV1O,2,<MILESTONES>)
	DSPTAB (L1ONLY,4,<ONLY-DEVELOPER>)
	DSPTAB (LEV1O,1,<TASKS>)
	$ETAB

L1ONLY:	PDBDEF	(.CMUSR,CM%PO,,,,,LEV1O)


LEV0CP:	$KEYDSP (LV0CPT)
LV0CPT:	$STAB
	DSPTAB (LEVOG,GPLOT,<GANTT-CHART>)
	DSPTAB (LEV1O,PPLOT,<PERT-CHART>)
	DSPTAB (LEV1O,SPPLOT,<SELECTED-PERT-BOXES>)
	$ETAB

LEV1O:	$NOISE (LEV1O1,<TO FILE>)
LEV1O1:	$OFILE (CRLF)

LEV0CU:	$NOISE (LEV0U1,<PROJECT>)
LEV0U1:	PDBDEF (.CMKEY,,,,,,LEV1U,,STOTSK,SETPRJ)
LEV1U:	$NOISE (LEV1U1,<TASK>)
LEV1U1:	PDBDEF (.CMKEY,,,,,CRLF,CRLF,,,SETTSK)


SDATA:	$INIT (SDATA1)
SDATA1:	$NUMBER (CRLF,<^D10>,<LOOK AHEAD LEVEL>)

LEV1CP:	$NOISE	(LV1CP1,<FOR PROJECT>)
LV1CP1:	PDBDEF	(.CMKEY,,,,,,LV1CP2,,STOTSK,SETPRJ)
LV1CP2:	$NOISE	(LV1CP3,<TASK>)
LV1CP3:	PDBDEF	(.CMKEY,,,,,,LEV1O,,,SETTSK)
;PROJECT DATA COMMAND

PDATA:	$INIT (PDATA1)
PDATA1:	$KEYDSP (PDATAT)
PDATAT:	$STAB
	DSPTAB (PDATDL,PRJDEL,<DELETE>)
	DSPTAB (DATDV,PRJDEV,<DEVELOPER>)
	DSPTAB (PDATAF,PRJFIN,<FINISHED>)
	DSPTAB (CRLF,PRJLST,<LIST>)
	DSPTAB (PDATP,PRJPRF,<PREFERENCE-VALUE>)
	DSPTAB (CRLF,PRJDSC,<PROJECT-DESCRIPTION>)
	$ETAB

PDATDL:	$KEYDSP (PDTDL1)
PDTDL1:	$STAB
	DSPTAB (PDTDLD,PRJDLD,<DEVELOPER>)
	$ETAB

PDTDLD:	PDBDEF (.CMUSR,CM%PO,,,,,CRLF)

PDATAF:	$NOISE (CRLF,<UPDATING PROJECT DATA>)

PDATP:	$NOISE (PDATP1,<FOR FREE CHOICE>)
PDATP1:	$FLOAT (CRLF)


DDATA:	$INIT (DDATA1)
DDATA1:	$DATE (CRLF)
;DATA COMMAND

DATA:	$INIT (DATA1)			;INITIALIZATION

DATA1:	$KEYDSP (DATAT1)		;FIRST LEVEL KEYWORD TABLE

DATAT1:	DATT1L-1,,DATT1L-1
	DSPTAB (CRLF,TKAR,<ALL-DEVELOPERS-REQUIRED>)
	DSPTAB (DATAT,TKAT,<ATTRIBUTE>)
	DSPTAB (DATCD,TKCD,<COMPLETION-DATE>)
	DSPTAB (DATDL,TKDL,<DELETE>)
	DSPTAB (DATDP,TKDP,<DEPENDENCY>)
	DSPTAB (DATDV,TKDV,<DEVELOPER>)
	DSPTAB (DATEL,TKEL,<ESTIMATED-PROJECT-LENGTH>)
	DSPTAB (DATXD,TKXD,<EXPECTED>)
	DSPTAB (DATFC,TKFC,<FINISHED>)
	DSPTAB (CRLF,TKLS,<LIST>)
	DSPTAB (DATLA,TKLA,<LONG-ATTRIBUTE>)
	DSPTAB (CRLF,TKMI,<MILESTONE>)
	DSPTAB (DATMD,TKMD,<MINIMUM-STARTING-DATE>)
	DSPTAB (DATPA,TKPTH,<PATH-CHARACTER>)
	DSPTAB (DATPF,TKPF,<PREFERENCE-VALUE>)
	DSPTAB (DATSD,TKSD,<STARTING-DATE>)
	DSPTAB (DATTD,TKTD,<TASK-DESCRIPTION>)
	DSPTAB (DATTI,TKTI,<TIME-TO-DATE>)
DATT1L==.-DATAT1

DATXD:	$KEYDSP (DATXD1)
DATXD1:	$STAB
	DSPTAB (DATXD2,0,<COMPLETION-DATE>)
	DSPTAB (DATXD2,1,<STARTING-DATE>)
	$ETAB

DATXD2:	$NOISE (DATXD3,<IS>)
DATXD3:	$DATE (CRLF)

DATCD:	$DATE (CRLF)			;COMPLETION-DATE

DATMD:	$DATE (CRLF)			;MINIMUM STARTING DATE

DATPA:	$NOISE (DATPA1,<IS>)
DATPA1:	$FIELD (CRLF,<SINGLE ALPHA-NUMERIC CHARACTER TO LABEL THE CRITICAL PATH FOR THIS TASK>)

DATDL:	$KEYDSP (DATDL1)
DATDL1:	$STAB
	DSPTAB (CRLF,TKDCD,<COMPLETION-DATE>)
	DSPTAB (DATDP,TKDDP,<DEPENDENCY>)
	DSPTAB (DATDLD,TKDLD,<DEVELOPER>)
	DSPTAB (CRLF,TKDEL,<ESTIMATED-PROJECT-LENGTH>)
	DSPTAB (DATDX,TKDXD,<EXPECTED>)
	DSPTAB (CRLF,TKDMD,<MINIMUM-STARTING-DATE>)
	DSPTAB (CRLF,TKDPC,<PATH-CHARACTER>)
	DSPTAB (CRLF,TKDPF,<PREFERENCE-VALUE>)
	DSPTAB (CRLF,TKDSD,<STARTING-DATE>)
	DSPTAB (CRLF,TKDTI,<TIME-TO-DATE>)
	$ETAB

DATDX:	$KEYDSP (DATDX1)
DATDX1:	$STAB
	DSPTAB (CRLF,0,<COMPLETION-DATE>)
	DSPTAB (CRLF,1,<STARTING-DATE>)
	$ETAB

DATDLD:	PDBDEF (.CMUSR,CM%PO,,,,,CRLF)

DATDP:	$NOISE (DATDP1,<ON PROJECT>)	;DEPENDENCY (ON PROJECT)
DATDP1:	PDBDEF (.CMKEY,,,,,,DATDP2,,STOTSK,SETPRJ)
DATDP2:	$NOISE (DATDP3,<TASK NAME>)
DATDP3:	PDBDEF (.CMKEY,,,,,,DATDP4,,,SETTSK)
DATDP4:	$CRLF

DATDV:	PDBDEF (.CMUSR,CM%PO,,,,,DATDV1)	;DEVELOPER
DATDV1:	$NOISE (DATDV2,<RATE>)
DATDV2:	$FLOAT (DATDV3,<FRACTIONAL TIME TO BE ALLOCATED ON THIS TASK>)
DATDV3:	$NOISE (DATDV4,<HANDICAP>)
DATDV4:	$FLOAT (DATDV5,<RELATIONSHIP OF DEVELOPERS RATE TO ESTIMATE OF PROJECT LENGTH>)
DATDV5:	$CRLF

DATEL:	$NOISE (DATEL1,<IN DAYS>)	;ESTIMATED-PROJECT-LENGTH
DATEL1:	$NUMBER (DATEL2,<^D10>,<NUMBER OF WORK DAYS TO DO THIS TASK>)
DATEL2:	$CRLF

DATFC:	$NOISE (CRLF,<UPDATING TASK DATA>)

DATPF:	$NOISE (DATPF1,<FOR FREE CHOICE>)
DATPF1:	$FLOAT (CRLF)

DATSD:	$DATE (DATSD1)			;STARTING-DATE
DATSD1:	$CRLF

DATTD:	$CRLF				;TASK-DESCRIPTION

DATTI:	$NOISE (DATTI1,<IN DAYS>)	;TIME-TO-DATE
DATTI1:	$NUMBER (DATTI2,<^D10>,<NUMBER OF DAYS ALREADY SPENT ON THIS TASK>)
DATTI2:	$NOISE (DATTI3,<AT DATE>)
DATTI3:	$DATE (DATTI4)
DATTI4:	$CRLF

DATLA:	$NOISE (DATLA1,<NAME IS>)
DATLA1:	$FIELD (CRLF,<NAME OF ATTRIBUTE>)

DATAT:	$NOISE (DATATR,<NAME IS>)
DATATR:	$FIELD (DATTR1,<NAME OF ATTRIBUTE>)
DATTR1:	$NOISE (DATTR2,<VALUE>)
DATTR2:	$FIELD (CRLF,<VALUE OF ATTRIBUTE>)


;YES/NO COMMAND TABLE

YNCT:	$INIT (YNCT1)
YNCT1:	$KEY (CRLF,YNCTTB)
YNCTTB:	YNCTBL-1,,YNCTBL-1
	KEYTAB (,0,<NO>)
	KEYTAB (,1,<YES>)
	YNCTBL==.-YNCTTB

CRLF:	$CRLF

SEL:	$INIT (SEL1)

SEL1:	$KEYDSP (SELT1)

SELT1:	$STAB
	DSPTAB	(SELF,SELFI,<FINISHED>)
	DSPTAB	(SELI,SELIP,<INCLUDE>)
	$ETAB

SELI:	$KEYDSP (SELI1)
SELI1:	$STAB
	DSPTAB	(SELI2,SELIPR,<PROJECT>)
	$ETAB

SELI2:	$NOISE	(LEV0U1,<NAME>)

SELF:	$NOISE	(CRLF,<SELECTING -- START PERT>)

	XLIST			;LITERALS
	VAR
	LIT
	LIST			;LITERALS

	END <3,,ENTVEC>