DIRECTORY BasicTime USING [FromPupTime, GetClockPulses, GMT, Now, Period, Pulses, PulsesToMicroseconds, PulsesToSeconds], Booting USING [Boot, Checkpoint], Commander USING [CommandObject, CommandProc, CommandProcHandle, CommandProcObject, Handle, Lookup, Register], CommandTool USING [AddProcToList, AddSearchRule, ArgumentVector, DoCommand, Failed, GetProp, Parse, ParseToList, RemoveProcFromList], CommandToolLookup USING [DoLookup, FindMatchingCommands], Convert USING [AppendChar, Error, IntFromRope, RopeFromTime], EditedStream USING [Rubout], FileNames USING [ConvertToSlashFormat, CurrentWorkingDirectory, ResolveRelativePath, StripVersionNumber], FS USING [EnumerateForNames, Error, NameProc, StreamOpen], IO USING [Close, EndOf, EndOfStream, Error, GetBlock, GetLine, PutBlock, PutChar, PutF, PutF1, PutFR, PutRope, STREAM], List USING [AList, Assoc, Memb, PutAssoc], Process USING [Abort, CheckForAbort, GetCurrent, Pause, SecondsToTicks], Real USING [Fix, RealException], Rope USING [Concat, Equal, Fetch, Find, IsEmpty, Length, Match, ROPE], RopeList USING [DReverse], SafeStorage USING [NWordsAllocated], SystemVersion USING [bootFileDate, release], TiogaMenuOps USING [Open], UserCredentials USING [Get], ViewerClasses USING [Viewer], VMStatistics USING [pageFaults]; InitialCommandsImpl: CEDAR MONITOR IMPORTS BasicTime, Booting, Commander, CommandTool, CommandToolLookup, Convert, EditedStream, FileNames, FS, IO, List, Process, Real, Rope, RopeList, SafeStorage, SystemVersion, TiogaMenuOps, UserCredentials, VMStatistics = BEGIN ProcAny: TYPE = PROC ANY RETURNS ANY; ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; Date: Commander.CommandProc = { RETURN[NIL, Convert.RopeFromTime[from: BasicTime.Now[], includeDayOfWeek: TRUE]]; }; User: Commander.CommandProc = { user: ROPE _ UserCredentials.Get[].name; IF user.Length[] = 0 THEN user _ "??"; RETURN[NIL, user]; }; Version: Commander.CommandProc = TRUSTED { PutVersion[cmd.out]; }; PutVersion: PROC [out: STREAM] = { IO.PutF[out, "Cedar %g.%g", [integer[SystemVersion.release.major]], [integer[SystemVersion.release.minor]]]; IF SystemVersion.release.patch # 0 THEN IO.PutF1[out, ".%g", [integer[SystemVersion.release.patch]]]; IO.PutF1[out, " of %t\n", [time[BasicTime.FromPupTime[SystemVersion.bootFileDate]]]]; }; Fail: Commander.CommandProc = { RETURN[$Failure, "This Command Always Fails"]; }; HelpCommand: Commander.CommandProc = { full: BOOL _ cmd.procData.clientData = $Full; out: STREAM _ cmd.out; argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd: cmd ! CommandTool.Failed => {msg _ errorMsg; GO TO oops}]; IF argv.argc <= 1 THEN {msg _ "Usage: Help pattern ...\n"; GO TO oops}; FOR i: NAT IN [1..argv.argc) DO arg: ROPE _ argv[i]; matchList: LIST OF ROPE _ IF full THEN CommandToolLookup.DoLookup[cmd, arg].paths ELSE CommandToolLookup.FindMatchingCommands[arg, FALSE, CommandTool.GetProp[cmd, $SearchRules]].paths; IF matchList = NIL THEN { IO.PutF1[out, "No matching commands for %g\n", [rope[arg]] ]; LOOP; }; FOR each: LIST OF ROPE _ matchList, each.rest WHILE each # NIL DO name: ROPE _ each.first; pData: Commander.CommandProcHandle _ Commander.Lookup[name]; IO.PutF1[out, "%-20g", [rope[name]] ]; IF pData = NIL THEN { SELECT TRUE FROM NOT full => IO.PutRope[out, " {helpless}\n"]; Rope.Match["*.load*", name, FALSE] => IO.PutRope[out, " {load file}\n"]; Rope.Match["*.cm*", name, FALSE] => IO.PutRope[out, " {command file}\n"]; ENDCASE => IO.PutRope[out, " {helpless}\n"]; LOOP; }; IO.PutRope[out, " "]; IO.PutRope[out, pData.doc]; IO.PutRope[out, "\n"]; ENDLOOP; IF matchList.rest = NIL THEN { pData: Commander.CommandProcHandle _ Commander.Lookup[matchList.first]; IF pData # NIL AND pData.proc # NIL THEN { new: REF ProcAny _ NEW[ProcAny _ pData.proc]; IO.PutF1[out, "{implementor: %g}\n", [refAny[new]] ]; }; }; ENDLOOP; EXITS oops => result _ $Failure; }; Unregister: Commander.CommandProc = { procData: Commander.CommandProcHandle; argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd, TRUE ! CommandTool.Failed => {msg _ errorMsg; GO TO oops}]; IF argv.argc = 2 THEN { procData _ Commander.Lookup[argv[1]]; IF procData # NIL AND procData.proc # NIL THEN Commander.Register[key: argv[1], proc: NIL, doc: NIL] ELSE cmd.out.PutF1["Unregister: %g not found\n", [rope[argv[1]]]]; } ELSE cmd.out.PutRope["Usage: Unregister commandname\n"]; EXITS oops => result _ $Failure; }; Open: Commander.CommandProc = { argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd ! CommandTool.Failed => {msg _ errorMsg; GO TO oops}]; IF argv.argc < 2 THEN {OpenViewer[NIL, cmd.out]; RETURN}; FOR i: NAT IN [1..argv.argc) DO list: LIST OF ROPE _ ExpandStar[argv[i]]; WHILE list # NIL DO name: ROPE _ FileNames.ResolveRelativePath[list.first]; OpenViewer[name, cmd.out]; list _ list.rest; ENDLOOP; ENDLOOP; EXITS oops => result _ $Failure; }; ExpandStar: PROC [token: ROPE] RETURNS [LIST OF ROPE] = { IF Rope.Find[token, "*"] # -1 THEN { stripVersion: BOOL; listOfTokens: LIST OF ROPE _ NIL; ConsProc: FS.NameProc = { fullFName _ FileNames.ConvertToSlashFormat[fullFName]; IF stripVersion THEN fullFName _ FileNames.StripVersionNumber[fullFName]; listOfTokens _ CONS[fullFName, listOfTokens]; -- on front of list RETURN[TRUE]; }; IF token.Find["!"] = -1 THEN token _ Rope.Concat[token, "!H"]; stripVersion _ token.Find["!H", 0, FALSE] # -1; FS.EnumerateForNames[pattern: FileNames.ResolveRelativePath[token], proc: ConsProc ! FS.Error => IF error.group # bug THEN CONTINUE]; RETURN[RopeList.DReverse[listOfTokens]]; } ELSE RETURN[LIST[token]]; }; New: Commander.CommandProc = { OpenViewer[NIL, cmd.out]; }; Comment: Commander.CommandProc = { }; OpenViewer: PROC [name: ROPE, out: STREAM] = { viewer: ViewerClasses.Viewer; IF Rope.IsEmpty[name] THEN name _ FileNames.CurrentWorkingDirectory[]; viewer _ TiogaMenuOps.Open[name]; IF viewer = NIL THEN out.PutF1["\tViewer file not found: %g\n", [rope[name]]] ELSE out.PutF1["\tCreated Viewer: %g\n", [rope[viewer.name]]]; }; statBeforeRef: Commander.CommandProcHandle _ NEW[Commander.CommandProcObject _ [StatBefore]]; statAfterRef: Commander.CommandProcHandle _ NEW[Commander.CommandProcObject _ [StatAfter]]; StatDataObject: TYPE = RECORD [ cmd: Commander.Handle _ NIL, startTime: BasicTime.GMT, startPulses: BasicTime.Pulses, startFaults: INT, startWords: INT ]; MaxStats: NAT = 10; StatArray: TYPE = RECORD [ a: SEQUENCE length: [0..MaxStats+1) OF StatDataObject ]; stats: REF StatArray _ NEW[StatArray[MaxStats]]; StatBefore: ENTRY Commander.CommandProc = { ENABLE UNWIND => NULL; FOR i: NAT IN [0..MaxStats) DO IF stats.a[i].cmd = NIL THEN { stats.a[i] _ [ cmd: cmd, startTime: BasicTime.Now[], startPulses: BasicTime.GetClockPulses[], startFaults: VMStatistics.pageFaults, startWords: SafeStorage.NWordsAllocated[] ]; EXIT; }; ENDLOOP; result _ $Preserve; }; StatAfter: ENTRY Commander.CommandProc = { ENABLE UNWIND => NULL; pulses: BasicTime.Pulses = BasicTime.GetClockPulses[]; now: BasicTime.GMT = BasicTime.Now[]; wordsNow: INT = SafeStorage.NWordsAllocated[]; faultsNow: INT = VMStatistics.pageFaults; FOR i: NAT IN [0..MaxStats) DO statObj: StatDataObject = stats.a[i]; IF statObj.cmd = cmd THEN { seconds: INT _ BasicTime.Period[statObj.startTime, now]; nw: INT = wordsNow - statObj.startWords; nf: INT = faultsNow - statObj.startFaults; stats.a[i].cmd _ NIL; cmd.out.PutRope[" {"]; SELECT seconds FROM < 0 => cmd.out.PutRope["?? seconds"]; >= 60 => { cmd.out.PutF1["%r seconds", [integer[seconds]]]; }; ENDCASE => { tt: REAL _ BasicTime.PulsesToSeconds[pulses - statObj.startPulses]; fraction: INT _ 0; seconds _ Real.Fix[tt ! Real.RealException => { seconds _ LAST[INT]; CONTINUE; }]; fraction _ Real.Fix[(tt - seconds) * 100.0 ! Real.RealException => { fraction _ 0; CONTINUE; }]; cmd.out.PutF["%d.%02d seconds", [integer[seconds]], [integer[fraction]]] }; IF nw > 0 AND nw < 10000000 THEN cmd.out.PutF1[", %d words", [integer[nw]]]; IF nf > 0 AND nf < 10000000 THEN cmd.out.PutF1[", %d page faults", [integer[nf]]]; cmd.out.PutRope["}\n"]; EXIT; }; ENDLOOP; result _ $Preserve; }; Statistics: Commander.CommandProc = { argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd: cmd ! CommandTool.Failed => {msg _ errorMsg; GO TO oops}]; which: {on, off, swap} _ swap; IF argv.argc > 1 THEN { arg: ROPE _ argv[1]; SELECT TRUE FROM Rope.Equal[arg, "on", FALSE] => which _ on; Rope.Equal[arg, "off", FALSE] => which _ off; ENDCASE => {msg _ "Illegal option.\n"; GO TO oops}; }; WITH List.Assoc[key: $Before, aList: cmd.propertyList] SELECT FROM rbl: LIST OF REF ANY => { IF List.Memb[ref: statBeforeRef, list: rbl] THEN { SELECT which FROM swap, off => { cmd.propertyList _ CommandTool.RemoveProcFromList[aList: cmd.propertyList, listKey: $Before, proc: statBeforeRef]; cmd.propertyList _ CommandTool.RemoveProcFromList[aList: cmd.propertyList, listKey: $After, proc: statAfterRef]; GO TO showOff; }; ENDCASE; GO TO showOn; }; }; ENDCASE; SELECT which FROM swap, on => { cmd.propertyList _ CommandTool.AddProcToList[aList: cmd.propertyList, listKey: $Before, proc: statBeforeRef]; cmd.propertyList _ CommandTool.AddProcToList[aList: cmd.propertyList, listKey: $After, proc: statAfterRef]; GO TO showOn; }; ENDCASE; GO TO showOff; EXITS showOff => msg _ "Statistics off.\n"; showOn => msg _ "Statistics on.\n"; oops => result _ $Failure; }; Echo: Commander.CommandProc = { argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd, TRUE ! CommandTool.Failed => {msg _ errorMsg; GO TO oops}]; FOR i: NAT IN [1..argv.argc) DO cmd.out.PutRope[argv[i]]; cmd.out.PutChar[' ]; Process.CheckForAbort[]; ENDLOOP; cmd.out.PutChar['\n]; EXITS oops => result _ $Failure; }; PrintSearchRules: Commander.CommandProc = { rules: LIST OF REF ANY _ NARROW[List.Assoc[key: $SearchRules, aList: cmd.propertyList]]; cmd.out.PutRope["( "]; IF rules = NIL THEN cmd.out.PutChar[' ]; WHILE rules # NIL DO cmd.out.PutRope[NARROW[rules.first, ROPE]]; rules _ rules.rest; cmd.out.PutChar[' ]; Process.CheckForAbort[]; ENDLOOP; cmd.out.PutRope[")\n"]; }; SetSearchRules: Commander.CommandProc = { args: LIST OF ROPE; dir: ROPE; first: CHAR; args _ CommandTool.ParseToList[cmd, TRUE ! CommandTool.Failed => {msg _ errorMsg; GO TO oops}].list; IF cmd.procData.clientData = $SetSearchRules THEN cmd.propertyList _ List.PutAssoc[key: $SearchRules, val: NIL, aList: cmd.propertyList]; WHILE args # NIL DO dir _ args.first; dir _ FileNames.ResolveRelativePath[dir]; IF dir.Length[] < 3 THEN { msg _ Rope.Concat["Directory name too short: ", dir]; GO TO oops}; first _ dir.Fetch[0]; IF first # '[ AND first # '/ THEN { msg _ Rope.Concat["Bad directory name: ", dir]; GO TO oops}; CommandTool.AddSearchRule[cmd: cmd, dir: dir, append: TRUE]; args _ args.rest; Process.CheckForAbort[]; ENDLOOP; EXITS oops => result _ $Failure; }; Sleep: Commander.CommandProc = { seconds: INT; secondsCard: CARDINAL; argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd, TRUE ! CommandTool.Failed => {msg _ errorMsg; GO TO oops}]; IF argv.argc # 2 THEN {msg _ "Usage: Sleep seconds"; GO TO oops}; seconds _ Convert.IntFromRope[argv[1] ! Convert.Error => {msg _ "Bad arg"; GO TO oops}]; IF seconds NOT IN [0..LAST[CARDINAL]] THEN {msg _ "Bad arg"; GO TO oops}; secondsCard _ seconds; Process.Pause[Process.SecondsToTicks[seconds]]; EXITS oops => result _ $Failure; }; Indent: Commander.CommandProc = { depth: INT; depthNAT: NAT; spaces: REF TEXT; line: REF TEXT _ NEW[TEXT[200]]; argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd, TRUE ! CommandTool.Failed => {msg _ errorMsg; GO TO oops}]; IF argv.argc > 2 THEN {msg _ "Usage: Indent depth"; GO TO oops}; IF argv.argc < 2 THEN { depth _ 8; depthNAT _ 8; } ELSE { depth _ Convert.IntFromRope[argv[1] ! Convert.Error => {msg _ "Bad arg"; GO TO oops}]; IF depth NOT IN [0..80] THEN {msg _ "depth should be in [0..80]"; GO TO oops}; depthNAT _ depth; }; spaces _ NEW[TEXT[depthNAT]]; FOR i: NAT IN [0..depthNAT) DO spaces[i] _ ' ; ENDLOOP; spaces.length _ depthNAT; DO IF cmd.in.EndOf[ ! IO.Error => EXIT] THEN EXIT; line _ cmd.in.GetLine[buffer: line ! IO.EndOfStream => GOTO Finished; IO.Error => EXIT; EditedStream.Rubout => GOTO Finished; ]; cmd.out.PutBlock[block: spaces ! IO.Error => EXIT]; cmd.out.PutBlock[block: line ! IO.Error => EXIT]; cmd.out.PutChar['\n ! IO.Error => EXIT]; ENDLOOP; EXITS Finished => NULL; oops => result _ $Failure; }; Tee: Commander.CommandProc = { fileStream: STREAM _ NIL; block: REF TEXT _ NEW[TEXT[512]]; { ENABLE UNWIND => IF fileStream # NIL THEN fileStream.Close[]; argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd, TRUE ! CommandTool.Failed => {msg _ errorMsg; GO TO oops}]; IF argv.argc > 2 THEN {msg _ "Usage: Tee filename"; GO TO oops}; IF argv.argc = 2 THEN fileStream _ FS.StreamOpen[fileName: argv[1], accessOptions: $create ! FS.Error => IF error.group # $bug THEN {msg _ error.explanation; GO TO oops}]; DO count: NAT; block.length _ 0; IF cmd.in.EndOf[] THEN EXIT; count _ cmd.in.GetBlock[block: block ! IO.EndOfStream => EXIT; IO.Error => EXIT; EditedStream.Rubout => EXIT; ]; IF count = 0 THEN EXIT; IF fileStream # NIL THEN fileStream.PutBlock[block: block ! IO.Error => EXIT]; cmd.out.PutBlock[block: block ! IO.Error => EXIT]; Process.CheckForAbort[]; ENDLOOP; fileStream.Close[ ! IO.Error => CONTINUE]; }; EXITS oops => RETURN[$Failure, msg]; }; Abort: Commander.CommandProc = TRUSTED { Process.Abort[LOOPHOLE[Process.GetCurrent[], UNSPECIFIED]]; }; Shift: Commander.CommandProc = { result _ CommandTool.DoCommand[commandLine: cmd.commandLine, parent: cmd]; }; ShiftInterp: Commander.CommandProc = { result _ CommandTool.DoCommand[commandLine: cmd.commandLine, parent: cmd]; }; Time: Commander.CommandProc = { start: BasicTime.Pulses _ BasicTime.GetClockPulses[]; stop: BasicTime.Pulses; microseconds, seconds: LONG CARDINAL; digit: CARDINAL; any: BOOL _ FALSE; text: REF TEXT _ NEW[TEXT[8]]; result _ CommandTool.DoCommand[commandLine: cmd.commandLine, parent: cmd]; stop _ BasicTime.GetClockPulses[]; microseconds _ BasicTime.PulsesToMicroseconds[stop - start]; seconds _ microseconds / 1000000; microseconds _ microseconds MOD 1000000; THROUGH [0..6) DO microseconds _ microseconds * 10; digit _ microseconds / 1000000; microseconds _ microseconds MOD 1000000; IF NOT any THEN { text _ Convert.AppendChar[to: text, from: '., quote: FALSE]; any _ TRUE; }; text _ Convert.AppendChar[to: text, from: digit + '0, quote: FALSE]; IF microseconds = 0 THEN EXIT; ENDLOOP; RETURN [NIL, IO.PutFR["Running time: %r%g\n", [cardinal[seconds]], [text[text]]]]; }; Checkpoint: Commander.CommandProc = { errmsg: ROPE; out: STREAM = cmd.out; IO.PutF1[out, "Creating checkpoint at %g\n", [time[BasicTime.Now[]]]]; IO.PutF1[out, " made by %g\n", [rope[UserCredentials.Get[].name]]]; errmsg _ Booting.Checkpoint[]; IF errmsg.Length[] # 0 THEN RETURN[$Failure, errmsg]; IO.PutF[out, "Rollback at %g\n User: %g\n Version: ", [time[BasicTime.Now[]]], [rope[UserCredentials.Get[].name]]]; PutVersion[cmd.out]; }; Rollback: Commander.CommandProc = { RETURN[$Failure, Booting.Boot[[self[]], [r: TRUE]]]; }; Init: PROC = { Register: PROC [name: ROPE, proc: Commander.CommandProc, doc: ROPE, data: REF _ NIL, un: BOOL _ FALSE] = { name _ Rope.Concat["///Commands/", name]; Commander.Register[name, proc, doc, data, NOT un]; }; Register["-", Comment, "Comment", NIL, TRUE]; Register["--", Comment, "Comment", NIL, TRUE]; Register["/", Comment, "Comment", NIL, TRUE]; Register["//", Comment, "Comment", NIL, TRUE]; Register["?", HelpCommand, "List registered commands"]; Register["??", HelpCommand, "List registered commands (including those not yet loaded)", $Full]; Register["Help", HelpCommand, "List registered commands"]; Register["HelpFull", HelpCommand, "List registered commands (including those not yet loaded)", $Full]; Register["Abort", Abort, "Abort -- Raises ABORTED"]; Register["AddSearchRules", SetSearchRules, "Add command search rules: AddSearchRules list-of-directories"]; Register["Checkpoint", Checkpoint, "Create a checkpoint"]; Register["Date", Date, "Print date and time"]; Register["Echo", Echo, "Print command line"]; Register["Fail", Fail, "This command always fails"]; Register["Indent", Indent, "Indent n -- Indent n spaces"]; Register["New", New, "Open an empty viewer"]; Register["Open", Open, "Open fileName - open a viewer"]; Register["PrintSearchRules", PrintSearchRules, "Print command search rules"]; Register["Rollback", Rollback, "Roll back to previous checkpoint"]; Register["SetSearchRules", SetSearchRules, "Set command search rules: SetSearchRules directory*", $SetSearchRules]; Register["Shift", Shift, "Shift command-line (uninterpreted)", NIL, TRUE]; Register["ShiftInterp", ShiftInterp, "ShiftInterp command-line (interpreted)"]; Register["Sleep", Sleep, "Sleep n -- pause for n seconds"]; Register["Statistics", Statistics, "Turn statistics printing on or off"]; Register["Tee", Tee, "Tee file -- copy standard input to file"]; Register["Time", Time, "Time command-line (uninterpreted)", NIL, TRUE]; Register["Unregister", Unregister, "Unregister a command"]; Register["User", User, "Print name of logged in user"]; Register["Version", Version, "Print Cedar version number"]; }; Init[]; END. April 4, 1983 4:42 pm, Stewart, Created April 20, 1983 7:10 pm, Stewart, add commandfile arguments and auto commandfiles September 7, 1983 11:10 am, Stewart, Cedar 5 October 24, 1983 9:42 am, Stewart, New CommandTool November 3, 1983 9:37 am, Stewart, Bulletproofing November 3, 1983 9:37 am, Stewart, add Checkpoint and Rollback January 14, 1984 8:18 pm, Stewart, new Open `InitialCommandsImpl.mesa Copyright c 1984, 1985 by Xerox Corporation. All rights reserved. L. Stewart, January 17, 1984 5:03 pm Russ Atkinson, April 23, 1985 12:28:45 pm PST Paul Rovner, November 29, 1983 8:51 am Doug Wyatt, May 25, 1984 2:52:01 pm PDT [cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] Maybe this is a file, really Exact match, so try to print the implementing procedure as well Long elapsed time, so use low precision clock to avoid overflow High precision elapsed time Now we have to preserve the result, or else we will not preserve $Failure! can turn off if we want to Κs˜codešœ™Kšœ Οmœ7™BK™%K™-K™&K™'—K˜šΟk ˜ Kšœ žœžœ>˜oKšœžœ˜!Kšœ žœ^˜mKšœ žœt˜…Kšœžœ"˜9Kšœžœ0˜=Kšœ žœ ˜Kšœ žœZ˜iKšžœžœ2˜:Kšžœžœgžœ˜wKšœžœ ˜*Kšœžœ;˜HKšœžœ˜ Kšœžœ6žœ˜FKšœ žœ ˜Kšœ žœ˜$Kšœžœ˜,Kšœ žœ˜Kšœžœ˜Kšœžœ ˜Kšœ žœ˜ —K˜šœžœž˜"Kšžœbžœžœn˜έKšœž˜—˜Kš Οnœžœžœžœžœžœ˜%Kšžœžœžœ˜Kšžœžœžœžœ˜—K˜šœ˜Kšžœžœ@žœ˜QK˜—K˜šœ˜Kšœžœ˜(Kšžœžœ ˜&Kšžœžœ˜K˜—K˜šœ!žœ˜*Kšœ˜K˜K˜—šŸ œžœžœ˜"šžœ˜KšœP˜P—šžœ!ž˜'Kšžœ;˜=—KšžœS˜UK˜—K˜šœ˜Kšžœ(˜.K˜—K˜šœ&˜&Kš œžœ žœžœžœžœ™:Kšœžœ#˜-Kšœžœ ˜šœ=˜=Kšœ)žœžœ˜6—Kšžœžœ%žœžœ˜Gšžœžœžœž˜Kšœžœ ˜šœ žœžœžœ˜šžœ˜Kšžœ+˜/Kšžœ-žœ0˜f——šžœ žœžœ˜Kšžœ;˜=Kšžœ˜K˜—š žœžœžœžœžœžœž˜AKšœžœ˜Kšœ<˜˜B—K˜—Kšžœ4˜8—Kšžœ˜ K˜—K˜šœ˜šœ ˜ KšœAžœžœ˜N—Kšžœžœ žœ žœ˜9šžœžœžœž˜Kšœžœžœžœ˜)šžœžœž˜Kšœžœ-˜7Kšœ˜K˜Kšžœ˜—Kšžœ˜—Kšžœ˜ K˜—K˜šŸ œžœ žœžœžœžœžœ˜9šžœžœ˜$Kšœžœ˜Kš œžœžœžœžœ˜!šœ žœ ˜Kšœ6˜6Kšžœžœ5˜IKšœžœΟc˜BKšžœžœ˜ K˜—Kšžœžœ"˜>Kšœ#žœ˜/šžœP˜RKš œžœ žœžœžœ˜2—Kšžœ"˜(K˜—Kšžœžœžœ ˜K˜—K˜šœ˜Kšœ žœ ˜K˜—K˜šœ"˜"K˜—K˜šŸ œžœžœžœ˜0Kšœ˜Kšžœžœ,˜FKšœ!˜!Kšžœ žœžœ9˜MKšžœ:˜>K˜—K˜šœ*˜*Kšœžœ-˜2—šœ)˜)Kšœžœ,˜1—K˜šœžœžœ˜Kšœžœ˜Kšœžœ˜Kšœ˜Kšœ žœ˜Kšœ ž˜K˜—K˜Kšœ žœ˜K˜šœ žœžœ˜Kšœžœžœ˜5K˜K˜—Kšœžœ žœ˜0K˜šœ žœ˜+Kšžœžœžœ˜šžœžœžœž˜šžœžœžœ˜šœ˜Kšœ ˜ Kšœ˜Kšœ(˜(Kšœ%˜%Kšœ,˜,—Kšžœ˜K˜—Kšžœ˜—K˜K˜—K˜šœ žœ˜*Kšžœžœžœ˜Kšœ6˜6Kšœžœ˜%Kšœ žœ!˜.Kšœ žœ˜)K˜šžœžœžœž˜Kšœ%˜%šžœžœ˜Kšœ žœ,˜8Kšœžœ!˜(Kšœžœ#˜*Kšœžœ˜Kšœ˜šžœ ž˜K˜%šœ ˜ Kšœ?™?Kšœ0˜0K˜—šžœ˜ Kšœ™Kšœžœ;˜CKšœ žœ˜šœ˜Kšœ$žœžœžœ˜<—šœ*˜*Kšœ(žœ˜5—KšœH˜HK˜——Kšžœžœžœ-˜MKšžœžœžœ3˜SKšœ˜Kšžœ˜K˜—Kšžœ˜—KšœJ™JKšœ˜K˜—K˜šœ%˜%šœ=˜=Kšœ)žœžœ˜6—K˜šžœžœ˜Kšœžœ ˜šžœžœž˜Kšœžœ˜+Kšœžœ˜-Kšžœ žœžœ˜3—K˜—K˜šžœ3žœž˜Bš œžœžœžœžœ˜šžœ*žœ˜2Kšœ™šžœž˜šœ˜Kšœr˜rKšœp˜pKšžœžœ ˜K˜—Kšžœ˜—Kšžœžœ˜ K˜—K˜—Kšžœ˜—šžœž˜šœ ˜ Kšœm˜mKšœk˜kKšžœžœ˜ K˜—Kšžœ˜—Kšžœžœ ˜šž˜Kšœ%˜%Kšœ#˜#Kšœ˜—K˜—K˜šœ˜šœ:ž˜>Kšœ)žœžœ˜6—šžœžœžœž˜K˜K˜Kšœ˜Kšžœ˜—K˜Kšžœ˜ K˜—K˜šœ+˜+šœžœžœžœž˜Kšœžœ9˜A—Kšœ˜Kšžœ žœžœ˜(šžœ žœž˜Kšœžœžœ˜+Kšœ˜Kšœ˜Kšœ˜Kšžœ˜—Kšœ˜K˜—K˜šœ)˜)Kšœžœžœžœ˜Kšœžœ˜ Kšœžœ˜ šœ$ž˜(Kšœ)žœžœ ˜;—šžœ+ž˜1Kšœ9žœ˜W—šžœžœž˜Kšœ˜Kšœ)˜)šžœžœ˜Kšœ6žœžœ˜B—Kšœ˜šžœ žœ žœ˜#Kšœ0žœžœ˜<—Kšœ6žœ˜˜>Kšœ+˜+K˜K˜K˜K˜K˜—…—Dž[q