DIRECTORY BasicTime USING [GMT, Now], Convert USING [RopeFromReal, RopeFromTime], FS USING [StreamOpen], Graph USING [Entity, EntityGroup, EntityHash, EntityHashSize, EntityList, EntityRec, GRAPH, GraphHandle, NestedEntities, NestedEntitiesList, NestedEntitiesRec, SegmentDataList, SegmentDataRec, ValueList], GraphOps USING [AddCrossSection, AddText, Lock, NewGraph, EnlistEntity, Unlock], GraphPrivate USING [PaintAll, PaintTails], GraphUtil USING [Almost, AppendX, AppendY], IO USING [int, PutF, PutFR, real, Reset, rope, STREAM, time], Labels USING [Set], Rope USING [Concat, Cat, FromRefText, ROPE], spGlobals USING [argument, argumentPtr, branchPtr, conLinkPtr, error, findNodeOrBranch, FlushCloseNil, getSignedNumber, Handle, instTreePtr, makeStringNB, maxPlots, maxPrints, namePtr, next, nodePtr, OutputFileRoot, plotBlkPtr, plotBlk, printBlk, printBlkPtr, RefC, RefCircuitRec, RefCktInstRec, RefI, RefL, RefR, RefV, version], ViewerTools USING [GetContents]; spOutput: CEDAR PROGRAM IMPORTS BasicTime, Convert, FS, GraphOps, GraphPrivate, GraphUtil, IO, Labels, Rope, spGlobals, ViewerTools EXPORTS spGlobals= BEGIN OPEN spGlobals; nodeComment: Rope.ROPE = ": node"; InitPP: PUBLIC PROC[handle: Handle, tMin, tMax: REAL] = { OPEN handle.vars; file: Rope.ROPE _ Rope.Concat[OutputFileRoot[handle], ".graph"]; tid: INT _ -1; [graphHandle, ] _ GraphOps.NewGraph[ fileName: file, comment: title, xName: Rope.Cat["Time[", Unit[tUnit, "S"], "]"], bounds: [tMin/tUnit, yMin, tMax/tUnit, yMax], autoBounds: FALSE ]; GraphOps.Lock[graphHandle]; graphHandle.chart.viewer.inhibitDestroy _ TRUE; [] _ GraphOps.AddText[handle: graphHandle, rope: title, place: [0.5, 1.1], fontIndex: 2, justifX: center, justifY: bottom]; [] _ GraphOps.AddText[handle: graphHandle, rope: file, place: [0, -0.35], fontIndex: 1, justifX: left, justifY: bottom]; [] _ GraphOps.AddText[handle: graphHandle, rope: Convert.RopeFromTime[from: simTime, includeDayOfWeek: TRUE], place: [1.0, -0.35], fontIndex: 1, justifX: right, justifY: bottom]; [] _ GraphOps.AddText[handle: graphHandle, rope: Rope.Cat["[", Unit[tUnit, "S"], "]"], place: [1.01, 0.0], justifX: left, justifY: bottom]; [] _ GraphOps.AddText[handle: graphHandle, rope: Rope.Cat["[", Unit[vUnit, "V"], ", ", Unit[iUnit, "A"], "]"], place: [0.0, 1.01], justifX: left, justifY: bottom]; GraphOps.Unlock[graphHandle]; }; -- InitPP Unit: PROC [unit: REAL, base: Rope.ROPE] RETURNS [Rope.ROPE] = { dUnit: REAL _ SELECT unit FROM > 30.0 => 1.0e3, > 30.0e-3 => 1.0, > 30.0e-6 => 1.0e-3, > 30.0e-9 => 1.0e-6, ENDCASE => 1.0e-9; mul: Rope.ROPE _ SELECT dUnit FROM 1.0e3 => "k", 1.0 => "", 1.0e-3 => "m", 1.0e-6 => "u", ENDCASE => "n"; RETURN[Rope.Cat[ IF GraphUtil.Almost[unit, dUnit] THEN "" ELSE Convert.RopeFromReal[unit/dUnit], mul, base]]; }; -- Unit InitNE: PROC [handle: Handle, t: REAL] = { EnlistTree: PROC[tree: instTreePtr, group: Graph.EntityGroup, parent: Graph.NestedEntities, hash: Graph.EntityHash, lastId: INT, graph: Graph.GRAPH] RETURNS [newLastId: INT, ne: Graph.NestedEntities _ NIL] = { lastChild, nel: Graph.NestedEntitiesList _ NIL; ne _ NEW[Graph.NestedEntitiesRec _ [parent: parent]]; IF parent # NIL THEN { cktInst: RefCktInstRec _ NARROW[tree.instance.details]; cktInstOfDetails: RefCircuitRec _ NARROW[cktInst.of.details]; ne.name _ tree.instance.name; ne.comment _ IO.PutFR[": %g[%g]", IO.rope[cktInst.of.name], IO.rope[Arguments[cktInst.connections, cktInstOfDetails.fakeNodes]] ]; }; newLastId _ lastId; newLastId _ EnlistNB[tree, group, ne, hash, newLastId, graph]; FOR i: instTreePtr _ tree.sons, i.brothers UNTIL i=NIL DO child: Graph.NestedEntities; [newLastId, child] _ EnlistTree[i, group, ne, hash, newLastId, graph]; nel _ CONS[child, NIL]; IF lastChild = NIL THEN ne.children _ lastChild _ nel ELSE {lastChild.rest _ nel; lastChild _ nel}; ENDLOOP; }; -- EnlistTree EnlistNB: PROC[tree: instTreePtr, group: Graph.EntityGroup, parent: Graph.NestedEntities, hash: Graph.EntityHash, lastId: INT, graph: Graph.GRAPH] RETURNS [newLastId: INT] = { PlotIt: PROC [entity: Graph.Entity] = { lel: Graph.EntityList _ CONS[entity, NIL]; sdl: Graph.SegmentDataList _ CONS[ NEW[Graph.SegmentDataRec _ [end: entity.oldValues.first]], NIL]; entity.segments _ entity.lastSegment _ sdl; IF graph.entityList = NIL THEN graph.entityList _ lel ELSE FOR el: Graph.EntityList _ graph.entityList, el.rest UNTIL el = NIL DO IF el.rest = NIL THEN {el.rest _ lel; EXIT}; ENDLOOP; }; -- PlotIt lastEL, el: Graph.EntityList _ NIL; hashIndex: INT[0..Graph.EntityHashSize); newLastId _ lastId; FOR n: nodePtr _ tree.nodes, n.brotherNodes UNTIL n=NIL DO entity: Graph.Entity _ NEW[Graph.EntityRec _ [ name: n.nodeName.name, comment: nodeComment, group: group, parent: parent, id: (newLastId _ newLastId+1) ]]; [] _ GraphUtil.AppendY[entity, n.nHist.y/handle.vars.vUnit, 0, 0]; n.entity _ entity; hashIndex _ entity.id MOD Graph.EntityHashSize; hash[hashIndex] _ CONS[entity, hash[hashIndex]]; el _ CONS[entity, NIL]; IF lastEL = NIL THEN parent.entityList _ lastEL _ el ELSE {lastEL.rest _ el; lastEL _ el}; IF newLastId <= 12 THEN PlotIt[entity]; ENDLOOP; FOR b: branchPtr _ tree.branches, b.brotherBranches UNTIL b=NIL DO entity: Graph.Entity _ NEW[Graph.EntityRec _ [ name: b.branchName.name, comment: IO.PutFR[": %g[%g, %g]", IO.rope[BranchType[b]], IO.rope[b.posNode.nodeName.name], IO.rope[b.negNode.nodeName.name] ], group: group, parent: parent, id: (newLastId _ newLastId+1) ]]; [] _ GraphUtil.AppendY[entity, BranchCurrent[b]/handle.vars.iUnit, 0, 0]; b.entity _ entity; hashIndex _ entity.id MOD Graph.EntityHashSize; hash[hashIndex] _ CONS[entity, hash[hashIndex]]; el _ CONS[entity, NIL]; IF lastEL = NIL THEN parent.entityList _ lastEL _ el ELSE {lastEL.rest _ el; lastEL _ el}; IF newLastId <= 12 THEN PlotIt[entity]; ENDLOOP; }; -- EnlistNB Arguments: PROC[conn: conLinkPtr, fakes: namePtr] RETURNS [r: Rope.ROPE _ NIL] = { FOR c: conLinkPtr _ conn, c.nextLink UNTIL c = NIL DO r _ IF r = NIL THEN Rope.Cat[fakes.name, ": ", c.namedNode.name] ELSE Rope.Cat[fakes.name, ": ", c.namedNode.name, ", ", r]; fakes _ fakes.nextName; ENDLOOP; }; -- Arguments BranchType: PROC[branch: branchPtr] RETURNS [Rope.ROPE] = { RETURN[WITH branch.body SELECT FROM r: RefR => "R", c: RefC => "C", v: RefV => "V", i: RefI => "I", l: RefL => "L", ENDCASE => NIL -- (error. Will it happen?) ]; }; -- BranchType gh: Graph.GraphHandle _ handle.vars.graphHandle; group: Graph.EntityGroup _ gh.entityGroupList.first; [] _ GraphUtil.AppendX[group.x, t/handle.vars.tUnit]; group.length _ 1; [handle.vars.lastEntityId, group.ys] _ EnlistTree[handle.vars.treeRoot, group, NIL, gh.entityHash, handle.vars.lastEntityId, gh.graph]; GraphPrivate.PaintAll[handle.vars.graphHandle, FALSE, TRUE]; -- just for legends. }; -- InitNE BranchCurrent: PROC [branch: branchPtr] RETURNS [REAL] = { RETURN[WITH branch.body SELECT FROM r: RefR => (branch.posNode.nHist.y - branch.negNode.nHist.y)/branch.comVal, c: RefC => (branch.posNode.nHist.f0 - branch.negNode.nHist.f0)*branch.comVal, v: RefV => v.vsCurrent, i: RefI => branch.comVal, l: RefL => l.iHist.y/branch.comVal, ENDCASE => 0.0 -- (error. Will it happen?) ]; }; -- BranchCurrent UpdatePP: PUBLIC PROC[handle: Handle, t: REAL] = { firstTime: BOOL; group: Graph.EntityGroup; GraphOps.Lock[handle.vars.graphHandle]; group _ handle.vars.graphHandle.entityGroupList.first; firstTime _ group.ys.entityList = NIL; IF firstTime THEN InitNE[handle, t] ELSE { UpdateTree: PROC [tree: instTreePtr, oldV1, oldV2: Graph.ValueList] RETURNS [newV1, newV2: Graph.ValueList] = { AppendIt: PROC [new: REAL, entity: Graph.Entity] = { old: REAL _ GraphUtil.AppendY[entity, new, t1, t2]; IF entity.segments # NIL THEN { newV1 _ CONS[old, newV1]; newV2 _ CONS[new, newV2]; }; }; -- AppendIt newV1 _ oldV1; newV2 _ oldV2; FOR n: nodePtr _ tree.nodes, n.brotherNodes UNTIL n=NIL DO AppendIt[n.nHist.y/handle.vars.vUnit, n.entity]; ENDLOOP; FOR b: branchPtr _ tree.branches, b.brotherBranches UNTIL b=NIL DO AppendIt[BranchCurrent[b]/handle.vars.iUnit, b.entity]; ENDLOOP; FOR i: instTreePtr _ tree.sons, i.brothers UNTIL i=NIL DO [newV1, newV2] _ UpdateTree[i, newV1, newV2]; ENDLOOP; }; -- UpdateTree t2: REAL _ t/handle.vars.tUnit; t1: REAL _ GraphUtil.AppendX[group.x, t2]; v1, v2: Graph.ValueList _ NIL; [v1, v2] _ UpdateTree[handle.vars.treeRoot, v1, v2]; group.length _ group.length + 1; GraphPrivate.PaintTails[handle.vars.graphHandle, paint, v1, v2, t1, t2]; }; GraphOps.Unlock[handle.vars.graphHandle]; }; -- UpdatePP initPlot: PUBLIC PROC[handle: Handle, tMin, tMax: REAL]= { OPEN handle.vars; rope: Rope.ROPE; pl: plotBlkPtr; FOR i: NAT IN [0..numPlots) DO OPEN plots[i]; file: Rope.ROPE _ Rope.Concat[OutputFileRoot[handle], IO.PutFR[".graph%g", IO.int[i]]]; time: Rope.ROPE _ Convert.RopeFromTime[from: simTime, includeDayOfWeek: TRUE]; xmin: REAL _ tMin/plots[i].plotTimeRelTo; xmax: REAL _ tMax/plots[i].plotTimeRelTo; [plotHandle, ] _ GraphOps.NewGraph[ fileName: file, comment: title, xName: Rope.Cat["Time[", Unit[plots[i].plotTimeRelTo, "S"], "]"], bounds: [xmin, ymin, xmax, ymax], autoBounds: FALSE ]; GraphOps.Lock[plotHandle]; plotHandle.chart.viewer.inhibitDestroy _ TRUE; plotHandle.userEditAllowed _ FALSE; [] _ GraphOps.AddText[handle: plotHandle, rope: title, place: [0.5, 1.1], fontIndex: 2, justifX: center, justifY: bottom]; [] _ GraphOps.AddText[handle: plotHandle, rope: file, place: [0, -0.35], fontIndex: 1, justifX: left, justifY: bottom]; [] _ GraphOps.AddText[handle: plotHandle, rope: time, place: [1.0, -0.35], fontIndex: 1, justifX: right, justifY: bottom]; [] _ GraphOps.AddText[handle: plotHandle, rope: Rope.Cat["[", Unit[plots[i].plotTimeRelTo, "S"], "]"], place: [1.01, 0.0], justifX: left, justifY: bottom]; pl _ plotList; UNTIL pl = NIL DO heading: Rope.ROPE _ SELECT TRUE FROM pl.arg.getComVal => "Value of ", pl.arg.current => "Current through ", pl.arg.dvdt => "Derivative of ", ENDCASE => "Voltage at "; rope_ heading.Concat[makeStringNB[handle, pl.arg.node, pl.arg.branch]]; IF pl.relativeTo # 1.0 THEN rope _ IO.PutFR["%g/%g", IO.rope[rope], IO.real[pl.relativeTo]]; [] _ GraphOps.EnlistEntity[handle: plotHandle, name: rope]; pl _ pl.nextBlk; ENDLOOP; GraphOps.Unlock[plotHandle]; ENDLOOP; }; -- initPlot plotFromList: PUBLIC PROC[handle: Handle, t: REAL] = { OPEN handle.vars; FOR iPlot: NAT IN [0..numPlots) DO values: Graph.ValueList _ NIL; p: plotBlkPtr_ plots[iPlot].plotList; time: REAL _ t/plots[iPlot].plotTimeRelTo; UNTIL p = NIL DO values _ CONS[evaluateArgument[p.arg]/p.relativeTo, values]; p _ p.nextBlk; ENDLOOP; GraphOps.Lock[plots[iPlot].plotHandle]; GraphOps.AddCrossSection[plots[iPlot].plotHandle, time, values]; GraphOps.Unlock[plots[iPlot].plotHandle]; ENDLOOP; }; -- plotFromList getPlotNum: PROC [handle: Handle] RETURNS[r: REAL_ 1.0] = { r_ getSignedNumber[handle]; IF handle.vars.item = comma THEN next[handle] ELSE error[handle, 603,, FALSE] }; -- getPlotNum makePlotList: PUBLIC PROC[handle: Handle]= { OPEN handle.vars; I, D, cv: BOOL; pb: plotBlkPtr; n: nodePtr; b: branchPtr; IF numPlots >= maxPlots THEN { error[handle, 632, FALSE]; numPlots _ numPlots - 1 }; IF item = leftB THEN next[handle] ELSE error[handle, 600]; IF item = string THEN { plots[numPlots].title _ Rope.FromRefText[newString]; next[handle]; IF item = comma THEN next[handle] ELSE error[handle, 603,, FALSE] }; IF item = colon THEN { plots[numPlots].plotTimeRelTo_ scale[handle]; IF item = comma THEN next[handle] ELSE error[handle, 603,, FALSE] } ELSE plots[numPlots].plotTimeRelTo _ 1.0; plots[numPlots].ymin _ getPlotNum[handle]; plots[numPlots].ymax _ getPlotNum[handle]; IF plots[numPlots].ymin >= plots[numPlots].ymax THEN error[handle, 630, FALSE]; plots[numPlots].plotList _ NIL; UNTIL item # name DO [n, b] _ findNodeOrBranch[handle]; IF n = NIL AND b = NIL THEN error[handle, 620] ELSE { I_ b # NIL AND item = upArrow; D_ n # NIL AND item = quote; cv_ b # NIL AND item = atSign; IF I OR D OR cv THEN next[handle]; pb_ NEW[plotBlk_ [nextBlk: plots[numPlots].plotList, relativeTo: scale[handle], arg: NEW[argument_ [FALSE, n, b, cv, D, I]]] ]; plots[numPlots].plotList_ pb; }; IF item = comma THEN next[handle] ELSE EXIT; ENDLOOP; IF item = rightB THEN next[handle] ELSE error[handle, 601, TRUE]; numPlots _ numPlots + 1; }; -- makePlotList PutMsgLine: PUBLIC PROC[handle: Handle, s: Rope.ROPE]= { handle.msgStream.PutF["%g\n", IO.rope[s]]; }; -- PutMsgLine evaluateArgument: PROC[a: argumentPtr] RETURNS[iv: REAL]= { b: branchPtr; IF a.getComVal THEN RETURN[a.branch.comVal]; IF a.node # NIL THEN iv_ IF a.dvdt THEN a.node.nHist.f0 ELSE a.node.nHist.y ELSE { b_ a.branch; IF a.current THEN WITH b.body SELECT FROM r: RefR => iv_ (b.posNode.nHist.y - b.negNode.nHist.y)/b.comVal; c: RefC => iv_ (b.posNode.nHist.f0 - b.negNode.nHist.f0)*b.comVal; l: RefL => iv_ l.iHist.y/b.comVal; v: RefV => iv_ v.vsCurrent; i: RefI => iv_ b.comVal; ENDCASE ELSE iv_ b.posNode.nHist.y - b.negNode.nHist.y; }; }; -- evaluateArgument initPrint: PUBLIC PROC[handle: Handle, time: BasicTime.GMT]= { FOR i: NAT IN [0..handle.vars.numPrints) DO output: IO.STREAM_ handle.vars.prints[i].printStream; output.PutF["* Simulation started at %g.\n", IO.time[time]]; ENDLOOP; }; -- initPrint printFromList: PUBLIC PROC[handle: Handle, ni: INT, t: REAL, printStep: BOOL]= { i: NAT; p: printBlkPtr; r, trel: REAL; FOR i IN [0..handle.vars.numPrints) DO output: IO.STREAM_ handle.vars.prints[i].printStream; p_ handle.vars.prints[i].printList; trel_ t/handle.vars.prints[i].printTimeRelTo; output.PutF["%10.3e", IO.real[trel]]; IF printStep THEN output.PutF["(%2d)", IO.int[ni]]; UNTIL p=NIL DO r_ evaluateArgument[p.arg]/p.relativeTo; output.PutF[" %10.3f", IO.real[r]]; p_ p.nextBlk; ENDLOOP; output.PutF["\n"]; ENDLOOP; }; -- printFromList scale: PROC[handle: Handle] RETURNS[s: REAL_ 1.0]= { IF handle.vars.item=colon THEN {next[handle]; s_ getSignedNumber[handle]}; }; -- scale makePrintList: PUBLIC PROC[handle: Handle]= { OPEN handle.vars; I, D, cv: BOOL; pb, pb2, pb3: printBlkPtr; n: nodePtr; b: branchPtr; outFileNameRoot, outFileName, outFiles: Rope.ROPE; IF numPrints >= maxPrints THEN { error[handle, 631]; numPrints_ numPrints - 1; }; IF item=leftB THEN next[handle] ELSE error[handle, 600]; IF item=colon THEN { prints[numPrints].printTimeRelTo_ scale[handle]; IF item=comma THEN next[handle] ELSE error[handle, 603,, FALSE]; } ELSE prints[numPrints].printTimeRelTo_ 1.0; prints[numPrints].printList_ NIL; UNTIL item # name DO [n, b]_ findNodeOrBranch[handle]; IF n=NIL AND b=NIL THEN error[handle, 620] ELSE { I_ (b # NIL) AND item=upArrow; -- branch current D_ (n # NIL) AND item=quote; -- derivative of node voltage cv_ (b # NIL) AND item=atSign; -- branch value IF I OR D OR cv THEN next[handle]; pb_ NEW[printBlk_ [nextBlk: prints[numPrints].printList, relativeTo: scale[handle], arg: NEW[argument_ [FALSE, n, b, cv, D, I]] ] ]; prints[numPrints].printList_ pb; }; IF item=comma THEN next[handle] ELSE EXIT; ENDLOOP; pb_ NIL; pb3_ prints[numPrints].printList; UNTIL pb3=NIL DO pb2_ pb3; pb3_ pb3.nextBlk; pb2.nextBlk_ pb; pb_ pb2; ENDLOOP; prints[numPrints].printList_ pb; outFileNameRoot_ OutputFileRoot[handle]; outFileName_ IO.PutFR["%g.out%g", IO.rope[outFileNameRoot], IO.int[numPrints]]; prints[numPrints].printStream_ FS.StreamOpen[fileName: outFileName, accessOptions: $create]; prints[numPrints].printStream.Reset[ ]; outFiles_ IF numPrints=0 THEN outFileName ELSE IO.PutFR["%g.out0...out%g", IO.rope[outFileNameRoot], IO.int[numPrints]]; Labels.Set[handle.output, outFiles]; prints[numPrints].printStream.PutF[ "** %g\n*\n* File: %g\n* Input: %g\n* Time: %g\n*\n", IO.rope[version], IO.rope[outFileName], IO.rope[ViewerTools.GetContents[handle.input]], IO.time[simTime] ]; numPrints_ numPrints + 1; IF item=rightB THEN next[handle] ELSE error[handle, 601, TRUE]; }; -- makePrintList dumpAll: PUBLIC PROC[handle: Handle, t: REAL]= { OPEN handle.vars; dname: Rope.ROPE; dump: IO.STREAM; nodes: nodePtr_ nodeList; inds: branchPtr_ inductorList; dname_ IO.PutFR["%g.dump", IO.rope[OutputFileRoot[handle]]]; dump_ FS.StreamOpen[fileName: dname, accessOptions: $create]; dump.Reset[]; dump.PutF["ic[%f,\n", IO.real[t]]; UNTIL nodes=NIL DO dump.PutF["%g_ %f", IO.rope[makeStringNB[handle, nodes, NIL, FALSE]], IO.real[nodes.nHist.y]]; nodes_ nodes.nextNode; IF nodes # NIL THEN dump.PutF[",\n"] ELSE dump.PutF["\n"]; ENDLOOP; UNTIL inds=NIL DO indsBody: RefL_ NARROW[inds.body]; dump.PutF["%g_ %f", IO.rope[makeStringNB[handle, NIL, inds, FALSE]], IO.real[indsBody.iHist.y]]; inds_ indsBody.nextInductor; IF inds # NIL THEN IO.PutF[dump, ",\n"] ELSE IO.PutF[dump, "\n"]; ENDLOOP; dump.PutF["];\n"]; handle.msgStream.PutF["Dumped into file %g at %g.\n", IO.rope[dname], IO.time[]]; dump _ FlushCloseNil[dump]; }; -- dumpAll END. CHANGE LOG Wilhelm, April 6, 1982 11: 36 AM Barth, 7-May-82 10: 45: 07 PDT Chen, June 12, 1984 6:59:26 pm PDT, cedarized. Chen, July 22, 1985 8:09:51 pm PDT, => Cedar6.0. File: spOutput.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Last Edited by: Sweetsun Chen, November 17, 1985 2:50:32 am PST title, file, time, tunit, vunit, iunit enlist enity on graph.entityList, and initialize entity.segments. Κ˜J™Jšœ Οmœ1™<™J™/—J˜šΟk ˜ Jšœ žœžœ˜Jšœžœ˜+Jšžœžœ˜JšœžœJžœr˜ΜJšœ žœB˜PJšœ žœ˜*Jšœ žœ˜+Jšžœžœ'žœ˜=Jšœžœ˜Jšœžœžœ˜,Jšœ žœΊ˜ΙJšœ žœ˜ —J˜šœ žœž˜Jšžœžœ%žœ&˜kJšžœ ˜—J˜Jšžœžœ ˜J˜Jšœžœ ˜"J˜šΟnœžœžœžœ˜9Jšžœ ˜Jšœ žœ1˜@Jšœžœ˜˜$Jšœ˜Jšœ˜Jšœ0˜0J˜-Jšœ ž˜J˜—J˜Jšœ*žœ˜/J˜J™&šœ*˜*JšœP˜P—šœ*˜*JšœM˜M—šœ*˜*Jšœ<žœ˜BJšœD˜D—šœ*˜*Jšœ+˜+Jšœ4˜4—šœ*˜*JšœC˜CJšœ4˜4—J˜JšœΟc ˜ J˜š Ÿœžœžœ žœžœžœ˜@šœžœžœž˜J˜J˜J˜J˜Jšžœ ˜—šœ žœžœž˜"Jšœ7žœ˜F—šžœ ˜Jšžœžœžœ"˜OJšœ ˜ —Jšœ ˜ J˜—šŸœžœžœ˜*šŸ œžœlžœžœžœ žœžœ˜ΡJšœ+žœ˜/Jšœžœ-˜5šžœ žœžœ˜Jšœžœ˜7Jšœ"žœ˜=Jšœ˜šœ žœ˜!Jšžœ˜JšžœA˜CJšœ˜—J˜—Jšœ˜Jšœ>˜>šžœ(žœžœž˜9Jšœ˜JšœF˜FJšœžœžœ˜Jšžœ žœžœ˜5Jšžœ)˜-Jšžœ˜—Jšœ  ˜—J˜š Ÿœžœlžœžœžœ žœ˜―šŸœžœ˜'JšœA™AJšœžœ žœ˜*šœžœ˜"Jšžœ8žœ˜@—Jšœ+˜+Jšžœžœžœ˜5š žœžœ2žœžœž˜KJšžœ žœžœžœ˜,Jšžœ˜—Jšœ  ˜ J˜—Jšœžœ˜#Jšœ žœ˜(Jšœ˜šžœ)žœžœž˜:šœžœ˜.Jšœ˜J˜J˜ Jšœ˜Jšœ˜J˜—JšœB˜BJ˜Jšœžœ˜/Jšœžœ˜0Jšœžœ žœ˜Jšžœ žœžœ ˜4Jšžœ!˜%Jšžœžœ˜'Jšžœ˜—J˜šžœ1žœžœž˜Bšœžœ˜.Jšœ˜šœ žœ˜!Jšžœ˜Jšžœ˜!Jšžœ˜ Jšœ˜—J˜ Jšœ˜Jšœ˜J˜—JšœI˜IJ˜Jšœžœ˜/Jšœžœ˜0Jšœžœ žœ˜Jšžœ žœžœ ˜4Jšžœ!˜%Jšžœžœ˜'Jšžœ˜—Jšœ  ˜J˜—š Ÿ œžœ#žœ žœžœ˜Ršžœ"žœžœž˜5Jš œžœžœžœ.žœ7˜|J˜Jšžœ˜—Jšœ  ˜—J˜šŸ œžœžœžœ˜;šžœžœ žœž˜#Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšžœžœ ˜*Jšœ˜—Jšœ  ˜J˜—Jšœ0˜0Jšœ4˜4Jšœ5˜5Jšœ˜JšœOžœ5˜‡Jšœ/žœžœ ˜Qšœ  ˜ J˜——šŸ œžœžœžœ˜:šžœžœ žœž˜#JšœK˜KJšœM˜MJšœ˜Jšœ˜Jšœ#˜#Jšžœ ˜*J˜—Jšœ ˜——J˜šŸœžœžœžœ˜2Jšœ žœ˜Jšœ˜J˜'Jšœ6˜6Jšœ"žœ˜&Jšžœ žœ˜#šžœ˜šŸ œžœ4žœ$˜ošŸœžœžœ˜4Jšœžœ*˜3šžœžœžœ˜Jšœžœ ˜Jšœžœ ˜J˜—Jšœ  ˜—Jšœ˜šžœ)žœžœž˜:Jšœ0˜0Jšžœ˜—šžœ1žœžœž˜BJšœ7˜7Jšžœ˜—šžœ(žœžœž˜9Jšœ-˜-Jšžœ˜—Jšœ  ˜J˜—Jšœžœ˜Jšœžœ"˜*Jšœžœ˜Jšœ4˜4J˜ J˜HJ˜—J˜)Jšœ  ˜—J˜šœ žœžœžœ˜:Jšžœ ˜Jšœ žœ˜Jšœ˜J˜šžœžœžœž˜Jšžœ ˜Jšœ žœ'žœžœ ˜WJšœ žœ9žœ˜NJšœžœ˜)Jšœžœ˜)J˜˜#J˜Jšœ˜JšœA˜AJšœ!˜!Jšœ ž˜J˜J˜—J˜Jšœ)žœ˜.Jšœžœ˜#J˜˜)JšœP˜P—˜)JšœM˜M—˜)JšœP˜P—šœ)˜)Jšœ<˜šžœžœžœž˜+Jšœžœžœ$˜5Jšœ-žœ ˜