IMD 1.16: 2/09/2008 14:58:52 84-93530-03 e860 f53003 cartos eII maintenance diskette    @0|)wwЀЀtQql)  " }gA `_8M@IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIOS4 MF182042218131504820422181315 820422181315;F53003 VOLCARTOS EII MAINT. DISKETTE 84-93530-03 (E850)   IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII_8M@iGyy GGG`HZ@ b G`^Y e IQ BBp@;:9 :7P@ G:پN 8!0. * C'xC# b# }B @0DAJL w+™ЀЀΖQA1"   i ž} š} @EEFF)DEۄF8 џ} ԟ} ̟} * `jUBBI,v BI, # @ G9H@pܾrCHC C GTq` Lg"gEXC P+s=胾P+c fQN p $Rxnj  ޔniZ ތ⊞ } }HGž Ÿ@ALS)"$ C k20j.h( +$`%ꂜ\1 !M' y %'+os慾)sY ed|{ @8 o O m J K i gN )V% t%sLn`"E F. F„ D>) =`;nrgy w"G,{Kq1 A&}E*`(t@% ;c  765y342(.OS:: SYS"iwvc Bc A@6<# Ic B# gIjHc r* ======== * CSI0.ASM * ======== * * C A R T O S S Y S T E M I N T E R F A C E * * Module 0 * Assemble language module * * Revision History * X001 --- 19 Jan 1982 AWB: Initial Write * E810 --- 18 Feb 1982 AWB: C A R T O S Pilot release * E820 --- 08 Mar 1982 AWB: Now releases EMP Blocks * E830 --- 19 Mar 1982 AWB: WRLOG0 ignores UL errors, OPEN0 does not * do a connect if DontOpen. is TRUE. * E840 --- 23 Mar 1982 AWB: GETUID Handles dot and dot dot. * E843 --- 66 Mar 1986 AWB: Open by F# and SCB.OMD included. Later * allowed previously open LUN to not be closed by EXIT0. * E850 --- 22 Apr 1982 rph: Bumped rev. for release and that limey * RGB made a fix to CSI6 to stop it crapping on the EMP. * E860 --- 23 Apr 1982 RGB: fixed Get tproection to allow hex numbers * OBJNOTE '*** EII.LBR - REV E860 ***' * OLDOPS OPTIONS +4 INCLUDE X1/USERCOMMON.MAC INCLUDE X1/SDB.MAC OPTIONS OLDOPS * * SCB chain head. DATA:RAM REL SHARABLE DATA:RAM NAM C:SCBCH C:SCBCH WORD 0 * * Stream lockout Sema4 NAM C:SSEMA4 SSDB SDB: 0,1 C:SSEMA4 EQU SSDB+SD:ID END * * Write Prompt DATA:RAM REL SHARABLE DATA:RAM NAM C:WP,C:WPL C:WP BYTE ' ' C:WPL WORD 6 END * * Write Command Prompt DATA:RAM REL SHARABLE DATA:RAM NAM C:WPC,C:WPCL C:WPC BYTE  ' CSI..' C:WPCL WORD 6 END * * Extent Size DATA:RAM REL SHARABLE DATA:RAM NAM C:EXTSIZ C:EXTSIZ WORD :2 END * * ======== * B:UPDCSI * ======== * Called as BCPL routine. * A Reg contains address of two word CFI block * Q Reg contains CFI increment. * The CFI, if valid, is bumped by the increment. * CODE:ROM REL SHARABLE CODE:ROM ROMMABLE CODE:ROM NAM B:UPDCFI B:UPDCFI BENTRY JEQ A,NOINC * Invalid CFI COPY A,X * Address of CFI COPY =0,A * Clear high word of AQ pair ADD 0(X),AQ * Do the add COPYE AQ,0(X) * Store it back NOINC BRTN END * * ======== * B:FINISH * ======== * Terminates this task and returns a termination code to * the operating system. * OLDOPS OPTIONS +4 INCLUDE X1/E:XXXX.MAC INCLUDE X1/USERCOMMON.MAC OPTIONS OLDOPS CODE:ROM REL  SHARABLE CODE:ROM ROMMABLE CODE:ROM NAM B:FINISH B:FINISH BENTRY COPY A,X E:MONC 0(X) END * * ===== * B:CMD * ===== * Entry by BCPL calling sequence. Performs an E:CMD of the buffer * whose address is provided as the routine's only parameter. * OLDOPS OPTIONS +4 INCLUDE X1/E:XXXX.MAC INCLUDE X1/USERCOMMON.MAC OPTIONS OLDOPS CODE:ROM REL SHARABLE CODE:ROM ROMMABLE CODE:ROM NAM B:CMD B:CMD BENTRY COPY A,X * Get buffer E:CMD 0(X) * Do the E:CMD END * * ===== * B:RCI * ===== * Entry by BCPL calling sequence. Performs an E:RCI of the * ISM block whose address is provided as the routines only * parameter. * OLDOPS OPTIONS +4 INCLUDE X1/E:XXXX.MAC INCLUDE X1/USERCOMMON.MAC OPTIONS OLDOPS CODE:ROM REL SHARABLE CODE:ROM ROMMABLE CODE:ROM NAM B:RCI B:RCI BENTRY COPY A,X * Get Buffer E:RCI 0(X) * Do the E:RCI BRTN * Return END * * ======= * GETBYTE * ======= * CODE:ROM REL ROMMABLE CODE:ROM SHARABLE CODE:ROM NAM GETBYTE: GETBYTE: BENTRY . GETBYTE COPY Q,X X=OFFSET COPY Y,Q Q=STACK POINTER TEMP COPY A,Y Y=WORD ADDRESS OF STRING SBIT 2,S SET BYTE MODE COPY 0(X,Y),A GET THE BYTE RBIT 2,S RESET WORD MODE COPY Q,Y RESTORE STACK POINTER BRTN * * ======= * PUTBYTE * ======= * NAM PUTBYTE: PUTBYTE: BENTRY . PUTBYTE COPY Q,X X=OFFSET COPY Y,Q Q=STACK POINTER TEMP COPY 4(Y),Y BYTE TO Y EXCH Y,A BYTE IN A,ADDR IN Y SBIT 2,S SET BYTE MODE COPY A,0(X,Y) PUT THE BYTE RBIT 2,S RESET WORD MODE COPY Q,Y RESTORE STACK POINTER BRTN END * * ======= * TASKID: * ======= * Returns the L register as a task identifier * CODE:ROM REL SHARABLE CODE:ROM ROMMABLE CODE:ROM NAM TASKID: TASKID: BENTRY COPY L,A BRTN END Entry by BCPL calling sequence. Performs an E:CMD of the buffer * whose address is provided as the routine's only parameter. * OLDOPS OPTIONS +4 INCLUDE X1/E:XXXX.MAC INCLUDE X1/USERCOMMON.MAC OPTIONS OLDOPS CODE:ROM REL SHARABLE CODE:ROM ROMMABLE CODE:ROM NAM B:CMD B:CMD BENTRY COPY A,X * Get buffer E:CMD 0(X) * Do the E:CMD END * * ===== * B:RCI * ===== * Entry by BCPL calli// ======== // CSI3.BPL // ======== // C A R T O S S Y S T E M I N T E R F A C E // Module 3 // Basic File I/O Operation Services GET "CSI.HDR" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" // ======== // C.SPUID0 Service // ======== // Splits a UID block into its constituent parts A, B and C. LET C.SPUID0(UID,PARTA,PARTB,PARTC,aREPLY)=VALOF $( LET LENA=GETBYTE(UID,UID.LENA) // Length of part A LET LENB=GETBYTE(UID,UID.LENB) // Length of part B LET LENC=GETBYTE(UID,UID.LENC) // Le ngth of part C LET CSTART=UID.TEXT // Current starting position C.MOVBTS(UID,CSTART,PARTA,1,LENA) PUTBYTE(PARTA,0,LENA) // Transfer part A CSTART := CSTART + LENA // New starting byte for part B C.MOVBTS(UID,CSTART,PARTB,1,LENB) PUTBYTE(PARTB,0,LENB) // Transfer part B CSTART := CSTART + LENB // New starting byte for part B C.MOVBTS(UID,CSTART,PARTC,1,LENC) PUTBYTE(PARTC,0,LENC) // Transfer part C !aREPLY := OK // Reply is always good RESULTIS OK $) . GET "CSI.HDR" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" // ======== // C.MGUID0 Service // ======== // Merges Parts A, B and C of a UID block into a new UID block LET C.MGUID0(PARTA,PARTB,PARTC,UID,aREPLY)=VALOF $( LET LENA = GETBYTE(PARTA,0) // Part A length LET LENB = GETBYTE(PARTB,0)  // Part B length LET LENC = GETBYTE(PARTC,0) // Part C length LET UIDLEN = LENA + LENB + LENC +3 // Total UID length LET CSTART = UID.TEXT // Current starting index} IF UIDLEN>255 THEN // UID too big  $( !aREPLY := ER.UFN.TOO.BIG // Error RESULTIS ER.UFN.TOO.BIG $) C.MOVBTS(PARTA,1,UID,CSTART,LENA) // Copy over part A PUTBYTE(UID,UID.LENA,LENA) // Part A length CSTART := CSTART + LENA C.MOVBTS(PARTB,1,UID,CSTART,LENB) // Copy over part B PUTBYTE(UID,UID.LENB,LENB) // Part B length CSTART := CSTART + LENB C.MOVBTS(PARTC,1,UID,CSTART,LENC) // Copy over part C PUTBYTE(UID,UID.LENC,LENC) // Part C length PUTBYTE(UID,UID.LEN,UIDLEN)  // Total UID length !aREPLY := OK // Everything OK RESULTIS OK $) . GET "CSI.HDR" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" // ======== // C.RDUID0 Service // ======== // Builds a UID block from an ASCII file identifier string read from // the device connected to LUN. The identifier string is checked // for validity. LET C.RDUID0(aLUN,UID,aCH,aREPLY)=VALOF $( LET PB=VEC GTC.SIZ // C.RD0 Parameter Block PB!GTC.FUN := C.RdCh // Reading function PB!GTC.aLU := aLUN // Address of LUN PB!GTC.aCH := aCH // RdCh Character read PB!GTC.aRE := aREPLY // CSI reply address RESULTIS C.GETUID(UID,PB) // Get the UID $) // ====== // C.RdCh // ====== // Reads a character from an open LUN. PB is a parameter block with // the following format // GTC.FUN - Function C.RdCH // GTC.aLU - Address of LUN // GTC.aCH - Terminating Character // GTC.aRE - CSI reply Code. AND C.RdCh(PB)=VALOF $( LET BUF=VEC 0 // Single Character Buffer LET C=? // Character LET RBC=?  // Returned byte count TEST C.RD0(PB!GTC.aLU,BUF,1,@RBC,PB!GTC.aRE) = EOF THEN $(EOF C := ENDSTREAMCH // Return -1 !(PB!GTC.aRE) := EOF // Flag as EOF $)EOF OR C := AllCaps( GETBYTE(BUF,0) ) // Get the character !(PB!GTC.aCH) := C // Store it RESULTIS C $) // ======= // AllCaps // ======= // Returns the character C forced to be a capital AND AllCaps(C)= 'a'<=C<='z' -> C-'a'+'A', C . GET "CSI.HDR"  GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" // ======== // C.IPUID0 Service // ======== // Builds a UID block in the same manner as C.RDUID0, but takes // the information from a memory resident byte stream instead of // from an open file. LET C.IPUID0(BUF,ByteOffset,Length,UID,aCH,aREPLY)=VALOF $( LET PB=VEC GTC.SIZ // C.GCFM Parameter Block PB!GTC.FUN := C.GCFM  // Reading Function PB!GTC.BUF := BUF // C.GCFM Buffer PB!GTC.PTR := ByteOffset // C.GCFM pointer PB!GTC.L2G := Length // C.GCFM LEN2GO PB!GTC.aCH := aCH // C.GCFM Character read PB!GTC.aRE := aREPLY // CSI Reply address RESULTIS C.GETUID(UID,PB) // Get the UID $) // ====== // C.GCFM // ====== // Gets a character from memory. PB is a parameter block with the // following format. // GTC.FUN - Function C.GCFM // GTC.BUF - Buffer address // GTC.PTR - Buffer byte pointer // GTC.L2G - Buffer length to go // GTC.aCH - Address of terminating character // GTC.aRE - Address of CSI reply code. AND C.GCFM(PB)=VALOF $( LET L2GO,P = PB!GTC.L2G, PB!GTC.PTR LET aCH = PB!GTC.aCH TEST L2GO=0 THEN // Reached end of string to parse $(EOF !aCH := ENDSTREAMCH // Return -1 $)EOF OR $( !aCH := AllCaps(GETBYTE(PB!GTC.BUF,P)) PB!GTC.PTR := P + 1  // Bump pointer PB!GTC.L2G := L2GO - 1 // Decrement length $) !(PB!GTC.aRE) := OK  // Always good reply RESULTIS !aCH $) // ======= // AllCaps // ======= // Returns the character C forced to be a capital AND AllCaps(C)= 'a'<=C<='z' -> C-'a'+'A', C . GET "CSI.HDR" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" GET "/RON/CARTOS/BDFS/LAB.BDF" // ======== // C.GETUID // ======== // General purpose UID getter. // Fills UID from a file identifier. Returns TRUE if a valid UID // is read. LET C.GETUID(UID,PB)=VALOF $( LET C=? // Terminator LET InPartB = TRUE // We will be soon LET InPassword = FALSE // Not in password LET InProtection = FALSE  // Not in protection LET Last.Fn.Sep.at=? // Last Filename Sep. position LET aREPLY=PB!GTC.aRE  // CSI reply address LET TL=? // A temporary length value !UID, UID!1 := (UID.TEXT-1)<<8, 0 // Clear UID C := GetLUN(UID,PB) // Attempt to get LUN (if any) UNLESS !aREPLY>=OK RESULTIS !aREPLY// Invalid LUN TL := GETBYTE(UID,UID.LENA) // Get any LUN length Last.Fn.Sep.at := TL>0 -> TL, 0 // Set last separator here if LUN $(Next.Symbol // Get next symbol LET StartingPartC=FALSE // Not yet starting PartC LET SectionTerminated = FALSE // Section terminator. LET GetaCh = PB!GTC.FUN // Character reading function LET ULen = GETBYTE(UID,UID.LEN) SWITCHON C INTO // Check terminator $(Check.Term  CASE Fn.Sep: // Separator Last.Fn.sep.at := ULen + 1 // Separator position UNLESS InPartB DO SectionTerminated := TRUE ENDCASE CASE Fn.PWS: // Password start InPasswor d := TRUE // Flag it ENDCASE CASE Fn.PRS: // Protection Start InProtection := TRUE // Flag it ENDCASE CASE Fn.PCS: // PartC start IF InPartB DO TEST ( ULen = Last.Fn.Sep.at) \/ ( Ulen = UID.TEXT-1 ) DO $(Dot.or.DotDot AppendCh(UID,C) // Store the first dot C := GetaCH(PB) // Get next character.. IF C = '.' THEN // We have dot dot $(Dot.Dot AppendCh(UID,C) // Add to UID C := GetaCH(PB) // Get the terminator $)Dot.Dot LOOP // Go process terminator $)Dot.or.DotDot OR StartingPartC := TRUE // We are starting PartC DEFAULT: SectionTerminated := TRUE ENDCASE $)Check.Term IF GETBYTE(UID,UID.LEN) = Last.Fn.Sep.at DO $(Force.UID.End SectionTerminated := TRUE StartingPartC := FALSE $)Force.UID.End IF SectionTerminated DO  // Reached PartC or End $( LET L=GETBYTE(UID,UID.LEN) LET AL = GETBYTE(UID,UID.LENA) LET BL, CL = ?, ? // Part B and C lengths IF InPartB THEN // Complete PartB $(End.PartB  BL := L-AL-UID.TEXT+1 // PartB length PUTBYTE(UID,UID.LENB,BL) InPartB := FALSE  $)End.PartB UNLESS StartingPartC DO // Finish off $(End.UID BL := GETBYTE(UID,UID.LENB) CL := L-AL-BL-UID.TEXT+1 // Length of part C PUTBYTE(UID,UID.LENC,CL) // Stuff it BREAK  // Exit $)End.UID $) AppendCh(UID,C) // Append the terminator // Get the next symbol TEST InProtection THEN $( C := GetProtection(UID,PB) InProtection := FALSE  // Got Protection and Terminator $) OR $(Get.Fn.Ext.or.PW // Get Filename, Ext. or Password C := GetaCh(PB) // Get first character UNLESS 'A'<=C<='Z' DO // Validate it $( IF InPassword THEN // Null password, Invalid! $(Null.Password !aREPLY := ER.Invalid.PW RESULTIS !aREPLY $)Null.Password UNLESS '0'<=C<='9' \/ C='_' THEN LOOP // Invalid $)  AppendCh(UID,C) // Append the starting character C := C.ReadString(PB,UID,FnValid, // Read remainder InPassword->Fn.PwL-1, // .. of password InPartB ->Fn.FnL-1,  // .. or filename Fn.ExL-1) // .. or extension IF InPassword DO  // Check terminator $( TEST C=Fn.PwE THEN // Read next $( AppendCh(UID,C) // Append this terminator C := GetaCH(PB) InPassword := FALSE // No longer getting password $)  OR $( !aREPLY := ER.Invalid.PW RESULTIS !aREPLY $) $) $)Get.Fn.Ext. or.PW // Check CSI code. If error we can terminate here UNLESS !aREPLY >= OK THEN RESULTIS !aREPLY $)Next.Symbol REPEAT // Come here and UID is Hunky Dory RESULTIS !aREPLY $) // ====== // GetLUN // ====== // Attempts to read and append a LUN to UID. // Returns the terminating character as a result. AND GetLUN(UID,PB)=VALOF $( LET LUNValue=0 LET LUNLength=0 // Length of LUN LET GetaCH = PB!GTC.FUN // Character reading function LET C=GetaCh(PB) LET aREPLY=PB!GTC.aRE LET ValidLUN=TRUE TEST NUM(C) THEN // Require numeric LUN $(Get.Numeric.LUN LUNValue := LUNValue*10 + C - '0' UNLESS NUM(C) /\ (LUNValue<=Max.User.LUN) DO $(End.Numeric.LUN BREAK $)End.Numeric.LUN AppendCh(UID,C) // Append latest good character C := GetaCH(PB) // Next character $)Get.Numeric.LUN REPEAT OR IF ALPHA(C) DO $(Get.Alpha.LUN  AppendCh(UID,C) // Put in UID C := C.ReadString(PB,UID,Fnvalid,Fn.FnL-1) ValidLUN := VALOF  // Is it LUN or PartB $( LET L=GETBYTE(UID,UID.LEN)-UID.TEXT+1 LET LAB=VEC LA.SIZ // GLA buffer UNLESS (L=Fn.LUL) /\ ALPHA(GETBYTE(UID,UID.TEXT+Fn.LUL-1)) DO RESULTIS FALSE  // Must be part of PartB // Code to check for valid LUN // Provided UID.TEXT is a multiple of BytesperWord then there // is no need to form the LUN in a word from the UID. TEST UID.TEXT REM BytesPerWord=0 THEN LAB!LA.LUN := UID!(UID.TEXT/BytesPerWord) OR $( LET LUN=? // Conditionally assembled LUN := (GETBYTE(UID,UID.TEXT)<<8) + GETBYTE(UID,UID.TEXT+1) LAB!LA.LUN := LUN // Store LUN $) RESULTIS C.GLA(LAB) $) $)Get.Alpha.LUN // Store part A length, CSI reply code already set // If terminator is Fn.Sep it belongs to PartA, so bump count. LUNLength := ValidLUN -> GETBYTE(UID,UID.LEN)-UID.TEXT +  (C=Fn.Sep -> 2,1), 0 PUTBYTE(UID,UID.LENA,LUNLength) RESULTIS C $) // ============= // GetProtection // ============= // Appends a protection specification to UID. PB is the reading // routines parameter buffer. // Any errors are returned as a negative !PB!GTC.aRE, CSI reply code. // Returns the terminating character as a result. AND GetProtection(UID,PB)=VALOF $( LET GetaCH = PB!GTC.FUN // Character reading function LET aREPLY,C = PB!GTC.aRE, GetaCh(PB) FOR I=1 TO Fn.PrL+1 DO // Including terminator $( UNLESS ((I=Fn.PrL+1) -> C=Fn.PrE, NUM(C)\/('A'<=C<='F')) DO $(Invalid.Ch  !aREPLY := ER.Invalid.PR // Set reply code BREAK // Exit with error set $)Invalid.Ch AppendCh(UID,C) // Append the character to UID C := GetaCH(PB) // Get next $) // Come here on termination of protection field RESULTIS C $) // ======= // FnValid // ======= // Returns TRUE if C is valid for a filename AND FnValid(C)=ALPHA(C) \/ NUM(C) \/ C=':' \/ C='_' // ===== // ALPHA // ===== // Returns T RUE if C is Alpha AND ALPHA(C)='A'<=C<='Z' // === // NUM // === // Returns TRUE if C is numeric. AND NUM(C)='0'<=C<='9' // ============ // C.ReadString // ============ // Reads a BCPL string into S, while the characters // are valid according to the function VAL. Characters above MAXLEN are // thrown out. PB is a parameter block defining the reading function. // Returns the terminating character as a result. AND C.ReadString(PB,S,VAL,MAXLEN)=VALOF $( LET LEN,GetaCh = 0, PB!GTC.FUN LET P=GETBYTE(S,0) // Pointer LET CH = GetaCh(PB) // Get first character WHILE VAL(CH) DO  // If valid .. $( LEN := LEN + 1 // Bump length UNLESS LEN>MAXLEN DO // Unless skipping.. $( P := P+1 // Bump pointer PUTBYTE(S,P,CH) // Stuff it. $)  CH := GetaCh(PB) // Get next character $) PUTBYTE(S,0,P) // String Length RESULTIS CH $) // ======== // AppendCh // ======== // Appends character CH to string S AND AppendCh(S,CH) BE $( LET L=GETBYTE(S,0) +1 // Current string length PUTBYTE(S,L,CH) // Stuff character PUTBYTE(S,0,L)  // .. and new length $) n of protection field RESULTIS C $) // ======= // FnValid // ======= // Returns TRUE if C is valid for a filename AND FnValid(C)=ALPHA(C) \/ NUM(C) \/ C=':' \/ C='_' // ===== // ALPHA // ===== // Returns T// ======== // CSI4.BPL // ======== // C A R T O S S Y S T E M I N T E R F A C E // Module 4 // Supplementary File I-O Services GET "CSI.HDR" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" // ====== // C.POS0 Service // ====== // The C.POS0 Service allows the program to manipulate the CFI // of a file. The user specifies the logical unit connected to // the file and the new CFI value. LET C.POS0(aLUN,reqCFI1,reqCFI2,retaCFI,aREPLY)=VALOF $(Pos0 LET SCB, RES = ?, ? !aREPLY := VALOF $(Do.the.Position SCB := C.FindSCB(aLUN,aREPLY) // Try to find SCB IF SCB=0 RESULTIS !aREPLY // File not open. IF SCB!SCB.FTP = Device. RESULTIS ER.Pos.ILL SCB!SCB.CG1 := reqCFI1 // Set Hi CFI word SCB!(SCB.CG1+1) := reqCFI2 // .. and Lo CFI word SCB!SCB.ELT := '*N' // Stuff new ELT !retaCFI, retaCFI!1 := reqCFI1, reqCFI2 RESULTIS OK $)Do.the.Position RESULTIS !aREPLY $)Pos0 . GET "CSI.HDR" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" // ======== // C.RDPOS0 Service // ======== // The CFI value of a file can be obtained. The user specifies the // logical unit connected to the file and the service returns the // CFI value. LET C.RDPOS0(aLUN,retaCFI,aREPLY)=VALOF $(RdPos0 !aREPLY := VALOF $(Find.the.Position LET SCB = C.FindSCB(aLUN,aREPLY) IF SCB=0 RESULTIS !aREPLY IF SCB!SCB.FTP = Device. RESULTIS ER.Pos.ILL !retaCFI := SCB!SCB.CG1 retaCFI!1:= SCB!(SCB.CG1+1) RESULTIS OK $)Find.the.Position RESULTIS !aREPLY $)RdPos0 . GET "CSI.HDR" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" GET "/RON/CARTOS/BDFS/IOB.BDF" // ======= // C.WEOF0 Service // ======= // This service allows a  program to modify a file size explicitly. LET C.WEOF0(aLUN,aREPLY)=VALOF $(WEOF0 !aREPLY := VALOF $(Find.the.SCB  LET SCB=C.FindSCB(aLUN,aREPLY) IF SCB=0 RESULTIS !aREPLY RESULTIS SCB=0 -> !aREPLY, I..IO(!aLUN,0,SCB!SCB.CFI,(PO.<<4)+WEOF.+ER.) $)Find.the.SCB RESULTIS !aREPLY $)WEOF0 . GET "CSI.HDR" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" GET "/RON/CARTOS/BDFS/IOB.BDF" GET "/RON/CARTOS/BDFS/GFN.BDF" GET "/RON/CARTOS/BDFS/FIB.BDF" GET "/RON/CARTOS/BDFS/MDE:GFN.BDF" GET "/RON/CARTOS/BDFS/X:COMMON.BDF" // ======== // C.RENAM0 Service // ======== // This service can be used to remove one UID from the file system // and replace it with another. LET C.RENAM0(UID1,UID2,aREPLY)=VALOF $(Renam0  LET GFNB1 = VEC GFNB.SIZ // GFN block for UID1 LET GFNB2 = VEC GFNB.SIZ // GFN block for UID2 LET FIB2 = GFNB2 + GF.FIB // FIB2 GFNB1!GF.DUN, GFNB2!GF.DUN := 0, 0 // Clear DUNs !aREPLY := VALOF $(Do.the.Rename LET LUN = ? LET RES = C.UID2GFN(UID1,"",GFNB1) // Create GFN block for UID1  UNLESS RES=OK RESULTIS RES // .. check GFN status RES := C.UID2GFN(UID2,"",GFNB2) // Create GFN block for UID2 UNLESS RES=OK RESULTIS RES // .. check GFN status FIB2!FI.NAME := GFNB2!GF.NAME // Put filename in FIB FIB2!FI.PROT := GFNB2!GF.PROT=0 -> -1, // Protection or -1 GFNB2!GF.PROT // if no change. FIB2!FI.PASS := GFNB2!GF.PASS=0 -> -1, // Password or -1 GFNB2!GF.PASS // if no change. RES := C.Connect(GFNB1,0) // Connect to original file UNLESS RES=OK RESULTIS RES  // .. check connect status LUN := GFNB1!GF.LUN // Get the auto-allocated LUN RES := I..IO(LUN,?,?,FUREN.,FIB2) // Do the rename C.DiscLUN(LUN) // Disconnect the LUN RESULTIS RES $)Do.the.Rename C.FreeDUN(GFNB1) // Free any DUN1 C.FreeDUN(GFNB2)  // Free any DUN2 RESULTIS !aREPLY $)Renam0 . GET "CSI.HDR" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" GET "/RON/CARTOS/BDFS/IOB.BDF" GET "/RON/CARTOS/BDFS/X:COMMON.BDF" // ======== // C.RDFST0 Service // ======== // This service can be used to obtain information about the current // status of a file or device. LET C.RDFST0(UID,aLOPS,aFtype,aHCFI,aREPLY)=VALOF $(RdFST0 LET aLUN = VEC 1 // Temporary LUN LET R = ? !aLOPs, !aFtype := 0, 0 // Clear returns !aLUN := 0 // .. and the LUN UNLESS C.OPEN0(UID,OPRE.,aLUN,aREPLY)=OK RESULTIS !aREPLY !aREPLY := VALOF $(File.now.open LET Ftype = ? LET SCB = C.FindSCB(aLUN,aREPLY) // Lookup SCB LET CLASS = C.DeviceClass(!aLUN) // Get LUN attributes IF SCB=0 \/ CLASS=0 RESULTIS ER.KaPuTT // CSI System Error Ftype := SCB!SCB.FTP // Get the file type !aFtype := FType  // .. and store it TEST CLASS = CLASS.FM THEN $(Disk.Device UNLESS C.REOF0(aLUN,aHCFI,aREPLY)=OK RESU LTIS !aREPLY !aLOPs := SCB!SCB.PRT ! (Ftype=DirectoryFile. -> (TABLE ST.F0DD, ST.F1DD, ST.F2DD, ST.F3DD,  ST.F4DD, ST.FFDD, ST.FFDD, ST.FFDD, ST.FFDD, ST.FFDD, ST.FFDD, ST.FFDD, ST.FFDD, ST.FFDD, ST.FFDD, ST.FFDD), (TABLE ST.F0DF, ST.F1DF, ST.F2DF, ST.F3DF, ST.F4DF, ST.FFDF, ST.FFDF, ST.FFDF, ST.FFDF, ST.FFDF, ST.FFDF, ST.FFDF, ST.FFDF, ST.FFDF, ST.FFDF, ST.FFDF))  $)Disk.Device OR $(CharDevice !aLOPs := CLASS=CLASS.TV -> ST.FACD + ST.FWCD + ST.FRCD,  ST.FACD + ST.FWCD !aHCFI, aHCFI!1 := 0, 0 $)CharDevice RESULTIS OK $)File.now.open C.CLOSE0(aLUN,@R) // Close the open file RESULTIS !aREPLY $)RdFST0 . GET "CSI.HDR" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" GET "/RON/CARTOS/BDFS/IOB.BDF" // ======= // C.REOF0 Service // ======= // This service can be used to obtain the size of a file. LET C.REOF0(aLUN,aHCFI,aREPLY)=VALOF $(REOF0 !aREPLY := I..IO(!aLUN,0,aHCFI,(PO.<<4) + REOF. +ER.) RESULTIS !aREPLY $)REOF0 . GET "CSI.HDR" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" // ======== // C.CVUID0 Service // ======== // This service can be used to obtain the UID block associated with // a specified open logical unit. LET C.CVUID0(aLUN,retUID,aREPLY)=VALOF $(CvUID0 LET SCB = ? !aREPLY := VALOF $(Convert.the.UID LET UID = ?  SCB := C.FindSCB(aLUN,aREPLY) // Find the SCB IF SCB=0 RESULTIS !aREPLY // .. not found UID := SCB!SCB.UID // The UID copy address C.MOVBTS(UID,0,retUID,0,GETBYTE(UID,0)+1) // Copy it over.  RESULTIS OK // It went OK $)Convert.the.UID RESULTIS !aREPLY $)CvUID0 . GET "CSI.HDR" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" // ======== // C.OPUID0 Service // ======== // This service converts a UID block into an ASCII filename // stored in memory. LET C.OPUID0(BUF,ByteOffset,MaxLength,UID,aLastByte,aREPLY)=VALOF $(OPUID0 LET UIDLength = GETBYTE(UID,UID.LEN) - UID.Text + 1 LET TooBig = UIDLength > MaxLength // Is the UID too big LET XferBytes = TooBig -> MaxLength, UIDLength C.MOVBTS(UID,UID.Text,BUF,ByteOffset,XferBytes) !aLastByte := ByteOffset + XferBytes - 1 // Last byte offset !aREPLY := TooBig -> ER.UID.Too.Big, OK RESULTIS !aREPLY $)OPUID0 . GET "CSI.HDR" GET "CSI_INT.HDR" // ======== // C.WRUID0 Service // ======== // The specified UID is converted to an ASCII filename string // and is output to an open LUN LET C.WRUID0(aLUN,UID,aREPLY)=VALOF $(WRUID0 LET XferBytes=? C.WR0(aLUN,UID+UID.Text/BytesPerWord, GETBYTE(UID,UID.Len)-UID.Text+1,@XferBytes,aREPLY) RESULTIS !aREPLY $)WRUID0 pecified open logical unit. LET C.CVUID0(aLUN,retUID,aREPLY)=VALOF $(CvUID0 LET SCB = ? !aREPLY := VALOF $(Convert.the.UID LET UID = ? // ======== // CSI5.BPL // ======== // C A R T O S S Y S T E M I N T E R F A C E // Module 5 // This module contains the routines used to read and write data. // The following table shows the IO modifiers and Buffer existance // for each data mod  e. // +---------+-------------------------+----------------------------+ // |Data Mode| Character Devices | Disk Devices | // +---------+-------------------------+----------------------------+ // | UFM. | Unbuffered UF. out | Is ISO2ISO | // | | UF. in | | // +---------+-------------------------+----------------------------+ // | ISO2ISO.| Buffered FA. out | Unbuffered UF. out | // | |  FA. in | UF. in | // +---------+-------------------------+----------------------------+ // | ASC2ASC.| Buffered FA. out | Unbuffered UF. out | // | | FA. in | UF. in  | // +---------+-------------------------+----------------------------+ // | ASC2ISO.| Buffered UF. out | Buffered  UF. out | // | | FA. in | FA. in | // +---------+-------------------------+----------------------------+ // | ISO2ASC.| Buffered FA. out | Buffered FA. out | // | | FA. in | FA. in | // +---------+-------------------------+----------------------------+ GET "CSI.HDR" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" GET "/RON/CARTOS/BDFS/IOB.BDF" GET "/RON/CARTOS/BDFS/SYSCOMMON.BDF" GET "/RON/CARTOS/BDFS/B:EXTERNAL.BDF" GET "/RON/CARTOS/BDFS/GFN.BDF" GET "/RON/CARTOS/BDFS/FIB.BDF" GET "/RON/CARTOS/BDFS/MDE:GFN.BDF" // ===== // C.RD0 Service // ===== // The C.RD0 service can be used to transfer a specified number // of bytes from a file into memory, starting at a specified location. // The user supplies the address of the logical unit connected to the // file. LET C.RD0(aLUN,BUF,ReqBC,aRetBC,aREPLY)=VALOF $( LET IOB = VEC IO.SIZ // IOB LET SCB, RetBC = ?, 0 // SCB and Returned byte count LET Count=ReqBC // Characters to go LET PBUF, PLEN = C.WP, !C.WPL // Default prompt !aREPLY := VALOF $(Do.The.Read LET R=? // Return status LET CHB = ?  LET FLW = ? LET aCFI= ? // Address of CFI UNLESS C.INIT() RESULTIS ER.FSPX // Initialise SCB := C.FindSCB(aLUN,aREPLY) // Try to find it IF SCB=0 RESULTIS !aREPLY // .. not found. CHB := SCB!SCB.CHB // Any buffer FLW := SCB!SCB.FLW // The flagword aCFI:= SCB!SCB.CFI  // Any CFI IOB!IO.LUN := !alUN // Set up IOB IOB!IO.PER, IOB!IO.CFI := 0, aCFI // Prepare for buffered read. Change later if not. IOB!IO.FC := (RE.<<4) + FA. + ER. IOB!IO.BUF:= CHB // Buffer address IOB!IO.BCT:= CSIBufferSize // If there is a write buffer pending, use it as prompt. // The existance of a non zero buffer pointer implies the existance // of a buffer. IF (SCB!SCB.IOM = CWrite.) /\ // If last mode was Write  (SCB!SCB.CBP ~= 0) DO // .. and buffer not empty $(Switch.Mode PLEN := TreatWriteBuffer(SCB) PBUF := CHB // Set up the prompt buffer SCB!SCB.CC := 0 // Clear the write  buffer $)Switch.Mode SCB!SCB.IOM := CRead. TEST FLW >= Buffered. THEN WHILE Count>0 DO $(Get.From.Buffer LET Ch = ? // Character IF SCB!SCB.CC = 0 DO // Need new buffer  $(Fill.Buffer LET P=? // Temporary pointer IF FLW = CharDevB. DO  $(Output.any.Prompt I..IO(!aLUN,?,0,WRWP.,PLEN,PBUF)// .. but ignore errors $)Output.any.Prompt R := I.IO(IOB)=SKIP. -> OK, IOB!IO.ST UNLESS R=OK RESULTIS R // An Error occurred P := IOB!IO.ACT // Get actual count PUTBYTE(CHB,P,'*N') SCB!SCB.CC := P+1 // Stuff new count SCB!SCB.CBP:= 0 // Stuff new buffer pointer $)Fill.Buffer // Now get the buffered character Ch := GETBYTE(CHB,SCB!SCB.CBP)// Get next character from buffer PUTBYTE(BUF,RetBC,Ch) // Stuff it in user space SCB!SCB.CBP := SCB!SCB.CBP+1 // Bump buffer pointer SCB!SCB.CC := SCB!SCB.CC -1 // Decrement remaining count RetBC := RetBC + 1 // Bump user buffer pointer Count := Count - 1 // Decrement User count // If character device then break on line terminator IF (FLW=CharDevB.)/\IsTerminator(Ch) THEN BREAK $)Get.From.Buffer OR $(Get.Unbuffered IOB!IO.FC := (RE.<<4) + ER. + UF. IOB!IO.BCT:= ReqBC // Requested byte count IOB!IO.BUF:= BUF // User Buffer R := I.IO(IOB)=SKIP. -> OK, IOB!IO.ST RetBC := IOB!IO.ACT // Count transferred UNLESS R=OK RESULTIS R // An error occurred $)Get.Unbuffered RESULTIS OK // No errors $)Do.The.Read !aRetBC := RetBC  // Actual count transferred RESULTIS !aREPLY $) . GET "CSI.HDR" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" GET "/RON/CARTOS/BDFS/IOB.BDF" GET "/RON/CARTOS/BDFS/SYSCOMMON.BDF" GET "/RON/CARTOS/BDFS/B:EXTERNAL.BDF" // ===== // C.WR0 Service // ===== // The C.WR0 service is used to transfer a specified number of sequential // bytes from memory, starting at a specified location, to the file // connected to a specified logical unit. LET C.WR0(aLUN,BUF,ReqBC,aRETBC,aREPLY)=VALOF $( LET IOB = VEC IO.SIZ // Temporary write IOB LET SCB, RetBC = ?, 0 // SCB and Returned byte count LET COUNT = ReqBC // Characters to output !aREPLY := VALOF $(Do.The.Write LET R=?  // Temporary status LET CH, ELT = ?, ? LET CHB = ? LET DTP = ? LET aCFI= ? UNLESS C.INIT() RESULTIS ER.FSPX // Initialise SCB := C.FindSCB(aLUN,aREPLY) // Get the SCB IF SCB=0 RESULTIS !aREPLY  // LUN not found CHB := SCB!SCB.CHB // .. and any buffer DTP := SCB!SCB.DTP // Data type aCFI:= SCB!SCB.CFI // Any CFI IOB!IO.LUN := !aLUN // Set up IOB IOB!IO.PER, IOB!IO.CFI := 0, aCFI // Prepare for buffered write.. change later if not IOB!IO.FC := (WR.<<4) + ER. + (DTP=ASCII2  ISO. -> UF., FA.) IOB!IO.BUF:= CHB // Buffer address IF SCB!SCB.IOM = CRead. THEN // Clear read buffer $(Switch.Mode SCB!SCB.CBP := 0 // Zero pointer SCB!SCB.CC := 0  // .. and count SCB!SCB.ELT := 0 // No previous line terminator $)Switch.Mode  // Any unread characters are lost SCB!SCB.IOM := CWrite. // New IO Mode ELT := SCB!SCB.ELT  // end-of-line char. TEST SCB!SCB.FLW >= Buffered. THEN WHILE COUNT>0 DO $(Write.Char CH := GETBYTE(BUF,RetBC) // Get next character RetBC := RetBC + 1 // actual transfer count COUNT := COUNT - 1 // Bytes to go. $(Put.in.Buffer TEST IsTerminator(CH) THEN // Dump buffer  $(Write.Buffer IOB!IO.BCT := TreatWriteBuffer(SCB) R := I.IO(IOB)=SKIP. -> OK, IOB!IO.ST  UNLESS R=OK RESULTIS R // An error occurred SCB!SCB.CC := 0 // Clear count SCB!SCB.CBP:= 0 // .. and buffer pointer SCB!SCB.ELT:= CH // .. store terminator CH := 0 // Kill newline character $)Write.Buffer OR $(Char LET CC = SCB!SCB.CC // Current count PUTBYTE(CHB,SCB!SCB.CBP,CH) SCB!SCB.CBP := SCB!SCB.CBP + 1  SCB!SCB.CC := CC + 1 UNLESS CC < CSIBufferSize-3 DO CH := '*N' $)Char $)Put.In.Buffer REPEATWHILE CH='*N' // End of line? $)Write.Char OR $(Write.Unbuffered IOB!IO.FC := (WR.<<4) + ER. + UF. IOB!IO.BCT:= ReqBC // Requested byte count IOB!IO.BUF:= BUF  // User buffer address R := I.IO(IOB)=SKIP. -> OK, IOB!IO.ST RetBC := IOB!IO.ACT // Count transferred UNLESS R=OK RESULTIS R // An error occurred $)Write.Unbuffered RESULTIS OK  // No errors $)Do.The.write !aRetBC := RetBC // Actual count transferred RESULTIS !aREPLY $) . GET "CSI.HDR" GET "CSI_INT.HDR" // ================ // TreatWriteBuffer // ================ // Processes the write buffer for stream belonging to SCB. // Returns the character count as result. LET TreatWriteBuffer(SCB)=VALOF $( LET CHB = SCB!SCB.CHB // Character Buffer LET CC = SCB!SCB.CC // .. and count LET DataType= SCB!SCB.DTP // The data conversion type LET ELT = ? SWITCHON DataType INTO $(Treat.DTypes CASE ISO2ISO.: // Null CASE ASCII2ASCII.: // Null RESULTIS CC CASE ISO2ASCII.:  // Insert control chars. ELT := SCB!SCB.ELT // Previous line terminator C.MOVBTS(CHB,0,CHB,1,CC) // Shift buffer up one byte PUTBYTE(CHB,0,ELT='*C' -> '+', // .. fill in carriage control  ELT='*P' -> '1', ' ') CC := CC + 1 // Bump count ENDCASE CASE ASCII2ISO.:   // Remove control chars. $( LET CCH = GETBYTE(CHB,0) // .. control char. LET CH = CCH='1' -> '*P', // .. and replacement. CCH='+' -> '*C', '*N' PUTBYTE(CHB,0,CH) // Stuff it.  IF CCH='0' THEN // Require two form feeds $(Two.Form.Feeds C.MOVBTS(CHB,0,CHB,1,CC)  // Shuffle buffer up PUTBYTE(CHB,0,CH) // Stuff the second one CC := CC + 1 // Buffer now one byte longer $)Two.Form.Feeds IF (CH='*N') /\ (SCB!SCB.FLW=CharDevB.) DO $(Add.CRs.For.Character.Devices C.MOVBTS(CHB,0,CHB,1,CC) // Shuffle up the buffer again PUTBYTE(CHB,0,'*C') // Insert the CR CC := CC + 1 // One more to count $)Add.CRs.For.Character.Devices $) ENDCASE $)Treat.DTypes SCB!SCB.CC := CC // Replace new count RESULTIS CC $) . GET "CSI.HDR" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" GET "/RON/CARTOS/BDFS/USERCOMMON.BDF" GET "/RON/CARTOS/BDFS/SYSCOMMON.BDF" GET "/RON/CARTOS/BDFS/IOB.BDF" GET "/RON/CARTOS/BDFS/ISM.BDF" GET "/RON/CARTOS/BDFS/GFN.BDF" GET "/RON/CARTOS/BDFS/FIB.BDF" GET "/RON/CARTOS/BDFS/MDE:GFN.BDF" STATIC $( NoPrompt = TRUE // No initial Command prompt $) // ======== // C.RDCOM0 Service // ======== // The C.RDCOM0 service inputs a line of text from the command // file/device. Up to 256 bytes can be input. LET C.RDCOM0(BUF,aLEN,aREPLY)=VALOF $(Rdcom0 LET BUF1 = VEC 127 LET ISMB = VEC IS.SIZ  // The ISM Block LET P = 0 // Pointer into user buffer LET UC = #X5543  // LUN for "UC" FOR I=0 TO IS.SIZ DO ISMB!I := 0 // Clear ISM Block ISMB!IS.CKW, ISMB!IS.UB := CKW.IS, BUF1  UNLESS NoPrompt DO I..IO(UC,?,0,WRWP.,!C.WPCL,C.WPC) NoPrompt := FALSE // Prompt next time for sure! C.RCI(ISMB) // Do the RCI FOR I=ISMB!IS.BP TO 255 DO // Copy and search buffer for end  $(Copy.Buffer LET Ch = GETBYTE(BUF1,I) // Get next character IF Ch=0 THEN BREAK // .. reached buffer end PUTBYTE(BUF,P,Ch) // Store character in user buffer P := P+1  // .. and increment pointer $)Copy.Buffer PUTBYTE(BUF,P,'*N') // Stuff in terminator !aLEN := P+1 // Give length to user !aREPLY := OK RESULTIS !aREPLY $)Rdcom0 . GET "CSI.HDR" GET "CSI_INT.HDR" GET "/RON/CARTOS/BDFS/IOB.BDF" GET "/RON/CARTOS/BDFS/SYSCOMMON.BDF" GET "/RON/CARTOS/BDFS/GFN.BDF" GET "/RON/CARTOS/BDFS/FIB.BDF" GET "/RON/CARTOS/BDFS/MDE:GFN.BDF" // ======== // C.WRLOG0 Service // ======== // This service outputs text of a specified length to the log // file/device. The text can contain any number of lines. // All lines input by C.RDCOM0 are automatically logged on the // log device. LET C.WRLOG0(BUF,LEN,aREPLY)=VALOF $(Wrlog0 LET rLEN=? LET UL, UC = #X554C, #X5543 // Write to log, but ignore errors. (UL may not be there) C.WR0(@UL,BUF,LEN,@rLEN,aREPLY) UNLESS SameLUN(UL,UC) DO C.WR0(@U  C,BUF,LEN,@rLEN,aREPLY) RESULTIS !aREPLY $)Wrlog0 AND SameLUN(LUN1,LUN2)=I..IO(LUN1,0,0,COMP.,0,LUN2)=SKIP. . GET "CSI_INT.HDR" // ============ // IsTerminator // ============ // Returns TRUE if CH is a text line terminator. LET IsTerminator(CH)= CH='*N' \/ CH='*P' \/ CH='*C' // ======== // C.MOVBTS // ======== // Moves a sequence of bytes from address SOURCE, byte index SINDX // to address DEST, byte index DINDX for LEN bytes. // The process is performed from Hi to Lo memory to avoid corrupting // overlapping data. This is necessary for the TreatWriteBuffer use // of this routine. AND C.MOVBTS(SOURCE,SINDX,DEST,DINDX,LEN) BE FOR I=LEN-1 TO 0 BY -1 DO PUTBYTE(DEST,I+DINDX,GETBYTE(SOURCE,I+SINDX)) // Stuff in terminator !aLEN := // ======== // CSI6.BPL // ======== // C A R T O S S Y S T E M I N T E R F A C E // Module 6 GET "CSI.HDR" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" GET "/RON/CARTOS/BDFS/IOB.BDF" GET "/RON/CARTOS/BDFS/GFN.BDF" GET "/RON/CARTOS/BDFS/FIB.BDF" GET "/RON/CARTOS/BDFS/LAB.BDF" GET "/RON/CARTOS/BDFS/MDE:GFN.BDF" GET "/RON/CARTOS/BDFS/X:COMMON.BDF" GET "/RON/CARTOS/BDFS/B:EXTERNAL.BDF" // ====== // C.INIT // ====== // Performs CSI Initialisation. // If the CSI has previously been initialised then the SCB Chain // Head C.SCBCH, will be non-zero. // Returns TRUE if the initialisation was successful, FALSE otherwise. LET C.INIT()= !C.SCBCH~=0 -> TRUE, VALOF $( LET RES=? LET R=? LET UCUID=TABLE #X0502, #X0000, #X5543 // UID for 'UC' LET ULUID=TABLE #X0502, #X0000, #X554C // UID for 'UL' LET CIUID=TABLE #X0502, #X0000, #X4349 // UID for 'CI' LET UL, UC, CI = #X554C, #X5543, #X4349 // LUNs LET SCB = C.GetSCB("",@R) // Create SCB chain LET LAB = VEC LA.SIZ  // LUN attribute block IF SCB=0 RESULTIS FALSE // Error UNLESS C.OPEN0(UCUID,DontOpen.,@UC,@R)=OK RESULTIS FALSE UNLESS C.OPEN0(CIUID,DontOpen.,@CI,@R)=OK RESULTIS FALSE // UL may or may not be present in system. LAB!LA.LUN := UL // Set LUN to UL IF C.GLA(LAB) DO // UL exists $(UL.Exists  UNLESS C.OPEN0(ULUID,DontOpen.,@UL,@R)=OK RESULTIS FALSE $)UL.Exists RESULTIS TRUE $) // ======= // C.EXIT0 Service // ======= // Causes the operating system to terminate the calling task. // All resources associated with the task are released: open // files are closed and allocated memory is released. AND C.EXIT0(reqTermCode)=VALOF $(Exit0 C.CloseAllStreams() // Close all open streams C.END(reqTermCode) // Do the end $)Exit0 // ======= // C.OPEN0 Service // ======= // The C.OPEN0 service establishes an association between a UID and // a logical unit. If the logical unit is specified as the address // of a doubleword in which the first byte is zero, then an unused // logical unit is opened for this UID. AND C.OPEN0(UID,P2,P3,P4,P5)=VALOF $( LET OpenMode, aLUN = P2, P3 // Probably these LET DataType, aREPLY = P4, P5 // .. and these LET RES = ? // Result LET IsDisk = ?  // TRUE if Disk or File LET SCB = 0 // Stream Control Block LET LUN = ?   // Current LUN LET GFNB = VEC GFNB.SIZ // Extended GFN Block LET PROT = ?  // Protection LET N = 0 // Says open by file name LET REPLY=VALOF  $(Perform.OPEN // Open and return CSI reply LET UL=? // If Open Mode was omitted from parameter list then we wish to // default an Open Mode and switch remaining parameters. IF (OpenMode>#X40) \/ (OpenMode<0) DO// OpenMode is an address $(Switch1 aReply := DataType DataType:= aLUN aLUN := OpenMode // .. switch parameters OpenMode:= OPRW. // .. default is read-write. $)Switch1 // If Data Type was omitted from parameter list then we wish // to default a Data Type and switch aREPLY. TEST (DataType>#X40) \/ (DataType<0) DO $(Switch2 aREPLY := DataType // .. in fact reply address  DataType := DefaultDataType // .. and default this $)Switch2 OR UNLESS UFM. <= Datatype <= ASCII2ISO. DO RESULTIS ER.ILL.DATA.MODE UNLESS C.INIT() DO RESULTIS ER.FSPX // Initialise SCB := C.GetSCB("",aREPLY) // Attempt to get us an SCB IF SCB=0 THEN RESULTIS !aREPLY // .. but failed, return error. // Check if Open by F-number requested. This code will not work unless // UID.TEXT is a multiple of BytesPerWord. TEST UID!(UID.TEXT>>1) = "x##"!1 DO // Open by F-number $(Open.By.What.Fnumber FOR I=1 TO 2 DO $(Get.Fnumber  N := (N<<4) + ASCII.TO.INTEGER(UID!((UID.TEXT>>1)+I)) $)Get.Fnumber C.UID2GFN(UID,aLUN,GFNB)  // Get UID into GFN block $)Open.By.What.Fnumber OR $(Open.by.Name RES := C.UID2GFN(UID,aLUN,GFNB) // Get UID into GFN block UNLESS RES=OK RESULTIS RES // Return Error $)Open.By.Name TEST OpenMode=DontOpen. DO LUN:=!aLUN// Just use LUN provided OR $(Connect.and.Open.it RES := C.Connect(GFNB,N)  // Connect to file UNLESS RES = OK RESULTIS RES // .. Error occurred LUN := GFNB!GF.LUN  // Get the LUN provided.. !aLUN := LUN // .. and return it to user. RES := C.OpenLUN(LUN,OPFIL.+OPRAN.+OpenMode) UNLESS RES=OK RESULTIS RES $)Connect.and.Open.it SCB!SCB.OMD := OpenMode  // Save the mode of open SCB!SCB.LUN := LUN // Store LUN in SCB I..IO(LUN,0,0,FU.V+RIB.+ER.,GFNB+GF.FIB) // Read the FIB IsDisk := GFNB!(GF.FIB+FI.CLAS)=CLASS.FM // Now fill remainder of SCB and Return  SCB!SCB.FTP := IsDisk -> GFNB!(GF.FIB+FI.TYPE) = FIV.DIR -> DirectoryFile., DataFile., Device. PROT := GFNB!(GF.FIB+FI.PROT) // Save protection code SCB!SCB.PRT := (PROT >> (GFNB!(GF.FIB+FI.TITL)<<2)) & #XF  SCB!SCB.FLW := VALOF // Set flagword $( SWITCHON DataType INTO // Deal with Data Type  $(What.Data.Type CASE DefaultDataType: // Set default here DataType := IsDisk -> ISO2ISO.,/ / No control chars. ISO2ASCII. CASE ISO2ISO.: CASE ASCII2ASCII.:  // Null operations RESULTIS IsDisk -> DiskUB., CharDevB. CASE UFM.: // Unformatted TEST IsDisk THEN $( DataType := ISO2ISO. // Change Data type RESULTIS DiskUB. $) OR RESULTIS CharDevUB. // Can't buffer unformatted CASE ISO2ASCII.:  CASE ASCII2ISO.: // Buffered operations RESULTIS IsDISK -> DiskB., CharDevB. $)What.Data.Type $) IF IsDisk DO SCB!SCB.CFI := SCB+SCB.CG1 // Plug Disk CFI pointer // Deal with any Buffer area IF SCB!SCB.FLW >= Buffered. DO // If req'd $(Get.Buffer UNLESS C.GTMEM0(CSIBufferSize/2+1,SCB+SCB.CHB,aREPLY)=OK DO RESULTIS !aREPLY $)Get.Buffer // Copy of UID UL := GETBYTE(UID,UID.LEN)/BytesPerWord + 1 UNLESS C.GTMEM0(UL,SCB+SCB.UID,aREPLY) = OK DO RESULTIS !aREPLY FOR I=0 TO UL DO (SCB!SCB.UID)!I := UID!I SCB!SCB.DTP := DataType // Stuff DataType RESULTIS OK $)Perform.OPEN // Deal with any Error Conditions !aREPLY := REPLY // Store CSI reply UNLESS REPLY >= OK DO CloseSCB(SCB) // Finish off C.FreeDUN(GFNB) // Free the directory unit RESULTIS REPLY $) // ======== // C.CLOSE0 // ======== // The C.CLOSE0 service can be used to dissolve the connection between // a file and a logical unit. After a call to C.CLOSE0 the logical unit // is no longer open and may be connected to another file. AND C.CLOSE0(aLUN,aREPLY)=VALOF $( C.FreeSCB(aLUN,aREPLY) RESULTIS !aREPLY $) // ======== // C.GetSCB // ======== // Returns the address of the SCB for the logical unit // contained in !aLUN. If the first byte of !aLUN is zero // then returns the first available SCB. // If no SCB is found for !aLUN then zero is returned. // !aREPLY is set to the CSI reply code. AND C.GetSCB(aLUN,aReply)=VALOF $( LET AnyFreeSCB = GETBYTE(aLUN,0)=0 LET SCB = ? // Current SCB C.LOCK()  // Lock out stream table SCB := C.FindSCB(aLUN,aREPLY) // Try to find LUN IF (SCB=0) /\ AnyFreeSCB DO  // Create a new SCB.. $(Create.New.SCB TEST C.GTMEM0(SCB.SIZ,@SCB,aREPLY)=OK DO $( SCB!SCB.CHN := !C.SCBCH // Insert new SCB in chain !C.SCBCH := SCB // Stuff new chain head $) OR SCB := 0 // No got SCB $)Create.New.SCB IF AnyFreeSCB DO UNLESS SCB=0 THEN // Implies new SCB so.. $(Initialise.SCB FOR I=SCB.LUN TO SCB.SIZ-1 DO SCB!I := 0 // Clear it SCB!SCB.FLW := Used.  // Flag as used SCB!SCB.USR := C.USER() // Mark for this task only $)Initialise.SCB C.UNLOCK() // Free Stream table RESULTIS SCB $) // ========= // C.FreeSCB // ========= // Frees the SCB for !aLUN // !aREPLY is set to the CSI reply code. AND C.FreeSCB(aLUN,aREPLY) BE $( LET SCB=? C.LOCK() SCB :=  C.FindSCB(aLUN,aREPLY) // Try to find SCB for LUN CloseSCB(SCB) // close it C.UNLOCK() // Free Stream Table $) // ========= // C.FindSCB // ========= // Finds an SCB in the stream table chain. // If the first byte of !aLUN is non-zero then the SCB returned is // for the logical unit at aLUN. Otherwise the first free SCB found // is returned. // If no SCB can be returned then the result is zero. // !aREPLY is set to the CSI reply code. ER.LUN.Not.Found is the // only possible error and will be returned only if a LUN is // specified. AND C.FindSCB(aLUN,aREPLY)=VALOF $( LET SCB=!C.SCBCH LET LUN = !aLUN LET AnyFreeSCB = GETBYTE(aLUN,0)=0 // Return with any free SCB WHILE SCB~=0 DO // Until table end $(Scan.Stream.Table TEST SCB!SCB.FLW=Unused. THEN // A free entry found IF AnyFreeSCB BREAK // .. if thats all thata req'd OR IF (SCB!SCB.LUN=LUN) /\  // Is it a match for the LUN (SCB!SCB.USR=C.USER()) BREAK // and for this user. SCB := SCB!SCB.CHN  // Get next SCB in Chain $)Scan.Stream.Table !aREPLY := SCB=0 -> ER.LUN.Not.Found, OK RESULTIS SCB $) // ================= // C.CloseAllStreams // ================= // Correctly terminates and closes all streams known to the // CSI file system. AND C.CloseAllStreams() BE $(Close.All LET SCB=!C.SCBCH // Point to start of chain C.LOCK() // Exclude all other access WHILE SCB~=0 DO $(Release.Stream  LET R = ? LET NextSCB = SCB!SCB.CHN // Next in chain UNLESS SCB!SCB.FLW=Unused. DO CloseSCB(SCB) C.FRMEM0(SCB,@R) // Free memory, ignore errors SCB := NextSCB // Point to next in chain. $)Release.Stream !C.SCBCH := 0 // Free SCB Chain for REENTER C.UNLOCK() $)Close.All // ======== // CloseSCB // ======== // Closes an SCB. // The SCB may be complete or partial. Frees any Buffer and UID Space // allocated. Closes and Disconnects any LUN. // If the SCB has been used for buffered writes then any remaining // buffered characters are flushed. AND CloseSCB(SCB) BE UNLESS SCB=0 DO $( LET FLUN = SCB!SCB.LUN // Any LUN to Free LET FBUF = SCB!SCB.CHB // Any Buffer to free LET FUID = SCB!SCB.UID // Any UID copy to free LET DontClose = SCB!SCB.OMD = DontOpen. // If already open, no close. LET R=OK // Reply code // If the flagword specifies Used. only, then the open of FLUN // was never performed - so don't attempt to close it. UNLESS FLUN=0 DO $(Close.Dis.LUN UNLESS SCB!SCB.FLW = Used. DO $(Flush.and.Close FlushSCB(SCB)  // Flush SCB.. UNLESS DontClose DO C.ClosLUN(FLUN) $)Flush.and.Close UNLESS DontClose DO C.DiscLUN(FLUN) // .. and disconnect it $)Close.Dis.LUN UNLESS FUID=0 DO C.FRMEM0(FUID,@R) // Ignore errors UNLESS FBUF=0 DO C.FRMEM0(FBUF,@R) SCB!SCB.FLW := Unused. // SCB is now free $) // ======== // FlushSCB  // ======== // If a write buffer exists for SCB then it is flushed by // writing '*N' to the open LUN. AND FlushSCB(SCB) BE  $(Flush LET LUN = SCB!SCB.LUN // The O P E N LUN LET TERMINATOR = '*N'<<8 // Terminating Character LET RBC, R = ?, ? IF SCB!SCB.IOM=CWrite. THEN UNLESS SCB!SCB.CC=0 DO C.WR0(@LUN, @TERMINATOR, 1, @RBC, @R) $)Flush // ====== // C.LOCK // ====== // Mutually excludes access to Stream Table until a C.UNLOCK // is performed by the same task. AND C.LOCK() BE R.WAIT.ON.SEMAPHORE(!C.SSEMA4) // ======== // C.UNLOCK // ======== // De-Mutually excludes access to stream table. AND C.UNLOCK() BE R.SIGNAL.SEMAPHORE(!C.SSEMA4) . GET "CSI.HDR" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" GET "/RON/CARTOS/BDFS/IOB.BDF" GET "/RON/CARTOS/BDFS/GFN.BDF" GET "/RON/CARTOS/BDFS/FIB.BDF" GET "/RON/CARTOS/BDFS/MDE:GFN.BDF" GET "/RON/CARTOS/BDFS/X:COMMON.BDF" GET "/RON/CARTOS/BDFS/B:EXTERNAL.BDF" // ======== // C.CREAT0 Service // ======== // The C.CREAT0 Service defines the UID of a file in the CSI file // system. In requesting the service, the programmer identifies the // UID block and indicates whether the file is a directory file or // a data file. LET C.CREAT0(UID,ReqFType,aREPLY)=VALOF  $(Creat0 LET RES = ? // Temporary result LET GFNB= VEC GFNB.SIZ // Enlarged GFN block LET REPLY = VALOF $(Perform.Create LET LUN = 0 RES := C.UID2GFN(UID,@LUN,GFNB) // Convert UID UNLESS RES=OK RESULTIS RES // .. and check reply IF GFNB!GF.NAME=0 RESULTIS OK // Null file.  TEST (GFNB!GF.ST&GFF.DIR)=0 THEN // Not directory specified $(Data.File.Specified UNLESS ReqFType=DataFile. RESULTIS ER.Ill.File.Ftype GFNB!(GF.FIB+FI.TYPE) := FIV.BS // Byte stream $)Data.File.Specified  OR $(Directory.Specified UNLESS ReqFType=DirectoryFile. RESULTIS ER.Ill.File.Ftype GFNB!(GF.FIB+FI.TYPE) := FIV.DIR // Unconditionally directory. // Remember FI.REC was zeroed  // at initialisation time. $)Directory.Specified GFNB!(GF.FIB+FI.IEXT):= !C.EXTSIZ // Default initial extent size GFNB!(GF.FIB+FI.SEXT):= !C.EXTSIZ // Default sec. extent size GFNB!(GF.FIB+FI.FLG) := FIF.CR // Says create and connect RES := C.CONN2LUN(GFNB,0) // Do it. Must not be there.  LUN := GFNB!GF.LUN // May or may not be present UNLESS LUN=0 DO C.DiscLUN(LUN) // Disconnect it if there. C.FreeDUN(GFNB) // Free the directory unit RESULTIS RES // Return result of create $)Perform.Create !aREPLY := REPLY RESULTIS REPLY $)Creat0 . GET "CSI.HDR" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" GET "/RON/CARTOS/BDFS/IOB.BDF" GET "/RON/CARTOS/BDFS/GFN.BDF" GET "/RON/CARTOS/BDFS/FIB.BDF" GET "/RON/CARTOS/BDFS/MDE:GFN.BDF" GET "/RON/CARTOS/BDFS/X:COMMON.BDF" GET "/RON/CARTOS/BDFS/B:EXTERNAL.BDF" // ====== // C.DEL0 Service // ====== // This Service can be used to delete a specified UID from the CSI // file system. LET C.DEL0(UID,aREPLY)=VALOF   $(Del0 LET RES = ? // Temporary result LET GFNB = VEC GFNB.SIZ // Enlarged GFN block LET REPLY= VALOF $(Perform.Delete LET DUN, FIB, CLASS =?, ?, ? LET LUN = 0  // Says auto allocate RES := C.UID2GFN(UID,@LUN,GFNB) // Convert UID UNLESS RES=OK RESULTIS RES // .. and check errors. DUN, FIB := GFNB!GF.DUN, GFNB+GF.FIB // Get GFNB info. CLASS := C.DeviceClass(DUN=0->UF,DUN)// The device class FIB!FI.NAME := GFNB!GF.NAME // Slot the name in the FIB FIB!FI.PASS := GFNB!GF.PASS  // .. and any password RESULTIS GFNB!GF.NAME=0 \/ CLASS ~= CLASS.FM -> ER.Bad.File.ID,  I..IO(?,?,?,FUDEL.,FIB,DUN) $)Perform.Delete C.FreeDUN(GFNB) // Free the directory unit !aREPLY := REPLY RESULTIS REPLY $)Del0 // Free the directory unit RESULTIS RES // // ======== // CSI7.BPL // ======== // C A R T O S S Y S T E M I N T E R F A C E // Module 7 // The CSI services described in this section can be used for: // * Allocating and deallocating a block of memory. // * Loading Object Code. // * Chaining to furthur programs // * Obtaining the current date and time. GET "CSI.HDR" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" GET "/RON/CARTOS/BDFS/B:EXTERNAL.BDF" // ======== // C.GTMEM0 Service // ======== // Allocates a block of contiguous memory locations. // Uses R:ABUF. LET C.GTMEM0(WORDS,aBLOCK,aREPLY)=VALOF $( R.ALLOCATE.EMP.BUFFER(WORDS,aBLOCK) // Attempt to get buffer  !aREPLY := !aBLOCK=0-> ER.FSPX,OK // Set reply code RESULTIS !aREPLY $) . GET "CSI.HDR" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" GET "/RON/CARTOS/BDFS/B:EXTERNAL.BDF" // ======== // C.FRMEM0 Service // ======== // Returns memory block previously allocated by C.GTMEM0. // Uses R:RBUF. Errors will be trapped by system exception. LET C.FRMEM0(BLOCK,aREPLY)=VALOF $( R.RETURN.EMP.BUFFER(BLOCK) // Return the block !aREPLY := OK // OK if we get here RESULTIS OK $) . GET "CSI.HDR" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" GET "/RON/CARTOS/BDFS/LDB.BDF" GET "/RON/CARTOS/BDFS/USERCOMMON.BDF" GET "/RON/CARTOS/BDFS/SYSCOMMON.BDF" GET "/RON/CARTOS/BDFS/B:EXTERNAL.BDF" // ======= // C.LOAD0 Service // ======= // The C.LOAD0 Service causes object code to be read from a file // and stored in memory at a specified location. The user specifies // the logical connected to the file to be read. LET C.LOAD0(aLUN,LoadBase,Limit,retaEntry,retaHigh,aREPLY)=VALOF $(Load0 LET LDB = VEC LD.SIZ // Load LDB LET RES = ? LDB!LD.LUN, LDB!LD.BUF := !aLUN, !LoadBase // Set up base LDB!LD.OFF, LDB!LD.HLL := 0, Limit LDB!LD.LLL := retaENTRY LDB!LD.STP := 0 LDB!LD.CKW := CKW.LD  // Checkword RES := I.OBJECT.LOAD(LDB)=SKIP. ->OK, LDB!LD.ST !RetaENTRY := LDB!LD.XAD  // Get returned entry !RetaHIGH := LDB!LD.HAD // and highest address RESULTIS RES $)Load0 . GET "CSI.HDR" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" GET "/RON/CARTOS/BDFS/SYSCOMMON.BDF" GET "/RON/CARTOS/BDFS/B:EXTERNAL.BDF" // == ====== // C.CHAIN0 Service // ======== // The C.CHAIN0 Service causes object code to be read from a file // and loaded into memory, replacing the calling program. // Control passes to the primary entry point of the memory image // produced by the loading process. // Note that a command line can also be passed. LET C.CHAIN0(UID,aREPLY) BE $(Chain0 // Get UID length (ignore length bytes) UID!1 := GETBYTE(UID,UID.LEN)-UID.TEXT+1 C.CloseAllStreams() // Close all CSI open streams C.CMD(UID+1) // Do an E:CMD of the buffer !aREPLY := ER.CHAIN.Fail // Don't come here please. $)Chain0 // There will be no return . GET "CSI.HDR" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" GET "/RON/CARTOS/BDFS/B:EXTERNAL.BDF" // ======== // C.DTTIM0 Service // ======== // Returns six binary integers specifying the current year, // month, day, hour, minute, second. LET C.DTTIM0(TIME.BLOCK,aREPLY)=VALOF $( LET TEMP.BLOCK=VEC 6 C.GATD(TEMP.BLOCK)  // Get TOD in ASCII FOR I=0 TO 5 DO TIME.BLOCK!I := ASCII.TO.INTEGER(TEMP.BLOCK!I) !aREPLY := OK RESULTIS OK $) . GET "CSI_INT.HDR" LET ASCII.TO.INTEGER(A)=((A>>8)-'0')*10+((Aÿ)-'0') taENTRY := LDB!LD.XAD // ======== // CSI8.BPL // ======== // C A R T O S S Y S T E M I N T E R F A C E // Module 8 - System Interface Code.  GET "/RON/CARTOS/BDFS/USERCOMMON.BDF" GET "/RON/CARTOS/BDFS/SYSCOMMON.BDF" GET "/RON/CARTOS/BDFS/B:EXTERNAL.BDF" GET "/RON/CARTOS/BDFS/IOB.BDF" GET "/RON/CARTOS/BDFS/ISM.BDF" GET "/RON/CARTOS/BDFS/GFN.BDF" GET "/RON/CARTOS/BDFS/DIB.BDF" GET "/RON/CARTOS/BDFS/FIB.BDF" GET "/RON/CARTOS/BDFS/X:COMMON.BDF" GET "/RON/CARTOS/BDFS/LAB.BDF" GET "/RON/CARTOS/BDFS/MDE:GFN.BDF" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" MANIFEST $( UF=#X5546 $) // ========= // C.LUN2LUN // ========= // Performs a LUN to LUN connection, connecting LUN1 to LUN2. // Returns TRUE if Success, FALSE otherwise. LET C.LUN2LUN(LUN1,LUN2)=I..IO(LUN2,0,0,COCON.,0,LUN1)=SKIP. //@ // ========= // C.UID2GFN // ========= // Gets a filename from UID by use of the I:GFN service. Returns the // status of the I:GFN call as a result. // The LUN specified at !aLUN is placed in the enlarged GFN block // at GFNB!GF.LUN. If the first byte of the specified LUN is zero // then the LUN stored is zero. AND C.UID2GFN(UID,aLUN,GFNB)=VALOF $(GFN LET RES=? // Will hold the result // First Initialise Extended GFN block // Initially all zeroes // GFN Parameter Block FOR I=0 TO GFNB.SIZ DO GFNB!I := 0 GFNB!GF.NAME:=GFNB+GF.FBUF // Set up the file name address GFNB!GF.PASS:=GFNB+GF.PBUF // Set up the password address GFNB!GF.CKW:=CKW.GF // Put in Checkword // ISM Parameter Block GFNB!(GF.ISM+IS.UB) := UID // Set ISM buffer GFNB!(GF.ISM+IS.BP) := UID.TEXT // .. and pointer GFNB!(GF.ISM+IS.BC) := GETBYTE(UID,UID.LEN) + 1 GFNB!(GF.ISM+IS.CKW):= CKW.IS // Set ISM Checkword // FIB Initialisation GFNB!(GF.FIB+FI.CKW) := CKW.FI // Store LUN (if any) UNLESS (GETBYTE(aLUN,0)=0) DO GFNB!GF.LUN := !aLUN I.GET.FILE.NAME(GFNB) // Get the file name // Process GFN result. RES:=GFNB!GF.ST // Get the result of the GFN IF (RES & (GFF.FN+GFF.DIR)) = 0 D O // Set name to zero if no name GFNB!GF.NAME := 0 IF (RES&GFF.PWD)=0 DO GFNB!GF.PASS:=0 // Set password to zero if no password IF (RES&GFF.PC )=0 DO GFNB!GF.PROT:=0 // Set protection to zero if none IF RES OK, ER.Bad.File.ID $)GFN // ========= // C.FreeDUN // ========= // Frees the DUN from the GFN block GFNB if that // slot is not set to zero. Note that only auto-created LUNs are // freed. On exit the GF.DUN slot will be reset to zero. AND C.FreeDUN(GFNB) BE $(FREE.DUN LET DUN=GFNB!GF.DUN  UNLESS DUN>=0 DO C.DiscLUN(DUN) // Free the DUN from the GFN block GFNB!GF.DUN:=0 // And don't try it again! $)FREE.DUN //@ // // ===== // C.GLA // ===== // Gets the LUN attributes into a standard block. It will fill // in the checkword and return TRUE if the lun is legal, FALSE otherwise. // AND C.GLA(LAB)=VALOF $(C.GLA LET FIBDIB=VEC FI.SIZ  // FIB or DIB LET RES=? // Will hold the result FIBDIB!FI.CKW:=CKW.FI  // Fill in the checkword for the FIB LAB!LA.CKW:=CKW.LA // Fill in the checkword for the GLA block  RES:=I.GET.LUN.ATTRIBUTES(LAB)=0 // TRUE if success LAB!LA.CLASS:=RES->VALOF $(NEED.TO.READ.THE.FIB.OR.DIB  I..IO(LAB!LA.LUN,0,0,FURIB.,FIBDIB) // Read the FIB or DIB RESULTIS FIBDIB!FI.CLAS // The result is the class  $)NEED.TO.READ.THE.FIB.OR.DIB ,0 // or return zero RESULTIS RES // and return the result $)C.GLA // // ========= // C.DiscLUN // ========= // Disconnects the logical unit LUN. Returns status. // AND C.DiscLUN(LUN)=I..IO(LUN,0,0,DC.V+ER.,0,0) //@ // // ========= // C.OpenLUN // ========= // Opens the file/device connected to logical unit LUN, for // access in mode MODE. Returns the status of the open, or zero if // it was successful. // AND C.OpenLUN(LUN,MODE)=VALOF $(C.OpenLUN LET OPNIOB=VEC IO.SIZ LET CFI=VEC 1 OPNIOB!IO.LUN,OPNIOB!IO.PER,OPNIOB!IO.CFI,OPNIOB!IO.FC:=LUN,0,CFI,FUOP. OPNIOB!IO.FOP,OPNIOB!IO.ST,OPNIOB!IO.CKW:=MODE,0,CKW.IO IF I.IO(OPNIOB)=SKIP. RESULTIS 0 RESULTIS OPNIOB!IO.ST $)C.OpenLUN // ========= // C.ClosLUN // ========= // Close a file without disconnecting the logical unit // in question. Takes the actual LUN as a parameter AND C.ClosLUN(LUN)=VALOF $(C.ClosLUN LET CFI=VEC 1 RESULTIS I..IO(LUN,0,CFI,FU.V+CL.+ER.) $)C.ClosLUN // // LUN2GFN - Generates a directory unit in GFN block GFNB from the // logical unit LUN. The technique used is to create a new logical // unit C.LUN2LUN connected to LUN, store it in GF.DUN and store LUN // in GF.ILUN. Returns TRUE if successful, FALSE otherwise. // AND LUN2GFN(LUN,GFNB)=VALOF $(LUN2GFN LET CONIOB=VEC IO.SIZ  // The Connect IOB AND RES=? // Will be used for reply FOR I=0 TO IO.CKW-1 DO CONIOB!I:=0 // Set up the IOB CONIOB!IO.CKW,CONIOB!IO.FC:=CKW.IO,COCON. // Checkword and function code CONIOB!IO.DUN:=LUN  // LUN to connect to IF I.IO(CONIOB)=NOSKIP. RESULTIS FALSE // Exit if error GFNB!GF.DUN,GFNB!GF.ILUN:=CONIOB!IO.LUN, LUN // Return the req'd info RESULTIS TRUE $)LUN2GFN // // I..IO - Does an I:IO operation with the parameters specified, // returning zero if successful, or the bad status if errors. // An abnormal return is deemed unsuccessful. // AND I..IO(LUN,PER,CFI,FC,BCT,BUF,ACT,STS,SID,CKW)=VALOF $(I..IO PER,SID,CKW:=0,0,CKW.IO IF I.IO(@LUN)=SKIP. RESULTIS 0 RESULTIS STS $)I..IO //@ // // ========== // C.CONN2LUN // ========== // Connects the logical unit LUN using the information stored in // the enlarged GFN block GFNB. If LUN is zero then a new unique // one will be created when the connection is made. The logical // unit will be returned in slot GF.LUN of the enlarged GFN block. // The result of this function is the status returned from the // connect. AND C.CONN2LUN(GFNB,LUN)=VALOF $(CONN2LUN LET CONIOB=VEC IO.SIZ // The Connect IOB AND RES=? // Will be used for reply AND DUN=GFNB!GF.DUN // Directory unit or 0 if UF LET FIB=GFNB+GF.FIB // The FIB address AND PASSWORD=GFNB!GF.PASS // The password to go in the FIB FOR I=0 TO IO.CKW-1 DO CONIOB!I:=0 // Set up the IOB CONIOB!IO.FC:=COCON. // Set up the function code in the IOB CONIOB!IO.CKW:=CKW.IO // Checkword CONIOB!IO.LUN:=LUN // LUN to connect  CONIOB!IO.DUN:=DUN=0->UF,DUN // The directory LUN CONIOB!IO.FIB:=GFNB!GF.NAME=0->0,VALOF // Zero if just a LUN  $(NAME.SPECIFIED IF !(GFNB!GF.NAME)=#X2E20 RESULTIS 0 // If ". " connect to DUN FIB!FI.NAME:=GFNB!GF.NAME // Put the File name in the FIB FIB!FI.PROT:=GFNB!GF.PROT // .. and any protection FIB!FI.PASS:=PASSWORD  // Sore the password or zero RESULTIS FIB // And return the FIB address $)NAME.SPECIFIED RES:=I.IO(CONIOB)=SKIP. // Do the connect? GFNB!GF.LUN:=CONIOB!IO.LUN // Place the LUN in the GFN block RESULTIS RES->0,CONIOB!IO.ST // And return the result $)CONN2LUN // // CONN - Connect the file/device as specified in the enlarged GFN // block GFNB. It is the same as C.CONN2LUN, except that the LUN must // be specified in the GF.LUN slot of the enlarged GFN block. AND CONN(GFNB)=C.CONN2LUN(GFNB,GFNB!GF.LUN) //@ // // ========= // C.Connect // ========= // Connects the file/device specified by the contents of the enlarged // GFN block, GFNB to a logical unit. If the logical unit specified // in GFNB is zero then the connection is made to a new unique logical // unit. // If N is zero the connect is a normal one. If N is non-zero then // a connect by F-number is assumed, the F-number being N. // Returns the connect status as a result. AND C.Connect(GFNB,N)=VALOF $(CONNECT LET RES=? // Will hold the result of the connect LET FIB=GFNB+GF.FIB // Points to the FIB FIB!FI.FLG := 0 // Clear FIB flag UNLESS N=0 DO  $(ITS.A.CONNECT.BY.F.NUMBER FIB!FI.FLG:=FIF.CFN // Says connect by F-Number GFNB!GF.NAME:=N // N replaces the name $)ITS.A.CONNECT.BY.F.NUMBER RESULTIS CONN(GFNB) // Connect to it (TEMPORARY) $)CONN ECT // // CLOSE.DIS - Closes and disconnects the logical unit LUN. No // result is returned. // AND CLOSE.DIS(LUN) BE $(CLOSE.DIS C.ClosLUN(LUN) // Close the LUN C.DiscLUN(LUN) // and disconnect it! $)CLOSE.DIS // ============= // C.DeviceClass // ============= // Returns the class of the device connected to LUN, // or zero if the LUN is illegal AND C.DeviceClass(LUN)=VALOF $(DEVICE.CLASS LET GLAVEC=VEC 12 GLAVEC!LA.LUN:=LUN RESULTIS C.GLA(GLAVEC)->GLAVEC!LA.CLASS,0 $)DEVICE.CLASS . GET "/RON/CARTOS/BDFS/USERCOMMON.BDF" GET "/RON/CARTOS/BDFS/SYSCOMMON.BDF" GET "/RON/CARTOS/BDFS/B:EXTERNAL.BDF" GET "/RON/CARTOS/BDFS/IOB.BDF" GET "/RON/CARTOS/BDFS/GFN.BDF" GET "/RON/CARTOS/BDFS/FIB.BDF" GET "/RON/CARTOS/BDFS/DIB.BDF" GET "/RON/CARTOS/BDFS/MDE:GFN.BDF" GET "/RON/CARTOS/BDFS/X:COMMON.BDF" GET "CSI_INT.HDR" GET "CSI_ERRORS.HDR" // READ.BLOCK - Reads logical sector N from the file opened on logical // unit LUN to address N. The actual count transferred (in bytes) is // returned at the address specified in ADRCOUNT. The result of the // function will be zero if success or the LUN status in cases of error. // LET READ.BLOCK(LUN,N,ADDR,ADRCOUNT)=VALOF $(READ.BLOCK LET CFI=VEC 1 LET RES,COUNT=?,?  LET IOVEC=VEC IO.SIZ !CFI,CFI!1:=0,N IOVEC!IO.LUN,IOVEC!IO.PER,IOVEC!IO.CFI:=LUN,0,CFI IOVEC!IO.FC,IOVEC!IO.BCT,IOVEC!IO.BUF:=REFA.,512,ADDR RES:=I.IO(IOVEC) // Do the I/O !ADRCOUNT:=IOVEC!IO.ACT RESULTIS RES=SKIP.->0,IOVEC!IO.ST $)READ.BLOCK // // WRITE.BLOCK - Writes out a block of length COUNT bytes from address // ADDR to logical sector N of the file opened on logical unit LUN. // If LUN is opened for sequential access the N may be a dummy one. // Returns TRUE if success, FALSE otherwise. // AND WRITE.BLOCK(LUN,N,ADDR,COUNT)=VALOF $(WRITE.BLOCK LET CFI=VEC 1 !CFI,CFI!1:=0,N RESULTIS I..IO(LUN,?,CFI,WRFA.,COUNT,ADDR)=0 $)WRITE.BLOCK // MOUNT.DEVICE - Performs a mount operation for the device // whose name is in DEVICE. The LUN mounted is LUN. If exclusive // is TRUE then it will be mounted for exclusive use. The parameters // VOLNAME, PASSWORD and SID are the volume name string, the password // string and the (file manager) special ID respectively. // The status of the mount operation is returned as the function // result. // AND MOUNT.DEVICE(DEVICE,LUN,EXCLUSIVE,VOLNAME,PASSWORD,SID)=VALOF $(MOUNT.DEVICE LET DIB=VEC DI.CKW LET RES=? FOR I=0 TO DI.CKW DO DIB!I:=0 // Zero the DIB vector  DIB!DI.NAME,DIB!(DI.NAME+1):=!DEVICE,DEVICE!1 // Put in device name DIB!DI.CKW:=CKW.DI // Set up the checkword DIB!DI.VOL:=VOLNAME // Put in the volume name DIB!DI.PASS:=PASSWORD // Put in the password DIB!DI.SID:=SID // Put in the file manager SID RES:=I..IO(LUN,0,0,MO.V+ER.+(EXCLUSIVE->EU.,SHR.),DIB) DEVICE!1:=DIB!(DI.NAME+1) // Return the device name mounted? RESULTIS RES // Return the Mount status $)MOUNT.DEVICE . GET "CSI_INT.HDR" GET "/RON/CARTOS/BDFS/B:EXTERNAL.BDF" // ====== // C.GATD // ====== // Gets the system time of day in ASCII form. The address // to store the information is in the 7-word vector TIME.BLOCK . LET C.GATD(TIME.BLOCK) BE   $(GATD LET TICKS=VEC 1 R.GET.SYSTEM.TOD(TICKS) // Get the date+time R.TOD.TO.ASCII(TIME.BLOCK,TICKS) // Convert to ASCII $)GATD // SATD - Sets the system time of day from its ASCII form. The address // to get the information is in the 7-word vector TIME.BLOCK . AND SATD(TIME.BLOCK) BE $(SATD LET TICKS=VEC 1 R.ASCII.TO.TOD(TIME.BLOCK,TICKS) // Convert to Ticks R.SET.SYSTEM.TOD(TICKS) // Set the date+time $)SATD le manager) special ID respectively. // The status of the mount operation is returned as the function // result. // AND MOUNT.DEVICE(DEVICE,LUN,EXCLUSIVE,VOLNAME,PASSWORD,SID)=VALOF $(MOUNT.DEVICE LET DIB=VEC DI.CKW LET RES=? FOR I=0 TO DI.CKW DO DIB!I:=0 // Zero the DIB vector IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII  IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII! IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII" IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII# IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIe820422181315820422181315820422181315e&L820422181315820422181315820423151557$ e 820422181315820422181315820422181315e820422181315820422181315820422181315820422181315820422181315820422181315e|8204230808452582042308084675820423151335e ;'8204230810355082042308103875820423151349e*]8203241224567582032412245875820423151400 e:% 78203241329097582032413291275820423151414 eV!A8204221515092582042215151250820423151429 ew 8203241353182582032415082975820423151439 e~08203231619590082032415081625820423151451 e8201251443182582012514431925820423151459eO8204231507020082042315070350820423151508e8n8204230820247582042308203325820423151527d& eQ 8204221547280082042215472950820423151537e\8201191011100082011910111100820423151545e_8112151103595081121511040050820423151554' ( ) . CSI0 ASMCSI3 BPLCSI4 BPL CSI5 BPL CSI6 BPL CSI7 BPL CSI8 BPL MACRO:EII ASMNEWCSI JCLEII LBRCSI_INT HDRCSI HDRCSI_ERRORS HDR TITL MACRO:EII.ASM - ASSEMBLER INTERFACE TO C A R T O S EII TITL ROUTINE MACRO ROUTINE XMACRO TITL #(-1) SHARABLE MAC:EII  ROMMABLE MAC:EII MAC:EII REL NAM C:#(-1)0 EXTR #(-1):0,RCALL: C:#(-1)0 EQU $ COPY =#(-1):0,A JSK RCALL: RSK ENDM SAVE END TITL ALL EII CALLS WR ROUTINE END RD ROUTINE OBJNOTE '*** MACRO:EII - REV A200 ***' END RENAM ROUTINE END IPUID ROUTINE END RDFST ROUTINE END DTTIM ROUTINE END EXIT ROUTINE END DEL ROUTINE END CREAT ROUTINE END POS ROUTINE END RDPOS ROUTIN* E END OPEN ROUTINE END CLOSE ROUTINE END REOF ROUTINE END WEOF ROUTINE END CHAIN ROUTINE END FRMEM ROUTINE END GTMEM ROUTINE END LOAD ROUTINE END RDUID ROUTINE END WRUID ROUTINE END CVUID ROUTINE END MAP ROUTINE END MGUID ROUTINE END SPUID ROUTINE END OPUID ROUTINE END RDCOM ROUTINE END WRLOG ROUTINE END UNMAP ROUTINE END TITL C:INIT MAC:EII REL SHARABLE MAC:EII ROMMABLE MAC:EII NAM C:INIT EXTR RCALL: EXTR B:INIT C:INIT EQU $ COPY =B:INIT,A JSK RCALL: RSK END TITL INTERFACE ROUTINE * * Enter with: * A = Address of B:xxxx routine to call * X = Address of Parameter block * K-L Stack set up (Minimum of KL:REQD Words) * MAXPARMS EQU 6 KL:REQD EQU 256 MAC:EII REL SHARABLE MAC:EII ROMMABLE MAC:EII NAM RCALL: RCALL: EQU $ COPY X,Q  * Save parameter block address COPY K,X * Get Top of K-L Stack SUB =KL:REQD,X * Reduce K-L Stack COPY Y,1(X) * Save old Y value COPY X,Y * This will be new Y stack COPY A,0(Y) * Save routine address COPY X,K * By minimum amount req'd for all routines COPY Y,X * all parameters across ADD =2,X * to Y-Stack COPY =MAXPARMS,A MOVE 0(Q),0(X),A * Do the move COPY 2(Y),A * First parameter must be in A COPY 3(Y),Q * ..and second in Q * * Call the EII service now * Note stack check is performed here by the JSK JSK *0(Y) * Call routine COPY Y,X * Get base of Y stack (new K) ADD =KL:REQD,X * Bump stack back up COPY X,K * Restore K-L Stack COPY 1(Y),Y * Restore old Y value RSK * Return, any result is in A END ROUTINE END RDPOS ROUTIN newcsi.jcl is released as 84-93530-2H (E860) ========== NEWCSI.JCL ========== COMPILES AND ASSEMBLES NEWEII.LBR MAIN SOURCE ASSUMED ON UF/ CARTOS MACRO AND BCPL DEFINITIONS FILES IN /RON/CARTOS/BDFS/ CREATES NEWEII.LBR AND NEWCSI.LST ON UF/  ============= MACRO:EII.JCL ============= Assemble MACRO:EII ROMmable interface for C A R T O S MACRO MACRO:EII(L=,P=57,D=SF/BCPLMACS,MACH=495) //CO MACRO:EII.LIB=MACRO:EII.OBJ DE MACRO:EII.OBJ ======== CSI0.JCL ======== Compile C A R T O S S Y S T E M I N T E R F A C E Module 0 AS LO=TV AS X1=/RON/CARTOS/BDFS/ MACRO CSI0(L=,P=62,MACH=495,D=SF/BCPLMACS.MAC) ======== CSI3.JCL ======== Compile C A R T O S S Y S T E M I N T E R F A C E Module 3 AS LO=TV BCPL CSI3.BSM,CSI3=CSI3%OGD2000L12000:Z0M490 MACRO CSI3.BSM(ERR) DE CSI3.BSM ======== CSI4.JCL ======== Compile C A R T O S S Y S T E M I N T E R F A C E Module 4 AS LO=TV BCPL CSI4.BSM,CSI4=CSI4%OD2000L14000:Z0M490 MACRO CSI4.BSM(ERR) DE CSI4.BSM ======== CSI5.JCL ======== Compile C A R T O S S Y S T E M I N T E R F A C E Module 5 AS LO=TV BCPL CSI5.BSM,CSI5=CSI5%OD3000L14000:Z0M490C DE CSI5.BSM ======== CSI6.JCL ======== Compile C A R T O S S Y S T E M I N T E R F A C E Module 6 AS LO=TV BCPL CSI6.BSM,CSI6=CSI6%OD2000L14000:WZ0M490 MACRO CSI6.BSM(ERR) DE CSI6.BSM ======== CSI7.JCL ======== Compile C A R T O S S Y S T E M I N T E R F A C E Module 7 AS LO=TV BCPL CSI7.BSM,CSI7=CSI7%OD3000L14000:Z0M490 MACRO CSI7.BSM(ERR) DE CSI7.BSM ======== CSI8.JCL ======== Compile C A R T O S S Y S T E M I N T E R F A C E Module 8 AS LO=TV BCPL CSI8.BSM,CSI8=CSI8%OL12000:Z0M490 MACRO CSI8.BSM(ER) DE CSI8.BSM ============ CSIMERGE.JCL ============ Merges all files for: Th+ e C A R T O S S Y S T E M I N T E R F A C E Assemble object //CO NEWEII.LBR=MACRO:EII.LIB+ CSI3.OBJ+ CSI4.OBJ+ CSI5.OBJ+ CSI6.OBJ+ CSI7.OBJ+ CSI8.OBJ+ CSI0.OBJ+ B:XXXX:ROM.LIB Assemble listings //COPY NEWCSI.LST=CSI3.LST+ CSI4.LST+ CSI5.LST+ CSI6.LST+ CSI7.LST+ CSI8.LST+ CSI0.LST+ MACRO:EII.LST //CO EII.LBR=NEWEII.LBR RO CSI0(L=,P=62,MACH=495,D=SF/BCPLMACS.MAC) ======== CSI3.JCL ======== Compile C A R T O S S Y S T E M I N T E R F A C E Module 3 AS LO=TV BCPL CSI3.BSM,CSI3=CSI3%OGD2000L12000:Z0M490 MACRO CSI3.BSM(ERR) DE CSI3.BSM ======== CSI4.JCL ======== Compile C A R T O S S Y S T E M I N T E R F A C E Module 4 AS LO=TV BCPL CSI4.BSM,CSI4=CSI4%OD2000L14000:Z0M490 MACRO CSI4.BSM(ERR) DE CSI4.BSM ======== CSI5.JCO0SEGMENTBLANK oim MACRO (F300) @JC:WR0 O0SEGMENTBLANK MAC:EII o KRCALL: WR:0 im MACRO (F300) @ig# ttJC:RD0 O0SEGMENTBLANK MAC:EII o KRCALL: RD:0 im MACRO (F300) @ig# m*** MACRO:EII - REV A20m0 ***ttJC:RENAM0O0SEGMENTBLANK MAC:EII o KRCALL: RENAM:0 im MACRO (F300) @ig# ttJC:IPUID0O0SEGMENTBLANK MAC:EII o KRCALL: IPUID:0 im MACRO (F300) @ig# ttJC:RDFST0O0SEGMENTBLANK MAC:EII o KRCALL: RDFST:0 im MACRO (F300) @ig# ttJC:DTTIM0O0SEGMENTBLANK MAC:EII o KRCALL: DTTIM:0 im MACRO (F300) @ig# ttJC:EXIT0 O0SEGMENTBLANK MAC:EII o KRCALL: EXIT:0 im MACRO (F300) @ig# ttJC:DEL0 O0SEGMENTBLANK MAC:EII o KRCALL: DEL:0 im MACRO (F300) @ig# ttJC:CREAT0O0SEGMENTBLANK MAC:EII o KRCALL: CREAT:0 im MACRO (F300) @ig# ttJC:POS0 O0SEGMENTBLANK MAC:EII o KRCALL: POS:0 im MACRO (F300) @ig# ttJC:RDPOS0O0SEGMENTBLANK MAC:EII o KRCALL: RDPOS:0 im MACRO (F300) @ig# ttJC:OPEN0 O0SEGMENTBLANK MAC:EII o KRCALL: OPEN:0 im MACRO (F300) @ig# ttJC:CLOSE0O0SEGMENTBLANK MAC:EII o KRCALL: CLOSE:0 im MACRO (F300) @ig# ttJC:REOF0 O0SEGMENTBLANK MAC:EII o KRCALL: REOF:0 im MACRO (F300) @ig# ttJC:WEOF0 O0SEGMENTBLANK MAC:EII o KRCALL: WEOF:0 im MACRO (F300) @ig# ttJC:CHAIN0O0SEGMENTBLANK MAC:EII o KRCALL: CHAIN:0 im MACRO (F300) @ig# ttJC:FRMEM0O0SEGMENTBLANK MAC:EII o KRCALL: FRMEM:0 im MACRO (F300) @ig# ttJC:GTMEM0O0SEGMENTBLANK MAC:EII o KRCALL: GTMEM:0 im MACRO (F300) @ig# ttJC:LOAD0 O0SEGMENTBLANK MAC:EII o KRCALL: LOAD:0 im MACRO (F300) @ig# ttJC:RDUID0O0SEGMENTBLANK MAC:EII o KRCALL: RDUID:0 im MACRO (F300) @ig# ttJC:WRUID0O0SEGMENTBLANK MAC:EII o KRCALL: WRUID:0 im MACRO (F300) @ig# ttJC:CVUID0O0SEGMENTBLANK MAC:EII o KRCALL: CVUID:0 im , MACRO (F300) @ig# ttJC:MAP0 O0SEGMENTBLANK MAC:EII o KRCALL: MAP:0 im MACRO (F300) @ig# ttJC:MGUID0O0SEGMENTBLANK MAC:EII o KRCALL: MGUID:0 im MACRO (F300) @ig# ttJC:SPUID0O0SEGMENTBLANK MAC:EII o KRCALL: SPUID:0 im MACRO (F300) @ig# ttJC:OPUID0O0SEGMENTBLANK MAC:EII o KRCALL: OPUID:0 im MACRO (F300) @ig# ttJC:RDCOM0O0SEGMENTBLANK MAC:EII o KRCALL: RDCOM:0 im MACRO (F300) @ig# ttJC:WRLOG0O0SEGMENTBLANK MAC:EII o KRCALL: WRLOG:0 im MACRO (F300) @ig# ttJC:UNMAP0O0SEGMENTBLANK MAC:EII o KRCALL: UNMAP:0 im MACRO (F300) @ig# ttJC:INIT O0SEGMENTBLANK MAC:EII o KB:INIT RCALL: im MACRO (F300) @ig# ttJRCALL: O0SEGMENTBLANK MAC:EII o im MACRO (F300) @ig @ p*` @p `+ &}BC@ `p A# JSPUID:0 O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:oXKPUTBYTE:B:MOVBTSGETBYTE:im MACRO (F300) @iiig BCIkjGIBkj HIBk jIIJCOI PGQJBk jGOIC k jGJJDO PHQ JBk jHOIDk j HJJEOIPIQJBk  jIOIEk j F T# tttiiXJMGUID:0 O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:oiKPUTBYTE:B:MOVBTSGETBYTE:im MACRO (F300) @iiig BCIkjGICkj HIDk jIHGB J IK˞FÀEPQ GRIBk jGPIEk  jGKKEPQHRIC k jHPIEk jHK KEPQIRIDk jI PIEk jJPIEk j F d# tttiiiJB:RDCH RDUID:0 O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:oOKGETBYTE:RD:0 B:GETUIDim MACRO (F300) @iiig BCF ĀFBF DąFEFCkj# g BCBIKLM Ckj HEB  ICk jkCdjEBEE@ # B a z J# tttidAiiOJB:GCFM IPUID:0 O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:oPKGETBYTE:B:GETUIDim MACRO (F300) @iiig BC H ĀHBH CĂHDHFąHGHEkj# g B CDEICQ EDkjkCd jEIDBĂC BB EB # B a z L# ttidCiiPJB:RDSTR B:GETUIDO0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:oKC:GLA PUTBYTE:GETBYTE:im MACRO (F300) @iiig BCEIFGCIBBIāCBk Cd jDISB@IBk jJ # HIKLCMBkjN INHEHLF HGEcHNQCINQDBkCd jCMkjD DBkCd jCMkjDCHKL D Ay .R /B GJDGk Cd jDDGBk Cd jCFk jGaGk CdjZGBk Cd j7NI OBCk 1jGI Bk j JG t K IBksjkCd j BYKKkj IIQOIBk [j I/GJQ  J  ENIBk jG # BC @DE Dk jFIG H G >FA Fk CdjIAtt FIHIF F DIHEFBk Cd jCDk jFGKGHDBF# BkCdjCBkCd jCI:BQAH@I@ _BA G# B A B MZIH@@# B 0  BM9IH@@# g BC FG@Ckj HBGk jIIFFE HHIN@Ck j BGk jIDk jHN@ttCk {jI # BCIkrj DCI@ BkjjDIIBkcj# id"ddd!d4diiJPOS:0 O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:o"KB:FNDSCBim MACRO (F300) @iiig BCFk jGF  򞎀CGDGI ċCEEDā FF # tii"JRDPOS:0 O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:oKB:FNDSCBim MACRO (F300) @iiig BCDkjED  򞈀CEFC DD# tiiJWEOF:0 O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:oKI::IO B:FNDSCBim MACRO (F300) @iiig BCkjDCC IJIBkjCC# t@$tiiJRENAM:0 O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:o~KB:FREEDUB:DISCLUI::IO KB:CON B:U2G im MACRO (F300) @iiig BCEGBGAK(G} 'AIĂE߀B kjAA CkjA'A '}'AQ@; '}'AQ@E '}IEkjA E~¤G} ~kj~kjj DEk~jAk~jDu# dtdt@5tttiCBi~JRDFST:0 O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:of KCLOSE:0 REOF:0 B:DVCLASKB:FNDSCBOPEN:0 im MACRO (F300) @iiig BCG C D GG OFPIBk jBFF Gk jLGk jMIL QALKDIMQ؀F REGkjBFL KN‚B N CIMQ‚MC EEIā T FG Gk jF\# ttttddti  ?==-(iifJREOF:0 O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:oKI::IO im MACRO (F300) @iiig BCIJIBkjD. D # @#tiiJCVUID:0 O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:o#KB:MOVBTSGETBYTE:B:FNDSCBim MACRO (F300) @iiig BCDkjED  FIk j CKM L@Fkj DD# tttii#JOPUID:0 O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:o/KB:MOVBTSGETBYTE:im MACRO (F300) @iiig BCIEkj HD IBDH JBOCPJQIEk j JC FIQB瞁 *GG,# ttii/JWRUID:0 O0SEGMENTBLANK  CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:oKWR:0 GETBYTE:im MACRO (F300) @iiig BCKIICk j JG KDLIBkjD# ttiiJRD:0 O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:oKB:ISTERMGETBYTE:PUTBYTE:KB:IO I::IO B:TRWBUFKB:FNDSCBB:INIT C:WPL KC:WP im MACRO (F300) @iiig BCGITDUV WkjFBk jSF YZ[ GBGIāG[G̈́ GYąG SJQ̈QJ kjWYVS SI ĊZ SQ Z @b§cWdVeBkj GkjGh XAG]I b@Ykj➐tt tt@t@ttt ]SSIĈS Ykj\aTCkhj SKĈS ITTU UIZQƀ\kjAU RGăGDGCą Gk?jGXGTA FTEF# tt@iiJWR:0 O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:oKPUTBYTE:B:IO B:TRWBUFKB:ISTERMGETBYTE:B:FNDSCBKB:INIT im MACRO (F300) @iiig BCGITDUkj FBkjSF YZ[GBGI āG[ Z\ / \GGYąS DŽS IĉS SIĊSX MTCkjWIT TU UWkjZSk jGGkjGj VAҠS SIĈSWtt@tttt IWS\W aYkjS I\ Sĉ\ I W W4 UR%GQăGDGC ąGkKjGVGTA FTEF# tiiJB:TRWBUFO0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:oKGETBYTE:PUTBYTE:B:MOVBTSim MACRO (F300) @iiig B CDEDB FCK LDMICk j FCIK JKQ + F 1 ** KJIkjIDDIC kjG  +G  DD HMICk jI0GQՀCM INDOICk jHMI Ck j DDI HQРB CM NDOICk jttt MICk ujID D@ A    BDD#  iiJRDCOM:0 O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:oKPUTBYTE:GETBYTE:B:RCI KI::IO C:WPC C:WPCL im MACRO (F300) @iiig BCEGG  GIG'' GKG' pn'đ'E QѢGG kjdIǵk jd'GEk jcGBk jbIGG /  bI GGBkUCdt@ttttt jd C DD# iiiJWRLOG:0 O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:o@KI::IO WR:0 im MACRO (F300) @iiig BCF·GCLGMD NBkjGFkCd jCLMDNBkjD( # BC HIJCK@B kjA # ULUCt@Ctid)ii@JB:MOVBTSB:ISTERMO0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:o0KPUTBYTE:GETBYTE:im MACRO (F300) @iiig B A I BQAH@I@ BA G# g BCF GEGCGK@ Bk jLKDkjGJGG+# ttii0JB:UNLOCKB:LOCK B:CSTRMSJB:FNDSCBB:FSCB B:GSCB JCLOSE:0 OPEN:0 EXIT:0 JB:INIT O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:o  KB:SIG B:WAIT C:SSEMA4KWR:0 B:DISCLUB:CLOSLUKFRMEM:0 TASKID: B:FREEDUKGETBYTE:GTMEM:0 I::IO KB:OPLUN B:CON B:U2G KB:A2I B:FINISHC:GLA KC:SCBCH im MACRO (F300) @iiig  BDEF GHIGk jJ G K]G^I DkjB  ]G ^IFkjB KG KkjNG]^I EkjB PP# g BkjBkj# g BCGDHEIFJIM OGLG @GIJHIGHtdddULUCCIdtxt GIM@SDJI SMkNj JkNWjMJB GŃQ NGLN1 NB GOkPj OLGNKGNN e OGRHBkNjORHBkNjddtt KAu GHNG LOkNjKAfONH 0G@NkNjKAXMG MNă (OIGRT SNkNjO A  LGJQ  ( * MOKNUB UMt t @3t LQB  CILQB  I LDII  LB  W Ia q JRDD MLQD MMM  +JR@ FkNjBJ IBkNjOGKGM MJGR@MkNt t e xjBJ NGM GO'NBPM' NGNKGNN'OkiMIČ  MJGMSEMkNCdjOkNjM# gBCkjC# tg BCIk3jA Dk jCBkjEDQTCJ G kjɢFEĀ EIED[IEQXI F GFE FKFG wuEkjEkjE,# Ettg BCkwjCBkjDkCdjknj# g BCgDBEIBkj A FDQĀFA EQȀGkLjGD D DIDQ tCDv# t g 6BkjBDE kCd jGBkjDB B kj# Bt C DE A FIGCQT K kCd jFQĀCkjFĀCk jIEQFGEkj DDGttt DkwjBIā# B C¢D ьOIK LGMGkj# gkj# gkj# ttttidd UCULCIiDx##i JCREAT:0 O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:oWKB:FREEDUB:DISCLUB:CON2LUKC:EXTSIZB:U2G im MACRO (F300) @0 iiig BCFIGBGGB BkCjEAF ICQBICQB  CF CFFIFkCj EFGBQD@kCjFkCjEKBDBP# tttttiiWJDEL:0 O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:oYKB:FREEDUI::IO B:DVCLASKB:U2G im MACRO (F300) @iiig BCEIGDIGD BkEjDAEA+('B‚ kEjCEGE'Bą EE'BEQD  CB㞎JGBGKALkEjGG AEkBjACAR# tUFt@4ttiiYJGTMEM:0 O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:oKB:ABUF im MACRO (F300) @iiig BCkjC  DD # tiiJFRMEM:0 O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:o KB:RBUF im MACRO (F300) @iiig BCkj C # tii JLOAD:0 O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:o-KB:LOAD im MACRO (F300) @iiig BC H BHCH IĂHDHEĄH H ’ċHkjH" VHEHFV*# tii-JCHAIN:0 O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:oKB:CMD B:CSTRMSGETBYTE:im MACRO (F300) @iiig BCIkj Bkj IB@kjC# tttiiJDTTIM:0 O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:o KB:A2I B:GATD im MACRO (F300) @iiig BCDk jILL Dk jLBLKLMr C # ttii JB:A2I O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:o im MACRO (F300) @iiig By @ G BB #  ii JB:DVCLASB:CON B:CON2LUJI::IO B:CLOSLUB:OPLUN JB:DISCLUC:GLA B:FREEDUJB:U2G B:LU2LU O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:oKB:IO B:GLA B:GFN KGETBYTE:im MACRO (F300) @iiig  BC HIJBK@CkjA # g  BC FI:GFD F KFFGvtI DDĀ  DDD¼ĊDBD  IBkj DDD ICkjCDCD kjDEXQĀ E DI@EQ DĈEA#hh# @@ttg B CCkjBIĂ# g BC lďBĄBk jA UOBIZ[ C\IkPjC BU# g BIGHIJBkj# g BCDGP BD IāDPD‹ăDCDIt @3@P@0ćDDŽDkjD# g BCJ¹KIBkj # BCD QIRQ D QKQQRvtD ˜ĉDDBąDkj DQCCBć# t@1@@g BC CJvKk rjI,# g BC DF+(RB S TIUTD TK TTUvtDOăDI DCĀ F‚FZ DBQ@ @ BTRBTRĈRSRtt DUF. DkjA EDTBĸEB 1 D# B kj# g BC (E Iā CFE¤āBCBkCdj # BkjBkj# g BC BĀCkjCC # |idddiiO0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:oKI::IO B:IO im MACRO (F300) @iii BCFG K FFC āKBKIāKFK ăK݄KDąKkjI KE IK-- # BCF FFCāF M¿NEODPBk jA G # BC HIZ [Z H ZKZ[wuHB BZHH•ďHE HFĆHGC\I]^@t@t _DQB   __H`]\knjYHZBāY# @`idd.dHiiJB:GATD O0SEGMENTBLANK CODE:ROMOCODE:RAMDATA:RAMDATA:ROMOGLOBVEC:o KB:SSTOD B:CATOD B:CTODA KB:GSTOD im MACRO (F300) @iiig BGC@kjCBk j# BC@BkjCkj# ttttidii JC:SSEMA4C:SCBCH O0SEGMENTBLANK DATA:RAMo  NSDB: im MACRO (F300) @m*** EII.LBR - REV E860 m ***igk fgJC:WPL C:WP O0SEGMENTBLANK DATA:RAMo im MACRO (F300) @ig gJC:WPCL C:WPC O0SEGMENTBLANK DATA:RAMo im MACRO (F300) @ig CSI..gJC:EXTSIZO0SEGMENTBLANK DATA:RAMo im MACRO (F300) @igJB:UPDCFIO0SEGMENTBLANK CODE:ROMo im MACRO (F300) @igF &+G'# JB:FINISHO0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig zJB:CMD O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig zJB:RCI O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig z# JPUTBYTE:GETBYTE:O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig @@``%'`@# g @@`Dh%'`@# JTASKID: O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @igP# O0SEGMENTBLANK oim MACRO (F300) @JB:DSENV O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig  # JB:SUENV O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig  # JB:REENV O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig  # JB:LDENV O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig oCDEFG oC # JB:GERI O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig  # JB:CRSMR O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig  # JB:MAPIN O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig  # JB:UNMAP O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig  # JB:CRTASKO0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig   # JB:DSTASKO0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig   # JB:BGIN O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig oCDEFG oC 2 # JB:END O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig JB:GPRI O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig  # JB:SPRI O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig  # JB:PAUS O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig  # JB:CRMBX O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig  # JB:DSMBX O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig  # JB:SEND O0SEGMENTBLANK CODE:ROMo  im MACRO (F300) @ig B @ # JB:RECV O0SEGMENTBLANK CODE:ROMo  im MACRO (F300) @ig B @ā # JB:SENDR O0SEGMENTBLANK CODE:ROMo  im MACRO (F300) @ig B @ # JB:RECVR O0SEGMENTBLANK CODE:ROMo  im MACRO (F300) @ig B @ā # JB:SIG O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig  # JB:WAIT O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig  # JB:WAITR O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig  # JB:CRSEM O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig  # JB:DSSEM O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig  # JB:CRQ O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig  # JB:DSQ O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig  # JB:QPUT O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig  # JB:QPUTR O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig  # JB:QGET O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig  # JB:QGETR O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig   # JB:QACK O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig # # JB:ITIC O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig $ # JB:MTIC O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig %# JB:CTIC O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig &# JB:AWAL O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig ' # JB:IWAL O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig ( # JB:CWAL O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig )# JB:GTOD O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig *ā # JB:STOD O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig + # JB:CDOW O0SEGMENTBLANK CODE:ROMo  im MACRO (F300) @ig C,C # JB:CTODA O0SEGMENTBLANK CODE:ROMo  im MACRO (F300) @ig B @- # JB:CATOD O0SEGMENTBLANK CODE:ROMo  im MACRO (F300) @ig B @.ā # JB:GSTOD O0SEGMENTBLAN3 K CODE:ROMo im MACRO (F300) @ig /ā # JB:SSTOD O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig 0 # JB:GELT O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig 1ā # JB:GEXT O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig 2ā # JB:CFREQ O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig C # JB:RBUF O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig 5 # JB:ABUF O0SEGMENTBLANK CODE:ROMo  im MACRO (F300) @ig C3C@(Ā # JB:PBUF O0SEGMENTBLANK CODE:ROMo  im MACRO (F300) @ig  C4C@(Ā # JB:LOAD O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig 8 # JB:OVL O0SEGMENTBLANK CODE:ROMo  im MACRO (F300) @ig @I:I@# JB:IO O0SEGMENTBLANK  CODE:ROMo im MACRO (F300) @ig 6 # JB:IOR O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig 7 # JB:DEVUP O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig ;# JB:DEVDN O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig <# JB:UEX O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig @> # JB:PUNT O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig@# JB:REX O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig?# JB:WEX O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @igA# JB:UID O0SEGMENTBLANK CODE:ROMo  im MACRO (F300) @ig Eā # JB:SUID O0SEGMENTBLANK CODE:ROMo  im MACRO (F300) @ig B @Zā # JB:GLA O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig !# JB:SLA O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig "# JB:ISM O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig D # JB:GFN O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig =# JB:UMOVE O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig F# JB:MOVE O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig Z#   CODE:ROMo im MACRO (F300) @ig 6 # JB:IOR O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig 7 # JB:DEVUP O0SEGMENTBLANK CODE:ROMo im MACRO (F300) @ig //@ // =========== // CSI_INT.HDR // =========== // C A R T O S S Y S T E M I N T E R F A C E // Internal Header File. MANIFEST $( BytesPerWord = 2 // Machine word size ENDSTREAMCH =-1 // End-of-stream code UF =#X5546 // 'UF' LUN FI.TITL = 3 // ***** USED BY AWB (sob!) ***** // UID Equates UID.LEN = 0 // Highest byte in UID UID.LENA = 1 // Length of part A UID.LENB 4  = 2 // Length of part B UID.LENC = 3 // Length of part C UID.TEXT = 4 // UID text // Filename Syntax Equates Max.User.LUN = 255 // Max value for numeric user LUN Fn.LUL  = 2 // Alpha LUN length Fn.FnL = 11 // File name length Fn.ExL = 3 // Extension length Fn.PwL = 8 // Password length Fn.PrL = 3 // Protection length Fn.Sep = '/' // Section separator Fn.PwS = '[' // Password start Fn.PwE = ']'  // Password end Fn.PrS = '<' // Protection start Fn.PrE = '>' // Protection end Fn.PCS = '.' // PartC start // C.GTCH Parameter Block Equates GTC.FUN = 0 // Read function GTC.BUF = 1 // C.GCFM Buffer GTC.PTR = 2 // C.GCFM Pointer GTC.L2G  = 3 // C.GCFM Length to go GTC.aLU = 1 // C.RD0 LUN GTC.aCH = 5  // Address of terminator GTC.aRE = 6 // Address of CSI reply GTC.SIZ = GTC.aRE + 1 // Size of table // Stream Control Block (SCB) Equates SCB.CHN = 0 // SCB Chain word SCB.FLW = SCB.CHN + 1 // Flagword SCB.USR = SCB.FLW + 1 // User ID SCB.LUN = SCB.USR + 1 // Current LUN SCB.CHB  = SCB.LUN + 1 // Character Buffer SCB.CFI = SCB.CHB + 1 // CFI Address SCB.CG1 = SCB.CFI + 1 // CFI Word 1 SCB.CBP = SCB.CG1 + 2 // Character Buffer Pointer SCB.CC = SCB.CBP + 1 // Character Count SCB.IOM = SCB.CC + 1 // IO Mode SCB.ELT = SCB.IOM + 1 // End of Line Terminator SCB.DTP = SCB.ELT + 1 // IO Data Type SCB.UID = SCB.DTP + 1 // UID Copy Address SCB.FTP = SCB.UID + 1 // File type SCB.PRT = SCB.FTP + 1 // Protection code SCB.OMD = SCB.PRT + 1 // File open mode SCB.SIZ = SCB.OMD + 1 // SCB size (Words) // SCB Flagword Equates Used. =-1 // Used SCB Entry Unused. = 0  // Unused SCB Entry DiskUB. = 1 // Disk, Unbuffered CharDevUB. = 2 // Character device Unbuffered DiskB. = 3 // Disk, Buffered CharDevB. = 4 // Character Device (Buffered) Buffered. = 3 // >= to this => Buffered Data CSIBufferSize = 138 // Character Buffer Size MaxPromptLen = 80 // Maximum prompt length // SCB IO Mode Equates CRead. = 4 CWrite.  = 5 // SCB Data Type Equates DefaultDataType =-1 // To be defaulted UFM. = 0 // Unformatted ISO2ASCII. = 1 // ISO to ASCII ISO2ISO. = 2 // ISO to ISO ASCII2ASCII.  = 3 // ASCII to ASCII ASCII2ISO. = 4 // ASCII to ISO DontOpen. = 5 // File already open // Create File Types DirectoryFile. = 1 // Create a directory DataFile. = 2 // Cr5 eate a data file // File Status Equates Device. = 3 // File status reply ST.FFDF = 0  // Disk devices, no access ST.F4DF = ST.FFDF + #X2000 + #X800 + #X40 + #X80 ST.F3DF = ST.F4DF + #X400 + #X100 ST.F2DF = ST.F3DF + #X1000 ST.F1DF = ST.F2DF + #X4 ST.F0DF = ST.F1DF + #X2 + #X1 + #X200 ST.FFDD = 0 // Disk directory, no access ST.F4DD = ST.FFDD + #X40 + #X80 ST.F3DD  = ST.F4DD + #X100+ #X400 ST.F2DD = ST.F3DD + #X1 ST.F1DD = ST.F2DD + #X4 ST.F0DD = ST.F1DD + #X2 ST.FACD = #X10C0 ST.FRCD = #X100 ST.FWCD = #X200 ST.FPCD = #X400 $) EXTERNAL $( // In CSI0 C.USER : "TASKID:" C.UpdateCFI: "B:UPDCFI" C.End : "B:FINISH" C.CMD : "B:CMD" C.RCI : "B:RCI" GETBYTE : "GETBYTE:" PUTBYTE : "PUTBYTE:" // In CSI3.BPL C.MOVBTS : "B:MOVBTS" C.ReadString : "B:RDSTR" C.GCFM : "B:GCFM" C.RdCh : "B:RDCH" C.GETUID : "B:GETUID" // In CSI5.BPL TreatWriteBuffer : "B:TRWBUF" IsTerminator : "B:ISTERM" // In CSI6.BPL C.INIT : "B:INIT" C.GetSCB : "B:GSCB" C.FindSCB: "B:FNDSCB" C.FreeSCB: "B:FSCB" C.CloseAllStreams: "B:CSTRMS" C.LOCK : "B:LOCK" C.UNLOCK : "B:UNLOCK" // In CSI7.BPL C.GLA : "C:GLA" C.GFN : "C:GFN" C.Connect: "B:CON" C.OpenLUN: "B:OPLUN" C.DiscLUN: "B:DISCLU" C.ClosLUN: "B:CLOSLU" C.FreeDUN: "B:FREEDU" C.DeviceClass: "B:DVCLAS" C.UID2GFN: "B:U2G" C.LUN2LUN: "B:LU2LU" C.CONN2LUN:"B:CON2LU" C.GATD: "B:GATD" I..IO: "I::IO" // In CSI8.BPL ASCII.TO.INTEGER: "B:A2I" // SCB Chain Head C.SCBCH : "C:SCBCH" // Stream Lockout Semaphore C.SSEMA4 : "C:SSEMA4" $) 0 + #X80 ST.F3DF = ST.F4DF + #X400//@ // ======= // CSI.HDR // ======= // C A R T O S S Y S T E M I N T E R F A C E // User Header file. // Each CSI service has two entry points. // Assembly language calls should use the C:xxxxx entry. // BCPL and CORAL calls should use the xxxxx:0 entry. // The xxxxx:0 calls are presented in this header in a more // convenient C.xxxxx form. EXTERNAL $( // Section 3 C.RDUID0 : "RDUID:0" C.IPUID0 : "IPUID:0" C.SPUID0 : "SPUID:0" C.MGUID0 : "MGUID:0" C.CREAT0 : "CREAT:0" C.OPEN0 : "OPEN:0" C.RD0 : "RD:0" C.WR0 : "WR:0" C.RDCOM0 : "RDCOM:0" C.WRLOG0 : "WRLOG:0" C.CLOSE0 : "CLOSE:0" C.DEL0 : "DEL:0" // Prompts C.WP : "C:WP" C.WPL : "C:WPL" C.WPC : "C:WPC" C.WPCL : "C:WPCL" // Extent sizes for C.CREAT0 C.EXTSIZ : "C:EXTSIZ" // Section 4 C.RDFST0 : "RDFST:0" C.RDPOS0 : "RDPOS:0" C.REOF0 : "REOF:0" C.CVUID0 : "CVUID:0" C.WRUID0 : "WRUID:0" C.OPUID0 : "OPUID:0" C.POS0 : "POS:0" C.WEOF0 : "WEOF:0" C.RENAM0 : "RENAM:0" C.MAP0 : "MAP:0" C.UNMAP0 : "UNMAP:0" // Section 5 C.GTMEM0 : "GTMEM:0" C.FRMEM0 : "FRMEM:0" C.LOAD0 : "LOAD:0" C.CHAIN0 : "CHAIN:0" C.DTTIM0 : "DTTIM:0" C.EXIT0 : "EXIT:0" $) 82042315154275820423151545d6 //@ // ============== // CSI_ERRORS.HDR // ============== // Internal header file including manifest equates for CSI error // returns. MANIFEST $( OK=0 // Operation successful ER.NONE=0 // ditto EOF=1 // End-of-File hit ER.LUN.FORMAT=-1 // LUN format incorrect ER.LUN.NOT.FOUND=-2 // LUN not found ER.CONN.FAIL=-3 // Connect failure ER.DK.NOT.FILE=-4 // Attempt to open a disk not a file ER.LUN.NOT.ASS=-5 // LUN not assigned ER.PUN.NOT.FOUND=-6 // PUN not found ER.LUN.NOT.OPEN=-7 // LUN not previously opened ER.ICH.RW=-8 // Incompatible character read-write ER.PUN.BAD=-9 // PUN incorrect. ER.ILL.FILE.FTYPE=-10// Illegal file type ER.FILE.EXISTS=-11 // File already exists ER.WE.ON.DIR=-12 // Write error on directory create. ER.DEL.FAIL=-13 // Delete failed ER.POS.ILL=-14 // Position illegal for this device ER.FSPX=-15 // Free space exhausted // -16 Not used // -17 Not used ER.ILL.HEX.VAL=-18 // Illegal hexadecimal value specified ER.CHAIN.FAIL=-19 // Load failed during CHAIN0 service ER.DIR.READ=-20 // Directory read error ER.UFN.TOO.BIG=-21 // User file name too large for UID ER.FILE.NOT.FOUND=-22// File not found in directory ER.NO.MEM=-23 // Insufficient memory ER.PUNS.DIFFER=-24 // PUNs differ (on RENAM0) ER.UID.TOO.BIG=-25 // UID too large for available memory (OPUID0) ER.ILL.DATA.MODE=-26 // Illegal data mode encounterd ER.INVALID.PW=-27 // Invalid Password ER.INVALID.PR=-28 // Invalid Protection ER.BAD.FILE.ID=-29 // Invalid file identifier ER.KAPUTT=-99 // CSI system error. $) // Operation successful ER.NONE=0 // ditto EOF=1 // End-of-File hit ER.LUN.FORMAT=-1 // LUN format incorrect ER.LUN.NOT.FOUND=-2 // LUN not found ER.CONN.FAIL=-3 // Connect failure ER.DK.NOT.FILE=-4 // Attempt to open a disk not a file ER.LUN.NOT.ASS=-5 // LUN not assigned ER.PUN.NOT.FOUND=-6 // IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII7 IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII8 IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII9 IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII: IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII; IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII< IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII= IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII> IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII? IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII@ IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIA IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIB IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIC IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIID IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIE IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIF IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIG IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIH IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIJ IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIK IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIL IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII