DIRECTORY AMTypes USING [Class, TypeClass, UnderType, TVType, TVToType, Range, TypeToName], Commander USING [Lookup, Enumerate, CommandProc], IO USING [char, ControlX, CreateViewerStreams, CurrentPosition, Flush, EndOf, EraseChar, ESC, IDProc, NewLine, Put, PutChar, PutF, PutRope, PutType, ROPE, rope, RIS, STREAM, text, type, UserAbort, BreakProc, SpaceTo, GetToken, TokenProc, WhiteSpace, SkipOver, UserAborted], List USING [Sort, CompareProc], MessageWindow USING [Append, Blink], Rope USING [Compare, Concat, Equal, Fetch, Find, IsEmpty, Length, Replace, Run, Substr], Spell USING [defaultModes, ModesRecord], UserProfile USING [ProfileChangedProc, CallWhenProfileChanges], UserExec USING [HistoryEvent, CommandProc, ExecHandle, Expression, MethodProc, RegisterCommand, RegisterMethod, TV, Type, CheckForFile, GetMatchingList, GetMatchingFileList, GetStreams], UserExecPrivate USING [commandGenerator, DoesUserMean, EventFailed, EvalEvent, ExecPrivateRecord, ExpandCommandLine, GetRegistrationData, PrintDeclFromSource, RunAndCall, ReadQuietly, CallRegisteredProc, CommandRecord, LookupCommand, methodList, MethodList, GetRestOfStream, dummyCommanderProc, HistoryEventPrivateRecord] ; UserExecMethodsImpl: CEDAR PROGRAM IMPORTS AMTypes, IO, Commander, List, MessageWindow, Rope, Spell, UserExec, UserExecPrivate, UserProfile EXPORTS UserExec, UserExecPrivate = BEGIN OPEN IO, UserExec; MethodProc: TYPE = UserExec.MethodProc; -- PROC [exec: ExecHandle] RETURNS[handled: BOOLEAN _ FALSE] ExecPrivateRecord: PUBLIC TYPE = UserExecPrivate.ExecPrivateRecord; HistoryEventPrivateRecord: PUBLIC TYPE = UserExecPrivate.HistoryEventPrivateRecord; dontConfirmModes: REF Spell.ModesRecord _ NEW[Spell.ModesRecord _ [inform: NULL, confirm: NULL, disabled: NULL, timeout: NULL, defaultConfirm: NULL]]; -- if user profile indicates confirmation required for * expansion, this will override that for benign operations such as ?, ^X etc. SetDontConfirmModes: UserProfile.ProfileChangedProc = { dontConfirmModes^ _ Spell.defaultModes^; dontConfirmModes.confirm _ MIN[allAccountedFor, dontConfirmModes.confirm]; dontConfirmModes.inform _ MIN[allAccountedFor, dontConfirmModes.inform]; }; Help: MethodProc = { OPEN Rope; out: STREAM; commandLine: ROPE = event.commandLine; inRopeStream: STREAM; len: INT; allButLast, firstToken: ROPE; len _ Rope.Length[commandLine]; SELECT Rope.Fetch[commandLine, len - 1] FROM '? => NULL; ENDCASE => RETURN[FALSE]; out _ UserExec.GetStreams[exec].out; NewLine[out]; IF len = 1 THEN { PrintAllCommands[out]; RETURN[TRUE]; }; allButLast _ Rope.Substr[commandLine, 0, len - 1]; inRopeStream _ RIS[allButLast]; firstToken _ IO.GetToken[inRopeStream, IF Rope.Fetch[allButLast, 0] = '_ THEN IO.TokenProc ELSE IO.WhiteSpace]; -- added IO.WhiteSpace to handle things like foo*? IO.SkipOver[inRopeStream, IO.WhiteSpace]; IF inRopeStream.EndOf[] THEN { -- command followed by ? IF NOT PrintCommand[name: firstToken, event: event, exec: exec] THEN out.PutF["*nnot a command\n"]; RETURN[TRUE]; } ELSE IF Rope.Equal[firstToken, "_"] THEN { -- print type of object OPEN AMTypes; expr: Expression; i: INT; target: ROPE; event.commandLine _ Rope.Concat[UserExecPrivate.GetRestOfStream[inRopeStream], "\n"]; [] _ IO.RIS[event.commandLine, event.commandLineStream]; UserExecPrivate.EvalEvent[event, exec]; expr _ event.expression; IF expr.correctionMade THEN event.input _ Rope.Concat[event.input, "?"]; out.PutRope["is of type "]; -- start printing so user doesnt see such a long delay. IF (i _ Rope.Find[expr.rope, "."]) # -1 -- is of form a.b, rather than a.b.c AND Rope.Find[s1: expr.rope, s2: ".", pos1: i + 1] = -1 THEN { fileName: ROPE = Rope.Concat[Rope.Substr[base: expr.rope, len: i], ".mesa"]; target _ Rope.Substr[base: expr.rope, start: i + 1, len: Rope.Length[expr.rope] - i - 1]; IF IO.WhiteSpace[Rope.Fetch[target, Rope.Length[target] - 1]] = sepr THEN target _ Rope.Substr[base: target, len: Rope.Length[target] - 1]; IF NOT UserExecPrivate.PrintDeclFromSource[target: target, file: fileName, exec: exec] THEN target _ NIL; -- to indicate that it didnt find it in file }; { typ, underType: Type; class: AMTypes.Class; typeName: ROPE; typ _ TVType[expr.value]; underType _ UnderType[typ]; class _ TypeClass[underType]; IF target = NIL -- didn't find it in file. OR Rope.Length[typeName _ TypeToName[typ]] # 0 -- named type. All that was printed was the name (and possibly comments), e.g. IO.CRBreak. calling PutType will print undertype. THEN out.PutType[type: typ, verbose: TRUE] ELSE SELECT class FROM type => -- print the undertype. Assumption is that the top level type would be the same as what you got from the file, e.g. STREAM? the file says of TYPE = REF HandleRecord, now printing from type system gives you what HandleRecord is. However, note that for synonyms, you haven't seen type yet, e.g. if I ask for UserExec.HistoryEvent, it tells me from the file that this is History.HistoryEvent, and now I will print out what HistoryEventNode is. The right thing to do probably is to try to print the type from type system and see if what you get is the same. { range: Type = UnderType[AMTypes.TVToType[expr.value]]; SELECT TypeClass[range] FROM ref, pointer, longPointer => -- e.g. STREAM? { rangeType: Type = Range[range]; underRangeType: Type = UnderType[rangeType]; SELECT TypeClass[underRangeType] FROM record, structure => out.Put[type[rangeType], text[": TYPE = "], type[underRangeType]]; ENDCASE; }; ENDCASE; }; ENDCASE; }; RETURN[TRUE]; } -- FUTURE EXTENSIONS TO ALLOW ? AT SOME LATER POINT IN COMMAND LINE. }; -- Help ExpandControlX: MethodProc = { OPEN Rope; breakProc: IO.BreakProc = { RETURN[IF char = ControlX THEN sepr ELSE IO.WhiteSpace[char]]; }; commandLine: ROPE _ event.commandLine; out: STREAM; inRopeStream: STREAM; registration: REF UserExecPrivate.CommandRecord; len: INT; allButLast, firstToken: ROPE; len _ Rope.Length[commandLine]; SELECT Rope.Fetch[commandLine, len - 1] FROM ControlX => NULL; ENDCASE => RETURN[FALSE]; out _ UserExec.GetStreams[exec].out; out.EraseChar[ControlX]; out.Flush[]; allButLast _ Rope.Substr[commandLine, 0, len - 1]; inRopeStream _ RIS[rope: allButLast]; firstToken _ IO.GetToken[inRopeStream, breakProc]; registration _ UserExecPrivate.GetRegistrationData[UserExecPrivate.LookupCommand[name: firstToken, event: event, exec: exec]]; IF registration # NIL AND registration.transformProc # NIL THEN { event.commandLine _ Rope.Concat[UserExecPrivate.GetRestOfStream[inRopeStream], "\n"]; [] _ RIS[rope: event.commandLine, oldStream: event.commandLineStream]; -- set up to call transformProc commandLine _ registration.transformProc[event, exec, registration.clientData]; } ELSE { commandLine _ UserExecPrivate.ExpandCommandLine[line: Rope.Substr[commandLine, 0, len - 1], modes: dontConfirmModes, event: event, exec: exec]; }; WHILE (len _ Rope.Length[commandLine]) # 0 AND IO.WhiteSpace[Rope.Fetch[commandLine, len -1]] = sepr DO commandLine _ Rope.Substr[base: commandLine, len: len - 1]; ENDLOOP; out.Put[char['\n], rope[commandLine]]; UserExecPrivate.ReadQuietly[rope: commandLine, exec: exec]; RETURN[TRUE]; }; -- of Expand Escape: MethodProc = { OPEN Rope; commandLine: ROPE = event.commandLine; out: STREAM; inRopeStream: STREAM; allButLast, firstToken: ROPE; first: BOOLEAN _ TRUE; r: ROPE; matches: LIST OF ROPE; len: INT; len _ Rope.Length[commandLine]; SELECT Rope.Fetch[commandLine, len - 1] FROM ESC => NULL; ENDCASE => RETURN[FALSE]; out _ UserExec.GetStreams[exec].out; out.EraseChar[ESC]; out.Flush[]; allButLast _ Rope.Substr[commandLine, 0, len - 1]; inRopeStream _ RIS[rope: allButLast]; DO firstToken _ IO.GetToken[inRopeStream, IO.IDProc]; IO.SkipOver[inRopeStream, IO.WhiteSpace]; IF inRopeStream.EndOf[] THEN EXIT; first _ FALSE; ENDLOOP; IF first THEN -- registered command matches _ UserExec.GetMatchingList[unknown: Rope.Concat[firstToken, "*"], generator: UserExecPrivate.commandGenerator, modes: dontConfirmModes, event: event, exec: exec] ELSE -- assume is a file name matches _ UserExec.GetMatchingFileList[file: Rope.Concat[firstToken, "*"], modes: dontConfirmModes, event: event, exec: exec]; r _ EscComplete[unknown: firstToken, matches: matches]; out.PutRope[r]; -- want to make it look like event just continued, so output extra characters. IF Rope.IsEmpty[r] THEN { MessageWindow.Append["No match", TRUE]; MessageWindow.Blink[]; }; UserExecPrivate.ReadQuietly[rope: Rope.Replace[base: commandLine, start: len - 1, len: 1, with: r], exec: exec]; RETURN[TRUE]; }; -- of Escape ImplicitRunAndCall: MethodProc = { commandLine: ROPE = event.commandLine; commandLineStream: STREAM = event.commandLineStream; privateEvent: REF HistoryEventPrivateRecord = event.privateStuff; firstToken, name, error: ROPE _ NIL; i: INT; IF privateEvent.inCMFile THEN {[] _ UserExecPrivate.RunAndCall[event: event, exec: exec, clientData: NIL]; RETURN[TRUE]}; IF privateEvent.inCommandFile THEN RETURN[FALSE]; firstToken _ IO.GetToken[commandLineStream]; IF (i _ Rope.Find[s1: firstToken, s2: "."]) = -1 THEN firstToken _ Rope.Concat[firstToken, ".bcd"] ELSE IF Rope.Find[s1: firstToken, s2: "bcd", pos1: i, case: FALSE] = -1 THEN RETURN[FALSE]; IF NOT UserExec.CheckForFile[firstToken] THEN RETURN[FALSE]; IO.SkipOver[commandLineStream, IO.WhiteSpace]; UserExecPrivate.DoesUserMean[Rope.Concat[IF commandLineStream.EndOf[] THEN "Run " ELSE "RunAndCall ", Rope.Substr[base: commandLine, len: Rope.Length[commandLine] - 1]], exec]; RETURN[TRUE]; }; Registered: MethodProc = { breakProc: IO.BreakProc = { RETURN[IF char = ControlX THEN sepr ELSE IO.TokenProc[char]]; }; commandLineStream: STREAM = event.commandLineStream; privateEvent: REF HistoryEventPrivateRecord = event.privateStuff; firstToken: ROPE; command: ROPE; i: INT; firstToken _ IO.GetToken[commandLineStream, breakProc]; command _ UserExecPrivate.LookupCommand[name: firstToken, event: event, exec: exec]; -- does correction. IF command = NIL AND privateEvent.inCMFile AND (i _ Rope.Find[s1: firstToken, s2: ".~"]) # -1 THEN { token: ROPE = Rope.Substr[base: firstToken, len: i]; command _ UserExecPrivate.LookupCommand[name: token, event: NIL, exec: NIL]; IF command = NIL THEN UserExecPrivate.EventFailed[event: event, msg: Rope.Concat[token, " is not a registered command.\n"], offender: token]; }; event.commandLine _ UserExecPrivate.GetRestOfStream[commandLineStream]; [] _ IO.RIS[event.commandLine, event.commandLineStream]; RETURN[UserExecPrivate.CallRegisteredProc[command, event, exec]]; }; EscComplete: PROC [unknown: ROPE, matches: LIST OF ROPE] RETURNS [common: ROPE] = { lenX: INT = Rope.Length[unknown]; r: ROPE; i: INT _ 0; IF matches = NIL THEN RETURN[""]; r _ matches.first; IF matches.rest = NIL THEN RETURN[Rope.Concat[Rope.Substr[base: r, start: lenX], " "]]; i _ Rope.Length[r]; FOR l: LIST OF ROPE _ matches.rest, l.rest UNTIL l = NIL DO i _ MIN[Rope.Run[s1: r, s2: l.first, case: FALSE]]; ENDLOOP; RETURN[Rope.Substr[base: r, start: lenX, len: i - lenX]]; }; ExplainExec: UserExec.CommandProc = { out: STREAM = IO.CreateViewerStreams["UserExec.doc"].out; out.PutRope["\nMethods are applied to the input line in the order listed below until one succeeds. If none succeed, print a message and go to next event."]; out.PutRope["\n\nMethods:\n"]; FOR lst: UserExecPrivate.MethodList _ UserExecPrivate.methodList, lst.rest UNTIL lst = NIL DO out.PutF["\n%g\n\t\t%g", rope[lst.first.name], rope[lst.first.doc]]; ENDLOOP; out.PutRope["\n\nRegistered Commands: "]; PrintAllCommands[out]; }; PrintCommand: PUBLIC PROC [name: ROPE, event: HistoryEvent, exec: UserExec.ExecHandle] RETURNS[BOOLEAN] = { command: ROPE _ UserExecPrivate.LookupCommand[name: name, event: event, exec: exec]; out: STREAM = UserExec.GetStreams[exec].out; IF command = NIL THEN -- name might be a pattern that matches more than one command TRUSTED { lst: LIST OF ROPE = UserExec.GetMatchingList[unknown: name, generator: UserExecPrivate.commandGenerator, modes: dontConfirmModes, event: event, exec: exec]; compare: List.CompareProc = TRUSTED { RETURN[Rope.Compare[NARROW[ref1], NARROW[ref2], FALSE]]; }; IF lst = NIL THEN RETURN[FALSE]; FOR commands: LIST OF ROPE _ LOOPHOLE[List.Sort[LOOPHOLE[lst], compare]], commands.rest UNTIL commands = NIL DO [] _ PrintCommand[name: commands.first, event: event, exec: exec]; ENDLOOP; } ELSE { reg: REF UserExecPrivate.CommandRecord = UserExecPrivate.GetRegistrationData[command]; doc: ROPE; out.PutF["*n%-15g", rope[command]]; IF reg # NIL THEN doc _ reg.documentation ELSE doc _ Commander.Lookup[command].doc; IF Rope.Length[doc] = 0 THEN out.PutRope["no documentation supplied with command"] ELSE out.Put[rope[doc]]; IF reg # NIL AND reg.nameOfBCD # NIL AND Commander.Lookup[command].proc = UserExecPrivate.dummyCommanderProc THEN out.PutF["*n{not loaded yet}"]; }; RETURN[TRUE]; }; PrintAllCommands: PROC [out: STREAM] = { commandList: LIST OF REF Reg; Reg: TYPE = RECORD[name, doc: ROPE]; makeList: PROCEDURE [name: ROPE, proc: Commander.CommandProc, doc: ROPE] RETURNS [stop: BOOL] = { commandList _ CONS[NEW[Reg _ [name, doc]], commandList]; RETURN[FALSE]; }; compare: List.CompareProc = { a, b: REF Reg; a _ NARROW[ref1]; b _ NARROW[ref2]; RETURN[Rope.Compare[a.name, b.name, FALSE]]; }; out.PutRope["(*) following the explanation indicates further explanation available by typing {command}?\n"]; [] _ Commander.Enumerate[makeList]; TRUSTED {commandList _ LOOPHOLE[List.Sort[LOOPHOLE[commandList], compare]]}; FOR l: LIST OF REF Reg _ commandList, l.rest UNTIL l = NIL DO reg: REF UserExecPrivate.CommandRecord = UserExecPrivate.GetRegistrationData[l.first.name]; IF IO.UserAbort[out] THEN ERROR IO.UserAborted[out]; IF reg # NIL AND reg.fromCatalogue THEN LOOP; out.PutF["\n%g", rope[l.first.name]]; IO.SpaceTo[out, 20]; IF reg # NIL THEN { out.PutRope[reg.briefDocumentation]; IF reg # NIL AND NOT Rope.Equal[reg.documentation, reg.briefDocumentation] THEN out.PutRope[" (*)"]; } ELSE { doc: ROPE = l.first.doc; i: INT = Rope.Find[doc, "\n"]; IF i # -1 THEN out.PutF["%g (**)", rope[Rope.Substr[base: doc, len: i]]] -- when registering with commander, this is the way to handle the brief versus full documentation issue ELSE out.PutRope[doc]; -- when registering with commander, this is the way to handle the brief versus full documentation issue }; ENDLOOP; out.PutChar['\n]; }; UserExec.RegisterMethod [proc: Help, name: "Help", doc: "? following a mesa expression, evaluates the expression and prints its type, e.g. {proc}? will print the arguments and return values of proc. If the mesa expression is of the form module.id, will also look in module for the declaration of id, and if found, print that declaration including its comments, instead of using the runtime type system. // In other contexts, ? presents explanation/documentation regarding the token immediately preceding the ?."]; UserExec.RegisterMethod [proc: ExpandControlX, name: "ControlX", doc: "causes the command line to be expanded and the result displayed to the user for confirmation before execution, e.g. @file => contents of file, history commands => corresponding input, * expansion performed, etc. "]; UserExec.RegisterMethod [proc: Escape, name: "ESC", doc: "completes the previous token where possible"]; UserExec.RegisterMethod [proc: Registered, name: "Registered Command", doc: "If the first token on the input line is the name of one of the registered commmands listed below (case does not matter), call the corresponding registered procedure on the remainder of the input line, e.g. Compile Foo Fie. // @{fileName} appearing in the input line is replaced by the contents of {fileNme} or {fileName}.cm, e.g. Print @myfiles."]; UserExec.RegisterMethod [proc: ImplicitRunAndCall, name: "Implicit RunAndCall", doc: "If the first token on the input line is the name of a bcd file, ask the user whether he mean to Run the bcd file, allowing him to confirm by simply typing CR."]; UserExec.RegisterCommand["Help", ExplainExec, "Provides more complete explanation of user exec in separate viewer."]; UserProfile.CallWhenProfileChanges[SetDontConfirmModes]; END. -- of UserExecMethodsImpl.mesa °UserExecMethodsImpl.mesa; Edited by Teitelman on June 20, 1983 1:24 pm connecting concrete and opaque types constants Methods matches is a LIST of ropes whose leading characters match unknown (probably obtained via FixSpell or FileSpell). EscComplete computes the longest common substring, echoes the characters to exec.out, followed by a space if only one candidate, and returns the longest common substring. Miscellaneous Initialization Edited on December 9, 1982 12:30 am, by Teitelman fixed bug in Escape causing BoundsFault changes to: Escape Edited on December 18, 1982 7:07 pm, by Teitelman fixed PrintCommands to take a stream, rather than exec so that ExplainExec could output all material to the other viewer. changes to: ExplainExec, PrintCommands , DIRECTORY, Help Edited on December 22, 1982 12:57 pm, by Teitelman changes to: DIRECTORY, IMPORTS, Help, breakProc (local of ExpandControlX), ExpandControlX, Escape, ImplicitRunAndCall, breakProc (local of Registered), Registered Edited on January 4, 1983 11:56 am, by Teitelman changes to: Help, PrintCommand, ExpandControlX, Escape Edited on January 21, 1983 4:23 pm, by Teitelman changes to: ExpandControlX Edited on March 1, 1983 11:41 pm, by Teitelman changes to: PrintCommand Edited on March 4, 1983 7:37 pm, by Teitelman changes to: Help Edited on March 6, 1983 2:44 pm, by Teitelman changes to: DIRECTORY, Registered Edited on March 10, 1983 3:06 am, by Teitelman changes to: DIRECTORY, IMPORTS, Registered Edited on March 28, 1983 3:51 pm, by Teitelman changes to: DIRECTORY, IMPORTS, Escape Edited on April 5, 1983 7:36 pm, by Teitelman changes to: Help Edited on April 7, 1983 2:33 pm, by Teitelman changes to: DIRECTORY, IMPORTS, Help, Escape, Registered, PrintCommand, PrintCommands, SetDontConfirmModes, RegisterCommanderProc, CommanderProcRecord, CallCommanderProc, IsACommanderProc, EscComplete, [, UserProfile, Help, Registered, UserExec, IMPORTS, Registered, Registered Edited on April 19, 1983 1:00 pm, by Teitelman changes to: DIRECTORY, ExpandControlX, Registered, PrintCommand, IMPORTS, print (local of PrintCommands), PrintCommands, Help, PrintAllCommands, makeList (local of PrintAllCommands), compare (local of PrintAllCommands), IMPORTS, ExplainExec, PrintAllCommands, PrintAllCommands, PrintAllCommands Edited on April 23, 1983 1:45 pm, by Teitelman changes to: PrintCommand, compare (local of PrintCommand) Edited on May 24, 1983 10:28 am, by Teitelman changed call to GetToken in escapecomplete to use IDProc rather than TokenProc because of file names containing -, e.g. Horning tried typing Larch-H ESC and got "No match" changes to: Escape Edited on June 20, 1983 1:09 pm, by Teitelman changes to: Help, ExplainExec, PrintAllCommands ΚΘ– "Cedar" style˜JšœF™FJ˜šΟk ˜ JšœœD˜QJšœ œ"˜1Jš œœQœ9œœœe˜‘Jšœœ˜Jšœœ˜$JšœœQ˜[Jšœœ˜(Jšœ œ.˜?Jšœ œbœH˜ΊJšœœ¬˜ΑJ˜J˜—J˜šΠblœœ˜"J˜—Jšœ œU˜hJ˜Jšœ˜"J˜Jšœ œœ ˜headšœ$™$JšΟn œœΠkrΡckr9˜dJšŸœœœ%˜CJšŸœœœ-˜S—šœ ™ JšŸœœœœ œ œ œœΟc„˜œJ˜šŸœ$˜7J˜(Jšœœ,˜JJšœœ+˜HJ˜——™šŸœ˜Jšœ˜ Jšœœ˜ Jšœ œ˜&Jšœœ˜Jšœœ˜ Jšœœ˜J˜Jšœ˜šœ"˜,Jšœœ˜ Jšœœœ˜—Jšœ$˜$J˜ šœ ˜J˜Jšœœ˜ J˜—J˜2Jšœœ ˜Jšœ œœ œœ œœ’2˜£Jšœ)˜)šœœ’˜7Jš œœ:œ!œœ˜rJšœ˜—šœœ’˜*šœ’˜Jšœ ˜ J˜Jšœœ˜Jšœœ˜ JšœU˜UJšœœœ-˜8Jšœ'˜'Jšœ˜Jšœœ-˜HJšœ’7˜Sšœ&’%˜Mšœ5˜>Jšœ œ>˜LJšœY˜YJšœœ@œB˜‹Jš œœQœ œ’,˜—J˜——š˜J˜J˜Jšœ œ˜J˜J˜J˜šœ œ’˜*šœ-’˜°Jšœ!œ˜*——š˜šœ˜šœ’©˜±š˜J˜6šœ˜šœ’˜,˜J˜ J˜,šœ˜%˜J˜B—Jšœ˜—J˜——Jšœ˜—J˜——Jšœ˜ ——Jšœ˜—Jšœœ˜ Jš˜——Jš’D˜DJšœ’˜ J˜—šŸœ˜Jšœ˜ šŸ œ˜Jšœœœœ˜>Jšœ˜—Jšœ œ˜&Jšœœ˜ Jšœœ˜Jšœœ˜0Jšœœ˜ Jšœœ˜Jšœ˜šœ"˜,Jšœ œ˜Jšœœœ˜—Jšœ$˜$Jšœ˜J˜ J˜2Jšœœ˜%Jšœ2˜2Jšœ~˜~š œœœœ˜AJšœU˜UJšœœ@’ ˜hJšœO˜OJ˜—š˜Jšœ˜J˜—šœ&œ7˜gJ˜;Jšœ˜—J˜&J˜;Jšœœ˜ Jšœ’ ˜J˜—šŸœ˜Jšœ˜ Jšœ œ˜&Jšœœ˜ Jšœœ˜Jšœœ˜Jšœœœ˜Jšœœ˜Jšœ œœœ˜Jšœœ˜ Jšœ˜šœ"˜,Jšœœ˜ Jšœœœ˜—Jšœ$˜$Jšœœ˜J˜ J˜2Jšœœ˜%šœ˜Jšœ2˜2Jšœ)˜)Jšœœœ˜"Jšœœ˜Jšœ˜—šœœ’˜$Jšœ©˜©—šœ’˜Jšœ~˜~—J˜7Jšœ’N˜_šœœ˜Jšœ!œ˜'J˜J˜—J˜pJšœœ˜ Jšœ’ ˜J˜J˜Jš’›™›—šŸœ˜$Jšœ œ˜&Jšœœ˜4Jšœœ0˜AJšœœœ˜$Jšœœ˜J˜Jš œœHœœœ˜yJšœœœœ˜1Jšœ,˜,J˜Jšœ/œ-˜bJš œœ5œœœœ˜[Jš œœ#œœœ˜=Jšœ.˜.šœ)œœœ˜eJ˜J—Jšœœ˜ J˜J˜—šŸ œ˜šŸ œ˜Jšœœœœ˜=Jšœ˜—Jšœœ˜4Jšœœ0˜AJšœ œ˜Jšœ œ˜Jšœœ˜Jšœ7˜7JšœV’˜iš œ œœœ0˜bšœ˜Jšœœ)˜4Jšœ<œœ˜LJšœ œœx˜J˜——JšœG˜GJšœœœ-˜8Jšœ;˜AJ˜——™ šŸ œœ œ œœœœ œ˜SJšœœ˜!Jšœœ˜Jšœœ˜ Jšœ œœœ˜!J˜Jšœœœœ6˜WJ˜Jš œœœœœœ˜;Jšœœ$œ˜3Jšœ˜Jšœ3˜9J˜J˜J˜—šŸ œ˜%Jšœœœ)˜9J˜œJ˜šœHœœ˜]J˜DJšœ˜—J˜)J˜J˜J˜—š Ÿ œœœœ2œœ˜kJšœ œG˜UJšœœ!˜,šœ œœ’>˜Ušœ˜ Jšœœœœ‹˜œšŸœœ˜%Jšœœœœ˜8J˜—Jš œœœœœ˜ šœ œœœœ œ œ œ˜oJšœB˜BJšœ˜—J˜——š˜JšœœN˜VJšœœ˜ Jšœ#˜#Jšœœœœ%˜SJšœœ6˜RJšœ˜Jš œœœœœEœ ˜‘J˜—Jšœœ˜ J˜J˜J˜—šŸœœœ˜(Jšœ œœœ˜Jšœœœ œ˜$š Ÿœ œœ$œœœ˜aJšœœœ"˜8Jšœœ˜J˜—šŸœ˜Jšœœ˜Jšœœ˜Jšœœ˜Jšœœ˜,J˜—J˜lJ˜#Jšœœ œ˜Lš œœœœœœ˜=JšœœS˜[Jšœœœ˜4Jš œœœœœ˜-Jšœ%˜%J˜šœœœ˜Jšœ$˜$Jš œœœœ7œ˜dJ˜—šœ˜Jšœœ˜Jšœœ˜Jšœœ<’g˜±Jšœ’g˜J˜—Jš˜—J˜J˜J˜——™Jšœ˜J˜Jšœž˜žJ˜Jšœh˜hJ˜Jšœ©˜©J˜Jšœχ˜χJšœw˜wJ˜J˜8J˜—Jšœ’˜#J™™1J™'Jšœ Οr™—™1J™yJšœ £™&Jš£™—™2Jšœ £#œ£7œ£ ™’—™0Jšœ £*™6—™0Jšœ £™—™.Jšœ £ ™—™-Jšœ £™—™-Jšœ £™!—™.Jšœ £™*—™.Jšœ £™&—™-Jšœ £™—™-Jšœ £‰™•—™.Jšœ £Cœ£1œ£ œ£L™¦—™.Jšœ £œ™9—J™™-J™«Jšœ £™—™-Jšœ £#™/—J™—…—?X|