DIRECTORY Ascii USING [CR, NUL], Commander USING [CommandProc, Register], Exec USING [AddCommand, GetChar, status, w], File USING [Capability], Heap USING [Create, Delete], Inline USING [LongCOPY], IO USING [EndOf, GetChar, RIS, STREAM], LongString USING [AppendString, EquivalentString, InvalidNumber, StringToDecimal], MB USING [ Abort, BCount, BHandle, BIndex, BObject, DumpBootHeader, DumpFrames, DumpInputBcds, DumpStartList, EchoInput, Error, FinishCache, FinishDebug, FinishLoader, FinishLoadmap, FinishMain, FinishOutput, FinishParse, FinishScript, FinishUtilities, FinishVM, Handle, InitCache, InitDebug, InitLoader, InitLoadmap, InitMain, InitMemory, InitOutput, InitParse, InitScript, InitUtilities, InitVM, InputBCDs, Load, MakeScript, Object, ProcessInput, ReportFrameAllocation, TurnOffStartTrap, WriteBootFile, WriteGermFile], MBCommandUtil USING [ CommandObject, CommandPtr, CopyString, Create, Destroy, Failed, FreePairList, FreeString, GetNthPair, ListLength, PairList, Parse, SetExtension], MBOut USING [Char, CR, OpenLoadmap, Spaces, Text, Time], MBTTY USING [ Handle, PutChar, PutCR, PutDecimal, PutLine, PutLongDecimal, PutLongNumber, PutString, UserAbort], PrincOps USING [GFTIndex], PSB USING [PsbIndex], Runtime USING [CallDebugger, GetBcdTime, GlobalFrame, IsBound], RuntimeInternal USING [Codebase], Segments USING [FHandle, FileNameProblem, FPFromFile, GetFileTimes, NewFile, ReleaseFile], Space USING [GetAttributes, GetHandle, GetWindow, Handle, PageFromLongPointer], Time USING [Append, Current, Packed, Unpack], TTYIO USING [CreateTTYHandleFromStreams], Volume USING [InsufficientSpace]; MBDriver: MONITOR IMPORTS Commander, Exec, Heap, Inline, IO, MB, MBCommandUtil, MBOut, MBTTY, Runtime, RuntimeInternal, Segments, Space, String: LongString, Time, TTYIO, Volume EXPORTS MB SHARES File = BEGIN useCommander: BOOL = Runtime.IsBound[Commander.Register]; -- *** temporary data: MB.Handle _ NIL; tty: MBTTY.Handle; commandStream: IO.STREAM; Outcome: TYPE = Exec.status; RunFromCommander: Commander.CommandProc = TRUSTED { commandStream _ IO.RIS[cmd.commandLine]; tty _ TTYIO.CreateTTYHandleFromStreams[in: cmd.in, out: cmd.out]; [] _ DoRun[]; }; RunFromExec: PROC = { tty _ Exec.w; [] _ DoRun[]; }; DoRun: ENTRY PROC RETURNS [outcome: Outcome] = { ENABLE UNWIND => NULL; WriteHerald[Time.Current[]]; DO -- until no commands remain start: LONG CARDINAL _ Time.Current[]; nFilePages, nModules, nGFIs, nResidentPages, nBootLoadedPages: CARDINAL; outcome _ abort; Initialize[]; outcome _ DoWork[ ! UNWIND => Finalize[]; MB.Abort, ABORTED => CONTINUE; Volume.InsufficientSpace => {MBTTY.PutLine[tty, "!Disk full"L]; CONTINUE}; Segments.FileNameProblem[] => { MBTTY.PutString[tty, "!Can't find "L]; MBTTY.PutLine[tty, name]; CONTINUE } ]; SELECT outcome FROM normal => { nFilePages _ data.nFilePages; nModules _ data.nModules; nGFIs _ data.nGFIs; nResidentPages _ data.nResidentPages; nBootLoadedPages _ data.nBootLoadedPages; }; abort => {MBTTY.PutLine[tty, "...MakeBoot aborted"L]; EXIT}; spare1 --no commands remain-- => {outcome _ normal; EXIT}; ENDCASE --warning or error-- => EXIT; Finalize[]; ReportStats[ nFilePages: nFilePages, nModules: nModules, nGFIs: nGFIs, nResidentPages: nResidentPages, nBootLoadedPages: nBootLoadedPages, elapsedTime: (LOOPHOLE[Time.Current[], LONG CARDINAL] - start)]; ENDLOOP; Finalize[]; }; WriteHerald: PROC [now: Time.Packed] = { herald: STRING _ [80]; MakeBootVersion[herald]; MBTTY.PutLine[tty, herald]; herald.length _ 0; Time.Append[herald, Time.Unpack[[now]]]; herald.length _ herald.length-3; -- remove seconds MBTTY.PutLine[tty, herald]; }; Initialize: PROC = { InitDriver[]; MB.InitCache[data]; MB.InitDebug[data]; MB.InitLoader[data]; MB.InitLoadmap[data]; MB.InitMain[data]; MB.InitOutput[data]; MB.InitParse[data]; MB.InitScript[data]; MB.InitUtilities[data]; MB.InitVM[data]; }; Finalize: PROC = { MB.FinishOutput[]; MB.FinishLoader[]; MB.FinishVM[]; MB.FinishUtilities[]; MB.FinishScript[]; MB.FinishParse[]; MB.FinishMain[]; MB.FinishLoadmap[]; MB.FinishDebug[]; MB.FinishCache[]; FinishDriver[]; }; InitDriver: PROC = { zone: UNCOUNTED ZONE _ Heap.Create[initial: 4, swapUnit: 1]; data _ zone.NEW[MB.Object]; Zero[data, SIZE[MB.Object]]; data.zone _ zone; data.buildTime _ Time.Current[]; data.ttyHandle _ tty; data.inputBCDs _ data.zone.NEW[MB.InputBCDs[10] _ [nBcds: 1]]; data.inputBCDs.bcds[0] _ data.zone.NEW[MB.BObject _ [ name: NIL, bcd: NIL, bcdSeg: NIL, bcdSegment: NIL, mt: DESCRIPTOR[NIL, 0], gfiOffset: 0, files: NIL]]; }; FinishDriver: PROC = { zone: UNCOUNTED ZONE _ data.zone; [] _ MBCommandUtil.FreeString[data.input]; [] _ MBCommandUtil.FreeString[data.output]; [] _ MBCommandUtil.FreeString[data.etherOutput]; [] _ MBCommandUtil.FreeString[data.loadmap]; FOR i: MB.BIndex IN [0..data.inputBCDs.nBcds) DO IF data.inputBCDs.bcds[i] ~= NIL THEN { [] _ MBCommandUtil.FreeString[data.inputBCDs.bcds[i].name]; data.zone.FREE[@data.inputBCDs.bcds[i]]; }; ENDLOOP; zone.FREE[@data.inputBCDs]; zone.FREE[@data]; Heap.Delete[zone]; }; DoWork: PROC RETURNS [outcome: Outcome] = { CheckAbort: PROC = {IF MBTTY.UserAbort[tty] THEN ERROR MB.Abort}; CheckAbort[]; IF (outcome _ ProcessCmds[]) ~= normal THEN RETURN; MBOut.OpenLoadmap[]; MB.InitMemory[]; CheckAbort[]; EchoBCDs[]; MB.EchoInput[]; CheckAbort[]; MB.Load[]; CheckAbort[]; MB.TurnOffStartTrap[]; MB.ReportFrameAllocation[]; IF data.debug THEN {MB.DumpInputBcds[]; MB.DumpFrames[]}; CheckAbort[]; IF data.germ THEN MB.WriteGermFile[] ELSE { MB.MakeScript[]; CheckAbort[]; MB.WriteBootFile[]; }; CheckAbort[]; IF data.debug AND ~data.germ THEN {MB.DumpBootHeader[]; MB.DumpStartList[]}; RETURN[normal] }; ProcessCmds: PROC RETURNS [outcome: Outcome] = { args, results: MBCommandUtil.PairList; switches, sourceName: LONG STRING _ NIL; commandPtr: MBCommandUtil.CommandPtr _ MBCommandUtil.Create[GetChar]; GetChar: PROC RETURNS [char: CHARACTER] = { IF useCommander THEN { -- *** temporary IF commandStream.EndOf[] THEN RETURN [Ascii.NUL]; char _ commandStream.GetChar[]; IF char = Ascii.CR THEN char _ Ascii.NUL; } ELSE RETURN[Exec.GetChar[]]}; CleanupParse: PROC = { IF sourceName ~= NIL THEN { [] _ MBCommandUtil.FreeString[sourceName]; [] _ MBCommandUtil.FreePairList[args]; [] _ MBCommandUtil.FreePairList[results]; [] _ MBCommandUtil.FreeString[switches]; }; MBCommandUtil.Destroy[commandPtr]; }; BEGIN [sourceName, args, results, switches] _ MBCommandUtil.Parse[ cmd: commandPtr, opX: 2+("bcd"L).length, resultX: 2+("boot"L).length ! MBCommandUtil.Failed => GOTO badCommands]; IF sourceName = NIL THEN {CleanupParse[]; RETURN[outcome: spare1]}; -- no commands remain EXITS badCommands => { MBTTY.PutLine[tty, "!Bad MakeBoot command line"L]; CleanupParse[]; RETURN[outcome: error] } END; IF switches # NIL THEN { sense: BOOLEAN _ TRUE; FOR i: CARDINAL IN [0..switches.length) DO SELECT switches[i] FROM '-, '~ => sense _ ~sense; 'd, 'D => {data.debug _ sense; sense _ TRUE}; 'e, 'E => {data.etherFormat _ sense; sense _ TRUE}; 'g, 'G => {data.germ _ sense; sense _ TRUE}; 'h, 'H => {data.hexLoadmap _ sense; sense _ TRUE}; '! => Runtime.CallDebugger["Called from MakeBoot"L]; ENDCASE; ENDLOOP; }; data.input _ MBCommandUtil.CopyString[s: sourceName, extra: (".bcd"L).length]; data.input _ MBCommandUtil.SetExtension[root: data.input, defaultExt: "bcd"L]; data.inputBCDs.bcds[0].name _ MBCommandUtil.CopyString[data.input]; ProcessResults[results ! UNWIND => CleanupParse[]]; EchoCommand[]; ProcessArgs[args ! UNWIND => CleanupParse[]]; CleanupParse[]; RETURN[outcome: normal] }; EchoCommand: PROC = { MBTTY.PutString[tty, "Building "L]; MBTTY.PutString[tty, IF data.germ THEN "germ"L ELSE "boot"L]; MBTTY.PutString[tty, " file "L]; MBTTY.PutString[tty, data.output]; IF data.etherFormat THEN { MBTTY.PutString[tty, " and ether "L]; MBTTY.PutString[tty, IF data.germ THEN "germ"L ELSE "boot"L]; MBTTY.PutString[tty, " file "L]; MBTTY.PutString[tty, data.etherOutput]; }; MBTTY.PutCR[tty]; MBTTY.PutString[tty, "Writing load map to "L]; MBTTY.PutString[tty, data.loadmap]; MBTTY.PutCR[tty]; }; EchoBCDs: PROC = { MBOut.Text["Input BCD"L]; IF data.inputBCDs.nBcds ~= 0 THEN MBOut.Char['s]; MBOut.Char[':]; MBOut.CR[]; MBOut.CR[]; FOR i: CARDINAL IN [0..data.inputBCDs.nBcds) DO file: STRING = [40]; String.AppendString[file, data.inputBCDs.bcds[i].name]; MBOut.Spaces[2]; MBOut.Text[file, 39]; MBOut.Spaces[2]; {ENABLE Segments.FileNameProblem[] => CONTINUE; MBOut.Time[Segments.GetFileTimes[Segments.NewFile[file]].create]; }; MBOut.CR[]; ENDLOOP; MBOut.CR[]; }; ProcessResults: PROC [results: MBCommandUtil.PairList] = { key, value: LONG STRING; bootFileExt: LONG STRING = IF data.germ THEN "germ"L ELSE "boot"L; loadMapExt: LONG STRING = "loadmap"L; data.output _ data.etherOutput _ data.loadmap _ NIL; FOR i: CARDINAL IN [0..MBCommandUtil.ListLength[results]) DO [key: key, value: value] _ MBCommandUtil.GetNthPair[results, i]; SELECT TRUE FROM key = NIL => data.output _ MBCommandUtil.CopyString[s: value, extra: bootFileExt.length+1]; String.EquivalentString["bootFile"L, key] => IF data.output = NIL THEN data.output _ MBCommandUtil.CopyString[s: value, extra: bootFileExt.length+1] ELSE MB.Error["Duplicate result keyword 'bootFile'"L]; String.EquivalentString["loadMap"L, key] => IF data.loadmap = NIL THEN data.loadmap _ MBCommandUtil.CopyString[s: value, extra: loadMapExt.length+1] ELSE MB.Error["Duplicate result keyword 'loadMap'"L]; ENDCASE => MB.Error["Unrecognized result keyword"L]; ENDLOOP; IF data.output = NIL THEN StripExtension[data.output _ MBCommandUtil.CopyString[data.input]]; data.output _ MBCommandUtil.SetExtension[root: data.output, defaultExt: bootFileExt]; IF data.etherFormat THEN { etherExt: STRING = IF data.germ THEN "eg"L ELSE "pb"L; data.etherOutput _ MBCommandUtil.CopyString[s: data.output, extra: etherExt.length+1]; StripExtension[data.etherOutput]; data.etherOutput _ MBCommandUtil.SetExtension[root: data.etherOutput, defaultExt: etherExt]; }; EnsureNotCurrentBootFile[]; IF data.loadmap = NIL THEN StripExtension[data.loadmap _ MBCommandUtil.CopyString[data.output]]; data.loadmap _ MBCommandUtil.SetExtension[root: data.loadmap, defaultExt: loadMapExt]; }; StripExtension: PROC [s: LONG STRING] = { FOR i: CARDINAL IN [0..s.length) DO IF s[i] = '. THEN {s.length _ i; RETURN}; ENDLOOP; }; EnsureNotCurrentBootFile: PROC = { name: STRING _ [40]; cap: File.Capability; someBootFileCode: Space.Handle _ Space.GetHandle[Space.PageFromLongPointer[ RuntimeInternal.Codebase[Runtime.GlobalFrame[Space.GetHandle]]]]; file: Segments.FHandle; String.AppendString[name, data.output]; file _ Segments.NewFile[name ! Segments.FileNameProblem[] => GO TO ok]; Segments.FPFromFile[file, @cap]; Segments.ReleaseFile[file]; DO parent: Space.Handle; mapped: BOOL; [parent: parent, mapped: mapped] _ Space.GetAttributes[someBootFileCode]; IF mapped THEN EXIT; someBootFileCode _ parent; ENDLOOP; IF Space.GetWindow[someBootFileCode].file.fID = cap.fID THEN MB.Error["I refuse to overwrite the currently executing boot file."L]; EXITS ok => NULL; }; ProcessArgs: PROC [args: MBCommandUtil.PairList] = { key, value: LONG STRING; nProcesses, gftLength: CARDINAL _ LAST[CARDINAL]; FOR i: CARDINAL IN [0..MBCommandUtil.ListLength[args]) DO [key: key, value: value] _ MBCommandUtil.GetNthPair[args, i]; SELECT TRUE FROM String.EquivalentString["parm"L, key] => { parmFile: LONG STRING _ MBCommandUtil.CopyString[s: value, extra: (".bootmesa"L).length]; parmFile _ MBCommandUtil.SetExtension[root: parmFile, defaultExt: "bootmesa"L]; MBTTY.PutString[tty, "Processing parameter file "L]; MBTTY.PutString[tty, parmFile]; MB.ProcessInput[parmFile ! UNWIND => [] _ MBCommandUtil.FreeString[parmFile]]; parmFile _ MBCommandUtil.FreeString[parmFile]; MBTTY.PutCR[tty]; }; String.EquivalentString["bcd"L, key] => { bH: MB.BHandle; IF data.inputBCDs.nBcds = LAST[MB.BCount] - 1 --save slot for NullConfig-- THEN MB.Error["Too many input BCDs"L]; IF data.inputBCDs.nBcds = data.inputBCDs.length THEN { newLength: MB.BCount = MIN[2*data.inputBCDs.length, LAST[MB.BCount]]; newInputBCDs: LONG POINTER TO MB.InputBCDs _ data.zone.NEW[MB.InputBCDs[newLength] _ [nBcds: data.inputBCDs.nBcds]]; Inline.LongCOPY[ from: @data.inputBCDs.bcds[0], to: @newInputBCDs.bcds[0], nwords: data.inputBCDs.nBcds*SIZE[MB.BHandle]]; data.zone.FREE[@data.inputBCDs]; data.inputBCDs _ newInputBCDs}; bH _ data.zone.NEW[MB.BObject _ [ name: NIL, bcd: NIL, bcdSeg: NIL, bcdSegment: NIL, mt: DESCRIPTOR[NIL, 0], gfiOffset: 0, files: NIL]]; bH.name _ MBCommandUtil.CopyString[s: value, extra: (".bcd"L).length]; bH.name _ MBCommandUtil.SetExtension[root: bH.name, defaultExt: "bcd"L]; data.inputBCDs.bcds[data.inputBCDs.nBcds] _ bH; data.inputBCDs.nBcds _ data.inputBCDs.nBcds+1; }; String.EquivalentString["nProcesses"L, key] => { nProcesses _ String.StringToDecimal[value ! String.InvalidNumber => GO TO bogus]; IF ~(nProcesses-1 IN PSB.PsbIndex) THEN GO TO bogus; EXITS bogus => MB.Error["Invalid nProcesses"L]; }; String.EquivalentString["gftLength"L, key] => { gftLength _ String.StringToDecimal[value ! String.InvalidNumber => GO TO bogus]; IF ~(gftLength-1 IN PrincOps.GFTIndex) THEN GO TO bogus; EXITS bogus => MB.Error["Invalid gftLength"L]; }; ENDCASE => MB.Error["Unrecognized parameter keyword"L]; ENDLOOP; IF nProcesses ~= LAST[CARDINAL] THEN { data.nProcesses _ nProcesses; MBTTY.PutString[tty, "Number of processes set to "L]; MBTTY.PutDecimal[tty, nProcesses]; MBTTY.PutCR[tty]; }; IF gftLength ~= LAST[CARDINAL] THEN { data.gftLength _ gftLength; MBTTY.PutString[tty, "GFT length set to "L]; MBTTY.PutDecimal[tty, gftLength]; MBTTY.PutCR[tty]; }; }; ReportStats: PROC [ nFilePages, nModules, nGFIs, nResidentPages, nBootLoadedPages: CARDINAL, elapsedTime: LONG CARDINAL] = { OPEN MBTTY; PutString[tty, "Boot file pages: "L]; PutDecimal[tty, nFilePages]; PutString[tty, " ("L]; PutDecimal[tty, nBootLoadedPages]; PutString[tty, " bootloaded, of which "L]; PutDecimal[tty, nResidentPages]; PutLine[tty, " are resident)"L]; PutString[tty, "Modules: "L]; PutDecimal[tty, nModules]; PutString[tty, " (requiring "L]; PutDecimal[tty, nGFIs]; PutLine[tty, " GFIs)"L]; PutString[tty, "Time: "L]; IF elapsedTime > 60 THEN { PutLongDecimal[tty, elapsedTime/60]; PutChar[tty, ':]; elapsedTime _ elapsedTime MOD 60; }; PutLongNumber[tty, elapsedTime, [base: 10, zerofill: TRUE, unsigned: TRUE, columns: 2]]; PutCR[tty]; }; Abort: PUBLIC SIGNAL = CODE; Error: PUBLIC PROC [msg: STRING] = { MBTTY.PutCR[data.ttyHandle]; MBTTY.PutString[data.ttyHandle, "MakeBoot Error: "L]; MBTTY.PutLine[data.ttyHandle, msg]; SIGNAL MB.Abort; }; Zero: PUBLIC PROC [p: LONG POINTER, n: CARDINAL] = { IF n # 0 THEN {p^ _ 0; Inline.LongCOPY[from: p, to: p+1, nwords: n-1]}; }; MakeBootVersion: PUBLIC PROC [s: STRING] = { s.length _ 0; String.AppendString[s, "Cedar MakeBoot of "L]; Time.Append[s, Time.Unpack[Runtime.GetBcdTime[]]]; s.length _ s.length-3; -- remove seconds }; Init: PROC = { IF useCommander THEN -- *** temporary Commander.Register[key: "MakeBoot", proc: RunFromCommander, doc: NIL] ELSE Exec.AddCommand["MakeBoot.~"L, RunFromExec]; }; Init[]; END. žMBDriver.mesa Edited by Sandman on 6-Aug-81 15:40:03 Edited by Lewis on 28-Sep-81 16:46:51 Edited by Levin on April 13, 1983 5:00 pm the following must be first The order of the following is arbitrary. The ordering of the following is significant. The ordering of the following is arbitrary. the following must be last create BObject describing main input Bcd, used by ProcessCmds Miscellaneous Utilities ÊÔ˜Jšœ™Jšœ&™&Jšœ%™%Jšœ)™)J˜šÏk ˜ Jšœœœœ˜Jšœ œ˜(Jšœœ"˜,Jšœœ˜Jšœœ˜Jšœœ ˜Jšœœœœ˜'Jšœ œB˜Ršœœ˜ J˜ý—šœœ˜J˜‘—Jšœœœ#˜8šœœ˜ J˜b—Jšœ œ ˜Jšœœ ˜Jšœœ2˜?Jšœœ ˜!Jšœ œL˜ZJšœœD˜OJšœœ#˜-Jšœœ˜)Jšœœ˜!J˜—šœ ˜šœ˜JšœœœœT˜–—Jšœ˜ Jšœ˜ —J˜Jš˜J˜Jšœœ)Ïc˜KJ˜Jšœœ œ˜Jšœœ˜Jšœœœ˜J˜Jšœ œ˜J˜šœ*œ˜3Jšœœœ˜(JšœA˜AJ˜ J˜—J˜šÏn œœ˜Jšœ ˜ Jšœ ˜ Jšœ˜—J˜šŸœœœœ˜0Jšœœœ˜J˜šœž˜Jšœœœ˜&Jšœ?œ˜HJ˜J˜ ˜šœœ˜Jšœœœ˜Jšœœœ˜K˜Jšœ"œ˜@Jš˜Jšœ˜——Jšœ˜—šœ ˜˜ J˜J˜J˜J˜%J˜)J˜—Jšœ œ(œ˜=Jšœžœœ˜:Jšœžœœ˜%—J˜ ˜ J˜9J˜CJšœœœœ ˜@—Jšœ˜—J˜ J˜J˜—šŸ œœ˜(Jšœœ˜J˜Jšœ˜J˜J˜(Jšœ"ž˜3Jšœ˜Jšœ˜J˜—šŸ œœ˜Jšœ™J˜ Jšœ(™(Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜J˜—šŸœœ˜Jšœ-™-Jšœ˜Jšœ˜Jšœ+™+Jšœ ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ™J˜J˜J˜—šŸ œœ˜Jšœ œœ(˜Jšœ=™=šœ#œœ ˜5Jšœœ˜ Jšœœ œœ˜(Jšœ œœ˜%Jšœœ˜ —šœ˜J˜——šŸ œœ˜Jšœ œœ ˜!J˜*J˜+J˜0J˜,šœœœ˜0šœœœ˜'J˜;Jšœ œ˜(Jšœ˜—Jšœ˜—Jšœœ˜Jšœœ˜J˜J˜J˜—šŸœœœ˜+JšŸ œœœœœœœ˜AJ˜ Jšœ%œœ˜3J˜Jšœ˜J˜ J˜ Jšœ ˜J˜ Jšœ˜ J˜ Jšœ˜Jšœ˜Jšœ œœœ˜9J˜ Jšœ œœ˜$šœ˜Jšœ˜J˜ Jšœ˜Jšœ˜—J˜ Jš œ œ œœœ˜LJšœ˜Jšœ˜J˜—šŸ œœœ˜0J˜&Jšœœœœ˜(J˜EJ˜šŸœœœ œ˜+šœœž˜(Jšœœœœ˜1Jšœ˜Jšœœœœ˜)Jšœ˜—Jšœœ˜—J˜šŸ œœ˜šœœœ˜J˜*J˜&J˜)J˜(J˜—J˜"J˜J˜—Jš˜˜<˜EJšœœ˜,——Jš œœœœž˜Zšœ˜˜Jšœ-˜2J˜Jšœ˜Jšœ˜——Jšœ˜šœ œœ˜Jšœœœ˜šœœœ˜*šœ ˜J˜Jšœ'œ˜-Jšœ-œ˜3Jšœ&œ˜,Jšœ,œ˜2J˜4Jšœ˜—Jš˜—Jšœ˜—J˜NJ˜NJ˜CJšœœ˜3J˜Jšœœ˜-J˜Jšœ˜Jšœ˜J˜—šŸ œœ˜Jšœ˜#Jšœœ œ œ ˜=Jšœœ˜Dšœœ˜Jšœ ˜%Jšœœ œ œ ˜=Jšœœ"˜IJ˜—Jšœ ˜Jšœ*œ˜RJšœ ˜Jšœ˜J˜—šŸœœ˜J˜Jšœœ˜1Jšœœ œ˜'šœœœ˜/Jšœœ˜J˜7J˜8šœœœ˜/J˜AJ˜—Jšœœ˜ Jšœ˜—Jšœœ˜ Jšœ˜J˜—šŸœœ&˜:Jšœ œœ˜Jš œ œœœ œ œ ˜BJšœ œœ˜%Jšœ0œ˜4šœœœ(˜