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, bottom => displacement1 _ offset1.pos; right, top => displacement1 _ offset1.pos + 1.0; origin => displacement1 _ offset1.pos + (box1.leftExtent / (box1.leftExtent + box1.rightExtent)); center => displacement1 _ offset1.pos + 0.5; ENDCASE => ERROR; SELECT offset2.wrt FROM left, bottom => displacement2 _ offset2.pos; right, top => displacement2 _ offset2.pos + 1.0; 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 left, bottom => displacement1 _ offset1.pos; right, top => displacement1 _ offset1.pos + 1.0; origin => displacement1 _ offset1.pos + (box1.descent / (box1.descent + box1.ascent)); center => displacement1 _ offset1.pos + 0.5; ENDCASE => ERROR; SELECT offset2.wrt FROM left, bottom => displacement2 _ offset2.pos; right, top => displacement2 _ offset2.pos + 1.0; 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 IN [0..nRows) DO FOR c: NAT 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. dMathRulesImpl.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 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 scale the absolute boxes => relative boxes (extents & offsets) compute relative origin location 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 Κh˜Jšœ™Jšœ0™0J˜codešΟk ˜ Kšœ˜Kšœ œ ˜Kšœœ ˜Kšœ œ ˜Kšœœœ˜Kšœœœ˜%Kšœœ:˜GKšœ ˜ K˜—šΟn œœœ˜Kšœ˜&Kšœ ˜K˜Kš˜K˜Kšž™™Kšœœ œ˜Kšœœœ˜Kšœœ œ˜Kšœœ˜K˜Kšœ œ˜*Kšœœ˜.Kšœœ˜2Kšœœ˜2K˜Kšœ œ˜*Kšœ œ˜&Kšœœ˜ Kšœœ˜,K˜Kšœœ˜K˜—K˜Jšž ™ ˜Jšœ œ˜Jšœœ˜Jšœœ˜Jšœ œ˜—K˜K˜Kšž™˜š žœœœ2œœœ˜uKšœE™EKšœ$™$Kšœœ˜)K˜šœ ˜K˜,K˜0K˜bK˜,Kšœœ˜K˜—šœ ˜K˜,K˜0K˜TK˜,Kšœœ˜K˜—KšœD˜JK˜K™K˜—š ž œœœ2œœœ˜sKšœC™CKšœ$™$Kšœœ˜#K˜šœ ˜K˜,K˜0K˜WK˜,Kšœœ˜K˜—šœ ˜K˜,K˜0K˜RK˜,Kšœœ˜K˜—KšœB˜HK˜K˜—K˜—Kšž™˜šžœœœœœœœœ.œœœœœ˜‡KšœE™EKšœ>™>K™Kšœ™Kš œ œœœœΟc(˜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šœ œ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˜2Kšœ4˜4K˜*K˜Kšœ ™ šœœ˜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˜Kšœ˜——…—46O