DIRECTORY CHNameP2V0 USING [Name], IO USING [STREAM], NSString USING [AppendString, CopyString, EquivalentStrings, FreeString, LogicalLength, MakeString, nullString, ScanForCharacter, String, StringFromMesaString], NSExec, NSTTY USING [PutLine, SetPagination], Process USING [Detach], Rope USING [FromRefText, ROPE], TTY USING [Handle, NewLine, PutCR, PutLine, PutString, UserAbort], TTYExtras USING [], XFormat USING [Handle], XNS USING [Address, unknownAddress], XNSAuth USING [Identity]; NSExecImpl: CEDAR MONITOR IMPORTS NSExec, NSString, NSTTY, Rope, TTY, TTYExtras EXPORTS NSExec = BEGIN OPEN CHName: CHNameP2V0; ROPE: TYPE ~ Rope.ROPE; STREAM: TYPE ~ IO.STREAM; Handle: PUBLIC TYPE = RECORD [session: CARDINAL]; Client: TYPE = REF ClientData; ClientData: TYPE = RECORD [ name: NSString.String _ NSString.nullString, -- generic name of this client command: NSExec.Command, -- the "primary" command registered to identify the client in the NSExec and executed by the user to switch to the client's context. acronym: NSString.String _ NSString.nullString, id: NSExec.ClientID, procs: NSExec.ClientProcs, initialized: BOOLEAN _ FALSE, next: Client _ NIL]; -- pointer to next node in list ExecData: TYPE = REF RECORD [data: SEQUENCE length: CARDINAL OF ExecObject]; ExecObject: TYPE = RECORD [ tty: TTY.Handle, output: XFormat.Handle, currentClient: Client _ NIL, okForAsyncMessage: BOOLEAN _ FALSE, -- between commands qTop: CARDINAL _ 0, -- index of first free queue slot in asyncQ asyncQList: AsyncQList, hostName: NSString.String _ NSString.nullString, -- of connected m/c user: SELECT loggedOnStatus: * FROM loggedOn => [ userName: CHName.Name _ [NIL, NIL, NIL], userIdentity: XNSAuth.Identity _ NIL, userAServerSA, userEnabled: BOOLEAN _ FALSE], notLoggedOn => NULL, ENDCASE _ notLoggedOn[]]; AsyncQList: TYPE = RECORD[q: QArray]; QArray: TYPE = ARRAY [0..qSize) OF QEntry; QEntry: TYPE = RECORD [time: CARD _ 0, message: NSString.String _ NIL]; qSize: CARDINAL = 3; ActiveServices: TYPE = REF ActiveStatus; ActiveStatus: TYPE = RECORD [name: NSString.String, next: ActiveServices]; localExec: PUBLIC READONLY Handle; -- handle for the local TTY totalClients: CARDINAL _ 0; firstClient: PUBLIC Client _ NIL; execData: ExecData _ NIL; serverName: CHName.Name _ [NIL, NIL, NIL]; serverDesc: NSString.String _ NSString.nullString; serverIdentity: XNSAuth.Identity; Error: PUBLIC ERROR [type: NSExec.Errortype] = CODE; NotFound: ERROR = CODE; AssignClientID: PUBLIC ENTRY PROCEDURE RETURNS [NSExec.ClientID] = { ENABLE UNWIND => NULL; RETURN[[totalClients _ totalClients + 1]]}; CreateClient: PUBLIC ENTRY PROCEDURE [id: NSExec.ClientID, command: NSExec.Command, procs: NSExec.ClientProcs, acronym: NSString.String] = BEGIN ENABLE UNWIND => NULL; IF NOT ValidID[id] THEN RETURN WITH ERROR NSExec.Error[invalidID]; IF command.name.length = 0 OR acronym.length = 0 THEN RETURN WITH ERROR NSExec.Error[invalidString]; BEGIN clientName: NSString.String _ NSString.CopyString[command.name]; firstClient _ NEW[ClientData _ [name: clientName, command: [clientName, command.proc, command.activityCheck, command.helpProc], acronym: NSString.CopyString[acronym], id: id, procs: procs, next: firstClient]]; END; END; -- CreateClient DestroyClient: PUBLIC ENTRY PROCEDURE [id: NSExec.ClientID] = BEGIN ENABLE UNWIND => NULL; client, predecessor: Client; [client, predecessor] _ FindClient[id ! NotFound => ERROR NSExec.Error[invalidID]]; IF predecessor = NIL THEN firstClient _ client.next ELSE predecessor.next _ client.next; END; -- DestroyClient EnumerateClients: PUBLIC PROCEDURE [enumProc: NSExec.EnumerateClientProc] = BEGIN continue: BOOLEAN _ TRUE; FOR client: Client _ firstClient, client.next UNTIL client = NIL OR NOT continue DO IF ~client.initialized THEN LOOP; continue _ enumProc[client.id, client.command, Rope.FromRefText[client.acronym], client.procs] ENDLOOP; END; -- EnumerateClients ClientState: PUBLIC PROCEDURE [id: NSExec.ClientID] RETURNS [activated, initialized: BOOLEAN] = BEGIN client: Client _ FindClient[id ! NotFound => ERROR NSExec.Error[invalidID]].client; activated _ Activated[client.name]; initialized _ client.initialized; END; -- ClientState AddClientCommands: PUBLIC PROCEDURE [id: NSExec.ClientID, commands: NSExec.Commands] = BEGIN ENABLE UNWIND => NULL; client: Client _ FindClient[id ! NotFound => ERROR NSExec.Error[invalidID]].client; FOR i: CARDINAL IN [0..commands.length) DO AddCommand[commands[i], client] ENDLOOP END; -- AddClientCommands CreateExec: PUBLIC PROCEDURE [tty: TTY.Handle, host: XNS.Address] = BEGIN ENABLE ABORTED => CONTINUE; DisplayHerald[tty: tty, displayTime: FALSE]; -- may raise ABORTED ExecProcess[CreateExecInternal[tty, host].exec]; END; -- CreateExec EnumerateExecs: PUBLIC PROCEDURE [enumProc: NSExec.EnumerateExecProc] = {}; AddExecCommand: PUBLIC PROCEDURE [command: NSExec.Command, unload: PROCEDURE _ NIL] = BEGIN AddCommand[command: command, client: NIL, unload: unload]; END; -- AddExecCommand GetTTY: PUBLIC PROCEDURE [exec: NSExec.Handle] RETURNS [tty: TTY.Handle] = { RETURN[execData.data[exec.session].tty]}; CheckForAbort: PUBLIC PROCEDURE [exec: NSExec.Handle] RETURNS [abort: BOOLEAN] = {RETURN[TTY.UserAbort[NSExec.GetTTY[exec]]]}; SetContext: PUBLIC PROCEDURE [exec: Handle, id: NSExec.ClientID, context: NSExec.Context, terminationHandler: NSExec.TerminationHandler] = BEGIN END; -- SetContext GetContext: PUBLIC PROCEDURE [exec: Handle, id: NSExec.ClientID] RETURNS [context: LONG UNSPECIFIED] = BEGIN RETURN[LONG[0]]; END; -- of GetContext DestroyContext: PUBLIC PROCEDURE [exec: Handle, id: NSExec.ClientID] = BEGIN END; -- of DestroyContext BroadcastAsyncMessage: PUBLIC PROCEDURE [string: NSString.String, id: NSExec.ClientID] = { broadcastMessage: NSExec.EnumerateExecProc = {PutAsyncMessage[exec, string, id]}; NSExec.EnumerateExecs[broadcastMessage]}; -- of BroadcastAsyncMessage PutAsyncMessage: PUBLIC PROCEDURE [exec: NSExec.Handle, string: NSString.String, id: NSExec.ClientID] = BEGIN client: Client _ FindClient[id ! NotFound => ERROR NSExec.Error[invalidID]].client; msg: NSString.String _ NSString.MakeString[client.acronym.length + 2 + string.length]; tty: TTY.Handle; -- should be initialized within the catch phase for NSSession.Error BEGIN ENABLE --NSSession.Error, --ABORTED => {NSString.FreeString[msg]; CONTINUE}; msg _ NSString.AppendString[msg, client.acronym]; msg _ NSString.AppendString[msg, NSString.StringFromMesaString[": "]]; msg _ NSString.AppendString[msg, string]; IF TTY.NewLine[tty _ NSExec.GetTTY[exec]] OR OkForAsyncMsg[exec] THEN { oldPageLength: CARDINAL _ NSTTY.SetPagination[h: tty, pageLength: 0]; -- eliminates (more) PutMessage[exec, msg]; [] _ NSTTY.SetPagination[h: tty, pageLength: oldPageLength]; NSString.FreeString[msg]} ELSE TRUSTED {Process.Detach[FORK PutAsyncMessageEntry[exec, msg]]}; END; -- ENABLE END; -- PutAsyncMessage PutErrorMessage, PutIndentedMessage: PUBLIC PROCEDURE [exec: NSExec.Handle, string: NSString.String] = BEGIN tty: TTY.Handle _ NSExec.GetTTY[exec]; IF ~TTY.NewLine[tty] THEN TTY.PutCR[tty]; TTY.PutString[tty, " "]; NSTTY.PutLine[tty, string]; END; -- PutErrorMessage, PutIndentedMessage PutMessage: PUBLIC PROCEDURE [exec: NSExec.Handle, string: NSString.String] = BEGIN tty: TTY.Handle _ NSExec.GetTTY[exec]; IF ~TTY.NewLine[tty] THEN TTY.PutCR[tty]; NSTTY.PutLine[tty, string]; END; -- PutMessage OutputHandle: PUBLIC PROCEDURE [exec: NSExec.Handle] RETURNS [output: XFormat.Handle] = {RETURN[(execData[exec.session].output)]}; UserName: PUBLIC PROCEDURE [exec: NSExec.Handle] RETURNS [name: CHName.Name _ [NIL, NIL, NIL]] = {RETURN[LoggedOnData[exec].userName]}; UserIdentity: PUBLIC PROCEDURE [exec: NSExec.Handle] RETURNS [identity: XNSAuth.Identity] = {RETURN[LoggedOnData[exec].userIdentity]}; UserState: PUBLIC PROCEDURE [exec: NSExec.Handle] RETURNS [loggedOn, serverSA, enabled: BOOLEAN _ FALSE] = TRUSTED { data: ExecObject = execData[exec.session]; WITH d: data SELECT FROM loggedOn => {loggedOn _ TRUE; serverSA _ d.userAServerSA; enabled _ d.userEnabled}; ENDCASE => NULL; }; UserAServerSA: PUBLIC NSExec.Predicate = {RETURN[UserState[exec].serverSA]}; UserEnabled: PUBLIC NSExec.Predicate = {RETURN[UserState[exec].enabled]}; UserLoggedOn: PUBLIC NSExec.Predicate = {RETURN[UserState[exec].loggedOn]}; Genesis: PUBLIC NSExec.Predicate = {RETURN[FALSE]}; GenesisOrEnabledSA: PUBLIC NSExec.Predicate = {RETURN[TRUE]}; GenesisOrSA: PUBLIC NSExec.Predicate = {RETURN[TRUE]}; ServerName: PUBLIC PROCEDURE RETURNS [name: CHName.Name] = { RETURN[serverName]}; ServerIdentity: PUBLIC PROCEDURE RETURNS [identity: XNSAuth.Identity] = { RETURN[serverIdentity]}; SystemDirectory: PUBLIC PROCEDURE RETURNS [directory: Rope.ROPE] = { RETURN["///System/"]}; WorkingDirectory: PUBLIC PROCEDURE RETURNS [directory: Rope.ROPE] = { RETURN["///Working/"]}; Run: PROCEDURE [name: ROPE, exec: Handle, codeLinks: BOOLEAN _ FALSE] = {}; Activated: PUBLIC --NSExecInternal-- PROCEDURE [name: NSString.String] RETURNS [BOOLEAN _ FALSE] = BEGIN FOR s: ActiveServices _ activeServices, s.next UNTIL s = NIL DO IF NSString.EquivalentStrings[name, s.name] THEN RETURN[TRUE]; ENDLOOP; END; -- Activated AddCommand: ENTRY PROCEDURE [command: NSExec.Command, client: Client, clientName: BOOLEAN _ FALSE, unload: PROCEDURE _ NIL] = BEGIN ENABLE UNWIND => NULL; length: CARDINAL _ NSString.LogicalLength[command.name]; pos, offset: CARDINAL _ 0; list: Entry _ topEntry; commandWord: NSString.SubStringDescriptor; IF length = 0 THEN ERROR NSExec.Error[invalidString]; DO pos _ NSString.ScanForCharacter[c: [0, LOOPHOLE[Ascii.SP]], s: command.name, start: offset]; SELECT pos FROM offset => {offset _ offset + 1; LOOP}; -- skip spaces LAST[CARDINAL] => { commandWord _ [command.name, offset, length - offset]; list _ InsertWordInList[list, commandWord]; EXIT}; ENDCASE => { commandWord _ [command.name, offset, pos - offset]; list _ InsertWordInList[list, commandWord]; offset _ pos + 1}; ENDLOOP; BEGIN -- begin exits DuplicateCommand IF clientName THEN {IF list.commandProcs # NIL THEN GOTO DuplicateCommand ELSE {list.commandProcs _ NEW[clientName ProcData _ [ execute: command.proc, activityProc: command.activityCheck, helpProc: command.helpProc, commandType: clientName[client]]]}} ELSE BEGIN p: NSExecInternal.Procs; FOR p _ list.commandProcs, p.next UNTIL p = NIL DO WITH commandProc: p SELECT FROM exec, clientName => GOTO DuplicateCommand; client => IF commandProc.client = client THEN GOTO DuplicateCommand; ENDCASE ENDLOOP; IF client = NIL THEN -- exec command p _ NEW[exec ProcData _ [execute: command.proc, activityProc: command.activityCheck, helpProc: command.helpProc, commandType: exec[unload]]] ELSE -- client command p _ NEW[client ProcData _ [next: list.commandProcs, execute: command.proc, activityProc: command.activityCheck, helpProc: command.helpProc, commandType: client[client]]]; list.commandProcs _ p; END; EXITS DuplicateCommand => { s: LONG STRING _ [128]; nss: NSString.String _ NSString.StringFromMesaString[s]; o: XFormat.Object _ XFormat.NSStringObject[@nss]; SCSCommon.FormatExpandedMsg[@o, M[keyDuplicateCommand], command.name]; NSExec.BroadcastAsyncMessage[nss, NSExec.nullClientID]}; END; -- of exits DuplicateCommand END; -- AddCommand CreateExecInternal: PUBLIC PROCEDURE [tty: TTY.Handle, hostName: XNS.Address _ XNS.unknownAddress] RETURNS [exec: Handle, execData: ExecData] = BEGIN nss: NSString.String _ NSString.MakeString[100]; object: XFormat.Handle _ XFormat.NSStringObject[nss]; asyncQ: AsyncQList; XFormat.NetworkAddress[object, hostName, productSoftware]; execData _ NEW[ExecObject _ [tty: tty, asyncQList: asyncQ, output: XFormat.TTYObject[tty], hostName: NSString.CopyString[nss]]]; END; -- of CreateExecInternal DisplayHerald: PUBLIC -- NSExecInternal -- PROCEDURE [tty: TTY.Handle, displayTime: BOOLEAN _ TRUE] = BEGIN o: XFormat.Handle _ XFormat.TTYObject[tty]; PutHerald: PROCEDURE [s: NSString.String] = {NSTTY.PutString[tty, s]}; PutBcdTime: PROCEDURE = BEGIN XFormat.Date[h: o, time: Loader.BCDBuildTime[DisplayHerald]]; END; -- PutBcdTime TTY.PutCR[tty]; NSHerald.GetExecHerald[PutHerald]; NSTTY.PutString[tty, " of "]; PutBcdTime[]; IF displayTime THEN XFormat.Date[o, BasicTime.Now[], dateAndTime]; TTY.PutCR[tty]; NSHerald.GetCopyrightMsg[PutHerald]; END; -- DisplayHerald ExecProcess: PUBLIC PROCEDURE [exec: Handle] = BEGIN ENABLE UNWIND => {}; -- FreeExecData[exec]; [] _ NSTTY.SetPagination[NSExec.GetTTY[exec], 23]; IF NSExec.ServerName[] # NIL AND exec # LOOPHOLE[NSExec.localExec] THEN DisplayServerName[exec]; -- may raise ABORTED ProcessCommands[exec]; END; -- ExecProcess FindClient: PUBLIC --NSExecInternal-- PROCEDURE [id: CARDINAL] RETURNS [client, predecessor: Client _ NIL] = BEGIN FOR client _ firstClient, client.next UNTIL client = NIL DO IF client.id = id THEN RETURN; predecessor _ client; ENDLOOP; ERROR NotFound; END; -- FindClient LoggedOnData: PROCEDURE [exec: Handle] RETURNS [REF loggedOn ExecObject] = { data: ExecObject = execData[exec]; WITH d: data SELECT FROM loggedOn => {data: REF loggedOn ExecObject _ d; RETURN[data]}; ENDCASE => NSExec.Error[noUser]}; OkForAsyncMsg: PROC [exec: Handle] RETURNS [okForAsyncMessage: BOOLEAN _ FALSE] = { }; PutAsyncMessageEntry: ENTRY PROCEDURE [exec: Handle, s: NSString.String] = BEGIN ENABLE UNWIND => NULL; END; -- PutAsyncMessageEntry ValidID: PUBLIC --NSExecInternal-- PROCEDURE [id: NSExec.ClientID] RETURNS [BOOLEAN] = {RETURN[id IN [1..totalClients]]}; END. LOG [Time - Person - Action] 14-Nov-83 8:54:49 - McManis - Created file. 3-Jan-84 15:16:44 - McManis - Added nullHandle, nullClientID, Context and TerminationHandler. Changed SetContext and GetContext to use Context and TerminationHandler. Renamed OutputObject to OutputHandle and changed it to return XFormat.Handle. Changed CreateExec to take "host: System.NetworkAddress" rather than credentials. 29-Apr-85 15:52:51 - McManis - Added cannotExpunge and cannotInitialize to ErrorType. Removed notInitialized from ClientStatus. Added predicates for Genesis. ͺNSExecImpl.mesa Copyright (C) 1984, 1985, 1986 by Xerox Corporation. All rights reserved. Tim Diebert: December 11, 1986 1:22:02 pm PST -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- Copied Types -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- Types -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- userFilingSession: NSFile.Session _ NSFile.nullSession, -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- Constants : -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- Variables : -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- Errors: -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- Creating and Manipulating Exec Clients: -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- RemoveClientCommands[id]; -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- Creating and Manipulating Execs: -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- << ASSERT: 1) All calls to this proc are for OTHER than the local exec. 2) The server profile has been established. >> TTYExtras.SetDataFile[tty, LOOPHOLE[UserProfile.GetEnumeratedValue[[XM[keyServer], XM[keyRemoteTerminalType]]]]]; Aborted: SIGNAL = CODE; EnumerateProc: NSSession.EnumerateProc = { proc: PROCEDURE = {IF ~enumProc[LOOPHOLE[session]] THEN SIGNAL Aborted}; EnterSessionAndExecute[session, proc ! NSSession.Error => CONTINUE]}; NSSession.Enumerate[sessionId, EnumerateProc ! Aborted => CONTINUE]}; RemoveExecCommand: PROCEDURE [name: NSString.String]; removes name as an exec command, having no effect if name is not a command. noContext: BOOLEAN _ FALSE; newContext: LONG POINTER TO ClientContext; IF ~NSExecInternal.ValidID[id] THEN NSExec.Error[invalidID]; newContext _ NSSession.GetContext[exec, sessionId, id ! NSSession.Error => {noContext _ TRUE; CONTINUE}]; IF noContext THEN newContext _ NEW[ ClientContext _ [ clientData: context, clientTerminateProc: terminationHandler]] ELSE newContext^ _ [clientData: context, clientTerminateProc: terminationHandler]; NSSession.SetContext[exec, sessionId, newContext, TerminationHandler, id]; clientContext: LONG POINTER TO ClientContext; IF ~NSExecInternal.ValidID[id] THEN NSExec.Error[invalidID]; clientContext _ NSSession.GetContext[exec.session, sessionId, LOOPHOLE[id] ! NSSession.Error => IF type = notSet THEN NSExec.Error[noContextSet]]; RETURN[clientContext.clientData]; IF ~NSExecInternal.ValidID[id] THEN NSExec.Error[invalidID]; NSSession.DestroyContext[exec, sessionId, id ! NSSession.Error => GOTO NoContext]; EXITS NoContext => ERROR NSExec.Error[noContextSet]; -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- String Output: -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- User Data: -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- UserFilingSession: PROCEDURE [exec: Handle] RETURNS [session: NSFile.Session]; -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- Genesis: -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- These predicates are used when commands should be available during Genesis. -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- Server and System Data: -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- SystemFilingSession: PROCEDURE RETURNS [session: NSFile.Session]; -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- Running Additional Software: -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- Local Procedures -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -- exec.session _ NSSession.Create[id: sessionId, name: NIL]; NSSession.SetContext[exec.session, sessionId, execData]; beginning of DisplayHerald FreeExecData[exec]; proc: ExecDataProc = {okForAsyncMessage _ execData.okForAsyncMessage}; Execute[exec, proc]; ENABLE {UNWIND => NULL; NSSession.Error => CONTINUE}; MustDisplayQ: PROCEDURE RETURNS [BOOLEAN _ FALSE] = BEGIN IF qTop = NSExecInternal.qSize -- queue is full OR PulsesToMilliSec[System.GetClockPulses[]] - PulsesToMilliSec[ asyncQ[qTop - 1].time] >= longAsyncDelayInMilliSec -- queue is old THEN RETURN[TRUE]; END; -- of MustDisplayQ tty: TTY.Handle = NSExec.GetTTY[exec]; -- raises NSSession.Error if the exec has already been destroyed. qTop: CARDINAL ¬ GetQTop[exec]; qEntry: NSExecInternal.QEntry ¬ [ time: System.GetClockPulses[], message: s]; asyncQ: NSExecInternal.AsyncQList; IF TTYAborted[tty] THEN RETURN; SetQTop[exec, qTop _ qTop + 1]; SetQEntry[exec, qEntry]; asyncQ ¬ GetAsyncQ[exec]; BEGIN ENABLE ABORTED => CONTINUE; -- can be raised by ANY call to TTY output msgs if we are between commands, between output lines, or the queue is full IF OkForAsyncMsg[exec] OR TTY.NewLine[tty] OR MustDisplayQ[] THEN DisplayQ[exec, qTop, asyncQ]; END; -- ENABLE Κ.˜codešœ™KšœI™IK™-—K˜šΟk ˜ Kšœ œ˜Kšœœœ˜Kšœ œ“˜‘K˜Kšœœ˜%Kšœœ ˜Kšœœœ˜Kšœœ9˜BKšœ œ˜Kšœœ ˜Kšœœ˜$Kšœœ ˜—K˜šΟn œœ˜Kšœœœ ˜5Kšœ˜Kšœ˜Kšœžœ ˜K™Kšœ8™8Kšœ ™ Kšœ9™9Kšœœœ˜Kšœœœœ˜K˜Kšœ8™8Kšœ™Kšœ9™9K˜Kš œœœœ œ˜1Kšœœœ ˜šœ œœ˜Kšœ.Οc˜LKšœŸ„˜žK˜/K˜K˜Kšœ œœ˜KšœœŸ˜5—K˜Kš œ œœœœ œœ ˜Lšœ œœ˜Kšœœ˜Kšœ˜Kšœœ˜KšœœœŸ˜8KšœœŸ+˜@Kšœ˜Kšœ2Ÿ˜Ešœœ˜#˜ Kšœœœœ˜(Kšœ!œ˜%K™7Kšœœœ˜-—Kšœœ˜Kšœ˜—K˜Kšœ œœ ˜%Kšœœœ œ˜*Kš œœœœ!œ˜GKšœœ˜Kšœœœ˜(Kšœœœ/˜J—K˜Kšœ9™9Kšœ ™ Kšœ8™8K˜Kšœ9™9Kšœ ™ Kšœ8™8K˜Kšœ œœ Ÿ˜?Kšœœ˜Kšœ œ œ˜!Kšœœ˜Kšœœœœ˜*Kšœ2˜2Kšœ!˜!K˜Kšœ8™8Kšœ™Kšœ9™9K˜Kšžœœœœ˜4Kšžœœœ˜K˜Kšœ8™8Kšœ'™'Kšœ8™8š žœœœ œœ˜DKšœœœœ%˜B—K˜š ž œœœ œf˜Kšœœœ˜Kš œœ œœœœ˜Bšœœ˜5Kšœœœ˜.—š˜K˜@Kšœœΐ˜ΡKšœ˜—KšœŸ˜——˜š ž œœœ œ˜CKšœœœ˜K˜Kšœ4œ˜SKšœ™Kšœœœœ ˜XKšœŸ˜——˜šžœœ œ)˜QKšœ œœ˜š œ+œ œœœ ˜SKšœœœ˜!˜ K˜S—Kšœ˜—KšœŸ˜——˜š ž œœ œ œœ˜fKšœ-œ!˜SK˜#K˜!KšœŸ˜——˜šžœœ œ3˜\Kšœœœ˜Kšœ-œ!˜Sšœœœ˜*Kšœ ˜'—KšœŸ˜——˜Kšœ8™8Kšœ ™ Kšœ8™8K˜š ž œœ œœœ ˜IKšœœœ˜Kšœœ$œD™vKšœœ!œ œ™qKšœ%œŸ˜BK˜0KšœŸ ˜——˜šžœœ œ+˜KKšžœœœ™šž œ™*Kš œ œœ œ œœ ™HKšœ:œ™E—Kšœ:œ™E——˜š žœœ œ# œœ˜UKšœ&œœŸ˜X——˜šžœ œ™5KšœK™K——˜š žœœ œœœ ˜LKšœ#˜)——˜š ž œœ œœ œ˜PKšœœœ"˜-——˜šž œœ œn˜Kšœ œœ™Kšœ œœœ™*K™Kšœœ™—š™K™M——K™JKšœŸ ˜——˜š ž œœ œ$œ œ œ˜lKšœœœœ™-Kšœœ™<šœ>œ™JKšœœœ™G—Kšœ™!Kšœœ˜KšœŸ˜——˜šžœœ œ&˜LKšœœ™Kšœ˜—KšœŸ ˜—K˜šž œœ œ7œœ  œœ˜ƒKšœœœ˜Kšœœ(˜8Kšœ œ˜K˜K˜*Kšœ œœ˜5š˜Kšœ'œœ$˜\šœ˜Kšœ œŸ˜6šœœ˜K˜6K˜+Kšœ˜—šœ˜ K˜3K˜+K˜——Kšœ˜—KšœŸ˜&šœ ˜ šœœ˜ Kšœœ˜Kšœœ”˜±—š ˜ K˜šœœœ˜2šœœ˜Kšœœ˜*Kšœ œœœ˜DKš˜—Kšœ˜—šœ ˜šœŸ˜Kšœœ…˜Œ—šœŸ˜Kšœœ£˜ͺ——K˜Kšœ˜——š˜˜Kšœœœ ˜K˜8K˜1K˜FK˜8——KšœŸ˜"KšœŸ ˜—K˜šžœœ œœœ œœ%˜•Kšœ0˜0K˜5Kšœ˜K˜K˜:šœ œL˜ZK˜%—Kšœ5œ™:K™8KšœŸ˜—K˜šž œœŸœ œœœœ˜kK˜+Kšž œ œœ˜Fšž œ œ˜Kšœ=˜=KšœŸ ˜—Kšœ™Kšœ ˜K˜"Kšœ˜K˜ Kšœ œ/˜BKšœ ˜K˜$KšœŸ˜—K˜šž œœ œ˜4KšœœŸ˜,Kšœœ(˜2š œœœœ˜GKšœŸ˜.—K˜K™KšœŸ˜—K˜šž œœŸœ œœœ œ˜ršœ#œ œ˜;Kšœœœœ˜=—Kšœ ˜KšœŸ ˜K˜—šž œ œœœ˜LK˜"šœ œ˜Kšœœœ˜>Kšœ˜!——J˜š ž œœœœœ˜SK™FK™K˜K˜—šžœœ œ%˜PJšœœœ˜Jšœœœœ™5š ž œ œœœœ™9šœŸ™0šœ>™@Jšœ4Ÿ™C—Jšœœœ™—JšœŸ™—Jšœœ ŸA™iJšœœ™™!J™+—J™"Jšœœœ™J™J™J™Jš œœœŸ#™FšœR™Rš œœœœ™AJ™—JšœŸ ™—JšœŸ˜—K˜šžœœŸœ œ˜BKšœœœœ˜6—K˜Kšœ˜K˜—Kšœ˜K˜˜,K˜Ι—K˜ŸK˜—…—72^