DIRECTORY MathBox, MathTypes USING [Style], Imager USING [Context], ImagerFont USING [Extents], Vector USING [VEC, Sub], Rope USING [ROPE, Find, Substr, Cat], Convert USING [RopeFromAtom, AtomFromRope, CardFromRope, RopeFromCard], MathRules; MathRulesImpl: CEDAR PROGRAM IMPORTS MathBox, Vector, Convert, Rope EXPORTS MathRules ~ BEGIN VEC: TYPE ~ Vector.VEC; ROPE: TYPE ~ Rope.ROPE; BOX: TYPE ~ MathBox.BOX; Style: TYPE ~ MathTypes.Style; AtomBoxProc: TYPE ~ MathRules.AtomBoxProc; AtomPaintProc: TYPE ~ MathRules.AtomPaintProc; CompoundBoxProc: TYPE ~ MathRules.CompoundBoxProc; CompositionProc: TYPE ~ MathRules.CompositionProc; Alignment2D: TYPE ~ MathRules.Alignment2D; Alignment: TYPE ~ MathRules.Alignment; Offset: TYPE ~ MathRules.Offset; TaggedOffset: TYPE ~ MathRules.TaggedOffset; Size: TYPE ~ MathRules.Size; smallGap: REAL = 0.05; medGap: REAL = 0.1; bigGap: REAL = 0.25; matrixGap: REAL = 0.4; AlignHorizontal: PUBLIC PROC[box1: ImagerFont.Extents, offset1: Offset, box2: BOX, offset2: Offset] RETURNS[REAL] ~ { displacement1, displacement2: REAL _ 0.0; SELECT offset1.wrt FROM left => displacement1 _ offset1.pos; right => displacement1 _ offset1.pos + 1.0; bottom, top => ERROR; -- horizontal alignment with bottom or top is bogus origin => displacement1 _ offset1.pos + (box1.leftExtent / (box1.leftExtent + box1.rightExtent)); center => displacement1 _ offset1.pos + 0.5; ENDCASE => ERROR; SELECT offset2.wrt FROM left => displacement2 _ offset2.pos; right => displacement2 _ offset2.pos + 1.0; bottom, top => ERROR; -- horizontal alignment with bottom or top is bogus origin => displacement2 _ offset2.pos + (box2.Extents[].leftExtent / box2.Width[]); center => displacement2 _ offset2.pos + 0.5; ENDCASE => ERROR; RETURN[MathBox.AlignHorizontal[box1, displacement1, box2, displacement2]]; }; AlignVertical: PUBLIC PROC[box1: ImagerFont.Extents, offset1: Offset, box2: BOX, offset2: Offset] RETURNS[REAL] ~ { displacement1, displacement2: REAL; SELECT offset1.wrt FROM bottom => displacement1 _ offset1.pos; top => displacement1 _ offset1.pos + 1.0; left, right => ERROR; -- vertical alignment with left or right is bogus origin => displacement1 _ offset1.pos + (box1.descent / (box1.descent + box1.ascent)); center => displacement1 _ offset1.pos + 0.5; ENDCASE => ERROR; SELECT offset2.wrt FROM bottom => displacement2 _ offset2.pos; top => displacement2 _ offset2.pos + 1.0; left, right => ERROR; -- vertical alignment with left or right is bogus origin => displacement2 _ offset2.pos + (box2.Extents[].descent / box2.Height[]); center => displacement2 _ offset2.pos + 0.5; ENDCASE => ERROR; RETURN[MathBox.AlignVertical[box1, displacement1, box2, displacement2]]; }; Compose: PUBLIC PROC[boxes: LIST OF BOX, alignments: LIST OF Alignment2D, hOrigin, vOrigin: TaggedOffset] RETURNS[BOX, LIST OF BOX] ~ { relBoxes: LIST OF BOX _ NIL; -- cons up return values; relative units myBox, myRelBox: BOX; -- box which encloses entire expression myExtents: ImagerFont.Extents; tempBox, attachHRelBox, attachVRelBox: BOX; farLeft, farRight, farUp, farDown: REAL _ 0.0; scaleVec, originOffset: VEC _ [0.0, 0.0]; dummyPtExtents: ImagerFont.Extents _ [leftExtent: 0.0, rightExtent: 0.001, descent: 0.0, ascent: 0.001]; -- null-sized extents used for alignment purposes LocalScale: PROC[b: BOX] RETURNS[BOX] ~ { scaledBox: BOX _ MathBox.Scale[b, scaleVec]; RETURN[MathBox.ChangeType[scaledBox, relative]]; }; LocalFixOffset: PROC[b: BOX] RETURNS[BOX] ~ { RETURN[MathBox.ChangeOffset[b, Vector.Sub[b.Offset[], originOffset]]]; }; IF alignments = NIL THEN ERROR unable[$noAlignments]; tempBox _ MathBox.GetBox[alignments.first.hAttach.tag, boxes]; relBoxes _ CONS[MathBox.ChangeOffset[tempBox, [0.0, 0.0]], relBoxes]; FOR l: LIST OF Alignment2D _ alignments, l.rest UNTIL l = NIL DO tempBox _ MathBox.GetBox[l.first.tag, boxes]; attachHRelBox _ MathBox.GetBox[l.first.hAttach.tag, relBoxes]; attachVRelBox _ MathBox.GetBox[l.first.vAttach.tag, relBoxes]; relBoxes _ CONS[MathBox.ChangeOffset[tempBox, [AlignHorizontal[tempBox.Extents[], l.first.hAttach.offset1, attachHRelBox, l.first.hAttach.offset2], AlignVertical[tempBox.Extents[], l.first.vAttach.offset1, attachVRelBox, l.first.vAttach.offset2]]], relBoxes]; ENDLOOP; FOR l: LIST OF BOX _ relBoxes, l.rest UNTIL l = NIL DO farLeft _ MIN[farLeft, l.first.Offset[].x - l.first.Extents[].leftExtent]; farRight _ MAX[farRight, l.first.Offset[].x + l.first.Extents[].rightExtent]; farDown _ MIN[farDown, l.first.Offset[].y - l.first.Extents[].descent]; farUp _ MAX[farUp, l.first.Offset[].y + l.first.Extents[].ascent]; ENDLOOP; myBox _ MathBox.MakeBox[$composeMyBox, NIL, other, absolute, [leftExtent: -farLeft, rightExtent: farRight, descent: -farDown, ascent: farUp]]; scaleVec _ [1 / myBox.Width[], 1/ myBox.Height[]]; relBoxes _ MathBox.MapBoxList[relBoxes, LocalScale]; myRelBox _ MathBox.Scale[myBox, scaleVec]; IF hOrigin.tag = $self THEN { attachHRelBox _ myRelBox; } ELSE { attachHRelBox _ MathBox.GetBox[hOrigin.tag, relBoxes]; }; IF vOrigin.tag = $self THEN { attachVRelBox _ myRelBox; } ELSE { attachVRelBox _ MathBox.GetBox[vOrigin.tag, relBoxes]; }; originOffset _ [ AlignHorizontal[dummyPtExtents, [origin], attachHRelBox, hOrigin.offset], AlignVertical[dummyPtExtents, [origin], attachVRelBox, vOrigin.offset] ]; relBoxes _ MathBox.MapBoxList[relBoxes, LocalFixOffset]; myExtents _ myRelBox.Extents[]; myRelBox _ MathBox.ChangeExtents[myRelBox, [leftExtent: myExtents.leftExtent + originOffset.x, rightExtent: myExtents.rightExtent - originOffset.x, descent: myExtents.descent + originOffset.y, ascent: myExtents.ascent - originOffset.y]]; myBox _ MathBox.Scale[myRelBox, [myBox.Width[], myBox.Height[]]]; RETURN[myBox, relBoxes]; }; AtomFromRowCol: PUBLIC PROC[row, col: NAT] RETURNS[ATOM] ~ { rowRope: ROPE _ Convert.RopeFromCard[row]; colRope: ROPE _ Convert.RopeFromCard[col]; RETURN[Convert.AtomFromRope[Rope.Cat["r", rowRope, "c", colRope]]]; }; RowColFromAtom: PUBLIC PROC[rc: ATOM] RETURNS[NAT, NAT] ~ { rcRope: ROPE _ Convert.RopeFromAtom[from: rc, quote: FALSE]; rPos: INT _ Rope.Find[rcRope, "r"]; cPos: INT _ Rope.Find[rcRope, "c"]; row, col: NAT _ 0; IF (cPos = -1) OR (rPos = -1) OR (cPos < rPos) THEN ERROR badFormat; row _ Convert.CardFromRope[Rope.Substr[rcRope, rPos+1, (cPos - (rPos+1))]]; col _ Convert.CardFromRope[Rope.Substr[rcRope, cPos+1]]; RETURN[row, col]; }; ComposeMatrix: PUBLIC PROC[nRows, nCols: NAT, boxes: LIST OF BOX, spaceBox, openSymBox, closeSymBox: BOX] RETURNS[BOX, LIST OF BOX, BOX, BOX] ~ { NatSeq: TYPE ~ REF NatSeqRec; NatSeqRec: TYPE ~ RECORD[ elements: SEQUENCE size: NAT OF NAT ]; Element: TYPE ~ RECORD [ box: BOX _ NIL ]; Row: TYPE ~ REF RowRec; RowRec: TYPE ~ RECORD [ elements: SEQUENCE numberOfCols: NAT OF Element ]; Matrix: TYPE ~ REF MatrixRec; MatrixRec: TYPE ~ RECORD[ rows: SEQUENCE numberOfRows: NAT OF Row ]; tallest: NatSeq _ NEW[NatSeqRec[nRows]]; widest: NatSeq _ NEW[NatSeqRec[nCols]]; a: Matrix; myBox, myRelBox: BOX; relBoxes: LIST OF BOX _ NIL; maxHeight, maxWidth, scaleFactor, yOffset: REAL _ 0.0; currentRow, currentCol: NAT _ 0; tempElt: Element; farLeft, farRight, farUp, farDown: REAL _ 0.0; scaleVec, originOffset: VEC _ [0.0, 0.0]; myExtents: ImagerFont.Extents; closeBox, openBox: BOX; horizSpace: BOX _ spaceBox; -- inter-column spacing vertSpace: BOX _ spaceBox; -- inter-row spacing a _ NEW[MatrixRec[nRows]]; FOR row: NAT IN [0..nRows) DO a[row] _ NEW[RowRec[nCols]]; ENDLOOP; FOR elements: LIST OF BOX _ boxes, elements.rest UNTIL elements = NIL DO [currentRow, currentCol] _ RowColFromAtom[elements.first.Tag[]]; a[currentRow - 1][currentCol - 1].box _ elements.first; ENDLOOP; FOR r:NAT IN [0..nRows) DO tallest[r] _ 0; maxHeight _ 0.0; FOR c:NAT IN [0..nCols) DO IF a[r][c].box = NIL THEN ERROR unable[$missingElement]; -- missing r,c element IF a[r][c].box.Height[] > maxHeight THEN { tallest[r] _ c; maxHeight _ a[r][c].box.Height[]; }; ENDLOOP; ENDLOOP; FOR c:NAT IN [0..nCols) DO widest[c] _ 0; maxWidth _ 0.0; FOR r:NAT IN [0..nRows) DO IF a[r][c].box.Width[] > maxWidth THEN { widest[c] _ r; maxWidth _ a[r][c].box.Width[]; }; ENDLOOP; ENDLOOP; a[0][tallest[0]].box _ MathBox.ChangeOffset[a[0][tallest[0]].box, [0.0, 0.0]]; -- set vOrigin FOR r:NAT IN [1..nRows) DO tempElt _ a[r][tallest[r]]; -- just shorthand vertSpace _ MathBox.ChangeOffset[vertSpace, [0.0, AlignVertical[vertSpace.Extents[], [top], a[r-1][tallest[r-1]].box, [bottom]]]]; a[r][tallest[r]].box _ MathBox.ChangeOffset[tempElt.box, [0.0, AlignVertical[tempElt.box.Extents[], [top], vertSpace, [bottom]]]]; ENDLOOP; FOR r:NAT IN [0..nRows) DO FOR c:NAT IN [0..nCols) DO IF c # tallest[r] THEN a[r][c].box _ MathBox.ChangeOffset[a[r][c].box, [0.0, AlignVertical[a[r][c].box.Extents[], [origin], a[r][tallest[r]].box, [origin]]]]; ENDLOOP; ENDLOOP; a[widest[0]][0].box _ MathBox.ChangeOffset[a[widest[0]][0].box, [0.0, a[widest[0]][0].box.Offset[].y]]; -- set horizontal origin FOR c:NAT IN [1..nCols) DO tempElt _ a[widest[c]][c]; -- just shorthand horizSpace _ MathBox.ChangeOffset[horizSpace, [AlignHorizontal[horizSpace.Extents[], [left], a[widest[c-1]][c-1].box, [right]], 0.0]]; -- punt vertical offset a[widest[c]][c].box _ MathBox.ChangeOffset[tempElt.box, [AlignHorizontal[tempElt.box.Extents[], [left], horizSpace, [right]], tempElt.box.Offset[].y]]; ENDLOOP; FOR c:NAT IN [0..nCols) DO FOR r:NAT IN [0..nRows) DO IF r # widest[c] THEN a[r][c].box _ MathBox.ChangeOffset[a[r][c].box, [AlignHorizontal[a[r][c].box.Extents[], [center], a[widest[c]][c].box, [center]], a[r][c].box.Offset[].y]]; ENDLOOP; ENDLOOP; FOR r:NAT IN [0..nRows) DO FOR c:NAT IN [0..nCols) DO farLeft _ MIN[farLeft, a[r][c].box.Offset[].x - a[r][c].box.Extents[].leftExtent]; farRight _ MAX[farRight, a[r][c].box.Offset[].x + a[r][c].box.Extents[].rightExtent]; farDown _ MIN[farDown, a[r][c].box.Offset[].y - a[r][c].box.Extents[].descent]; farUp _ MAX[farUp, a[r][c].box.Offset[].y + a[r][c].box.Extents[].ascent]; ENDLOOP; ENDLOOP; myBox _ MathBox.MakeBox[$composeMatrixBox, NIL, other, absolute, [leftExtent: -farLeft, rightExtent: farRight, descent: -farDown, ascent: farUp]]; scaleFactor _ MAX[0.25, ((1 + medGap) * (-farDown + farUp)) / openSymBox.Height[]]; openBox _ MathBox.Scale[openSymBox, [scaleFactor, scaleFactor]]; scaleFactor _ MAX[0.25, ((1 + medGap) * (-farDown + farUp)) / closeSymBox.Height[]]; closeBox _ MathBox.Scale[closeSymBox, [scaleFactor, scaleFactor]]; openBox _ MathBox.ChangeOffset[openBox, [ AlignHorizontal[openBox.Extents[], [right, medGap], myBox, [left]], AlignVertical[openBox.Extents[], [center], myBox, [center]]]]; closeBox _ MathBox.ChangeOffset[closeBox, [ AlignHorizontal[closeBox.Extents[], [left, -medGap], myBox, [right]], AlignVertical[closeBox.Extents[], [center], myBox, [center]]]]; farLeft _ openBox.Offset[].x - openBox.Extents[].leftExtent; farRight _ closeBox.Offset[].x + closeBox.Extents[].rightExtent; farUp _ openBox.Offset[].y + openBox.Extents[].ascent; farDown _ openBox.Offset[].y - openBox.Extents[].descent; myBox _ MathBox.MakeBox[$composeMatrixBox, NIL, other, absolute, [leftExtent: -farLeft, rightExtent: farRight, descent: -farDown, ascent: farUp]]; scaleVec _ [1 / myBox.Width[], 1/ myBox.Height[]]; FOR r:NAT IN [0..nRows) DO FOR c:NAT IN [0..nCols) DO scaledBox: BOX _ MathBox.Scale[a[r][c].box, scaleVec]; a[r][c].box _ MathBox.ChangeType[scaledBox, relative]; ENDLOOP; ENDLOOP; myRelBox _ MathBox.Scale[myBox, scaleVec]; openBox _ MathBox.Scale[openBox, scaleVec]; openBox _ MathBox.ChangeType[openBox, relative]; closeBox _ MathBox.Scale[closeBox, scaleVec]; closeBox _ MathBox.ChangeType[closeBox, relative]; yOffset _ AlignVertical[[leftExtent: 0.0, rightExtent: 0.1, descent: 0.0, ascent: 0.1], [origin], openBox, [center]]; originOffset _ [0.0, yOffset]; FOR r:NAT IN [0..nRows) DO FOR c:NAT IN [0..nCols) DO a[r][c].box _ MathBox.ChangeOffset[a[r][c].box, Vector.Sub[a[r][c].box.Offset[], originOffset]]; ENDLOOP; ENDLOOP; openBox _ MathBox.ChangeOffset[openBox, Vector.Sub[openBox.Offset[], originOffset]]; closeBox _ MathBox.ChangeOffset[closeBox, Vector.Sub[closeBox.Offset[], originOffset]]; myExtents _ myRelBox.Extents[]; myRelBox _ MathBox.ChangeExtents[myRelBox, [leftExtent: myExtents.leftExtent + originOffset.x, rightExtent: myExtents.rightExtent - originOffset.x, descent: myExtents.descent + originOffset.y, ascent: myExtents.ascent - originOffset.y]]; myBox _ MathBox.Scale[myRelBox, [myBox.Width[], myBox.Height[]]]; relBoxes _ NIL; -- cons up new list from matrix a FOR r: NAT DECREASING IN [0..nRows) DO FOR c: NAT DECREASING IN [0..nCols) DO relBoxes _ CONS[a[r][c].box, relBoxes]; ENDLOOP; ENDLOOP; RETURN[myBox, relBoxes, openBox, closeBox]; }; ComputeSize: PUBLIC PROC[base, adjustment: Size] RETURNS[Size] ~ { SELECT base FROM normal => RETURN[adjustment]; script => { SELECT adjustment FROM normal => RETURN[script]; script, scriptscript => RETURN[scriptscript]; big => RETURN[normal]; ENDCASE => ERROR; }; scriptscript => { SELECT adjustment FROM normal, script, scriptscript => RETURN[scriptscript]; big => RETURN[script]; ENDCASE => ERROR; }; big => { SELECT adjustment FROM normal, big => RETURN[big]; script => RETURN[normal]; scriptscript => RETURN[script]; ENDCASE => ERROR; }; ENDCASE => ERROR; }; VecFromSize: PUBLIC PROC[size: Size] RETURNS[VEC] ~ { SELECT size FROM normal => RETURN[[1.0, 1.0]]; script => RETURN[[0.6, 0.6]]; scriptscript => RETURN[[0.36, 0.36]]; big => RETURN[[1.5, 1.5]]; ENDCASE => ERROR; }; unable: PUBLIC ERROR[reason: ATOM] = CODE; badFormat: PUBLIC ERROR = CODE; END. RMathRulesImpl.mesa Carl Waldspurger, August 30, 1986 4:35:33 pm PDT Imported Type Abbreviations Constants Alignment Operations effects: Horizontally aligns box1 with box2 using specified offsets. Returns x offset for box1. effects: Vertically aligns box1 with box2 using specified offsets. Returns y offset for box1. Automated Layout Composition effects: Performs the layout composition for boxes using alignments. Returns information expected from a CompositionProc. local declarations should really ENABLE boxNotFound => ERROR unable local procedures n.b. input boxes are in absolute units (boxes), output boxes are in relative units (relBoxes) but we are still working in real absolute units here get first referenced box & save it as the initial (temporary) origin dsa - get the first box that we say we want to align with respect to, and make its lower left hand corner the origin of absolute coordinates compute offset locations in absolute (n.b. not relative) units align tempBox to attach H&V boxes and save it find extreme edge points to determine myBox size set myBox dimensions in REAL units dsa - note that since we made the lower left hand corner of tempbox the origin of absolute coordinates above, farLeft <= 0.0 and farDown<= 0.0, hence all extents above will get set to nonnegative values. dsa - note that we accept the default offset of [0.0, 0.0] scale the absolute boxes => relative boxes (extents & offsets) dsa - the scaling of offsets that MathBox.Scale will do is ok since the offsets of all the relBoxes have been changed to be with respect to our new origin of coordinates, and that myRelBox has offset of [0.0, 0.0] dsa - n.b. myRelBox is an absolute box compute relative origin location dsa - why do we do this? dsa - presumably the new origin will be somewhere inside myRelBox? adjust all relative box offsets by originOffset adjust myRelBox w.r.t new origin effects: Returns the atom $r{row}c{col} requires: rc is of the form $r#c# effects: Returns the row and column indexes associated with $r#c# SIGNALS badFormat if rc does not conform to the format $r#c# local declarations effects: Performs the layout composition for a generalized matrix. Returns information expected by Format, preserving input row&col orderings. type declarations local declatations convert boxes into a SEQUENCE (ugh!) matrix type instantiate matrix "a" (isn't CLU's array[]$create() much nicer, really?) mark tallest elt in each row mark widest elt in each row vertically align tallest elts, row by row align a vertical space between each row vertically align all other (shorter) elts row by row horizontally align widest elts, col by col align a horizSpace between each column horizontally align all other (narrower) elts col by col now find extreme edge points to determine myBox size preliminary "myBox" for aligning open and close symbols magnify (don't allow too much shrinkage - using hardcoded #s here is a kludge, but I have a plane to catch...) openSymBox and closeSymBox boxes (absolute boxes) align openBox and closeBox align using myBox info recompute extreme points scale the absolute boxes => relative boxes (extents & offsets) compute relative origin location let origin be thru center; find center using dummy alignment extents adjust all relative boxes by origin offset amount adjust myRelBox w.r.t new origin reconstruct LIST OF BOX for return value (from MATRIX sequence structure) Size Operations effects: Returns the size of adjustment applied to base. effects: Returns scaling vector corresponding to size (e.g. normal = unit vec) Signals & Errors Κ»˜Jšœ™Jšœ0™0J˜codešΟk ˜ Kšœ˜Kšœ œ ˜Kšœœ ˜Kšœ œ ˜Kšœœœ˜Kšœœœ˜%Kšœœ:˜GKšœ ˜ K˜—šΟn œœœ˜Kšœ˜&Kšœ ˜K˜Kš˜K˜—headšž™Kšœœ œ˜Kšœœœ˜Kšœœ œ˜Kšœœ˜K˜Kšœ œ˜*Kšœœ˜.Kšœœ˜2Kšœœ˜2K˜Kšœ œ˜*Kšœ œ˜&Kšœœ˜ Kšœœ˜,K˜Kšœœ˜K˜—šž ™ Jšœ œ˜Jšœœ˜Jšœœ˜Jšœ œ˜—šž™š žœœœ2œœœ˜uKšœE™EKšœ$™$Kšœœ˜)K˜šœ ˜K˜$K˜+KšœœΟc3˜IK˜bK˜,Kšœœ˜K˜—šœ ˜K˜$K˜+KšœœŸ3˜IK˜TK˜,Kšœœ˜K˜—KšœD˜JK˜K™K˜—š ž œœœ2œœœ˜sKšœC™CKšœ$™$Kšœœ˜#K˜šœ ˜K˜&K˜)KšœœŸ1˜GK˜WK˜,Kšœœ˜K˜—šœ ˜K˜&K˜)KšœœŸ1˜GK˜RK˜,Kšœœ˜K˜—KšœB˜HK˜K˜—K˜—šž™šžœœœœœœœœ.œœœœœ˜‡KšœE™EKšœ>™>K™Kšœ™Kš œ œœœœŸ(˜FKšœœŸ'˜>K˜Kšœ'œ˜+Kšœ#œ˜.Kšœœ˜)KšœjŸ1˜›K˜Kšœ0™0K˜Kšœ™š ž œœœœœ˜)Kšœ œ˜,Kšœ*˜0K˜—K˜š žœœœœœ˜-Kšœ@˜FK˜—K˜K˜Kšœœœœ˜5K˜Kšœ]™]Kšœ4™4K˜KšœD™DK™ŒK˜>Kšœ œ6˜EK˜Kšœ>™>š œœœ"œœ˜@K˜-K˜>K˜>Kšœ-™-Kšœ œτ˜ƒKšœ˜—K˜Kšœ0™0š œœœœœœ˜6Kšœ œ=˜JKšœ œ?˜MKšœ œ:˜GKšœœ7˜BKšœ˜—˜K˜—Kšœ"™"Kšœ'œd˜ŽKšœΜ™ΜK™:K˜Kšœ>™>KšœΦ™ΦK˜2Kšœ4˜4K˜*Kšœ&™&K˜Kšœ ™ Kšœ™KšœB™Bšœœ˜K˜K˜—šœ˜K˜6K˜—šœœ˜K˜K˜—šœ˜K˜6K˜—K˜˜K˜IK˜FK˜—K˜Kšœ/™/K˜8K˜Kšœ ™ K˜K˜νK˜K˜AK˜Kšœ˜K˜K˜—š žœœœ œœœ˜K˜—˜+K˜EK˜?—K˜Kšœ™K˜™>K˜2K˜šœœœ ˜šœœœ ˜Kšœ œ(˜6Kšœ6˜6Kšœ˜—Kšœ˜K˜—K˜*K˜+K˜0K˜-K˜2K˜Kšœ ™ KšœD™DK˜uKšœ˜K˜Kšœ1™1šœœœ ˜šœœœ ˜K˜`Kšœ˜—Kšœ˜—K˜TK˜WK˜Kšœ ™ K˜K˜νK˜K˜AK˜KšœI™IK˜Kšœ œŸ!˜2šœœ œ ˜&šœœ œ ˜&Kšœ œ˜'Kšœ˜—Kšœ˜K˜—Kšœ&˜,K˜˜K˜K˜K˜———šž™K˜šž œœœœ ˜BKšœ9™9K™šœ˜Kšœ œ ˜˜ šœ ˜Kšœ œ ˜Kšœœ˜-Kšœœ ˜Kšœœ˜—K˜—˜šœ ˜Kšœ œ˜5Kšœœ ˜Kšœœ˜—K˜—˜šœ ˜Kšœœ˜Kšœ œ ˜Kšœœ ˜Kšœœ˜—K˜—Kšœœ˜—K˜—K˜š ž œœœ œœ˜5KšœO™OK™šœ˜Kšœ œ ˜Kšœ œ ˜Kšœœ˜%Kšœœ ˜Kšœœ˜—K˜—K˜—šž™K˜Kš œœœ œœ˜*Kšœ  œœ˜˜K˜——K˜Kšœ˜—…—56SC