DIRECTORY Carets USING [ResumeCarets, SuspendCarets], IconManager USING [selectedIcon], Icons USING [DrawIcon], Imager USING [black, ClipView, Context, Create, DoSave, IntegerClipRectangle, IntegerMaskRectangle, IntegerSetXY, Reset, SetColor, SetView, ShowCharacters, TranslateT, white, XOR], MenusPrivate USING [DrawMenu, ViewerMenus], Process USING [Detach, GetCurrent, MsecToTicks, Pause, Ticks], Rope USING [ROPE], VFonts USING [defaultFont, FONT, RopeWidth], ViewerOps USING [AddProp, ChangeColumn, EnumerateViewers, EnumProc, FetchProp, GreyScreen, PaintHint, UserToScreenCoords, ViewerColumn], ViewerClasses USING [PaintRectangle, Viewer], ViewerLocks USING [CallUnderReadLock, CallUnderWriteLock, ColumnWedged, Wedged], ViewerSpecs USING [captionDescent, captionHeight, iconHeight, iconWidth, menuBarHeight, openBottomY, windowBorderSize], ViewersStallNotifier USING [], ViewerTools USING [GetSelectedViewer]; ViewerPaintImpl: CEDAR MONITOR IMPORTS Carets, Imager, IconManager, Icons, MenusPrivate, Process, VFonts, ViewerLocks, ViewerTools, ViewerOps, ViewerSpecs EXPORTS ViewerOps, ViewersStallNotifier SHARES ViewerClasses, ViewerLocks = BEGIN OPEN ViewerSpecs; Viewer: TYPE = ViewerClasses.Viewer; PaintRectangle: TYPE = ViewerClasses.PaintRectangle; PaintHint: TYPE = ViewerOps.PaintHint; Context: TYPE = Imager.Context; ROPE: TYPE = Rope.ROPE; InvisiblePaint: PUBLIC SIGNAL = CODE; PaintCaption: PROC[viewer: Viewer, context: Context] = { IF viewer.class.caption#NIL THEN { -- client-painted caption CallClient: PROC = { wbs: INTEGER = IF viewer.border THEN windowBorderSize ELSE 0; Imager.IntegerClipRectangle[context, viewer.wx+wbs, viewer.wy+viewer.wh-wbs-captionHeight, viewer.ww-(2*wbs), captionHeight]; viewer.class.caption[viewer, context]; }; Imager.DoSave[context, CallClient]; } ELSE { font: VFonts.FONT = VFonts.defaultFont; headerW: INTEGER _ VFonts.RopeWidth[viewer.name]; IF viewer.saveInProgress THEN headerW _ headerW + sipW ELSE IF viewer.newFile THEN headerW _ headerW + newFW ELSE IF viewer.newVersion THEN headerW _ headerW + newVW; IF viewer.link#NIL THEN headerW _ headerW + linkW; headerW _ MIN[headerW, viewer.ww]; Imager.IntegerMaskRectangle[context, viewer.wx, viewer.wy+viewer.wh-captionHeight, viewer.ww, captionHeight]; Imager.SetColor[context, Imager.white]; Imager.IntegerSetXY[context, viewer.wx+(viewer.ww-headerW)/2, viewer.wy+viewer.wh-captionHeight+captionDescent]; Imager.ShowCharacters[context, viewer.name, font]; IF viewer.saveInProgress THEN Imager.ShowCharacters[context, sipT, font] ELSE IF viewer.newFile THEN Imager.ShowCharacters[context, newFT, font] ELSE IF viewer.newVersion THEN Imager.ShowCharacters[context, newVT, font]; IF viewer.link#NIL THEN Imager.ShowCharacters[context, linkT, font]; }; }; PaintDocumentHeader: PROC[viewer: Viewer, context: Context, clear: BOOL, hint: PaintHint, whatChanged: REF ANY] = { Imager.IntegerClipRectangle[context, viewer.wx, viewer.wy, viewer.ww, viewer.wh]; IF hint#menu THEN PaintCaption[viewer, context]; IF viewer.menus#NIL AND hint#caption THEN { menus: MenusPrivate.ViewerMenus = NARROW[viewer.menus]; menuHeight: INTEGER = menus.h; wbs: INTEGER = IF viewer.border THEN windowBorderSize ELSE 0; IF whatChanged=NIL THEN { IF ~clear THEN { Imager.SetColor[context, Imager.white]; Imager.IntegerMaskRectangle[context, viewer.wx+wbs, viewer.wy+viewer.wh-wbs-captionHeight-menuHeight, viewer.ww-(2*wbs), menuHeight]; }; Imager.SetColor[context, Imager.black]; Imager.IntegerMaskRectangle[context, viewer.wx, viewer.wy+viewer.wh-wbs-captionHeight-menuHeight, viewer.ww, menuBarHeight]; }; MenusPrivate.DrawMenu[viewer, menus, context, whatChanged]; }; }; PaintIcon: PROC[viewer: Viewer, hint: PaintHint, whatChanged: REF ANY _ NIL] = { context: Context; IF viewer.parent#NIL THEN RETURN; context _ AcquireContext[viewer, FALSE]; -- all icons on b&w display IF viewer.icon=private THEN -- client wants to draw the icon viewer.class.paint[viewer, context, whatChanged, hint=all] ELSE IF hint=all OR hint=caption THEN { label: ROPE = GetIconLabel[viewer]; DrawIcon: PROC = {Icons.DrawIcon[flavor: viewer.icon, context: context, label: label]}; IF viewer.icon=document AND (viewer.newVersion OR viewer.newFile) THEN viewer.icon _ dirtyDocument ELSE IF viewer.icon=dirtyDocument AND NOT (viewer.newVersion OR viewer.newFile) THEN viewer.icon _ document; Imager.DoSave[context, DrawIcon]; IF IconManager.selectedIcon=viewer THEN { Imager.SetColor[context, Imager.XOR]; Imager.IntegerMaskRectangle[context, 0, 0, iconWidth, iconHeight]; }; }; ReleaseContext[context]; }; SetIconLabel: PUBLIC PROC[viewer: Viewer, label: ROPE] = { ViewerOps.AddProp[viewer, $IconLabel, label]; }; GetIconLabel: PROC[viewer: Viewer] RETURNS[label: ROPE] = { prop: REF ANY = ViewerOps.FetchProp[viewer, $IconLabel]; IF prop#NIL THEN RETURN[NARROW[prop]] ELSE RETURN[viewer.name]; }; RecursivelyPaintViewers: PROC [viewer: Viewer, hint: PaintHint, clearClient: BOOL, clear: BOOL, rect: PaintRectangle, whatChanged: REF ANY] = { vx, vy: INTEGER; context: Context _ NIL; bitmapY: INTEGER _ 0; FOR v: Viewer _ viewer, v.parent UNTIL v=NIL DO -- visibility test IF v.parent#NIL THEN { IF (v.wy+v.wh < 0) OR (v.wy > v.parent.ch) THEN RETURN; IF (v.ww+v.ww < 0) OR (v.wx > v.parent.cw) THEN RETURN; } ENDLOOP; IF hint#client THEN { ENABLE UNWIND => IF context#NIL THEN ReleaseContext[context]; PaintHeader: PROC = {PaintDocumentHeader[viewer, context, clear, hint, whatChanged]}; context _ AcquireContext[viewer.parent, viewer.column=color]; IF ~viewer.visible OR viewer.destroyed THEN SIGNAL InvisiblePaint; IF clearClient AND ~clear AND hint=all THEN { Imager.SetColor[context, Imager.white]; Imager.IntegerMaskRectangle[context, viewer.wx, viewer.wy, viewer.ww, viewer.wh]; Imager.SetColor[context, Imager.black]; clear _ TRUE; }; IF viewer.border AND hint=all THEN { wbs: INTEGER ~ windowBorderSize; Imager.IntegerMaskRectangle[context, viewer.wx, viewer.wy, viewer.ww, wbs]; Imager.IntegerMaskRectangle[context, viewer.wx, viewer.wy, wbs, viewer.wh]; Imager.IntegerMaskRectangle[context, viewer.wx+viewer.ww-wbs, viewer.wy, wbs, viewer.wh]; Imager.IntegerMaskRectangle[context, viewer.wx, viewer.wy+viewer.wh-wbs, viewer.ww, wbs]; }; IF viewer.parent=NIL AND viewer.column#static THEN Imager.DoSave[context, PaintHeader]; ReleaseContext[context]; }; IF hint=all OR hint=client THEN { ENABLE UNWIND => IF context#NIL THEN ReleaseContext[context]; PaintClient: PROC = {viewer.class.paint[viewer, context, whatChanged, clear]}; context _ NIL; context _ AcquireContext[viewer, viewer.column=color]; IF ~viewer.visible OR viewer.destroyed THEN SIGNAL InvisiblePaint; IF rect#NIL AND rect.flavor=blt AND viewer.class.bltContents = none THEN clearClient _ TRUE; IF clearClient AND ~clear THEN { Imager.SetColor[context, Imager.white]; Imager.IntegerMaskRectangle[context, 0, 0, viewer.cw, viewer.ch]; Imager.SetColor[context, Imager.black]; IF rect # NIL THEN whatChanged _ NIL; rect _ NIL; clear _ TRUE; }; IF viewer.class.paint#NIL THEN { IF viewer.clientContext THEN PaintClient[] ELSE Imager.DoSave[context, PaintClient]; }; ReleaseContext[context]; }; IF rect # NIL AND rect.flavor=blt AND viewer.parent = NIL THEN { IF viewer.cx >= rect.x AND (viewer.cx + viewer.cw <= rect.x + rect.w) AND viewer.cy >= rect.y AND (viewer.cy + viewer.ch <= rect.y + rect.h) THEN RETURN}; IF hint=all OR clear THEN FOR v: Viewer _ viewer.child, v.sibling UNTIL v=NIL DO IF rect # NIL AND rect.flavor=blt THEN { -- don't paint if it is completely within the blt [vx, vy] _ ViewerOps.UserToScreenCoords[viewer, v.wx, v.wy]; IF vx >= rect.x AND (vx + v.ww <= rect.x + rect.w) AND vy >= rect.y AND (vy + v.wh <= rect.y + rect.h) THEN LOOP}; RecursivelyPaintViewers[v, all, FALSE, clear, rect, whatChanged]; ENDLOOP; }; PaintViewer: PUBLIC PROC [viewer: Viewer, hint: PaintHint _ client, clearClient: BOOL _ TRUE, whatChanged: REF ANY _ NIL] = { LocalPaintViewer: PROC = { ENABLE ABORTED => {Carets.ResumeCarets[]; CONTINUE}; rect: PaintRectangle _ NIL; IF ~viewer.visible OR viewer.destroyed THEN RETURN; IF viewer.iconic THEN {PaintIcon[viewer, hint, whatChanged]; RETURN}; WITH whatChanged SELECT FROM r: PaintRectangle => rect _ r; ENDCASE; Carets.SuspendCarets[]; RecursivelyPaintViewers[viewer, hint, clearClient AND ~(hint=menu OR hint=caption), FALSE, rect, whatChanged ! InvisiblePaint => CONTINUE]; Carets.ResumeCarets[]; }; ViewerLocks.CallUnderReadLock[LocalPaintViewer, viewer ! ViewerLocks.Wedged => CONTINUE]; }; PaintVector: TYPE = REF PaintVectorRec; PaintVectorRec: TYPE = RECORD [ next: PaintVector _ NIL, viewer: Viewer _ NIL, inUse: BOOL _ FALSE, resetOnRelease: BOOL _ FALSE, color: BOOL _ FALSE, process: UNSAFE PROCESS _ NIL, context: Context _ NIL, previous: PaintVector _ NIL]; nVectors: CARDINAL = 5; usedVectors: CARDINAL _ 0; PaintVectorAvailable: CONDITION; paintingLock: CARDINAL _ 0; vectorRoot: PaintVector _ NIL; Init: ENTRY PROC = { new: PaintVector; FOR n: CARDINAL IN [0..nVectors) DO new _ NEW[PaintVectorRec]; new.context _ Imager.Create[$LFDisplay]; new.next _ vectorRoot; IF vectorRoot#NIL THEN vectorRoot.previous _ new; vectorRoot _ new; ENDLOOP; newFW _ VFonts.RopeWidth[newFT]; newVW _ VFonts.RopeWidth[newVT]; linkW _ VFonts.RopeWidth[linkT]; sipW _ VFonts.RopeWidth[sipT]; }; colorInit: BOOL _ FALSE; InitialiseColorPainting: PUBLIC PROC = { colorInit _ TRUE; ViewerOps.GreyScreen[0, 0, 9999, 9999, TRUE, FALSE]; }; ZapVector: INTERNAL PROC [p: PaintVector] = { oldContext: Context _ p.context; p.context _ Imager.Create[$LFDisplay]; p.viewer _ NIL; p.inUse _ FALSE; p.process _ NIL; IF ~p.color THEN usedVectors _ usedVectors - 1; Imager.SetView[oldContext, [0,0,0,0]]; -- smash old BROADCAST PaintVectorAvailable; }; UnWedgePainter: PUBLIC ENTRY PROC [process: PROCESS, kind: ATOM] = { ENABLE UNWIND => NULL; FOR p: PaintVector _ vectorRoot, p.next UNTIL p=NIL DO IF p.inUse AND p.process=process THEN ZapVector[p]; ENDLOOP; }; UnWedge: ENTRY PROC [process: PROCESS, kind: ATOM] = { FOR p: PaintVector _ vectorRoot, p.next UNTIL p=NIL DO IF p.inUse THEN ZapVector[p]; ENDLOOP; usedVectors _ 0; -- make sure paintingLock _ 0; -- make sure BROADCAST PaintVectorAvailable; }; InternalDisablePainting: INTERNAL PROC [wait: BOOL _ TRUE] = INLINE { IF wait THEN WHILE usedVectors#0 DO WAIT PaintVectorAvailable; ENDLOOP; paintingLock _ paintingLock+1; }; DisablePainting: PUBLIC ENTRY PROC [wait: BOOL _ TRUE] = { ENABLE UNWIND => NULL; InternalDisablePainting[wait]; }; InternalEnablePainting: INTERNAL PROC = INLINE { IF paintingLock#0 THEN paintingLock _ paintingLock-1; IF paintingLock=0 THEN BROADCAST PaintVectorAvailable; }; EnablePainting: PUBLIC ENTRY PROC = { ENABLE UNWIND => NULL; InternalEnablePainting[]; }; DisablePaintingUnWedged: INTERNAL PROC [wait: BOOL _ TRUE] = INLINE { AllWedged: INTERNAL PROC RETURNS[BOOL] = INLINE { FOR p: PaintVector _ vectorRoot, p.next UNTIL p=NIL DO IF ~p.inUse THEN LOOP; IF p.viewer = NIL THEN RETURN[FALSE]; -- context = screen IF ~ViewerLocks.ColumnWedged[ViewerOps.ViewerColumn[p.viewer]].wedged THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]; }; IF wait THEN { WHILE usedVectors#0 DO IF AllWedged[] THEN EXIT ELSE WAIT PaintVectorAvailable; ENDLOOP; }; paintingLock _ paintingLock+1; }; WaitForPaintingToFinish: PUBLIC ENTRY PROC = { WHILE usedVectors#0 DO WAIT PaintVectorAvailable ENDLOOP; }; ResetPaintCache: PUBLIC ENTRY PROC [viewer: Viewer _ NIL, wait: BOOL _ TRUE] = { ENABLE UNWIND => NULL; DisablePaintingUnWedged[wait]; FOR p: PaintVector _ vectorRoot, p.next UNTIL p=NIL DO IF p.inUse THEN { IF p.viewer = NIL OR ~ViewerLocks.ColumnWedged[ViewerOps.ViewerColumn[p.viewer]].wedged THEN IF wait THEN RETURN WITH ERROR fatalViewersError; p.resetOnRelease _ TRUE; } ELSE IF p.viewer#NIL THEN { Imager.Reset[p.context]; p.viewer _ NIL; }; ENDLOOP; InternalEnablePainting[]; }; fatalViewersError: ERROR = CODE; ReleaseContext: PUBLIC ENTRY PROC [free: Context] = { ENABLE UNWIND => NULL; CleanUp: INTERNAL PROC [p: PaintVector] = { p.inUse _ FALSE; IF usedVectors=0 THEN RETURN WITH ERROR fatalViewersError ELSE usedVectors _ usedVectors-1; IF p.resetOnRelease THEN { Imager.Reset[p.context]; p.viewer _ NIL; p.resetOnRelease _ FALSE; }; p.process _ NIL; BROADCAST PaintVectorAvailable; }; IF free=NIL THEN RETURN WITH ERROR fatalViewersError; FOR p: PaintVector _ vectorRoot, p.next UNTIL p=NIL DO IF free=p.context THEN {CleanUp[p]; EXIT}; ENDLOOP; }; AcquireContext: PUBLIC ENTRY PROC [viewer: Viewer, color: BOOL _ FALSE] RETURNS [allocated: Context] = { ENABLE UNWIND => NULL; bestFit: PaintVector; nil: BOOL _ FALSE; MakeFirst: INTERNAL PROC [pv: PaintVector] = INLINE { -- LRU caching scheme IF pv=vectorRoot THEN RETURN; pv.previous.next _ pv.next; IF pv.next#NIL THEN pv.next.previous _ pv.previous; pv.next _ vectorRoot; vectorRoot.previous _ pv; vectorRoot _ pv; }; IF color THEN { IF ~colorInit THEN ERROR fatalViewersError }; UNTIL usedVectors openBottomY THEN { ClipIcon[context]; Imager.ClipView[context, [viewer.wx, viewer.wy, viewer.ww, viewer.wh], FALSE]; Imager.TranslateT[context, viewer.wx, viewer.wy]; --xlate since ClipView does no x,y translation } ELSE Imager.SetView[context, [viewer.wx, viewer.wy, viewer.ww, viewer.wh]]; } ELSE IF viewer.parent=NIL THEN { Imager.SetView[context, [viewer.cx, viewer.cy, viewer.cw, viewer.ch]]; } ELSE { RecursivelyPushParent[viewer]; Imager.TranslateT[context, x, y]; }; }; InvertForMenus: PUBLIC PROC [viewer: Viewer, x: INTEGER, y: INTEGER, w: INTEGER, h: INTEGER] = { context: Context _ AcquireContext[viewer.parent, viewer.column=color]; ActuallyDoDrawing: PROC = { Imager.IntegerClipRectangle[context, viewer.wx, viewer.wy, viewer.ww, viewer.wh]; Imager.SetColor[context, Imager.XOR]; Imager.IntegerMaskRectangle[context, x, y, w, h]; }; Imager.DoSave[context, ActuallyDoDrawing]; ReleaseContext[context]; }; ClipIcon: PROC [context: Context] = { ClipOpenViewer: ViewerOps.EnumProc = { IF ~v.iconic AND (v.column=right OR v.column=left) THEN Imager.ClipView[context, [v.wx, v.wy, v.ww, v.wh], TRUE]; }; ViewerOps.EnumerateViewers[ClipOpenViewer]; }; BlinkIcon: PUBLIC PROC [viewer: Viewer, count, interval: NAT] = { IF interval >= 1000 THEN interval _ interval/1000; IF viewer.offDeskTop THEN ViewerOps.ChangeColumn[viewer, left]; IF count = 1 THEN BlinkProcess[viewer, count, interval] ELSE TRUSTED {Process.Detach[FORK BlinkProcess[viewer, count, interval]]}; }; BlinkProcess: PROC [viewer: Viewer, count, n: NAT] = { howOften: Process.Ticks = Process.MsecToTicks[500]; Blink: PROC = { context: Context; IF NOT viewer.visible OR viewer.destroyed THEN RETURN; context _ AcquireContext[viewer, IF viewer.iconic THEN FALSE ELSE viewer.column=color]; Imager.SetColor[context, Imager.XOR]; Imager.IntegerMaskRectangle[context, 0, 0, viewer.ww, viewer.wh]; Process.Pause[Process.MsecToTicks[400]]; Imager.IntegerMaskRectangle[context, 0, 0, viewer.ww, viewer.wh]; ReleaseContext[context]; Process.Pause[Process.MsecToTicks[350]]; -- so can be called back-to-back }; DO ViewerLocks.CallUnderWriteLock[Blink, viewer]; IF count = 1 THEN RETURN; IF count > 0 THEN count _ count - 1; FOR i: NAT IN [0..2*n) DO -- blink every n seconds, but wake up every half second. Process.Pause[howOften]; IF viewer.destroyed OR ~viewer.iconic OR viewer = ViewerTools.GetSelectedViewer[] THEN RETURN; ENDLOOP; ENDLOOP; }; newVT: ROPE = " [New Version]"; newVW: INTEGER; newFT: ROPE = " [New File]"; newFW: INTEGER; linkT: ROPE = " [Split]"; linkW: INTEGER; sipT: ROPE = " [Saving...]"; sipW: INTEGER; Init[]; ViewerOps.GreyScreen[0, 0, 9999, 9999, FALSE, FALSE]; END. ViewerPaintImpl.mesa; written by S. McGregor Edited by McGregor on August 8, 1983 4:00 pm Edited by Maxwell, June 3, 1983 8:23 am Last Edited by: Pausch, August 26, 1983 3:39 pm Last Edited by: Wyatt, October 24, 1983 12:37 pm Paint caption: Paint menu: Clear the menu area, if necessary Draw the bar below the menu do we need to paint any of the children? recursively paint children these guys should be painted in reverse order for correct overlaps map to the coodinate system that rect uses IF viewer.class.coordSys = top THEN [vx, vy] _ ViewerOps.UserToScreenCoords[viewer, v.wx, v.wy+v.wh] ELSE [vx, vy] _ ViewerOps.UserToScreenCoords[viewer, v.wx, v.wy]; call from debugger broadcast since all are likely to be free assumes interesting paints already in progress invert: BOOL _ FALSE; invertCoords: BOOL = IF v.parent=NIL THEN v.class.coordSys=top ELSE v.class.coordSys#v.parent.class.coordSys; IF invert THEN y _ y + v.parent.ch - v.cy - v.ch ELSE IF invertCoords THEN invert _ ~invert; IF viewer.class.coordSys=top THEN { Imager.TranslateT[context, 0, viewer.ch]; Imager.Scale2T[context, 1, -1]; }; IF invert THEN { Imager.TranslateT[context, x, y+viewer.ch]; Imager.Scale2T[context, 1, -1]; } ELSE clips for overlapping top level windows given valid Context and Viewer ΚΊ– "cedar" style˜JšΟc,™,Jš,™,J™'J™/J™0J˜šΟk ˜ Jšœžœ˜+Jšœ žœ˜!Jšœžœ ˜Jšœžœ£žœ˜΄Jšœ žœ˜+Jšœžœ1˜>Jšœžœžœ˜Jšœžœžœ ˜,Jšœ žœy˜ˆJšœžœ˜-Jšœ žœ@˜QJšœ žœf˜wJšœžœ˜Jšœ žœ˜&J˜—Jšœžœž˜Jšžœt˜{Jšžœ ˜'Jšžœ˜!Jšœžœžœ ˜J˜Jšœžœ˜$Jšœžœ ˜4Jšœ žœ˜&Jšœ žœ˜Jšžœžœžœ˜J˜Jšœžœžœžœ˜%J˜šΟn œžœ&˜8šžœžœžœ˜<šŸ œžœ˜Jš œžœžœžœžœ˜=˜$J˜5J˜"—J˜&Jšœ˜—J˜#Jšœ˜—šžœ˜Jšœ žœ˜'Jšœ žœ!˜1Jšžœžœ˜6Jšžœžœžœ˜5Jšžœžœžœ˜9Jšžœ žœžœ˜2Jšœ žœ˜"˜$J˜H—J˜'˜J˜ J˜2—Jšœ2˜2Jšžœžœ+˜HJšžœžœžœ,˜GJšžœžœžœ-˜KJšžœ žœžœ-˜DJšœ˜—J˜J˜—š Ÿœžœ*žœ žœžœ˜sJ˜QJ™Jšœ™Jšžœ žœ˜0J™Jšœ ™ šžœžœžœžœ˜+Jšœ"žœ˜7Jšœ žœ ˜Jš œžœžœžœžœ˜=šžœ žœžœ˜Jšœ!™!šžœžœ˜J˜'˜$J˜@J˜—Jšœ˜—Jšœ™J˜'˜$J˜Jšžœ*™.—J˜ Jšžœžœ#ž™5Jšœ ˜ Jšœ-žœ˜4Jšžœžœ™&Jšœ˜—Jšœ˜Jšžœžœžœž˜šžœžœžœ˜šžœ#žœ˜+Jšœ˜JšœGžœ˜NJšœ2.˜`Jšœ˜—JšžœG˜KJšœ˜—šžœžœžœžœ˜ JšœF˜Fšžœžœ™#J™)Jšœ™Jšœ™—Jšœ˜—šžœ˜Jšœ˜šžœžœ™J™+Jšœ™Jšœž™—Jšœ!˜!Jšœ˜—Jšœ˜J˜—šŸœžœžœžœžœžœžœ˜`J˜FšŸœžœ˜JšœQ˜QJšœ žœ˜%Jšœ1˜1J˜—J˜*J˜Jšœ˜J˜—šŸœžœ˜%JšF™Fšœ&˜&šžœ žœžœž˜7Jšœ3žœ˜9—Jšœ˜—J˜+Jšœ˜J˜—šŸ œžœžœ#žœ˜AJšžœžœ˜2Jšžœžœ&˜?Jšžœ žœ&˜7Jšžœžœžœ)˜JJšœ˜J˜—šŸ œžœžœ˜7Jšœ3˜3šŸœžœ˜J˜Jš žœžœžœžœžœ˜6Jš œ!žœžœžœžœ˜WJšœ žœ˜%J˜AJ˜(J˜AJ˜Jšœ) ˜IJšœ˜—šž˜J˜.Jšžœ žœžœ˜Jšžœ žœ˜$š žœžœžœ žœ8˜SJšœ˜šžœžœ˜&Jšžœ*žœžœ˜8—Jšžœ˜—Jšžœ˜—Jšœ˜J˜—J˜Jšœžœ˜ Jšœžœ˜J˜Jšœžœ˜Jšœžœ˜J˜Jšœžœ˜Jšœžœ˜J˜Jšœžœ˜Jšœžœ˜J˜J˜J˜Jšœ'žœžœ˜5J˜Jšžœ˜J˜J˜—…—Bf^(