DIRECTORY FS USING [ComponentPositions, ExpandName], LoganBerry, LoganBerryRpcControl, RefID USING [Seal, Unseal], Rope USING [Equal, ROPE, Substr, Replace], RPC USING [ShortROPE, VersionRange, matchAllVersions, SecurityLevel, Conversation, EncryptionKey, MakeKey, StartConversation, AuthenticateFailed, AuthenticateFailure, CallFailed, CallFailure, ImportFailed, ImportFailure], UserCredentials USING [Get], LoganBerryStub; LoganBerryStubImpl: CEDAR PROGRAM IMPORTS FS, LoganBerry, LoganBerryRpcControl, RefID, Rope, RPC, UserCredentials EXPORTS LoganBerryStub ~ BEGIN OPEN LoganBerryStub; ROPE: TYPE = Rope.ROPE; loganBerryType: RPC.ShortROPE = "LoganBerry.Lark"; loganBerryVersion: RPC.VersionRange = RPC.matchAllVersions; securityLevel: RPC.SecurityLevel = authOnly; InstanceInterface: TYPE = REF InstanceInterfaceRecord; InstanceInterfaceRecord: TYPE = RECORD [ instance: RPC.ShortROPE, interface: LoganBerryRpcControl.InterfaceRecord, conv: RPC.Conversation ]; interfaceCache: LIST OF InstanceInterface; DBInterface: TYPE = REF DBInterfaceRecord; DBInterfaceRecord: TYPE = RECORD [ interface: LoganBerryRpcControl.InterfaceRecord, conv: RPC.Conversation, db: LoganBerry.OpenDB, instance: RPC.ShortROPE, dbName: ROPE ]; CursorInterface: TYPE = REF CursorInterfaceRecord; CursorInterfaceRecord: TYPE = RECORD [ dbi: DBInterface, cursor: LoganBerry.Cursor ]; Error: PUBLIC ERROR [ec: ErrorCode, explanation: ROPE _ NIL] = CODE; Open: PUBLIC PROC [conv: Conv _ NIL, dbName: ROPE] RETURNS [db: OpenDB] ~ { ENABLE { RPC.CallFailed => {PostRpcCallError[why, NIL]; RETRY;}; LoganBerry.Error => ERROR Error[ec, explanation]; }; instance: RPC.ShortROPE; interface: LoganBerryRpcControl.InterfaceRecord; conversation: RPC.Conversation; cp: FS.ComponentPositions; fullDBName: ROPE; remoteDB: LoganBerry.OpenDB; [fullDBName, cp] _ FS.ExpandName[dbName]; instance _ Rope.Substr[fullDBName, cp.server.start, cp.server.length]; fullDBName _ Rope.Replace[base: fullDBName, start: cp.server.start, len: cp.server.length, with: NIL]; [interface, conversation] _ ImportLoganBerry[instance]; IF conv # NIL THEN conversation _ conv; -- use the conversation presented if possible remoteDB _ interface.Open[conversation, fullDBName]; db _ SaveDBInterface[interface, conversation, remoteDB, instance, fullDBName]; }; ReadEntry: PUBLIC PROC [conv: Conv _ NIL, db: OpenDB, key: AttributeType, value: AttributeValue] RETURNS [entry: Entry, others: BOOLEAN] ~ { ENABLE { RPC.CallFailed => {PostRpcCallError[why, GetDBInterface[db]]; RETRY;}; LoganBerry.Error => {PostLoganBerryError[ec, explanation, GetDBInterface[db]]; RETRY;}; }; dbi: DBInterface _ GetDBInterface[db]; IF conv # NIL THEN dbi.conv _ conv; [entry, others] _ dbi.interface.ReadEntry[dbi.conv, dbi.db, key, value]; }; EnumerateEntries: PUBLIC PROC [db: OpenDB, key: AttributeType, start: AttributeValue _ NIL, end: AttributeValue _ NIL, proc: EntryProc] RETURNS [] ~ { ENABLE { RPC.CallFailed => {PostRpcCallError[why, GetDBInterface[db]]; RETRY;}; LoganBerry.Error => {PostLoganBerryError[ec, explanation, GetDBInterface[db]]; RETRY;}; }; isLocal: BOOLEAN _ FALSE; dbi: DBInterface _ GetDBInterface[db]; FOR l: LIST OF InstanceInterface _ interfaceCache, l.rest WHILE l # NIL DO IF Rope.Equal[l.first.instance, ""] THEN { IF l.first.interface = dbi.interface THEN -- beware: pointer comparison isLocal _ TRUE; EXIT; }; ENDLOOP; IF NOT isLocal THEN ERROR Error[$BadDBHandle, "Enumerates can only be done on local databases."]; dbi.interface.EnumerateEntries[dbi.db, key, start, end, proc]; }; GenerateEntries: PUBLIC PROC [conv: Conv _ NIL, db: OpenDB, key: AttributeType, start: AttributeValue _ NIL, end: AttributeValue _ NIL] RETURNS [cursor: Cursor] ~ { ENABLE { RPC.CallFailed => {PostRpcCallError[why, GetDBInterface[db]]; RETRY;}; LoganBerry.Error => {PostLoganBerryError[ec, explanation, GetDBInterface[db]]; RETRY;}; }; remoteCursor: LoganBerry.Cursor; dbi: DBInterface _ GetDBInterface[db]; IF conv # NIL THEN dbi.conv _ conv; remoteCursor _ dbi.interface.GenerateEntries[dbi.conv, dbi.db, key, start, end]; cursor _ SaveCursorInterface[dbi, remoteCursor]; }; NextEntry: PUBLIC PROC [conv: Conv _ NIL, cursor: Cursor, dir: CursorDirection _ increasing] RETURNS [entry: Entry] ~ { ENABLE { RPC.CallFailed => {PostRpcCallError[why, GetCursorInterface[cursor].dbi]; RETRY;}; LoganBerry.Error => {PostLoganBerryError[ec, explanation, GetCursorInterface[cursor].dbi]; RETRY;}; }; ci: CursorInterface _ GetCursorInterface[cursor]; IF conv # NIL THEN ci.dbi.conv _ conv; entry _ ci.dbi.interface.NextEntry[ci.dbi.conv, ci.cursor, dir]; }; EndGenerate: PUBLIC PROC [conv: Conv _ NIL, cursor: Cursor] RETURNS [] ~ { ENABLE { RPC.CallFailed => {PostRpcCallError[why, GetCursorInterface[cursor].dbi]; RETRY;}; LoganBerry.Error => {PostLoganBerryError[ec, explanation, GetCursorInterface[cursor].dbi]; RETRY;}; }; ci: CursorInterface _ GetCursorInterface[cursor]; IF conv # NIL THEN ci.dbi.conv _ conv; ci.dbi.interface.EndGenerate[ci.dbi.conv, ci.cursor]; }; WriteEntry: PUBLIC PROC [conv: Conv _ NIL, db: OpenDB, entry: Entry, log: LogID _ activityLog, replace: BOOLEAN _ FALSE] RETURNS [] ~ { ENABLE { RPC.CallFailed => {PostRpcCallError[why, GetDBInterface[db]]; RETRY;}; LoganBerry.Error => {PostLoganBerryError[ec, explanation, GetDBInterface[db]]; RETRY;}; }; dbi: DBInterface _ GetDBInterface[db]; IF conv # NIL THEN dbi.conv _ conv; dbi.interface.WriteEntry[dbi.conv, dbi.db, entry, log, replace]; }; DeleteEntry: PUBLIC PROC [conv: Conv _ NIL, db: OpenDB, key: AttributeType, value: AttributeValue] RETURNS [] ~ { ENABLE { RPC.CallFailed => {PostRpcCallError[why, GetDBInterface[db]]; RETRY;}; LoganBerry.Error => {PostLoganBerryError[ec, explanation, GetDBInterface[db]]; RETRY;}; }; dbi: DBInterface _ GetDBInterface[db]; IF conv # NIL THEN dbi.conv _ conv; dbi.interface.DeleteEntry[dbi.conv, dbi.db, key, value]; }; Close: PUBLIC PROC [conv: Conv _ NIL, db: OpenDB] RETURNS [] ~ { ENABLE { RPC.CallFailed => {PostRpcCallError[why, GetDBInterface[db]]; RETRY;}; LoganBerry.Error => {PostLoganBerryError[ec, explanation, GetDBInterface[db]]; RETRY;}; }; dbi: DBInterface _ GetDBInterface[db]; IF conv # NIL THEN dbi.conv _ conv; dbi.interface.Close[dbi.conv, dbi.db]; }; BuildIndices: PUBLIC PROC [conv: Conv _ NIL, db: OpenDB] RETURNS [] ~ { ENABLE { RPC.CallFailed => {PostRpcCallError[why, GetDBInterface[db]]; RETRY;}; LoganBerry.Error => {PostLoganBerryError[ec, explanation, GetDBInterface[db]]; RETRY;}; }; dbi: DBInterface _ GetDBInterface[db]; IF conv # NIL THEN dbi.conv _ conv; dbi.interface.BuildIndices[dbi.conv, dbi.db]; }; CompactLogs: PUBLIC PROC [conv: Conv _ NIL, db: OpenDB] RETURNS [] ~ { ENABLE { RPC.CallFailed => {PostRpcCallError[why, GetDBInterface[db]]; RETRY;}; LoganBerry.Error => {PostLoganBerryError[ec, explanation, GetDBInterface[db]]; RETRY;}; }; dbi: DBInterface _ GetDBInterface[db]; IF conv # NIL THEN dbi.conv _ conv; dbi.interface.CompactLogs[dbi.conv, dbi.db]; }; Describe: PUBLIC PROC [conv: Conv _ NIL, db: OpenDB] RETURNS [info: SchemaInfo] ~ { ENABLE { RPC.CallFailed => {PostRpcCallError[why, GetDBInterface[db]]; RETRY;}; LoganBerry.Error => {PostLoganBerryError[ec, explanation, GetDBInterface[db]]; RETRY;}; }; dbi: DBInterface _ GetDBInterface[db]; IF conv # NIL THEN dbi.conv _ conv; info _ dbi.interface.Describe[dbi.conv, dbi.db]; }; ImportLoganBerry: PROC [instance: RPC.ShortROPE] RETURNS [interface: LoganBerryRpcControl.InterfaceRecord, conv: RPC.Conversation] ~ { interface _ NIL; FOR l: LIST OF InstanceInterface _ interfaceCache, l.rest WHILE l # NIL DO IF Rope.Equal[l.first.instance, instance] THEN { interface _ l.first.interface; conv _ l.first.conv; EXIT; }; ENDLOOP; IF interface = NIL THEN { IF Rope.Equal[instance, ""] THEN { -- need local interface interface _ NewLocalInterface[]; conv _ NIL; } ELSE { -- import remote interface interface _ LoganBerryRpcControl.ImportNewInterface[[type: loganBerryType, instance: instance, version: loganBerryVersion] ! RPC.ImportFailed => PostRpcImportError[why]]; conv _ NewConversation[instance]; }; interfaceCache _ CONS[NEW[InstanceInterfaceRecord _ [instance, interface, conv]], interfaceCache]; }; }; InvalidateInterface: PROC [instance: RPC.ShortROPE] RETURNS [] ~ { prev: LIST OF InstanceInterface _ NIL; FOR l: LIST OF InstanceInterface _ interfaceCache, l.rest WHILE l # NIL DO IF Rope.Equal[l.first.instance, instance] THEN IF prev = NIL THEN interfaceCache _ l.rest ELSE prev.rest _ l.rest; prev _ l; ENDLOOP; }; NewLocalInterface: PROC [] RETURNS [interface: LoganBerryRpcControl.InterfaceRecord] ~ { interface _ NEW[LoganBerryRpcControl.InterfaceRecordObject]; interface^ _ [Error: LoganBerry.Error, clientStubOpen: localOpen, clientStubDescribe: localDescribe, clientStubReadEntry: localReadEntry, clientStubEnumerateEntries: localEnumerateEntries, clientStubGenerateEntries: localGenerateEntries, clientStubNextEntry: localNextEntry, clientStubEndGenerate: localEndGenerate, clientStubWriteEntry: localWriteEntry, clientStubDeleteEntry: localDeleteEntry, clientStubClose: localClose, clientStubBuildIndices: localBuildIndices, clientStubCompactLogs: localCompactLogs]; }; localOpen: PROC [interface: LoganBerryRpcControl.InterfaceRecord, conv: Conv _ NIL, dbName: ROPE] RETURNS [db: OpenDB] ~ { RETURN[LoganBerry.Open[conv, dbName]]; }; localReadEntry: PROC [interface: LoganBerryRpcControl.InterfaceRecord, conv: Conv _ NIL, db: OpenDB, key: AttributeType, value: AttributeValue] RETURNS [entry: Entry, others: BOOLEAN] ~ { [entry, others] _ LoganBerry.ReadEntry[conv, db, key, value]; }; localEnumerateEntries: PROC [interface: LoganBerryRpcControl.InterfaceRecord, db: OpenDB, key: AttributeType, start: AttributeValue _ NIL, end: AttributeValue _ NIL, proc: EntryProc] RETURNS [] ~ { LoganBerry.EnumerateEntries[db, key, start, end, proc]; }; localGenerateEntries: PROC [interface: LoganBerryRpcControl.InterfaceRecord, conv: Conv _ NIL, db: OpenDB, key: AttributeType, start: AttributeValue _ NIL, end: AttributeValue _ NIL] RETURNS [cursor: Cursor] ~ { RETURN[LoganBerry.GenerateEntries[conv, db, key, start, end]]; }; localNextEntry: PROC [interface: LoganBerryRpcControl.InterfaceRecord, conv: Conv _ NIL, cursor: Cursor, dir: CursorDirection _ increasing] RETURNS [entry: Entry] ~ { RETURN[LoganBerry.NextEntry[conv, cursor, dir]]; }; localEndGenerate: PROC [interface: LoganBerryRpcControl.InterfaceRecord, conv: Conv _ NIL, cursor: Cursor] RETURNS [] ~ { LoganBerry.EndGenerate[conv, cursor]; }; localWriteEntry: PROC [interface: LoganBerryRpcControl.InterfaceRecord, conv: Conv _ NIL, db: OpenDB, entry: Entry, log: LogID _ activityLog, replace: BOOLEAN _ FALSE] RETURNS [] ~ { LoganBerry.WriteEntry[conv, db, entry, log, replace]; }; localDeleteEntry: PROC [interface: LoganBerryRpcControl.InterfaceRecord, conv: Conv _ NIL, db: OpenDB, key: AttributeType, value: AttributeValue] RETURNS [] ~ { LoganBerry.DeleteEntry[conv, db, key, value]; }; localClose: PROC [interface: LoganBerryRpcControl.InterfaceRecord, conv: Conv _ NIL, db: OpenDB] RETURNS [] ~ { LoganBerry.Close[conv, db]; }; localBuildIndices: PROC [interface: LoganBerryRpcControl.InterfaceRecord, conv: Conv _ NIL, db: OpenDB] RETURNS [] ~ { LoganBerry.BuildIndices[conv, db]; }; localCompactLogs: PROC [interface: LoganBerryRpcControl.InterfaceRecord, conv: Conv _ NIL, db: OpenDB] RETURNS [] ~ { LoganBerry.CompactLogs[conv, db]; }; localDescribe: PROC [interface: LoganBerryRpcControl.InterfaceRecord, conv: Conv _ NIL, db: OpenDB] RETURNS [info: SchemaInfo] ~ { RETURN[LoganBerry.Describe[conv, db]]; }; NewConversation: PROC [instance: RPC.ShortROPE] RETURNS [conv: RPC.Conversation] ~ { caller: ROPE _ UserCredentials.Get[].name; key: RPC.EncryptionKey _ RPC.MakeKey[UserCredentials.Get[].password]; conv _ RPC.StartConversation[caller: caller, key: key, callee: instance, level: securityLevel ! RPC.AuthenticateFailed => PostRpcAuthError[why]]; }; SaveDBInterface: PROC [interface: LoganBerryRpcControl.InterfaceRecord, conv: RPC.Conversation, db: LoganBerry.OpenDB, instance: RPC.ShortROPE, dbName: ROPE] RETURNS [localDB: LoganBerry.OpenDB] ~ { dbi: DBInterface _ NEW[DBInterfaceRecord _ [interface, conv, db, instance, dbName]]; RETURN[RefID.Seal[dbi]]; }; GetDBInterface: PROC [localDB: LoganBerry.OpenDB] RETURNS [dbi: DBInterface] ~ { ref: REF = RefID.Unseal[localDB]; IF ref = NIL THEN ERROR Error[$BadDBHandle, "NIL OpenDB handle."]; WITH ref SELECT FROM dbi: DBInterface => RETURN[dbi]; ENDCASE => ERROR Error[$BadDBHandle, "Invalid OpenDB handle."]; }; SaveCursorInterface: PROC [dbi: DBInterface, cursor: LoganBerry.Cursor] RETURNS [localCursor: LoganBerry.Cursor] ~ { ci: CursorInterface _ NEW[CursorInterfaceRecord _ [dbi, cursor]]; RETURN[RefID.Seal[ci]]; }; GetCursorInterface: PROC [localCursor: LoganBerry.Cursor] RETURNS [ci: CursorInterface] ~ { ref: REF = RefID.Unseal[localCursor]; IF ref = NIL THEN ERROR Error[$BadCursor, "NIL cursor handle."]; WITH ref SELECT FROM ci: CursorInterface => RETURN[ci]; ENDCASE => ERROR Error[$BadCursor, "Invalid cursor passed to NextEntry."]; }; PostLoganBerryError: PROC[ec: LoganBerry.ErrorCode, explanation: Rope.ROPE, dbi: DBInterface] RETURNS [] = { SELECT ec FROM $DBClosed, $BadDBHandle => { -- try to reopen database dbi.db _ dbi.interface.Open[dbi.conv, dbi.dbName ! LoganBerry.Error => PostLoganBerryError[ec, explanation, dbi]]; }; ENDCASE => { -- propagate the error as a LoganBerryStub.Error ERROR Error[ec, explanation]; }; }; PostRpcCallError: PROC[why: RPC.CallFailure, dbi: DBInterface] RETURNS [] = { SELECT why FROM $timeout => ERROR Error[$CallFailed, "no acknowledgement within reasonable time"]; $busy => ERROR Error[$CallFailed, "server says it is too busy"]; $runtimeProtocol => ERROR Error[$CallFailed, "user/server runtimes do not understand each other"]; $stubProtocol => ERROR Error[$CallFailed, "user/server stubs do not understand each other"]; $unbound => { -- try to reimport the interface IF dbi # NIL THEN { InvalidateInterface[dbi.instance]; [interface: dbi.interface] _ ImportLoganBerry[dbi.instance]; }; }; ENDCASE => ERROR Error[$CallFailed, "unknown reason"]; }; PostRpcAuthError: PROC [why: RPC.AuthenticateFailure] RETURNS [] ~ { explanation: ROPE _ SELECT why FROM $communications => "could not contact authentication server", $badCaller => "invalid caller name", $badKey => "incorrect caller password", $badCallee => "invalid callee name", ENDCASE => "unknown reason"; ERROR Error[$AuthenticateFailed, explanation]; }; PostRpcImportError: PROC [why: RPC.ImportFailure] RETURNS [] ~ { explanation: ROPE _ SELECT why FROM $communications => "could not access binding database", $badType => "unacceptable interface type name", $badInstance => "unacceptable interface instance name", $badVersion => "statically silly version range", $wrongVersion => "exported version not in required range", $unbound => "this instance not exported", $stubProtocol => "exporter protocol incompatible with importer", ENDCASE => "unknown reason"; ERROR Error[$ImportFailed, explanation]; }; END. èLoganBerryStubImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Doug Terry, April 23, 1986 4:10:38 pm PST LoganBerryStub provides easy access to local or remote LoganBerry database servers. It attempts to hide any RPC details. That is, it (1) catches RPC failures and attempts to either recover or turn them into LoganBerry errors, (2) imports RPC interfaces from multiple servers on demand, (3) uses secure RPC conversations, and (4) tries to keep LoganBerry databases open. The interface is identical to LoganBerry.mesa. LoganBerry operations This operation can only be called on local databases. Importing interfaces Keep a cache of interface records and conversations for various instances. Searches the interface cache for an existing interface for the given instance. If one is not found then a new interface is imported. Also, a single conversation is used in conjunction with a given interface. Removes the interface associated with the given instance from the interface cache. Subsequent attempts to import the instance will create a new cache entry. Creates an interface record and fills it in with procedures that do local, rather than remote, calls. local calls to the LoganBerry interface Security Secure RPC conversations are used so that callers can be authenticated and identified by a remote server. Currently, a security level of "authOnly" is used, i.e. calls are not encrypted, and a one-to-one correspondence exists between conversations and interfaces. An alternative would be to generate a new conversation for every Open call. Handles and interface mappings Keep a table mapping open database handles to the interfaces that should be used for them. The database handle presented to clients of LoganBerryStub is not the same as the one returned by a remote LoganBerry server since remote handles are not globally unique. Thus, a new (unique) handle is generated. This handle is mapped to the actual remote handle, the proper interface, and the conversation on every call. Cursors are handled in a similar manner. Note: there are probably more efficient ways to perform these mappings than using the RefID table. Error handling The following error handling procedures attempt to reconcile LoganBerry and RPC errors if possible. If an error can not be recovered from, then it is re-raised as a LoganBerryStub.Error, i.e. the handler never returns to its caller. A successful return from one of these error handlers indicates that the operation producing the error should be retried. If the database has been closed, then attempt to reopen it. The error $BadDBHandle should never occur; but if it does then we also attempt to reopen the database in order to get a new handle. The attempt to reopen the database may in turn raise LoganBerry errors that cause this handler to be called recursively; we don't have to worry about infinite recursion since the Open operation can not raise $DBClosed or $BadDBHandle. RPC errors are caught elsewhere. Trys to reimport an interface if an $unbound error is encountered. All other errors are propagated as LoganBerryStub.Errors. Doug Terry, April 17, 1986 6:02:39 pm PST Created. changes to: DIRECTORY, LoganBerryStubImpl, EXPORTS, ~, Describe, interfaceCache, interfaceCacheSize, interfaceCache, IF, END Doug Terry, April 18, 1986 3:40:47 pm PST Support for multiple import and efficient local import. changes to: ~, ImportLoganBerry, NewLocalInterface, localOpen, localReadEntry, localEnumerateEntries, localGenerateEntries, localNextEntry, localEndGenerate, localWriteEntry, localDeleteEntry, localClose, localBuildIndices, localCompactLogs, localDescribe, Open, ReadEntry, NewConversation, EnumerateEntries, GenerateEntries, NextEntry, EndGenerate, WriteEntry, DeleteEntry, Close, BuildIndices, CompactLogs, Describe, SaveDBInterface, GetDBInterface, SaveCursorInterface, GetCursorInterface, DIRECTORY, IMPORTS Doug Terry, April 23, 1986 3:58:07 pm PST Added error handling routines. changes to: ~, PostLBError, Open, SaveDBInterface, ReadEntry, DIRECTORY, NewConversation, PostRPCError, PostRpcAuthError, ImportLoganBerry, PostRpcImportError, InvalidateInterface, GenerateEntries, NextEntry, EndGenerate, SaveCursorInterface, EnumerateEntries, WriteEntry, DeleteEntry, Close, BuildIndices, CompactLogs, Describe ÊĘcodešœ™Kšœ Ïmœ1™˜>K˜—K˜š œžœžœžœ:žœžœžœ˜¤šžœ˜Jšžœ9žœžœ˜FJšœOžœ˜WJšœ˜—Jšœ ˜ Jšœ&˜&Jšžœžœžœ¡˜#KšœP˜PKšœ0˜0Kšœ˜—K˜š   œžœžœžœ5žœ˜wšžœ˜JšžœEžœžœ˜RJšœ[žœ˜cJšœ˜—Jšœ1˜1Jšžœžœžœ¡˜&Kšœ@˜@K˜—K˜š   œžœžœžœžœ˜Jšžœ˜JšžœEžœžœ˜RJšœ[žœ˜cJšœ˜—Jšœ1˜1Jšžœžœžœ¡˜&Kšœ5˜5K˜—K˜š  œžœžœžœ?žœžœžœ˜‡šžœ˜Jšžœ9žœžœ˜FJšœOžœ˜WJšœ˜—Jšœ&˜&Jšžœžœžœ¡˜#Kšœ@˜@K˜—K˜š   œžœžœžœ9žœ˜qšžœ˜Jšžœ9žœžœ˜FJšœOžœ˜WJšœ˜—Jšœ&˜&Jšžœžœžœ¡˜#Kšœ8˜8K˜—K˜š  œžœžœžœžœ˜@šžœ˜Jšžœ9žœžœ˜FJšœOžœ˜WJšœ˜—Jšœ&˜&Jšžœžœžœ¡˜#Kšœ&˜&K˜—K˜š   œžœžœžœžœ˜Gšžœ˜Jšžœ9žœžœ˜FJšœOžœ˜WJšœ˜—Jšœ&˜&Jšžœžœžœ¡˜#Kšœ-˜-Kšœ˜—K˜š   œžœžœžœžœ˜Fšžœ˜Jšžœ9žœžœ˜FJšœOžœ˜WJšœ˜—Jšœ&˜&Jšžœžœžœ¡˜#Kšœ,˜,K˜—K˜š  œžœžœžœžœ˜Sšžœ˜Jšžœ9žœžœ˜FJšœOžœ˜WJšœ˜—Jšœ&˜&Jšžœžœžœ¡˜#Kšœ0˜0K˜——™LšœJ™JL™š œžœ žœ žœN˜†KšœÑ™ÑKšœ žœ˜š žœžœžœ,žœžœž˜Jšžœ(žœ˜0Kšœ˜Kšœ˜Kšžœ˜K˜—Kšžœ˜—šžœ žœžœ˜šžœžœ£˜;K˜ Kšœžœ˜ K˜—šžœ£˜"Kšœª˜ªKšœ!˜!K˜—KšœžœžœI˜bK˜—K˜K˜—š œžœ žœ žœ˜BKšœ™Kšœžœžœžœ˜&š žœžœžœ,žœžœž˜Jšžœ(ž˜.šžœžœž˜Kšœ˜—šž˜K˜——K˜ Kšžœ˜—K˜K˜—š œžœžœ6˜XK™eKšœ žœ-˜Kšœ˜—š œžœ@žœ5žœ˜¦Kšžœ*˜0K˜—š œžœ@žœžœ˜yKšœ%˜%K˜—š  œžœ@žœ?žœžœžœ˜¶Kšœ5˜5K˜—š œžœ@žœ9žœ˜ Kšœ-˜-K˜—š  œžœ@žœžœ˜oKšœ˜K˜—š œžœ@žœžœ˜vKšœ"˜"Kšœ˜—š œžœ@žœžœ˜uKšœ!˜!K˜—š  œžœ@žœžœ˜‚Kšžœ ˜&K˜——™K™ÕK˜š œžœžœ˜TKšœžœ˜*KšœC¡œ˜E–l[caller: RPC.Principal, key: RPC.EncryptionKey, callee: RPC.Principal, level: RPC.ConversationLevel]šœ_˜_Kšœ1˜1—K˜——™L™ÉK™bK˜š  œžœ9žœGžœžœ!˜ÆKšœžœ>˜TKšžœ˜K˜K˜—š œžœžœ˜PKšœžœ˜!šžœžœž˜Kšžœ+˜0—šžœžœž˜Kšœžœ˜ Kšžœžœ/˜?—K˜K˜—š œžœ/žœ%˜tKšœžœ(˜AKšžœ˜K˜K˜—š œžœ"žœ˜[Kšœžœ˜%šžœžœž˜Kšžœ)˜.—šžœžœž˜Kšœžœ˜"Kšžœžœ:˜J—K˜——™J™ãJ™š œžœ-žœžœ˜lJ™Îšžœž˜šœ£˜7Jšœr˜rJ˜—šžœ£0˜>Jšžœ˜Jšœ˜——J˜J˜—š œžœžœ žœ˜MJšœ}™}šžœž˜Jšœ žœA˜RJšœ žœ2˜@JšœžœI˜bJšœžœF˜\šœ£ ˜/šžœžœžœ˜Jšœ"˜"Jšœ<˜