DIRECTORY IntCodeDefs, IntCodeStuff, IntCodeUtils, C2CBasics, C2CIntCodeUtils, C2CPreprocessing, C2CTarget, Rope; C2CPreprocessingImpl: CEDAR PROGRAM IMPORTS C2CBasics, IntCodeStuff, C2CIntCodeUtils, IntCodeUtils EXPORTS C2CPreprocessing = BEGIN OPEN IntCodeDefs; debugDontChangeIntCode: BOOL ¬ FALSE; -- while debugging plain generation we might want to make sure that the int code tree is correct z: ZONE ¬ IntCodeUtils.zone; defaultFlags: VariableFlags ~ DefaultFlags[]; DefaultFlags: PROC [] RETURNS [dummyParameterFlags: VariableFlags] = { dummyParameterFlags[used] ¬ TRUE; dummyParameterFlags[constant] ¬ FALSE; dummyParameterFlags[addressed] ¬ TRUE; dummyParameterFlags[upLevel] ¬ FALSE; dummyParameterFlags[notRegister] ¬ TRUE; dummyParameterFlags[named] ¬ FALSE; }; dummyParameterFlags: VariableFlags ~ DummyParameterFlags[]; DummyParameterFlags: PROC [] RETURNS [dummyParameterFlags: VariableFlags] = { dummyParameterFlags[used] ¬ TRUE; dummyParameterFlags[constant] ¬ TRUE; dummyParameterFlags[addressed] ¬ FALSE; dummyParameterFlags[upLevel] ¬ FALSE; dummyParameterFlags[notRegister] ¬ TRUE; dummyParameterFlags[named] ¬ FALSE; }; addition: Node ¬ IntCodeStuff.GenOperNode[operRep: [arith[class: [unsigned, FALSE, C2CTarget.bitsPerWord], select: add]], bits: C2CTarget.bitsPerWord]; multiplication: Node ¬ IntCodeStuff.GenOperNode[operRep: [arith[class: [unsigned, FALSE, C2CTarget.bitsPerWord], select: mul]], bits: C2CTarget.bitsPerWord]; AppendNode: PROC [nodes: NodeList, node: Node] RETURNS [NodeList] = { IF node=NIL THEN RETURN [nodes]; IF nodes=NIL THEN RETURN [IntCodeUtils.NodeListCons[first: node]]; FOR nl: NodeList ¬ nodes, nl.rest DO IF nl.rest=NIL THEN {nl.rest ¬ IntCodeUtils.NodeListCons[first: node]; RETURN [nodes]} ENDLOOP; }; GenNullSource: PROC [nodes: NodeList, bits: INT ¬ 0] RETURNS [SourceNode] = { RETURN [z.NEW[NodeRep.source ¬ [bits, source[nullSourceRange, nodes]]]]; }; HasFreeDecl: PROC [node: Node] RETURNS [has: BOOL ¬ FALSE] = { Inner: IntCodeUtils.Visitor = { WITH node SELECT FROM block: BlockNode => RETURN [node]; --stop recursion decl: DeclNode => {has ¬ TRUE; RETURN [node]}; ENDCASE => {}; IntCodeUtils.MapNode[node, Inner]; RETURN [node] }; [] ¬ Inner[node]; }; GenWordConst: PROC [val: Word, bits: INT] RETURNS [ConstNode] = { RETURN [ IntCodeStuff.GenConst[int: IntCodeUtils.WordToInt[val], bits: bits] ]; }; GenLocalLocation: PROC [id: VariableId, parent: Label ¬ NIL] RETURNS [loc: Location] = { loc ¬ z.NEW[LocationRep.localVar ¬ [localVar[id: id, parent: parent]]]; }; GenIndexedLocation: PROC [base: Node, index: Node] RETURNS [loc: IndexedLocation] = { loc ¬ z.NEW[LocationRep.indexed ¬ [indexed[base: base, index: index]]]; }; ProcDescMayRaiseErrors: PROC [applyNode: ApplyNode] RETURNS [BOOL] = { WITH applyNode.proc SELECT FROM oper: OperNode => RETURN [FALSE]; mc: MachineCodeNode => RETURN [FALSE]; ENDCASE => RETURN [~IntCodeUtils.SideEffectFree[applyNode.proc, TRUE]]; }; ArgsMayRaiseErrors: PROC [applyNode: ApplyNode] RETURNS [BOOL] = { RETURN [~IntCodeUtils.SideEffectFreeList[applyNode.args, TRUE]] }; ConsideredConstant: PROC [node: Node] RETURNS [isConst: BOOL ¬ TRUE] = { isConst ¬ WITH node SELECT FROM var: Var => var.flags[constant], const: ConstNode => TRUE, decl: DeclNode => ConsideredConstant[decl.var] AND IntCodeUtils.SideEffectFree[decl.init, TRUE], comment: CommentNode => TRUE, ENDCASE => FALSE; }; MoveFrontParametersWhichMayRaiseErrors: PROC [node: Node] = { DoIt: PROC [outer: Node, parent: Label] = { Inner: IntCodeUtils.Visitor = { DoIt[node, parent]; WITH node SELECT FROM applyNode: ApplyNode => { IF applyNode.handler#NIL THEN { descDanger: BOOL ¬ ProcDescMayRaiseErrors[applyNode: applyNode]; argDanger: BOOL ¬ ArgsMayRaiseErrors[applyNode: applyNode]; blockNodes: NodeList ¬ NIL; Move: PROC [node: Node] RETURNS [substitute: Var] = { GenLocalVariable: PROC [parent: Label, bits: INT, flags: VariableFlags ¬ defaultFlags] RETURNS [var: Var] = { id: VariableId ¬ C2CIntCodeUtils.NewVariableId[]; loc: Location ¬ GenLocalLocation[id, parent]; var ¬ IntCodeStuff.GenAnonVar[bits, loc]; var.id ¬ id; var.flags ¬ flags; }; var: Var ¬ GenLocalVariable[parent, node.bits, dummyParameterFlags]; declNode: Node ¬ IntCodeStuff.GenDecl[var: var, init: node]; blockNodes ¬ AppendNode[blockNodes, declNode]; RETURN [var]; }; IF descDanger THEN { substitute: Var ¬ Move[applyNode.proc]; applyNode.proc ¬ substitute; }; IF argDanger THEN { FOR args: NodeList ¬ applyNode.args, args.rest WHILE args#NIL DO IF ~ConsideredConstant[args.first] THEN { substitute: Var ¬ Move[args.first]; args.first ¬ substitute; } ENDLOOP; }; IF blockNodes#NIL THEN { blockNodes ¬ AppendNode[blockNodes, applyNode]; IF HasFreeDecl[applyNode] THEN RETURN [GenNullSource[nodes: blockNodes, bits: applyNode.bits]] ELSE RETURN [IntCodeStuff.GenBlock[nodes: blockNodes, bits: applyNode.bits]]; }; }; }; ENDCASE => {}; RETURN [node]; }; WITH outer SELECT FROM labelNode: LabelNode => WITH labelNode.label.node SELECT FROM labeledLambda: LambdaNode => parent ¬ labelNode.label; ENDCASE => {}; ENDCASE => {}; IntCodeUtils.MapNode[outer, Inner]; }; IF debugDontChangeIntCode THEN RETURN; IF ISTYPE[node, ApplyNode] THEN ERROR; --recursion starts wrong DoIt[node, NIL]; }; EliminateSideEffectsOfErrors: PUBLIC PROC [] = { CleanupFields[]; CleanupLabels[]; MoveFrontParametersWhichMayRaiseErrors[C2CBasics.rootNode]; C2CBasics.Report[]; }; CleanupLabels: PROC [] = { usedlabels: IntCodeUtils.IdTab ¬ IntCodeUtils.NewIdTab[]; FindGotos: IntCodeUtils.Visitor = { WITH node SELECT FROM goto: GotoNode => [] ¬ IntCodeUtils.Store[usedlabels, goto.dest.id, $used]; oper: OperNode => WITH oper.oper SELECT FROM codeOp: CodeOper => [] ¬ IntCodeUtils.Store[usedlabels, codeOp.label.id, $used]; ENDCASE => {}; ENDCASE => {}; IntCodeUtils.MapNode[node, FindGotos]; RETURN [node]; }; VisitLambdas: IntCodeUtils.Visitor = { WITH node SELECT FROM lambda: LambdaNode => { IntCodeUtils.MapNode[node, VisitLabels]; RETURN [node]; --dont recurse }; ENDCASE => {}; IntCodeUtils.MapNode[node, VisitLambdas]; RETURN [node]; }; VisitLabels: IntCodeUtils.Visitor = { WITH node SELECT FROM label: LabelNode => { IF label.label.id#nullLogicalId AND IntCodeUtils.Fetch[usedlabels, label.label.id]=IntCodeUtils.NullValue THEN { label.label.id ¬ nullLogicalId }; }; ENDCASE => {}; IntCodeUtils.MapNode[node, VisitLabels]; RETURN [node]; }; [] ¬ FindGotos[C2CBasics.rootNode]; [] ¬ VisitLambdas[C2CBasics.rootNode]; }; MaskOut: PROC [use: Word, from, bits: INT] RETURNS [Word] = { ShiftRight: PROC [use: Word, bits: INT] RETURNS [Word] = { IF bits#0 THEN { FOR b: INT DECREASING IN [bits..IntCodeDefs.bitsPerWord) DO use[b] ¬ use[b-bits] ENDLOOP; }; RETURN [use]; }; RestrictTo: PROC [use: Word, bits: INT] RETURNS [Word] = { FOR b: INT IN [0..IntCodeDefs.bitsPerWord-bits) DO use[b] ¬ FALSE; ENDLOOP; RETURN [use]; }; use ¬ ShiftRight[use, C2CTarget.bitsPerWord-(from+bits)]; RETURN [RestrictTo[use, bits]]; }; HasLeftBitSet: PROC [limWord: Word, leftBits: INT] RETURNS [BOOL ¬ FALSE] = { FOR b: INT IN [0..leftBits+IntCodeDefs.bitsPerWord-C2CTarget.bitsPerWord) DO IF limWord[b] THEN RETURN [TRUE]; ENDLOOP }; SimplifyBoundsChecks: PROC [oBckApply: ApplyNode] RETURNS [replaceBy: Node] = { replaceBy ¬ oBckApply; IF oBckApply.handler=NIL THEN { oBCkSimple: BOOL; oBCkLimit: CARD; [oBCkSimple, oBCkLimit] ¬ C2CIntCodeUtils.IsSimpleConst[--limit--oBckApply.args.rest.first]; IF oBCkSimple THEN { oArgument: Node ¬ oBckApply.args.first; WITH oArgument SELECT FROM nApply: ApplyNode => IF nApply.handler=NIL THEN { WITH nApply.proc SELECT FROM nOper: OperNode => { WITH nOper.oper SELECT FROM nCheckOp: CheckOper => { IF CheckOpSimple[nCheckOp] THEN { nBCkSimple: BOOL; nBCkLimit: CARD; [nBCkSimple, nBCkLimit] ¬ C2CIntCodeUtils.IsSimpleConst[--limit--nApply.args.rest.first]; IF nBCkSimple THEN { IF oBCkLimit<=nBCkLimit THEN {oBckApply.args.first ¬ nApply.args.first} ELSE {replaceBy ¬ nApply} }; }; }; nArithOp: ArithOper => { --precision ok without test IF nArithOp.class.kind=unsigned AND nArithOp.select=sub THEN { WITH nApply.args.first --base of sub-- SELECT FROM bApply: ApplyNode => IF bApply.handler=NIL THEN { WITH bApply.proc SELECT FROM bOper: OperNode => WITH bOper.oper SELECT FROM bCheckOp: CheckOper => { IF CheckOpSimple[bCheckOp] THEN { nBCkSimple: BOOL; nBCkLimit: CARD; [nBCkSimple, nBCkLimit] ¬ C2CIntCodeUtils.IsSimpleConst[--limit--bApply.args.rest.first]; IF nBCkSimple THEN { subSimple: BOOL; subVal: CARD; [subSimple, subVal] ¬ C2CIntCodeUtils.IsSimpleConst[--sub--nApply.args.rest.first]; IF nBCkSimple AND subSimple AND oBCkLimit<=nBCkLimit AND CARD[nBCkLimit-oBCkLimit]>=subVal THEN { nApply.args.first --base of sub-- ¬ bApply.args.first }; }; }; }; ENDCASE --bOper.oper-- => {}; ENDCASE --bApply.proc-- => {}; }; ENDCASE --nApply.args.first-- => {}; }; }; ENDCASE --nOper.oper-- => {}; }; ENDCASE --nApply.proc-- => {}; }; ENDCASE --oArgument-- => {}; }; }; }; CheckOpSimple: PROC [checkOp: CheckOper] RETURNS [BOOL] = { RETURN [checkOp.sense=lt AND checkOp.class.kind=unsigned AND checkOp.class.precision<=C2CTarget.bitsPerWord] }; CleanupFields: PROC [] = { largestDummy: INT ¬ 0; idsForPtrTab: IntCodeUtils.IdTab ¬ IntCodeUtils.NewIdTab[]; lhs: BOOL ¬ FALSE; --used as hint only FindFields: IntCodeUtils.Visitor = { oldLhs: BOOL ¬ lhs; --set on every RETURN WITH node SELECT FROM apply: ApplyNode => { WITH apply.proc SELECT FROM oper: OperNode => WITH oper.oper SELECT FROM checkOp: CheckOper => { IF CheckOpSimple[checkOp] THEN node ¬ SimplifyBoundsChecks[apply] }; arithOp: ArithOper => { IF arithOp.class.kind=unsigned AND arithOp.class.precision=BITS[CARD] AND apply.args#NIL AND apply.args.rest#NIL THEN { arg1: Node ¬ apply.args.first; arg2: Node ¬ apply.args.rest.first; WITH arg1 SELECT FROM carg1: IntCodeDefs.WordConstNode => { WITH arg2 SELECT FROM carg2: IntCodeDefs.WordConstNode => { fold: BOOL ¬ FALSE; value: CARD; c1: CARD ¬ IntCodeUtils.WordToCard[carg1.word]; c2: CARD ¬ IntCodeUtils.WordToCard[carg2.word]; SELECT arithOp.select FROM add => {value ¬ c1+c2; fold ¬ TRUE}; sub => {value ¬ c1-c2; fold ¬ TRUE}; mul => {value ¬ c1*c2; fold ¬ TRUE}; div => IF c2#0 THEN {value ¬ c1/c2; fold ¬ TRUE}; mod => IF c2#0 THEN {value ¬ c1 MOD c2; fold ¬ TRUE}; ENDCASE; IF fold THEN node ¬ IntCodeStuff.GenConst[LOOPHOLE[value], C2CTarget.bitsPerWord]; }; ENDCASE; }; ENDCASE; }; }; convert: ConvertOper => IF convert.from.precision=0 AND apply.args.first.bits=0 AND convert.to.precision>0 THEN { WITH apply.args.first SELECT FROM apply2: ApplyNode => WITH apply2.proc SELECT FROM oper2: OperNode => WITH oper2.oper SELECT FROM mesa2: MesaOper => SELECT mesa2.mesa FROM error => { apply2.bits ¬ 1; convert.from.precision ¬ 1; }; ENDCASE => {--?--}; ENDCASE => {--?--}; ENDCASE => {--?--}; ENDCASE => {--?--}; }; ENDCASE => {}; ENDCASE => {}; }; var: Var => { IF var.flags[frequent] THEN { IF var.bits#C2CTarget.bitsPerWord THEN var.flags[frequent] ¬ FALSE; IF var.flags[addressed] THEN var.flags[frequent] ¬ FALSE; IF var.flags[notRegister] THEN var.flags[frequent] ¬ FALSE; IF var.flags[upLevel] THEN var.flags[frequent] ¬ FALSE; IF var.flags[frequent] THEN [] ¬ IntCodeUtils.Store[idsForPtrTab, var.id, $yes]; --provisionally }; WITH var.location SELECT FROM field: FieldLocation => { IF var.bits>0 AND field.base.bits<=C2CTarget.bitsPerWord THEN { WITH field.base SELECT FROM var: Var => var.flags[frequent] ¬ FALSE; --some code to take fields uses the address const: ConstNode => WITH const SELECT FROM wordConst: WordConstNode => { replacementNode: Node ¬ GenWordConst[MaskOut[wordConst.word, field.start, var.bits], var.bits]; lhs ¬ oldLhs; RETURN [replacementNode]; --instead of field-var! }; ENDCASE => {}; apply: ApplyNode => WITH apply.proc SELECT FROM oper: OperNode => WITH oper.oper SELECT FROM checkOp: CheckOper => { IF checkOp.sense=lt AND field.start+var.bits=C2CTarget.bitsPerWord THEN { isConst: BOOL; p: INT ¬0; limWord: Word; constVal: CARD ¬ 0; limit: Node ¬ apply.args.rest.first; [isConst, constVal] ¬ C2CIntCodeUtils.IsSimpleConst[limit]; IF isConst AND constVal>0 THEN { limWord ¬ IntCodeUtils.CardToWord[constVal-1]; IF ~HasLeftBitSet[limWord, field.start] THEN { replacementNode: Node ¬ z.NEW[apply NodeRep ¬ apply­]; replacementNode.bits ¬ var.bits; lhs ¬ oldLhs; RETURN [replacementNode]; --instead of field-var! }; }; }; }; ENDCASE => {}; ENDCASE => {}; ENDCASE => {}; }; }; indexed: IndexedLocation => { IF var.bits WITH bvar.location SELECT FROM bindexed: IndexedLocation => IF bvar.bits IF bfield.start MOD C2CTarget.bitsPerWord # 0 THEN { IF bfield.start MOD var.bits = 0 THEN { doReplace: BOOL ¬ FALSE; IF bfield.base.bits<=C2CTarget.bitsPerWord AND C2CIntCodeUtils.SizeIsProvableOk[bfield.base] THEN { doReplace ¬ TRUE; }; IF doReplace THEN { offset: Node ¬ IntCodeStuff.GenConst[bfield.start/var.bits, C2CTarget.bitsPerWord]; summands: NodeList ¬ IntCodeStuff.NodeListCons2[indexed.index, offset]; newIndex: ApplyNode ¬ IntCodeStuff.GenApply[addition, summands, C2CTarget.bitsPerWord]; newLocation: Location ¬ GenIndexedLocation[base: bfield.base, index: newIndex]; var.location ¬ newLocation; lhs ¬ oldLhs; RETURN [FindFields[node]]; --recurse on same node }; }; }; ENDCASE => {}; ENDCASE => {} }; indexed.base ¬ FindFields[indexed.base]; lhs ¬ FALSE; indexed.index ¬ FindFields[indexed.index]; lhs ¬ oldLhs; RETURN [node]; }; dummy: DummyLocation => largestDummy ¬ MAX[largestDummy, var.bits]; deref: DerefLocation => { lhs ¬ FALSE; deref.addr ¬ FindFields[deref.addr]; lhs ¬ oldLhs; RETURN [node]; }; ENDCASE => {}; }; assign: AssignNode => { lhs ¬ TRUE; assign.lhs ¬ NARROW[FindFields[assign.lhs]]; lhs ¬ FALSE; assign.rhs ¬ FindFields[assign.rhs]; lhs ¬ oldLhs; RETURN [node]; }; ENDCASE => {}; IntCodeUtils.MapNode[node, FindFields]; lhs ¬ oldLhs; RETURN [node]; }; EliminateVar: PROC [var: Var] = { IF var.flags[frequent] AND var.bits=C2CTarget.bitsPerWord THEN [] ¬ IntCodeUtils.Store[idsForPtrTab, var.id, NIL]; }; EliminatePointerUsage: IntCodeUtils.Visitor = { WITH node SELECT FROM var: Var => { EliminateVar[var]; WITH var.location SELECT FROM deref: DerefLocation => { IntCodeUtils.MapNode[deref.addr, EliminatePointerUsage]; RETURN [node]; }; ENDCASE => {}; }; decl: DeclNode => { [] ¬ EliminatePointerUsage[decl.init]; WITH decl.init SELECT FROM oper: OperNode => WITH oper.oper SELECT FROM mesa: MesaOper => SELECT mesa.mesa FROM globalFrame => {}; --that is ok usage ENDCASE => EliminateVar[decl.var]; ENDCASE => EliminateVar[decl.var]; ENDCASE => IF decl.init#NIL THEN EliminateVar[decl.var]; RETURN [node]; --avoids direct visit of var }; ENDCASE => {}; IntCodeUtils.MapNode[node, EliminatePointerUsage]; RETURN [node]; }; C2CBasics.PutProp[$MayBeDeclaredAsPtrTab, idsForPtrTab]; C2CBasics.PutProp[$LargestDummy, NEW[INT ¬ largestDummy]]; [] ¬ FindFields[C2CBasics.rootNode]; [] ¬ EliminatePointerUsage[C2CBasics.rootNode]; }; MayBeDeclaredAsPtr: PUBLIC PROC [var: IntCodeDefs.Var] RETURNS [BOOL ¬ FALSE] = { IF var.bits#C2CTarget.bitsPerWord THEN RETURN [FALSE]; IF ~var.flags[frequent] THEN RETURN [FALSE]; WITH C2CBasics.GetProp[$MayBeDeclaredAsPtrTab] SELECT FROM tab: IntCodeUtils.IdTab => RETURN [IntCodeUtils.Fetch[tab, var.id]=$yes] ENDCASE => RETURN [FALSE]; }; END. ΰ C2CPreprocessingImpl.mesa Copyright Σ 1987, 1988, 1989, 1990, 1991 by Xerox Corporation. All rights reserved. Christian Jacobi, 1987 Christian Jacobi, January 27, 1993 6:19 pm PST Willie-s, March 26, 1991 1:15 pm PST --returns whether node has declarations not inside local blocks --this does NOT tell whether the procedure raises errors, but, --whether finding the procedure descriptor may raise errors --side effect: changes blockNode (also uses C2CIntCodeUtils.NewVariableId, parent) --generates new variable, but not yet declared --constancy required, not error-freeness (evaluation order!) --DoIt --don't clobber IntCode tree while debugging other parts --check to make sure the recursion starts right at this point --for each lambda call VisitLabels --and replace id of unused labels --returns "bits" rightadjusted bits from location "from" --oCkApply = outer bounds checking apply --When called, oBckApply oper most be a check operation, lt, unsigned, <= one word --eliminate masking constants and bound checks --reduce frequent flags where problems are to be expected --also compute size of largest dummy --fix converts of mesa errors from 0 bits to 1 bit This case does constant folding. There are some few cases where the mimosa front end might miss the folding of a constant. I wouldn't consider them worth this effort, but: In these cases a C compiler might get confused whether to use signed or unsigned arithmetic. I decided that I'd rather introduce constant folding then lots of casts to unsigned... --don't do that, size may be wrong IF field.base.bits=var.bits AND field.start=0 THEN { --field is complete record RETURN [field.base]; }; --return new, modified constant if possible --we've got it! --eliminate masking over bound checks if possible --we've got it! --try to get rid of multi dimensional packed arrays --now field can be removed or changed, but --check if removing field actually helps... doReplace _ lhs; --avoids direct visit of addr --don't recurse on the var itself! Κ’–(cedarcode) style•NewlineDelimiter ™šœ™Icodešœ ΟeœI™TKšœ™K™.K™$K˜—šΟk ˜ Kšœ ˜ Kšœ ˜ Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ˜Kšœ ˜ Kšœ˜K˜—šΟnœžœž˜#Kšžœ7˜>Kšžœ˜—šž˜Kšžœ ˜—K˜K˜šœžœžœ˜&KšΟc`˜`—K˜šœžœ˜K˜—šœ-˜-šŸ œžœžœ)˜FKšœžœ˜"Kšœ!žœ˜'Kšœ"žœ˜'Kšœ žœ˜&Kšœ$žœ˜)Kšœžœ˜$K˜K˜——šœ;˜;šŸœžœžœ)˜MKšœžœ˜"Kšœ!žœ˜&Kšœ"žœ˜(Kšœ žœ˜&Kšœ$žœ˜)Kšœžœ˜$K˜K˜——šœLžœF˜—K˜—šœRžœF˜K˜—šŸ œžœžœ˜EKšžœžœžœžœ ˜ Kšžœžœžœžœ*˜Bšžœž˜$Kšžœ žœžœ4žœ ˜VKšžœ˜—K˜—K˜šŸ œžœžœžœ˜MKšžœžœ;˜H˜K˜——š Ÿ œžœžœžœžœ˜>Kš ?™?šŸœ˜šžœžœž˜Kšœžœ  ˜3Kšœžœžœ ˜.Kšžœ˜—Kšœ"˜"Kšžœ˜ Kšœ˜—Kšœ˜K˜—K˜šŸ œžœžœžœ˜AKšžœI˜OK˜—K˜šŸœžœ!žœžœ˜XKšœžœ<˜GK˜K˜—šŸœžœžœ˜UKšœžœ<˜GK˜K˜—šŸœžœžœžœ˜FKšœ>™>Kšœ Οz œ™<šžœžœž˜Kšœžœžœ˜!Kšœžœžœ˜&Kšžœžœ/žœ˜G—K˜K˜—šŸœžœžœžœ˜BKšžœ3žœ˜?K˜K˜—š Ÿœžœžœ žœžœ˜Hšœ ˜ šžœžœž˜Kšœ!˜!Kšœžœ˜Kšœ0žœ(žœ˜aKšœžœ˜Kšžœ žœ˜——K˜—K˜šŸ&œžœ˜=šŸœžœ!˜+šŸœ˜Kšœ˜šžœžœž˜šœ˜šžœžœžœ˜Kšœ žœ0˜@Kšœ žœ,˜;Kšœžœ˜šŸœžœžœ˜5Kš R™RšŸœžœžœ'žœ˜mKš .™.Kšœ1˜1Kšœ-˜-Kšœ+˜+Kšœ ˜ Kšœ˜K˜—KšœF˜FKšœ<˜šžœ œžœž˜2šœžœžœžœ˜1šžœ žœž˜šœ˜šžœ žœž˜šœ˜šžœžœ˜!Kšœ žœ žœ˜"Kšœ8  œ˜Yšžœ žœ˜Kšœ žœ žœ˜Kšœ4 œ˜Sš žœ žœ žœžœžœžœ˜aKšœ œ˜5K˜—Kšœ˜—K˜—K˜—Kšžœ œ˜——Kšžœ œ˜—K˜—Kšžœ œ˜$—K˜—K˜—Kšžœ œ˜—K˜—Kšžœ œ˜—K˜—Kšžœ  œ˜—K˜—K˜—Kšœ˜—K˜šŸ œžœžœžœ˜;Kšžœžœžœ0˜lKšœ˜—K˜šŸ œžœ˜Kš .™.Kš 9™9Kš $™$Kšœžœ˜Kšœ;˜;Kšœžœžœ ˜&šŸ œ˜$Kšœžœ ˜)šžœžœž˜˜Kš 2™2šžœ žœž˜šœ˜šžœ žœž˜šœ˜Kšžœžœ$˜BK˜—˜Jšžβ™βšžœžœžœžœžœ žœžœžœžœ˜wK˜K˜#šžœžœž˜˜%šžœžœž˜˜%Kšœžœžœ žœ˜ Kšœžœ'˜/Kšœžœ'˜/šžœž˜Kšœžœ˜$Kšœžœ˜$Kšœžœ˜$Kšœžœžœžœ˜1Kš œžœžœ žœ žœ˜5Kšžœ˜—šžœžœ˜ Kšœžœœ˜E—K˜—Kšžœ˜—K˜—Kšžœ˜—K˜—K˜—šœ˜šžœžœžœžœ˜Yšžœžœž˜!˜šžœ žœž˜šœ˜šžœ žœž˜šœ˜šžœ ž˜šœ ˜ Kšœ˜Kšœ˜Kšœ˜—Kšžœ œ˜——Kšžœ œ˜——Kšžœ œ˜——Kšžœ œ˜—K˜——Kšžœ˜——Kšžœ˜—K˜—šœ ˜ šžœžœ˜Kšžœ žœžœ˜CKšžœžœžœ˜9Kšžœžœžœ˜;Kšžœžœžœ˜7Kšžœžœ6 ˜`K˜—šžœžœž˜šœ˜Kš "™"šžœžœžœ™4Kš ™Kšžœ™K™—šžœ žœ(žœ˜?šžœ žœž˜Kšœ"žœ +˜Tšœ˜Kš +™+šžœžœž˜šœ˜Kš ™Kšœ_˜_Kšœ ˜ Kšžœ ˜1K˜—Kšžœ˜——šœ˜Kš 1™1šžœ žœž˜šœ˜šžœ žœž˜šœ˜šžœžœ,žœ˜IKšœ žœžœžœ˜Kšœ.žœ˜3—Kšœ˜—šŸœ˜/šžœžœž˜šœ ˜ KšΟb˜šžœžœž˜šœ˜Kš ™Kšœ8˜8Kšžœ ˜K˜—Kšžœ˜—K˜—šœ˜Kš "™"Kšœ&˜&šžœ žœž˜˜šžœ žœž˜šœ˜šžœ ž˜Kšœ ˜%Kšžœ£œ˜"——Kšžœ£œ˜"——Kš žœžœ žœžœ£œ˜8—Kšžœ  ˜+K˜—Kšžœ˜—Kšœ2˜2Kšžœ˜K˜—Kšœ8˜8Kšœ!žœžœ˜:Kšœ$˜$Kšœ/˜/K˜—Iimp˜š Ÿœžœžœžœžœžœ˜QKšžœ žœžœžœ˜6Kšžœžœžœžœ˜,šžœ+žœž˜:Kšœžœ'˜HKšžœžœžœ˜—K˜—K˜Kšžœ˜K˜—…—>’\