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 USING [AppendMenuEntry, CreateEntry, CreateMenu, MenuEntry, Menu,
MenuProc, ReplaceMenuEntry, SetGuarded],
MenusPrivate USING [ClearMenu, DrawMenu, HitMenu, MarkMenu],
MessageWindow USING [Append, Blink],
TIPUser USING [TIPScreenCoords, TIPScreenCoordsRec],
UserTerminal USING [BlinkDisplay],
ViewerClasses USING [Column, ScrollOp, Viewer],
ViewerMenus,
ViewerOps USING [AcquireContext, ChangeColumn, CloseViewer, EnumerateViewers, EnumProc, InitialiseColorPainting, InvisiblePaint, MouseInViewer, PaintViewer, ReleaseContext],
ViewerSpecs USING [captionHeight, scrollBarW, windowBorderSize],
WindowManager,
WindowManagerPrivate;

WindowManagerImpl: CEDAR MONITOR

IMPORTS Carets, ColorWorld, Cursors, Imager, InputFocus, InterminalExtra, Menus, MenusPrivate,
MessageWindow, ViewerMenus, ViewerOps, UserTerminal
EXPORTS WindowManager, WindowManagerPrivate
SHARES InputFocus, Menus, 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] =
BEGIN OPEN v;
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,
menu#NIL AND mousePos.mouseY IN ((cy-wy)+ch..wh-captionHeight) => menu,
ENDCASE	=> none
]
END;

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[feedbackViewer.menu,
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	=> SetC[textPointer];

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[self.menu,
self, mousePos, red, shift, control];
$BU			=> MenusPrivate.HitMenu[self.menu,
self, mousePos, blue, shift, control];
$YU			=> MenusPrivate.HitMenu[self.menu,
self, mousePos, yellow, shift, control];
$RM, $BM, $YM
=> {MenusPrivate.MarkMenu[self.menu,
self, mousePos]};
$RD, $BD, $YD
=> MenusPrivate.MarkMenu[self.menu,
self, mousePos];
$Control		=> control _ TRUE;
$Shift			=> shift _ TRUE;
ENDCASE		=> NULL;
caption		=> SELECT z FROM
$RU			=> MenusPrivate.HitMenu[windowMenu,
self, mousePos, red, shift, control];
$BU			=> MenusPrivate.HitMenu[windowMenu,
self, closePos, blue, FALSE, FALSE];
$YU			=> MenusPrivate.HitMenu[windowMenu,
self, growPos, yellow, FALSE, FALSE];
$RM, $RD	=> MenusPrivate.MarkMenu[windowMenu,
self, mousePos];
$BM, $BD	=> MenusPrivate.MarkMenu[windowMenu,
self, closePos];
$YM, $YD	=> MenusPrivate.MarkMenu[windowMenu,
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 Menus.SetGuarded[destroyEntry,
guardDestroy OR (newVersion AND link=NIL AND ~saveInProgress)];
MenusPrivate.DrawMenu[windowMenu, context, x, y];
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[windowMenu, feedbackViewer, FALSE];
feedbackViewer _ v;
END;
InternalDrawCaptionMenu[v, TRUE];
END;

RemoveCaptionFeedback: ENTRY PROC = BEGIN
ENABLE UNWIND => NULL;
IF feedbackViewer#NIL THEN BEGIN
MenusPrivate.ClearMenu[windowMenu, 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[];
Menus.ReplaceMenuEntry[windowMenu, tNopEntry, tColorEntry];
growPos^ _ [growEntry.xPos+1, FALSE, 0];
closePos^ _ [closeEntry.xPos+1, FALSE, 0];
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;
Menus.ReplaceMenuEntry[windowMenu, tColorEntry, tNopEntry];
growPos^ _ [growEntry.xPos+1, FALSE, 0];
closePos^ _ [closeEntry.xPos+1, FALSE, 0];
END;

BuildWindowMenus: PROC = BEGIN
windowMenu _ Menus.CreateMenu[];
Menus.AppendMenuEntry[windowMenu, destroyEntry _ Menus.CreateEntry[name: "Destroy",
proc: ViewerMenus.Destroy, fork: FALSE, documentation: "Edits will be discarded..."]];
Menus.AppendMenuEntry[windowMenu, Menus.CreateEntry[name: "Adjust",
proc: ViewerMenus.Adjust, fork: FALSE]];
Menus.AppendMenuEntry[windowMenu, Menus.CreateEntry[name: "Top",
proc: ViewerMenus.Top, fork: FALSE]];
Menus.AppendMenuEntry[windowMenu, Menus.CreateEntry[name: "",
proc: ViewerMenus.Left, fork: FALSE]];
Menus.AppendMenuEntry[windowMenu, Menus.CreateEntry[name: "",
proc: ViewerMenus.Right, fork: FALSE]];
Menus.AppendMenuEntry[windowMenu, tNopEntry _ Menus.CreateEntry["", NIL]];
tColorEntry _ Menus.CreateEntry[name: "Color", proc: ViewerMenus.Color, fork: FALSE];
Menus.AppendMenuEntry[windowMenu, growEntry _ Menus.CreateEntry[name: "Grow",
proc: ViewerMenus.Grow, fork: FALSE]];
Menus.AppendMenuEntry[windowMenu, closeEntry _ Menus.CreateEntry[name: "Close",
proc: ViewerMenus.Close, fork: FALSE]];
growPos _ NEW[TIPUser.TIPScreenCoordsRec _ [growEntry.xPos+1, FALSE, 0]];
closePos _ NEW[TIPUser.TIPScreenCoordsRec _ [closeEntry.xPos+1, FALSE, 0]];
END;

colorDisplayOn: PUBLIC BOOL _ FALSE;	-- color display status

windowMenu: PUBLIC Menus.Menu;
destroyEntry, closeEntry, growEntry, tColorEntry, tNopEntry: Menus.MenuEntry;
growPos, closePos: TIPUser.TIPScreenCoords;

BuildWindowMenus[];

END.


�����WindowManagerImpl.mesa; Written by S. McGregor
Edited by McGregor on August 8, 1983 1:18 pm
Last Edited by: Maxwell, February 8, 1983 3:58 pm
not monitored since notifier is synchronous
flip origin
Ê
=��–
"cedar" style˜�JšÏc.™.Jš,™,Jšœ1™1J˜�šÏk	˜	Jšœžœ˜+Jšœžœ˜-Jšœžœ$˜1JšœžœG˜WJšœžœ˜%Jšœžœp˜|šœžœ<˜GJ˜(—Jšœ
žœ*˜<Jšœžœ˜$Jšœžœ'˜4Jšœ
žœ˜"Jšœžœ˜/J˜Jšœ
žœž˜­Jšœžœ/˜@J˜J˜J˜�—Jšœž
˜ J˜�šžœW˜^Jšœ3˜3—Jšžœ$˜+Jšžœ.˜4J˜�Jšžœžœ%˜/J˜�Jšœžœ*˜4J˜J˜�šÏn
œžœ0žœ˜SJšžœžœ˜
šžœžœžœž˜Jš	œžœžœžœžœ#˜VJš	œžœžœžœžœ˜[Jšœžœžœžœ(˜Gšžœ˜J˜——Jšžœ˜J˜�—šŸœžœžœžœžœžœžœž˜PJš+™+J˜Jšœ	žœ˜Jšœžœžœ˜J˜"J˜�Jšžœžœžœžœžœžœžœžœžœ	žœž˜P˜�Jšœžœžœžœ˜!˜�š	žœ	žœžœžœ˜9J˜6˜GJšœ"žœ˜'—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šžœžœ˜—šœ	žœž˜˜(J˜%—˜(J˜&—˜(J˜(—˜
˜$J˜——˜
˜#J˜——Jšœžœ˜Jšœžœ˜Jšžœžœ˜—šœžœž˜˜)J˜%—˜)Jšœžœžœ˜$—˜)Jšœžœžœ˜%—˜-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šžœ˜J˜�—šŸœžœž˜"J˜Jšœžœ˜Jšžœžœžœžœ˜"J˜˜UJšœžœ˜)—š	žœžœžœ*žœž˜TJš™Jšœ;˜;Jšœ!˜!˜JJšœžœžœžœ˜8—Jšž˜—Jšžœžœžœžœ˜YJšœžœžœžœ˜TJ˜'J˜PJ˜"Jšžœ˜
Jšžœžœ˜<Jšžœ˜J˜�—š
Ÿœžœžœžœžœ˜=Jšœžœžœžœ%˜;J˜�—šŸœžœžœžœžœžœ˜OJ˜šŸœžœž˜Jšœžœ˜J˜J˜JšœP˜PJ˜'J˜<J˜'šžœžœ˜,Jš	œ
žœ
žœžœžœ˜?—J˜1Jšžœ˜—Jš
žœžœžœ
žœžœ˜6˜7Jšœžœ˜)—Jšœ$˜$Jšœ"˜"Jšžœ	žœ˜Jšžœ˜J˜�—šŸœžœžœž˜3Jšžœžœžœ˜šžœžœžœ
˜,šžœžœž˜Jšœ3žœ˜:—J˜Jšžœ˜—Jšœžœ˜!Jšžœ˜J˜�—šŸœžœžœž˜)Jšžœžœžœ˜šžœžœžœž˜ Jšœ3žœ˜:J˜/Jšœžœ˜Jšžœ˜—Jšžœ˜J˜�—Jšœžœžœ˜J˜�š	Ÿ
œžœžœžœ,ž˜NJšžœžœžœ˜Jšžœžœ˜2J˜Jšžœ˜J˜�—š	Ÿœžœžœžœž˜'Jšžœžœžœ˜Jšœžœ˜"Jšžœ
žœ˜$Jšžœ˜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˜ ˜SJšœ!žœ0˜V—˜CJšœ žœ˜(—˜@Jšœžœ˜%—˜?Jšœžœ˜&—˜?Jšœžœ˜'—JšœDžœ˜JJšœNžœ˜U˜MJšœžœ˜&—˜OJšœžœ˜'—Jšœ
žœ1žœ˜IJšœžœ2žœ˜KJšžœ˜J˜�—Jšœžœžœžœ˜<J˜�Jšœžœ˜J˜MJ˜+J˜�J˜J˜�Jšžœ˜J˜�J˜�—�…—����1”��?��