DIRECTORY MathDisplayExpr, MathExpr, MathBox, MathConstructors, MathDB, MathTypes, MathRules, Convert USING [RopeFromAtom], Rope USING [ROPE, Length, Find, Replace, Cat], Imager USING [Context, black, SetColor, MaskRectangle], XRope; MathDisplayExprImpl: CEDAR PROGRAM IMPORTS MathBox, MathExpr, MathDB, MathConstructors, Imager, MathRules, Rope, Convert, XRope EXPORTS MathDisplayExpr ~ BEGIN ROPE: TYPE ~ Rope.ROPE; BOX: TYPE ~ MathBox.BOX; EXPR: TYPE ~ MathExpr.EXPR; AtomEXPR: TYPE ~ MathExpr.AtomEXPR; CompoundEXPR: TYPE ~ MathExpr.CompoundEXPR; MatrixEXPR: TYPE ~ MathExpr.MatrixEXPR; Style: TYPE ~ MathTypes.Style; Argument: TYPE ~ MathExpr.Argument; Symbol: TYPE ~ MathExpr.Symbol; AtomClass: TYPE ~ MathExpr.AtomClass; AtomFlavor: TYPE ~ MathExpr.AtomFlavor; CompoundClass: TYPE ~ MathExpr.CompoundClass; MatrixClass: TYPE ~ MathExpr.MatrixClass; Size: TYPE ~ MathRules.Size; Selection: TYPE ~ MathDisplayExpr.Selection; ReplacePair: TYPE ~ MathDisplayExpr.ReplacePair; DisplayExprRep: PUBLIC TYPE ~ RECORD [ tag: ATOM, -- identifying tag such as $integrand expression: DisplayObj, -- atom, compound expr, or matrix relativeBox: BOX, -- bounding box in relative units absoluteBox: BOX, -- bounding box in absolute units iconic: BOOL _ FALSE, -- TRUE iff expression is currently iconic (2/87apparentlyUnused) parent: DisplayExpr _ NIL -- enclosing parent expression ]; DisplayObj: TYPE ~ REF DisplayObjRep; DisplayObjRep: TYPE ~ RECORD [ SELECT type:* FROM atom => [class: AtomClass, value: ROPE], compound => [class: CompoundClass, subExprs: LIST OF DisplayExpr _ NIL], matrix => [ class: MatrixClass, -- type of matrix op, e.g. matrix, vector, determinant, etc. nRows, nCols: INT, -- matrix size, rows x cols elements: LIST OF DisplayExpr _ NIL, -- matrix elements openSym: DisplayExpr, -- left bracket closeSym: DisplayExpr, -- right bracket space: DisplayExpr -- inter-element spacing ] ENDCASE ]; AtomDisplayObj: TYPE ~ REF AtomDisplayObjRep; AtomDisplayObjRep: TYPE ~ atom DisplayObjRep; CompoundDisplayObj: TYPE ~ REF CompoundDisplayObjRep; CompoundDisplayObjRep: TYPE ~ compound DisplayObjRep; MatrixDisplayObj: TYPE ~ REF MatrixDisplayObjRep; MatrixDisplayObjRep: TYPE ~ matrix DisplayObjRep; DisplayExpr: TYPE ~ REF DisplayExprRep; -- inside impl module, use rep MakeAtomicDisplayExpr: PUBLIC PROC[tag: ATOM, class: AtomClass, value: ROPE, relBox, absBox: BOX, parent: DisplayExpr _ NIL] RETURNS[DisplayExpr] ~ { RETURN[NEW[DisplayExprRep _ [tag: tag, relativeBox: relBox, absoluteBox: absBox, parent: parent, expression: NEW[AtomDisplayObjRep _ [atom[class: class, value: value]]]]]]; }; MakeCompoundDisplayExpr: PUBLIC PROC[tag: ATOM, class: CompoundClass, subExprs: LIST OF DisplayExpr, relBox, absBox: BOX, parent: DisplayExpr _ NIL] RETURNS[DisplayExpr] ~ { RETURN[NEW[DisplayExprRep _ [tag: tag, relativeBox: relBox, absoluteBox: absBox, parent: parent, expression: NEW[CompoundDisplayObjRep _ [compound[class: class, subExprs: subExprs]]]]]]; }; MakeMatrixDisplayExpr: PUBLIC PROC[tag: ATOM, class: MatrixClass, nRows, nCols: INT, elements: LIST OF DisplayExpr, relBox, absBox: BOX, openSym, closeSym, space: DisplayExpr, parent: DisplayExpr _ NIL] RETURNS[DisplayExpr] ~ { RETURN[NEW[DisplayExprRep _ [tag: tag, relativeBox: relBox, absoluteBox: absBox, parent: parent, expression: NEW[MatrixDisplayObjRep _ [matrix[class: class, nRows: nRows, nCols: nCols, elements: elements, openSym: openSym, closeSym: closeSym, space: space]]]]]]; }; ASRopeFromDisplayExpr: PUBLIC PROC[expr: DisplayExpr, flavor: ATOM _ $AS] RETURNS[ROPE] ~ { WITH expr.expression SELECT FROM a: AtomDisplayObj => SELECT flavor FROM $Reduce => IF a.class.cvtReduceRope # NIL THEN RETURN[a.class.cvtReduceRope[a.value]] ELSE RETURN[a.value]; $SMP => IF a.class.cvtSMPRope # NIL THEN RETURN[a.class.cvtSMPRope[a.value]] ELSE RETURN[a.value]; ENDCASE => IF a.class.cvtASRope # NIL THEN RETURN[a.class.cvtASRope[a.value]] ELSE RETURN[a.value]; c: CompoundDisplayObj => { template: ROPE _ SELECT flavor FROM $Reduce => c.class.cvtReduce, -- template for return value $SMP => c.class.cvtSMP, -- template for return value ENDCASE => c.class.cvtAS; -- template for return value argName: ROPE _ NIL; position: INT _ -1; IF Rope.Length[template] < 1 THEN RETURN[""]; FOR l: LIST OF Argument _ c.class.arguments, l.rest UNTIL l = NIL DO argName _ Convert.RopeFromAtom[l.first.name]; position _ Rope.Find[template, argName]; IF position # -1 THEN template _ Rope.Replace[base: template, start: position, len: Rope.Length[argName], with: ASRopeFromDisplayExpr[GetDisplayExpr[l.first.name, c.subExprs], flavor] ]; ENDLOOP; IF c.class.name = $complex THEN { position _ Rope.Find[template, "+ -"]; IF position # -1 THEN template _ Rope.Replace[base: template, start: position, len: 3, with: "- "]; }; RETURN[template]; }; m: MatrixDisplayObj => { Element: TYPE ~ RECORD [ expr: DisplayExpr _ 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 ]; a: Matrix; currentRow, currentCol: NAT; result: ROPE _ NIL; -- return value a _ NEW[MatrixRec[m.nRows]]; FOR row:INT IN [0..m.nRows) DO a[row] _ NEW[RowRec[m.nCols]]; ENDLOOP; FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO [currentRow, currentCol] _ MathRules.RowColFromAtom[l.first.tag]; a[currentRow - 1][currentCol - 1].expr _ l.first; ENDLOOP; SELECT m.class.name FROM $matrix => { result _ "List[ "; FOR r:INT IN [0..m.nRows) DO result _ Rope.Cat[result, "List[ "]; -- row start char FOR c:INT IN [0..m.nCols) DO result _ Rope.Cat[result, ASRopeFromDisplayExpr[a[r][c].expr]]; IF c # (m.nCols - 1) THEN result _ Rope.Cat[result, ", "]; -- col separator ENDLOOP; result _ Rope.Cat[result, " ]"]; -- row end char IF r # (m.nRows - 1) THEN result _ Rope.Cat[result, ", "]; -- row separator ENDLOOP; result _ Rope.Cat[result, " ]"]; -- end with matrix end char }; $vector, $sequence, $set, $point => { result _ "List[ "; -- should select set, sequence, etc. IF m.nRows = 1 THEN { -- row vector FOR c: INT IN [0..m.nCols) DO result _ Rope.Cat[result, ASRopeFromDisplayExpr[a[0][c].expr]]; IF c # (m.nCols - 1) THEN result _ Rope.Cat[result, ", "]; -- col separator ENDLOOP; } ELSE { -- column vector FOR r: INT IN [0..m.nRows) DO result _ Rope.Cat[result, ASRopeFromDisplayExpr[a[r][0].expr]]; IF r # (m.nRows - 1) THEN result _ Rope.Cat[result, ", "]; -- row separator ENDLOOP; }; result _ Rope.Cat[result, " ]"]; }; ENDCASE => result _ "unknownMatrixType"; RETURN[result]; }; ENDCASE => ERROR; }; DisplayExprFromExpr: PUBLIC PROC[expr: EXPR] RETURNS[DisplayExpr] ~ { myDisplayExpr, tempDisplayExpr: DisplayExpr; emptyAtom: ATOM _ $expr; -- generic identifier emptyRelBox: BOX _ MathBox.MakeBox[emptyAtom, NIL, other, relative]; emptyAbsBox: BOX _ MathBox.MakeBox[emptyAtom, NIL, other, absolute]; SELECT expr.GetType[] FROM atom => { a: AtomEXPR _ expr.GetAtomExpr[]; RETURN[MakeAtomicDisplayExpr[emptyAtom, MathExpr.GetAtomClass[a], MathExpr.GetValue[a], emptyRelBox, emptyAbsBox]]; }; compound => { c: CompoundEXPR _ expr.GetCompoundExpr[]; compClass: CompoundClass _ MathExpr.GetCompoundClass[c]; displaySubExprs: LIST OF DisplayExpr _ NIL; -- cons up list of display expressions FOR l: LIST OF Argument _ compClass.arguments, l.rest UNTIL l = NIL DO tempDisplayExpr _ DisplayExprFromExpr[MathExpr.GetTaggedExpr[l.first.name, MathExpr.GetSubExprs[c] ! exprNotFound => {ERROR unable[$missingArg]}].expression]; tempDisplayExpr.tag _ l.first.name; -- set name tag for display expr displaySubExprs _ CONS[tempDisplayExpr, displaySubExprs]; ENDLOOP; FOR l: LIST OF Symbol _ compClass.symbols, l.rest UNTIL l = NIL DO tempDisplayExpr _ DisplayExprFromExpr[MathExpr.GetTaggedExpr[l.first.name, MathExpr.GetSubExprs[c] ! exprNotFound => {ERROR unable[$missingSym]}].expression]; tempDisplayExpr.tag _ l.first.name; -- set name tag for display expr displaySubExprs _ CONS[tempDisplayExpr, displaySubExprs]; ENDLOOP; myDisplayExpr _ MakeCompoundDisplayExpr[emptyAtom, MathExpr.GetCompoundClass[c], displaySubExprs, emptyRelBox, emptyAbsBox]; FOR l: LIST OF DisplayExpr _ displaySubExprs, l.rest UNTIL l = NIL DO l.first.parent _ myDisplayExpr; -- set parent ENDLOOP; RETURN[myDisplayExpr]; }; matrix => { m: MatrixEXPR _ expr.GetMatrixExpr[]; elts: LIST OF MathExpr.TaggedMathExpr _ MathExpr.GetMatrixElements[m]; class: MatrixClass _ MathExpr.GetMatrixClass[m]; displayElts, displayEltsPointer: LIST OF DisplayExpr _ NIL; nRows, nCols: NAT; openSym, closeSym, space: DisplayExpr; [nRows, nCols] _ MathExpr.GetMatrixSize[m]; FOR l: LIST OF MathExpr.TaggedMathExpr _ elts, l.rest UNTIL l = NIL DO tempDisplayExpr _ DisplayExprFromExpr[l.first.expression]; tempDisplayExpr.tag _ l.first.id; -- set name tag for display expr IF displayElts = NIL THEN displayElts _ displayEltsPointer _ LIST[tempDisplayExpr] ELSE displayEltsPointer _ displayEltsPointer.rest _ LIST[tempDisplayExpr]; ENDLOOP; openSym _ DisplayExprFromExpr[class.openSym]; closeSym _ DisplayExprFromExpr[class.closeSym]; space _ DisplayExprFromExpr[class.space]; myDisplayExpr _ MakeMatrixDisplayExpr[emptyAtom, class, nRows, nCols, displayElts, emptyRelBox, emptyAbsBox, openSym, closeSym, space]; FOR l: LIST OF DisplayExpr _ displayElts, l.rest UNTIL l = NIL DO l.first.parent _ myDisplayExpr; -- set parent ENDLOOP; RETURN[myDisplayExpr]; }; ENDCASE => ERROR; }; ExprFromDisplayExpr: PUBLIC PROC[expr: DisplayExpr] RETURNS[EXPR] ~ { WITH expr.expression SELECT FROM a: AtomDisplayObj => { RETURN[MathExpr.MakeAtomicExpr[a.class.name, a.value]]; }; c: CompoundDisplayObj => { args: LIST OF MathExpr.TaggedMathExpr _ NIL; FOR l: LIST OF DisplayExpr _ c.subExprs, l.rest UNTIL l = NIL DO args _ CONS[[l.first.tag, ExprFromDisplayExpr[l.first]], args]; ENDLOOP; RETURN[MathExpr.MakeCompoundExpr[c.class.name, args]]; }; m: MatrixDisplayObj => { elts, eltsPointer: LIST OF MathExpr.TaggedMathExpr _ NIL; FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO -- changed 3/4/87 taggedMathExpr: MathExpr.TaggedMathExpr _ [l.first.tag, ExprFromDisplayExpr[l.first]]; IF elts = NIL THEN elts _ eltsPointer _ LIST[taggedMathExpr] ELSE eltsPointer _ eltsPointer.rest _ LIST[taggedMathExpr]; ENDLOOP; RETURN[MathExpr.MakeMatrixExpr[m.class.name, m.nRows, m.nCols, elts]]; }; ENDCASE => ERROR; }; Copy: PUBLIC PROC[expr: DisplayExpr] RETURNS[DisplayExpr] ~ { WITH expr.expression SELECT FROM a: AtomDisplayObj => { RETURN[MakeAtomicDisplayExpr[expr.tag, a.class, a.value, expr.relativeBox, expr.absoluteBox]]; }; c: CompoundDisplayObj => { exprCopy: DisplayExpr; -- return value copiedSubExprs: LIST OF DisplayExpr _ NIL; -- cons up new list of copies FOR l: LIST OF DisplayExpr _ c.subExprs, l.rest UNTIL l = NIL DO copiedSubExprs _ CONS[Copy[l.first], copiedSubExprs]; ENDLOOP; exprCopy _ MakeCompoundDisplayExpr[expr.tag, c.class, copiedSubExprs, expr.relativeBox, expr.absoluteBox]; FOR l: LIST OF DisplayExpr _ copiedSubExprs, l.rest UNTIL l = NIL DO l.first.parent _ exprCopy; -- set parent pointers appropriately ENDLOOP; RETURN[exprCopy]; }; m: MatrixDisplayObj => { exprCopy: DisplayExpr; -- return value copiedElts, copiedEltsPtr: LIST OF DisplayExpr _ NIL; -- cons up a new list of copied elements FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO IF copiedElts = NIL THEN copiedElts _ copiedEltsPtr _ LIST[Copy[l.first] ] ELSE copiedEltsPtr _ copiedEltsPtr.rest _ LIST[Copy[l.first] ]; ENDLOOP; exprCopy _ MakeMatrixDisplayExpr[expr.tag, m.class, m.nRows, m.nCols, copiedElts, expr.relativeBox, expr.absoluteBox, Copy[m.openSym], Copy[m.closeSym], Copy[m.space]]; FOR l: LIST OF DisplayExpr _ copiedElts, l.rest UNTIL l = NIL DO l.first.parent _ exprCopy; -- set parent pointers appropriately ENDLOOP; RETURN[exprCopy]; }; ENDCASE => ERROR; }; Tag: PUBLIC PROC[expr: DisplayExpr] RETURNS[ATOM] ~ { RETURN[expr.tag]; }; Class: PUBLIC PROC[expr: DisplayExpr] RETURNS[ATOM] ~ { WITH expr.expression SELECT FROM a: AtomDisplayObj => RETURN[a.class.name]; c: CompoundDisplayObj => RETURN[c.class.name]; m: MatrixDisplayObj => RETURN[m.class.name]; ENDCASE => ERROR; }; GetSubExprs: PUBLIC PROC[expr: DisplayExpr] RETURNS[LIST OF DisplayExpr] ~ { WITH expr.expression SELECT FROM a: AtomDisplayObj => RETURN[NIL]; -- atoms don't have any children c: CompoundDisplayObj => RETURN[c.subExprs]; m: MatrixDisplayObj => RETURN[m.elements]; ENDCASE => ERROR; }; Format: PUBLIC PROC[expr: DisplayExpr, size: Size] RETURNS[BOX] ~ { subExprBoxes: LIST OF BOX; myBox, tempBox: BOX; WITH expr.expression SELECT FROM a: AtomDisplayObj => { RETURN[MathBox.Scale[MathBox.MakeBox[tag: a.class.name, aliases: NIL, formatClass: a.class.formatClass, type: absolute, extents: a.class.boxRule[a.value, a.class.style]], MathRules.VecFromSize[size]]]; }; c: CompoundDisplayObj => { subExprBoxes _ NIL; -- cons up list of subexpression boxes FOR l: LIST OF Argument _ c.class.arguments, l.rest UNTIL l = NIL DO tempBox _ Format[GetDisplayExpr[l.first.name, c.subExprs ! exprNotFound => {ERROR unable[$missingArg]}], MathRules.ComputeSize[base: size, adjustment: l.first.size]]; subExprBoxes _ CONS[MathBox.MakeBox[l.first.name, l.first.aliases, tempBox.FormatClass[], tempBox.Type[], tempBox.Extents[], tempBox.Offset[], tempBox.SubscriptHint[], tempBox.SuperscriptHint[]], subExprBoxes]; ENDLOOP; FOR l: LIST OF Symbol _ c.class.symbols, l.rest UNTIL l = NIL DO tempBox _ Format[GetDisplayExpr[l.first.name, c.subExprs ! exprNotFound => {ERROR unable[$missingSym]}], MathRules.ComputeSize[base: size, adjustment: l.first.size]]; subExprBoxes _ CONS[MathBox.MakeBox[l.first.name, l.first.aliases, tempBox.FormatClass[], tempBox.Type[], tempBox.Extents[], tempBox.Offset[], tempBox.SubscriptHint[], tempBox.SuperscriptHint[]], subExprBoxes]; ENDLOOP; subExprBoxes _ c.class.boxRule[subExprBoxes]; [myBox, subExprBoxes] _ c.class.compBox[subExprBoxes]; myBox _ MathBox.ChangeFormatClass[myBox, c.class.formatClass]; FOR l: LIST OF DisplayExpr _ c.subExprs, l.rest UNTIL l = NIL DO IF l.first.relativeBox.Type # relative THEN ERROR unable[$wrongBoxType]; l.first.relativeBox _ MathBox.GetBox[l.first.tag, subExprBoxes ! MathBox.boxNotFound => {ERROR unable[$boxNotFound]}]; -- set box ENDLOOP; RETURN[myBox]; }; m: MatrixDisplayObj => { elementBoxes, elementBoxesPtr: LIST OF BOX _ NIL; tempBox, spaceBox, openSymBox, closeSymBox: BOX; FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO tempBox _ Format[l.first, MathRules.ComputeSize[base: size, adjustment: script]]; IF elementBoxes = NIL THEN elementBoxes _ elementBoxesPtr _ LIST[ MathBox.MakeBox[l.first.tag, NIL, tempBox.FormatClass[], tempBox.Type[], tempBox.Extents[], tempBox.Offset[], tempBox.SubscriptHint[], tempBox.SuperscriptHint[] ] ] ELSE elementBoxesPtr _ elementBoxesPtr.rest _ LIST[ MathBox.MakeBox[l.first.tag, NIL, tempBox.FormatClass[], tempBox.Type[], tempBox.Extents[], tempBox.Offset[], tempBox.SubscriptHint[], tempBox.SuperscriptHint[] ] ]; ENDLOOP; spaceBox _ Format[m.space, MathRules.ComputeSize[base: size, adjustment: script]]; openSymBox _ Format[m.openSym, normal]; closeSymBox _ Format[m.closeSym, normal]; [myBox, elementBoxes, m.openSym.relativeBox, m.closeSym.relativeBox] _ MathRules.ComposeMatrix[m.nRows, m.nCols, elementBoxes, spaceBox, openSymBox, closeSymBox]; myBox _ MathBox.ChangeFormatClass[myBox, m.class.formatClass]; FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO IF l.first.relativeBox.Type # relative THEN ERROR unable[$wrongBoxType]; l.first.relativeBox _ MathBox.GetBox[l.first.tag, elementBoxes ! MathBox.boxNotFound => {ERROR unable[$boxNotFound]}]; -- set box ENDLOOP; RETURN[myBox]; }; ENDCASE => ERROR; }; Paint: PUBLIC PROC[expr: DisplayExpr, context: Imager.Context, absBox: BOX, selections: LIST OF Selection] ~ { currentDisplayExpr: DisplayExpr; IF absBox.Type # absolute THEN ERROR unable[$wrongBoxType]; expr.absoluteBox _ absBox; WITH expr.expression SELECT FROM a: AtomDisplayObj => { a.class.paintRule[a.value, a.class.style, context, absBox]; }; c: CompoundDisplayObj => { FOR l: LIST OF Argument _ c.class.arguments, l.rest UNTIL l = NIL DO currentDisplayExpr _ GetDisplayExpr[l.first.name, c.subExprs ! exprNotFound => {ERROR unable[$missingArg]}]; Paint[currentDisplayExpr, context, MathBox.RelToAbsBox[currentDisplayExpr.relativeBox, absBox], selections]; ENDLOOP; FOR l: LIST OF Symbol _ c.class.symbols, l.rest UNTIL l = NIL DO currentDisplayExpr _ GetDisplayExpr[l.first.name, c.subExprs ! exprNotFound => {ERROR unable[$missingArg]}]; Paint[currentDisplayExpr, context, MathBox.RelToAbsBox[currentDisplayExpr.relativeBox, absBox], selections]; ENDLOOP; }; m: MatrixDisplayObj => { FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO Paint[l.first, context, MathBox.RelToAbsBox[l.first.relativeBox, absBox], selections]; ENDLOOP; Paint[m.openSym, context, MathBox.RelToAbsBox[m.openSym.relativeBox, absBox], selections]; Paint[m.closeSym, context, MathBox.RelToAbsBox[m.closeSym.relativeBox, absBox], selections]; }; ENDCASE => ERROR; FOR l: LIST OF Selection _ selections, l.rest UNTIL l = NIL DO IF (expr = l.first.expr) THEN { context.SetColor[l.first.color]; Imager.MaskRectangle[context, [x: absBox.Offset[].x - (absBox.Extents[].leftExtent + 1), y: absBox.Offset[].y - (absBox.Extents[].descent + 1), w: absBox.Width[] + 1, h: absBox.Height[] + 2]]; context.SetColor[Imager.black]; }; ENDLOOP; }; GetDisplayExpr: PUBLIC PROC[tag: ATOM, exprs: LIST OF DisplayExpr] RETURNS[DisplayExpr] ~ { FOR l: LIST OF DisplayExpr _ exprs, l.rest UNTIL l = NIL DO IF l.first.tag = tag THEN RETURN[l.first]; ENDLOOP; ERROR exprNotFound; }; DisplayExprFromCoords: PUBLIC PROC[expr: DisplayExpr, x, y: REAL] RETURNS[DisplayExpr] ~ { IF expr = NIL THEN ERROR noSelection; IF ~MathBox.Inside[expr.absoluteBox, x, y] THEN ERROR noSelection; WITH expr.expression SELECT FROM a: AtomDisplayObj => { IF Selectable[expr] THEN RETURN[expr] ELSE ERROR noSelection; }; c: CompoundDisplayObj => { FOR l: LIST OF DisplayExpr _ c.subExprs, l.rest UNTIL l = NIL DO IF MathBox.Inside[l.first.absoluteBox, x, y] THEN RETURN[DisplayExprFromCoords[l.first, x, y ! noSelection => CONTINUE]]; ENDLOOP; IF Selectable[expr] THEN RETURN[expr] ELSE ERROR noSelection; }; m: MatrixDisplayObj => { FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO IF MathBox.Inside[l.first.absoluteBox, x, y] THEN RETURN[DisplayExprFromCoords[l.first, x, y ! noSelection => CONTINUE]]; ENDLOOP; IF Selectable[expr] THEN RETURN[expr] ELSE ERROR noSelection; }; ENDCASE => ERROR; }; Selectable: PUBLIC PROC[expr: DisplayExpr] RETURNS[BOOL] ~ { IF expr = NIL THEN RETURN[FALSE]; WITH expr.expression SELECT FROM a: AtomDisplayObj => { IF a.class.flavor = symbol THEN RETURN[FALSE] ELSE RETURN[TRUE]; }; c: CompoundDisplayObj => RETURN[TRUE]; m: MatrixDisplayObj => RETURN[TRUE]; ENDCASE => ERROR; }; SelectableParent: PUBLIC PROC[expr: DisplayExpr] RETURNS[DisplayExpr] ~ { IF (expr = NIL) OR (expr.parent) = NIL THEN ERROR noSelection; RETURN[expr.parent]; }; SelectableChild: PUBLIC PROC[expr: DisplayExpr] RETURNS[DisplayExpr] ~ { childExpr: DisplayExpr _ NIL; IF expr = NIL THEN ERROR noSelection; WITH expr.expression SELECT FROM a: AtomDisplayObj => ERROR noSelection; -- atom has no children c: CompoundDisplayObj => { FOR l: LIST OF Argument _ c.class.arguments, l.rest UNTIL l = NIL DO childExpr _ GetDisplayExpr[l.first.name, c.subExprs]; IF Selectable[childExpr] THEN RETURN[childExpr]; -- return selected expression ENDLOOP; ERROR noSelection; }; m: MatrixDisplayObj => { ERROR noSelection; }; ENDCASE => ERROR; }; ExtendFunctionSelectSibling: PROC [expr: DisplayExpr] RETURNS [DisplayExpr] ~ { emptyAtom: ATOM _ $expr; -- generic identifier emptyRelBox: BOX _ MathBox.MakeBox[emptyAtom, NIL, other, relative]; emptyAbsBox: BOX _ MathBox.MakeBox[emptyAtom, NIL, other, absolute]; arg12Space: DisplayExpr _ MakeAtomicDisplayExpr[$arg12Space, MathDB.LookupAtomClass[$space], Convert.RopeFromAtom[$medium, FALSE], emptyRelBox, emptyAbsBox]; arg23Space: DisplayExpr _ MakeAtomicDisplayExpr[$arg23Space, MathDB.LookupAtomClass[$space], Convert.RopeFromAtom[$medium, FALSE], emptyRelBox, emptyAbsBox]; arg34Space: DisplayExpr _ MakeAtomicDisplayExpr[$arg34Space, MathDB.LookupAtomClass[$space], Convert.RopeFromAtom[$medium, FALSE], emptyRelBox, emptyAbsBox]; comma12: DisplayExpr _ MakeAtomicDisplayExpr[$comma12, MathDB.LookupAtomClass[$italicSym], XRope.FromChar[',] , emptyRelBox, emptyAbsBox]; comma23: DisplayExpr _ MakeAtomicDisplayExpr[$comma23, MathDB.LookupAtomClass[$italicSym], XRope.FromChar[',] , emptyRelBox, emptyAbsBox]; comma34: DisplayExpr _ MakeAtomicDisplayExpr[$comma34, MathDB.LookupAtomClass[$italicSym], XRope.FromChar[',] , emptyRelBox, emptyAbsBox]; newExprs: LIST OF DisplayExpr; sibling: DisplayExpr _ DisplayExprFromExpr[MathConstructors.MakePlaceHolder[] ]; sibling.parent _ expr.parent; WITH expr.parent.expression SELECT FROM c: CompoundDisplayObj => SELECT c.class.name FROM $nullaryFunction, $unaryFunction, $binaryFunction, $ternaryFunction => { SELECT c.class.name FROM $nullaryFunction => { c.class _ MathDB.LookupCompoundClass[$unaryFunction]; sibling.tag _ $arg1; newExprs _ LIST[sibling] }; $unaryFunction => { c.class _ MathDB.LookupCompoundClass[$binaryFunction]; sibling.tag _ $arg2; newExprs _ LIST[sibling, arg12Space, comma12] }; $binaryFunction => { c.class _ MathDB.LookupCompoundClass[$ternaryFunction]; sibling.tag _ $arg3; newExprs _ LIST[sibling, arg23Space, comma23] }; $ternaryFunction => { c.class _ MathDB.LookupCompoundClass[$quaternaryFunction]; sibling.tag _ $arg4; newExprs _ LIST[sibling, arg34Space, comma34] }; ENDCASE => ERROR; -- can't extend quaternaryFunction IF c.subExprs = NIL THEN c.subExprs _ newExprs ELSE { p: LIST OF DisplayExpr _ c.subExprs; WHILE p.rest#NIL DO p _ p.rest ENDLOOP; p.rest _ newExprs; }; }; ENDCASE => ERROR noSelection; ENDCASE => ERROR noSelection; RETURN[sibling]; }; SelectableSibling: PUBLIC PROC[expr: DisplayExpr] RETURNS[DisplayExpr] ~ { afterExpr: LIST OF Argument _ NIL; -- sibling after expr in parent's subexpr list siblingExpr: DisplayExpr _ NIL; IF (expr = NIL) OR (expr.parent = NIL) THEN ERROR noSelection; WITH expr.parent.expression SELECT FROM a: AtomDisplayObj => ERROR noSelection; c: CompoundDisplayObj => { FOR l: LIST OF Argument _ c.class.arguments, l.rest UNTIL l = NIL DO IF l.first.name = expr.tag THEN {afterExpr _ l.rest; EXIT}; ENDLOOP; FOR l: LIST OF Argument _ afterExpr, l.rest UNTIL l = NIL DO siblingExpr _ GetDisplayExpr[l.first.name, c.subExprs]; IF Selectable[siblingExpr] THEN RETURN[siblingExpr]; -- return selected expression ENDLOOP; SELECT c.class.name FROM $nullaryFunction, $unaryFunction, $binaryFunction, $ternaryFunction => RETURN[ExtendFunctionSelectSibling[expr]]; -- hack ENDCASE; IF c.class.name=$paren THEN RETURN[SelectableSibling[expr.parent] ]; FOR l: LIST OF Argument _ c.class.arguments, l.rest UNTIL l = NIL DO IF l.first.name = expr.tag THEN EXIT; -- already looked thru entire list siblingExpr _ GetDisplayExpr[l.first.name, c.subExprs]; IF Selectable[siblingExpr] THEN RETURN[siblingExpr]; -- return selected expression ENDLOOP; ERROR noSelection; }; m: MatrixDisplayObj => { ERROR noSelection; }; ENDCASE => ERROR; }; Replace: PUBLIC PROC[expr, old, new: DisplayExpr] RETURNS[DisplayExpr] ~ { RETURN[ReplaceN[expr, LIST[[old: old, new: new]]]]; }; ReplaceN: PUBLIC PROC[expr: DisplayExpr, replacements: LIST OF ReplacePair] RETURNS[DisplayExpr] ~ { FOR l: LIST OF ReplacePair _ replacements, l.rest UNTIL l = NIL DO IF expr = l.first.old THEN { parent: DisplayExpr _ l.first.old.parent; new: DisplayExpr _ l.first.new; IF FALSE THEN { parenArgTag: ATOM = $a; argDisplayExpr: DisplayExpr; parenExpr: DisplayExpr _ DisplayExprFromExpr[MathExpr.MakeCompoundExpr[$paren, LIST[[parenArgTag, MathConstructors.MakePlaceHolder[] ]] ] ]; FOR l: LIST OF DisplayExpr _ GetSubExprs[parenExpr], l.rest UNTIL l = NIL DO IF Tag[l.first] = parenArgTag THEN { argDisplayExpr _ l.first; EXIT }; ENDLOOP; parenExpr _ Replace[parenExpr, argDisplayExpr, new]; parenExpr.tag _ l.first.old.tag; -- replacement has same tag (e.g. $integrand, etc.) parenExpr.parent _ parent; -- replacement has same parent as before RETURN[parenExpr] } ELSE { new.tag _ l.first.old.tag; -- replacement has same tag (e.g. $integrand, etc.) new.parent _ parent; -- replacement has same parent as before RETURN[new] }; }; ENDLOOP; WITH expr.expression SELECT FROM a: AtomDisplayObj => { RETURN[Copy[expr]]; }; c: CompoundDisplayObj => { exprCopy: DisplayExpr; -- return value copiedSubExprs: LIST OF DisplayExpr _ NIL; -- cons up new list of copies FOR l: LIST OF DisplayExpr _ c.subExprs, l.rest UNTIL l = NIL DO copiedSubExprs _ CONS[ReplaceN[l.first, replacements], copiedSubExprs]; ENDLOOP; exprCopy _ MakeCompoundDisplayExpr[expr.tag, c.class, copiedSubExprs, expr.relativeBox, expr.absoluteBox]; FOR l: LIST OF DisplayExpr _ copiedSubExprs, l.rest UNTIL l = NIL DO l.first.parent _ exprCopy; -- set parent pointers appropriately ENDLOOP; RETURN[exprCopy]; }; m: MatrixDisplayObj => { exprCopy: DisplayExpr; -- return value copiedElts, copiedEltsPtr: LIST OF DisplayExpr _ NIL; -- cons up a new list of copied elements FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO IF copiedElts = NIL THEN copiedElts _ copiedEltsPtr _ LIST[ReplaceN[l.first, replacements] ] ELSE copiedEltsPtr _ copiedEltsPtr.rest _ LIST[ReplaceN[l.first, replacements] ]; ENDLOOP; exprCopy _ MakeMatrixDisplayExpr[expr.tag, m.class, m.nRows, m.nCols, copiedElts, expr.relativeBox, expr.absoluteBox, Copy[m.openSym], Copy[m.closeSym], Copy[m.space]]; FOR l: LIST OF DisplayExpr _ copiedElts, l.rest UNTIL l = NIL DO l.first.parent _ exprCopy; -- set parent pointers appropriately ENDLOOP; RETURN[exprCopy]; }; ENDCASE => ERROR; }; unable: PUBLIC ERROR[reason: ATOM] = CODE; noSelection: PUBLIC ERROR = CODE; exprNotFound: PUBLIC ERROR = CODE; END. !˜MathDisplayExprImpl.mesa Carl Waldspurger, August 29, 1986 2:58:56 pm PDT Arnon, December 11, 1986 11:23:05 am PST Type Abbreviations from Imported Interfaces Private Type Rep A DisplayExpr is a MUTABLE math expression which is mapped to a viewer. useful type shorthands Display Expression Constructors effects: Constructs and returns a new atomic display expression. effects: Constructs and returns a new compound display expression. effects: Constructs and returns a new matrix display expression. Parse/UnParse Routines effects: Returns a ROPE in selected format recursively copy subexpressions Hack for complexes with negative imaginary part. December 11, 1986 11:24:18 am PST convert boxes into a SEQUENCE (ugh!) matrix type instantiate matrix "a" (isn't CLU's array[]$create() much nicer, really?) add a comma if not last col in row add a comma if not last row in matrix add a comma if not last col in vector add a comma if not last row in vector effects: Constructs and returns a new display expression from expr. All Display formatting information is set to default values. local declarations should really combine passed in style with local atomic style recursively generate displayexprs for all subexpressions (arguments & symbols) generate all argument subexpressions generate all symbol subexpressions construct return value now so can set "parent" component of subexpressions set parents of display subexpressions convert elements from expr to displayexpr FOR l: LIST OF MathExpr.TaggedMathExpr _ elts, l.rest UNTIL l = NIL DO tempDisplayExpr _ DisplayExprFromExpr[l.first.expression]; tempDisplayExpr.tag _ l.first.id; -- set name tag for display expr displayElts _ CONS[tempDisplayExpr, displayElts]; ENDLOOP; convert elements from expr to displayexpr -- changed 3/4/87 construct return value now so can set "parent" component of subexpressions effects: Constructs and returns a new EXPR from expr. 2/87 - amounts to just stripping away the formatting info from the DisplayExpr, i.e. stripping relativeBox, absoluteBox, and parent pointers. local declarations recursively build a list of tagged arg exprs local declarations FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO elts _ CONS[[l.first.tag, ExprFromDisplayExpr[l.first]], elts]; ENDLOOP; effects: Returns a new, distinct copy of expr. local declarations recursively copy subexpressions construct return value now so we can set parent pointers for subexprs local declarations recursively copy elements FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO copiedElts _ CONS[Copy[l.first], copiedElts]; ENDLOOP; recursively copy elements -- changed 3/4/87 construct return value now so we can set parent pointers for subexprs Selectors effects: Returns tag associated with expr. effects: Returns class of expr. effects: Returns subexpressions for expr. Returns NIL if no subexpressions exist Format and Paint modifies: expr effects: expr is updated into a "paintable" form (dsa - perhaps in the sense that all subExprs have been given correct relative bounding boxes) Returns a bounding box for expr. SIGNALS unable[reason: ATOM] if Formatting can not be completed. local declarations recursively format all subexpressions (arguments & symbols) format all argument subexpressions format all symbol subexpressions compute corrected boxes using sizing constraints compose layout for boxes using alignment constraints set format class for mybox set relative boxes of display subexpressions local declarations recursively format all matrix elements FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO tempBox _ Format[l.first, MathRules.ComputeSize[base: size, adjustment: script]]; elementBoxes _ CONS[MathBox.MakeBox[l.first.tag, NIL, tempBox.FormatClass[], tempBox.Type[], tempBox.Extents[], tempBox.Offset[], tempBox.SubscriptHint[], tempBox.SuperscriptHint[]], elementBoxes]; ENDLOOP; recursively format all matrix elements format openSym, closeSym, and space compose layout for matrix by using alignment constraints set format class for mybox set relative boxes of matrix elements requires: absBox is an absolute BOX modifies: expr effects: Displays expr in context, bounded by absBox. Updates absolute bounding boxes (viewer coords). SIGNALS unable[reason: ATOM] if Painting cannot be completed. local declarations update absolute coordinates paint all subexpressions paint arguments paint symbols paint all matrix elements paint open & close symbols if selected, highlight region appropriately, using a one pixel border set proper color depending on selection highlight region reset color to black List Operations effects: Returns the DisplayExpr in exprs associated with tag. SIGNALS exprNotFound if no association exists. cdr down list looking for tag not found, so signal error Selection Operations effects: Returns the subexpression associated with coordinates [x, y] in expression expr. SIGNALS noSelection if no association exists. see if selection can be further narrowed if above loop does not return, then can't narrow selection any more see if selection can be further narrowed if above loop does not return, then can't narrow selection any more effects: Returns TRUE iff expr is selectable. effects: Returns the parent (enclosing expression) of expr. SIGNALS noParent if no selectable parent exists. complain if no expr or no parent effects: Returns a child expressions (subexpression) for expr. SIGNALS noSelection if no selectable child exists. local declarations keep looking for selectable child if there are no selectable children, signal noSelection ** FOO FIX THIS ** Hack 7/10/87: Assuming expr is the last arg of a function, change its parent to be larger function class and select the new last arg. effects: Returns the "next" sibling expression from expr. SIGNALS noSelection if no selectable sibling exists. local declarations "cycle" thru parent's children and return "next" selectable sibling in list find starting point to begin looking for next selectable sibling expr look for next selectable sibling in exprs after expr in list (i.e. in afterExpr) *** hack 7/16/87 to handle extra inserted parentheses *** end hack if no selectable sibling exists after expr, then wraparound list to before expr if we haven't RETURNed yet, then there are no selectable siblings ** FOO FIX THIS ** effects: Returns a copy of display expression expr with new substituted for old. caveats: Return value must be reformatted before Paint[]'ing. Note that new is used (not a copy). Hence if expr = old, then new returned, i.e. a "copy" returned iff old is a proper subexpression of expr. effects: Returns a copy of display expression expr with new substituted for old for each pair in replacements [old, new]. If expr = old_i, then new_i i.e. a "copy" returned iff each old_i is a proper subexpression of expr. Note that replacements can "interfere" with each other; outcome depends on their ordering. caveats: Return value must be reformatted before Paint[]'ing. Note that "old" components of replace pairs must be the actual pointers to the exprs we wish to replace, i.e. we only replace that actual expr, and not any other expr which is equivalent but physically distinct from it. Note that the "new" components of replace pairs are used (not copies). Hence anyone who holds the pointer to a "new" component can e.g. later ask to have it replaced by something. Note that recursion terminates as soon as we find a match, i.e. if expr = one of the olds (i.e. expr is one of the things to be replaced), we won't examine any subexprs of expr for possible additional matches Parenthesize replacement if its op has lower precedence than parent IF parent #NIL AND MathDB.CompareOps[Class[new], Class[parent] ] = less THEN { -- 7/10/87 -- turn off op precedence for functional notation parsing Create skeleton for parenthesized expression (i.e. dummy arg) Grab onto dummy arg Stuff actual pointer to new into parenExpr Update pointers new.tag _ $a; new.parent _ parenExpr; local declarations recursively copy subexpressions construct return value now so we can set parent pointers for subexprs local declarations recursively copy elements FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO copiedElts _ CONS[ReplaceN[l.first, replacements], copiedElts]; ENDLOOP; recursively copy elements - changed 3/4/87 construct return value now so we can set parent pointers for subexprs Signals & Errors Ê!ˆ˜Jšœ™Jšœ0™0Jšœ(™(J˜šÏk ˜ J˜J˜ J˜J˜J˜J˜ Jšœ ˜ Jšœœ˜Jšœœœ˜.Jšœœ+˜7Jšœ˜—J˜šÏnœœ˜"JšœU˜\Jšœ˜J˜Jš˜J˜—headšž+™+J™Jšœœœ˜Jšœœ œ˜Jšœœ œ˜Jšœ œ˜#Jšœœ˜+Jšœ œ˜'Jšœœ˜Jšœ œ˜#Jšœœ˜Jšœ œ˜%Jšœ œ˜'Jšœœ˜-Jšœ œ˜)J˜Jšœœ˜Jšœ œ˜,Jšœ œ˜0J˜—šž™JšœG™GIcode˜šœœœ˜šœ˜LšœœÏc%˜1LšœŸ!˜:Lšœ œŸ!˜4Lšœ œŸ!˜4LšœœœŸA˜WLšœœŸ˜9L˜—L˜—Lšœ œœ˜'šœœœ˜šœ˜Lšœ"œ˜(Lšœ-œœœ˜Hšœ ˜ LšœŸ<˜QLšœœŸ˜/Lšœ œœœŸ˜8LšœŸ˜%LšœŸ˜'LšœŸ˜+Lšœ˜—Lš˜—L˜L˜—Lšœ™Lšœœœ˜-Lšœœ˜-Lšœœœ˜5Lšœœ˜5Lšœœœ˜1Lšœœ˜1L˜Lšœ œœŸ˜G—šž™šžœœœœœœœœ˜–LšœA™ALšœœcœ<˜¬L˜L˜—šžœœœœ"œœœœœ˜­LšœC™CLšœœcœJ˜ºL˜L˜—šžœœœœ$œ œœœ?œœ˜äLšœA™ALšœœcœ–˜†L˜L˜——šž™š žœœœœœœ˜[Lšœ+™+L™šœœ˜ L˜šœœ˜'Lš œ œœœœ!œœ ˜kLš œœœœœœœ ˜bLšœœœœœœœ ˜c—L˜˜šœ œœ˜#LšœŸ˜;LšœŸ˜5LšœŸ˜7—Lšœ œœ˜Lšœ œ˜Lšœœœ˜-L˜Lšœ™š œœœ&œœ˜DL˜-L˜(Lšœœ¥˜ºLšœ˜ —L˜LšœR™Ršœœ˜!L˜&LšœœN˜cL˜L˜—Lšœ ˜L˜—L˜šœ˜šœ œœ˜Lšœ˜L˜—Lšœœœ˜šœœœ˜Lšœ œœœ˜/L˜—Lšœœœ ˜šœ œœ˜Lšœœœœ˜'L˜—L˜L˜ Lšœœ˜LšœœœŸ˜$L˜Lšœ0™0LšœBÏzœ™JLšœœ˜šœœœ˜Lšœ œ˜Lšœ˜—š œœœ"œœ˜@L˜AL˜1Lšœ˜L˜—šœ˜˜ Lšœ˜šœœœ˜Lšœ&Ÿ˜7šœœœ˜L˜?Lšœ"™"Lšœœ#Ÿ˜LLšœ˜—Lšœ"Ÿ˜1Lšœ%™%Lšœœ#Ÿ˜LLšœ˜—Lšœ"Ÿ˜=L˜—˜%LšœŸ%˜8šœ œŸ ˜#šœœœ˜L˜?Lšœ%™%Lšœœ#Ÿ˜LLšœ˜—L˜—šœŸ˜šœœœ˜L˜?Lšœ%™%Lšœœ#Ÿ˜LLšœ˜—L˜—Lšœ!˜!L˜—Lšœ!˜(—Lšœ ˜L˜—Lšœœ˜L˜—˜L˜—L˜—š žœœœœœ˜ELšœD™DL™FL™Lšœ™L˜,L˜Lšœ œ Ÿ˜/Lšœ œœ˜DLšœ œœ˜DL˜šœ˜L˜šœ ˜ Lšœ!˜!L˜Lšœ=™=Lšœm˜sL˜L˜—šœ ˜ L˜Lšœ)˜)L˜8LšœN™NL˜LšœœœœŸ'˜TL˜Lšœ$™$š œœœ(œœ˜FLšœvœ#˜žLšœ%Ÿ ˜ELšœœ#˜9Lšœ˜—L˜Lšœ"™"š œœœ$œœ˜BLšœvœ#˜žLšœ%Ÿ ˜ELšœœ#˜9Lšœ˜—L˜L™LšœJ™JLšœ|˜|L˜Lšœ%™%š œœœ'œœ˜ELšœ!Ÿ˜/Lšœ˜—L˜Lšœ˜L˜—˜ L˜L˜%Lšœœœ9˜FL˜0Lšœ!œœœ˜;Lšœœ˜L˜&L˜L˜+L˜Lšœ)™)š œœœ(œœ™FLšœ:™:Lšœ"Ÿ ™BLšœœ™1Lšœ™L™—Lšœ;™;š œœœ(œœ˜FLšœ:˜:Lšœ"Ÿ ˜BLš œœœ$œœ0œ˜Lšœ˜—L˜L˜-L˜/˜)L˜—LšœJ™JL˜‡L˜š œœœ#œœ˜ALšœ Ÿ ˜-Lšœ˜—L˜Lšœ˜L˜—Lšœœ˜—L™L˜L˜—š žœœœœœ˜ELšœ6™6Lšœ™L™šœœ˜ L˜˜Lšœ1˜7L˜—L˜˜Lšœ™Lšœœœœ˜,L˜Lšœ,™,š œœœ"œœ˜@Lšœœ4˜?Lšœ˜—L˜Lšœ0˜6L˜—L˜˜Lšœ™Lšœœœœ˜9L˜š œœœ"œœ™@Lšœœ4™?Lšœ™L™—š œœœ"œœœŸ˜RLšœV˜VLš œœœœœ"œ˜xLšœ˜—L˜Lšœ@˜FL˜—L˜Lšœœ˜—˜L˜—L˜L˜—šžœœœœ˜=Lšœ/™/šœœ˜ L˜šœ˜LšœX˜^L˜—L˜L˜˜Lšœ™LšœŸ˜'LšœœœœŸ˜IL˜Lšœ™š œœœ"œœ˜@Lšœœ ˜5Lšœ˜ L˜—LšœE™ELšœj˜jš œœœ&œœ˜DLšœŸ$˜@Lšœ˜—L˜Lšœ ˜L˜—L˜˜L˜Lšœ™LšœŸ˜&LšœœœœŸ(˜_L˜Lšœ™š œœœ"œœ™@Lšœ œ™-Lšœ™L˜—Lšœ+™+š œœœ"œœ˜@Lš œœœœœ&œ˜ŠLšœ˜—L˜LšœE™ELšœ¨˜¨š œœœ"œœ˜@LšœŸ$˜@Lšœ˜—L˜Lšœ ˜L˜L™L˜—Lšœœ˜—L˜——šž ™ š žœœœœœ˜5Lšœ+™+Lšœ ˜L˜L˜—š žœœœœœ˜7Lšœ ™ šœœ˜ Lšœœ˜*Lšœœ˜.Lšœœ˜,Lšœœ˜—L˜L˜—š ž œœœœœœ˜LLšœ*™*Lšœ0™0L™šœœ˜ LšœœœŸ ˜CLšœœ ˜,Lšœœ ˜*Lšœœ˜—L˜——šž™š žœœœ œœ˜CLšœ™Lšœ™Lšœ*™*LšœJ™JL™Lšœ™Lšœœœœ˜Lšœœ˜L˜šœœ˜ L˜šœ˜Lšœ;œ…˜ÉL˜L˜—L˜šœ˜L˜Lšœ;™;L˜LšœœŸ&˜;L˜Lšœ"™"š œœœ&œœ˜DLšœLœU˜¦Lšœœ¿˜ÒLšœ˜—L˜Lšœ ™ š œœœ"œœ˜@LšœLœU˜¦Lšœœ¿˜ÒLšœ˜—L˜Lšœ0™0L˜-L˜Lšœ4™4L˜6Lšœ™L˜>L˜Lšœ,™,š œœœ"œœ˜@Lšœ%œœ˜HLšœYœŸ ˜‚Lšœ˜—L˜Lšœ˜L˜—L˜˜Lšœ™Lš œœœœœ˜1Lšœ,œ˜0L˜Lšœ&™&š œœœ"œœ™@LšœQ™QLšœœœ‘™ÅLšœ™L˜—Lšœ&™&š œœœ"œœ˜@LšœQ˜Qšœœ˜Lšœ!œœ„˜Ë—š˜Lšœ)œœ…˜Ô—Lšœ˜—L˜Lšœ#™#L˜RL˜'L˜)L˜Lšœ8™8L˜¢Lšœ™L˜>L˜Lšœ%™%š œœœ"œœ˜@Lšœ%œœ˜HLšœYœŸ ˜‚Lšœ˜—L˜Lšœ˜L˜L˜—L˜Lšœœ˜—L™L˜L˜—š žœœœ5œœœ˜oLšœ#™#Lšœ™Lšœ6™6Lšœ:™:LšœG™GL™Lšœ™L˜ L™Lšœ™Lšœœœ˜;L˜L˜šœœ˜ L˜˜L˜;L˜—L˜˜L˜Lšœ™L™Lšœ™š œœœ&œœ˜DLšœPœ˜lLšœl˜lLšœ˜L˜—Lšœ ™ š œœœ"œœ˜@LšœPœ˜lLšœl˜lLšœ˜—L˜—L˜L˜˜Lšœ™š œœœ"œœ˜@LšœV˜VLšœ˜L˜—Lšœ™LšœZ˜ZLšœ\˜\L˜—L˜Lšœœ˜L˜—LšœE™Eš œœœ œœ˜>šœœ˜Lšœ'™'L˜ L˜Lšœ™L˜ÀL˜Lšœ™L˜L˜—Lšœ˜—L˜L˜——šž™šžœœœœ œœœ˜[Lšœ>™>Lšœ7™7L˜Lšœ™š œœœœœ˜;Lšœœœ ˜*Lšœ˜—L˜Lšœ™Lšœ˜L˜——šž™š žœœœœœ˜ZLšœ\™\L™7L™Lšœœœœ ˜%Lšœ)œœ ˜BL˜šœœ˜ L˜šœ˜Lš œœœœœ ˜=L˜L˜—˜Lšœ(™(š œœœ"œœ˜@šœ+˜1Lšœ6œ˜G—Lšœ˜—L˜LšœC™CLš œœœœœ˜?L˜—L˜˜Lšœ(™(š œœœ"œœ˜@šœ+˜1Lšœ6œ˜G—Lšœ˜—L˜LšœC™CLš œœœœœ˜?L˜—L˜Lšœœ˜—L˜˜L˜——š ž œœœœœ˜™>L™Lšœ™Lšœ œœ œŸ.˜RLšœœ˜L˜Lš œ œœœœœ ˜>L˜LšœK™Kšœœ˜'Lšœœ ˜'˜Lšœ) œ™Eš œœœ&œœ˜DLšœœœ˜;Lšœ˜—Lšœ* œ!™Pš œœœœœ˜