DIRECTORY DicentraInputOutput, Heap, Inline, Process, ProcessorFace, OthelloDefs, RavenSlotDriver, Watchdog; RavenSlotDriverImpl: MONITOR IMPORTS DicentraInputOutput, Inline, Heap, Process, ProcessorFace, OthelloDefs, Watchdog EXPORTS RavenSlotDriver = BEGIN hyperStart: DicentraInputOutput.IOAddress = MustBe64KWordBoundary[100000H]; hyperEndPlus1: DicentraInputOutput.IOAddress = LOOPHOLE[200000H]; bpi: CARDINAL = 384; pageLengthInches: CARDINAL = 12; -- ample slop - 11 would probably do pageWidthInches: CARDINAL = 8; white: CARDINAL = 0; slot: Slot = LOOPHOLE[LONG[4000H]]; -- controller IO address Slot: TYPE = LONG POINTER TO SlotRec; SlotRec: TYPE = RECORD [ printerCSR: CARDINAL, marginCount: CARDINAL, scanCount: CARDINAL, uARTModeOrCmd: CARDINAL, uARTData: CARDINAL]; slotBufferSize: CARDINAL = 2048; feedPageCommand: CARDINAL = 40H; txOffRxOnCommand: CARDINAL = 014H; resetCommand: CARDINAL = 40H; -- internal reset to go into 'Mode' mode configureUART: CARDINAL = 03BH; -- 1 stop bit, even parity, 7 bits, 64X clock rxEnable: CARDINAL = 015H; -- Error reset, Recv enable startSlot: CARDINAL = 01H; stopSlot: CARDINAL = 0; getStatus: CARDINAL = 20H; txReady: CARDINAL = 1; rxReady: CARDINAL = 2; bufferEmpty: CARDINAL = 80H; bufferSize: CARDINAL = 512; -- PowerOfTwoAtLeast[(bpi*pageLengthInches)/16]; Buffer: TYPE = LONG POINTER TO BufferRecord; BufferRecord: TYPE = ARRAY [0..bufferSize) OF WORD; dataBuffer: Buffer _ Heap.systemZone.NEW[BufferRecord]; whiteBuffer: Buffer _ Heap.systemZone.NEW[BufferRecord]; mpInitialising: NAT = 600; initUart: RavenSlotDriver.PrinterStatus = VAL[0]; fillingHyper: RavenSlotDriver.PrinterStatus = VAL[1]; patterningHyper: RavenSlotDriver.PrinterStatus = VAL[2]; checkingHyper: RavenSlotDriver.PrinterStatus = VAL[3]; hyperOK: RavenSlotDriver.PrinterStatus = VAL[4]; errorHiDigits: RavenSlotDriver.PrinterStatus = VAL[13]; errorLoDigits: RavenSlotDriver.PrinterStatus = VAL[14]; mpOK: NAT = 700; mpWarning: NAT = 800; mpFailure: NAT = 1300; warningOrOKcode: NAT _ mpOK; K64Words: LONG CARDINAL = LONG[64]*1024; FallenOffTheEndOfHyperspace: PUBLIC ERROR = CODE; BadParameters: PUBLIC ERROR = CODE; outputTrayFullFlag: PUBLIC BOOLEAN _ FALSE; lowTonerFlag: PUBLIC BOOLEAN _ FALSE; HyperStore: PUBLIC PROC [ sourcePtr: LONG POINTER TO WORD, destOffset: LONG CARDINAL, wordCount: LONG CARDINAL] = BEGIN IF LOOPHOLE[hyperStart+destOffset+wordCount, LONG CARDINAL] > LOOPHOLE[hyperEndPlus1, LONG CARDINAL] THEN ERROR FallenOffTheEndOfHyperspace; WHILE wordCount>0 DO toNextBoundary: LONG CARDINAL _ K64Words - Inline.LowHalf[destOffset]; xferSize: CARDINAL _ CARDINAL[MIN[wordCount, toNextBoundary, K64Words-1]]; DicentraInputOutput.WriteHyper[from: sourcePtr, to: hyperStart+destOffset, words: xferSize]; sourcePtr _ sourcePtr + xferSize; destOffset _ destOffset + xferSize; wordCount _ wordCount - xferSize; ENDLOOP; END; GetStatus: PUBLIC PROC[] RETURNS[s: RavenSlotDriver.PrinterStatus] = BEGIN SendCommand[getStatus]; RETURN[ReceiveStatus[]]; END; DisplayBadStatusInMP: PUBLIC PROC[s: RavenSlotDriver.PrinterStatus] = BEGIN MPReport[s, mpFailure]; END; PrintPage: PUBLIC ENTRY PROC [slowMargin, fastMargin: NAT, numberOfLines, scanLineLength: NAT, paperSource: RavenSlotDriver.PaperSource, paperStacking: RavenSlotDriver.PaperStacking] RETURNS [RavenSlotDriver.SuccessCode] = BEGIN deviceSlowMargin: CARDINAL = 100; deviceFastMargin: CARDINAL = 400; s: RavenSlotDriver.PrinterStatus; scanLineWords: CARDINAL; hyperOffset: LONG CARDINAL _ 0; choppedLineLength:NAT _ (scanLineLength/16)*16; -- SLOT needs multiple of 16 p: CARDINAL _ Process.GetPriority[]; -- don't get interrupted while writing FeedPage: PROC[] RETURNS[RavenSlotDriver.PrinterStatus]= BEGIN commandByte: CARDINAL _ feedPageCommand + (IF paperSource=bottom THEN 0 ELSE 16) + (IF paperStacking=aligned THEN 0 ELSE 1); SendCommand[commandByte]; DO SELECT s _ ReceiveStatus[] FROM -- status bytes that we don't need to worry about IN [key0..keyOffLine], lowToner, -- ReceiveStatus[] has set lowTonerFlag outputTrayFull, -- ReceiveStatus[] has set lowTonerFlag displayAcknowledge, pageAtOutputTray, goingToSleep, feeding, readyToFeed => NULL; ENDCASE => EXIT; -- everything else is serious ENDLOOP; RETURN [s]; END; XFerBufferToSlot: PROC[b: Buffer] RETURNS[] = BEGIN start: CARDINAL _ slotBufferSize-scanLineWords; DicentraInputOutput.WriteBlock[from: b, to: slot+8000H+start, words: scanLineWords]; END; SkipScanLines: PROCEDURE [lines: CARDINAL] RETURNS[BOOLEAN]= { BufferEmpty: PROCEDURE RETURNS [BOOLEAN] = { x: CARDINAL _ DicentraInputOutput.Input[@slot.printerCSR]; RETURN[Inline.BITAND[x, bufferEmpty] # 0]; }; FOR i: CARDINAL IN [0..lines) DO count: CARDINAL _ 65000; WHILE NOT BufferEmpty[] DO count _ count - 1; IF count=0 THEN RETURN[FALSE]; ENDLOOP; ENDLOOP; RETURN[TRUE]; -- ok exit }; IF slowMargin+numberOfLines > pageWidthInches*bpi THEN { OthelloDefs.WriteLine["slowMargin/numberOfLines problem"]; numberOfLines _ pageWidthInches*bpi - slowMargin; }; IF fastMargin+scanLineLength > pageLengthInches*bpi THEN { IF fastMargin > pageLengthInches*bpi THEN { OthelloDefs.WriteLine["fastMargin > pageLengthInches*bpi"]; fastMargin _ scanLineLength _ 16; numberOfLines _ 0; } ELSE { OthelloDefs.WriteLine["fastMargin+scanLineLength > pageLengthInches*bpi"]; choppedLineLength _ ((pageLengthInches*bpi-fastMargin)/16)*16; }; }; scanLineWords _ scanLineLength/16; DicentraInputOutput.Output[-(fastMargin+deviceFastMargin), @slot.marginCount]; DicentraInputOutput.Output[-(choppedLineLength), @slot.scanCount]; slowMargin _ MAX[MIN[slowMargin, pageWidthInches*bpi], 0] + deviceSlowMargin; -- add client margin to device margin IF (s _ FeedPage[]) # pageSync THEN { -- Feed a page (or tell client about problem) DisplayBadStatusInMP[s]; SELECT s FROM registrationJam => OthelloDefs.WriteLine[" - Registration jam"]; fuserJam => OthelloDefs.WriteLine[" - Fuser jam"]; warming => OthelloDefs.WriteLine[" - Warming up"]; feederFault => OthelloDefs.WriteLine[" - Out of paper"]; interlockOpen => OthelloDefs.WriteLine[" - Door open"]; fuserCold => OthelloDefs.WriteLine[" - Fuser cold"]; parityError => OthelloDefs.WriteLine[" - Parity Error"]; offLine => OthelloDefs.WriteLine[" - Offline"]; ENDCASE => OthelloDefs.WriteLine[" - Can't feed page"]; RETURN[error]; }; MPReport[s, warningOrOKcode]; Process.SetPriority[7]; -- don't get interrupted XFerBufferToSlot[whiteBuffer]; -- prime slot buffer A with white DicentraInputOutput.Output[startSlot, @slot.printerCSR]; -- crank up slot IF NOT SkipScanLines[1] THEN { -- wait for first buffer to go out OthelloDefs.WriteLine[" - Timeout 1"]; Process.SetPriority[p]; -- allow interrupts again RETURN[error]; }; XFerBufferToSlot[whiteBuffer]; -- prime slot buffer B with white IF NOT SkipScanLines[slowMargin-1] THEN { -- freewheel thru A and B till margin out OthelloDefs.WriteLine[" - Timeout 2"]; Process.SetPriority[p]; -- allow interrupts again RETURN[error]; }; IF numberOfLines=0 THEN { OthelloDefs.WriteLine[" - Empty page!"]; } ELSE FOR i: CARDINAL IN [0..numberOfLines) DO HyperRead[destPtr: @dataBuffer[0], sourceOffset: hyperOffset, wordCount: scanLineWords]; XFerBufferToSlot[dataBuffer]; -- copy data back to slot buffer hyperOffset _ hyperOffset + scanLineWords; IF NOT SkipScanLines[1] THEN { OthelloDefs.WriteLine[" - Timeout 3"]; Process.SetPriority[p]; -- allow interrupts again RETURN[error]; } ENDLOOP; XFerBufferToSlot[whiteBuffer]; IF NOT SkipScanLines[1] THEN { OthelloDefs.WriteLine[" - Timeout 4"]; Process.SetPriority[p]; -- allow interrupts again RETURN[error]; }; XFerBufferToSlot[whiteBuffer]; -- fill other buffer and freewheel to end DicentraInputOutput.Output[stopSlot, @slot.printerCSR]; -- stop slot Process.SetPriority[p]; -- allow interrupts again DO s _ ReceiveStatus[]; SELECT s FROM pageAtOutputTray => EXIT; IN [key0..keyOffLine], lowToner, -- ReceiveStatus[] has set lowTonerFlag outputTrayFull, -- ReceiveStatus[] has set lowTonerFlag displayAcknowledge, goingToSleep, feeding, readyToFeed, statusRQtimeout => NULL; feederFault => { OthelloDefs.WriteLine[" - Out of paper?"]; }; ENDCASE => { code:CARDINAL _ VAL[s]; DisplayBadStatusInMP[s]; -- OthelloDefs.WriteLongNumber[code]; OthelloDefs.WriteLine[" - Page didn't complete satisfactorily"]; RETURN[error]; }; ENDLOOP; MPReport[GetStatus[], warningOrOKcode]; IF warningOrOKcode=mpWarning THEN { IF lowTonerFlag THEN OthelloDefs.WriteLine[" - Page completed (Toner Low)"]; IF outputTrayFullFlag THEN OthelloDefs.WriteLine[" - Page completed (Output tray full)"]; RETURN[warning]; } ELSE { code:CARDINAL _ VAL[s]; -- OthelloDefs.WriteLongNumber[code]; OthelloDefs.WriteLine[" - Page completed OK"]; RETURN[ok]; }; END; MustBe64KWordBoundary: PROC[i: LONG CARDINAL] RETURNS[DicentraInputOutput.IOAddress] = { IF i MOD K64Words # 0 THEN ERROR; RETURN [LOOPHOLE[i]]; }; HyperRead: PROC [destPtr: LONG POINTER TO WORD, sourceOffset: LONG CARDINAL, wordCount: LONG CARDINAL] = BEGIN WHILE wordCount>0 DO toNextBoundary: LONG CARDINAL _ K64Words - Inline.LowHalf[sourceOffset]; xferSize: CARDINAL _ CARDINAL[MIN[wordCount, toNextBoundary, K64Words-1]]; IF Inline.HighHalf[hyperStart+sourceOffset] # Inline.HighHalf[hyperStart+sourceOffset+xferSize-1] THEN ERROR; DicentraInputOutput.ReadHyper[from: hyperStart+sourceOffset, to: destPtr, words: xferSize]; destPtr _ destPtr + xferSize; sourceOffset _ sourceOffset + xferSize; wordCount _ wordCount - xferSize; ENDLOOP; END; Susp: PROC[n: CARDINAL] RETURNS[] = BEGIN Process.Pause[Process.MsecToTicks[n]] END; MPReport: PROC[s: RavenSlotDriver.PrinterStatus, offset: CARDINAL] = BEGIN ProcessorFace.SetMP[LOOPHOLE[s, CARDINAL]+offset]; END; MSecs1000WaitProcess: PROCESS _ NIL; SendCommand: PROCEDURE [command: CARDINAL] = { XmitReady: PROCEDURE RETURNS [BOOLEAN] = { x: CARDINAL_ DicentraInputOutput.Input[@slot.uARTModeOrCmd]; RETURN[Inline.BITAND[x, txReady] # 0]; }; IF MSecs1000WaitProcess # NIL THEN [] _ JOIN MSecs1000WaitProcess; MSecs1000WaitProcess _ NIL; -- turn receiver off, transmitter on DicentraInputOutput.Output[01H, @slot.uARTModeOrCmd]; WHILE NOT XmitReady[] DO ENDLOOP; DicentraInputOutput.Output[command, @slot.uARTData]; WHILE NOT XmitReady[] DO ENDLOOP; -- turn transmitter off, receiver on DicentraInputOutput.Output[txOffRxOnCommand, @slot.uARTModeOrCmd]; MSecs1000WaitProcess _ FORK Susp[1000]; }; ReceiveStatus: PROCEDURE RETURNS [s: RavenSlotDriver.PrinterStatus] = { RecReady: PROCEDURE RETURNS [BOOLEAN] = { bits: CARDINAL _ DicentraInputOutput.Input[@slot.uARTModeOrCmd]; RETURN[Inline.BITAND[bits, rxReady] # 0]; }; timeOut: LONG CARDINAL _ 100000; WHILE NOT RecReady[] DO timeOut _ timeOut - 1; IF timeOut=0 THEN RETURN[statusRQtimeout]; ENDLOOP; s _ DicentraInputOutput.Input[@slot.uARTData]; SELECT s FROM lowToner => { lowTonerFlag _ TRUE; warningOrOKcode _ mpWarning; }; outputTrayFull => { outputTrayFullFlag _ TRUE; warningOrOKcode _ mpWarning; }; ENDCASE => { lowTonerFlag _ outputTrayFullFlag _ FALSE; warningOrOKcode _ mpOK; }; RETURN[s]; }; Init: PROC[checkHyper: BOOLEAN_TRUE] RETURNS[] = BEGIN StripeHyper: PROC = BEGIN buffer: ARRAY [0..4) OF PACKED ARRAY [0..3840) OF BOOLEAN; p: POINTER _ @buffer; offset: LONG CARDINAL _ 0; FOR i: NAT IN [0..3840) DO buffer[0][i] _ ((i MOD 38) + i / 100) > 37; ENDLOOP; buffer[1] _ buffer[2] _ buffer[3] _ buffer[0]; MPReport[fillingHyper, mpInitialising]; WHILE offset < hyperEndPlus1-hyperStart DO wordCount: CARDINAL _ CARDINAL[MIN[(hyperEndPlus1-hyperStart)-offset, 3840/4]]; HyperStore[sourcePtr: p, destOffset: offset, wordCount: wordCount]; offset _ offset + wordCount; ENDLOOP; END; FillHyper: PROC [pattern: CARDINAL] = BEGIN buffer: ARRAY [0..256) OF CARDINAL _ ALL[pattern]; offset: LONG CARDINAL _ 0; MPReport[fillingHyper, mpInitialising]; OthelloDefs.WriteLine["Initialising memory"]; WHILE offset < hyperEndPlus1-hyperStart DO wordCount: CARDINAL _ CARDINAL[MIN[(hyperEndPlus1-hyperStart)-offset, 256]]; HyperStore[sourcePtr: @buffer[0], destOffset: offset, wordCount: wordCount]; offset _ offset + wordCount; ENDLOOP; END; PatternHyper: PROC [pattern: CARDINAL] = BEGIN buffer: ARRAY [0..99) OF CARDINAL; offset: LONG CARDINAL _ 0; mod: CARDINAL _ 0; MPReport[patterningHyper, mpInitialising]; OthelloDefs.WriteLine["Initialising memory"]; WHILE offset < hyperEndPlus1-hyperStart DO wordCount: CARDINAL _ CARDINAL[MIN[(hyperEndPlus1-hyperStart)-offset, 99]]; FOR j: CARDINAL IN [0..wordCount) DO mod _ mod + 1; IF mod = 10 THEN {pattern _ pattern * 13 + 5; mod _ 0}; buffer[j] _ pattern; ENDLOOP; HyperStore[sourcePtr: @buffer[0], destOffset: offset, wordCount: wordCount]; offset _ offset + wordCount; ENDLOOP; END; CheckHyper: PROC [pattern: CARDINAL] = BEGIN buffer: ARRAY [0..101) OF CARDINAL; fromHyper: ARRAY [0..101) OF CARDINAL; offset: LONG CARDINAL _ 0; mod: CARDINAL _ 0; MPReport[checkingHyper, mpInitialising]; OthelloDefs.WriteLine["Checking memory"]; WHILE offset < hyperEndPlus1-hyperStart DO wordCount: CARDINAL _ CARDINAL[MIN[(hyperEndPlus1-hyperStart)-offset, 101]]; FOR j: CARDINAL IN [0..wordCount) DO mod _ mod + 1; IF mod = 10 THEN {pattern _ pattern * 13 + 5; mod _ 0}; buffer[j] _ pattern; ENDLOOP; HyperRead[destPtr: @fromHyper[0], sourceOffset: offset, wordCount: wordCount]; FOR i: NAT IN [0..wordCount) DO IF fromHyper[i] # buffer[i] THEN DO p: CARDINAL _ Process.GetPriority[]; Process.SetPriority[7]; OthelloDefs.WriteLine["Problem with memory"]; MPReport[errorHiDigits, mpInitialising]; THROUGH [1..100000] DO ENDLOOP; ProcessorFace.SetMP[NAT[(offset+i)/1000]]; THROUGH [1..100000] DO ENDLOOP; MPReport[errorLoDigits, mpInitialising]; THROUGH [1..100000] DO ENDLOOP; ProcessorFace.SetMP[NAT[(offset+i) MOD 1000]]; THROUGH [1..100000] DO ENDLOOP; Process.SetPriority[p]; ERROR; ENDLOOP; ENDLOOP; offset _ offset + wordCount; ENDLOOP; END; MPReport[initUart, mpInitialising]; OthelloDefs.WriteLine["Initialising SLOT UART"]; DO s: RavenSlotDriver.PrinterStatus; DicentraInputOutput.Output[0H, @slot.uARTModeOrCmd]; DicentraInputOutput.Output[0H, @slot.uARTModeOrCmd]; DicentraInputOutput.Output[0H, @slot.uARTModeOrCmd]; DicentraInputOutput.Output[resetCommand, @slot.uARTModeOrCmd]; DicentraInputOutput.Output[configureUART, @slot.uARTModeOrCmd]; DicentraInputOutput.Output[rxEnable, @slot.uARTModeOrCmd]; IF (s _ GetStatus[])#statusRQtimeout THEN EXIT; DisplayBadStatusInMP[s]; OthelloDefs.WriteLine["Raven not answering"]; ENDLOOP; IF checkHyper THEN { DicentraInputOutput.SetNxmExpected[TRUE]; -- don't die on non-existant mem. StripeHyper[]; DicentraInputOutput.SetNxmExpected[FALSE]; MPReport[hyperOK, mpInitialising]; Susp[500]; OthelloDefs.WriteLine["Memory checks out OK"]; FOR i: CARDINAL IN [0..bufferSize] DO whiteBuffer[i] _ white; ENDLOOP; }; END; testCopies:CARDINAL _ 0; TestKeyPressed: ENTRY PROC[] RETURNS[yes:BOOLEAN _ FALSE] = BEGIN s:RavenSlotDriver.PrinterStatus; SELECT s _ ReceiveStatus[] FROM keyTest => yes_TRUE; IN [key0..key9] => { }; ENDCASE; END; TestProcess: PROC[] RETURNS[] = BEGIN Process.SetPriority[Process.priorityBackground]; DO s: RavenSlotDriver.PrinterStatus ; successCode: RavenSlotDriver.SuccessCode; UNTIL TestKeyPressed[] DO ENDLOOP; OthelloDefs.WriteLine["Printing test page"]; successCode _ PrintPage[0, 0, 3072, 3840, top, aligned]; SELECT successCode FROM warning => NULL; error => { p: CARDINAL _ Process.GetPriority[]; Process.SetPriority[7]; WHILE (s_GetStatus[])#standBy DO DisplayBadStatusInMP[s]; ENDLOOP; Process.SetPriority[p]; -- allow interrupts again }; ENDCASE => NULL; -- ok ENDLOOP; END; tester: PROCESS; Watchdog.Deactivate[]; Init[]; -- tester _ FORK TestProcess[]; OthelloDefs.WriteLine["Raven ready for service"]; END. *RavenSlotDriverImpl.mesa Mik Lamming, December 9, 1983 1:25 pm ** Dicentra hyperspace configuration constants ** Raven constants ** Slot paraphenalia ** Slot command codes ** Status masks ** Maintenance panel codes ** Miscellaneous dross *** PUBLIC PROCEDURES AND VARIABLES *** The destination area is referred to by an offset from the beginning of hyperspace. The microcode that implements WriteHyper has a feature that prevents it writing data across a 64K hyperspace boundary. Thats why some transfers have to be done in two parts. use Inline.LowHalf above because MOD on LONG CARDINAL generates bad code Returns the Raven status. Note the extra status code statusRQtimeout which gets returned if the Raven failed to answer the request for status. show the Raven status with a 1300 code Returns when page is complete or an unrecoverable error has occurred. If error use LastStatus to find out why. If warning investigate outputTrayFullFlag and lowTonerFlag Feed a page and return useful status bytes: warming, feederFault, registrationJam, fuserJam, noExit, interlockOpen, fuserCold, parityError, illegalCharacter, illegalSequence, noPaper, pageSync, goingOffLine, offLine, statusOverRun Move scanLineWords into the Slot buffer in IO space using microcode loop Wait for Slot buffer to empty lines times - Returns FALSE if a timeout occured. *** CHECK FOR REASONABLE PARAMETERS *** *** SET UP MARGIN DIMENSIONS *** *** START PAGE ROLLING *** *** WRITE WHITE INTO MARGIN *** *** WRITE CLIENT DATA TILL EXHAUSTED *** get a scan lines worth of data from hyper to my buffer *** FINISH OFF WITH SOME WHITE SPACE AGAIN *** *** WAIT FOR PAGE TO LAND IN OUTPUT HOPPER *** Used to check configuration values at start up The destination area is referred to by an offset from the beginning of hyperspace. Has to cope with microcode feature which will not transfer across 64K boundaries Suspend for 'n' milliseconds Display status and status code in Dicentra MP ***** Initialize the UART ***** PatternHyper[103]; CheckHyper[103]; testCopies _ testCopies*10+CARDINAL[s-key0] MOD 100; ÊG˜J™J™%J™šÏk ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜Jšœ ˜ —J™šœœ˜JšœR˜YJšœ˜—J˜J˜Jšœ.™.JšœK˜KJšœ/œ ˜AJ˜J™Jšœœ˜JšœœÏc$˜EJšœœ˜Jšœœ˜J˜J™Jšœ œœ ž˜=Jš œœœœœ ˜%šœ œœ˜Jšœ œ˜Jšœ œ˜Jšœ œ˜Jšœœ˜Jšœ œ˜—Jšœœ˜ J˜J™Jšœœ˜!Jšœœ ˜#Jšœœ ž(˜HJšœœ ž-˜NJšœ œ ž˜9Jšœ œ ˜Jšœ œ ˜Jšœ œ ˜J˜J™Jšœ œ˜Jšœ œ˜Jšœ œ˜J˜Jšœ œž0˜LJš œœœœœ˜,Jš œœœœœ˜3Jšœ%œ˜7Jšœ&œ˜8J˜J˜J™šœœ˜Jšœ*œ˜1Jšœ.œ˜5Jšœ1œ˜8Jšœ/œ˜6Jšœ)œ˜0Jšœ/œ˜7Jšœ/œ˜7—Jšœœ˜Jšœ œ˜Jšœ œ˜Jšœœ˜J˜J™Jšœ œœœ ˜(J˜J˜J˜J˜J™'J™JšÏnœ œœ˜1JšŸ œ œœ˜#J™JšŸœœœ˜+JšŸ œœœ˜%J˜šŸ œ œœœœœœœ œœ˜wJ™RJšœ­™­Jšœœ"œœœœœœœ˜Œšœ ˜šœœœ)˜FJšœ!Ïsœ œ œ™H—Jšœ œœœ)˜JJšœ\˜\Jšœ!˜!Jšœ#˜#Jšœ!˜!Jš˜—Jšœ˜J˜—š Ÿ œ œœœ˜JJšœŽ™ŽJ˜Jšœ˜Jšœ˜J˜—šŸœ œœ˜KJ™&Jšœ˜Jšœ˜J˜—š Ÿ œœœ!œZœ!˜äJšœE™EJšœ Ïf œ™(Jšœ¡œ¡ ™:J™Jšœœ˜"Jšœœ˜!Jšœœ˜!Jšœœ˜Jšœ œœ˜Jšœœž˜LJšœœž&˜KJ˜š Ÿœœœœ˜>™,Jš¡º™º—šœ œ˜'Jšœœœœ˜(Jšœœœœ˜+—Jšœ˜š˜šœž2˜RJšœ!žÐcfž ¢ žœž¢ž ¢ œMœ˜ÔJšœœž˜/—Jš˜—Jšœ˜ Jšœ˜—J˜šŸœœ œ˜3Jšœ¡ œœ™HJšœœ ˜/JšœT˜TJšœ˜—J˜š Ÿ œ œ œœœ˜>Jšœ¡œ-™PšŸ œ œœœ˜,Jšœœ/˜:Jšœœ˜*Jšœ˜—šœœœ ˜ Jšœœ ˜šœœ˜Jšœ˜Jšœ œœœ˜Jšœ˜—Jšœ˜—Jšœœž ˜Jšœ˜J˜—J˜Jšœ'™'šœ+œœ˜8Jšœ:˜:Jšœœ˜1Jšœ˜—šœ-œœ˜:šœœœ˜+Jšœ4œ˜;Jšœ!˜!Jšœ˜Jšœ˜—šœ˜JšœCœ˜JJšœ&œ˜>Jšœ˜—Jšœ˜—Jšœ"˜"J™J™ JšœN˜NJšœB˜BJšœ œœ:ž%˜sJ˜J™šœœž.˜SJšœ˜šœ˜ Jšœ@˜@Jšœ2˜2Jšœ2˜2Jšœ8˜8Jšœ7˜7Jšœ4˜4Jšœ8˜8Jšœ/˜/Jšœ0˜7—Jšœ˜Jšœ˜—Jšœ˜J˜J™Jšœž˜0Jšœž¢ž ˜@Jšœ9ž˜Išœœœž"˜AJšœ&˜&Jšœž˜2Jšœ ˜J˜—Jšœ"ž¢ž ˜@š œœœž¢ž¢ž˜SJšœ&˜&Jšœž˜2Jšœ ˜J˜—J˜J™(šœœ˜Jšœ(˜(Jšœ˜—šœ˜šœœœ˜(Jšœ6™6JšœX˜XJšœž ˜>Jšœ*˜*šœœœ˜Jšœ&˜&Jšœž˜2Jšœ˜J˜—Jšœ˜——J˜J™.Jšœ˜šœœœ˜Jšœ&˜&Jšœž˜2Jšœ ˜J˜—Jšœž)˜HJšœ8ž ˜DJ˜Jšœž˜2J˜J™.š˜Jšœ˜šœ˜ Jšœœ˜Jšœ!ž¢ž ¢ žœž¢ž ¢ œLœ˜Óšœ˜Jšœ*˜*J˜—šœ˜ Jšœœœ˜Jšœ˜Jšœ%˜%Jšœ@˜@Jšœ˜J˜——Jš˜—J˜Jšœ'˜'šœœ˜#Jšœœ7˜LJšœœ?˜YJšœ ˜J˜—šœ˜Jšœœœ˜Jšœ%˜%Jšœ.˜.Jšœ˜ J˜—Jšœ˜J˜—š Ÿœœœœœ"˜XJ™.Jšœœœœ˜!Jšœœ˜Jšœ˜J˜—šŸ œœ œœœœœœ œœ˜nJ™£šœ ˜Jšœœœ+˜HJšœ œœœ)˜JJšœ`œœ˜nJšœ[˜[Jšœ˜Jšœ'˜'Jšœ!˜!Jš˜—Jšœ˜—J˜J˜š Ÿœœœœ˜)J™Jšœ%˜%šœ˜J˜——š Ÿœœœœ˜KJšœ+™-Jšœœœ ˜2Jšœ˜—J˜J˜Jšœœœ˜$J˜šŸ œ œ œ˜.šŸ œ œœœ˜*Jšœœ1˜˜>Jšœ?˜?Jšœ:˜:Jšœ#œœ˜/Jšœ˜Jšœ-˜-Jšœ˜—J™šœ œ˜Jšœ#œž!˜KJšœ™Jšœ™J˜Jšœ#œ˜*Jšœ-˜-Jšœ.˜.šœœœ˜%J˜Jš ˜ —J˜—Jšœ˜J˜—Jšœ œ˜š Ÿœœœœœœ˜AJšœ ˜ šœ˜Jšœœ˜šœ˜Jšœœ œ™4J˜—Jšœ˜—Jšœ˜J˜—šŸ œœœ˜%Jšœ0˜0šœ˜Jšœ"˜"Jšœ)˜)Jšœœœ˜"Jšœ,˜,Jšœ8˜8šœ ˜Jšœ œ˜šœ ˜ Jšœœ˜$Jšœ˜šœ˜ Jšœ˜Jšœ˜—Jšœž˜2Jšœ˜—Jšœœž˜—Jšœ˜—Jšœ˜—J˜Jšœœ˜Jšœ˜J˜Jšœ œ˜Jšœ1˜1Jšœ˜J˜—…—=ZYË