DIRECTORY Ascii USING [CR, SP, TAB], Commander USING [CommandProc, Register], Convert USING [DefaultUnsigned, Parse, Value], ConvertUnsafe USING [AppendRope, ToRope], IO USING [ bool, BreakProc, card, EndOfStream, GetOutputStreamRope, GetToken, PFCodeProc, PutChar, PutF, PutFR, PutRope, RIS, rope, SetPFCodeProc, STREAM, time], List USING [Map, Reverse], MB USING [ Abort, BCount, BHandle, 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, OpenLoadmap, ProcessInput, ReportFrameAllocation, TurnOffStartTrap, WriteBootFile, WriteGermFile], PrincOps USING [GFTIndex, PsbIndex], Rope USING [Cat, Equal, Fetch, Find, Index, Length, ROPE, Substr], Runtime USING [CallDebugger, GetBcdTime], Segments USING [FHandle, FileNameProblem, GetFileTimes, NewFile], Time USING [Current, Packed], Volume USING [InsufficientSpace]; MBDriver: MONITOR IMPORTS Commander, Convert, ConvertUnsafe, IO, List, MB, Rope, Runtime, Segments, Time, Volume EXPORTS MB = BEGIN ROPE: TYPE = Rope.ROPE; data: MB.Handle _ NIL; typescript: IO.STREAM; commandStream: IO.STREAM; Outcome: TYPE = {normal, error, abort, noMoreCommands}; RunFromCommander: Commander.CommandProc = TRUSTED { commandStream _ IO.RIS[cmd.commandLine]; typescript _ cmd.out; [] _ DoWork[]; commandStream _ typescript _ NIL; }; DoWork: ENTRY PROC RETURNS [outcome: Outcome] = { ENABLE UNWIND => NULL; WriteHerald: PROC = {typescript.PutF["%g\N%t\N", IO.rope[MakeBootVersion[]], IO.time[]]}; ReportStats: PROC [ nFilePages, nModules, nGFIs, nResidentPages, nBootLoadedPages: CARDINAL, elapsedTime: LONG CARDINAL] = { typescript.PutF["Boot file pages: %d (%d bootloaded, of which %d are resident)\N", IO.card[nFilePages], IO.card[nBootLoadedPages], IO.card[nResidentPages]]; typescript.PutF["Modules: %d (requiring %d GFIs)\N", IO.card[nModules], IO.card[nGFIs]]; typescript.PutF["Time: %r\N", IO.card[elapsedTime]]; }; 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[]; }; DoRealWork: PROC RETURNS [outcome: Outcome] = { CheckAbort: PROC = {IF --something-- FALSE THEN ERROR MB.Abort}; CheckAbort[]; IF (outcome _ ProcessCmds[]) ~= normal THEN RETURN; MB.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] }; WriteHerald[]; DO -- until no commands remain start: LONG CARDINAL _ Time.Current[]; nFilePages, nModules, nGFIs, nResidentPages, nBootLoadedPages: CARDINAL; outcome _ abort; Initialize[]; outcome _ DoRealWork[ ! UNWIND => Finalize[]; MB.Abort, ABORTED => CONTINUE; Volume.InsufficientSpace => {typescript.PutRope["! Disk full\N"]; CONTINUE}; Segments.FileNameProblem[] => { typescript.PutF["! Can't find %g\N", IO.rope[ConvertUnsafe.ToRope[name]]]; CONTINUE } ]; SELECT outcome FROM normal => { nFilePages _ data.nFilePages; nModules _ data.nModules; nGFIs _ data.nGFIs; nResidentPages _ data.nResidentPages; nBootLoadedPages _ data.nBootLoadedPages; }; abort => {typescript.PutRope["...MakeBoot aborted\N"]; EXIT}; noMoreCommands => {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[]; }; InitDriver: PROC = { typescript.SetPFCodeProc['y, GermOrBoot]; data _ NEW[MB.Object _ [ buildTime: Time.Current[], typescript: typescript, inputBCDs: NEW[MB.InputBCDs[10] _ [nBcds: 1]] ]]; data.inputBCDs.bcds[0] _ NEW[MB.BObject _ [ name: NIL, bcd: NIL, bcdSeg: NIL, bcdSegment: NIL, mt: NIL, gfiOffset: 0, files: NIL]]; }; FinishDriver: PROC = { typescript.SetPFCodeProc['y, NIL]; data _ NIL; -- drop the whole structure on the floor }; GermOrBoot: IO.PFCodeProc = TRUSTED { typescript.PutRope[IF data.germ THEN "germ" ELSE "boot"]}; ProcessCmds: PROC RETURNS [outcome: Outcome] = { args, results: PairList; switches, sourceName: ROPE _ NIL; BEGIN [sourceName, args, results, switches] _ Parse[commandStream ! ParseFailed => GOTO bogus]; IF sourceName = NIL THEN RETURN[outcome: noMoreCommands]; EXITS bogus => { typescript.PutRope["! Bad MakeBoot command line\N"]; RETURN[outcome: error] }; END; IF switches ~= NIL THEN { sense: BOOL _ TRUE; FOR i: INT IN [0..switches.Length[]) DO SELECT switches.Fetch[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.inputBCDs.bcds[0].name _ data.input _ SetExtension[sourceName, "bcd"]; ProcessResults[results]; EchoCommand[]; ProcessArgs[args]; RETURN[outcome: normal] }; EchoCommand: PROC = { typescript.PutF["Building %y file %g", IO.bool[data.germ], IO.rope[data.output]]; IF data.etherFormat THEN typescript.PutF[" and ether %y file %g\N", IO.bool[data.germ], IO.rope[data.etherOutput]] ELSE typescript.PutChar['\N]; typescript.PutF["Writing load map to %g\N", IO.rope[data.loadmapName]]; }; EchoBCDs: PROC = { data.loadmap.PutRope["Input BCD"]; IF data.inputBCDs.nBcds ~= 0 THEN data.loadmap.PutChar['s]; data.loadmap.PutRope[":\N\N"]; FOR i: CARDINAL IN [0..data.inputBCDs.nBcds) DO data.loadmap.PutF[" %39j", IO.rope[data.inputBCDs.bcds[i].name]]; {ENABLE Segments.FileNameProblem[] => CONTINUE; file: STRING = [40]; ConvertUnsafe.AppendRope[to: file, from: data.inputBCDs.bcds[i].name]; data.loadmap.PutF[" %t", IO.time[Segments.GetFileTimes[Segments.NewFile[file]].create]]; }; data.loadmap.PutChar['\N]; ENDLOOP; data.loadmap.PutChar['\N]; }; ProcessResults: PROC [results: PairList] = { DoOnePair: SAFE PROC [p: REF ANY, rest: LIST OF REF ANY] = TRUSTED { key, value: ROPE; [key, value] _ NARROW[p, REF Pair]^; SELECT TRUE FROM key = NIL => data.output _ value; key.Equal["bootFile", FALSE] => IF data.output = NIL THEN data.output _ value ELSE MB.Error["Duplicate result keyword 'bootFile'"]; key.Equal["loadMap", FALSE] => IF data.loadmapName = NIL THEN data.loadmapName _ value ELSE MB.Error["Duplicate result keyword 'loadMap'"]; ENDCASE => MB.Error["Unrecognized result keyword"]; }; data.output _ data.etherOutput _ data.loadmapName _ NIL; List.Map[results, DoOnePair]; IF data.output = NIL THEN data.output _ StripExtension[data.input]; data.output _ SetExtension[data.output, IF data.germ THEN "germ" ELSE "boot"]; IF data.etherFormat THEN data.etherOutput _ SetExtension[StripExtension[data.output], IF data.germ THEN "eg" ELSE "pb"]; IF data.loadmapName = NIL THEN data.loadmapName _ StripExtension[data.output]; data.loadmapName _ SetExtension[data.loadmapName, "loadmap"]; }; SetExtension: PROC [r, ext: ROPE] RETURNS [ROPE] = { RETURN[IF r.Find["."] = -1 THEN r.Cat[".", ext] ELSE r]}; StripExtension: PROC [r: ROPE] RETURNS [ROPE] = {RETURN[r.Substr[len: r.Index[s2: "."]]]}; ProcessArgs: PROC [args: PairList] = { nProcesses, gftLength: CARDINAL _ LAST[CARDINAL]; RopeToNumber: PROC [r: ROPE] RETURNS [ok: BOOL _ FALSE, v: LONG CARDINAL] = { value: Convert.Value; index: INT; [value, index] _ Convert.Parse[[rope[r]], Convert.DefaultUnsigned]; WITH val: value SELECT FROM unsigned => RETURN[index = r.Length[], val.unsigned]; ENDCASE; }; DoOnePair: SAFE PROC [p: REF ANY, rest: LIST OF REF ANY] = TRUSTED { key, value: ROPE; [key, value] _ NARROW[p, REF Pair]^; SELECT TRUE FROM key.Equal["parm", FALSE] => { parmFile: ROPE = SetExtension[value, "bootmesa"]; typescript.PutF["Processing parameter file %g", IO.rope[parmFile]]; MB.ProcessInput[parmFile]; typescript.PutChar[Ascii.CR]; }; key.Equal["bcd", FALSE] => { IF data.inputBCDs.nBcds = LAST[MB.BCount] - 1 --save slot for NullConfig-- THEN MB.Error["Too many input BCDs"]; IF data.inputBCDs.nBcds = data.inputBCDs.length THEN { newLength: MB.BCount = MIN[2*data.inputBCDs.length, LAST[MB.BCount]]; newInputBCDs: REF MB.InputBCDs _ NEW[MB.InputBCDs[newLength] _ [nBcds: data.inputBCDs.nBcds]]; FOR i: CARDINAL IN [0..data.inputBCDs.nBcds) DO newInputBCDs.bcds[i] _ data.inputBCDs.bcds[i]; ENDLOOP; data.inputBCDs _ newInputBCDs; }; data.inputBCDs.bcds[data.inputBCDs.nBcds] _ NEW[MB.BObject _ [ name: SetExtension[value, "bcd"], bcd: NIL, bcdSeg: NIL, bcdSegment: NIL, mt: NIL, gfiOffset: 0, files: NIL]]; data.inputBCDs.nBcds _ data.inputBCDs.nBcds+1; }; key.Equal["nProcesses", FALSE] => { ok: BOOL; [ok, nProcesses] _ RopeToNumber[value]; IF ~ok OR ~(nProcesses-1 IN PrincOps.PsbIndex) THEN MB.Error["Invalid nProcesses"]; }; key.Equal["gftLength", FALSE] => { ok: BOOL; [ok, gftLength] _ RopeToNumber[value]; IF ~ok OR ~(gftLength-1 IN PrincOps.GFTIndex) THEN MB.Error["Invalid gftLength"]; }; ENDCASE => MB.Error["Unrecognized parameter keyword"]; }; List.Map[args, DoOnePair]; IF nProcesses ~= LAST[CARDINAL] THEN { data.nProcesses _ nProcesses; typescript.PutF["Number of processes set to %d\N", IO.card[nProcesses]]; }; IF gftLength ~= LAST[CARDINAL] THEN { data.gftLength _ gftLength; typescript.PutF["GFT length set to %d\N", IO.card[gftLength]]; }; }; PairList: TYPE = LIST OF REF --Pair-- ANY; Pair: TYPE = RECORD [key, value: ROPE]; ParserState: TYPE = [0..17]; ParseFailed: ERROR = CODE; dontAdvance: BOOL _ FALSE; token: ROPE _ NIL; Parse: PROC [cmd: IO.STREAM, allowNoTagParm: BOOL _ FALSE] RETURNS [operator: ROPE _ NIL, argList, resultList: PairList _ NIL, switches: ROPE _ NIL] = { state: ParserState _ 0; pair0, pair1: ROPE _ NIL; DontAdvance: PROC = INLINE {dontAdvance _ TRUE}; NextToken: IO.BreakProc = TRUSTED { SELECT char FROM Ascii.SP, Ascii.CR, Ascii.TAB => RETURN[sepr]; IN ['a..'z], IN ['A..'Z], IN ['0..'9], '<, '>, '., '+, '-, '~, '!, '$ => RETURN[other]; ';, '_, '[, ',, '], ':, '/ => RETURN[break]; ENDCASE; ERROR ParseFailed; }; PushArg: PROC = INLINE { argList _ CONS[NEW[Pair _ [key: pair0, value: pair1]], argList]}; PushResult: PROC = INLINE { resultList _ CONS[NEW[Pair _ [key: pair0, value: pair1]], resultList]}; UNTIL state = LAST[ParserState] DO IF dontAdvance THEN dontAdvance _ FALSE ELSE token _ cmd.GetToken[NextToken ! IO.EndOfStream => {token _ NIL; CONTINUE}]; IF token = NIL THEN -- end of command stream SELECT state FROM 0, 1, 9, 14, 15, 16 => state _ 17; ENDCASE => ERROR ParseFailed ELSE SELECT Rope.Fetch[token] FROM '_ => SELECT state FROM 1 => { pair0 _ NIL; pair1 _ operator; operator _ NIL; PushResult[]; state _ 2}; 7 => state _ 8; ENDCASE => ERROR ParseFailed; '[ => SELECT state FROM 0 => state _ 3; 1, 9 => state _ 10; 14 => {DontAdvance[]; state _ 17}; ENDCASE => ERROR ParseFailed; '] => SELECT state FROM 3, 6 => state _ 7; 4 => IF allowNoTagParm THEN { pair1 _ pair0; pair0 _ NIL; PushArg[]; state _ 7} ELSE ERROR ParseFailed; 10, 13 => state _ 14; 11 => IF allowNoTagParm THEN { pair1 _ pair0; pair0 _ NIL; PushArg[]; state _ 14} ELSE ERROR ParseFailed; ENDCASE => ERROR ParseFailed; ': => SELECT state FROM 4 => state _ 5; 11 => state _ 12; ENDCASE => ERROR ParseFailed; ', => SELECT state FROM 4 => IF allowNoTagParm THEN { pair1 _ pair0; pair0 _ NIL; PushArg[]; state _ 3} ELSE ERROR ParseFailed; 6 => state _ 3; 11 => IF allowNoTagParm THEN { pair1 _ pair0; pair0 _ NIL; PushArg[]; state _ 10} ELSE ERROR ParseFailed; 13 => state _ 10; ENDCASE => ERROR ParseFailed; '/ => SELECT state FROM 0, 1, 9, 14 => state _ 15; ENDCASE => ERROR ParseFailed; '; => SELECT state FROM 1, 9, 14, 15, 16 => state _ 17; ENDCASE => ERROR ParseFailed; ENDCASE => -- id-- SELECT state FROM 0 => {operator _ token; state _ 1}; 2, 8 => {operator _ token; state _ 9}; 3 => {pair0 _ token; state _ 4}; 5 => {pair1 _ token; PushResult[]; state _ 6}; 10 => {pair0 _ token; state _ 11}; 12 => {pair1 _ token; PushArg[]; state _ 13}; 15 => {switches _ token; state _ 16}; 1, 9, 14, 16 => {DontAdvance[]; state _ 17}; ENDCASE => ERROR ParseFailed; ENDLOOP; resultList _ List.Reverse[resultList]; argList _ List.Reverse[argList]; }; Abort: PUBLIC SIGNAL = CODE; Error: PUBLIC PROC [msg: Rope.ROPE] = { typescript.PutF["\NError: %g\N", IO.rope[msg]]; SIGNAL MB.Abort; }; MakeBootVersion: PUBLIC PROC RETURNS [r: ROPE] = { r _ IO.PutFR["Cedar MakeBoot of %t", IO.time[Runtime.GetBcdTime[]]]; }; Commander.Register[key: "MakeBoot", proc: RunFromCommander, doc: NIL] 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 November 4, 1983 4:47 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 %y: Argument is Boolean Command Line Parsing and Analysis Command Line Parser 0: 1: id 2: id _ 3: [ ?{ARG}, 4: [ ?{ARG}, id 5: [ ?{ARG}, id : 6: [ ?{ARG}, id : id 7: [ ?{ARG}, ] 8: [ ?{ARG}, ] _ 9: LHS _ id 10: ?(LHS _) id [ ?{ARG}, 11: ?(LHS _) id [ ?{ARG}, id 12: ?(LHS _) id [ ?{ARG}, id : 13: ?(LHS _) id [ ?{ARG}, id : id 14: ?(LHS _) id RHS 15: ?(LHS _) id ?RHS / 16: ?(?(LHS _) id ?RHS) / id 17: ?(?(LHS _) id ?RHS) ?(/ ?id) (;|eom) | eom where LHS = id | [ ?{ARG}, ] RHS = [ ?{ARG}, ] ARG = id : id | id (if allowNoTagParm) Miscellaneous Exported Utilities Initialization Ê\˜Jšœ™Jšœ&™&Jšœ%™%Jšœ+™+J˜šÏk ˜ Jš œœœœœ˜Jšœ œ˜(Jšœœ!˜.Jšœœ˜)šœœ˜ Jšœnœœ˜–—Jšœœ˜šœœ˜ J˜‚—Jšœ œ˜$Jšœœ*œ ˜BJšœœ˜)Jšœ œ3˜AJšœœ˜Jšœœ˜!J˜—šœ ˜šœ˜Jšœ#œœ'˜V—Jšœœ˜ —J˜Jš˜J˜Jšœœœ˜J˜Jšœœ œ˜Jšœ œœ˜Jšœœœ˜J˜Jšœ œ*˜7J˜šœ*œ˜3Jšœœœ˜(Jšœ˜J˜Jšœœ˜!J˜—J˜J˜šÏnœœœœ˜1Jšœœœ˜Jšž œœ œœ ˜Yšž œœ˜Jšœ?œ˜HJšœ œœ˜šœR˜RJšœœœ˜I—Jšœ5œœ˜XJšœœ˜4J˜—šž œœ˜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šž œœœÏc œœœœ˜@J˜ Jšœ%œœ˜3Jšœ˜Jšœ˜J˜ J˜ Jšœ ˜J˜ Jšœ˜ J˜ Jšœ˜Jšœ˜Jšœ œœœ˜9J˜ Jšœ œœ˜$šœ˜Jšœ˜J˜ Jšœ˜Jšœ˜—J˜ Jš œ œ œœœ˜LJšœ˜Jšœ˜—J˜šœŸ˜Jšœœœ˜&Jšœ?œ˜HJ˜J˜ ˜šœœ˜Jšœœœ˜JšœCœ˜M˜Jšœ%œ#˜JJš˜Jšœ˜——Jšœ˜—šœ ˜˜ J˜J˜J˜J˜%J˜)J˜—Jšœ8œ˜>Jšœ%œ˜+JšœŸœœ˜%—J˜ ˜ J˜9J˜CJšœœœœ ˜@—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™šž œœœ˜0J˜Jšœœœ˜!Jš˜JšœMœ˜YJšœœœœ˜9šœ˜˜ Jšœ4˜4Jšœ˜Jšœ˜——Jšœ˜šœ œœ˜Jšœœœ˜šœœœ˜'šœ˜J˜Jšœ'œ˜-Jšœ-œ˜3Jšœ&œ˜,Jšœ,œ˜2J˜4Jšœ˜—Jš˜—Jšœ˜—J˜KJšœ˜J˜Jšœ˜Jšœ˜Jšœ˜J˜—šž œœ˜Jšœ&œœ˜Qšœ˜Jšœ+œœ˜Y—Jšœ˜Jšœ,œ˜GJšœ˜J˜—šžœœ˜J˜"Jšœœ˜;Jšœ˜šœœœ˜/Jšœœ$˜Bšœœœ˜/Jšœœ˜J˜FJšœœ=˜YJ˜—Jšœ˜Jšœ˜—Jšœ˜Jšœ˜J˜—šžœœ˜,šž œ œœœœœœœœ˜DJšœ œ˜Jšœœœ˜$šœœ˜Jšœœ˜!šœœ˜Jšœœœ˜-Jšœœ.˜5—šœœ˜Jšœœœ˜7Jšœœ-˜4—Jšœœ&˜3—J˜—Jšœ4œ˜8J˜Jšœœœ*˜CJšœ(œ œœ ˜Nšœ˜šœ˜Jšœ*œ œœ˜L——Jšœœœ0˜NJ˜=J˜J˜—š ž œœ œœœ˜4Jšœœœœ˜9—J˜Jš žœœœœœœ#˜ZJ˜šž œœ˜&Jšœœœœ˜1šž œœœœœœœœ˜MJ˜Jšœœ˜ J˜Cšœ œ˜Jšœ œ#˜5Jšœ˜—J˜—šž œœœœœœœœœœ˜DJšœ œ˜Jšœœœ˜$šœœ˜šœœ˜Jšœ œ#˜1Jšœ0œ˜CJšœ˜Jšœœ˜Jšœ˜—šœœ˜š œœœ Ÿœ˜OJšœ˜ —šœ.œ˜6Jš œ œ œœœ ˜Ešœœœ ˜ Jšœœ7˜=—šœœœ˜/J˜.Jšœ˜—J˜J˜—šœ,œœ ˜>Jšœ!˜!Jšœœ œœ˜'Jšœœ˜Jšœœ˜ —J˜.J˜—šœœ˜#Jšœœ˜ Jšœ'˜'Jš œœœœœ˜SJšœ˜—šœœ˜"Jšœœ˜ Jšœ&˜&Jš œœœœœ˜QJšœ˜—Jšœœ)˜6—J˜—J˜šœœœœ˜&J˜Jšœ3œ˜HJšœ˜—šœœœœ˜&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šœ3™3Jšœ™Jšœ™Jšœ(™(J˜—Jšœ œœ˜J˜Jšœ œœ˜Jšœœœ˜J˜š žœœœœœœ˜:Jš œ œœ"œ œœ˜]J˜Jšœœœ˜J˜Jšž œœœœ˜0J˜šœ œ œ˜#šœ˜Jš œœœœœ˜.Jšœ œ œ-œ˜WJšœœ˜,Jšœ˜—Jšœ ˜šœ˜J˜——šžœœœ˜Jšœ œœ/˜A—J˜šž œœœ˜Jšœ œœ2˜G—J˜šœ œ˜"Jšœ œ˜'Jšœ"œœœ˜Qšœ œœŸ˜-šœ˜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šœœ ˜——šœŸ˜šœ˜Jšœ&˜&Jšœ&˜&Jšœ#˜#Jšœ1˜1Jšœ$˜$Jšœ/˜/Jšœ'˜'J˜,Jšœœ ˜————Jšœ˜—J˜&J˜ Jšœ˜—J˜J™Jšœ ™ J˜Jšœœœœ˜J˜šžœœœ œ˜(Jšœ!œ ˜/Jšœœ˜Jšœ˜J˜—šžœœ œœ˜2Jšœœœ˜DJ˜J˜—Jšœ™J™JšœAœ˜EJ˜šœ˜J˜J˜——…—3ìJR