DIRECTORY Basics USING [bytesPerWord], FS USING [StreamOpen, Error], Imager USING [Box], IconEditorDefs, IconRegistry USING [IsRegistered, InvalidateCache], IO USING [Close, Error, Flush, GetLength, STREAM, UnsafeGetBlock, UnsafePutBlock], MessageWindow USING [Append, Blink], Real USING [FixI], Rope USING [ROPE], RuntimeError USING [BoundsFault], PrincOpsUtils USING [IsBound] ; IconEditorIO: CEDAR PROGRAM IMPORTS FS, IO, IconRegistry, MessageWindow, Real, RuntimeError, PrincOpsUtils EXPORTS IconEditorDefs = { CouldntLoadIcons: PUBLIC SIGNAL = CODE; CouldntSaveIcons: PUBLIC SIGNAL = CODE; ViewerNoGood: PUBLIC SIGNAL = CODE; PointsMarked: PUBLIC PROC [handle: IconEditorDefs.IconHandle, type: IconEditorDefs.MarkType] RETURNS [BOOLEAN] = { IF (handle.mark1.x = 0) AND (handle.mark1.y = 0) AND (handle.mark2.x = 0) AND (handle.mark2.y = 0) THEN { SELECT type FROM rect => MessageWindow.Append["Hold down yellow mouse button and mark a rectangular area first...", TRUE]; line => MessageWindow.Append["Hold down yellow mouse button and control key and mark a line first...", TRUE]; ENDCASE => ERROR; MessageWindow.Blink[]; RETURN[FALSE] } ELSE RETURN[TRUE]; }; SaveBitMap: PUBLIC PROC [handle: IconEditorDefs.IconHandle] = { handle.savedBitMap _ handle.icons[LOOPHOLE[handle.currentIC]].bits; }; LayoutBoard: PUBLIC PROC [handle: IconEditorDefs.IconHandle, bounds: Imager.Box] = { iconsOnDisplay: IconEditorDefs.Nat _ MIN[handle.numberOfIcons, IconEditorDefs.maxIconsOnDisplay]; handle.numIconsPerRow _ Real.FixI[bounds.xmax/(IconEditorDefs.iconW+IconEditorDefs.distX)]; handle.numIconsPerCol _ Real.FixI[bounds.ymax/(IconEditorDefs.iconH+IconEditorDefs.distY)]; IF handle.numIconsPerRow*handle.numIconsPerCol < iconsOnDisplay THEN { MessageWindow.Append["Icon Editor viewer is too small to display current Icon menu.", TRUE]; SIGNAL ViewerNoGood }; handle.possibleX _ Real.FixI[bounds.xmax - ((iconsOnDisplay + handle.numIconsPerCol - 1) / handle.numIconsPerCol) * (IconEditorDefs.iconW + IconEditorDefs.distX)]; handle.possibleY _ Real.FixI[bounds.ymax - ((iconsOnDisplay + handle.numIconsPerRow-1) / handle.numIconsPerRow) * (IconEditorDefs.iconH+IconEditorDefs.distY)]; IF handle.possibleX < IconEditorDefs.minimumUnit * IconEditorDefs.iconW AND handle.possibleY < IconEditorDefs.minimumUnit * IconEditorDefs.iconH THEN { MessageWindow.Append["Icon Editor viewer is too small for a decent drawing board.", TRUE]; SIGNAL ViewerNoGood }; IF handle.possibleX <= handle.possibleY THEN { -- use a vertical layout, preferred if square handle.boardSize _ MIN[bounds.xmax, handle.possibleY]; handle.numIconsPerCol _ (iconsOnDisplay + handle.numIconsPerRow - 1) / handle.numIconsPerRow; handle.icX _ 0; handle.icY _ Real.FixI[handle.boardSize] + 1 } ELSE { -- use a horizontal layout handle.boardSize _ MIN[bounds.ymax, handle.possibleX]; handle.numIconsPerRow _ (iconsOnDisplay + handle.numIconsPerCol - 1) / handle.numIconsPerCol; handle.icX _ Real.FixI[handle.boardSize] + 1; handle.icY _ 0 }; handle.unit _ Real.FixI[handle.boardSize / (IconEditorDefs.intHBound + 1)]; handle.boardSize _ handle.unit * (IconEditorDefs.intHBound + 1); }; GetNewFlavor: PUBLIC PROC [handle: IconEditorDefs.IconHandle] RETURNS [newFlavor: IconEditorDefs.IconFlavor] = { newFlavor _ handle.nextFlavor; handle.nextFlavor _ SUCC[newFlavor]; IF LOOPHOLE[handle.nextFlavor, IconEditorDefs.Nat] >= IconEditorDefs.maxStorage THEN { MessageWindow.Append[message: "Sorry- you have exceeded the current limit on number of icons.", clearFirst: TRUE]; MessageWindow.Blink[]; ERROR }; }; LoadIcons: PUBLIC PROC[handle: IconEditorDefs.IconHandle, filename: Rope.ROPE] RETURNS [nRead: IconEditorDefs.Nat, iconFile: IO.STREAM _ NIL] = TRUSTED { ENABLE IO.Error => GOTO Punt; badNews: BOOL _ FALSE; newFlavor: IconEditorDefs.IconFlavor; handle.nextFlavor _ FIRST[IconEditorDefs.IconFlavor]; -- Initialize this since our icons start w/ the 1st flavor iconFile _ FS.StreamOpen[fileName: filename ! FS.Error => { MessageWindow.Append[filename, TRUE]; MessageWindow.Append[": ", FALSE]; MessageWindow.Append[error.explanation, FALSE]; MessageWindow.Blink[]; badNews _ TRUE; CONTINUE }]; IF badNews THEN RETURN; FOR i: INTEGER IN [0..IconEditorDefs.maxStorage) DO handle.icons[i] _ NIL; ENDLOOP; nRead _ iconFile.GetLength[] / (Basics.bytesPerWord*SIZE[IconEditorDefs.IconFileFormat]); FOR n: IconEditorDefs.Nat IN [0..nRead) DO newFlavor _ GetNewFlavor[handle]; IF handle.icons[LOOPHOLE[newFlavor]] = NIL THEN handle.icons[LOOPHOLE[newFlavor]] _ NEW[IconEditorDefs.IconFileFormat]; [] _ iconFile.UnsafeGetBlock[block: [base: LOOPHOLE[handle.icons[LOOPHOLE[newFlavor]]], startIndex: 0, count: SIZE[IconEditorDefs.IconFileFormat]*Basics.bytesPerWord] ! RuntimeError.BoundsFault => GOTO Punt]; ENDLOOP; iconFile.Close[]; -- now close things up EXITS Punt => SIGNAL CouldntLoadIcons; }; SaveIcons: PUBLIC PROC [handle: IconEditorDefs.IconHandle, filename: Rope.ROPE, numberOfIcons: IconEditorDefs.Nat] RETURNS [iconFile: IO.STREAM _ NIL] = { badNews: BOOL _ FALSE; iconFile _ FS.StreamOpen[fileName: filename, accessOptions: create, keep: 2 ! FS.Error => { MessageWindow.Append[filename, TRUE]; MessageWindow.Append[": ", FALSE]; MessageWindow.Append[error.explanation, FALSE]; MessageWindow.Blink[]; badNews _ TRUE; CONTINUE }]; IF badNews THEN RETURN; FOR j: IconEditorDefs.Nat IN [0..numberOfIcons) DO iconName: Rope.ROPE; iconFile.UnsafePutBlock[block: [LOOPHOLE[handle.icons[LOOPHOLE[j]]], 0, SIZE[IconEditorDefs.IconFileFormat]*Basics.bytesPerWord] ! RuntimeError.BoundsFault => GOTO Punt]; TRUSTED {IF PrincOpsUtils.IsBound[LOOPHOLE[IconRegistry.IsRegistered]] AND (iconName _ IconRegistry.IsRegistered[fileName: filename, index: j].name) # NIL THEN IconRegistry.InvalidateCache[iconName]}; -- w.t. ENDLOOP; iconFile.Flush[]; -- make sure we got everything iconFile.Close[]; -- now close things up EXITS Punt => SIGNAL CouldntSaveIcons; }; NormalizeRectangle: PUBLIC PROC [corner1, corner2: IconEditorDefs.MarkPoint] RETURNS [rect: IconEditorDefs.RectangleRec] = { rect.x _ MIN[corner1.x, corner2.x]; rect.y _ MIN[corner1.y, corner2.y]; rect.w _ ABS[corner2.x-corner1.x] + 1; rect.h _ ABS[corner2.y-corner1.y] + 1; }; TransferEndPoints: PUBLIC PROC [endpoint1, endpoint2: IconEditorDefs.MarkPoint] RETURNS [line: IconEditorDefs.LineRec] = { line.x1 _ endpoint1.x; line.y1 _ endpoint1.y; line.x2 _ endpoint2.x; line.y2 _ endpoint2.y; }; ComputeEndPoints: PUBLIC PROC [handle: IconEditorDefs.IconHandle, oldLine: IconEditorDefs.LineRec] RETURNS [newLine: IconEditorDefs.LineRec] = { center: IconEditorDefs.Nat; center _ Real.FixI[handle.unit/2]; -- used to center endpoints of line in grid square newLine.x1 _ oldLine.x1*handle.unit; newLine.y1 _ (IconEditorDefs.intHBound- oldLine.y1)*handle.unit; newLine.x2 _ oldLine.x2*handle.unit; newLine.y2 _ (IconEditorDefs.intHBound- oldLine.y2)*handle.unit; IF newLine.x1 > newLine.x2 THEN { newLine.x1 _ newLine.x1 + handle.unit - center; newLine.x2 _ newLine.x2 + center }; IF newLine.x2 > newLine.x1 THEN { newLine.x2 _ newLine.x2 + handle.unit - center; newLine.x1 _ newLine.x1 + center }; IF newLine.x1 = newLine.x2 THEN { newLine.x1 _ newLine.x2 _ newLine.x2 + center }; IF newLine.y1 > newLine.y2 THEN { newLine.y1 _ newLine.y1 + handle.unit - center; newLine.y2 _ newLine.y2 + center }; IF newLine.y2 > newLine.y1 THEN { newLine.y2 _ newLine.y2 + handle.unit - center; newLine.y1 _ newLine.y1 + center }; IF newLine.y1 = newLine.y2 THEN { newLine.y1 _ newLine.y2 _ newLine.y2 + center }; }; ClearIcon: PUBLIC PROC [handle: IconEditorDefs.IconHandle, flavor: IconEditorDefs.IconFlavor] = { i,j: IconEditorDefs.Nat; iconToClear: IconEditorDefs.IconRef _ handle.icons[LOOPHOLE[flavor]]; FOR i IN IconEditorDefs.IntW DO FOR j IN IconEditorDefs.IntH DO iconToClear.bits[j].b[i] _ FALSE; ENDLOOP; ENDLOOP; }; MirrorIcon: PUBLIC PROC [handle: IconEditorDefs.IconHandle, flavor: IconEditorDefs.IconFlavor, rect: IconEditorDefs.RectangleRec] = { i,j: IconEditorDefs.Nat; temp: BOOLEAN; farRight: IconEditorDefs.Nat _ rect.x+rect.w-1; FOR j IN [rect.y..rect.y+rect.h-1] DO FOR i IN [0..rect.w/2) DO temp _ handle.icons[LOOPHOLE[flavor]].bits[j].b[rect.x + i]; handle.icons[LOOPHOLE[flavor]].bits[j].b[rect.x + i] _ handle.icons[LOOPHOLE[flavor]].bits[j].b[farRight - i]; handle.icons[LOOPHOLE[flavor]].bits[j].b[farRight - i] _ temp; ENDLOOP; ENDLOOP; }; DrawLine: PUBLIC PROC [handle: IconEditorDefs.IconHandle, line: IconEditorDefs.LineRec, flavor: IconEditorDefs.IconFlavor]= { factor: INTEGER; deltaX, deltaY, i, e, x, y: IconEditorDefs.Nat; deltaX _ ABS[line.x2 - line.x1]; deltaY _ ABS[line.y2 - line.y1]; IF ((line.x1= deltaY THEN { e _ 2*deltaY - deltaX; FOR i IN [0..deltaX] DO handle.icons[LOOPHOLE[flavor]].bits[y].b[x] _ TRUE; IF e > 0 THEN { IF (y >= 0) AND (y < IconEditorDefs.intHBound) THEN y _ y + factor; -- Just to be safe e _ e + (2*deltaY - 2*deltaX) } ELSE e _ e + 2*deltaY; IF x < IconEditorDefs.intWBound THEN x _ x + 1; -- Just to be safe ENDLOOP; } ELSE { e _ 2*deltaX - deltaY; FOR i IN [0..deltaY] DO handle.icons[LOOPHOLE[flavor]].bits[y].b[x] _ TRUE; IF e > 0 THEN { IF x < IconEditorDefs.intWBound THEN x _ x + 1; -- Just to be safe e _ e + (2*deltaX - 2*deltaY) } ELSE e _ e + 2*deltaX; IF (y >= 0) AND (y < IconEditorDefs.intHBound) THEN y _ y + factor; -- Just to be safe ENDLOOP; }; FreshMarks[handle]; }; FreshMarks: PUBLIC PROC [handle: IconEditorDefs.IconHandle] = { handle.mark1.x _ handle.mark1.y _ handle.mark2.x _ handle.mark2.y _ 0; handle.functionNotApplied _ FALSE; }; WhiteLabel: PUBLIC PROC [handle: IconEditorDefs.IconHandle, flavor: IconEditorDefs.IconFlavor] = { handle.icons[LOOPHOLE[flavor]].invertLabel _ TRUE; }; BlackLabel: PUBLIC PROC [handle: IconEditorDefs.IconHandle, flavor: IconEditorDefs.IconFlavor] = { handle.icons[LOOPHOLE[flavor]].invertLabel _ FALSE; }; SetLabel: PUBLIC PROC [handle: IconEditorDefs.IconHandle, flavor: IconEditorDefs.IconFlavor, rect: IconEditorDefs.RectangleRec]= { i: IconEditorDefs.IconRef _ handle.icons[LOOPHOLE[flavor]]; i.label _ TRUE; handle.labelRect.x _ i.lx _ rect.x; i.ly _ IconEditorDefs.iconH - 1 - (rect.y + rect.h); handle.labelRect.y _ rect.y; handle.labelRect.w _ i.lw _ rect.w; handle.labelRect.h _ i.lh _ rect.h; FreshMarks[handle]; }; UnSetLabel: PUBLIC PROC [handle: IconEditorDefs.IconHandle, flavor: IconEditorDefs.IconFlavor]= { i: IconEditorDefs.IconRef _ handle.icons[LOOPHOLE[flavor]]; i.label _ FALSE; i.lx _ 0; i.ly _ 0; i.lw _ 0; i.lh _ 0; }; SetBlack: PUBLIC PROC [handle: IconEditorDefs.IconHandle, flavor: IconEditorDefs.IconFlavor, rect: IconEditorDefs.RectangleRec] = { i, j: IconEditorDefs.Nat; FOR i IN [rect.x..rect.x+rect.w-1] DO FOR j IN [rect.y..rect.y+rect.h-1] DO handle.icons[LOOPHOLE[flavor]].bits[j].b[i] _ TRUE; ENDLOOP; ENDLOOP; FreshMarks[handle]; }; SetWhite: PUBLIC PROC [handle: IconEditorDefs.IconHandle, flavor: IconEditorDefs.IconFlavor, rect: IconEditorDefs.RectangleRec] = { i, j: IconEditorDefs.Nat; iconToClear: IconEditorDefs.IconRef _ handle.icons[LOOPHOLE[flavor]]; FOR i IN [rect.x..rect.x+rect.w-1] DO FOR j IN [rect.y..rect.y+rect.h-1] DO iconToClear.bits[j].b[i] _ FALSE; ENDLOOP; ENDLOOP; FreshMarks[handle]; }; SetDeskTopGray: PUBLIC PROC [handle: IconEditorDefs.IconHandle, flavor: IconEditorDefs.IconFlavor, rect: IconEditorDefs.RectangleRec] = { i, j, k: IconEditorDefs.Nat; indent: IconEditorDefs.Nat _ 0; SetWhite[handle: handle, flavor: flavor, rect: rect]; --must clear before setting grey bits FOR j _ 0, j+2 WHILE j < LOOPHOLE[IconEditorDefs.intHBound] DO FOR k IN [0..1] DO FOR i _ indent, i+4 WHILE i <= LOOPHOLE[IconEditorDefs.intWBound] DO IF j IN [rect.y .. rect.y+rect.h) AND i IN [rect.x ..rect.x+rect.w) THEN handle.icons[LOOPHOLE[flavor]].bits[j+k].b[i] _ TRUE; ENDLOOP; ENDLOOP; indent _ IF indent=0 THEN 2 ELSE 0; ENDLOOP; FreshMarks[handle]; }; SetDarkGray: PUBLIC PROC [handle: IconEditorDefs.IconHandle, flavor: IconEditorDefs.IconFlavor, rect: IconEditorDefs.RectangleRec] = { i, j: IconEditorDefs.Nat; indent: IconEditorDefs.Nat _ 0; SetWhite[handle: handle, flavor: flavor, rect: rect]; --must clear before setting grey bits FOR j IN [rect.y..rect.y+rect.h-1) DO FOR i _ (rect.x+indent), i+2 WHILE i < (rect.x+rect.w-1) DO handle.icons[LOOPHOLE[flavor]].bits[j].b[i] _ TRUE; ENDLOOP; indent _ IF indent=0 THEN 1 ELSE 0; ENDLOOP; FreshMarks[handle]; }; Invert: PUBLIC PROC [handle: IconEditorDefs.IconHandle, flavor: IconEditorDefs.IconFlavor, rect: IconEditorDefs.RectangleRec] = { i,j: IconEditorDefs.Nat; FOR i IN [rect.x..rect.x+rect.w-1] DO FOR j IN [rect.y..rect.y+rect.h-1] DO handle.icons[LOOPHOLE[flavor]].bits[j].b[i] _ IF handle.icons[LOOPHOLE[flavor]].bits[j].b[i] THEN FALSE ELSE TRUE; ENDLOOP; ENDLOOP; FreshMarks[handle]; }; ICRectangle: TYPE = RECORD [xmin, ymin, xmax, ymax: IconEditorDefs.Nat]; GetRectangle: PROC[handle: IconEditorDefs.IconHandle] RETURNS[ICRectangle] = { x1, y1, x2, y2: IconEditorDefs.Nat; x1 _ handle.mark1.x; y1 _ handle.mark1.y; x2 _ handle.mark2.x; y2 _ handle.mark2.y; IF x1=0 AND y1=0 AND x2=0 AND y2=0 THEN { x2 _ IconEditorDefs.intWBound; y2 _ IconEditorDefs.intHBound }; RETURN[[xmin: MIN[x1, x2], ymin: MIN[y1, y2], xmax: MAX[x1, x2], ymax: MAX[y1, y2]]]; }; MoveRight: PUBLIC PROC [handle: IconEditorDefs.IconHandle, flavor: IconEditorDefs.IconFlavor, slowShift: BOOLEAN] = { numberToMove: IconEditorDefs.Nat _ IF slowShift THEN 1 ELSE 4; r: ICRectangle = GetRectangle[handle]; FOR k: IconEditorDefs.Nat IN [1..numberToMove] DO oldBits: IconEditorDefs.BitArray _ handle.icons[LOOPHOLE[flavor]].bits; FOR i: IconEditorDefs.Nat IN [r.xmin..r.xmax] DO FOR j: IconEditorDefs.Nat IN [r.ymin..r.ymax] DO handle.icons[LOOPHOLE[flavor]].bits[j].b[i] _ oldBits[j].b[IF i=r.xmin THEN r.xmax ELSE i-1]; ENDLOOP; ENDLOOP; ENDLOOP; }; MoveLeft: PUBLIC PROC [handle: IconEditorDefs.IconHandle, flavor: IconEditorDefs.IconFlavor, slowShift: BOOLEAN] = { numberToMove: IconEditorDefs.Nat _ IF slowShift THEN 1 ELSE 4; r: ICRectangle = GetRectangle[handle]; FOR k: IconEditorDefs.Nat IN [1..numberToMove] DO oldBits: IconEditorDefs.BitArray _ handle.icons[LOOPHOLE[flavor]].bits; FOR i: IconEditorDefs.Nat IN [r.xmin..r.xmax] DO FOR j: IconEditorDefs.Nat IN [r.ymin..r.ymax] DO handle.icons[LOOPHOLE[flavor]].bits[j].b[i] _ oldBits[j].b[IF i=r.xmax THEN r.xmin ELSE i+1]; ENDLOOP; ENDLOOP; ENDLOOP; }; MoveUp: PUBLIC PROC [handle: IconEditorDefs.IconHandle, flavor: IconEditorDefs.IconFlavor, slowShift: BOOLEAN] = { numberToMove: IconEditorDefs.Nat _ IF slowShift THEN 1 ELSE 4; r: ICRectangle = GetRectangle[handle]; FOR k: IconEditorDefs.Nat IN [1..numberToMove] DO oldBits: IconEditorDefs.BitArray _ handle.icons[LOOPHOLE[flavor]].bits; FOR i: IconEditorDefs.Nat IN [r.xmin..r.xmax] DO FOR j: IconEditorDefs.Nat IN [r.ymin..r.ymax] DO handle.icons[LOOPHOLE[flavor]].bits[j].b[i] _ oldBits[IF j=r.ymax THEN r.ymin ELSE j+1].b[i]; ENDLOOP; ENDLOOP; ENDLOOP; }; MoveDown: PUBLIC PROC [handle: IconEditorDefs.IconHandle, flavor: IconEditorDefs.IconFlavor, slowShift: BOOLEAN] = { numberToMove: IconEditorDefs.Nat _ IF slowShift THEN 1 ELSE 4; r: ICRectangle = GetRectangle[handle]; FOR k: IconEditorDefs.Nat IN [1..numberToMove] DO oldBits: IconEditorDefs.BitArray _ handle.icons[LOOPHOLE[flavor]].bits; FOR i: IconEditorDefs.Nat IN [r.xmin..r.xmax] DO FOR j: IconEditorDefs.Nat IN [r.ymin..r.ymax] DO handle.icons[LOOPHOLE[flavor]].bits[j].b[i] _ oldBits[IF j=r.ymin THEN r.ymax ELSE j-1].b[i]; ENDLOOP; ENDLOOP; ENDLOOP; }; }. ΞIconEditorIO.mesa Last Edited by: Ken Pier, May 17, 1985 4:11:24 pm PDT each gray line is two lines high paint gray next time do a differnt indentation paint gray next time do a differnt indentation Κ~˜Jšœ™Jšœ5™5šΟk ˜ Jšœœ˜Jšœœ˜Jšœœ˜J˜Jšœ œ!˜3Jšœœ"œ"˜RJšœœ˜$Jšœœ˜Jšœœœ˜Jšœ œ˜!Jšœœ ˜J˜—J˜šΟn œœ˜Jšœœœ@˜NJšœ˜J˜Jšœœœœ˜'Jšœœœœ˜'Jšœœœœ˜#J˜š ž œœœDœœ˜rJšœœ˜4šœœœ˜4šœ˜Jšœcœ˜iJšœgœ˜mJšœœ˜—J˜Jšœœ˜J˜—Jšœœœ˜J˜—J˜šž œœœ(˜?Jšœ"œ˜CJ˜—J˜šž œœœ<˜TJšœ%œ9˜aJ˜[J˜[šœ>œ˜FJšœVœ˜\Jšœ ˜J˜—˜ZJ˜H—˜XJ˜F—šœFœFœ˜—JšœTœ˜ZJšœ ˜J˜—šœ&œΟc-˜\Jšœœ ˜6˜FJ˜—J˜J˜,J˜—šœŸ˜!Jšœœ ˜6˜FJ˜—J˜-J˜J˜—J˜KJ˜@J˜—J˜šž œœœ%œ+˜pJ˜Jšœœ ˜$šœœEœ˜V˜_Jšœ œ˜—J˜Jš˜J˜—J˜—J˜Jšž œœœ3œ˜Nšœ'œ œœ˜JJšœœ œ˜Jšœ œœ˜J˜%JšœœŸ:˜pšœ œ!œ ˜;Icodešœœ˜%Kšœœ˜"Kšœ(œ˜/Kšœ!œ˜/Kšœ˜—Jšœ œœ˜Kš œœœ œœœ˜SJšœ4œ!˜Yšœœ ˜*J˜!Jšœœœœ˜0Jšœ œœ ˜GJš œ+œœ%œSœ˜ΠJšœ˜—JšœŸ˜)Jšœ œ˜&J˜—J˜šž œœœ4œ%œ œ œ˜šJšœ œœ˜šœ œAœ ˜[Kšœœ˜%Kšœœ˜"Kšœ(œ˜/Kšœ!œ˜/Kšœ˜—Jšœ œœ˜šœœœ˜3Jšœœ˜šœ œœ ˜GJšœSœ˜b—Jš œœœœMœœ+Ÿ˜ΡJšœ˜—JšœŸ˜0JšœŸ˜(Jšœ œ˜&J˜—J˜šžœœœ.œ(˜|Jšœ œ˜#Jšœ œ˜#Jšœ œ˜&Jšœ œ˜&J˜—J˜šžœœœ2œ#˜zJ˜-J˜-J˜—J˜šžœœœFœ&˜J˜Jšœ$Ÿ2˜VJ˜fJ˜fšœœ˜"J˜0J˜ J˜—šœœ˜"J˜0J˜ J˜—šœœ˜"J˜-J˜—šœœ˜"J˜0J˜ J˜—šœœ˜"J˜0J˜ J˜—šœœ˜!J˜-J˜—J˜—J˜šž œœœK˜aJ˜Jšœ3œ ˜Ešœœ˜šœœ˜Jšœœ˜!Jšœ˜—Jšœ˜—J˜—J˜šž œœœn˜…J˜Jšœœ˜J˜/šœœ˜%šœœ˜Jšœœ ˜<šœ œ!˜6Jšœ œ"˜7—Jšœ œ)˜>Jšœ˜—Jšœ˜—J˜—J˜šžœœœh˜}Jšœœ˜J˜/Jšœ œ˜ Jšœ œ˜ š œœœœœ˜`J˜ Jšœœ˜J˜—šœ˜J˜ Jšœœ˜J˜—Jšœœ˜šœœ˜J˜šœœ ˜Jšœ œœ˜3šœœ˜Jšœ œ œŸ˜VJ˜J˜—Jšœ˜JšœœŸ˜DJšœ˜—J˜—šœ˜J˜šœœ ˜Jšœ œœ˜3šœœ˜Jšœœ Ÿ˜BJ˜J˜—Jšœ˜Jšœ œ œŸ˜WJšœ˜—J˜—J˜J˜—J˜šž œœœ(˜?J˜FJšœœ˜"J˜—J˜šž œœœK˜bJšœ œœ˜2J˜—J˜šž œœœK˜bJšœ œœ˜3J˜—J˜šžœœœm˜‚Jšœ)œ ˜;Jšœ œ˜J˜#J˜4J˜J˜#J˜#J˜J˜—J˜šž œœœJ˜aJšœ)œ ˜;Jšœ œ˜J˜J˜J˜—J˜šžœœœn˜ƒJ˜šœœ˜%šœœ˜%Jšœ œœ˜3Jšœ˜—Jšœ˜—J˜J˜—J˜šžœœœn˜ƒJ˜Jšœ3œ ˜Ešœœ˜%šœœ˜%Jšœœ˜!Jšœ˜—Jšœ˜—J˜J˜—J˜šžœœœn˜‰J˜J˜Jšœ6Ÿ%˜[šœ œœ˜>Jšœ ™ šœœ˜Jšœ ™ Jšœœœ˜DJš œœœœœ˜IJšœ œœ˜5Jšœ˜ —Jšœ˜Jšœ#™#Jšœ œ œœ˜#Jšœ˜—J˜J˜—J˜šž œœœn˜†J˜J˜Jšœ6Ÿ%˜[šœœ˜%Jšœ ™ šœœ˜;Jšœ œœ˜3Jšœ˜ —Jšœ#™#Jšœ œ œœ˜#Jšœ˜—J˜J˜—J˜šžœœœn˜J˜šœœ˜%šœœ˜%šœ œ˜-Jš œœœœœœ˜D—Jšœ˜—Jšœ˜—J˜J˜—J˜Jšœ œœ.˜HJ˜šž œœ$œ˜NJ˜#J˜)J˜)Jš œœœœœB˜iJš œœœœœ ˜UJ˜—J˜šž œœœSœ˜uJšœ#œ œœ˜>J˜&šœœ˜1Jšœ0œ˜Gšœœ˜0šœœ˜0šœ œ˜-Jšœ œ œœ˜/—Jšœ˜—Jšœ˜—Jšœ˜—J˜—J˜šžœœœSœ˜tJšœ#œ œœ˜>J˜&šœœ˜1Jšœ0œ˜Gšœœ˜0šœœ˜0šœ œ˜-Jšœ œ œœ˜/—Jšœ˜—Jšœ˜—Jšœ˜—J˜—J˜šžœœœSœ˜rJšœ#œ œœ˜>J˜&šœœ˜1Jšœ0œ˜Gšœœ˜0šœœ˜0šœ œ˜-Jšœœ œœ ˜/—Jšœ˜—Jšœ˜—Jšœ˜—J˜—J˜šžœœœSœ˜tJšœ#œ œœ˜>J˜&šœœ˜1Jšœ0œ˜Gšœœ˜0šœœ˜0šœ œ˜-Jšœœ œœ ˜/—Jšœ˜—Jšœ˜—Jšœ˜—J˜—J˜J˜——…—=nMΊ