DIRECTORY Imager USING [Context, SetGray, MaskRectangle, SetFont, TranslateT, Scale2T], ImagerFont USING [Find], ImagerBackdoor USING [GetBounds], Containers USING [Container, Create, ChildXBound, ChildYBound], Menus USING [Menu, CreateMenu, AppendMenuEntry, CreateEntry, MenuLine, MenuProc, GetNumberOfLines, GetLine, SetLine, MenuEntry, ChangeNumberOfLines, MouseButton], ViewerClasses USING [Viewer, ViewerClass, ViewerClassRec, NotifyProc, PaintProc, DestroyProc, ScrollProc], ViewerOps USING [CreateViewer, PaintViewer, RegisterViewerClass], TIPUser USING [InstantiateNewTIPTable ,TIPScreenCoords], Atom USING [GetPName], MessageWindow USING [Append, Blink], Real USING [FixI], Rope USING [ROPE, Equal, Concat], ViewerBLT USING [ChangeNumberOfLines], Process USING [Detach], QuickViewer USING []; QuickViewerImpl: CEDAR MONITOR IMPORTS Imager, ImagerBackdoor, ImagerFont, Containers, Menus, ViewerOps, TIPUser, Real, Atom, MessageWindow, ViewerBLT, Rope, Process EXPORTS QuickViewer SHARES Menus = BEGIN okToProceed: BOOL _ TRUE; prevEventActed: CONDITION; numMenuButtonQd: NAT _ 0; --To count the number of menu buttons waiting. Click proc won't be called if numMenuButtonQd > 0-- numFixedLine: NAT _ 2; --This is the number of menu lines which aren't controlled entryHeight: CARDINAL = 12; -- height of a line of items in a menu entryVSpace: CARDINAL = 3; -- vertical leading between lines entryHSpace: CARDINAL = 8; -- horizontal space between items on a line quickView: QuickView _ NIL; -- This is the only instance allowed QuickView: TYPE = REF QuickViewData; QuickViewData: TYPE = RECORD [outer: Containers.Container _ NIL, -- enclosing container viewer: ViewerClasses.Viewer, -- Imager area within xTranslation, yTranslation: REAL _ 0., xyScale: REAL _ 1.0, autoScaling: BOOL, xLeft, xRight, yBottom, yTop: REAL, proc: PROC [context: Imager.Context, scaleFactor: REAL]]; DrawProc: PROC[Imager.Context, REAL]; -- name of procedure for redrawing on window resizing, etc. ButtProc: PROC[ATOM, Menus.MouseButton, BOOL, BOOL]; -- name of procedure for acting on button pushes ClickProc: PROC[ATOM, REAL, REAL]; -- name of procedure for acting on mouse clicks within the viewer ExitProc: PROC[]; -- name of procedure for cleaning up on exit line0Menu, line1Menu, line2Menu, line3Menu, line4Menu, line5Menu, line6Menu: Menus.MenuEntry; line2Control, line3Control, line4Control, line5Control, line6Control: Rope.ROPE; BuildViewer: PUBLIC PROC[ ReDrawProc: PROC[Imager.Context, REAL], QuitProc: PROC[], MenuButtonProc: PROC[ATOM, Menus.MouseButton, BOOL, BOOL], --event, mouseButton, shift, control-- ViewerClickProc: PROC[ATOM, REAL, REAL], --ATOM is one of {$LeftButton, $MiddleButton, $RighButton}, xControlPt, yControlPt viewerTitle: Rope.ROPE, autoScaling: BOOL, menuLabelsLine0, menuLabelsLine1, controlledLine2, controlledLine3, controlledLine4, controlledLine5, controlledLine6: LIST OF ATOM _ NIL] = BEGIN menu: Menus.Menu; AppendEntry: PROC[name, doc: Rope.ROPE, proc: Menus.MenuProc, lineNo: INT] ={ Menus.AppendMenuEntry[menu: menu, entry: Menus.CreateEntry[name: name, proc: proc, clientData: quickView, documentation: doc], line: lineNo];}; --AppendEntry-- SetUpMenuLine: PROC[labels: LIST OF ATOM, lineNo: INT] ={ WHILE labels # NIL DO Menus.AppendMenuEntry[-- enter menu buttons menu: menu, entry: Menus.CreateEntry[ name: Atom.GetPName[labels.first], proc: MenuProc, clientData: labels.first, documentation: " "], line: lineNo]; labels _ labels.rest; ENDLOOP; }; --SetUpMenuLine-- IF quickView # NIL THEN {MessageWindow.Append["Only one instance of QuickViewer is allowed at a time!", TRUE]; MessageWindow.Blink[]; RETURN}; quickView _ NEW[QuickViewData]; -- allocate a data object menu _ Menus.CreateMenu[lines: 2]; -- set up menu DrawProc _ ReDrawProc; -- store away procedure names ButtProc _ MenuButtonProc; ClickProc _ ViewerClickProc; ExitProc _ QuitProc; line0Menu_ line1Menu_ line2Menu_ line3Menu_ line4Menu_ line5Menu_ line6Menu _ NIL; line2Control_ line3Control_ line4Control_ line5Control_ line6Control _ NIL; IF controlledLine2 # NIL THEN line2Control _ Atom.GetPName[controlledLine2.first]; IF controlledLine3 # NIL THEN line3Control _ Atom.GetPName[controlledLine3.first]; IF controlledLine4 # NIL THEN line4Control _ Atom.GetPName[controlledLine4.first]; IF controlledLine5 # NIL THEN line5Control _ Atom.GetPName[controlledLine5.first]; IF controlledLine6 # NIL THEN line6Control _ Atom.GetPName[controlledLine6.first]; AppendEntry["Refresh", "Refresh the viewer", Refresh, 0]; -- enter "Refresh" button AppendEntry["<<<", "Roll image to left", RollLeft, 0]; -- enter "<<<" button AppendEntry[">>>", "Roll image to right", RollRight, 0]; -- enter ">>>" button AppendEntry["Enlarge", "Increase maginification", Enlarge, 0]; -- enter "Enlarge" button AppendEntry["Reduce", "Decrease maginification", Reduce, 0]; -- enter "Reduce" button SetUpMenuLine[menuLabelsLine0, 0]; --Add (the rest of) menu line0 AppendEntry[line2Control, " ", Line2Menu, 0]; -- enter line 2 control button AppendEntry[line3Control, " ", Line3Menu, 0]; -- enter line 3 control button AppendEntry[line4Control, " ", Line4Menu, 0]; -- enter line 4 control button AppendEntry[line5Control, " ", Line5Menu, 0]; -- enter line 5 control button AppendEntry[line6Control, " ", Line6Menu, 0]; -- enter line 6 control button SetUpMenuLine[menuLabelsLine1, 1]; --Add menu line1 now line0Menu _ Menus.GetLine[menu, 0]; line1Menu _ Menus.GetLine[menu, 1]; IF controlledLine2 # NIL THEN SetUpMenuLine[controlledLine2.rest, 2]; line2Menu _ Menus.GetLine[menu, 2]; Menus.SetLine[menu, 2, NIL]; IF controlledLine3 # NIL THEN SetUpMenuLine[controlledLine3.rest, 2]; line3Menu _ Menus.GetLine[menu, 2]; Menus.SetLine[menu, 2, NIL]; IF controlledLine4 # NIL THEN SetUpMenuLine[controlledLine4.rest, 2]; line4Menu _ Menus.GetLine[menu, 2]; Menus.SetLine[menu, 2, NIL]; IF controlledLine5 # NIL THEN SetUpMenuLine[controlledLine5.rest, 2]; line5Menu _ Menus.GetLine[menu, 2]; Menus.SetLine[menu, 2, NIL]; IF controlledLine6 # NIL THEN SetUpMenuLine[controlledLine6.rest, 2]; line6Menu _ Menus.GetLine[menu, 2]; Menus.SetLine[menu, 2, NIL]; Menus.ChangeNumberOfLines[menu, 2]; -- only show the top two levels to start with. quickView.outer _ Containers.Create[[name: viewerTitle, -- define outer viewer menu: menu, iconic: TRUE, column: left, scrollable: FALSE]]; quickView.viewer _ ViewerOps.CreateViewer -- define Imager area [flavor: $QuickViewer, info: [parent: quickView.outer, wx: 0, wy: 0, -- position WRT parent ww: quickView.outer.ww, -- CHildXBound below wh: quickView.outer.wh, -- CHildXBound below data: quickView, -- describes the current scene scrollable: TRUE]]; Containers.ChildXBound[quickView.outer, quickView.viewer]; Containers.ChildYBound[quickView.outer, quickView.viewer]; quickView.autoScaling _ autoScaling; ViewerOps.PaintViewer[quickView.outer, all]; -- load up the viewer (paint it) quickView.xTranslation _ quickView.yTranslation _ 0.; quickView.xLeft _ quickView.yBottom _ 0.; quickView.xRight _ quickView.viewer.ww; quickView.yTop _ quickView.viewer.wh; END; --BuildViewer-- EraseViewer: PUBLIC PROC[] ={ DoErase: PROC [context: Imager.Context, scaleFactor: REAL] = { -- mark: Graphics.Mark _ Graphics.Save[context]; mark stack Imager.SetGray[context, 0]; -- set color to white Imager.MaskRectangle[context, ImagerBackdoor.GetBounds[context]]; -- erase by drawing box -- Graphics.Restore[context,mark]; restore stack }; --DoErase-- DrawInViewer[DoErase];}; --EraseViewer-- SetViewerName: PUBLIC PROC[name: Rope.ROPE] ={quickView.outer.name _ name}; --SetViewerName PaintProc: ViewerClasses.PaintProc = -- repaint screen for updates BEGIN x,y: REAL; x _ quickView.xTranslation + quickView.viewer.ww/2.; -- center image on relative origin y _ quickView.yTranslation + quickView.viewer.wh/2.; Imager.SetFont[context, ImagerFont.Find["Xerox/TiogaFonts/Tioga10"]]; -- CLUDGE!! IF whatChanged = NIL THEN {Imager.TranslateT[context, [x, y]]; IF quickView.autoScaling THEN Imager.Scale2T[context, [quickView.xyScale, quickView.xyScale]]; DrawProc[context, quickView.xyScale]} -- window resized, redraw ELSE {Imager.TranslateT[context, [x, y]]; IF quickView.autoScaling THEN Imager.Scale2T[context, [quickView.xyScale, quickView.xyScale]]; NARROW[whatChanged, REF PROC[Imager.Context, REAL]]^[context, quickView.xyScale]}; END; DrawInViewer: PUBLIC PROCEDURE [proc: PROC [Imager.Context, REAL]] = -- pass procedure to PaintProc BEGIN drawProc: REF PROC[Imager.Context, REAL] _ NIL; TRUSTED {drawProc _ NEW[PROC[Imager.Context, REAL] _ proc];}; ViewerOps.PaintViewer[viewer: quickView.viewer, -- pass record to viewer painter hint: client, whatChanged: drawProc, clearClient: FALSE]; END; Refresh: PROCEDURE [parent: REF ANY, clientData: REF ANY, mouseButton: Menus.MouseButton, shift, control: BOOL] = { EraseViewer[]; DrawInViewer[DrawProc]; }; --Refresh-- RollLeft: PROCEDURE [parent: REF ANY, clientData: REF ANY, mouseButton: Menus.MouseButton, shift, control: BOOL] = { EraseViewer[]; quickView.xTranslation _ quickView.xTranslation - (SELECT mouseButton FROM red => 64, yellow => 128, blue => 256, ENDCASE => ERROR); -- Move image to left DrawInViewer[DrawProc]; }; --RollLeft-- RollRight: PROCEDURE [parent: REF ANY, clientData: REF ANY, mouseButton: Menus.MouseButton, shift, control: BOOL] = { EraseViewer[]; quickView.xTranslation _ quickView.xTranslation + (SELECT mouseButton FROM red => 64, yellow => 128, blue => 256, ENDCASE => ERROR); -- Move image to right DrawInViewer[DrawProc]}; --RollRight-- Enlarge: PROCEDURE [parent: REF ANY, clientData: REF ANY, mouseButton: Menus.MouseButton, shift, control: BOOL] = { EraseViewer[]; quickView.xyScale _ quickView.xyScale * (SELECT mouseButton FROM red => 1.2, yellow => 2.0, blue => 4.0, ENDCASE => ERROR); -- Enlarge image DrawInViewer[DrawProc]}; --Enlarge-- Reduce: PROCEDURE [parent: REF ANY, clientData: REF ANY, mouseButton: Menus.MouseButton, shift, control: BOOL] = { EraseViewer[]; quickView.xyScale _ quickView.xyScale * (SELECT mouseButton FROM red => 0.8, yellow => 0.5, blue => 0.25, ENDCASE => ERROR); -- Reduce image DrawInViewer[DrawProc]}; --Reduce-- Line2Menu: Menus.MenuProc = { ChangeMenu[NARROW[parent], line2Menu] }; Line3Menu: Menus.MenuProc = { ChangeMenu[NARROW[parent], line3Menu] }; Line4Menu: Menus.MenuProc = { ChangeMenu[NARROW[parent], line4Menu] }; Line5Menu: Menus.MenuProc = { ChangeMenu[NARROW[parent], line5Menu] }; Line6Menu: Menus.MenuProc = { ChangeMenu[NARROW[parent], line6Menu] }; ChangeMenu: PROC [viewer: ViewerClasses.Viewer, subMenu: Menus.MenuEntry] = { menu: Menus.Menu _ viewer.menu; numLines: Menus.MenuLine _ Menus.GetNumberOfLines[menu]; FOR i: Menus.MenuLine IN [numFixedLine..numLines) DO -- See if already showing the submenu IF Rope.Equal[Menus.GetLine[menu,i].name, subMenu.name] THEN { -- Yes, so remove it FOR j: Menus.MenuLine IN (i..numLines) DO Menus.SetLine[menu, j-1, Menus.GetLine[menu, j]]; ENDLOOP; ViewerBLT.ChangeNumberOfLines[viewer, numLines.PRED]; RETURN --DONE }; --ENDIF ENDLOOP; --If numLines will not be more within limit of Menus.MenuLine then move all controlled lines 1 step up and replace the lowest line by new request -- IF numLines.SUCC IN Menus.MenuLine THEN {Menus.SetLine[menu, numLines, subMenu]; numLines _ numLines.SUCC} ELSE { FOR j: Menus.MenuLine IN (numFixedLine..numLines) DO Menus.SetLine[menu, j-1, Menus.GetLine[menu, j]]; ENDLOOP; Menus.SetLine[menu, numLines.PRED, subMenu];}; --ENDIF ViewerBLT.ChangeNumberOfLines[viewer, numLines]; }; --ChangeMenu-- MenuProc: PROCEDURE [parent: REF ANY, clientData: REF ANY, mouseButton: Menus.MouseButton, shift, control: BOOL] = { menuButton: ATOM _ NARROW[clientData]; MenuButtonMonitor[menuButton, mouseButton, shift, control]; }; --MenuProc-- MenuButtonMonitor: ENTRY PROCEDURE [event: ATOM, mouseButton: Menus.MouseButton, shift, control: BOOL] ={ numMenuButtonQd _ numMenuButtonQd.SUCC; WHILE ~ okToProceed DO WAIT prevEventActed; ENDLOOP; okToProceed _ FALSE; BEGIN ENABLE UNWIND =>GOTO aborted; ButtProc[event, mouseButton, shift, control]; EXITS aborted => {MessageWindow.Append[Rope.Concat[Atom.GetPName[event], " aborted"], TRUE]; MessageWindow.Blink[]} END; okToProceed _ TRUE; NOTIFY prevEventActed; numMenuButtonQd _ numMenuButtonQd.PRED;};--MenuButtonMonitor-- NotifyProc: ViewerClasses.NotifyProc = BEGIN-- PROCEDURE [self: Viewer, input: LIST OF REF ANY] IF ISTYPE[input.first, TIPUser.TIPScreenCoords] THEN -- If input is coords from mouse {mousePlace: TIPUser.TIPScreenCoords _ NARROW[input.first]; --get mouse coordinates, store globally controlPointX: REAL _ (mousePlace.mouseX - quickView.xTranslation - quickView.viewer.ww/2.0)/ quickView.xyScale; controlPointY: REAL _ (mousePlace.mouseY - quickView.yTranslation - quickView.viewer.wh/2.0)/quickView.xyScale; IF controlPointX > quickView.xRight THEN quickView.xRight _ controlPointX ELSE IF controlPointX < quickView.xLeft THEN quickView.xLeft _ controlPointX; IF controlPointY > quickView.yTop THEN quickView.yTop _ controlPointY ELSE IF controlPointY < quickView.yBottom THEN quickView.yBottom _ controlPointY; IF ISTYPE[input.rest.first, ATOM] THEN { mouseButton: ATOM _ NARROW[input.rest.first]; IF numMenuButtonQd = 0 THEN ClickMonitor[mouseButton, controlPointX, controlPointY] ELSE MessageWindow.Append[Rope.Concat[Atom.GetPName[mouseButton], " click ignored"], TRUE]}; }; END; ClickMonitor: ENTRY PROCEDURE [mouseButton: ATOM, xCoord, yCoord: REAL] ={ WHILE ~ okToProceed DO WAIT prevEventActed; ENDLOOP; okToProceed _ FALSE; BEGIN ENABLE UNWIND =>GOTO aborted; ClickProc[mouseButton, xCoord, yCoord]; EXITS aborted => {MessageWindow.Append[Rope.Concat[Atom.GetPName[mouseButton], " click aborted"], TRUE]; MessageWindow.Blink[]} END; okToProceed _ TRUE; NOTIFY prevEventActed;};--ClickMonitor-- DestroyProc: ViewerClasses.DestroyProc ={ -- clean up on exit (viewer destroyed) TRUSTED {Process.Detach[FORK ExitProc[]];}; quickView _ NIL; --So can create other instance }; --DestroyProc-- ScrollProc: ViewerClasses.ScrollProc = -- act on scrollbar mouse hits BEGIN SELECT op FROM up => {quickView.yTranslation _ quickView.yTranslation + amount; EraseViewer[]; DrawInViewer[DrawProc]}; down => {quickView.yTranslation _ quickView.yTranslation - amount; EraseViewer[]; DrawInViewer[DrawProc]}; thumb => {quickView.yTranslation _ - (quickView.yBottom + (1. - amount/100.) * (quickView.yTop - quickView.yBottom)); EraseViewer[]; DrawInViewer[DrawProc]}; query => {OPEN quickView; RETURN[Real.FixI[100. - (-yTranslation + self.ch - yBottom) * 100. / (yTop - yBottom)], Real.FixI[100. - (-yTranslation - yBottom) * 100. / (yTop - yBottom)]]}; ENDCASE; END; ViewerOps.RegisterViewerClass[$QuickViewer, NEW [ViewerClasses.ViewerClassRec _ [paint: PaintProc, -- procedure called when viewer contents must be repainted notify: NotifyProc, -- procedure to respond to input events (from TIP table) destroy: DestroyProc, -- procedure to clean up when done scroll: ScrollProc, -- procedure to respond to scroll bar hits tipTable: TIPUser.InstantiateNewTIPTable["QuickViewer.TIP"], icon: document ]]]; -- Register with viewers END. Ϊfile: QuickViewerImpl.mesa Makes viewer (Init) Sets up menu and buttons (BuildViewer) Handles screen updates (PaintProc) Handles graphic input (NotifyProc) Preas, August 2, 1986 9:54:45 pm PDT Last Edited by: Preas, September 11, 1984 3:31:49 pm PDT Last Edited by: Shou, November 21, 1984 8:59:21 am PST Last Edited by: CSChow, January 12, 1985 1:30:20 pm PST --Menus is otherwise private. --First get the names of the controlling atoms-- --Now menu line1 and menu line2 are done -- constrain Imager area to lie in viewer space left over after menu, etc. are drawn [self: Viewer, context: Imager.Context, whatChanged: REF ANY, clear: BOOL] --This procedure is based on [Indigo]TEditDocumentsImpl.mesa. expand work area if clicked outside existing bounds TYPE = PROC[self: Viewer, op: ScrollOp, amount: INTEGER] -- RETURNS[top, bottom: INTEGER _ LAST[INTEGER]]; -- ScrollOp: TYPE = {query, up, down, thumb} -- Tip table (translates mouse events to commands) Κ‰˜Jšœ™Jšœ™Jšœ&™&Jšœ"™"šœ"™"Icode™$—J˜Jšœ8™8J™6J™7J™šΟk ˜ JšœœA˜MJšœ œ˜Jšœœ ˜!Jšœ œ/˜?šœœ‰˜”J˜—šœœ2˜EJ˜%—Jšœ œ2˜AJšœœ+˜8Jšœœ ˜Jšœœ˜$Jšœœ˜Jšœœœ˜!Jšœ œ˜&Jšœœ ˜Jšœ œ˜J˜J˜—šœœ˜Jšœ˜ˆJšœ ˜Jšœ ˜Jšœ™J˜Jš˜J˜Jšœ œœ˜Jšœ œ˜JšœœΟcb˜|Jšœœž:˜QJ˜Jšœ œž&˜BJšœ œž!˜J˜Jšœ]˜]JšœKœ˜PJ˜šŸ œœœ˜JšŸ œœœ˜'JšŸœœ˜Jš Ÿœœœœœž&˜aJš ŸœœœœœžR˜{Jšœœ˜J˜Jšœ œ˜Jš œwœœœœ˜ŒJ˜Jš˜Jšœ˜šŸ œœœ œ˜Mšœ"˜"šœ$˜$Jšœ ˜ Jšœ˜Jšœ˜—Jšœž˜ ——J˜š Ÿ œœ œœœ œ˜9šœ œ˜šœž˜,Jšœ ˜ šœ˜Jšœ"˜"Jšœ˜Jšœ˜Jšœ˜—Jšœ˜—Kšœ˜Kšœ˜—Jšœž˜—K˜Kš œ œœQœœ˜ŽJšœ œž˜9Jšœ#ž˜1J˜Jšœž˜4Jšœ˜Jšœ˜Jšœ˜J˜JšœMœ˜RJšœGœ˜KJ™0Kšœœœ5˜RKšœœœ5˜RKšœœœ5˜RKšœœœ5˜Ršœœœ5˜RJ˜—J˜Jšœ:ž˜SJšœ7ž˜LJšœ9ž˜NJšœ?ž˜XJšœ=ž˜UJ˜Jšœ#ž˜AJ˜Jšœ.ž˜LJšœ.ž˜LJšœ.ž˜LJšœ.ž˜LJšœ.ž˜LJ˜Jšœ#ž˜7J˜Jšœ#˜#Jšœ#˜#J™(J™Kšœœœ(˜EJšœ$˜$Jšœœ˜K˜Kšœœœ(˜EJšœ$˜$Jšœœ˜J™Kšœœœ(˜EJšœ#˜#Jšœœ˜J™Kšœœœ(˜EJšœ#˜#Jšœœ˜J™Kšœœœ(˜EJšœ#˜#Jšœœ˜J™Jšœ$ž/˜SJ˜šœ8ž˜NJ˜ Jšœœ˜ J˜ Jšœ œ˜—šœ*žœ˜Všœ˜Jšœž˜$Jšœž˜,Jšœž˜,Jšœž˜/Jšœ œ˜Jšœ˜——JšœT™TJšœ:˜:Jšœ:˜:J˜Jšœ$˜$Jšœ-ž ˜MJšœ5˜5Jšœ)˜)Jšœ'˜'Jšœ%˜%Jšœž˜—J˜J˜šŸ œœœ˜šŸœœ(œ˜>Jšœ1ž ˜œ˜GK˜—šœ˜šœœ˜4šœ1˜1Kšœ˜ ——Kšœœž˜6——Jšœ0˜0Jšœž˜J˜—J˜š Ÿœ œ œœœœ˜;Jšœ˜Jšœœ˜Jšœ œœ ˜&Jšœ;˜;Jšœž œ˜—š Ÿœœ œ œ2œ˜iKšœ"œ˜'šœ˜Kšœ˜Kš˜—Jšœœ˜š˜Jšœœœ ˜Jšœ-˜-š˜JšœPœ˜m—Jšœ˜—Jšœœ˜Jšœ˜Jšœ"œžœ˜@—š  œ˜'J˜Jšž3˜8J˜šœœ'ž!˜UJšœ'œž'˜cKšœœ\˜pJšœœ\˜oJ˜Jšœ3™3Jšœ"œ!˜IJšœœ!œ!˜MJ˜Jšœ œ˜EJšœœ#œ#˜QJ˜J˜šœœœœ˜)Jšœ œœ˜-šœ˜Jšœ8˜=JšœQœ˜\——J˜—Jšœ˜—J˜š Ÿ œœ œœœ˜Jšœ˜Kšœ˜Kš˜—Jšœœ˜š˜Jšœœœ ˜Jšœ'˜'š˜Jšœ\œ˜y—Jšœ˜—Jšœœ˜Jšœžœ˜*—š  œž&˜PJšœœ˜+Jšœ œž˜/Jšœž˜—Jšœ˜š  œžœ˜GJšœ™™™Jšœ˜šœ˜šœ˜Jšœ;˜;—Jšœ˜Jšœ˜šœ˜Jšœ;˜;—Jšœ˜Jšœ˜šœ˜Jšœl˜lJšœ˜Jšœ˜—šœ˜Jšœœ ˜Jšœœ›˜’—Jšœ˜—Jšœ˜——˜šœ,œ˜0šœ˜Jšœž:˜MJšœž8˜MJšœž"˜9Jšœž*˜?Jšœ4™4Jšœ<˜