DIRECTORY Buttons, ChoiceButtons, Containers, Convert, Core, CoreClasses, CoreOps, IO, Ports, Process, Rope, Rosemary, RosemaryUser, Rules, ViewerClasses, ViewerIO, ViewerOps, ViewerTools; RosemaryUserImpl: CEDAR MONITOR IMPORTS Buttons, ChoiceButtons, Containers, Convert, CoreOps, IO, Ports, Process, Rope, Rosemary, Rules, ViewerIO, ViewerOps, ViewerTools EXPORTS RosemaryUser = BEGIN OPEN RosemaryUser; debug: BOOL _ FALSE; entryHeight: NAT = 15; -- how tall to make each line of items entryVSpace: NAT = 4; -- vertical leading space between lines pointsPerInch: NAT = 72; -- horizontal space for text ropes borderOffset: NAT = 2; Column: TYPE = NAT [0..3); ColumnStart: ARRAY Column OF NAT = [entryVSpace, 1*pointsPerInch+entryVSpace, 4*pointsPerInch+entryVSpace]; Tester: TYPE = REF TesterRec; TesterRec: TYPE = RECORD [ cellType: Core.CellType, testPort: Ports.Port _ NIL, intermediatePort: Ports.Port _ NIL, simulation: Rosemary.Simulation _ NIL, runState: ViewerClasses.Viewer _ NIL, evalsSinceStart: ViewerClasses.Viewer _ NIL, evalSinceStartCount: INT, proceedUntil: ViewerClasses.Viewer _ NIL, evalUntil: INT, historyTrigger: ViewerClasses.Viewer _ NIL, historyTriggerCount: INT, currentStatePoint: NAT _ 0, displayedStatePoint: NAT _ 0, validStates: NAT _ 0, historySize: NAT _ 0, testVectorBuffer: Rosemary.PortSequence _ NIL, proceed: CONDITION, testStarted: BOOL _ FALSE, waiting: BOOL _ FALSE, abort: BOOL _ FALSE, interrupt: BOOL _ FALSE, singleEval: BOOL _ FALSE, displayWires: LIST OF ChoiceButtons.PromptDataRef _ NIL, bitBucket: Ports.LevelSequence _ NIL, testButtonList: LIST OF Buttons.Button, currentTestProc: TestProc, tsin: IO.STREAM _ NIL, tsout: IO.STREAM _ NIL]; TestHandle: TYPE = REF TestHandleRec; TestHandleRec: TYPE = RECORD[ h: Tester, proc: TestProc]; DisplayWireHandle: TYPE = REF DisplayWireHandleRec; DisplayWireHandleRec: TYPE = RECORD[ h: Tester, instantiationPath: Rosemary.InstantiationPath, wire: Core.Wire, wireSize: NAT]; MakeStandardViewer: PUBLIC PROC [name: ROPE _ NIL, cellType: Core.CellType, testButtons: LIST OF TestButton, displayWires: DisplayWires _ NIL, flatten: BOOL _ FALSE, cutSet: ROPE _ NIL, historySize: NAT _ 0] RETURNS [simulation: Rosemary.Simulation] = { viewer: ViewerClasses.Viewer_ Containers.Create[[ name: name, iconic: FALSE, column: left, scrollable: FALSE ]]; height: CARDINAL _ entryVSpace; h: Tester _ NEW[TesterRec]; h.cellType _ cellType; h.testPort _ Ports.CreatePort[cellType.public, TRUE]; h.intermediatePort _ Ports.CreatePort[cellType.public, TRUE]; simulation _ h.simulation _ IF flatten THEN Rosemary.InstantiateInstances[cellType, h.intermediatePort, cutSet, historySize] ELSE Rosemary.InstantiateCellType[cellType, h.intermediatePort, historySize]; IF historySize>0 THEN { h.historySize _ historySize; h.testVectorBuffer _ NEW[Rosemary.PortSequenceRec[historySize]]; FOR b: NAT IN [0..historySize) DO h.testVectorBuffer[b] _ Ports.CreatePort[cellType.public, TRUE]; ENDLOOP; }; [] _ Buttons.Create[info: [name: "Start Test", wx: ColumnStart[0], wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: h, proc: StartTest]; h.runState _ ChoiceButtons.BuildTextPrompt[viewer: viewer, x: ColumnStart[1], y: height-borderOffset, title: "Run State:", textViewerWidth: 2*pointsPerInch].textViewer; ViewerTools.InhibitUserEdits[h.runState]; ViewerTools.SetContents[h.runState, "Idle"]; IF historySize>0 THEN h.historyTrigger _ ChoiceButtons.BuildTextPrompt[viewer: viewer, x: ColumnStart[2], y: height-borderOffset, title: "History Trigger:", textViewerWidth: 2*pointsPerInch].textViewer; height _ height + entryHeight + entryVSpace; [] _ Buttons.Create[info: [name: "Interrupt", wx: ColumnStart[0], wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: h, proc: Interrupt]; h.evalsSinceStart _ ChoiceButtons.BuildTextPrompt[viewer: viewer, x: ColumnStart[1], y: height-borderOffset, title: "Evals Since Start:", textViewerWidth: 1*pointsPerInch].textViewer; ViewerTools.InhibitUserEdits[h.evalsSinceStart]; IF historySize>0 THEN [] _ Buttons.Create[info: [name: "Next State", wx: ColumnStart[2], wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: h, proc: NextState]; height _ height + entryHeight + entryVSpace; [] _ Buttons.Create[info: [name: "Proceed", wx: ColumnStart[0], wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: h, proc: Proceed]; h.proceedUntil _ ChoiceButtons.BuildTextPrompt[viewer: viewer, x: ColumnStart[1], y: height-borderOffset, title: "Proceed Until:", textViewerWidth: 1*pointsPerInch].textViewer; IF historySize>0 THEN [] _ Buttons.Create[info: [name: "Previous State", wx: ColumnStart[2], wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: h, proc: PreviousState]; height _ height + entryHeight + entryVSpace; [] _ Buttons.Create[info: [name: "Abort", wx: ColumnStart[0], wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: h, proc: Abort, guarded: TRUE]; [] _ Buttons.Create[info: [name: "Single Eval", wx: ColumnStart[1]+borderOffset, wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: h, proc: SingleEval]; height _ height + entryHeight + entryVSpace; Containers.ChildXBound[viewer, Rules.Create[[parent: viewer, wy: height, ww: viewer.cw, wh: 2]]]; height _ height + entryVSpace; IF displayWires#NIL THEN { Column: TYPE = NAT [0..2); ColumnStart: ARRAY Column OF NAT = [entryVSpace, 3*pointsPerInch+pointsPerInch/4+entryVSpace]; column: Column _ 0; maxWireSize: NAT _ 0; FOR dws: DisplayWires _ displayWires, dws.rest UNTIL dws=NIL DO root: Core.Wire; rec: CoreClasses.RecordCellType; last: Rosemary.InstantiationPath _ dws.first.instantiationPath; nameList: LIST OF ROPE; dw: DisplayWireHandle; IF last=NIL THEN { ct: Core.CellType _ Rosemary.Recordify[h.cellType]; rec _ NARROW[ct.data]; } ELSE { UNTIL last.rest=NIL DO last _ last.rest ENDLOOP; rec _ NARROW[last.first.type.data]; }; root _ rec.internal; nameList _ CoreOps.GetFullWireNames[root, dws.first.wire]; dw _ NEW[DisplayWireHandleRec _ [h, dws.first.instantiationPath, dws.first.wire, CoreOps.WireBits[dws.first.wire]]]; h.displayWires _ CONS[ChoiceButtons.BuildTextPrompt[viewer: viewer, x: ColumnStart[column], y: height-borderOffset, title: IF nameList=NIL THEN NIL ELSE nameList.first, textViewerWidth: pointsPerInch, clientdata: dw], h.displayWires]; IF column=LAST[Column] THEN { column _ 0; height _ height + entryHeight + entryVSpace; } ELSE column _ column+1; maxWireSize _ MAX[maxWireSize, dw.wireSize]; ENDLOOP; IF column>0 THEN height _ height + entryHeight + entryVSpace; h.bitBucket _ NEW[Ports.LevelSequenceRec[maxWireSize]]; Containers.ChildXBound[viewer, Rules.Create[[parent: viewer, wy: height, ww: viewer.cw, wh: 2]]]; height _ height + entryVSpace; }; IF testButtons.rest#NIL THEN { column: Column _ 0; FOR tbs: LIST OF TestButton _ testButtons, tbs.rest UNTIL tbs=NIL DO testHandle: TestHandle _ NEW[TestHandleRec _ [h, tbs.first.proc]]; h.testButtonList _ CONS[Buttons.Create[info: [name: tbs.first.name, wx: ColumnStart[column], wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: testHandle, proc: TestButtonProc], h.testButtonList]; IF column=LAST[Column] THEN { column _ 0; height _ height + entryHeight + entryVSpace; } ELSE column _ column+1; ENDLOOP; IF column>0 THEN height _ height + entryHeight + entryVSpace; Buttons.SetDisplayStyle[h.testButtonList.first, $BlackOnGrey]; Containers.ChildXBound[viewer, Rules.Create[[parent: viewer, wy: height, ww: viewer.cw, wh: 2]]]; height _ height + entryVSpace; }; h.currentTestProc _ testButtons.first.proc; [h.tsin, h.tsout] _ ViewerIO.CreateViewerStreams[name: "Rosemary Script", viewer:ViewerOps.CreateViewer[flavor: $TypeScript, info:[parent: viewer, wy: height+2, ww: 7*pointsPerInch, wh: 56 * entryHeight, scrollable: TRUE, border: FALSE]]]; height _ height + 10 * entryHeight; height _ height + entryHeight + entryVSpace/2; ViewerOps.SetOpenHeight[viewer, height]; ViewerOps.PaintViewer[viewer, all]; }; TestButtonProc: Buttons.ButtonProc = { t: TestHandle _ NARROW[clientData]; h: Tester _ t.h; selectedButton: ViewerClasses.Viewer _ NARROW[parent]; FOR l: LIST OF Buttons.Button _ h.testButtonList, l.rest WHILE l#NIL DO Buttons.SetDisplayStyle[l.first, IF l.first = selectedButton THEN $BlackOnGrey ELSE $BlackOnWhite]; ENDLOOP; h.currentTestProc _ t.proc; }; AbortSignal: SIGNAL = CODE; StartTest: Buttons.ButtonProc = { h: Tester _ NARROW[clientData]; IF NOT AlreadyStarted[h] THEN DoStartTest[h]; }; DoStartTest: PROC [h: Tester] = { Eval: PROC = { UpdateWire: Rosemary.UpdateProc = { UpdateDisplay[h]; IF wire.currentValue=NIL THEN IO.PutF[h.tsout, "%g_%g ", IO.rope[CoreOps.GetShortWireName[wire.wire]], IO.rope[SELECT wire.wireLevel FROM L => "L", X => "X", H => "H", ENDCASE => ERROR]]; }; DO inBuf: BOOL _ h.displayedStatePoint#h.currentStatePoint AND h.validStates>0; testPort: Ports.Port _ IF inBuf THEN h.testVectorBuffer[NextBuf[h, h.displayedStatePoint]] ELSE h.testPort; Ports.CopyPortValue[from: testPort, to: h.intermediatePort]; Rosemary.Settle[h.simulation, IF debug THEN UpdateWire ELSE NIL]; IF debug THEN IO.PutRope[h.tsout, "\n\n"]; UpdateESSC[h, h.evalSinceStartCount+1]; IF h.evalSinceStartCount>=h.historyTriggerCount AND NOT inBuf AND h.historySize>0 THEN { h.currentStatePoint _ NextBuf[h, h.currentStatePoint]; h.displayedStatePoint _ h.currentStatePoint; IF h.validStates < h.historySize THEN h.validStates _ h.validStates + 1; Rosemary.StatePoint[h.simulation, h.currentStatePoint]; Ports.CopyPortValue[from: h.testPort, to: h.testVectorBuffer[h.currentStatePoint]]; }; Ports.CheckPortValue[root: h.cellType.public, truth: testPort, question: h.intermediatePort ! Ports.CheckError => UpdateDisplay[h]]; IF EvalsFinished[h] THEN SIGNAL AbortSignal; IF inBuf THEN { h.displayedStatePoint _ NextBuf[h, h.displayedStatePoint]; IF h.displayedStatePoint=h.currentStatePoint THEN EXIT; } ELSE EXIT; ENDLOOP; }; h.evalSinceStartCount _ 0; h.validStates _ 0; ViewerTools.SetContents[h.evalsSinceStart, "0"]; SetEvalUntil[h: h, interrupt: FALSE, abort: FALSE]; ViewerTools.SetContents[h.runState, "Running"]; h.currentTestProc[h.cellType, h.testPort, Eval ! AbortSignal => CONTINUE; UNWIND => FinishedTest[h]]; FinishedTest[h]; }; AlreadyStarted: ENTRY PROC [h: Tester] RETURNS [started: BOOL] = { started _ h.testStarted OR h.singleEval; h.testStarted _ TRUE; BROADCAST h.proceed; }; FinishedTest: ENTRY PROC [h: Tester] = { UpdateDisplay[h]; ViewerTools.SetContents[h.runState, "Idle"]; h.testStarted _ FALSE; BROADCAST h.proceed; }; Interrupt: Buttons.ButtonProc = { h: Tester _ NARROW[clientData]; SetEvalUntil[h: h, interrupt: TRUE, abort: FALSE]; }; Proceed: Buttons.ButtonProc = { h: Tester _ NARROW[clientData]; SetEvalUntil[h: h, interrupt: FALSE, abort: FALSE]; }; Abort: Buttons.ButtonProc = { h: Tester _ NARROW[clientData]; SetEvalUntil[h: h, interrupt: FALSE, abort: TRUE]; }; SingleEval: Buttons.ButtonProc = { h: Tester _ NARROW[clientData]; DoSingleEval[h]; SetEvalUntil[h: h, interrupt: TRUE, abort: FALSE]; }; DoSingleEval: ENTRY PROC [h: Tester] = { h.singleEval _ TRUE; IF h.testStarted THEN { h.interrupt _ TRUE; UNTIL h.waiting OR NOT h.testStarted DO WAIT h.proceed ENDLOOP; IF h.testStarted THEN { count: INT _ h.evalSinceStartCount; until: INT _ h.evalUntil; h.evalUntil _ count+1; h.interrupt _ FALSE; BROADCAST h.proceed; UNTIL h.evalSinceStartCount > count OR h.abort OR NOT h.testStarted DO WAIT h.proceed; ENDLOOP; h.interrupt _ TRUE; h.evalUntil _ until; }; } ELSE TRUSTED { h.evalUntil _ 1; h.testStarted _ TRUE; Process.Detach[FORK DoStartTest[h]]; UNTIL h.waiting OR h.abort DO WAIT h.proceed ENDLOOP; }; h.singleEval _ FALSE; }; NextState: Buttons.ButtonProc = { h: Tester _ NARROW[clientData]; DoNextState[h]; }; DoNextState: ENTRY PROC [h: Tester] = { IF h.waiting AND NOT h.singleEval THEN { IF h.displayedStatePoint=h.currentStatePoint THEN IO.PutRope[h.tsout, "No next state"] ELSE { h.displayedStatePoint _ NextBuf[h, h.displayedStatePoint]; Rosemary.RestoreState[h.simulation, h.displayedStatePoint]; UpdateESSC[h, h.evalSinceStartCount+1]; UpdateDisplay[h]; }; }; }; PreviousState: Buttons.ButtonProc = { h: Tester _ NARROW[clientData]; DoPreviousState[h]; }; DoPreviousState: ENTRY PROC [h: Tester] = { IF h.waiting AND NOT h.singleEval THEN { ndsp: NAT _ IF h.displayedStatePoint=0 THEN h.historySize-1 ELSE h.displayedStatePoint-1; SELECT TRUE FROM ndsp>=h.validStates => IO.PutRope[h.tsout, "No previous state, not enough evals since history trigger"]; ndsp=h.currentStatePoint => IO.PutRope[h.tsout, "No previous state, buffer depth exceeded"]; ENDCASE => { h.displayedStatePoint _ ndsp; Rosemary.RestoreState[h.simulation, h.displayedStatePoint]; UpdateESSC[h, h.evalSinceStartCount-1]; UpdateDisplay[h]; }; }; }; SetEvalUntil: PROC [h: Tester, interrupt: BOOL, abort: BOOL] = { GetCount: PROC [v: ViewerClasses.Viewer] RETURNS [count: INT] = { IF v=NIL THEN count _ 0 ELSE { vRope: ROPE _ ViewerTools.GetContents[v]; count _ LAST[INT]; IF vRope#NIL THEN count _ Convert.IntFromRope[vRope ! Convert.Error => CONTINUE]; }; }; SetUntil[h, GetCount[h.proceedUntil], GetCount[h.historyTrigger], interrupt, abort]; }; SetUntil: ENTRY PROC [h: Tester, count: INT, trigger: INT, interrupt: BOOL, abort: BOOL] = { IF NOT h.singleEval THEN { h.evalUntil _ count; h.historyTriggerCount _ trigger; IF trigger>h.evalSinceStartCount THEN h.validStates _ 0; h.interrupt _ interrupt; }; h.abort _ abort; BROADCAST h.proceed; }; EvalsFinished: ENTRY PROC [h: Tester] RETURNS [abort: BOOL] = { resetRunState: BOOL _ FALSE; WHILE (h.evalUntil<=h.evalSinceStartCount OR h.interrupt) AND NOT h.abort DO UpdateDisplay[h]; ViewerTools.SetContents[h.runState, "Interrupted"]; resetRunState _ TRUE; BROADCAST h.proceed; h.waiting _ TRUE; WAIT h.proceed; h.waiting _ FALSE; ENDLOOP; IF resetRunState THEN ViewerTools.SetContents[h.runState, "Running"]; abort _ h.abort; }; UpdateDisplay: PROC [h: Tester] = { FOR dwvs: LIST OF ChoiceButtons.PromptDataRef _ h.displayWires, dwvs.rest UNTIL dwvs=NIL DO dw: DisplayWireHandle _ NARROW[dwvs.first.clientdata]; new: ROPE; Rosemary.GetWireValue[h.simulation, dw.instantiationPath, dw.wire, h.bitBucket]; new _ Ports.LevelSequenceToRope[h.bitBucket, dw.wireSize]; IF NOT Rope.Equal[new, ViewerTools.GetContents[dwvs.first.textViewer]] THEN ViewerTools.SetContents[dwvs.first.textViewer, new]; ENDLOOP; }; NextBuf: PROC [h: Tester, buf: NAT] RETURNS [next: NAT] = { next _ (buf + 1) MOD h.historySize; }; UpdateESSC: PROC [h: Tester, new: NAT] = { h.evalSinceStartCount _ h.evalSinceStartCount + 1; ViewerTools.SetContents[h.evalsSinceStart, Convert.RopeFromCard[from: h.evalSinceStartCount, showRadix: FALSE]]; }; DisplayPortLeafWires: PUBLIC PROC [wire: Core.Wire, instantiationPath: Rosemary.InstantiationPath _ NIL] RETURNS [displayWires: DisplayWires _ NIL] = { FindLeaves: CoreOps.EachWireProc = { IF Ports.WirePortType[wire]#composite THEN { subWires _ FALSE; dws _ CONS[[instantiationPath: instantiationPath, wire: wire], dws]; }; }; dws: DisplayWires _ NIL; IF CoreOps.VisitWire[wire, FindLeaves] THEN ERROR; FOR d: DisplayWires _ dws, d.rest UNTIL d=NIL DO displayWires _ CONS[d.first, displayWires]; ENDLOOP; }; WireValue: PUBLIC PROC [simulation: Rosemary.Simulation, name: ROPE, base: NAT _ 16] RETURNS [val: ROPE _ NIL] = { DiscoverWire: CoreOps.EachWireProc = { IF CoreOps.IsFullWireName[root, wire, name] THEN { namedWire _ wire; matchCount _ 1; quit _ TRUE; } ELSE IF Rope.Equal[name, CoreOps.GetShortWireName[wire]] THEN { namedWire _ wire; matchCount _ matchCount + 1; }; }; namedWire: Core.Wire _ NIL; root: Core.Wire _ simulation.coreCellType.public; matchCount: NAT _ 0; [] _ CoreOps.VisitWire[root, DiscoverWire]; IF matchCount=1 THEN { container: Ports.LevelSequence _ NEW[Ports.LevelSequenceRec[ CoreOps.WireBits[namedWire]]]; Rosemary.GetWireValue[simulation, NIL, namedWire, container]; val _ Ports.LevelSequenceToRope[container, container.size, base]; }; }; END. NRosemaryUserImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Barth, March 25, 1986 10:56:22 am PST Louis Monier January 17, 1986 5:30:28 pm PST Last Edited by: Gasbarro January 23, 1986 11:45:55 am PST Last Edited by: Neil Gunther February 27, 1986 11:29:46 am PST check new state same as recorded state; Κ³– "cedar" style˜codešœ™Kšœ Οmœ1™K™—KšΟk œJžœg˜ΌK˜•StartOfExpansion[]šΟbœžœž˜Kšžœ7žœI˜‰Kšžœ ˜Kšœžœžœ˜—J˜Jšœžœžœ˜J˜Jšœ žœΟc&˜=Jšœ žœ '˜>Jšœžœ "˜˜^Jšœ˜Jšœ žœ˜šžœ,žœžœž˜?Kšœ˜Kšœ ˜ Kšœ?˜?Kšœ žœžœžœ˜Kšœ˜šžœžœžœ˜Kšœ3˜3Kšœžœ ˜K˜—šžœ˜Kšžœ žœžœžœ˜0Kšœžœ˜#K˜—K˜Kšœ:˜:Kšœžœl˜tKš œžœfžœ žœžœžœžœR˜κšžœžœ žœ˜Jšœ ˜ Jšœ,˜,Jšœ˜—Jšžœ˜Kšœžœ˜,Kšžœ˜—Jšžœ žœ-˜=Kšœžœ&˜7Kšœa˜aKšœ˜K˜J˜—šžœžœžœ˜Jšœ˜š žœžœžœ$žœžœž˜DJšœžœ&˜Bšœžœ,˜CJšœ$˜$Jšœ˜JšœžœD˜`—šžœžœ žœ˜Jšœ ˜ Jšœ,˜,Jšœ˜—Jšžœ˜Jšžœ˜—Jšžœ žœ-˜=Jšœ>˜>Jšœa˜aJšœ˜J˜—Jšœ+˜+J˜KšœΨžœ žœ˜οJšœ#˜#Jšœ.˜.Jšœ(˜(Jšœ#˜#J˜J˜—š‘œ˜&Kšœžœ ˜#Kšœ˜Kšœ'žœ ˜6š žœžœžœ+žœžœž˜GKšœ!žœžœžœ˜cKšžœ˜—Kšœ˜Kšœ˜K˜—šœ žœžœ˜K˜—š‘ œ˜!Kšœ žœ ˜Kšžœžœžœ˜-Kšœ˜K˜—š‘ œžœ˜!K˜š‘œžœ˜K˜š‘ œ˜#Kšœ˜Kšžœžœžœžœ,žœžœžœžœžœ˜»K˜K˜—šž˜Kšœžœ-žœ˜LJšœžœžœ7žœ ˜kJšœ<˜˜\šžœ˜ Kšœ˜Kšœ;˜;Kšœ'˜'K˜K˜——Kšœ˜—Kšœ˜K˜—š‘ œžœžœ žœ˜@K˜š‘œžœžœ žœ˜AKšžœžœžœ ˜šžœ˜Kšœžœ˜)Kšœžœžœ˜Kšžœžœžœ6žœ˜QK˜—K˜K˜—KšœT˜TKšœ˜K˜—š‘œžœžœžœ žœ žœ žœ˜\šžœžœžœ˜Kšœ˜Kšœ ˜ Kšžœžœ˜8Kšœ˜K˜—Kšœ˜Kšž œ ˜Kšœ˜K˜—š ‘ œžœžœ žœ žœ˜?Kšœžœžœ˜š žœ%žœžœžœ ž˜LKšœ˜Jšœ3˜3Kšœžœ˜Kšž œ ˜Kšœ žœ˜Kšžœ ˜Kšœ žœ˜Jšžœ˜—Jšžœžœ0˜EK˜Kšœ˜K˜—š‘ œžœ˜#š žœžœžœ9žœžœž˜[Kšœžœ˜6Kšœžœ˜ KšœP˜PKšœ:˜:KšžœžœAžœ5˜€Kšžœ˜—K˜K˜—š ‘œžœžœžœžœ˜;Kšœžœ˜#K˜K˜—š‘ œžœžœ˜*Kšœ2˜2Kšœhžœ˜pK˜K˜—š ‘œžœžœCžœžœžœ˜—K˜š‘ œ˜$šžœ$žœ˜,Kšœ žœ˜Kšœžœ:˜DK˜—K˜K˜—Kšœžœ˜Kšžœ%žœžœ˜2šžœžœžœž˜0Kšœžœ˜+Kšžœ˜—K˜K˜—š‘ œžœžœ)žœžœžœžœžœ˜rK˜š‘ œ˜&šžœ*žœ˜2Kšœ˜Kšœ˜Kšœžœ˜ K˜—šžœžœ2žœ˜?Kšœ˜Kšœ˜K˜—K˜K˜—Kšœžœ˜Kšœ1˜1Kšœ žœ˜Kšœ+˜+šžœžœ˜Kšœ!žœ7˜[Kšœ"žœ˜=KšœA˜AK˜—K˜K˜—Kšžœ˜—…—>ξQο