DIRECTORY Environment USING [bytesPerWord], FileIO USING [Open], Graphics USING [Box], IconEditorDefs, IconRegistry USING [IsRegistered, InvalidateCache], IO, MessageWindow USING [Append, Blink], Real USING [FixC, FixI], Rope USING [ROPE], Runtime USING [IsBound]; IconEditorIO: CEDAR PROGRAM IMPORTS FileIO, IO, IconRegistry, MessageWindow, Real, Runtime EXPORTS IconEditorDefs = BEGIN OPEN IconEditorDefs; CouldntLoadIcons: PUBLIC SIGNAL = CODE; CouldntSaveIcons: PUBLIC SIGNAL = CODE; ViewerNoGood: PUBLIC SIGNAL = CODE; PointsMarked: PUBLIC PROC [handle: IconHandle,representation: MarkType] RETURNS [BOOLEAN] = { OPEN MessageWindow; -- for Append and Blink IF (handle.mark1.x = 0) AND (handle.mark1.y = 0) AND (handle.mark2.x = 0) AND (handle.mark2.y = 0) THEN { SELECT representation FROM rect=>Append["Hold down yellow mouse button and mark a rectangular area first...",TRUE]; line=>Append["Hold down yellow mouse button and control key and mark a line first...", TRUE]; ENDCASE => ERROR; Blink[]; RETURN[FALSE] } ELSE RETURN[TRUE]; }; SaveBitMap: PUBLIC PROCEDURE [handle: IconHandle] = { handle.savedBitMap _ handle.icons[LOOPHOLE[handle.currentIC]].bits; }; LayoutBoard: PUBLIC PROC [handle: IconHandle, bounds: Graphics.Box] = { iconsOnDisplay: CARDINAL _ MIN[handle.numberOfIcons, maxIconsOnDisplay]; handle.numIconsPerRow _ Real.FixC[bounds.xmax/(iconW+distX)]; handle.numIconsPerCol _ Real.FixC[bounds.ymax/(iconH+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.FixC[bounds.xmax - ((iconsOnDisplay + handle.numIconsPerCol - 1) / handle.numIconsPerCol) * (iconW + distX)]; handle.possibleY _ Real.FixC[bounds.ymax - ((iconsOnDisplay + handle.numIconsPerRow-1) / handle.numIconsPerRow) * (iconH+distY)]; IF handle.possibleX < minimumUnit * iconW AND handle.possibleY < minimumUnit * 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[Real.FixC[bounds.xmax], handle.possibleY]; handle.numIconsPerCol _ (iconsOnDisplay + handle.numIconsPerRow - 1) / handle.numIconsPerRow; handle.icX _ 0; handle.icY _ Real.FixC[handle.boardSize] + 1} ELSE { -- use a horizontal layout handle.boardSize _ MIN[Real.FixC[bounds.ymax], handle.possibleX]; handle.numIconsPerRow _ (iconsOnDisplay + handle.numIconsPerCol - 1) / handle.numIconsPerCol; handle.icX _ Real.FixC[handle.boardSize] + 1; handle.icY _ 0}; handle.unit _ Real.FixI[handle.boardSize / (intHBound + 1)]; handle.boardSize _ handle.unit * (intHBound + 1); }; GetNewFlavor: PUBLIC PROC [handle: IconHandle] RETURNS [newFlavor: iconFlavor] = BEGIN newFlavor _ handle.nextFlavor; handle.nextFlavor _ SUCC[newFlavor]; IF LOOPHOLE[handle.nextFlavor, CARDINAL] >= maxStorage THEN { MessageWindow.Append[message: "Sorry but you have exceeded the current limit on icons.", clearFirst: TRUE]; MessageWindow.Blink[]; ERROR}; END; LoadIcons: PUBLIC PROCEDURE[handle: IconHandle, filename: Rope.ROPE] RETURNS [nRead: INTEGER, iconFile: IO.Handle] = TRUSTED { ENABLE IO.Error => GOTO Punt; newFlavor: iconFlavor; handle.nextFlavor _ FIRST[iconFlavor]; -- Initialize this since our icons start w/ the 1st flavor iconFile _ FileIO.Open[fileName: filename]; nRead _ iconFile.GetLength[] / (Environment.bytesPerWord*SIZE[iconFileFormat]); FOR n: INTEGER IN [0..nRead) DO newFlavor _ GetNewFlavor[handle]; IF handle.icons[LOOPHOLE[newFlavor]] = NIL THEN handle.icons[LOOPHOLE[newFlavor]] _ NEW[iconFileFormat]; [] _ IO.UnsafeGetBlock[iconFile, [LOOPHOLE[handle.icons[LOOPHOLE[newFlavor]]], 0, SIZE[iconFileFormat]*2]]; ENDLOOP; IO.Close[iconFile]; -- now close things up EXITS Punt => SIGNAL CouldntLoadIcons; }; SaveIcons: PUBLIC PROC [handle: IconHandle, filename: Rope.ROPE, numberOfIcons: CARDINAL] RETURNS [iconFile: IO.Handle] = { iconFile _ FileIO.Open[fileName: filename, accessOptions: overwrite]; FOR j: CARDINAL IN [0..numberOfIcons) DO iconName: Rope.ROPE; IO.UnsafePutBlock[iconFile, [LOOPHOLE[handle.icons[LOOPHOLE[j]]], 0, SIZE[iconFileFormat]*2]]; TRUSTED {IF Runtime.IsBound[IconRegistry.IsRegistered] AND (iconName _ IconRegistry.IsRegistered[fileName: filename, index: j].name) # NIL THEN IconRegistry.InvalidateCache[iconName]}; -- w.t. ENDLOOP; IO.Flush[iconFile]; -- make sure we got everything IO.Close[iconFile]; -- now close things up }; NormalizeRectangle: PUBLIC PROC [corner1, corner2: markPoint] RETURNS [rect: 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: markPoint] RETURNS [line: lineRec] = { line.x1 _ endpoint1.x; line.y1 _ endpoint1.y; line.x2 _ endpoint2.x; line.y2 _ endpoint2.y; }; ComputeEndPoints: PUBLIC PROC [handle: IconHandle, oldLine: lineRec] RETURNS [newLine: lineRec] = { center: INTEGER; center _ Real.FixI[handle.unit/2]; -- used to center endpoints of line in grid square newLine.x1 _ oldLine.x1*handle.unit; newLine.y1 _ (intHBound- oldLine.y1)*handle.unit; newLine.x2 _ oldLine.x2*handle.unit; newLine.y2 _ (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: IconHandle, flavor: iconFlavor] = { i,j: CARDINAL; iconToClear: iconRef _ handle.icons[LOOPHOLE[flavor]]; FOR i IN intW DO FOR j IN intH DO iconToClear.bits[j].b[i] _ FALSE; ENDLOOP; ENDLOOP; }; MirrorIcon: PUBLIC PROC [handle: IconHandle, flavor: iconFlavor, rect: rectangleRec] = { i,j: INTEGER; temp: BOOLEAN; farRight: CARDINAL _ 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: IconHandle, line: lineRec, flavor: iconFlavor]= { deltaX, deltaY, i, e, x, y, factor: INTEGER; 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 < intHBound) THEN y _ y + factor; -- Just to be safe e _ e + (2*deltaY - 2*deltaX) } ELSE e _ e + 2*deltaY; IF x < 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 < 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 < intHBound) THEN y _ y + factor; -- Just to be safe ENDLOOP; }; FreshMarks[handle]; }; FreshMarks: PUBLIC PROC [handle: IconHandle] = { handle.mark1.x _ handle.mark1.y _ handle.mark2.x _ handle.mark2.y _ 0; handle.functionNotApplied _ FALSE; }; WhiteLabel: PUBLIC PROC [handle: IconHandle, flavor: iconFlavor] = { handle.icons[LOOPHOLE[flavor]].invertLabel _ TRUE; }; BlackLabel: PUBLIC PROC [handle: IconHandle, flavor: iconFlavor] = { handle.icons[LOOPHOLE[flavor]].invertLabel _ FALSE; }; SetLabel: PUBLIC PROC [handle: IconHandle, flavor: iconFlavor, rect: rectangleRec]= { OPEN i: handle.icons[LOOPHOLE[flavor]]; i.label _ TRUE; handle.labelRect.x _ i.lx _ rect.x; i.ly _ 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: IconHandle, flavor: iconFlavor]= { OPEN i: handle.icons[LOOPHOLE[flavor]]; i.label _ FALSE; i.lx _ 0; i.ly _ 0; i.lw _ 0; i.lh _ 0; }; SetWhite: PUBLIC PROC [handle: IconHandle, flavor: iconFlavor, rect: rectangleRec] = { i, j: INTEGER; iconToClear: 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: IconHandle, flavor: iconFlavor, rect: rectangleRec] = { i, j, k: INTEGER; indent: INTEGER _ 0; FOR j _ 0, j+2 WHILE j < LOOPHOLE[IconEditorDefs.intHBound] DO -- each gray line is two lines high FOR k IN [0..1] DO -- paint gray 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; -- next time do a differnt indentation indent _ IF indent=0 THEN 2 ELSE 0; ENDLOOP; FreshMarks[handle]; }; SetDarkGray: PUBLIC PROC [handle: IconHandle, flavor: iconFlavor, rect: rectangleRec] = { i, j: INTEGER; indent: INTEGER _ 0; FOR j IN [rect.y..rect.y+rect.h-1) DO -- paint gray 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; -- next time do a differnt indentation indent _ IF indent=0 THEN 1 ELSE 0; ENDLOOP; FreshMarks[handle]; }; SetBlack: PUBLIC PROC [handle: IconHandle, flavor: iconFlavor, rect: rectangleRec] = { i, j: INTEGER; 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]; }; Invert: PUBLIC PROC [handle: IconHandle, flavor: iconFlavor, rect: rectangleRec] = { i,j: INTEGER; 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]; }; Rectangle: TYPE = RECORD[xmin, ymin, xmax, ymax: NAT]; GetRectangle: PROC[handle: IconHandle] RETURNS[Rectangle] = { x1, y1, x2, y2: 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 _ intWBound; y2 _ intHBound }; RETURN[[xmin: MIN[x1, x2], ymin: MIN[y1, y2], xmax: MAX[x1, x2], ymax: MAX[y1, y2]]]; }; MoveRight: PUBLIC PROC [handle: IconHandle, flavor: iconFlavor, slowShift: BOOLEAN] = { numberToMove: CARDINAL _ IF slowShift THEN 1 ELSE 4; r: Rectangle = GetRectangle[handle]; FOR k: CARDINAL IN [1..numberToMove] DO oldBits: bitArray _ handle.icons[LOOPHOLE[flavor]].bits; FOR i: NAT IN [r.xmin..r.xmax] DO FOR j: 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: IconHandle, flavor: iconFlavor, slowShift: BOOLEAN] = { numberToMove: CARDINAL _ IF slowShift THEN 1 ELSE 4; r: Rectangle = GetRectangle[handle]; FOR k: CARDINAL IN [1..numberToMove] DO oldBits: bitArray _ handle.icons[LOOPHOLE[flavor]].bits; FOR i: NAT IN [r.xmin..r.xmax] DO FOR j: 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: IconHandle, flavor: iconFlavor, slowShift: BOOLEAN] = { numberToMove: CARDINAL _ IF slowShift THEN 1 ELSE 4; r: Rectangle = GetRectangle[handle]; FOR k: CARDINAL IN [1..numberToMove] DO oldBits: bitArray _ handle.icons[LOOPHOLE[flavor]].bits; FOR i: NAT IN [r.xmin..r.xmax] DO FOR j: 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: IconHandle, flavor: iconFlavor, slowShift: BOOLEAN] = { numberToMove: CARDINAL _ IF slowShift THEN 1 ELSE 4; r: Rectangle = GetRectangle[handle]; FOR k: CARDINAL IN [1..numberToMove] DO oldBits: bitArray _ handle.icons[LOOPHOLE[flavor]].bits; FOR i: NAT IN [r.xmin..r.xmax] DO FOR j: 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; }; END. žIconEditorIO.mesa Last edit by Michael Plass, January 31, 1983 2:51 pm Last Edited by: Teitelman, April 12, 1983 5:01 pm Last Edited by: Doug Wyatt, April 22, 1983 4:37 pm takes two diagonal points and computes the bottom left corner of the rectangle and its width and height Now add one unit to the rightmost x and to the upper y so that an accurate representation of the line is drawn. Reflects icon accross imaginary x-axis. Achieves the effect of holding the icon in a mirror sets the proper parameters in the file representation undoes the proper parameters in the file representation set gray pattern in specified icon set dark gray pattern in specified icon fills in a rectangle with black Edited on April 11, 1983 3:20 pm, by Teitelman fixed SaveIcons to invalidate cache of IconRegistry for any icons in the file that is being saved. changes to: SaveIcons, DIRECTORY, IMPORTS Edited on April 12, 1983 4:59 pm, by Teitelman changes to: SaveIcons, DIRECTORY, IMPORTS Edited on April 22, 1983 4:35 pm, by Doug Wyatt Added GetRectangle; the shifting operations now use GetRectangle, so they are insensitive to which corners were used to select the rectangle. Κ Π– "Mesa" style˜šΟc™J™Jš4™4J™1J™2—J˜JšΟk œžœžœžœ'žœ#žœžœžœžœžœ žœ ˜’J˜Jšœžœž˜Jšžœ7˜>Jšžœ˜Jšžœžœ˜J˜Jšœžœžœžœ˜'Jšœžœžœžœ˜'Jšœžœžœžœ˜#J˜šΟn œž œ/žœžœ˜]Jš#žœžœžœžœžœžœžœžœUžœ[ž œžœžœ žœžœžœžœžœ˜Ή—J˜šŸ œžœ˜5Jšœ"žœ˜F—J˜šŸ œž œ/˜GJš%œžœžœ§žœ>žœYžœžœšžœ(žœ(žœXžœžœžœ&žœ.œžœΝžœœžœΏ˜“ —J˜š Ÿ œžœžœžœž˜VJšœ3žœ žœžœžœžœkžœžœžœ˜——JšBŸ œžœž œ$žœžœ žœ žœ žœžœžœ žœ4žœ:œhžœžœžœžœ žœ'žœžœžœžœžœžœžœžœžœžœžœžœœžœ žœ˜ J˜š Ÿ œžœžœ$žœžœžœ˜{Jš(œGžœžœžœžœΟzΠkz œžœžœžœ žœž œ,žœMžœžœ+œžœžœžœœ˜˜—J˜šŸœžœžœžœ˜^Jšh™hJš œ žœ!žœ!žœ$žœ˜™—J˜šŸœžœžœ#žœ˜\Jšœ_˜_—J˜šŸœžœžœ(žœ˜cJšœ žœ&3œ―˜˜Jšp™pJšžœžœZžœžœZžœžœ5žœžœZžœžœZžœžœ6˜Ž—J˜šŸ œžœžœ-˜CJšœžœ&žœ žœžœžœžœžœžœžœžœžœ˜₯—J˜šŸ œžœžœA˜XJš]™]Jšœžœžœ žœžœžœžœžœžœžœžœ0žœ2žœ2žœ+žœžœ˜Ž—J˜šŸœžœžœ;˜PJšœ$žœ žœžœ˜nš žœžœžœžœžœ˜`Jšœžœ˜)—šžœ˜Jšœžœ˜)—Jšœžœ˜šžœžœ˜Jš œžœžœ žœžœžœžœžœžœ žœžœœ#žœžœžœžœ˜Ί—šžœ˜Jš œžœžœ žœžœžœžœžœžœžœ œ#žœžœ žœžœžœ˜Ί—Jšœ˜—J˜šŸ œžœžœ˜0Jšœdžœ˜m—J˜šŸ œž œ-˜DJšœžœžœ˜6—J˜šŸ œžœžœ-˜DJšœžœžœ˜7—J˜šŸœž œ@˜UJš5™5JšžœžœžœΗ˜ύ—J˜šŸ œž œ,˜CJš7™7Jšžœžœžœ-˜d—J˜šŸœž œA˜VJšœžœ&žœ žœžœžœžœžœžœžœžœžœ˜β—J˜šŸœž œA˜\Jš"™"Jš;œ žœ žœžœ žœžœžœ$œžœžœžœœžœžœžœžœžœžœžœžœžœžœžœžœžœ'œ žœ žœžœžœ˜ƒ—J˜šŸ œž œA˜YJš(™(Jš!œžœ žœžœžœžœœžœžœžœ2žœžœ'œ žœ žœžœžœ˜Ι—J˜šŸœž œA˜VJš ™ Jšœžœžœžœžœžœžœžœ1žœžœžœ˜Ύ—J˜šŸœž œA˜TJš!œžœžœžœžœžœžœžœžœžœžœžœžœžœžœžœžœ˜ώ—J˜Jšœ žœžœžœ˜6J˜šŸ œžœžœ˜=Jšœžœ˜J˜)J˜)Jš žœžœžœžœžœ$˜KJš žœžœžœžœžœ ˜UJ˜—J˜šŸ œžœžœ5žœ˜WJš œžœžœ žœžœ˜4Jšœ$˜$šžœžœžœž˜'Jšœ!žœ˜8šžœžœžœž˜!šžœžœžœž˜!šœ žœ˜-Jšœ žœ žœžœ˜/—Jšžœ˜—Jšžœ˜—Jšžœ˜—Jšœ˜—J˜šŸœžœžœ5žœ˜VJš œžœžœ žœžœ˜4Jšœ$˜$šžœžœžœž˜'Jšœ!žœ˜8šžœžœžœž˜!šžœžœžœž˜!šœ žœ˜-Jšœ žœ žœžœ˜/—Jšžœ˜—Jšžœ˜—Jšžœ˜—Jšœ˜—J˜šŸœžœžœ5žœ˜TJš œžœžœ žœžœ˜4Jšœ$˜$šžœžœžœž˜'Jšœ!žœ˜8šžœžœžœž˜!šžœžœžœž˜!šœ žœ˜-Jšœžœ žœžœ ˜/—Jšžœ˜—Jšžœ˜—Jšžœ˜—Jšœ˜—J˜šŸœžœžœ5žœ˜VJš œžœžœ žœžœ˜4Jšœ$˜$šžœžœžœž˜'Jšœ!žœ˜8šžœžœžœž˜!šžœžœžœž˜!šœ žœ˜-Jšœžœ žœžœ ˜/—Jšžœ˜—Jšžœ˜—Jšžœ˜—Jšœ˜—J˜Jšžœ˜J™™.J™bJšœ Οr™)—J™™.Jšœ ’™)—J™™/J™—J™J™—…—34C’