DIRECTORY DisplayFace USING [ Connect, cursorPosition, Disconnect, GetBitBltTable, globalStateSize, hasBorder, hasBuffer, height, Initialize, InitializeCleanup, pagesForBitmap, pixelsPerInch, SetBackground, SetBorderPattern, SetCursorPattern, TurnOff, TurnOn, width], KeyboardFace USING [keyboard], Keys USING [KeyBits], MouseFace USING [position, SetPosition], PrincOps USING [BBTable, BYTE], PrincOpsUtils USING [AllocateNakedCondition], Process USING [ Detach, GetPriority, MsecToTicks, Pause, Priority, priorityForeground, SetPriority, Ticks], Terminal USING [ BitmapState, BWBackground, BWCursorBitmap, Position, SetBWCursorPosition, SetMousePosition, SwapAction, SwapNotifier, Object, Virtual], VM USING [Allocate, CantAllocate, Free, Interval, lowCore, Pin, Unpin], VMSideDoor USING [AssignSpecialRealMemory, ReleaseSpecialRealMemory]; TerminalImpl: CEDAR MONITOR LOCKS terminalLock IMPORTS DisplayFace, KeyboardFace, MouseFace, PrincOpsUtils, Process, Terminal, VM, VMSideDoor EXPORTS Terminal SHARES Terminal = BEGIN Virtual: TYPE = Terminal.Virtual; TerminalList: TYPE = LIST OF Virtual; VirtualImpl: TYPE = REF VirtualImplObject; VirtualImplObject: TYPE = RECORD [ keyboard: Keys.KeyBits _ ALL[up], mouse: Terminal.Position _ [0, 0], cursor: Terminal.Position _ [0, 0], pattern: Terminal.BWCursorBitmap _ ALL[0], bwBitmapState: Terminal.BitmapState _ none, bwBackground: Terminal.BWBackground _ white, bwBorderOdd: PrincOps.BYTE _ 0, bwBorderEven: PrincOps.BYTE _ 0, bwBitmap: VM.Interval _ NULL, bwSavedBitMap: VM.Interval _ NULL, notifiers: Notifier _ NIL ]; Notifier: TYPE = REF NotifierItem; NotifierItem: TYPE = RECORD [ next, prev: Notifier, proc: Terminal.SwapNotifier ]; priorityDuringSelect: Process.Priority = Process.priorityForeground; blinkTime: Process.Ticks = Process.MsecToTicks[100]; terminalLock: PUBLIC MONITORLOCK; terminals: TerminalList; current: Virtual _ NIL; lockDepth: NAT _ 0; terminalChanging: BOOL _ FALSE; terminalStable: CONDITION _ [timeout: 0]; bwRetrace: LONG POINTER TO CONDITION; meFirst: BOOL _ TRUE; verticalRetrace: CONDITION _ [timeout: 0]; CantDoIt: PUBLIC ERROR = CODE; Create: PUBLIC PROC RETURNS [vt: Virtual] = { AddToList: ENTRY PROC [vt: Virtual] = INLINE {terminals _ CONS[vt, terminals]}; AddToList[vt _ NewVirtual[]]; }; Select: PUBLIC PROC [vt: Virtual _ NIL, lock: BOOL _ FALSE] RETURNS [worked: BOOL] = { old: Virtual _ current; new: Virtual _ vt; AcquisitionOutcome: TYPE = {cantSelect, correctTerminal, swapNeeded}; AcquireForSelect: ENTRY PROC RETURNS [AcquisitionOutcome] = INLINE { WHILE terminalChanging DO WAIT terminalStable; ENDLOOP; IF new = NIL THEN FOR t: TerminalList _ terminals, terminals.rest UNTIL t = NIL DO IF t.first = current THEN { new _ (IF t.rest = NIL THEN terminals ELSE t.rest).first; EXIT }; REPEAT FINISHED => ERROR; ENDLOOP; IF lockDepth > 0 AND old ~= new THEN RETURN[cantSelect]; IF lock THEN lockDepth _ lockDepth + 1; RETURN[IF (terminalChanging _ old ~= new) THEN swapNeeded ELSE correctTerminal] }; NotifyNewTerminal: ENTRY PROC = INLINE { terminalChanging _ FALSE; BROADCAST terminalStable; }; DoNotifiers: PROC [vt: Virtual, action: Terminal.SwapAction] = { impl: VirtualImpl = NARROW[vt.impl]; head: Notifier = impl.notifiers; n: Notifier _ impl.notifiers; IF head = NIL THEN RETURN; DO n.proc[vt, action]; IF (n _ IF action = coming THEN n.next ELSE n.prev) = head THEN EXIT; ENDLOOP; }; FlipTerminal: ENTRY PROC [old, new: Virtual] = INLINE { UnloadTerminal[old]; current _ new; LoadTerminal[new]; }; SELECT AcquireForSelect[] FROM cantSelect => RETURN[FALSE]; correctTerminal => NULL; swapNeeded => { priority: Process.Priority = Process.GetPriority[]; IF priority < priorityDuringSelect THEN TRUSTED {Process.SetPriority[priorityDuringSelect]}; DoNotifiers[old, going]; DoNotifiers[new, coming]; FlipTerminal[old: old, new: new]; DoNotifiers[old, gone]; DoNotifiers[new, here]; IF priority < priorityDuringSelect THEN TRUSTED {Process.SetPriority[priority]}; NotifyNewTerminal[]; }; ENDCASE; RETURN[TRUE] }; Current: PUBLIC ENTRY PROC RETURNS [vt: Virtual, lockCount: NAT] = { WaitUntilStable[]; RETURN [vt: current, lockCount: lockDepth] }; PermitSwaps: PUBLIC ENTRY PROC [vt: Virtual] = { IF current ~= vt OR lockDepth = 0 THEN RETURN; lockDepth _ lockDepth - 1; }; PreventSwaps: PUBLIC ENTRY PROC [vt: Virtual] = { WaitUntilSelected[vt]; lockDepth _ lockDepth + 1; }; RegisterNotifier: PUBLIC ENTRY PROC [vt: Virtual, notifier: Terminal.SwapNotifier] = { impl: VirtualImpl = NARROW[vt.impl]; n: Notifier = NEW[NotifierItem _ [next: NIL, prev: NIL, proc: notifier]]; head: Notifier = impl.notifiers; IF head = NIL THEN n.next _ n.prev _ n ELSE {n.next _ head; n.prev _ head.prev; head.prev.next _ n; head.prev _ n}; impl.notifiers _ n; }; UnregisterNotifier: PUBLIC ENTRY PROC [vt: Virtual, notifier: Terminal.SwapNotifier] = { impl: VirtualImpl = NARROW[vt.impl]; head: Notifier = impl.notifiers; n: Notifier _ impl.notifiers; IF head ~= NIL THEN DO IF n.proc = notifier THEN { n.prev.next _ n.next; n.next.prev _ n.prev; IF n = head THEN impl.notifiers _ IF n.next = n THEN NIL ELSE n.next; EXIT }; IF (n _ n.next) = head THEN EXIT; ENDLOOP; }; KeyboardWatcher: PROC = TRUSTED { KeysRecord: TYPE = RECORD [ SELECT OVERLAID * FROM bits => [bits: Keys.KeyBits], words => [words: ARRAY [0..SIZE[Keys.KeyBits]) OF WORD], ENDCASE ]; keyboard: LONG POINTER TO KeysRecord = LOOPHOLE[KeyboardFace.keyboard]; waitTime: Process.Ticks = Process.MsecToTicks[300]; lastTime: KeysRecord _ keyboard^; magicCombination: KeysRecord _ [words[words: ALL[177777B]]]; magicCombination.bits[Ctrl] _ magicCombination.bits[LeftShift] _ magicCombination.bits[RightShift] _ down; Process.SetPriority[Process.priorityForeground]; DO Process.Pause[waitTime]; IF lockDepth = 0 THEN { thisTime: KeysRecord = keyboard^; changed: BOOL _ FALSE; select: BOOL _ TRUE; FOR word: NAT IN [0..SIZE[KeysRecord]) DO thisWord: WORD = thisTime.words[word]; IF thisWord ~= lastTime.words[word] THEN changed _ TRUE; IF thisWord ~= magicCombination.words[word] THEN select _ FALSE; ENDLOOP; IF changed THEN { lastTime _ thisTime; IF select THEN [] _ Select[NIL]; }; }; ENDLOOP; }; SetMousePosition: PUBLIC ENTRY PROC [vt: Virtual, position: Terminal.Position] = { impl: VirtualImpl = NARROW[vt.impl]; IF current = vt THEN MouseFace.SetPosition[LOOPHOLE[position]] ELSE impl.mouse _ position; }; GetBWCursorPattern: PUBLIC ENTRY PROC [vt: Virtual] RETURNS [pattern: Terminal.BWCursorBitmap] = { impl: VirtualImpl = NARROW[vt.impl]; RETURN[impl.pattern] }; SetBWCursorPattern: PUBLIC ENTRY PROC [vt: Virtual, pattern: Terminal.BWCursorBitmap] = { impl: VirtualImpl = NARROW[vt.impl]; impl.pattern _ pattern; IF current = vt THEN TRUSTED {DisplayFace.SetCursorPattern[LOOPHOLE[LONG[@pattern]]]}; }; GetBWBitmapState: PUBLIC ENTRY PROC [vt: Virtual] RETURNS [Terminal.BitmapState] = { impl: VirtualImpl = NARROW[vt.impl]; RETURN [impl.bwBitmapState] }; SetBWBitmapState: PUBLIC ENTRY PROC [vt: Virtual, new: Terminal.BitmapState] RETURNS [old: Terminal.BitmapState] = { ENABLE UNWIND => NULL; impl: VirtualImpl = NARROW[vt.impl]; TurnOff: INTERNAL PROC = { DisplayFace.TurnOff[]; lockDepth _ lockDepth + 1; WaitForBWVerticalRetraceInternal[vt]; WaitForBWVerticalRetraceInternal[vt]; lockDepth _ lockDepth - 1; IF DisplayFace.hasBuffer THEN VMSideDoor.ReleaseSpecialRealMemory[impl.bwBitmap] ELSE VM.Unpin[impl.bwBitmap]; }; IF (old _ impl.bwBitmapState) = new THEN RETURN; IF old = none THEN { impl.bwBitmap _ AllocateBWBitmap[]; IF current = vt THEN DisplayFace.Connect[impl.bwBitmap.page]; IF (impl.bwBitmapState _ new) = allocated THEN RETURN; }; SELECT new FROM displayed => IF current = vt THEN { IF DisplayFace.hasBuffer THEN VMSideDoor.AssignSpecialRealMemory[impl.bwBitmap] ELSE VM.Pin[impl.bwBitmap]; DisplayFace.TurnOn[]; }; allocated => IF current = vt THEN TurnOff[]; none => { IF current = vt THEN {TurnOff[]; DisplayFace.Disconnect[]}; TRUSTED {VM.Free[impl.bwBitmap]}; }; ENDCASE; impl.bwBitmapState _ new; }; GetBWBackground: PUBLIC ENTRY PROC [vt: Virtual] RETURNS [Terminal.BWBackground] = { impl: VirtualImpl = NARROW[vt.impl]; RETURN [impl.bwBackground] }; SetBWBackground: PUBLIC ENTRY PROC [vt: Virtual, new: Terminal.BWBackground] RETURNS [old: Terminal.BWBackground] = { impl: VirtualImpl = NARROW[vt.impl]; IF (old _ impl.bwBackground) = new THEN RETURN; impl.bwBackground _ new; IF vt = current THEN DisplayFace.SetBackground[IF new = white THEN white ELSE black]; }; GetBWBorder: PUBLIC ENTRY PROC [vt: Virtual] RETURNS [oddPairs, evenPairs: PrincOps.BYTE] = { impl: VirtualImpl = NARROW[vt.impl]; RETURN [impl.bwBorderOdd, impl.bwBorderEven] }; SetBWBorder: PUBLIC ENTRY PROC [vt: Virtual, oddPairs, evenPairs: PrincOps.BYTE] = { impl: VirtualImpl = NARROW[vt.impl]; impl.bwBorderOdd _ oddPairs; impl.bwBorderEven _ evenPairs; IF DisplayFace.hasBorder AND vt = current THEN DisplayFace.SetBorderPattern[oddPairs: oddPairs, evenPairs: evenPairs]; }; GetBitBltTable: PUBLIC ENTRY UNSAFE PROC [vt: Virtual] RETURNS [bbt: PrincOps.BBTable] = { RETURN[DisplayFace.GetBitBltTable[]] }; WaitForBWVerticalRetrace: PUBLIC ENTRY PROC [vt: Virtual] = { WaitUntilSelected[vt]; WaitForBWVerticalRetraceInternal[vt]; }; BlinkBWDisplay: PUBLIC PROC [vt: Virtual] = { background: Terminal.BWBackground; PreventSwapsCurrent[]; background _ NARROW[vt.impl, VirtualImpl].bwBackground; DisplayFace.SetBackground[IF background = white THEN black ELSE white]; Process.Pause[blinkTime]; DisplayFace.SetBackground[IF background = white THEN white ELSE black]; PermitSwapsCurrent[]; }; WaitUntilStable: INTERNAL PROC = { WHILE terminalChanging DO WAIT terminalStable; ENDLOOP; }; WaitUntilSelected: INTERNAL PROC [vt: Virtual] = { UNTIL current = vt DO WAIT terminalStable; ENDLOOP; }; PreventSwapsCurrent: ENTRY PROC = INLINE { WaitUntilStable[]; lockDepth _ lockDepth + 1; }; PermitSwapsCurrent: ENTRY PROC = INLINE { lockDepth _ lockDepth - 1; }; WaitForBWVerticalRetraceInternal: INTERNAL PROC [vt: Virtual] = { IF meFirst THEN { meFirst _ FALSE; TRUSTED {WAIT bwRetrace^}; BROADCAST verticalRetrace; meFirst _ TRUE; } ELSE WAIT verticalRetrace; }; LoadTerminal: PROC [vt: Virtual] = TRUSTED { vtImpl: VirtualImpl = NARROW[vt.impl]; vt.keyboard _ LOOPHOLE[KeyboardFace.keyboard]; vt.mouse _ LOOPHOLE[MouseFace.position]; MouseFace.SetPosition[LOOPHOLE[vtImpl.mouse]]; vt.bwCursor _ LOOPHOLE[DisplayFace.cursorPosition]; vt.bwCursor^ _ LOOPHOLE[vtImpl.cursor]; DisplayFace.SetBackground[IF vtImpl.bwBackground = white THEN white ELSE black]; DisplayFace.SetBorderPattern[oddPairs: vtImpl.bwBorderOdd, evenPairs: vtImpl.bwBorderEven]; DisplayFace.SetCursorPattern[@vtImpl.pattern]; SELECT vtImpl.bwBitmapState FROM displayed => { DisplayFace.Connect[vtImpl.bwBitmap.page]; IF DisplayFace.hasBuffer THEN VMSideDoor.AssignSpecialRealMemory[vtImpl.bwBitmap] ELSE VM.Pin[vtImpl.bwBitmap]; DisplayFace.TurnOn[]; }; allocated => { DisplayFace.Connect[vtImpl.bwBitmap.page]; IF DisplayFace.hasBuffer THEN VMSideDoor.AssignSpecialRealMemory[vtImpl.bwBitmap]; }; none => NULL; ENDCASE; }; UnloadTerminal: PROC [vt: Virtual] = TRUSTED { vtImpl: VirtualImpl = NARROW[vt.impl]; vtImpl.keyboard _ LOOPHOLE[KeyboardFace.keyboard^]; vt.keyboard _ @vtImpl.keyboard; vtImpl.mouse _ LOOPHOLE[MouseFace.position^]; vt.mouse _ @vtImpl.mouse; vtImpl.cursor _ LOOPHOLE[DisplayFace.cursorPosition^]; vt.bwCursor _ @vtImpl.cursor; SELECT vtImpl.bwBitmapState FROM displayed => { DisplayFace.TurnOff[]; IF DisplayFace.hasBuffer THEN VMSideDoor.ReleaseSpecialRealMemory[vtImpl.bwBitmap] ELSE VM.Unpin[vtImpl.bwBitmap]; DisplayFace.Disconnect[]; }; allocated => { IF DisplayFace.hasBuffer THEN VMSideDoor.ReleaseSpecialRealMemory[vtImpl.bwBitmap]; DisplayFace.Disconnect[]; }; none => NULL; ENDCASE; }; NewVirtual: PROC RETURNS [vt: Virtual] = { vtImpl: VirtualImpl = NEW[VirtualImplObject _ []]; TRUSTED { vt _ NEW[Terminal.Object _ [ keyboard: LOOPHOLE[@vtImpl.keyboard], mouse: LOOPHOLE[@vtImpl.mouse], hasBlackAndWhiteDisplay: TRUE, bwWidth: DisplayFace.width, bwHeight: DisplayFace.height, bwHasBorder: DisplayFace.hasBorder, bwPixelsPerInch: DisplayFace.pixelsPerInch, bwCursor: LOOPHOLE[@vtImpl.cursor], hasColorDisplay: FALSE, colorWidth: 0, colorHeight: 0, colorPixelsPerInch: 0, colorDisplayType: NULL, colorMode: [FALSE, 0, 0], colorBitmapA: NIL, colorBitmapB: NIL, colorWordsPerLineA: 0, colorWordsPerLineB: 0, impl: LOOPHOLE[vtImpl] ]]; }; }; AllocateBWBitmap: PROC RETURNS [interval: VM.Interval] = { interval _ VM.Allocate[count: DisplayFace.pagesForBitmap, in64K: TRUE ! VM.CantAllocate => GO TO cant]; EXITS cant => ERROR CantDoIt; }; Initialize: PROC = TRUSTED { WordSequence: TYPE = RECORD [SEQUENCE COMPUTED CARDINAL OF WORD]; headGlobalP: LONG POINTER = VM.lowCore.NEW[WordSequence[DisplayFace.globalStateSize]]; mask: WORD; vt: Virtual = NewVirtual[]; initialPosition: Terminal.Position; [bwRetrace, mask] _ PrincOpsUtils.AllocateNakedCondition[]; DisplayFace.Initialize[headGlobalP, mask]; DisplayFace.InitializeCleanup[]; initialPosition _ [x: vt.bwWidth/2, y: vt.bwHeight/2]; Terminal.SetMousePosition[vt, initialPosition]; Terminal.SetBWCursorPosition[vt, initialPosition]; LoadTerminal[current _ vt]; terminals _ CONS[current, NIL]; Process.Detach[FORK KeyboardWatcher[]]; }; Initialize[]; END.  TerminalImpl.mesa last edited by: Levin on: June 30, 1983 3:52 pm Types Global variables protected by the monitor lock Exports to Terminal In the following, [bits[bits: ALL[up]]] doesn't quite work, since the number of bits in a Keys.KeyBits isn't evenly divisible by bitsPerWord, causing the excess bits in the last word not to be initialized. This leads to trouble in the word-oriented comparisons in the main loop. Mouse Black-and-White Cursor Black-and-White Display Internal Procedures Initialization �ʬ˜Jšœ™Jšœ/™/J˜šÏk ˜ šœ �œ˜Jšœí˜í—Jšœ �œ ˜Jšœ�œ ˜Jšœ �œ˜(Jšœ �œ �œ˜Jšœ�œ˜-šœ�œ˜Jšœ[˜[—šœ �œ˜Jšœ‡˜‡—Jš�œ�œ?˜GJšœ �œ5˜EJ˜—šœ�œ�œ�œ ˜.š�˜JšœH�œ ˜V—Jš�œ ˜Jš�œ ˜—J˜Jš�˜J˜J™J™Jšœ �œ˜!J˜Jšœ�œ�œ�œ ˜%J˜Jšœ �œ�œ˜*šœ�œ�œ˜"Jšœ�œ˜!Jšœ"˜"Jšœ#˜#Jšœ#�œ˜*Jšœ+˜+Jšœ,˜,Jšœ�œ˜Jšœ�œ˜ Jšœ �œ �œ˜Jšœ�œ �œ˜"Jšœ�˜J˜—J˜Jšœ �œ�œ˜"šœ�œ�œ˜Jšœ˜J˜J˜—J˜JšœD˜DJ˜4J™J™J™.J™Jšœ�œ� œ˜!J˜Jšœ˜Jšœ�œ˜J˜Jšœ �œ˜J˜Jšœ�œ�œ˜Jšœ� œ˜)J˜Jšœ �œ˜%Jšœ �œ�œ˜Jšœ� œ˜*J˜Jšœ™J™J™Jšœ �œ�œ�œ˜J˜šÏnœ�œ�œ�œ˜-Jš ž œ�œ�œ�œ�œ˜OJšœ˜Jšœ˜—J˜šžœ� œ�œ�œ�œ�œ �œ˜VJ˜J˜Jšœ�œ-˜Eš žœ�œ�œ�œ�œ˜DJš�œ�œ�œ�œ˜7š�œ�œ�˜š�œ-�œ�œ�˜@š�œ�œ˜Jš œ�œ �œ�œ �œ˜9Jš�˜J˜—š�˜Jš�œ�œ˜—Jš�œ˜——Jš�œ�œ �œ�œ ˜8Jš�œ�œ˜'Jš�œ�œ!�œ �œ˜OJ˜—šžœ�œ�œ�œ˜(Jšœ�œ˜Jš� œ˜J˜—šž œ�œ/˜@Jšœ�œ ˜$J˜ J˜Jš�œ�œ�œ�œ˜š�˜J˜Jš �œ�œ�œ�œ�œ�œ˜EJš�œ˜—J˜—šž œ�œ�œ�œ˜7J˜J˜Jšœ˜J˜—š�œ�˜Jšœ�œ�œ˜Jšœ�œ˜˜J˜3š�œ!�˜'Jš�œ,˜4—Jšœ˜Jšœ˜J˜!Jšœ˜Jšœ˜š�œ!�˜'Jš�œ ˜(—J˜J˜—Jš�œ˜—Jš�œ�œ˜ J˜—J˜š žœ�œ�œ�œ�œ�œ˜DJ˜Jš�œ$˜*J˜—J˜šž œ� œ�œ˜0Jš�œ�œ�œ�œ˜.Jšœ˜J˜J˜—šž œ� œ�œ˜1J˜Jšœ˜J˜—J˜šžœ�œ�œ�œ3˜VJšœ�œ ˜$Jšœ�œ�œ�œ˜IJ˜ Jš�œ�œ�œ˜&Jš�œH˜LJ˜J˜—J˜šžœ�œ�œ�œ3˜XJšœ�œ ˜$J˜ J˜š�œ �œ�˜š�˜š�œ�œ˜J˜J˜Jš �œ �œ�œ �œ�œ�œ˜EJš�˜J˜—Jš�œ�œ�œ˜!Jš�œ˜——J˜—J˜šžœ�œ�œ˜!šœ �œ�œ˜š�œ�œ�˜J˜Jš œ�œ�œ�œ�œ˜8Jš�˜J˜——Jš œ �œ�œ�œ�œ˜GJšœ3˜3Jšœ!˜!Jšœ—™—Jšœ-�œ ˜<˜@J˜)—J˜0š�˜Jšœ˜š�œ�œ˜Jšœ!˜!Jšœ �œ�œ˜Jšœ�œ�œ˜š �œ�œ�œ�œ�˜)Jšœ �œ˜&Jš�œ"�œ �œ˜8Jš�œ*�œ �œ˜@Jš�œ˜—š�œ �œ˜Jšœ˜Jš�œ�œ �œ˜ J˜—J˜—Jš�œ˜—J˜—J˜J˜J™˜J˜—šžœ�œ�œ�œ/˜RJšœ�œ ˜$Jš�œ�œ�œ ˜>Jš�œ˜J˜J˜—Jšœ™™J˜—šžœ�œ˜3Jš�œ'˜.Jšœ�œ ˜$Jš�œ˜J˜J˜—šžœ�œ4˜YJšœ�œ ˜$J˜Jš �œ�œ�œ�œ�œ˜VJ˜J˜—Jšœ™J˜šžœ�œ�œ˜TJšœ�œ ˜$Jš�œ˜J˜—J˜šžœ�œ)˜LJš�œ ˜'Jš�œ�œ�œ˜Jšœ�œ ˜$šžœ� œ˜J˜J˜J˜%J˜%J˜Jš�œ�œ3˜PJš�œ�œ˜J˜—Jš�œ"�œ�œ˜0š�œ �œ˜J˜#Jš�œ�œ)˜=Jš�œ(�œ�œ˜6J˜—š�œ�˜˜ š�œ�œ˜Jš�œ�œ2˜OJš�œ�œ˜Jšœ˜J˜——Jšœ �œ�œ ˜,˜ Jš�œ�œ'˜;Jš�œ�œ˜!J˜—Jš�œ˜—Jšœ˜J˜J˜—š žœ�œ�œ�œ�œ˜TJšœ�œ ˜$Jš�œ˜J˜J˜—šžœ�œ�œ�œ*˜LJš�œ!˜(Jšœ�œ ˜$Jš�œ!�œ�œ˜/Jšœ˜š�œ�˜Jšœ�œ �œ�œ˜@—J˜J˜—šž œ�œ� œ˜,Jš�œ �œ˜0Jšœ�œ ˜$Jš�œ&˜,J˜—J˜šž œ�œ� œ-�œ˜TJšœ�œ ˜$Jšœ˜Jšœ˜š�œ�œ�˜.JšœG˜G—J˜J˜—šžœ�œ˜6Jš�œ˜#Jš�œ˜$J˜J˜—šžœ�œ� œ˜=J˜J˜%J˜J˜—šžœ� œ˜-J˜"J˜Jšœ �œ$˜7Jšœ�œ�œ�œ˜GJ˜Jšœ�œ�œ�œ˜GJ˜J˜—J˜J™J˜šžœ�œ�œ˜"Jš�œ�œ�œ�œ˜7J˜—J˜šžœ�œ�œ˜2Jš�œ�œ�œ�œ˜3J˜J˜—šžœ�œ�œ�œ˜*J˜J˜J˜—J˜šžœ�œ�œ�œ˜)J˜J˜—J˜šž œ�œ�œ˜Aš�œ �œ˜Jšœ �œ˜Jš�œ�œ ˜Jš� œ˜Jšœ �œ˜J˜—Jš�œ�œ˜J˜J˜—šž œ�œ�œ˜,Jšœ�œ ˜&Jšœ�œ˜.Jšœ �œ˜(Jšœ�œ˜.Jšœ�œ˜3Jšœ�œ˜'Jšœ�œ�œ�œ˜PJšœ[˜[Jšœ.˜.š�œ�˜ ˜Jšœ*˜*Jš�œ�œ4˜QJš�œ�œ˜J˜J˜—˜Jšœ*˜*Jš�œ�œ5˜RJ˜—Jšœ�œ˜ Jš�œ˜—J˜—J˜šžœ�œ�œ˜.Jšœ�œ ˜&Jšœ�œ˜3Jšœ˜Jšœ�œ˜-Jšœ˜Jšœ�œ˜6Jšœ˜š�œ�˜ ˜J˜Jš�œ�œ5˜RJš�œ�œ˜J˜J˜—˜Jš�œ�œ6˜SJ˜J˜—Jšœ�œ˜ Jš�œ˜—J˜J˜—šž œ�œ�œ˜*Jšœ�œ˜2š�œ˜ šœ�œ˜Jšœ �œ˜%Jšœ�œ˜Jšœ�œ˜Jšœ˜Jšœ˜Jšœ#˜#Jšœ+˜+Jšœ �œ˜#Jšœ�œ˜Jšœ˜Jšœ˜Jšœ˜Jšœ�œ˜Jšœ �œ˜Jšœ�œ˜Jšœ�œ˜Jšœ˜Jšœ˜Jšœ�œ˜J˜—J˜—J˜—J˜šžœ�œ�œ �œ˜:šœ ˜ š�œ4�˜:Jšœ�œ�œ�œ˜!——š�˜Jšœ�œ ˜—J˜—J™Jšœ™J™šž œ�œ�œ˜Jšœ�œ�œ�œ�œ�œ�œ�œ˜AJš œ �œ�œ�œ �œ,˜VJšœ�œ˜ Jšœ˜J˜#J˜;J˜*J˜ Jšœ6˜6J˜/J˜2J˜Jšœ �œ �œ˜Jšœ�œ˜'J˜—J˜J˜ J˜Jš�œ˜J˜J˜—…—4Fº