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º