DIRECTORY Carets USING [ResumeCarets, SuspendCarets], ColorWorld USING [TurnOffColor, TurnOnColor], Cursors USING [CursorType, GetCursor, SetCursor], InputFocus USING [CaptureButtons, inputEnabled, ReleaseButtons, WindowManagerTIPTable], InterminalExtra USING [InsertAction], Imager USING [black, ClipIntRectangle, Color, Context, DoSave, MaskIntRectangle, IntScaleT, SetColor, IntTranslateT, white], Menus, MenusPrivate USING [AlterDebuggingLevel, ClearMenu, DrawMenu, HitMenu, MarkMenu, ReComputeWindowMenus, ViewerlessAddMenu, ViewerMenus], MessageWindow USING [Append, Blink], TIPUser USING [TIPScreenCoords, TIPScreenCoordsRec], UserTerminal USING [BlinkDisplay], ViewerClasses, ViewerOps USING [AcquireContext, Adjust, ChangeColumn, CloseViewer, DestroyViewer, EnumerateViewers, EnumProc, GrowViewer, InitialiseColorPainting, InvisiblePaint, MouseInViewer, PaintViewer, ReleaseContext, TopViewer], ViewerSpecs USING [captionHeight, scrollBarW, windowBorderSize], WindowManager, WindowManagerPrivate; WindowManagerImpl: CEDAR MONITOR IMPORTS Carets, ColorWorld, Cursors, Imager, InputFocus, InterminalExtra, WindowManager, Menus, MenusPrivate, MessageWindow, ViewerOps, UserTerminal EXPORTS WindowManager, WindowManagerPrivate SHARES InputFocus, ViewerClasses, ViewerOps = BEGIN OPEN Cursors, ViewerClasses, ViewerSpecs; Zone: TYPE = {none, menu, scroll, caption, client} ; trackingState: Zone _ none; CursorZone: PROC [v: Viewer, mousePos: TIPUser.TIPScreenCoords] RETURNS [z: Zone] = { OPEN v; m: MenusPrivate.ViewerMenus _ NARROW[v.menus]; RETURN[SELECT TRUE FROM parent=NIL AND column#static AND mousePos.mouseY IN [wh-captionHeight..wh] => caption, scrollable AND mousePos.mouseX IN [0..scrollBarW] AND mousePos.mouseY IN [0..ch] => scroll, m#NIL AND mousePos.mouseX IN [m.x..m.x+m.w] AND mousePos.mouseY IN [m.y..m.y+m.h] => menu, ENDCASE => none ] }; ProcessWindowResults: PUBLIC PROC [self: Viewer, input: LIST OF REF ANY] = BEGIN zone: Zone; newZone: BOOL; shift, control: BOOL _ FALSE; mousePos: TIPUser.TIPScreenCoords; FOR l: LIST OF REF ANY _ input, l.rest UNTIL l = NIL DO WITH l.first SELECT FROM z: ATOM => BEGIN OPEN InputFocus; IF newZone THEN SELECT trackingState FROM -- old feedback scroll => {ReleaseButtons[]; RemoveScrollFeedback[]}; menu => {ReleaseButtons[]; MenusPrivate.ClearMenu[NARROW[feedbackViewer.menus], feedbackViewer]; feedbackViewer _ NIL}; caption => {ReleaseButtons[]; RemoveCaptionFeedback[]}; ENDCASE; IF newZone THEN SELECT zone FROM -- first time stuff scroll => {CaptureButtons[ProcessWindowResults, WindowManagerTIPTable, self]; PostScrollFeedback[self]}; menu => {CaptureButtons[ProcessWindowResults, WindowManagerTIPTable, self]; feedbackViewer _ self; SetC[bullseye]}; caption => {CaptureButtons[ProcessWindowResults, WindowManagerTIPTable, self]; PostCaptionFeedback[self]; SetC[bullseye]}; ENDCASE => RestoreCursor[]; SELECT trackingState _ zone FROM -- zone specific ops scroll => SELECT z FROM $M => SetC[scrollUpDown]; $RU => HitScroll[self, mousePos.mouseY, up, shift, control]; $RD, $RM => SetC[scrollUp]; $YU => HitScroll[self, mousePos.mouseY, thumb, shift, control]; $YD, $YM => SetC[scrollRight]; $BU => HitScroll[self, mousePos.mouseY, down, shift, control]; $BD, $BM => SetC[scrollDown]; $Control => control _ TRUE; $Shift => shift _ TRUE; ENDCASE => NULL; menu => SELECT z FROM $RU => MenusPrivate.HitMenu[NARROW[self.menus], self, mousePos, IF shift THEN shiftleftup ELSE leftup]; $YU => MenusPrivate.HitMenu[NARROW[self.menus], self, mousePos, IF shift THEN shiftmiddleup ELSE middleup]; $BU => MenusPrivate.HitMenu[NARROW[self.menus], self, mousePos, IF shift THEN shiftrightup ELSE rightup]; $RM, $BM, $YM => {MenusPrivate.MarkMenu[NARROW[self.menus], self, mousePos]}; $RD, $BD, $YD => MenusPrivate.MarkMenu[NARROW[self.menus], self, mousePos]; $Control => control _ TRUE; $Shift => shift _ TRUE; ENDCASE => NULL; caption => SELECT z FROM $RU => MenusPrivate.HitMenu[windowMenus, self, mousePos, IF shift THEN shiftleftup ELSE leftup]; $YU => MenusPrivate.HitMenu[windowMenus, self, growPos, IF shift THEN shiftmiddleup ELSE middleup]; $BU => MenusPrivate.HitMenu[windowMenus, self, closePos, IF shift THEN shiftrightup ELSE rightup]; $RM, $RD => MenusPrivate.MarkMenu[windowMenus, self, mousePos]; $BM, $BD => MenusPrivate.MarkMenu[windowMenus, self, closePos]; $YM, $YD => MenusPrivate.MarkMenu[windowMenus, self, growPos]; $Control => control _ TRUE; $Shift => shift _ TRUE; ENDCASE => NULL; ENDCASE; END; z: TIPUser.TIPScreenCoords => { client: BOOL _ FALSE; mousePos _ z; IF mousePos.mouseX = 0 --AND trackingState = scroll-- THEN mousePos.mouseX _ 1; IF trackingState#none THEN [self, client] _ ViewerOps.MouseInViewer[mousePos]; zone _ IF client OR self=NIL THEN none ELSE CursorZone[self, mousePos]; newZone _ trackingState#zone OR (zone=caption AND self#feedbackViewer) OR (zone=scroll AND self#feedbackViewer); }; z: REF CHAR => TRUSTED {UserTerminal.BlinkDisplay[]}; ENDCASE => NULL; ENDLOOP; END; AlterColumn: PROC [v: Viewer, mx: INTEGER] = BEGIN column: ViewerClasses.Column; right: BOOL ~ mx >= v.ww/2; column _ SELECT v.column FROM left => IF right THEN right ELSE IF colorDisplayOn THEN color ELSE right, right => IF ~right THEN left ELSE IF colorDisplayOn THEN color ELSE left, color => IF right THEN right ELSE left, ENDCASE => ERROR; ViewerOps.ChangeColumn[v, column]; END; SetC: PROC [cursor: CursorType] = INLINE {IF waitCount=0 AND GetCursor[]#cursor THEN SetCursor[cursor]}; HitScroll: PROC [v: Viewer, y: LONG INTEGER, op: ScrollOp, shift, control: BOOL] = BEGIN RemoveScrollFeedback[]; IF v.parent=NIL OR v.class.coordSys#top THEN y _ v.ch-y; -- client coords IF v.class.scroll#NIL THEN [] _ v.class.scroll[v, op, SELECT op FROM up, down => y, ENDCASE => (100*(y+1))/v.ch, -- percent shift, control]; SetC[scrollUpDown]; -- put the cursor back PostScrollFeedback[v]; END; feedbackViewer: Viewer _ NIL; visible: REF CARDINAL = NEW[CARDINAL _ 122645B]; inVisible: REF CARDINAL = NEW[CARDINAL _ 100040B]; PostScrollFeedback: PROC [v: Viewer] = BEGIN context: Imager.Context; baseY, baseX, top, bottom: INTEGER; relY1, relY2: INT; -- so won't overflow IF feedbackViewer#NIL OR v.class.scroll=NIL THEN RETURN; IF ~v.init THEN RETURN; -- avoid a race condition bug [top, bottom] _ v.class.scroll[v, query, 0]; IF top>100 OR bottom>100 THEN RETURN; Carets.SuspendCarets[]; context _ ViewerOps.AcquireContext[v.parent, v.column=color ! ViewerOps.InvisiblePaint => GOTO Punt]; IF v.parent#NIL AND v.parent.class.coordSys=top THEN BEGIN -- flip origin Imager.IntTranslateT[context, 0, v.parent.ch]; Imager.IntScaleT[context, 1, -1]; baseY _ v.parent.ch - v.wy - v.wh + (IF v.border THEN windowBorderSize ELSE 0); END ELSE baseY _ v.wy + (IF v.border THEN windowBorderSize ELSE 0); baseX _ v.wx + (IF v.border THEN windowBorderSize ELSE 0); relY1 _ baseY; relY2 _ (LONG[100-bottom]*v.ch)/100+baseY; Imager.SetColor[context, inVisible]; Imager.MaskIntRectangle[context, [baseX, relY1, scrollBarW, relY2-relY1]]; relY1 _ relY2; relY2 _ relY2 + (LONG[bottom-top]*v.ch)/100; Imager.SetColor[context, visible]; Imager.MaskIntRectangle[context, [baseX, relY1, scrollBarW, relY2-relY1]]; Imager.SetColor[context, inVisible]; Imager.MaskIntRectangle[context, [baseX, relY2, scrollBarW, baseY+v.ch-relY2]]; ViewerOps.ReleaseContext[context]; feedbackViewer _ v; Carets.ResumeCarets[]; EXITS Punt => {feedbackViewer _ NIL; Carets.ResumeCarets[]}; END; RemoveScrollFeedback: PROC = BEGIN context: Imager.Context; baseX, baseY: INTEGER; IF feedbackViewer=NIL THEN RETURN; Carets.SuspendCarets[]; context _ ViewerOps.AcquireContext[feedbackViewer.parent, feedbackViewer.column=color ! ViewerOps.InvisiblePaint => GOTO Punt]; IF feedbackViewer.parent#NIL AND feedbackViewer.parent.class.coordSys=top THEN BEGIN Imager.IntTranslateT[context, 0, feedbackViewer.parent.ch]; Imager.IntScaleT[context, 1, -1]; baseY _ feedbackViewer.parent.ch - feedbackViewer.wy - feedbackViewer.wh + (IF feedbackViewer.border THEN windowBorderSize ELSE 0); END ELSE baseY _ feedbackViewer.wy + (IF feedbackViewer.border THEN windowBorderSize ELSE 0); baseX _ feedbackViewer.wx + (IF feedbackViewer.border THEN windowBorderSize ELSE 0); Imager.SetColor[context, Imager.white]; Imager.MaskIntRectangle[context, [baseX, baseY, scrollBarW, feedbackViewer.ch]]; ViewerOps.ReleaseContext[context]; GOTO Punt; EXITS Punt => {feedbackViewer _ NIL; Carets.ResumeCarets[]}; END; DrawCaptionMenu: PUBLIC ENTRY PROC [v: Viewer, guard: BOOL] = {ENABLE UNWIND => NULL; InternalDrawCaptionMenu[v, guard]}; InternalDrawCaptionMenu: INTERNAL PROC [v: Viewer, guard: BOOL] = BEGIN OPEN v; context: Imager.Context; DrawCaption: PROC = BEGIN x, y: INTEGER; x _ wx+windowBorderSize; y _ wy+wh-captionHeight; Imager.ClipIntRectangle[context, [x, y, ww-(2*windowBorderSize),captionHeight]]; Imager.SetColor[context, Imager.white]; Imager.MaskIntRectangle[context, [x, y, ww, captionHeight]]; Imager.SetColor[context, Imager.black]; IF guard THEN MenusPrivate.ReComputeWindowMenus[v, guardDestroy OR (newVersion AND link=NIL AND ~saveInProgress), colorDisplayOn] ELSE MenusPrivate.ReComputeWindowMenus[v, FALSE, colorDisplayOn]; MenusPrivate.DrawMenu[v, windowMenus, context]; END; IF feedbackViewer#v OR iconic OR ~visible THEN RETURN; context _ ViewerOps.AcquireContext[parent, column=color ! ViewerOps.InvisiblePaint => GOTO Punt]; Imager.DoSave[context, DrawCaption]; ViewerOps.ReleaseContext[context]; EXITS Punt => NULL; END; PostCaptionFeedback: ENTRY PROC [v: Viewer] = BEGIN ENABLE UNWIND => NULL; IF feedbackViewer#v THEN BEGIN -- remove old IF feedbackViewer#NIL THEN MenusPrivate.ClearMenu[windowMenus, feedbackViewer, FALSE]; feedbackViewer _ v; END; InternalDrawCaptionMenu[v, TRUE]; END; RemoveCaptionFeedback: ENTRY PROC = BEGIN ENABLE UNWIND => NULL; IF feedbackViewer#NIL THEN BEGIN MenusPrivate.ClearMenu[windowMenus, feedbackViewer, FALSE]; ViewerOps.PaintViewer[feedbackViewer, caption]; feedbackViewer _ NIL; END; END; waitCount: PUBLIC INTEGER _ 0; WaitCursor: PUBLIC ENTRY PROC [cursor: Cursors.CursorType _ hourGlass] = BEGIN ENABLE UNWIND => NULL; IF InputFocus.inputEnabled THEN SetCursor[cursor]; waitCount _ waitCount + 1; END; UnWaitCursor: PUBLIC ENTRY PROC = BEGIN ENABLE UNWIND => NULL; waitCount _ MAX[0, waitCount - 1]; IF waitCount=0 THEN RestoreCursor[]; END; RestoreCursor: PUBLIC PROC = TRUSTED {IF InputFocus.inputEnabled THEN InterminalExtra.InsertAction[[contents: deltaMouse[[0,0]]]]}; StartColorViewers: PUBLIC PROC [screenPos: WindowManager.ScreenPos, bitsPerPixel: CARDINAL] = BEGIN IF colorDisplayOn THEN StopColorViewers[]; colorDisplayOn _ ColorWorld.TurnOnColor[bitsPerPixel, (screenPos=left)]; IF ~colorDisplayOn THEN BEGIN MessageWindow.Append["Sorry, you don't have a color display.", TRUE]; MessageWindow.Blink[]; RETURN; END; ViewerOps.InitialiseColorPainting[]; END; StopColorViewers: PUBLIC PROC = BEGIN DoColorViewer: ViewerOps.EnumProc = BEGIN IF v.column=color THEN BEGIN ViewerOps.CloseViewer[v]; ViewerOps.ChangeColumn[v, left]; END; END; IF ~colorDisplayOn THEN RETURN; ViewerOps.EnumerateViewers[DoColorViewer]; ColorWorld.TurnOffColor[]; colorDisplayOn _ FALSE; END; BuildWindowMenus: PROC = BEGIN Menus.RegisterMenu[windowDestroyMenu]; Menus.RegisterMenu[windowGuardedDestroyMenu]; Menus.RegisterMenu[windowMovementMenu]; Menus.RegisterMenu[windowColorMenu]; Menus.RegisterMenu[windowSizeMenu]; Menus.RegisterMenu[windowDebugMenu]; MenusPrivate.ViewerlessAddMenu["windowDestroyMenu"]; MenusPrivate.ViewerlessAddMenu["windowGuardedDestroyMenu"]; MenusPrivate.ViewerlessAddMenu["windowMovementMenu"]; MenusPrivate.ViewerlessAddMenu["windowColorMenu"]; MenusPrivate.ViewerlessAddMenu["windowSizeMenu"]; MenusPrivate.ViewerlessAddMenu["windowDebugMenu"]; growPos _ NEW[TIPUser.TIPScreenCoordsRec _ [0, FALSE, 0]]; closePos _ NEW[TIPUser.TIPScreenCoordsRec _ [0, FALSE, 0]]; END; colorDisplayOn: PUBLIC BOOL _ FALSE; -- color display status windowMenus: PUBLIC MenusPrivate.ViewerMenus; growPos: PUBLIC TIPUser.TIPScreenCoords; closePos: PUBLIC TIPUser.TIPScreenCoords; windowDestroyMenu: Menus.Menu = [name: "windowDestroyMenu", beginsActive: TRUE, breakBefore: FALSE, breakAfter: FALSE, notify: ViewerMenuNotifier, entries: LIST[ ["Destroy", FALSE, NIL, LIST [ [LIST[all],LIST[$DestroyViewer],"Destroy the Viewer", "", NIL,NIL,NIL] ] ] ] ]; windowGuardedDestroyMenu: Menus.Menu = [name: "windowGuardedDestroyMenu", beginsActive: TRUE, breakBefore: FALSE, breakAfter: FALSE, notify: ViewerMenuNotifier, entries: LIST[ ["Destroy", TRUE, NIL, LIST [ [LIST[all],LIST[$DestroyViewer],"Destroy the Viewer", "Edits will be discarded...", NIL,NIL,NIL] ] ] ] ]; windowMovementMenu: Menus.Menu = [name: "windowMovementMenu", beginsActive: TRUE, breakBefore: FALSE, breakAfter: FALSE, notify: ViewerMenuNotifier, entries: LIST[ ["Adjust", FALSE, NIL, LIST[ [LIST[all], LIST[$AdjustViewer], "Adjust Viewer Size", "", NIL, NIL, NIL] ] ], ["Top", FALSE, NIL, LIST[ [LIST[all], LIST[$MoveViewerToTop], "Move Viewer To Top Of Column", "", NIL, NIL, NIL] ] ], ["Left", FALSE, "", LIST[ [LIST[shiftleftup, shiftmiddleup, shiftrightup], LIST[$MoveViewerToLeftColumn, $GrowViewer], "Move To Left Column and Grow ", "", NIL, NIL, NIL], [LIST[all], LIST[$MoveViewerToLeftColumn], "Move Viewer To Left Column", "", NIL, NIL, NIL] ] ], ["Right", FALSE, "", LIST[ [LIST[shiftleftup, shiftmiddleup, shiftrightup], LIST[$MoveViewerToRightColumn, $GrowViewer], "Move To Right Column and Grow ", "", NIL, NIL, NIL], [LIST[all], LIST[$MoveViewerToRightColumn], "Move Viewer To Right Column", "", NIL, NIL, NIL] ] ] ] ]; windowColorMenu: Menus.Menu = [name: "windowColorMenu", beginsActive: TRUE, breakBefore: FALSE, breakAfter: FALSE, notify: ViewerMenuNotifier, entries: LIST[ ["Color", FALSE, NIL, LIST[ [LIST[shiftleftup, shiftmiddleup, shiftrightup], LIST[$MoveViewerToColorColumnAndGrow], "Move To Color Display and Grow ", "", NIL, NIL, NIL], [LIST[all], LIST[$MoveViewerToColorColumn], "Move Viewer To Color Display", "", NIL, NIL, NIL] ] ] ] ]; windowSizeMenu: Menus.Menu = [name: "windowSizeMenu", beginsActive: TRUE, breakBefore: FALSE, breakAfter: FALSE, notify: ViewerMenuNotifier, entries: LIST[ ["Grow", FALSE, NIL, LIST[ [LIST[all],LIST[$GrowViewer],"Grow the Viewer", "", NIL,NIL,NIL] ] ], ["Close", FALSE, NIL, LIST[ [LIST[all],LIST[$CloseViewer],"Close the Viewer", "", NIL,NIL,NIL] ] ] ] ]; windowDebugMenu: Menus.Menu = [name: "windowDebugMenu", beginsActive: TRUE, breakBefore: FALSE, breakAfter: FALSE, notify: ViewerMenuNotifier, entries: LIST[ ["+Debug", FALSE, NIL, LIST[ [LIST[all],LIST[$IncreaseDebug],"Increase debugging level", "", NIL,NIL,NIL] ] ], ["-Debug", FALSE, NIL, LIST[ [LIST[all],LIST[$DecreaseDebug],"Decrease debugging level", "", NIL,NIL,NIL] ] ], ["NoBug", FALSE, NIL, LIST[ [LIST[all],LIST[$NoDebug],"Turn Off Debugging", "", NIL,NIL,NIL] ] ] ] ]; ViewerMenuNotifier: ViewerClasses.NotifyProc = { FOR current: LIST OF REF ANY _ input, current.rest UNTIL current = NIL DO SELECT current.first FROM $DestroyViewer => Destroy[self]; $CloseViewer => ViewerOps.CloseViewer[self]; $GrowViewer => ViewerOps.GrowViewer[self]; $MoveViewerToTop => ViewerOps.TopViewer[self]; $AdjustViewer => ViewerOps.Adjust[self]; $MoveViewerToLeftColumn => ViewerOps.ChangeColumn[self, left]; $MoveViewerToRightColumn => ViewerOps.ChangeColumn[self, right]; $MoveViewerToColorColumn => MoveToColorColumn[viewer: self, doGrow: FALSE]; $MoveViewerToColorColumnAndGrow => MoveToColorColumn[viewer: self, doGrow:TRUE]; $IncreaseDebug => MenusPrivate.AlterDebuggingLevel[amount: 1, relative: TRUE]; $DecreaseDebug => MenusPrivate.AlterDebuggingLevel[amount: -1, relative: TRUE]; $NoDebug => MenusPrivate.AlterDebuggingLevel[amount: 0, relative: FALSE]; ENDCASE => ERROR; ENDLOOP; }; Destroy: PROC[viewer: ViewerClasses.Viewer] = { IF ~viewer.inhibitDestroy THEN ViewerOps.DestroyViewer[viewer] ELSE {MessageWindow.Append["Sorry, this viewer can not be destroyed.", TRUE]; MessageWindow.Blink[]}; }; MoveToColorColumn: PRIVATE PROC[viewer: ViewerClasses.Viewer, doGrow: BOOL _ FALSE] = { IF WindowManager.colorDisplayOn THEN { ViewerOps.ChangeColumn[viewer, color]; IF doGrow THEN ViewerOps.GrowViewer[viewer]} ELSE BEGIN MessageWindow.Append["Sorry, the color display is not available.", TRUE]; MessageWindow.Blink[]; END; }; BuildWindowMenus[]; END. rWindowManagerImpl.mesa; Written by S. McGregor Edited by McGregor on August 16, 1983 4:49 pm Last Edited by: Maxwell, February 8, 1983 3:58 pm Last Edited by: Pausch, August 17, 1983 5:05 pm not monitored since notifier is synchronous flip origin we have to actually instantiate these pointers to start pointing at SOMETHING [self: Viewer, input: LIST OF REF ANY] Κc– "cedar" style˜JšΟc.™.Jš-™-Jšœ1™1J™/šΟk ˜ Jšœžœ˜+Jšœ žœ˜-Jšœžœ$˜1Jšœ žœG˜WJšœžœ˜%Jšœžœp˜|Jšœ˜Jšœ žœu˜‡Jšœžœ˜$Jšœžœ'˜4Jšœ žœ˜"Jšœ˜Jšœ žœΜ˜ΫJšœ žœ/˜@J˜J˜J˜—Jšœžœž˜ J˜šžœf˜mJšœ&˜&—Jšžœ$˜+Jšžœ'˜-J˜Jšžœžœ%˜/J˜Jšœžœ*˜4J˜J˜šΟn œžœ0žœ˜UJšžœ˜Jšœžœ ˜.šžœžœžœž˜Jš œžœžœžœžœ#˜VJš œ žœžœžœžœ˜[Jš œžœžœžœžœžœ˜Zšžœ˜J˜——Jšœ˜J˜—šŸœžœžœžœžœžœžœž˜PJš+™+J˜ Jšœ žœ˜Jšœžœžœ˜J˜"J˜Jšžœžœžœžœžœžœžœžœžœ žœž˜P˜Jšœžœžœžœ ˜!˜š žœ žœžœžœ˜9J˜6šœ3žœ˜PJšœ"žœ˜'—J˜7Jšžœ˜J˜—š žœ žœžœžœ˜4˜GJ˜J˜—˜EJ˜J˜J˜—˜GJ˜J˜J˜—Jšžœ˜J˜—šžœžœ˜5šœ žœž˜J˜J˜>J˜J˜AJ˜J˜@J˜Jšœžœ˜Jšœžœ˜Jšžœžœ˜—šœ žœž˜šœžœ ˜1Jšœžœžœ žœ ˜7—šœžœ ˜1Jšœžœžœžœ ˜;—šœžœ ˜1Jšœžœžœžœ ˜9—˜ šœžœ ˜-J˜——˜ šœžœ ˜,J˜——Jšœžœ˜Jšœžœ˜Jšžœžœ˜—šœ žœž˜˜*Jšœžœžœ žœ ˜7—˜*Jšœžœžœžœ ˜:—˜*Jšœžœžœžœ ˜9—˜.J˜—˜.J˜—˜.J˜—Jšœžœ˜Jšœžœ˜Jšžœžœ˜—Jšžœ˜J˜—Jšžœ˜J˜—˜Jšœžœžœ˜J˜ Jšžœœžœ˜OJšžœžœ4˜NJš œžœžœžœžœžœ˜Gšœžœžœ˜FJšžœžœ˜)—J˜J˜—Jšœžœžœžœ˜5J˜Jšžœžœ˜Jšžœ˜—Jšžœ˜J˜—šŸ œžœžœž˜2J˜Jšœžœ˜šœ žœ ž˜Jš œžœžœžœžœžœžœ˜IJš œ žœžœžœžœžœžœ˜IJšœ žœžœžœ˜'Jšžœžœ˜—J˜"Jšžœ˜J˜—šŸœžœž˜(Jšœžœ žœžœ˜?J˜—š Ÿ œžœžœžœ žœž˜XJ˜Jš žœ žœžœžœ ˜Išžœžœžœ˜5šžœž˜J˜Jšžœ ˜'—J˜—Jšœ˜*J˜Jšžœ˜J˜—Jšœžœ˜J˜Jš œ žœžœžœžœ ˜0Jš œ žœžœžœžœ ˜2J˜šŸœžœž˜,J˜Jšœžœ˜#Jšœžœ˜'Jš žœžœžœžœžœžœ˜8Jšžœ žœžœ˜6J˜,Jšžœ žœ žœžœ˜%J˜˜;Jšœžœ˜)—š žœ žœžœžœžœ˜IJšœ.˜.Jšœ!˜!Jšœ%žœ žœžœ˜OJšž˜—Jšžœžœ žœžœ˜?Jšœžœ žœžœ˜:J˜Jšœ žœ˜*J˜$J˜JJ˜Jšœžœ˜,J˜"J˜JJ˜$J˜OJ˜"Jšœ*˜*Jšžœžœ˜˜^J˜—šŸœžœžœ%˜CJšœžœž˜Jšžœžœ˜*J˜Hšžœžœž˜Jšœ?žœ˜EJšœ˜Jšžœ˜Jšžœ˜—J˜$Jšžœ˜J˜—šŸœžœžœž˜%šœ$ž˜)šžœžœž˜J˜J˜ Jšžœ˜—Jšžœ˜—Jšžœžœžœ˜J˜*J˜Jšœžœ˜Jšžœ˜—J˜šŸœžœž˜J˜&Jšœ-˜-Jšœ'˜'Jšœ$˜$Jšœ#˜#Jšœ$˜$Jšœ4˜4Jšœ;˜;Jšœ5˜5Jšœ2˜2Jšœ1˜1Jšœ2˜2JšœM™MJšœ žœ"žœ˜:Jšœ žœ"žœ˜;Jšžœ˜J˜—Jšœžœžœžœ˜žœžœžœ˜\J˜—šœ žœžœ˜šœžœ+˜0JšžœPžœžœžœ˜c—Jš œžœžœ@žœžœžœ˜^J˜—J˜—J˜—J˜—šœ˜šœ˜Jšœžœ˜Jšœ žœ˜Jšœ žœ˜Jšœ˜šœ žœ˜šœ žœžœžœ˜šœžœ+˜0JšžœKžœžœžœ˜^—Jš œžœžœAžœžœžœ˜_J˜—J˜—J˜—J˜—šœ˜šœ˜Jšœžœ˜Jšœ žœ˜Jšœ žœ˜Jšœ˜šœ žœ˜šœ žœžœžœ˜Jš œžœžœ%žœžœžœ˜AJ˜—šœ žœžœžœ˜Jš œžœžœ'žœžœžœ˜CJ˜—J˜—˜J˜—J˜——šœ˜šœ˜Jšœžœ˜Jšœ žœ˜Jšœ žœ˜Jšœ˜šœ žœ˜šœ žœžœžœ˜Jš œžœžœ1žœžœžœ˜MJ˜—šœ žœžœžœ˜Jš œžœžœ1žœžœžœ˜MJ˜—šœ žœžœžœ˜Jš œžœžœ%žœžœžœ˜AJ˜—J˜—˜J˜—J˜——˜0Jšœ&™&šžœ žœžœžœžœžœ žœž˜Išžœž˜J˜ Jšœ,˜,Jšœ*˜*Jšœ.˜.Jšœ(˜(Jšœ>˜>Jšœ@˜@JšœDžœ˜KJšœJžœ˜PJšœHžœ˜NJšœIžœ˜OJšœBžœ˜IJšžœžœ˜—Jšžœ˜—˜J˜——šŸœžœ"˜/Jšžœžœ ˜>šžœCžœ˜MJ˜—Jšœ˜J˜—J˜š Ÿœžœžœ'žœžœ˜Wšžœžœ˜&Jšœ&˜&Jšžœžœ˜,—šžœž˜ JšœCžœ˜IJ˜Jšžœ˜—Jšœ˜—J˜J˜J˜Jšžœ˜J˜J˜—…—@dU9