DIRECTORY BasicTime USING [ GMT ], IV USING [KeyTableBody], LoganBerry USING [ Attribute ], RefID USING [ ID ], Rope USING [ Concat ], RPC USING [ InterfaceName, Password, ShortROPE, VersionRange ], SRPCCalls USING [ Conversation, Error, GetSHandle, NewRPCConversation, ReleaseConversation, ReportProc, SHandle, TimeoutEnable ], ThParty, ThPartySunRPC, ThPartySunRPControl, ThPartySunRPCClient, Thrush, ThrushSunRPC, ThrushSunRPCConvert ; ThPartyToThPartySunRPC: CEDAR MONITOR IMPORTS Rope, SRPCCalls, ThPartySunRPCClient, ThrushSunRPCConvert EXPORTS ThParty, ThPartySunRPControl ~ { OPEN ThrushSunRPCConvert; Attributes: TYPE = ThParty.Attributes; Conversation: TYPE ~ SRPCCalls.Conversation; ConversationInfo: TYPE = ThParty.ConversationInfo; ConversationID: TYPE = Thrush.ConversationID; PartyID: TYPE = Thrush.PartyID; SmartsID: TYPE = Thrush.SmartsID; nullID: RefID.ID = Thrush.nullID; Credentials: TYPE = Thrush.Credentials; SRCredentials: TYPE = ThrushSunRPC.Credentials; NB: TYPE = Thrush.NB; ROPE: TYPE = Thrush.ROPE; SHHH: TYPE = Thrush.SHHH; none: SHHH = Thrush.none; SHandle: TYPE ~ SRPCCalls.SHandle; SmartsInterfaceName: TYPE = RPC.InterfaceName; sunSHHH: INT = 0; ThPartyHandle: TYPE ~ REF ThPartyHandleRec; ThPartyHandleRec: TYPE ~ RECORD [ rName: ROPE, type: Thrush.PartyType, interface: SmartsInterfaceName, properties: ThParty.SmartsProperties, reportState: ThPartySunRPControl.ReportState ¬ NIL, reportProblem: ThPartySunRPControl.ReportProblem ¬ NIL, reportData: REF ¬ NIL, -- supplied by client, returned in reports. registered: BOOL ¬ FALSE, -- implies sHandle.connected; also registered with Thrush. sHandle: SHandle, partyID: Thrush.PartyID¬ nullID, smartsID: Thrush.SmartsID¬ nullID ]; RetryAfterReconnect: ERROR = CODE; recentShhh: SHHH ¬ NIL; CreateConversation: PUBLIC PROC [shhh: SHHH ¬ none, credentials: Credentials, state: Thrush.StateInConv¬$initiating, reason: Thrush.Reason ¬ NIL, comment: ROPE ¬ NIL, convAttributes: Attributes¬NIL, partyAttributes: Attributes¬NIL, checkConflict: BOOL ¬ FALSE] RETURNS [ nb: NB, convEvent: Thrush.ConvEvent ] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shhh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; srConvEvent: ThrushSunRPC.ConvEvent; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shhh, credentials]; [srNB, srConvEvent] ¬ ThPartySunRPCClient.CreateConversation[pHandle.sHandle.handle, sunSHHH, srCredentials, StateToSr[state], ATOMToSr[reason], ROPEToSr[comment], AttributesToSr[convAttributes], AttributesToSr[partyAttributes], checkConflict ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; convEvent ¬ SrToConvEvent[srConvEvent]; }; Alert: PUBLIC PROC [shhh: SHHH ¬ none, credentials: Credentials, calledPartyID: PartyID¬nullID, comment: ROPE¬NIL, convAttributes: Attributes¬NIL, partyAttributes: Attributes¬NIL] RETURNS [nb: NB ] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shhh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shhh, credentials]; [srNB] ¬ ThPartySunRPCClient.Alert[pHandle.sHandle.handle, sunSHHH, srCredentials, calledPartyID, ROPEToSr[comment], AttributesToSr[convAttributes], AttributesToSr[partyAttributes] ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; }; Advance: PUBLIC PROC [shhh: SHHH ¬ none, credentials: Credentials, state: Thrush.StateInConv, reportToAll: BOOL¬FALSE, reason: Thrush.Reason¬NIL, comment: ROPE¬NIL, convAttributes: Attributes¬NIL, partyAttributes: Attributes¬NIL,bilateral: BOOL ¬ FALSE, checkConflict: BOOL ¬ FALSE ] RETURNS [nb: NB, convEvent: Thrush.ConvEvent ] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shhh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; srConvEvent: ThrushSunRPC.ConvEvent; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shhh, credentials]; [srNB, srConvEvent] ¬ ThPartySunRPCClient.Advance[pHandle.sHandle.handle, sunSHHH, srCredentials, StateToSr[state], reportToAll, ATOMToSr[reason], ROPEToSr[comment], AttributesToSr[convAttributes], AttributesToSr[partyAttributes], bilateral, checkConflict ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; convEvent ¬ SrToConvEvent[srConvEvent]; }; ReportAction: PUBLIC PROC [shhh: SHHH ¬ none, report: Thrush.ActionReport, reportToAll: BOOL ¬ FALSE, selfOnCompletion: BOOL¬FALSE ] RETURNS [nb: NB, numReportsIssued: NAT¬0] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shhh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shhh, report.other]; -- This is where caller puts its credentials! report.other ¬ SrToCredentials[srCredentials]; [srNB, numReportsIssued] ¬ ThPartySunRPCClient.ReportAction[pHandle.sHandle.handle, sunSHHH, ActionReportToSr[report], reportToAll, selfOnCompletion ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; }; GetConversationInfo: PUBLIC PROC [ shh: SHHH¬none, convID: ConversationID ] RETURNS [nb: NB, cInfo: ConversationInfo] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; srCInfo: ThPartySunRPC.ConversationInfo; pHandle: ThPartyHandle ¬ GetInfo[shh].pHandle; [srNB, srCInfo] ¬ ThPartySunRPCClient.GetConversationInfo[pHandle.sHandle.handle, sunSHHH, ConvIDToSr[convID] ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; cInfo ¬ SrToConversationInfo[srCInfo]; }; RegisterConversation: PUBLIC PROC [ shhh: SHHH ¬ none, credentials: Credentials, name: ROPE, convType: ThParty.ConvType ¬ $meeting, convAttributes: Attributes ¬ NIL, accessList: ThParty.AccessList ¬ NIL ] RETURNS [ nb: NB ] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shhh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shhh, credentials]; [srNB] ¬ ThPartySunRPCClient.RegisterConversation[pHandle.sHandle.handle, sunSHHH, srCredentials, ROPEToSr[name], ConvTypeToSr[convType], AttributesToSr[convAttributes], AccessListToSr[accessList] ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; }; GetConversationFromName: PUBLIC PROC [ shhh: SHHH ¬ none, partyID: PartyID, name: ROPE ] RETURNS [ nb: NB, cInfo: ConversationInfo ] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shhh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; srCInfo: ThPartySunRPC.ConversationInfo; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shhh]; partyID ¬ srCredentials.partyID; [srNB, srCInfo] ¬ ThPartySunRPCClient.GetConversationFromName[pHandle.sHandle.handle, sunSHHH, partyID, ROPEToSr[name] ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; cInfo ¬ SrToConversationInfo[srCInfo]; }; EnumerateNamedConversations: PUBLIC PROC [ shhh: SHHH ¬ none, partyID: PartyID ] RETURNS [ nb: NB, candidates: LIST OF ConversationInfo ] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shhh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; srCandidates: ThPartySunRPC.CandidateList; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shhh]; partyID ¬ srCredentials.partyID; [srNB, srCandidates] ¬ ThPartySunRPCClient.EnumerateNamedConversations[ pHandle.sHandle.handle, sunSHHH, partyID ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; candidates ¬ SrToCandidateList[srCandidates]; }; GetPartyInfo: PUBLIC PROC [ shh: SHHH¬none, credentials: Credentials, nameReq: ThParty.NameReq¬$current, allParties: BOOL¬FALSE ] RETURNS [ nb: NB, pInfo: ThParty.PartyInfo ] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; srPInfo: ThPartySunRPC.PartyInfo; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shh, credentials]; [srNB, srPInfo] ¬ ThPartySunRPCClient.GetPartyInfo[pHandle.sHandle.handle, sunSHHH, srCredentials, ATOMToSr[nameReq], allParties ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; pInfo ¬ SrToPartyInfo[srPInfo]; }; DescribeParty: PUBLIC PROC[ partyID: Thrush.PartyID, nameReq: ThParty.NameReq ] RETURNS [ nb: NB, description: Thrush.ROPE, type: Thrush.PartyType, partner: Thrush.PartyID¬nullID, visitee: Thrush.PartyID¬nullID, visitors: LIST OF Thrush.PartyID¬NIL ] ~ { shhh: SHHH ¬ recentShhh; { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shhh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; srType: ThrushSunRPC.PartyType; srVisitors: ThPartySunRPC.VisitorList; pHandle: ThPartyHandle; pHandle ¬ GetInfo[shhh].pHandle; [srNB, description, srType, partner, visitee, srVisitors] ¬ ThPartySunRPCClient.DescribeParty[pHandle.sHandle.handle, --sunSHHH,-- partyID, ATOMToSr[nameReq] ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; type ¬ SrToATOM[srType]; visitors ¬ SrToVisitorList[srVisitors]; description ¬ SrToROPE[description]; }; }; AddAttributes: PUBLIC PROC[ credentials: Credentials, convAttributes: Attributes¬NIL, partyAttributes: Attributes¬NIL ] RETURNS [nb: NB] ~ { shhh: SHHH ¬ recentShhh; { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shhh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shhh, credentials]; srNB ¬ ThPartySunRPCClient.AddAttributes[pHandle.sHandle.handle, --sunSHHH, -- srCredentials, AttributesToSr[convAttributes], AttributesToSr[partyAttributes] ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; }; }; RegisterServiceInterface: PUBLIC PROC[ shhh: SHHH ¬ none, credentials: Credentials, interfaceSpecPattern: Thrush.InterfaceSpec ] RETURNS [nb: NB, interfaceSpec: Thrush.InterfaceSpec] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shhh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; srInterfaceSpec: ThrushSunRPC.InterfaceSpec; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shhh, credentials]; interfaceSpecPattern.interfaceName.type ¬ Rope.Concat[interfaceSpecPattern.interfaceName.type, "-Sun"]; [srNB, srInterfaceSpec] ¬ ThPartySunRPCClient.RegisterServiceInterface[ pHandle.sHandle.handle, sunSHHH, srCredentials, InterfaceSpecToSr[interfaceSpecPattern] ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; interfaceSpec ¬ SrToInterfaceSpec[srInterfaceSpec]; }; LookupServiceInterface: PUBLIC PROC[ shhh: SHHH ¬ none, credentials: Credentials, serviceParty: PartyID, type: RPC.ShortROPE ] RETURNS [nb: NB, interfaceSpec: Thrush.InterfaceSpec] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shhh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; srInterfaceSpec: ThrushSunRPC.InterfaceSpec; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shhh, credentials]; [srNB, srInterfaceSpec] ¬ ThPartySunRPCClient.LookupServiceInterface[ pHandle.sHandle.handle, sunSHHH, srCredentials, serviceParty, Rope.Concat[type, "-Sun"] ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; interfaceSpec ¬ SrToInterfaceSpec[srInterfaceSpec]; }; RegisterKey: PUBLIC PROC[ shh: SHHH ¬ none, credentials: Credentials, key: Thrush.EncryptionKey, reportNewKeys: BOOL¬FALSE ] RETURNS [ nb: NB, keyIndex: [0..17B] ] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shh, credentials]; [srNB, keyIndex] ¬ ThPartySunRPCClient.RegisterKey[ pHandle.sHandle.handle, sunSHHH, srCredentials, EncryptionKeyToSr[key], reportNewKeys ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; }; GetKeyTable: PUBLIC PROC [ shh: SHHH¬none, credentials: Credentials ] RETURNS [ nb: NB, keyTable: Thrush.KeyTable ] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; srKeyTable: ThrushSunRPC.KeyTable; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shh, credentials]; [srNB, srKeyTable] ¬ ThPartySunRPCClient.GetKeyTable[ pHandle.sHandle.handle, sunSHHH, srCredentials ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; keyTable ¬ SrToKeyTable[srKeyTable]; }; UnregisterKey: PUBLIC PROC[ shh: SHHH ¬ none, credentials: Credentials, key: Thrush.EncryptionKey ] RETURNS [ nb: NB ] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shh, credentials]; srNB ¬ ThPartySunRPCClient.UnregisterKey[ pHandle.sHandle.handle, sunSHHH, srCredentials, EncryptionKeyToSr[key] ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; }; GetParty: PUBLIC PROC[ shh: SHHH¬none, partyID: PartyID, rName: ROPE¬NIL, type: Thrush.PartyType¬NIL ] RETURNS [nb: NB, newPartyID: PartyID] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shh]; partyID ¬ srCredentials.partyID; -- This is the right partyID to use. [srNB, newPartyID] ¬ ThPartySunRPCClient.GetParty[ pHandle.sHandle.handle, sunSHHH, partyID, ROPEToSr[rName], ATOMToSr[type] ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; }; GetPartyFromNumber: PUBLIC PROC[ shh: SHHH¬none, partyID: PartyID, phoneNumber: Thrush.ROPE¬NIL, description: ROPE¬NIL ] RETURNS [nb: NB, newPartyID: PartyID] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shh]; partyID ¬ srCredentials.partyID; -- This is the right partyID to use. [srNB, newPartyID] ¬ ThPartySunRPCClient.GetPartyFromNumber[ pHandle.sHandle.handle, sunSHHH, partyID, ROPEToSr[phoneNumber], ROPEToSr[description] ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; }; GetPartyFromFeepNum: PUBLIC PROC[ shh: SHHH¬none, partyID: PartyID, feepNum: Thrush.ROPE¬NIL ] RETURNS [nb: NB, newPartyID: PartyID] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shh]; partyID ¬ srCredentials.partyID; -- This is the right partyID to use. [srNB, newPartyID] ¬ ThPartySunRPCClient.GetPartyFromFeepNum[ pHandle.sHandle.handle, sunSHHH, partyID, ROPEToSr[feepNum] ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; }; GetCurrentParty: PUBLIC PROC[shh: SHHH¬none, smartsID: SmartsID] RETURNS [nb: NB, partyID: Thrush.PartyID] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shh]; smartsID ¬ srCredentials.smartsID; [srNB, partyID] ¬ ThPartySunRPCClient.GetCurrentParty[pHandle.sHandle.handle, sunSHHH, smartsID ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; }; ReleaseParty: PUBLIC PROC[shh: SHHH¬none, partyID: PartyID, targetPartyID: PartyID] RETURNS [nb: NB] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shh]; partyID ¬ srCredentials.partyID; -- This is the right partyID to use. srNB ¬ ThPartySunRPCClient.ReleaseParty[ pHandle.sHandle.handle, sunSHHH, partyID, targetPartyID ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; }; GetNumbersForRName: PUBLIC PROC[shh: SHHH¬none, rName: ROPE] RETURNS [fullRName: ROPE, number: ROPE, homeNumber: ROPE] ~ { ENABLE { SRPCCalls.Error => { [] ¬ ReportError[shh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; pHandle: ThPartyHandle; pHandle ¬ GetInfo[shhh: shh, rereg: FALSE].pHandle; [fullRName, number, homeNumber] ¬ ThPartySunRPCClient.GetNumbersForRName[ pHandle.sHandle.handle, sunSHHH, ROPEToSr[rName] ]; RETURN[fullRName: SrToROPE[fullRName], number: SrToROPE[number], homeNumber: SrToROPE[homeNumber] ]; }; Register: PUBLIC PROC[ shh: SHHH¬none, rName: ROPE¬NIL, type: Thrush.PartyType¬ $individual, clonePartyID: PartyID ¬ nullID, interface: SmartsInterfaceName, properties: ThParty.SmartsProperties ] RETURNS [ nb: NB, credentials: Credentials ] ~ { ERROR; -- Shouldn't call this directly! }; CheckIn: PUBLIC PROC[shh: SHHH¬none, credentials: Credentials] RETURNS [nb: NB] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shh, credentials]; srNB ¬ ThPartySunRPCClient.CheckIn[ pHandle.sHandle.handle, sunSHHH, srCredentials ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; }; Deregister: PUBLIC PROC[shh: SHHH¬none, smartsID: SmartsID] RETURNS [nb: NB] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shhh: shh, rereg: FALSE]; smartsID ¬ srCredentials.smartsID; srNB ¬ ThPartySunRPCClient.Deregister[ pHandle.sHandle.handle, sunSHHH, smartsID ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; }; Enable: PUBLIC PROC[shh: SHHH¬none, smartsID: SmartsID] RETURNS [nb: Thrush.NB] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shh]; smartsID ¬ srCredentials.smartsID; srNB ¬ ThPartySunRPCClient.Enable[ pHandle.sHandle.handle, sunSHHH, smartsID ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; }; Disable: PUBLIC PROC[shh: SHHH¬none, smartsID: SmartsID] RETURNS [nb: Thrush.NB] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shh]; smartsID ¬ srCredentials.smartsID; srNB ¬ ThPartySunRPCClient.Disable[ pHandle.sHandle.handle, sunSHHH, smartsID ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; }; Visit: PUBLIC PROC[ shh: SHHH¬none, hostPartyID: PartyID, guestPartyID: PartyID, guestPassword: RPC.Password ] RETURNS [nb: Thrush.NB] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shh]; hostPartyID ¬ srCredentials.partyID; srNB ¬ ThPartySunRPCClient.Visit[ pHandle.sHandle.handle, sunSHHH, hostPartyID, guestPartyID, PasswordToSr[guestPassword] ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; }; Unvisit: PUBLIC PROC[ shh: SHHH¬none, hostPartyID: PartyID, guestPartyID: PartyID, guestPassword: RPC.Password ] RETURNS [nb: Thrush.NB] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shh]; hostPartyID ¬ srCredentials.partyID; srNB ¬ ThPartySunRPCClient.Unvisit[ pHandle.sHandle.handle, sunSHHH, hostPartyID, guestPartyID, PasswordToSr[guestPassword] ]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; }; UnvisitSelf: PUBLIC PROC[ shh: SHHH¬none, guestPartyID: PartyID ] RETURNS [nb: Thrush.NB] ~ { ENABLE { SRPCCalls.Error => { nb ¬ ReportError[shh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; pHandle: ThPartyHandle; srCredentials: SRCredentials; [pHandle, srCredentials] ¬ GetInfo[shh]; guestPartyID ¬ srCredentials.partyID; srNB ¬ ThPartySunRPCClient.UnvisitSelf[ pHandle.sHandle.handle, sunSHHH, guestPartyID]; nb ¬ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; }; sunPgm: CARD ¬ 390909; -- decimal program number for ThParty sunPgmVersion: CARD ¬ 1; sunCallTimeout: INT ¬ 3000; sunCallRetries: INT ¬ 3; sunCallTimeoutEnable: SRPCCalls.TimeoutEnable ¬ always; ThrushConnect: PUBLIC PROC [ server: ROPE, rName: ROPE, type: Thrush.PartyType, interface: SmartsInterfaceName, properties: ThParty.SmartsProperties, reportState: ThPartySunRPControl.ReportState, reportProblem: ThPartySunRPControl.ReportProblem¬NIL, reportData: REF¬NIL] RETURNS [shhh: SHHH ¬ none] ~ { sHandle: SHandle; pHandle: ThPartyHandle; shhh ¬ SRPCCalls.NewRPCConversation[ serverName: server, rpcProgram: sunPgm, rpcVersion: sunPgmVersion, timeoutEnable: sunCallTimeoutEnable, timeoutInMs: sunCallTimeout, retries: sunCallRetries, reportProc: ReportNonfatalRPCError]; sHandle ¬ SRPCCalls.GetSHandle[shhh]; pHandle ¬ NEW[ThPartyHandleRec ¬ [rName: rName, type: type, interface: interface, properties: properties, sHandle: sHandle, reportState: reportState, reportProblem: reportProblem, reportData: reportData]]; sHandle.clientData ¬ pHandle; sHandle.enabled ¬ TRUE; -- Unilaterally assert a will to connect. { ENABLE { SRPCCalls.Error => { []¬ReportError[shhh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => CONTINUE; -- Successful completion of very strange procedure. }; ReRegisterOnFailure[pHandle, $unbound]; }; }; ThrushDisconnect: PUBLIC PROC [shhh: Thrush.SHHH, disable: BOOL¬TRUE] ~ { ENABLE { SRPCCalls.Error => { []¬ReportError[shhh, errCode, explanation]; CONTINUE; }; UNWIND => NULL; }; pHandle: ThPartyHandle ¬ GetInfo[shhh: shhh, rereg: FALSE].pHandle; wasRegistered: BOOL ¬ pHandle.registered; pHandle.registered ¬ FALSE; -- even if it fails! IF disable THEN pHandle.sHandle.enabled ¬ FALSE; IF wasRegistered THEN [] ¬ Deregister[shhh, pHandle.smartsID]; [] ¬ ReportError[shhh, $disconnected, "Disconnected from server"]; }; ThrushReportState: PUBLIC PROC [shhh: Thrush.SHHH, enabled: BOOL, connected: BOOL] ~ { ENABLE { SRPCCalls.Error => { []¬ReportError[shhh, errCode, explanation]; CONTINUE; }; UNWIND => NULL; }; pHandle: ThPartyHandle ¬ GetInfo[shhh: shhh, rereg: FALSE].pHandle; IF ~enabled THEN pHandle.sHandle.enabled ¬ FALSE; pHandle.registered ¬ connected; }; ReleaseConversation: PUBLIC PROC [shhh: Thrush.SHHH] ~ { ENABLE { SRPCCalls.Error => { []¬ReportError[shhh, errCode, explanation]; CONTINUE; }; UNWIND => NULL; }; SRPCCalls.ReleaseConversation[shhh]; -- Thrush already assumed disconnected, for now. }; GetInfo: ENTRY PROC[shhh: Conversation, credentials: Credentials¬[], rereg: BOOL¬TRUE] RETURNS [pHandle: ThPartyHandle, updatedCredentials: SRCredentials] ~ { ENABLE UNWIND => NULL; -- !!!!!!!!!!! DCS September 14, 1990 3:43:51 pm PDT sHandle: SHandle; IF shhh = NIL THEN SRPCCalls.Error[$noConversationSupplied]; sHandle ¬ SRPCCalls.GetSHandle[shhh]; IF sHandle=NIL THEN SRPCCalls.Error[$invalidConversationSupplied]; pHandle ¬ NARROW[sHandle.clientData]; IF pHandle = NIL THEN SRPCCalls.Error[$invalidConversationSupplied]; recentShhh ¬ shhh; -- Any port in a storm; see usage for explanation. IF ~pHandle.registered AND rereg THEN RROFInt[pHandle, $unbound]; credentials.partyID ¬ pHandle.partyID; credentials.smartsID ¬ pHandle.smartsID; updatedCredentials ¬ ThrushSunRPCConvert.CredentialsToSr[credentials]; }; ReportNonfatalRPCError: SRPCCalls.ReportProc ~ { IF sHandle#NIL AND sHandle.conversation#NIL THEN []¬ReportError[sHandle.conversation, ec, expl]; }; ReportError: PROC[shhh: SHHH, ec: ATOM, expl: ROPE] RETURNS [nb: NB] ~ { pHandle: ThPartyHandle ¬ NARROW[SRPCCalls.GetSHandle[shhh].clientData]; IF pHandle.reportProblem#NIL THEN pHandle.reportProblem[pHandle.reportData, ec, expl]; ReportState[pHandle]; nb ¬ $callFailed; }; ReRegisterOnFailure: ENTRY PROC[pHandle: ThPartyHandle, nb: NB] ~ { ENABLE UNWIND => NULL; RROFInt[pHandle, nb]; }; RROFInt: INTERNAL PROC[pHandle: ThPartyHandle, nb: NB] ~ { credentials: Credentials; srNB: ThrushSunRPC.NB; srCredentials: SRCredentials; SELECT nb FROM $noSuchParty, $noSuchSmarts, $unbound => NULL; ENDCASE => RETURN; -- $success, or some error that implies the connection is still around. pHandle.registered ¬ FALSE; IF ~pHandle.sHandle.enabled THEN RETURN; [srNB, srCredentials] ¬ ThPartySunRPCClient.Register[ h: pHandle.sHandle.handle, shh: sunSHHH, rName: ROPEToSr[pHandle.rName], type: ATOMToSr[pHandle.type], interface: InterfaceNameToSr[pHandle.interface], properties: SmartsPropertiesToSr[pHandle.properties], clonePartyID: nullID ]; nb ¬ SrToATOM[srNB]; credentials ¬ SrToCredentials[srCredentials]; IF nb=$success THEN { srNB ¬ ThPartySunRPCClient.Enable[ pHandle.sHandle.handle, sunSHHH, credentials.smartsID ]; nb ¬ SrToATOM[srNB]; }; IF nb=$success THEN { [srNB, credentials.partyID] ¬ ThPartySunRPCClient.GetCurrentParty[ h: pHandle.sHandle.handle, shh: sunSHHH, smartsID: credentials.smartsID]; nb ¬ SrToATOM[srNB]; }; IF nb#$success THEN { nb ¬ ReportError[pHandle.sHandle.conversation, nb, "Can't register with server"]; RETURN; }; pHandle.registered ¬ TRUE; pHandle.partyID ¬ credentials.partyID; pHandle.smartsID ¬ credentials.smartsID; ReportState[pHandle]; ERROR RetryAfterReconnect; -- really success. }; ReportState: PROC[pHandle: ThPartyHandle] ~ { IF NOT pHandle.sHandle.connected THEN pHandle.registered ¬ FALSE; IF pHandle.reportState#NIL THEN pHandle.reportState[ pHandle.reportData, pHandle.registered, pHandle.sHandle.connected, pHandle.sHandle.enabled, pHandle.partyID, pHandle.smartsID]; }; }. ThPartyToThPartySunRPC.mesa Copyright Σ 1990, 1992 by Xerox Corporation. All rights reserved. Polle Zellweger (PTZ) October 29, 1990 4:00:19 pm PST Pier, May 10, 1990 11:33:09 pm PDT Swinehart, June 4, 1992 12:27 pm PDT Note: RegisterServiceInterface and LookupServiceInterface append "-Sun" to their type parameters, to promote PCedar/DCedar source sharing. All action routines should be implemented as entry procedures protecting monitored records, but that would require redefining RPC.Conversation as a monitored record. We can do that once D-systems are dead. Current fallback: monitor the error management procedures, and hope for the best. If that doesn't work fallback: use a global monitor. This will sequentialize all party calls on the machine, but that's probably not much of a loss. DCS September 8, 1990 If problems arise, remember that we can easily enough require our clients, which are always "smartses", to serialize all calls on a per-shhh basis. DCS September 13, 1990 8:23:59 am PDT Definitions connected: connection exists and is healthy; enabled: autoConnect is still in effect. Both reportState and reportProblem are optional ways to report events to a common site. If reportProblem is not supplied and a problem is discovered, it will be reported only through nb error code returns. Derived values Conversation Management Enumerations, registrations, queries Named conversations Rope.InlineFlatten the rope?? Party information Use a remembered one; can sometimes slow performance of other instances. Use a remembered one; can sometimes slow performance of other instances. Service action registration, lookup. See also ReportAction, above. Encryption key registration. Names to Parties, Numbers to Parties Information about people and parties ReRegisterOnFailure[pHandle, $success]; -- Call won't fail here due to no registration Party and Smarts creation, initialization ENABLE { SRPCCalls.Error => { nb _ ReportError[shh, errCode, explanation]; CONTINUE; }; RetryAfterReconnect => RETRY; UNWIND => NULL; }; srNB: ThrushSunRPC.NB; pHandle: ThPartyHandle; srCredentials: SRCredentials; pHandle _ GetInfo[shh].pHandle; [srNB, srCredentials] _ ThPartySunRPCClient.Register[ pHandle.sHandle.handle, sunSHHH, rName, ATOMToSr[type], clonePartyID, InterfaceNameToSr[interface], SmartsPropertiesToSr[properties] ]; nb _ SrToATOM[srNB]; ReRegisterOnFailure[pHandle, nb]; credentials _ SrToCredentials[srCredentials]; Connecting If this procedure fails to import, it reports the failure as Report or Problem, and indicates the resulting connection state via the reportState routine. It will return a shhh value in any case, since that will be needed in order to retry later. Worry about what happens when interface is already imported. Perhaps not idempotent yet. Worry about how to unregister (Unfinch.) Consider a lookup that identifies already-imported interfaces? Consider a version of this that takes an existing, unregistered, pHandle as an argument! Register with Thrush Entry holds others out during error recovery. Else the error is not at present reported at all. Could use some default Feedback call. Fatal errors at this level will be caught and reported by the caller! When successful, this procedure raises RetryAfterReconnect, in order to permit its caller to retry the entire procedure. (Turns each of the callers into a kind of LOOP). Entry here should be enough to eliminate most important reentrancy problems? If there's an entry here, we can't call GetInfo or allow ReRegisterOnFailure to be recursively entered. Fatal errors at this level will be caught and reported by the caller! When successful, this procedure raises RetryAfterReconnect, in order to permit its caller to retry the entire procedure. (Turns each of the callers into a kind of LOOP). Entry here should be enough to eliminate most important reentrancy problems? If there's an entry here, we can't call GetInfo or allow ReRegisterOnFailure to be recursively entered. Notify any interested parties about current connection state. Polle Zellweger (PTZ) October 1, 1989 5:03:15 pm PDT changes to: ThPartyToThPartySunRPC, CreateConversation, Alert, SrToCredentials, } Polle Zellweger (PTZ) October 3, 1989 12:54:30 pm PDT changes to: ThPartyToThPartySunRPC, CreateConversation, Alert, SrToAttributes, AttributesToSr, SrToCredentials, SrToConvEvent, ConvEventToSr, Advance, ReportAction, SrToActionReport, ActionReportToSr Polle Zellweger (PTZ) March 16, 1990 6:14:47 pm PST changes to: ReportAction Polle Zellweger (PTZ) March 21, 1990 11:09:01 pm PST changes to: ThPartyToThPartySunRPC, GetConversationInfo, SrToConversationInfo, SrToAddress, SrToCredentials, thPartyInfo, GetInfo Polle Zellweger (PTZ) April 19, 1990 12:57:36 pm PDT changes to: ThPartyToThPartySunRPC, SrToAddress, } Polle Zellweger (PTZ) May 2, 1990 9:43:19 pm PDT changes to: DIRECTORY, ThPartyToThPartySunRPC, SmartsInterfaceRecord, sunSHHH, ThPartyInfo, ThPartyRecord, thinfo, GetInfo, FinchRegister, SrToConversationInfo Polle Zellweger (PTZ) May 4, 1990 4:53:29 pm PDT changes to: SrToKeyTable, KeyTableToSr, GetKeyTable, UnregisterKey, GetParty, GetPartyFromNumber, GetPartyFromFeepNum, GetCurrentParty, ReleaseParty, GetNumbersForRName, Visit, Unvisit Polle Zellweger (PTZ) May 8, 1990 4:50:33 pm PDT changes to: SrToAttributes, SmartsPropertiesToSr, SrToVisitorList, ReleaseParty, Register, CheckIn, Deregister, Enable, Disable, Visit, Unvisit, UnvisitSelf, DIRECTORY, SmartsInterfaceName, RegisterConversation, EnumerateNamedConversations, GetPartyInfo, SrToPartyInfo, PartySeq, SrToPartyList, DescribeParty, AddAttributes, GetKeyTable, UnregisterKey, SrToCandidateList, CredentialsToSr, SrToInterfaceSpec, SrToKeyTable, KeyTableToSr, SrToVersionRange, VersionRangeToSr, SrToSmartsInterface, SmartsInterfaceToSr, CreateConversation, Advance, GetConversationInfo, SrToConvEvent, ConvEventToSr, SrToConversationInfo, SrToConvID, ConvIDToSr, SrToConvType, ConvTypeToSr, SrToCredentials, SrToEncryptionKey, EncryptionKeyToSr, SrToGMT, GMTToSr, InterfaceSpecToSr, SrToPartyInfoSpec, PasswordToSr, SrToState, StateToSr Pier, May 10, 1990 11:33:09 am PDT moved data conversion routines to ThrushSunRPCConvert Polle Zellweger (PTZ) May 11, 1990 4:08:39 pm PDT Atom.GetPName couldn't handle NIL, so make a new conversion routine. Polle Zellweger (PTZ) July 24, 1990 7:28:23 pm PDT SunYPAgent.Match has different # params in DCedar & PCedar changes to: SunYPNameToAddress Polle Zellweger (PTZ) August 1, 1990 6:39:57 pm PDT Keep multiple handles for multiple callers. NOTE: 2 ThParty calls have no SHHH param!!! changes to: ImportInterface, GetInfo & all procs GetInfo[] -> GetInfo[shh or shhh] Polle Zellweger (PTZ) August 14, 1990 9:22:53 am PDT Append "-Sun" to calls to (Register|Lookup)ServiceInterface (promotes PCedar/DCedar source sharing). changes to: DIRECTORY, LookupServiceInterface, RegisterServiceInterface Swinehart, August 30, 1990 6:36:07 pm PDT Add robust failure management code. Primary concerns: invalid initial server specifications, response to timeouts due to server or network failures. Polle Zellweger (PTZ) October 29, 1990 3:58:11 pm PST Allow detection of NIL ropes across a SunRPC connection. changes to: CreateConversation, Alert, Advance, RegisterConversation, GetConversationFromName, DescribeParty, GetParty, GetPartyFromNumber, GetPartyFromFeepNum, GetNumbersForRName, RROFInt Κ’•NewlineDelimiter –(cedarcode) style˜šœ™Jšœ Οeœ7™BIcode™5Kšœ"™"K™$J™JšœŠ™ŠJ™JšΟtœΞ™ΟJšœQ™QJšœ¬žœ•ž&™ιJ™J™—šΟk ˜ Kšœ ŸœŸœ˜KšœŸœ˜Kšœ Ÿœ˜KšœŸœŸœ˜KšœŸœ ˜KšŸœŸœ6˜?šœ Ÿœ˜Kšœo˜o—Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜ K˜Kšœ˜K˜—šΠlnœŸœŸ˜%KšŸœ:˜AKšŸœ˜$—Kšœ˜K˜KšŸœ˜K˜™ K˜Kšœ Ÿœ˜&KšœŸœ˜,KšœŸœ˜2KšœŸœ˜-Kšœ Ÿœ˜šœ Ÿœ˜!K˜!—Kšœ Ÿœ˜'KšœŸœ˜/KšŸœŸœ Ÿœ˜KšŸœŸœ Ÿœ˜šŸœŸœ Ÿœ˜KšœŸœ˜—Kšœ Ÿœ˜"KšœŸœŸœ˜.K˜Icode0šœ Ÿœ˜L˜LšœŸœŸœ˜+šœŸœŸœ˜!LšœŸœ˜ L˜L˜L˜%šœ/Ÿœ˜3L™U—šœ3Ÿœ˜7L™WL™u—Lšœ ŸœŸœΟc+˜BL˜L™Lšœ ŸœŸœ‘:˜TL˜L˜ L˜!L˜L˜—LšΟnœŸœŸœ˜"L˜Lšœ ŸœŸœ˜K˜—™K˜š’œŸœŸœŸœbŸœ ŸœŸœŸœŸœŸœŸœŸœŸœ#˜ΈšΠos˜Kš£œ£6˜OKš£˜Kš£˜Kš£˜—KšœŸœ˜Kšœ$˜$Kš£5˜5Kš£œ£˜6Kšœ*Οbœ"£ œŠ˜υK˜Kš£!˜!K˜'K˜K˜—š’œŸœŸœŸœKŸœŸœŸœŸœŸœŸœ˜Ιš£˜Kš£œ£6˜OKš£˜Kš£˜Kš£˜—KšœŸœ˜Kš£5˜5Kš£œ£˜6Kšœ€œ•˜·K˜Kš£!˜!K˜K˜—š"’œŸœŸœŸœKŸœŸœŸœ ŸœŸœŸœŸœ ŸœŸœŸœŸœŸœŸœ#˜Ξš£˜Kš£œ£6˜OKš£˜Kš£˜Kš£˜—KšœŸœ˜Kšœ$˜$Kš£5˜5Kš£œ£˜6Kšœ*’œ"£ œ’˜‚K˜Kš£!˜!K˜'Kšœ˜K˜—š’ œŸœŸœŸœ3ŸœŸœŸœŸœŸœŸœŸœ˜²š£˜Kš£œ£6˜OKš£˜Kš£˜Kš£˜—KšœŸœ˜Kš£5˜5Kš£œ£œ‘-˜eKš£ œ£ ˜.Kšœ/’ œ\˜—K˜Kš£!˜!K˜—K˜—šœ$™$J™š ’œŸœŸœŸœŸœŸœ˜yš£˜Kš£œ£5˜NKš£˜Kš£˜Kš£˜—KšœŸœ˜Kšœ(˜(Kš£œ£˜.Kšœ&’œ7˜pK˜Kš£!˜!K˜&K˜—K˜—™J™š’œŸœŸœ Ÿœ)ŸœFŸœ#ŸœŸœŸœ˜γš£˜Kš£œ£6˜OKš£˜Kš£˜Kš£˜—KšœŸœ˜Kš£5˜5Kš£œ£˜6šœ’œ"£ œg˜ΗK™—K˜Kš£!˜!K˜K˜—š’œŸœŸœ Ÿœ!ŸœŸœŸœ˜ˆš£˜Kš£œ£6˜OKš£˜Kš£˜Kš£˜—KšœŸœ˜Kšœ(˜(Kš£5˜5Kš£œ£˜)Kš£œ£˜ Kšœ&’œ<˜yK˜Kš£!˜!K˜&K˜K˜—š’œŸœŸœ ŸœŸœŸœŸœŸœ˜š£˜Kš£œ£6˜OKš£˜Kš£˜Kš£˜—KšœŸœ˜Kšœ*˜*Kš£5˜5Kš£œ£˜)Kš£œ£˜ Kšœ+’œ-˜sK˜Kš£!˜!K˜-K˜—K˜—™K™š’ œŸœŸœŸœPŸœŸœŸœŸœ ˜²š£˜Kš£œ£5˜NKš£˜Kš£˜Kš£˜—KšœŸœ˜Kšœ!˜!Kš£5˜5Kš£œ£˜5Kšœ&’ œ"£ œ"˜ƒK˜Kš£!˜!K˜K˜K˜—š’ œŸœŸœ5˜OšŸœŸœŸœ˜CK˜?Kšœ ŸœŸœŸœ˜*—š£ œ£ Ρbos˜Jš£H™H—š£˜Kš£œ£6˜OKš£˜Kš£˜Kš£˜—KšœŸœ˜Kšœ˜Kšœ&˜&Kš£˜Kš£œ£˜ KšœP’ œC˜ K˜Kš£!˜!K˜K˜'K˜$Kš€œ˜K˜—š’ œŸœŸœ7ŸœŸœŸ œŸœ˜Œš£ œ£ ₯˜Jš£H™H—š£˜Kš£œ£6˜OKš£˜Kš£˜Kš£˜—KšœŸœ˜Kš£5˜5Kš£œ£˜6Kšœ’ œ'£ œD˜ K˜Kš£!˜!Kš€œ˜—K˜—™CK™š ’œŸœŸœŸœPŸœŸœ*˜Ίš£˜Kš£œ£6˜OKš£˜Kš£˜Kš£˜—KšœŸœ˜Kšœ,˜,Kš£5˜5Kš£œ£˜6K˜gKšœ.’œ#£ œ,˜’K˜Kš£!˜!K˜3K˜K˜—š’œŸœŸœŸœ@Ÿœ ŸœŸœ*˜Έš£˜Kš£œ£6˜OKš£˜Kš£˜Kš£˜—KšœŸœ˜Kšœ,˜,Kš£5˜5Kš£œ£˜6Kšœ.’œ#£ œ,˜ K˜Kš£!˜!K˜3K˜—K™—™K™š’ œŸœŸœŸœMŸœŸœŸœŸœ˜§š£˜Kš£œ£5˜NKš£˜Kš£˜Kš£˜—KšœŸœ˜Kš£5˜5Kš£œ£˜5Kšœ'’ œ#£ œ*˜ŒK˜Kš£!˜!K˜K˜—š ’ œŸœŸœŸœ!ŸœŸœ!˜wš£˜Kš£œ£5˜NKš£˜Kš£˜Kš£˜—KšœŸœ˜Kšœ"˜"Kš£5˜5Kš£œ£˜5Kšœ)’ œ#£ œ˜gK˜Kš£!˜!K˜$K˜K˜—š ’ œŸœŸœŸœ>ŸœŸœ˜zš£˜Kš£œ£5˜NKš£˜Kš£˜Kš£˜—KšœŸœ˜Kš£5˜5Kš£œ£˜5Kšœ’ œ#£ œ˜sK˜Kš£!˜!K˜—K™—™$K˜š’œŸœŸœŸœ ŸœŸœŸœŸœŸœ˜š£˜Kš£œ£5˜NKš£˜Kš£˜Kš£˜—KšœŸœ˜Kš£5˜5Kš£œ£˜(Kš£œ£<˜EKšœ)’œN˜K˜Kš£!˜!K˜K˜—š’œŸœŸœŸœ-ŸœŸœŸœŸœŸœŸœ˜’š£˜Kš£œ£5˜NKš£˜Kš£˜Kš£˜—KšœŸœ˜Kš£5˜5Kš£œ£˜(Kš£œ£<˜EKšœ)’œ[˜–K˜Kš£!˜!K˜K˜—š’œŸœŸœŸœ)ŸœŸœŸœŸœ˜ˆš£˜Kš£œ£5˜NKš£˜Kš£˜Kš£˜—KšœŸœ˜Kš£5˜5Kš£œ£˜(Kš£œ£<˜EKšœ)’œ@˜|K˜Kš£!˜!K˜K˜—š ’œŸœŸœŸœŸœŸœ˜nš£˜Kš£œ£5˜NKš£˜Kš£˜Kš£˜—KšœŸœ˜Kš£5˜5Kš£œ£˜(Kš£ œ£˜"Kšœ&’œ-˜bK˜Kš£!˜!K˜K˜—š ’ œŸœŸœŸœ0ŸœŸœ˜hš£˜Kš£œ£5˜NKš£˜Kš£˜Kš£˜—KšœŸœ˜Kš£5˜5Kš£œ£˜(Kš£œ£<˜EKšœ’ œ<˜cK˜Kš£!˜!K˜—K™—™$K™š’œŸœŸœŸœŸœŸœ Ÿœ ŸœŸœ˜zš£˜Kš£œ£5˜NKš£˜Kš£˜Kš£˜—Kš£˜Kš£œ£Ρkos£ ˜3Kšœ6’œ5˜}Kš£V™VKšŸœ^˜dK˜—K™—™)K™š’œŸœŸœŸœŸœŸœŸœŸœ ˜τKšŸœ‘ ˜'š£™Jš£N™NJš£™Jš£™Jš£™—JšœŸœ™Jš£5™5Jš£™Kšœ,’œ‰™½Kšœ™Kš£!™!Kšœ-™-K˜—K˜š ’œŸœŸœŸœ!ŸœŸœ˜Sš£˜Kš£œ£5˜NKš£˜Kš£˜Kš£˜—KšœŸœ˜Kš£5˜5Kš£œ£˜5Kšœ’œ#£ œ˜UK˜Kš£!˜!K˜K˜—š ’ œŸœŸœŸœŸœŸœ˜Pš£˜Kš£œ£5˜NKš£˜Kš£˜Kš£˜—KšœŸœ˜Kš£5˜5Kš£œ£¦£˜K˜BK˜K˜—š ’œŸœŸœŸœ Ÿœ Ÿœ˜VšŸœ˜KšœAŸœ˜MKšŸœŸœ˜K˜—Kšœ4Ÿœ ˜CKšŸœ ŸœŸœ˜1K˜K˜K˜—š’œŸœŸœŸœ˜8šŸœ˜KšœAŸœ˜MKšŸœŸœ˜K˜—Kšœ%‘ž‘-ž˜WK˜K˜—š ’œŸœŸœ9ŸœŸœŸœ@˜žK™-KšŸœŸœŸœ‘4˜KKšœ˜KšŸœŸœŸœ*˜