DIRECTORY CardTab, Convert, IO, FS, Process, Rope, SoftcardMonitor, SoftcardMonitorExch, SparcSoftcardLoaderOps, SparcSoftcardOps, SparcSymbols, SymTab, ViewerIO; SoftcardMonitorImpl: CEDAR MONITOR IMPORTS CardTab, Convert, IO, FS, Process, Rope, SoftcardMonitorExch, SparcSoftcardLoaderOps, SparcSoftcardOps, SparcSymbols, SymTab, ViewerIO EXPORTS SoftcardMonitor ~ BEGIN QUIT: CARD32 = SoftcardMonitorExch.QUIT; SPARCDEAD: CARD32 = 0; MONTRACE: CARD32 = 8; MONENTER: CARD32 = MONTRACE+1; MONDISPLAY: CARD32 = MONENTER+1; MONFILL: CARD32 = MONDISPLAY+1; MONOPEN8: CARD32 = MONFILL+1; MONOPEN16: CARD32 = MONOPEN8+1; MONOPEN32: CARD32 = MONOPEN16+1; MONDUMP: CARD32 = MONOPEN32+1; MONBRK: CARD32 = MONDUMP+1; MONCALL: CARD32 = MONBRK+1; firstAvailableCode: CARD32 _ MONCALL+1; --so that it can be looked at with the interpreter ROPE: TYPE ~ Rope.ROPE; CommandProcHandle: TYPE ~ REF CommandProcHandleRec; CommandProcHandleRec: TYPE ~ RECORD[ cmd: ROPE, doc: ROPE, proc: SoftcardMonitor.CommandProc ]; CheckTool: PROC ~ { IF in=NIL THEN GOTO CreateOne; IF IO.EndOf[in ! IO.Error => GOTO CreateOne] THEN GOTO CreateOne; EXITS CreateOne => CreateTool[]; }; CreateTool: PROC ~ { [in, out] _ ViewerIO.CreateViewerStreams[name: "Puff Monitor"]; TRUSTED { monitorProcess _ FORK DoMonitor[]; Process.Detach[monitorProcess]; }; }; nestingRope: ROPE _ "~"; prompt: ROPE _ "> "; PutPrompt: PROC ~ { IO.PutF[out, "%l%g%l", IO.rope["b"], IO.rope[prompt], IO.rope["B"]]; }; DoMonitor: PROC ~ { state: SoftcardMonitor.State _ NEW[SoftcardMonitor.StateRec]; DO quit: BOOLEAN _ FALSE; WaitForMonitorStart[]; UNTIL quit DO found: BOOLEAN; val: SymTab.Val; cmdLine: ROPE ; args: SoftcardMonitor.Arguments; PutPrompt[]; cmdLine _ IO.GetLineRope[in]; args _ ParseToTokens[cmdLine]; IF args#NIL THEN { [found, val] _ SymTab.Fetch[cmdTable, args[0]]; IF found THEN { ENABLE Convert.Error => {IO.PutRope[out, "Invalid number\n"]; CONTINUE}; proc: SoftcardMonitor.CommandProc _ NARROW[val, CommandProcHandle].proc; quit _ proc[args, in, out, state]; } ELSE IO.PutF[out, "*** cmd ""%g"" unknown\n", IO.rope[args[0]]]; }; ENDLOOP; IO.PutF[out, "%l%gmonitor exited\n%l", IO.rope["b"], IO.rope[prompt], IO.rope["B"]]; prompt _ Rope.Substr[base: prompt, start: Rope.Length[nestingRope]]; DisableMonitor[]; ENDLOOP; }; ActionDisplay: SoftcardMonitorExch.ActionProc ~ { i: CARD32 _ 0; IF data1=0 AND data2=0 THEN { ReleaseLock[]; RETURN; }; CheckTool[]; IO.PutF[out, "%l", IO.char['f]]; WHILE r.length>i DO modulo: NAT _ 0; lineSize: CARD32 _ MIN[16, r.length-i]; letters: ROPE _ Rope.FromRefText[r, i, lineSize]; IO.PutF[out, "%8x: ", IO.card[data1]]; FOR j: CARD32 IN [i..i+lineSize) DO IO.PutF[out, "%02x", IO.card[ORD[r[j]]]]; modulo _ modulo+1; IF modulo=4 THEN { IO.PutRope[out, " "]; modulo _ 0; }; ENDLOOP; FOR j: CARD32 IN [i+lineSize..i+16) DO IO.PutRope[out, " "]; modulo _ modulo+1; IF modulo=4 THEN { IO.PutRope[out, " "]; modulo _ 0; }; ENDLOOP; IO.PutF[out, "\t%g\n", IO.rope[letters]]; data1 _ data1+16; i _ i+16; ENDLOOP; IO.PutF[out, "%l", IO.char['F]]; }; ActionDump: SoftcardMonitorExch.ActionProc ~ { i: CARD32 _ 0; ireg: NAT _ 0; CheckTool[]; IO.PutF[out, "%l", IO.rope["f"]]; WHILE r.length>i DO lineSize: CARD32 _ MIN[4, r.length-i]; IO.PutF[out, "r%02d: ", IO.card[ireg]]; FOR j: CARD32 IN [i..i+lineSize) DO IO.PutF[out, "%02x", IO.card[ORD[r[j]]]]; ENDLOOP; i _ i+lineSize; IF (i MOD 16) =0 THEN IO.PutChar[out, '\n] ELSE IO.PutChar[out, ' ]; ireg _ ireg+1; ENDLOOP; IO.PutF[out, "%l", IO.rope["F"]]; ReleaseLock[]; }; ActionTrace: SoftcardMonitorExch.ActionProc ~ { CheckTool[]; IO.PutF[out, "%8xH, %8xH\n", IO.card[data1], IO.card[data2]]; }; ActionEnter: SoftcardMonitorExch.ActionProc ~ { CheckTool[]; SELECT data1 FROM 0 => IO.PutF[out, "\n***** UNEXPECTED TRAP # %d *****\n\n", IO.card[data2]]; 1 => IO.PutF[out, "\n***** UNCAUGHT ERROR *****\n\n"]; ENDCASE => IO.PutF[out, "\n***** BREAKPOINT # %x *****\n\n", IO.card[data2]]; prompt _ Rope.Concat[nestingRope, prompt]; IF monitorlevel#0 THEN PutPrompt[]; ReleaseLock[]; EnableMonitor[]; }; ActionCall: SoftcardMonitorExch.ActionProc ~ { CheckTool[]; IO.PutF[out, "returns : %8xH\n", IO.card[data2]]; ReleaseLock[]; }; ActionBrk: SoftcardMonitorExch.ActionProc ~ { IF data2#0 THEN [] _ CardTab.Insert[brktable, data1, NEW[CARD _ data2]]; }; ActionDead: SoftcardMonitorExch.ActionProc ~ { CheckTool[]; IO.PutRope[out, "\n***** INTERNAL SPARC ERROR *****\n\n"]; }; Register: PUBLIC PROC [cmd, doc: ROPE, proc: SoftcardMonitor.CommandProc] ~ { cmdH: CommandProcHandle _ NEW[CommandProcHandleRec _ [cmd, doc, proc]]; [] _ SymTab.Store[cmdTable, cmd, cmdH]; }; waitForAnswer: BOOLEAN _ FALSE; answerReceived: CONDITION; ReleaseLock: ENTRY PROC ~ { ENABLE UNWIND => NULL; waitForAnswer _ FALSE; BROADCAST answerReceived; }; WaitForLock: ENTRY PROC ~ { ENABLE UNWIND => NULL; WHILE waitForAnswer DO WAIT answerReceived ENDLOOP; }; waitForMonitor: BOOLEAN _ TRUE; monitorReady: CONDITION; monitorlevel: NAT _ 0; DisableMonitor: ENTRY PROC ~ { ENABLE UNWIND => NULL; monitorlevel _ monitorlevel-1; IF monitorlevel=0 THEN waitForMonitor _ TRUE; }; EnableMonitor: ENTRY PROC ~ { ENABLE UNWIND => NULL; monitorlevel _ monitorlevel+1; waitForMonitor _ FALSE; BROADCAST monitorReady; }; WaitForMonitorStart: ENTRY PROC ~ { ENABLE UNWIND => NULL; WHILE waitForMonitor DO WAIT monitorReady ENDLOOP; }; ParseToTokens: PROC [line: ROPE] RETURNS [args: SoftcardMonitor.Arguments] ~ { ris: IO.STREAM _ IO.RIS[line]; argc: NAT _ 0; aList: LIST OF ROPE _ NIL; {UNTIL IO.EndOf[ris] DO aList _ CONS[IO.GetTokenRope[ris, IO.IDProc ! IO.EndOfStream => GOTO Exit].token, aList]; argc _ argc+1; ENDLOOP; EXITS Exit => {}; }; IF argc=0 THEN RETURN; args _ NEW[SoftcardMonitor.ArgumentsRec[argc]]; FOR i: NAT DECREASING IN [0..argc) DO args[i] _ aList.first; aList _ aList.rest; ENDLOOP; }; UnixCardFromRope: PROC [r: ROPE] RETURNS [c: CARD] ~ { IF Rope.Length[r]=1 THEN RETURN[0]; c _ SELECT Rope.Fetch[r, 1] FROM 'x => Convert.CardFromRope[Rope.Substr[base: r, start: 2], 16], -- skip the `0x' part ENDCASE => Convert.CardFromRope[r, 8]; }; CardFromRope: PROC [r: ROPE, state: SoftcardMonitor.State] RETURNS [c: CARD _ 0] ~ { c _ SELECT Rope.Fetch[r, 0] FROM '0 => UnixCardFromRope[r], '* => state.here, ENDCASE => Convert.CardFromWholeNumberLiteral[r]; }; PutByteInBuf: PROC [val: CARD32, r: REF TEXT, start: NAT] ~ { c: [0..100h); --Don't ask me why the compiler asks for an intermediate range variable r.length _ r.length+1; c _ val; r[start] _ VAL[c]; }; PutWordInBuf: PROC [val: CARD32, r: REF TEXT, start: NAT] ~ { c: [0..100h); --Don't ask me why the compiler asks for an intermediate range variable r.length _ r.length+2; c _ val/100h; r[start] _ VAL[c]; c _ val-100h*c; r[start+1] _ VAL[c]; }; PutLongInBuf: PROC [val: CARD32, r: REF TEXT, start: CARD32] ~ { c: [0..100h); --Don't ask me why the compiler asks for an intermediate range variable r.length _ r.length+4; c _ val/1000000h; r[start] _ VAL[c]; val _ val-1000000h*c; c _ val/10000h; r[start+1] _ VAL[c]; val _ val-10000h*c; c _ val/100h; r[start+2] _ VAL[c]; val _ val-100h*c; c _ val; r[start+3] _ VAL[c]; }; FillSymbols: PROC ~ { s: IO.STREAM _ NIL; name: ROPE; IO.PutRope[out, "Enter file name : "]; name _ IO.GetLineRope[in]; s _ FS.StreamOpen[name ! FS.Error => { IO.PutF[out, "***** %g\n", IO.rope[error.explanation]]; CONTINUE; }]; IF s#NIL THEN symbols _ SparcSymbols.GetSymbols[s]; }; savedInputFile: IO.STREAM _ NIL; ResetMonitor: PUBLIC PROC [inputFile: IO.STREAM _ NIL] ~ { FOR i: NAT IN [0..monitorlevel) DO prompt _ Rope.Substr[base: prompt, start: Rope.Length[nestingRope]]; ENDLOOP; monitorlevel _ 0; waitForMonitor _ TRUE; waitForAnswer _ FALSE; IF monitorProcess#NIL THEN TRUSTED { Process.Abort[monitorProcess ! Process.InvalidProcess => CONTINUE]; monitorProcess _ NIL; }; IF in#NIL THEN IO.Close[in]; in _ NIL; symbols _ NIL; savedInputFile _ inputFile; SoftcardMonitorExch.Restart[]; }; Break: PUBLIC PROC ~ TRUSTED { SparcSoftcardOps.SetSparcToSparcInt[] }; DisplayCmd: SoftcardMonitor.CommandProc ~ { first: CARD32 _ IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state]; last: CARD32 _ IF args.argc<3 THEN first+4 ELSE CardFromRope[args[2], state]; waitForAnswer _ TRUE; state.here _ last; SoftcardMonitorExch.PutPacket[MONDISPLAY, first, last]; WaitForLock[]; }; DumpCmd: SoftcardMonitor.CommandProc ~ { addr: CARD32 _ IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state]; waitForAnswer _ TRUE; SoftcardMonitorExch.PutPacket[MONDUMP, addr]; WaitForLock[]; }; FillCmd: SoftcardMonitor.CommandProc ~ { first: CARD32 _ IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state]; last: CARD32 _ IF args.argc<3 THEN first+1 ELSE CardFromRope[args[2], state]; val: CARD32 _ IF args.argc<4 THEN 0 ELSE CardFromRope[args[3], state]; format: {b, w, l}; format _ IF args.argc>4 THEN SELECT Rope.Fetch[args[4]] FROM 'b, 'B => b, 'w, 'W => w, 'l, 'L => l, ENDCASE => b ELSE SELECT val FROM IN [0..100h) => b, IN [100h..10000h) => w, ENDCASE => l; state.here _ last; IF val# 0 THEN { --beware of the Cedar (weird) byte order... r: REF TEXT _ NEW[TEXT[4]]; r.length _ 0; SELECT format FROM b => PutByteInBuf[val, r, 0]; w => { IF first MOD 2#0 THEN { IO.PutF[out, "%x: invalid 16 bits address\n", IO.card[first]]; RETURN; }; PutWordInBuf[val, r, 0]; }; ENDCASE => { IF first MOD 4#0 THEN { IO.PutF[out, "%x: invalid 32 bits address\n", IO.card[first]]; RETURN; }; PutLongInBuf[val, r, 0]; }; SoftcardMonitorExch.PutPacket[MONFILL, first, last, r]; } ELSE SoftcardMonitorExch.PutPacket[MONFILL, first, last]; }; Open8Cmd: SoftcardMonitor.CommandProc ~ { add: CARD32 _ IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state]; val: CARD32 _ IF args.argc<3 THEN 0 ELSE CardFromRope[args[2], state]; SoftcardMonitorExch.PutPacket[MONOPEN8, add, val]; }; Open16Cmd: SoftcardMonitor.CommandProc ~ { add: CARD32 _ IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state]; val: CARD32 _ IF args.argc<3 THEN 0 ELSE CardFromRope[args[2], state]; IF add MOD 2#0 THEN IO.PutF[out, "%x: invalid 16 bits address\n", IO.card[add]] ELSE SoftcardMonitorExch.PutPacket[MONOPEN16, add, val]; }; Open32Cmd: SoftcardMonitor.CommandProc ~ { add: CARD32 _ IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state]; val: CARD32 _ IF args.argc<3 THEN 0 ELSE CardFromRope[args[2], state]; IF add MOD 4#0 THEN IO.PutF[out, "%x: invalid 32 bits address\n", IO.card[add]] ELSE SoftcardMonitorExch.PutPacket[MONOPEN32, add, val]; }; SetBrkCmd: SoftcardMonitor.CommandProc ~ { add: CARD32 _ IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state]; IF add MOD 4#0 THEN IO.PutF[out, "%x: invalid 32 bits address\n", IO.card[add]] ELSE SoftcardMonitorExch.PutPacket[MONBRK, add, 0]; }; ClearBrkCmd: SoftcardMonitor.CommandProc ~ { add: CARD32 _ IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state]; IF add MOD 4#0 THEN IO.PutF[out, "%x: invalid 32 bits address\n", IO.card[add]] ELSE { found: BOOLEAN; val: CardTab.Val; [found, val] _ CardTab.Fetch[brktable, add]; IF found THEN { SoftcardMonitorExch.PutPacket[MONBRK, add, NARROW[val, REF CARD]^]; [] _ CardTab.Delete[brktable, add]; } ELSE IO.PutF[out, "%x: no break (known) there\n", IO.card[add]]; }; }; CallCmd: SoftcardMonitor.CommandProc ~ { nArgs, addr: CARD32; IF args.argc<2 OR args.argc>7 THEN RETURN; IF symbols=NIL THEN FillSymbols[]; IF symbols=NIL THEN RETURN; addr _ SparcSymbols.GetAddress[args[1], symbols]; IF addr=0 THEN { addr _ SparcSymbols.GetAddress[Rope.Cat["_", args[1]], symbols]; IF addr=0 THEN {IO.PutRope[out, "unknown function\n"]; RETURN} ELSE IO.PutF[out, "using _%g instead\n", [rope[args[1]]] ]; }; nArgs _ args.argc-2; r.length _ 0; FOR i: CARD32 IN [0..nArgs) DO PutLongInBuf[CardFromRope[args[i+2], state], r, 4*i]; ENDLOOP; waitForAnswer _ TRUE; SoftcardMonitorExch.PutPacket[MONCALL, addr, nArgs, r]; WaitForLock[]; }; ContinueCmd: SoftcardMonitor.CommandProc ~ { SoftcardMonitorExch.PutPacket[QUIT]; quit _ TRUE; }; ListBrkCmd: SoftcardMonitor.CommandProc ~ { PrintOne: CardTab.EachPairAction ~ { opcode: CARD32 _ NARROW[val, REF CARD]^; IO.PutF[out, "\t%8x (%8x)\n", IO.card[key], IO.card[opcode]]; }; [] _ CardTab.Pairs[brktable, PrintOne]; }; HelpCmd: SoftcardMonitor.CommandProc ~ { PrintOne: SymTab.EachPairAction ~ { doc: ROPE _ NARROW[val, CommandProcHandle].doc; IO.PutF[out, "\t%g %g\n", IO.rope[key], IO.rope[doc]]; }; IF args.argc<2 THEN [] _ SymTab.Pairs[cmdTable, PrintOne] ELSE FOR i: NAT IN [1..args.argc) DO found: BOOLEAN; val: SymTab.Val; [found, val] _ SymTab.Fetch[cmdTable, args[i]]; IF found THEN { doc: ROPE _ NARROW[val, CommandProcHandle].doc; IO.PutF[out, "\t%g %g\n", IO.rope[args[i]], IO.rope[doc]]; } ELSE IO.PutF[out, "%g: unknown\n", IO.rope[args[i]]]; ENDLOOP; }; TranslateCmd: SoftcardMonitor.CommandProc ~ { IF symbols=NIL THEN FillSymbols[]; IF symbols#NIL THEN { addr: CARD32 _ SparcSymbols.GetAddress[args[1], symbols]; IF addr=0 THEN addr _ SparcSymbols.GetAddress[Rope.Cat["_", args[1]], symbols]; IF addr=0 THEN { IO.PutRope[out, "unknown symbol"]; RETURN; } ELSE { name: ROPE _ SparcSymbols.GetClosestName[addr, symbols]; IO.PutF[out, "%g : %8xH\n", IO.rope[name], IO.card[addr]]; }; }; }; WhereIsCmd: SoftcardMonitor.CommandProc ~ { name: ROPE; addr: CARD32 _ IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state]; state.here _ addr; IF symbols=NIL THEN FillSymbols[]; IF symbols#NIL THEN { name _ SparcSymbols.GetClosestName[addr, symbols]; addr _ SparcSymbols.GetAddress[name, symbols]; IO.PutF[out, "%g : %8xH\n", IO.rope[name], IO.card[addr]]; }; }; r: REF TEXT _ NEW[TEXT[2048]]; in, out: IO.STREAM; monitorProcess: PROCESS _ NIL; cmdTable: SymTab.Ref _ SymTab.Create[]; brktable: CardTab.Ref _ CardTab.Create[]; symbols: SparcSymbols.Tables _ NIL; Register["h", "cmd1 cmd2 ...: prints doc on commands", HelpCmd]; Register["?", "cmd1 cmd2 ...: prints doc on commands", HelpCmd]; Register["v", "firstAdd lastAdd : displays memory", DisplayCmd]; Register["d", " : dumps register contents", DumpCmd]; Register["f", "firstAdd lastAdd [val _0] [format]: fills memory with val; \n\tuses byte word(16) or long (32) chunks depending on format if specified or val size otherwise", FillCmd]; Register["o", "add [val _0] : puts byte val at add", Open8Cmd]; Register["e", "add [val _0] : puts short val at add", Open16Cmd]; Register["l", "add [val _0] : puts long val at add", Open32Cmd]; Register["c", "gives the control back to the Sparc", ContinueCmd]; Register["cb", "add : clears the breakpoint at add", ClearBrkCmd]; Register["sb", "add : sets a breakpoint at add", SetBrkCmd]; Register["lb", " : lists all breakpoints", ListBrkCmd]; Register["tr", "name: translates a name to hexa", TranslateCmd]; Register["whereis", "add: finds the closest ext name to such add", WhereIsCmd]; Register["call", "name arg0 ...): calls the function(5 32b args max)", CallCmd]; SoftcardMonitorExch.Register[SPARCDEAD, ActionDead, NIL]; SoftcardMonitorExch.Register[MONTRACE, ActionTrace, NIL]; SoftcardMonitorExch.Register[MONENTER, ActionEnter, NIL]; SoftcardMonitorExch.Register[MONDISPLAY, ActionDisplay, r]; SoftcardMonitorExch.Register[MONDUMP, ActionDump, r]; SoftcardMonitorExch.Register[MONBRK, ActionBrk, NIL]; SoftcardMonitorExch.Register[MONCALL, ActionCall, NIL]; SparcSoftcardLoaderOps.RegisterStartProc[$SparcMonitor, ResetMonitor]; END. HSoftcardMonitorImpl.mesa Copyright Σ 1987 by Xerox Corporation. All rights reserved. written by Ch. Le Cocq, September 6, 1988 Christian Le Cocq October 31, 1988 4:55:43 pm PST Christophe Cuenod October 19, 1988 4:48:25 pm PDT Softcard Debugger. Description of the procedure. Utilities Commands local commands Κ˜code•Mark outsideHeaderšœ™Kšœ<™Kšœ˜K˜—Kšœ˜Kšœ˜—šœ˜ šœœœ˜Kšœ,œ˜>Kšœ˜K˜—Kšœ˜Kšœ˜——Kšœœ˜7K˜—Kšœœ˜9K˜K˜—š œ!˜)Kš œœœ œ œ˜OKš œœœ œœ˜FKšœœ ˜2K˜K˜—š  œ!˜*Kš œœœ œ œ˜OKš œœœ œœ˜FKš œœœœ,œ ˜OKšœ œ ˜8K˜K˜—š  œ!˜*Kš œœœ œ œ˜OKš œœœ œœ˜FKš œœœœ,œ ˜OKšœ œ ˜8K˜K˜—š  œ!˜*Kš œœœ œ œ˜OKš œœœœ,œ ˜OKšœœ ˜3K˜K˜—š  œ!˜,Kš œœœ œ œ˜OKš œœœœ,œ ˜Ošœ˜Kšœœ˜Kšœ˜Kšœ,˜,šœœ˜Kš œœœœœ˜CKšœ#˜#K˜—Kšœœ+œ ˜@K˜—K˜K˜—š œ!˜(Kšœ œ˜Kšœ œ œœ˜*Kšœ œœ˜"Kšœ œœœ˜Kšœ1˜1šœœ˜Kšœ@˜@Kšœœœ$œ˜>Kšœœ4˜;K˜—Kšœ˜K˜ šœœœ ˜Kšœ5˜5Kšœ˜—Kšœœ˜Kšœœ˜7Kšœ˜K˜K˜—š  œ!˜,Kšœœ˜$Kšœœ˜ K˜K˜—L™š  œ!˜+š œ˜$Kš œœœœœ˜(Jšœœ œ˜=J˜—Jšœ'˜'K˜K˜—š œ!˜(š œ˜#Kšœœœ˜/Jšœœ œ ˜6J˜K˜—Kšœ œ&˜9š œœœœ˜$Jšœœ˜Jšœ˜Jšœ/˜/šœœ˜Kšœœœ˜/Jšœœœ ˜:K˜—Kšœœœ˜5Kšœ˜—K˜K˜—š  œ!˜-Kšœ œœ˜"šœ œœ˜Jšœœ-˜9Jšœœœ9˜Ošœœ˜Jšœ ˜"Jšœ˜J˜—šœ˜Jšœœ.˜8Jšœœ œ ˜:J˜—J˜—K˜K˜—š  œ!˜+Kšœœ˜ Kš œœœ œ œ˜PKšœ˜Kšœ œœ˜"šœ œœ˜Jšœ2˜2Jšœ.˜.Jšœœ œ ˜:J˜—K˜K˜—Kš œœœœœ˜Kšœ œœ˜Kšœœœ˜Kšœ'˜'Kšœ)˜)Kšœœ˜#Kšœ@˜@Kšœ@˜@Kšœ@˜@Kšœ5˜5Kšœ·˜·Kšœ?˜?KšœA˜AKšœ@˜@KšœB˜BKšœB˜BKšœ<˜