DIRECTORY Basics USING [Card16FromH, HFromCard16, HWORD, Word16], CHACLOpsP127V1 USING [AddMemberToDomainACL, AddMemberToOrganizationACL, AddMemberToPropertyACL, DeleteMemberFromDomainACL, DeleteMemberFromOrganizationACL, DeleteMemberFromPropertyACL, DomainName, IsInDomainACL, IsInOrganizationACL, IsInPropertyACL, OrganizationName, RetrieveDomainACL, RetrieveOrganizationACL, RetrievePropertyACL], CHEntriesP0V0 USING [addressList, associatedWorkstation, members], CHOpsP2V3 USING [AddGroupProperty, AddItemProperty, AddMember, AddSelf, Authenticator, ChangeItem, CreateAlias, CreateObject, DeleteAlias, DeleteMember, DeleteSelf, DeleteObject, DeleteProperty, IsMember, ItemObject, ListAliases, ListAliasesOf, ListDomains, ListDomainsServed, ListObjects, ListOrganizations, ListProperties, LookupObject, NetworkAddressList, RetrieveAddresses, RetrieveItem, RetrieveMembers], Convert USING [Error, RopeFromXNSAddress, XNSAddressFromRope], CrRPC USING [BulkDataCheckAbortProc, BulkDataValueProc, BulkDataXferProc, GetRope, Handle, MarshalledRopeHWords, PutRope, ReadBulkDataStream, WriteBulkDataSegment], IO USING [STREAM], RefText USING [AppendChar, ObtainScratch, ReleaseScratch], Rope USING [Cat, Concat, FromRefText, Fetch, IsEmpty, Length, ROPE], ThisMachineRegistry USING [RegisterThisMachineProcs, ThisMachineProcsRec, ThisMachineRef], XNS USING [Address, GetThisHost, Host, unknownAddress], XNSAuth USING [GetIdentityDetails, Identity], XNSCH USING [Conversation, Element, ElementStreamProc, EnumeratorProc, ErrorCode, InitiateConversation, Item, Name, NameStreamProc, notUsable, Pattern, Properties, PropertyID, TerminateConversation, unspecified, Which], XNSCHACL USING [AccessList], XNSCHName USING [FieldTooLong, Name, NameFromRope, RopeFromName], XNSCHPrivate USING [CallRemote, GetAuthenticator, IsGeneric, NACacheInsert, NACacheLookup, RemoteProc], XNSCredentials USING [GetIdentity], XNSRouter USING [GetHops] ; XNSCHImpl: CEDAR MONITOR IMPORTS Basics, CHACLOpsP127V1, CHOpsP2V3, Convert, CrRPC, RefText, Rope, ThisMachineRegistry, XNS, XNSAuth, XNSCH, XNSCHName, XNSCHPrivate, XNSCredentials, XNSRouter EXPORTS XNSCH, XNSCHACL, XNSCHPrivate ~ { OPEN CHEntries: CHEntriesP0V0, CHOps: CHOpsP2V3, CHACLOps: CHACLOpsP127V1; ROPE: TYPE ~ Rope.ROPE; Name: TYPE ~ XNSCH.Name; Pattern: TYPE ~ XNSCH.Pattern; Element: TYPE ~ XNSCH.Element; PropertyID: TYPE ~ XNSCH.PropertyID; Properties: TYPE ~ XNSCH.Properties; Item: TYPE ~ XNSCH.Item; Conversation: TYPE ~ XNSCH.Conversation; AccessList: TYPE ~ XNSCHACL.AccessList; DomainName: TYPE ~ CHACLOps.DomainName; OrganizationName: TYPE ~ CHACLOps.OrganizationName; HWORD: TYPE ~ Basics.HWORD; RemoteProc: TYPE ~ XNSCHPrivate.RemoteProc; BulkDataXferProc: TYPE ~ CrRPC.BulkDataXferProc; BulkDataValueProc: TYPE ~ CrRPC.BulkDataValueProc; shiftInName: ROPE ~ "CHServers"; chServiceName: Name ~ [organization~shiftInName, domain~shiftInName, object~"Clearinghouse Service"]; Error: PUBLIC ERROR [code: XNSCH.ErrorCode, which: XNSCH.Which] ~ CODE; Add: PUBLIC PROC [c: Conversation, name: Name] ~ { DoAdd: RemoteProc -- [handle, host] -- ~ { CHOps.CreateObject[handle, name, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoAdd, DomainFromElement[name]]; }; Delete: PUBLIC PROC [c: Conversation, name: Name] ~ { DoDelete: RemoteProc -- [handle, host] -- ~ { CHOps.DeleteObject[handle, name, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoDelete, DomainFromElement[name]]; }; Lookup: PUBLIC PROC [c: Conversation, pattern: Pattern] RETURNS [distingName: Name] ~ { DoLookup: RemoteProc -- [handle, host] -- ~ { distingName ¬ CHOps.LookupObject[handle, pattern, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoLookup, DomainFromElement[pattern]]; }; AddAlias: PUBLIC PROC [c: Conversation, name, alias: Name] RETURNS [distingName: Name] ~ { DoAddAlias: RemoteProc -- [handle, host] -- ~ { distingName ¬ CHOps.CreateAlias[handle, alias, name, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoAddAlias, DomainFromElement[alias--????--]]; }; DeleteAlias: PUBLIC PROC [c: Conversation, alias: Name] RETURNS [distingName: Name] ~ { DoDeleteAlias: RemoteProc -- [handle, host] -- ~ { distingName ¬ CHOps.DeleteAlias[handle, alias, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoDeleteAlias, DomainFromElement[alias]]; }; ListAliases: PUBLIC PROC [c: Conversation, pattern: Pattern, eachAlias: XNSCH.NameStreamProc] RETURNS [distingName: Name] ~ { ReadStreamOfNames: BulkDataXferProc ~ { EachNameInStream: BulkDataValueProc ~ { eachAlias[GetElement[s]] }; RETURN [CrRPC.ReadBulkDataStream[h, s, checkAbort, EachNameInStream]]; }; DoListAliases: RemoteProc -- [handle, host] -- ~ { distingName ¬ CHOps.ListAliasesOf[handle, pattern, ReadStreamOfNames, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoListAliases, DomainFromElement[pattern], FALSE]; }; GetProperties: PUBLIC PROC [c: Conversation, pattern: Pattern] RETURNS [distingName: Name, properties: Properties] ~ { DoGetProperties: RemoteProc -- [handle, host] -- ~ { [distinguishedObject~distingName, properties~properties] ¬ CHOps.ListProperties[handle, pattern, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoGetProperties, DomainFromElement[pattern]]; }; DeleteProperty: PUBLIC PROC [c: Conversation, name: Name, pID: PropertyID] RETURNS [distingName: Name] ~ { DoDeleteProperty: RemoteProc -- [handle, host] -- ~ { distingName ¬ CHOps.DeleteProperty[handle, name, pID, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoDeleteProperty, DomainFromElement[name]]; }; AddItemProperty: PUBLIC PROC [c: Conversation, name: Name, pID: PropertyID, item: Item] RETURNS [distingName: Name] ~ { DoAddItemProperty: RemoteProc -- [handle, host] -- ~ { distingName ¬ CHOps.AddItemProperty[handle, name, pID, item, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoAddItemProperty, DomainFromElement[name]]; }; ChangeItemProperty: PUBLIC PROC [c: Conversation, name: Name, pID: PropertyID, item: Item] RETURNS [distingName: Name] ~ { DoChangeItemProperty: RemoteProc -- [handle, host] -- ~ { distingName ¬ CHOps.ChangeItem[handle, name, pID, item, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoChangeItemProperty, DomainFromElement[name]]; }; LookupItemProperty: PUBLIC PROC [c: Conversation, pattern: Pattern, pID: PropertyID] RETURNS [distingName: Name, item: Item] ~ { DoLookupItemProperty: RemoteProc -- [handle, host] -- ~ { [distinguishedObject~distingName, value~item] ¬ CHOps.RetrieveItem[handle, pattern, pID, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoLookupItemProperty, DomainFromElement[pattern]]; }; LookupAddress: PUBLIC PROC [c: Conversation, pattern: Pattern] RETURNS [distingName: Name, address: XNS.Address] ~ { DoLookupAddress: RemoteProc -- [handle, host] -- ~ { item: Item; addresses: LIST OF XNS.Address; [distinguishedObject~distingName, value~item] ¬ CHOps.RetrieveItem[handle, pattern, CHEntries.addressList, XNSCHPrivate.GetAuthenticator[c, host]]; addresses ¬ AddressesFromItem[item]; IF addresses # NIL THEN address ¬ BestAddressInList[addresses] ELSE address ¬ XNS.unknownAddress; }; XNSCHPrivate.CallRemote[c, DoLookupAddress, DomainFromElement[pattern]]; }; LookupRopeProperty: PUBLIC PROC [c: Conversation, pattern: Pattern, pID: PropertyID] RETURNS [distingName: Name, ropeProperty: ROPE] ~ { DoLookupRopeProperty: RemoteProc -- [handle, host] -- ~ { item: Item; [distinguishedObject~distingName, value~item] ¬ CHOps.RetrieveItem[handle, pattern, pID, XNSCHPrivate.GetAuthenticator[c, host]]; ropeProperty ¬ RopeFromItem[item]; }; XNSCHPrivate.CallRemote[c, DoLookupRopeProperty, DomainFromElement[pattern]]; }; LookupNameProperty: PUBLIC PROC [c: Conversation, pattern: Pattern, pID: PropertyID] RETURNS [distingName: Name, nameProperty: Name] ~ { DoLookupNameProperty: RemoteProc -- [handle, host] -- ~ { item: Item; [distinguishedObject~distingName, value~item] ¬ CHOps.RetrieveItem[handle, pattern, pID, XNSCHPrivate.GetAuthenticator[c, host]]; nameProperty ¬ ElementFromItem[item]; }; XNSCHPrivate.CallRemote[c, DoLookupNameProperty, DomainFromElement[pattern]]; }; HeAborted: ERROR ~ CODE; AddGroupProperty: PUBLIC PROC [c: Conversation, name: Name, pID: PropertyID, enumerator: XNSCH.EnumeratorProc] RETURNS [distingName: Name] ~ { WriteStreamOfElements: BulkDataXferProc ~ { heAborted: BOOL ¬ FALSE; EachElement: PROC [element: Element] ~ { WriteTheElement: BulkDataValueProc ~ { PutElement[s, element]; RETURN [FALSE] }; [heAborted~heAborted] ¬ CrRPC.WriteBulkDataSegment[h, s, checkAbort, WriteTheElement, 1]; IF heAborted THEN ERROR HeAborted[]; }; enumerator[EachElement ! HeAborted => CONTINUE ]; IF NOT heAborted THEN [] ¬ CrRPC.WriteBulkDataSegment[h, s, NIL, NIL, 0]; RETURN [FALSE] }; DoAddGroupProperty: RemoteProc -- [handle, host] -- ~ { distingName ¬ CHOps.AddGroupProperty[handle, name, pID, WriteStreamOfElements, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoAddGroupProperty, DomainFromElement[name]]; }; AddMember: PUBLIC PROC [c: Conversation, name: Name, pID: PropertyID, member: Element] RETURNS [distingName: Name] ~ { DoAddMember: RemoteProc -- [handle, host] -- ~ { distingName ¬ CHOps.AddMember[handle, name, pID, member, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoAddMember, DomainFromElement[name]]; }; AddSelf: PUBLIC PROC [c: Conversation, name: Name, pID: PropertyID] RETURNS [distingName: Name] ~ { DoAddSelf: RemoteProc -- [handle, host] -- ~ { distingName ¬ CHOps.AddSelf[handle, name, pID, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoAddSelf, DomainFromElement[name]]; }; DeleteMember: PUBLIC PROC [c: Conversation, name: Name, pID: PropertyID, member: Element] RETURNS [distingName: Name] ~ { DoDeleteMember: RemoteProc -- [handle, host] -- ~ { distingName ¬ CHOps.DeleteMember[handle, name, pID, member, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoDeleteMember, DomainFromElement[name]]; }; DeleteSelf: PUBLIC PROC [c: Conversation, name: Name, pID: PropertyID] RETURNS [distingName: Name] ~ { DoDeleteSelf: RemoteProc -- [handle, host] -- ~ { distingName ¬ CHOps.DeleteSelf[handle, name, pID, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoDeleteSelf, DomainFromElement[name]]; }; ListMembers: PUBLIC PROC [c: Conversation, pattern: Pattern, pID: PropertyID, eachMember: XNSCH.ElementStreamProc] RETURNS [distingName: Name] ~ { ReadStreamOfElements: BulkDataXferProc ~ { EachElementInStream: BulkDataValueProc ~ { eachMember[GetElement[s]] }; RETURN [CrRPC.ReadBulkDataStream[h, s, checkAbort, EachElementInStream]]; }; DoListMembers: RemoteProc -- [handle, host] -- ~ { distingName ¬ CHOps.RetrieveMembers[handle, pattern, pID, ReadStreamOfElements, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoListMembers, DomainFromElement[pattern], FALSE]; }; IsMember: PUBLIC PROC [c: Conversation, pattern: Pattern, pID: PropertyID, member: Element] RETURNS [distingName: Name, isMember: BOOL] ~ { DoIsMember: RemoteProc -- [handle, host] -- ~ { [isMember~isMember, distinguishedObject~distingName] ¬ CHOps.IsMember[handle, pattern, pID, XNSCH.notUsable, member, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoIsMember, DomainFromElement[pattern]]; }; IsMemberClosure: PUBLIC PROC [c: Conversation, pattern: Pattern, pID: PropertyID, member: Element, pID2: PropertyID] RETURNS [distingName: Name, isMember: BOOL] ~ { DoIsMemberClosure: RemoteProc -- [handle, host] -- ~ { [isMember~isMember, distinguishedObject~distingName] ¬ CHOps.IsMember[handle, pattern, pID, pID2, member, XNSCHPrivate.GetAuthenticator[c, host]]; }; IF pID2 = XNSCH.unspecified THEN pID2 ¬ pID; XNSCHPrivate.CallRemote[c, DoIsMemberClosure, DomainFromElement[pattern]]; }; Enumerate: PUBLIC PROC [c: Conversation, pattern: Pattern, pID: PropertyID, eachObject: XNSCH.NameStreamProc] ~ { ReadStreamOfStrings: BulkDataXferProc ~ { EachStringInStream: BulkDataValueProc ~ { eachObject[[organization~pattern.organization, domain~pattern.domain, object~CrRPC.GetRope[s]]] }; RETURN [CrRPC.ReadBulkDataStream[h, s, checkAbort, EachStringInStream]]; }; DoEnumerate: RemoteProc -- [handle, host] -- ~ { CHOps.ListObjects[handle, pattern, pID, ReadStreamOfStrings, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoEnumerate, DomainFromElement[pattern], FALSE]; }; EnumerateAliases: PUBLIC PROC [c: Conversation, pattern: Pattern, eachName: XNSCH.NameStreamProc] ~ { ReadStreamOfStrings: BulkDataXferProc ~ { EachStringInStream: BulkDataValueProc ~ { eachName[[organization~pattern.organization, domain~pattern.domain, object~CrRPC.GetRope[s]]] }; RETURN [CrRPC.ReadBulkDataStream[h, s, checkAbort, EachStringInStream]]; }; DoEnumerateAliases: RemoteProc -- [handle, host] -- ~ { CHOps.ListAliases[handle, pattern, ReadStreamOfStrings, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoEnumerateAliases, DomainFromElement[pattern], FALSE]; }; EnumerateOrganizations: PUBLIC PROC [c: Conversation, pattern: Pattern, eachOrganization: XNSCH.ElementStreamProc] ~ { ReadStreamOfStrings: BulkDataXferProc ~ { EachStringInStream: BulkDataValueProc ~ { eachOrganization[[organization~CrRPC.GetRope[s], domain~NIL, object~NIL]] }; RETURN [CrRPC.ReadBulkDataStream[h, s, checkAbort, EachStringInStream]]; }; DoEnumerateOrganizations: RemoteProc -- [handle, host] -- ~ { CHOps.ListOrganizations[handle, pattern.organization, ReadStreamOfStrings, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoEnumerateOrganizations, NIL, FALSE]; }; EnumerateDomains: PUBLIC PROC [c: Conversation, pattern: Pattern, eachDomain: XNSCH.ElementStreamProc] ~ { ReadStreamOfStrings: BulkDataXferProc ~ { EachStringInStream: BulkDataValueProc ~ { eachDomain[[organization~pattern.organization, domain~CrRPC.GetRope[s], object~NIL]] }; RETURN [CrRPC.ReadBulkDataStream[h, s, checkAbort, EachStringInStream]]; }; DoEnumerateDomains: RemoteProc -- [handle, host] -- ~ { CHOps.ListDomains[handle, [organization~pattern.organization, domain~pattern.domain], ReadStreamOfStrings, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoEnumerateDomains, DomainFromOrgElement[pattern], FALSE]; }; ListMembersOfPropertyACL: PUBLIC PROC [c: Conversation, pattern: Pattern, pID: PropertyID, acl: AccessList, eachMember: XNSCH.ElementStreamProc] RETURNS [distingName: Name] ~ { ReadStreamOfElements: BulkDataXferProc ~ { EachElementInStream: BulkDataValueProc ~ { eachMember[GetElement[s]] }; RETURN [CrRPC.ReadBulkDataStream[h, s, checkAbort, EachElementInStream]]; }; DoListMembersOfPropertyACL: RemoteProc -- [handle, host] -- ~ { distingName ¬ CHACLOps.RetrievePropertyACL[handle, pattern, pID, acl, ReadStreamOfElements, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoListMembersOfPropertyACL, DomainFromElement[pattern], FALSE]; }; IsMemberOfPropertyACLClosure: PUBLIC PROC [c: Conversation, pattern: Pattern, pID: PropertyID, acl: AccessList, member: Element, pID2: PropertyID] RETURNS [distingName: Name, isMember: BOOL] ~ { DoIsMemberOfPropertyACLClosure: RemoteProc -- [handle, host] -- ~ { [inACL~isMember, distinguishedObject~distingName] ¬ CHACLOps.IsInPropertyACL[handle, pattern, pID, acl, pID2, member, XNSCHPrivate.GetAuthenticator[c, host]]; }; IF pID2 = XNSCH.unspecified THEN pID2 ¬ pID; XNSCHPrivate.CallRemote[c, DoIsMemberOfPropertyACLClosure, DomainFromElement[pattern]]; }; AddMemberToPropertyACL: PUBLIC PROC [c: Conversation, name: Name, pID: PropertyID, acl: AccessList, member: Element] RETURNS [distingName: Name] ~ { DoAddMemberToPropertyACL: RemoteProc -- [handle, host] -- ~ { distingName ¬ CHACLOps.AddMemberToPropertyACL[handle, name, pID, acl, member, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoAddMemberToPropertyACL, DomainFromElement[name]]; }; DeleteMemberFromPropertyACL: PUBLIC PROC [c: Conversation, name: Name, pID: PropertyID, acl: AccessList, member: Element] RETURNS [distingName: Name] ~ { DoDeleteMemberFromPropertyACL: RemoteProc -- [handle, host] -- ~ { distingName ¬ CHACLOps.DeleteMemberFromPropertyACL[handle, name, pID, acl, member, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoDeleteMemberFromPropertyACL, DomainFromElement[name]]; }; ListMembersOfDomainACL: PUBLIC PROC [c: Conversation, domain: Name, acl: AccessList, eachMember: XNSCH.ElementStreamProc] ~ { domainName: DomainName ~ [domain~domain.domain, organization~domain.organization]; ReadStreamOfElements: BulkDataXferProc ~ { EachElementInStream: BulkDataValueProc ~ { eachMember[GetElement[s]] }; RETURN [CrRPC.ReadBulkDataStream[h, s, checkAbort, EachElementInStream]]; }; DoListMembersOfDomainACL: RemoteProc -- [handle, host] -- ~ { [] ¬ CHACLOps.RetrieveDomainACL[handle, domainName, acl, ReadStreamOfElements, XNSCHPrivate.GetAuthenticator[c, host]]; -- RETURNS SOMETHING ???? }; XNSCHPrivate.CallRemote[c, DoListMembersOfDomainACL, DomainFromElement[domain], FALSE]; }; IsMemberOfDomainACLClosure: PUBLIC PROC [c: Conversation, domain: Name, acl: AccessList, member: Element, pID2: PropertyID] RETURNS [isMember: BOOL] ~ { domainName: DomainName ~ [domain~domain.domain, organization~domain.organization]; DoIsMemberOfDomainACLClosure: RemoteProc -- [handle, host] -- ~ { isMember ¬ CHACLOps.IsInDomainACL[handle, domainName, acl, pID2, member, XNSCHPrivate.GetAuthenticator[c, host]]; }; IF pID2 = XNSCH.unspecified THEN pID2 ¬ CHEntries.members; XNSCHPrivate.CallRemote[c, DoIsMemberOfDomainACLClosure, DomainFromElement[domain]]; }; AddMemberToDomainACL: PUBLIC PROC [c: Conversation, domain: Name, acl: AccessList, member: Element] ~ { domainName: DomainName ~ [domain~domain.domain, organization~domain.organization]; DoAddMemberToDomainACL: RemoteProc -- [handle, host] -- ~ { CHACLOps.AddMemberToDomainACL[handle, domainName, acl, member, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoAddMemberToDomainACL, DomainFromElement[domain]]; }; DeleteMemberFromDomainACL: PUBLIC PROC [c: Conversation, domain: Name, acl: AccessList, member: Element] ~ { domainName: DomainName ~ [domain~domain.domain, organization~domain.organization]; DoDeleteMemberFromDomainACL: RemoteProc -- [handle, host] -- ~ { CHACLOps.DeleteMemberFromDomainACL[handle, domainName, acl, member, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoDeleteMemberFromDomainACL, DomainFromElement[domain]]; }; ListMembersOfOrganizationACL: PUBLIC PROC [c: Conversation, organization: Name, acl: AccessList, eachMember: XNSCH.ElementStreamProc] ~ { organizationName: OrganizationName ~ organization.organization; ReadStreamOfElements: BulkDataXferProc ~ { EachElementInStream: BulkDataValueProc ~ { eachMember[GetElement[s]] }; RETURN [CrRPC.ReadBulkDataStream[h, s, checkAbort, EachElementInStream]]; }; DoListMembersOfOrganizationACL: RemoteProc -- [handle, host] -- ~ { CHACLOps.RetrieveOrganizationACL[handle, organizationName, acl, ReadStreamOfElements, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoListMembersOfOrganizationACL, DomainFromOrgElement[organization], FALSE]; }; IsMemberOfOrganizationACLClosure: PUBLIC PROC [c: Conversation, organization: Name, acl: AccessList, member: Element, pID2: PropertyID] RETURNS [isMember: BOOL] ~ { organizationName: OrganizationName ~ organization.organization; DoIsMemberOfOrganizationACLClosure: RemoteProc -- [handle, host] -- ~ { isMember ¬ CHACLOps.IsInOrganizationACL[handle, organizationName, acl, pID2, member, XNSCHPrivate.GetAuthenticator[c, host]]; }; IF pID2 = XNSCH.unspecified THEN pID2 ¬ CHEntries.members; XNSCHPrivate.CallRemote[c, DoIsMemberOfOrganizationACLClosure, DomainFromOrgElement[organization]]; }; AddMemberToOrganizationACL: PUBLIC PROC [c: Conversation, organization: Name, acl: AccessList, member: Element] ~ { organizationName: OrganizationName ~ organization.organization; DoAddMemberToOrganizationACL: RemoteProc -- [handle, host] -- ~ { CHACLOps.AddMemberToOrganizationACL[handle, organizationName, acl, member, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoAddMemberToOrganizationACL, DomainFromOrgElement[organization]]; }; DeleteMemberFromOrganizationACL: PUBLIC PROC [c: Conversation, organization: Name, acl: AccessList, member: Element] ~ { organizationName: OrganizationName ~ organization.organization; DoDeleteMemberFromOrganizationACL: RemoteProc -- [handle, host] -- ~ { CHACLOps.DeleteMemberFromOrganizationACL[handle, organizationName, acl, member, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoDeleteMemberFromOrganizationACL, DomainFromOrgElement[organization]]; }; LookupAddressFromRopeInner: PROC [rope: ROPE, doClosure: BOOL ¬ FALSE] RETURNS [distingName: Name ¬ [NIL,NIL,NIL], address: XNS.Address ¬ XNS.unknownAddress, didClosure: BOOL ¬ FALSE] ~ { c: Conversation ¬ XNSCH.InitiateConversation[]; name: Name; { { ENABLE Convert.Error => CONTINUE; address ¬ Convert.XNSAddressFromRope[rope]; GOTO Good }; { ENABLE XNSCHName.FieldTooLong => GOTO Bad; name ¬ XNSCHName.NameFromRope[rope]; }; DO { found: BOOL; [found, distingName, address] ¬ XNSCHPrivate.NACacheLookup[name]; IF found THEN GOTO Good; }; { ENABLE Error => CONTINUE; [distingName, address] ¬ LookupAddress[c, name]; XNSCHPrivate.NACacheInsert[name, distingName, address]; -- Note we cache direct mappings only, not closure mappings. GOTO Good }; IF doClosure THEN { ENABLE Error => CONTINUE; item: Item; [item~item] ¬ LookupItemProperty[c~c, pattern~name, pID~CHEntries.associatedWorkstation]; name ¬ ElementFromItem[item]; didClosure ¬ TRUE; LOOP; }; GOTO Bad; ENDLOOP; EXITS Good, Bad => NULL; }; XNSCH.TerminateConversation[c]; }; LookupAddressFromRope: PUBLIC PROC [rope: ROPE] RETURNS [distingName: Name, address: XNS.Address] ~ { [distingName~distingName, address~address] ¬ LookupAddressFromRopeInner[rope, FALSE]; }; LookupAddressFromRopeClosure: PUBLIC PROC [rope: ROPE] RETURNS [distingName: Name, address: XNS.Address, didClosure: BOOL] ~ { [distingName, address, didClosure] ¬ LookupAddressFromRopeInner[rope, TRUE]; }; GetServerAddresses: PUBLIC PROC [c: Conversation] RETURNS [addresses: LIST OF XNS.Address] ~ { list: CHOps.NetworkAddressList; DoGetServerAddresses: RemoteProc -- [handle, host] -- ~ { i: CARDINAL; list ¬ CHOps.RetrieveAddresses[handle]; i ¬ list.length; addresses ¬ NIL; WHILE i > 0 DO i ¬ i - 1; addresses ¬ CONS [LOOPHOLE[list.body[i]], addresses]; ENDLOOP; }; IF XNSCHPrivate.IsGeneric[c] THEN ERROR Error[inappropriateConversation, first]; XNSCHPrivate.CallRemote[c, DoGetServerAddresses, NIL]; }; EnumerateDomainsServed: PUBLIC PROC [c: Conversation, eachDomain: XNSCH.ElementStreamProc] ~ { ReadStreamOfDomains: BulkDataXferProc ~ { EachDomainInStream: BulkDataValueProc ~ { eachDomain[GetDomain[s]] }; RETURN [CrRPC.ReadBulkDataStream[h, s, checkAbort, EachDomainInStream]]; }; DoEnumerateDomainsServed: RemoteProc -- [handle, host] -- ~ { CHOps.ListDomainsServed[handle, ReadStreamOfDomains, XNSCHPrivate.GetAuthenticator[c, host]]; }; IF XNSCHPrivate.IsGeneric[c] THEN ERROR Error[inappropriateConversation, first]; XNSCHPrivate.CallRemote[c, DoEnumerateDomainsServed, NIL]; }; adrHWords: CARDINAL ~ BITS[XNS.Address]/BITS[HWORD]; AddressesFromItem: PUBLIC PROC [item: Item] RETURNS [addresses: LIST OF XNS.Address] ~ { buf: PACKED ARRAY [0..adrHWords) OF HWORD; cnt: CARD16; index: CARDINAL ¬ 1; IF item.length < 1 THEN RETURN[NIL]; cnt ¬ item.body[0]; IF item.length < 1+cnt*adrHWords THEN RETURN[NIL]; THROUGH [1..cnt] DO FOR i: CARDINAL IN [0..adrHWords) DO buf[i] ¬ Basics.HFromCard16[item.body[index]]; index ¬ index + 1; ENDLOOP; addresses ¬ CONS[LOOPHOLE[buf], addresses]; ENDLOOP; }; ItemFromAddresses: PUBLIC PROC [addresses: LIST OF XNS.Address] RETURNS [item: Item] ~ { buf: PACKED ARRAY [0..adrHWords) OF HWORD; index: CARDINAL; cnt: CARD16 ¬ 0; FOR temp: LIST OF XNS.Address ¬ addresses, temp.rest WHILE temp # NIL DO cnt ¬ cnt + 1; ENDLOOP; item ¬ NEW[CHOps.ItemObject[1+cnt*adrHWords]]; item.body[0] ¬ cnt; index ¬ 1; FOR temp: LIST OF XNS.Address ¬ addresses, temp.rest WHILE temp # NIL DO buf ¬ LOOPHOLE[temp.first]; FOR i: CARDINAL IN [0..adrHWords) DO item.body[index] ¬ Basics.Card16FromH[buf[i]]; index ¬ index + 1; ENDLOOP; ENDLOOP; }; RopeFromItem: PUBLIC PROC [item: Item] RETURNS [rope: ROPE] ~ { [rope~rope] ¬ RopeFromItemInner[item,0] }; ElementFromItem: PUBLIC PROC [item: Item] RETURNS [element: Element] ~ { pos: CARD32; [rope~element.organization, newPos~pos] ¬ RopeFromItemInner[item, 0]; [rope~element.domain, newPos~pos] ¬ RopeFromItemInner[item, pos]; [rope~element.object] ¬ RopeFromItemInner[item, pos]; }; RopeFromItemInner: PROC [item: Item, pos: CARD32] RETURNS [rope: ROPE, newPos: CARD32] ~ { buf: Basics.Word16; text: REF TEXT; cnt: CARD32; IF item.length <= pos THEN RETURN [NIL, pos]; cnt ¬ item.body[pos]; IF (CARD[item.length-pos-1]*BYTES[HWORD]) < cnt THEN RETURN [NIL, pos]; -- ERROR text ¬ RefText.ObtainScratch[cnt]; newPos ¬ pos+1; DO IF cnt = 0 THEN EXIT; buf.card ¬ item.body[newPos]; newPos ¬ newPos+1; text ¬ RefText.AppendChar[to~text, from~LOOPHOLE[buf.hi]]; cnt ¬ cnt-1; IF cnt = 0 THEN EXIT; text ¬ RefText.AppendChar[to~text, from~LOOPHOLE[buf.lo]]; cnt ¬ cnt-1; ENDLOOP; rope ¬ Rope.FromRefText[text]; RefText.ReleaseScratch[text]; }; ItemFromRope: PUBLIC PROC [rope: ROPE] RETURNS [item: Item] ~ { itemLen: CARD32 ~ CrRPC.MarshalledRopeHWords[rope]; item ¬ NEW[CHOps.ItemObject[itemLen]]; ItemFromRopeInner[rope, item, 0]; }; ItemFromElement: PUBLIC PROC [element: Element] RETURNS [item: Item] ~ { orgLen: CARD32 ~ CrRPC.MarshalledRopeHWords[element.organization]; domLen: CARD32 ~ CrRPC.MarshalledRopeHWords[element.domain]; objLen: CARD32 ~ CrRPC.MarshalledRopeHWords[element.object]; itemLen: CARD32 ~ orgLen + domLen + objLen; item ¬ NEW[CHOps.ItemObject[itemLen]]; ItemFromRopeInner[element.organization, item, 0]; ItemFromRopeInner[element.domain, item, orgLen]; ItemFromRopeInner[element.object, item, orgLen + domLen] }; ItemFromRopeInner: PROC [rope: ROPE, item: Item, pos: CARD32] ~ { buf: Basics.Word16; ropeLen, iFrom: INT; IF CrRPC.MarshalledRopeHWords[rope] > (item.length - pos) THEN ERROR; item.body[pos] ¬ ropeLen ¬ Rope.Length[rope]; pos ¬ pos + 1; iFrom ¬ 0; DO IF iFrom >= ropeLen THEN EXIT; buf.hi ¬ ORD[Rope.Fetch[rope, iFrom]]; iFrom ¬ iFrom+1; buf.lo ¬ IF iFrom < ropeLen THEN ORD[Rope.Fetch[rope, iFrom]] ELSE 0; iFrom ¬ iFrom+1; item.body[pos] ¬ buf.card; pos ¬ pos + 1; ENDLOOP; }; DomainFromElement: PROC [element: Element] RETURNS [rope: ROPE] ~ INLINE { rope ¬ Rope.Cat[element.domain, ":", element.organization] }; DomainFromOrgElement: PROC [element: Element] RETURNS [rope: ROPE] ~ INLINE { rope ¬ Rope.Cat[element.organization, ":", shiftInName] }; BestAddressInList: PUBLIC PROC [list: LIST OF XNS.Address] RETURNS [bestAddress: XNS.Address] ~ { bestHops: CARDINAL ¬ LAST[CARDINAL]; WHILE list # NIL DO tempHops: CARDINAL ~ XNSRouter.GetHops[list.first.net]; IF tempHops < bestHops THEN { bestAddress ¬ list.first; bestHops ¬ tempHops }; list ¬ list.rest; ENDLOOP; }; GetElement: PUBLIC PROC [stream: IO.STREAM] RETURNS [element: Element] ~ { element.organization ¬ CrRPC.GetRope[stream]; element.domain ¬ CrRPC.GetRope[stream]; element.object ¬ CrRPC.GetRope[stream] }; GetOrganization: PUBLIC PROC [stream: IO.STREAM] RETURNS [element: Element] ~ { element.organization ¬ CrRPC.GetRope[stream]; element.domain ¬ NIL; element.object ¬ NIL }; GetDomain: PUBLIC PROC [stream: IO.STREAM] RETURNS [element: Element] ~ { element.organization ¬ CrRPC.GetRope[stream]; element.domain ¬ CrRPC.GetRope[stream]; element.object ¬ NIL }; PutElement: PUBLIC PROC [stream: IO.STREAM, element: Element] ~ { CrRPC.PutRope[stream, element.organization]; CrRPC.PutRope[stream, element.domain]; CrRPC.PutRope[stream, element.object] }; cachedXNSName: ROPE ¬ NIL; cachedXNSNameOK: BOOL ¬ FALSE; TMName: PROC RETURNS[rope: ROPE ¬ NIL] = { GuessXNSName: PROC [guess: ROPE] ~ { address: XNS.Address; distingName: XNSCHName.Name; IF Rope.IsEmpty[guess] THEN RETURN; guess ¬ XNSCHName.RopeFromName[XNSCHName.NameFromRope[guess]]; [distingName, address] ¬ LookupAddressFromRope[guess]; IF address.host = XNS.GetThisHost[] THEN { cachedXNSName ¬ XNSCHName.RopeFromName[distingName]; cachedXNSNameOK ¬ TRUE }; }; IF NOT cachedXNSNameOK THEN { item: XNSCH.Item; c: XNSCH.Conversation; tempIdentity: XNSAuth.Identity ¬ XNSCredentials.GetIdentity[]; IF tempIdentity = NIL THEN GOTO Out; c ¬ XNSCH.InitiateConversation[]; [item~item] ¬ LookupItemProperty[c~c, pattern~XNSAuth.GetIdentityDetails[tempIdentity].name, pID~CHEntries.associatedWorkstation ! Error => { XNSCH.TerminateConversation[c]; GOTO Out } ]; XNSCH.TerminateConversation[c]; GuessXNSName[XNSCHName.RopeFromName[ElementFromItem[item]]]; EXITS Out => NULL; }; IF NOT cachedXNSNameOK THEN { tempIdentity: XNSAuth.Identity ¬ XNSCredentials.GetIdentity[]; IF tempIdentity # NIL THEN GuessXNSName[Rope.Concat[XNSAuth.GetIdentityDetails[tempIdentity].name.object, "-ws"]]; }; IF NOT cachedXNSNameOK THEN { cachedXNSName ¬ NIL; cachedXNSNameOK ¬ TRUE; }; rope ¬ cachedXNSName; }; TMAddress: PROC RETURNS[rope: ROPE ¬ NIL] = { rope ¬ Convert.RopeFromXNSAddress[Convert.XNSAddressFromRope["ME"]]; }; InitProcs: PROC = { thisMachineProcs: ThisMachineRegistry.ThisMachineRef ¬ NEW[ThisMachineRegistry.ThisMachineProcsRec ¬ [ which: $xns, Name: TMName, Address: TMAddress, ProcessorID: NIL ]]; ThisMachineRegistry.RegisterThisMachineProcs[thisMachineProcs]; }; InitProcs[]; }.  XNSCHImpl.mesa Copyright Σ 1988, 1989, 1991 by Xerox Corporation. All rights reserved. Demers, January 27, 1988 11:28:23 am PST Willie-Sue, February 13, 1989 3:37:56 pm PST Willie-s, December 10, 1991 1:26 pm PST This is a monitor only because of the nCache stuff in "Common Lookups". Operations on Objects [h: Handle, s: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL]; [s: IO.STREAM] RETURNS [abort: BOOL _ FALSE] Operations on Properties [h: Handle, s: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL]; [s: IO.STREAM] RETURNS [abort: BOOL] [h: Handle, s: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL]; [s: IO.STREAM] RETURNS [abort: BOOL _ FALSE] Enumeration operations [h: Handle, s: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL]; [s: IO.STREAM] RETURNS [abort: BOOL _ FALSE] [h: Handle, s: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL]; [s: IO.STREAM] RETURNS [abort: BOOL _ FALSE] [h: Handle, s: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL]; [s: IO.STREAM] RETURNS [abort: BOOL _ FALSE] [h: Handle, s: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL]; [s: IO.STREAM] RETURNS [abort: BOOL _ FALSE] Operations on Property ACLs [h: Handle, s: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL]; [s: IO.STREAM] RETURNS [abort: BOOL _ FALSE] Operations on Domain ACLs [h: Handle, s: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL]; [s: IO.STREAM] RETURNS [abort: BOOL _ FALSE] Operations on Organization ACLs [h: Handle, s: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL]; [s: IO.STREAM] RETURNS [abort: BOOL _ FALSE] Common Lookups Server-Specific Queries [h: Handle, s: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL]; [s: IO.STREAM] RETURNS [abort: BOOL _ FALSE] Utilities (Un)marshalling These are strange because the Items have already been byte-swapped to internal representation, which can mess up objects like XNS.Addresses that are stored inside them. Domain Name Ropes e.g. ["Xerox", "PARC", "*"] -> "PARC:Xerox" e.g. ["Xerox", "foo", "bar"] -> "Xerox:CHServers" Address List Manipulation Bulk Data Stream / Marshalling Procs taken from ThisMachineImpl; registered with ThisMachineRegistry Someday the XNS world will have to get its act together and allow address-to-name mapping. For now, we try to construct an XNS name either as -WS or by getting the Pup name and using the default domain and organization. We try this at most once, since it takes awhile if there isn't a Pup name service on the network. Guess -WS ... Give up ... Booting.RegisterProcs[r~Rollback]; Rollback: Booting.RollbackProc ~ { cachedXNSNameOK _ FALSE; cachedXNSName _ NIL; }; Κ –(cedarcode) style•NewlineDelimiter ™code™Kšœ Οeœ=™HK™(K™,K™'K™—šΟk ˜ Kšœžœžœ ˜7KšœžœΉ˜ΝKšœžœ/˜BKšœ žœŠ˜™Kšœžœ1˜>Kšœžœ™˜€Kšžœžœžœ˜Kšœžœ-˜:Kšœžœ4žœ˜DKšœžœA˜ZKšžœžœ.˜7Kšœžœ ˜-KšžœžœΠ˜ΫKšžœžœ˜Kšœ žœ2˜AKšœ žœU˜gKšœœ žœ˜#Kšœ žœ ˜Kšœ˜K˜—šΟn œžœž˜KšžœXžœ žœ4˜¦Kšžœžœžœ˜%K™GK˜KšžœŸ œŸœ Ÿœ˜JK˜Kšžœžœžœ˜K˜Kšœžœžœ˜Kšœ žœžœ ˜Kšœ žœžœ ˜Kšœ žœžœ ˜$Kšœ žœžœ ˜$Kšœžœžœ˜Kšœžœžœ˜(K˜Kšœ žœžœ ˜'K˜Kšœ žœ˜'Kšœžœ˜3K˜Kšžœžœ žœ˜K˜Kšœ žœ˜+Kšœžœ˜0Kšœžœ˜2K˜Kšœ žœ˜ K˜eK˜Kš Ÿœžœžœžœžœ žœ˜Ghead™šŸœžœžœ"˜2šŸœ Οcœ˜*KšœI˜IK˜—Kšœ;˜;K˜K˜—šŸœžœžœ"˜5šŸœ  œ˜-KšœI˜IK˜—Kšœ>˜>K˜K˜—šŸœžœžœ%žœ˜WšŸœ  œ˜-K˜ZK˜—KšœA˜AK˜K˜—šŸœžœžœ&žœ˜ZšŸ œ  œ˜/K˜]K˜—Kšœ> œ˜IK˜K˜—šŸ œžœžœ žœ˜WšŸ œ  œ˜2K˜WK˜—KšœD˜DK˜K˜—šŸ œž œ0žœžœ˜}šŸœ˜#Kš œžœžœ&žœ žœ™TK˜šŸœ˜#Kš œžœžœžœ žœžœ™,Kšœ˜—Kšžœ@˜FKšœ˜—šŸ œ  œ˜2K˜nK˜—KšœFžœ˜MK˜K˜——™šŸ œžœžœ%žœ0˜všŸœ  œ˜4˜:K˜N—K˜—KšœH˜HK˜K˜—šŸœžœžœ0žœ˜jšŸœ  œ˜5K˜^K˜—KšœF˜FK˜K˜—šŸœžœžœ<žœ˜wšŸœ  œ˜6K˜eK˜—KšœG˜GK˜K˜—šŸœžœžœ<žœ˜zšŸœ  œ˜9K˜`K˜—KšœJ˜JK˜K˜—šŸœžœžœ6žœ$˜€šŸœ  œ˜9˜/K˜Q—K˜—KšœM˜MK˜K˜—šŸ œžœžœ%žœ.˜tšŸœ  œ˜4K˜ Kšœ žœžœžœ ˜˜/Kšœc˜c—K˜$šžœ ž˜Kšžœ'˜+Kšžœ žœ˜"—K˜—KšœH˜HK˜K˜—š Ÿœžœžœ6žœ#žœ˜ˆšŸœ  œ˜9K˜ ˜/K˜Q—K˜"K˜—KšœM˜MK˜K˜—šŸœžœžœ6žœ,˜ˆšŸœ  œ˜9K˜ ˜/K˜Q—K˜%K˜—KšœM˜MK˜K˜—KšŸ œžœžœ˜K˜š Ÿœžœžœ<žœžœ˜ŽšŸœ˜'Kš œžœžœ&žœ žœ™TK˜Kšœ žœžœ˜šŸ œžœ˜(šŸœ˜"Kš œžœžœžœ žœ™$Kšœžœžœ˜-—K˜YKšžœ žœžœ ˜$K˜—Kšœ&žœ˜1Kš žœžœ žœ'žœžœ˜IKšžœžœ˜—šŸœ  œ˜7K˜wK˜—KšœH˜HK˜K˜—šŸ œž œAžœ˜všŸ œ  œ˜0K˜aK˜—KšœA˜AK˜K˜—šŸœž œ0žœ˜cšŸ œ  œ˜.K˜WK˜—Kšœ?˜?K˜K˜—šŸ œž œAžœ˜yšŸœ  œ˜3K˜dK˜—KšœD˜DK˜—K˜šŸ œž œ0žœ˜fšŸ œ  œ˜1K˜ZK˜—KšœB˜BK˜K˜—šŸ œž œBžœžœ˜’šŸœ˜&Kš œžœžœ&žœ žœ™TK˜šŸœ˜&Kš œžœžœžœ žœžœ™,Kšœ ˜ —KšžœC˜IKšœ˜—šŸ œ  œ˜2K˜xK˜—KšœFžœ˜MK˜K˜—šŸœž œGžœžœ˜‹šŸ œ  œ˜/Kšœ\žœ<˜K˜—KšœC˜CK˜K˜—šŸœž œYžœžœ˜€šŸœ  œ˜6K˜’K˜—Kšžœžœ ˜,KšœJ˜JK˜——™šŸ œž œBžœ˜qšŸœ˜%Kš œžœžœ&žœ žœ™TK˜šŸœ˜%Kš œžœžœžœ žœžœ™,Kšœf˜f—KšžœB˜HKšœ˜—šŸ œ  œ˜0Kšœe˜eK˜—KšœDžœ˜KK˜K˜—šŸœž œ/žœ˜ešŸœ˜%Kš œžœžœ&žœ žœ™TK˜šŸœ˜%Kš œžœžœžœ žœžœ™,Kšœd˜d—KšžœB˜HKšœ˜—šŸœ  œ˜7Kšœ`˜`K˜—KšœKžœ˜RK˜K˜—šŸœž œ7žœ˜všŸœ˜%Kš œžœžœ&žœ žœ™TK˜šŸœ˜%Kš œžœžœžœ žœžœ™,Kšœ<žœ žœ˜P—KšžœB˜HKšœ˜—šŸœ  œ˜=Kšœs˜sK˜—Kšœ5žœžœ˜AK˜K˜—šŸœž œ1žœ˜jšŸœ˜%Kš œžœžœ&žœ žœ™TK˜šŸœ˜%Kš œžœžœžœ žœžœ™,KšœSžœ˜[—KšžœB˜HKšœ˜—šŸœ  œ˜7Kšœ“˜“K˜—KšœNžœ˜UK˜——™šŸœž œSžœžœ˜°šŸœ˜&Kš œžœžœ&žœ žœ™TK˜šŸœ˜&Kš œžœžœžœ žœžœ™,Kšœ ˜ —KšžœC˜IKšœ˜—šŸœ  œ˜?K˜„K˜—KšœSžœ˜ZK˜K˜—šŸœž œjžœžœ˜ΒšŸœ  œ˜CK˜žK˜—Kšžœžœ ˜,KšœW˜WK˜K˜—šŸœž œRžœ˜”šŸœ  œ˜=K˜vK˜—KšœN˜NK˜K˜—šŸœž œRžœ˜™šŸœ  œ˜BK˜{K˜—KšœS˜SK˜——™šŸœž œ>žœ˜}KšœR˜RšŸœ˜&Kš œžœžœ&žœ žœ™TK˜šŸœ˜&Kš œžœžœžœ žœžœ™,Kšœ ˜ —KšžœC˜IKšœ˜—šŸœ  œ˜=Kšœx ˜‘K˜—KšœPžœ˜WK˜K˜—šŸœž œUžœ žœ˜˜KšœR˜RšŸœ  œ˜AK˜qK˜—Kšžœžœ žœ˜:KšœT˜TK˜—K˜šŸœž œF˜gKšœR˜RšŸœ  œ˜;Kšœg˜gK˜—KšœN˜NK˜K˜—šŸœž œF˜lKšœR˜RšŸœ  œ˜@Kšœl˜lK˜—KšœS˜SK˜——™šŸœž œDžœ˜‰Kšœ?˜?šŸœ˜&Kš œžœžœ&žœ žœ™TK˜šŸœ˜&Kš œžœžœžœ žœžœ™,Kšœ ˜ —KšžœC˜IKšœ˜—šŸœ  œ˜CKšœ~˜~K˜—Kšœ_žœ˜fK˜K˜—šŸ œž œ[žœ žœ˜€Kšœ?˜?šŸ"œ  œ˜GK˜}K˜—Kšžœžœ žœ˜:Kšœc˜cK˜K˜—šŸœž œL˜sKšœ?˜?šŸœ  œ˜AKšœs˜sK˜—Kšœ]˜]K˜K˜—šŸœž œL˜xKšœ?˜?šŸ!œ  œ˜FKšœx˜xK˜—Kšœb˜bK˜——™š Ÿœžœžœ žœžœ˜FKšžœžœžœžœ žœ žœžœžœ˜pKšœ˜Kšœžœ˜/K˜ ˜šœžœžœ˜#K˜+Kšžœ˜ —šœžœžœ˜,K˜$Kšœ˜—šž˜šœ žœ˜K˜AKšžœžœžœ˜K˜—šœžœ žœ˜K˜0Kšœ8 <˜tKšžœ˜ —šžœ žœ˜Kšžœ žœ˜K˜ K˜YK˜Kšœ žœ˜Kšžœ˜K˜—Kšžœ˜ Kšžœ˜—šž˜Kšœ žœ˜—K˜—Kšžœ˜Kšœ˜K˜—š Ÿœžœžœžœžœžœ ˜aKšœ˜KšœNžœ˜UK˜K˜—šŸœžœžœžœžœžœžœ˜zKšœ˜KšœFžœ˜LK˜——™šŸœžœžœžœ žœžœžœ ˜^Kšœ˜šŸœ  œ˜9Kšœžœ˜ K˜'K˜Kšœ žœ˜šžœž˜K˜ Kšœ žœžœ˜5Kšžœ˜—K˜—Kšžœžœžœ)˜PKšœ1žœ˜6Kšœ˜K˜—šŸœžœžœžœ˜^šŸœ˜%Kš œžœžœ&žœ žœ™TK˜šŸœ˜%Kš œžœžœžœ žœžœ™,Kšœ˜—KšžœB˜HKšœ˜—šŸœ  œ˜=Kšœ]˜]K˜—Kšžœžœžœ)˜PKšœ5žœ˜:Kšœ˜——™ ™K™¨K˜Kš œ žœžœžœ žœžœ˜4K˜š Ÿœž œžœ žœžœžœ ˜XKšœž œžœžœ˜*Kšœžœ˜ Kšœžœ˜Kšžœžœžœžœ˜$K˜Kšžœžœžœžœ˜2šžœ ž˜šžœžœžœž˜$K˜.K˜Kšžœ˜—Kšœ žœžœ˜+Kšžœ˜—K˜K˜—š Ÿœž œ žœžœžœ žœ˜XKš œžœžœžœžœ˜*Kšœžœ˜Kšœžœ˜š žœžœžœžœ žœžœž˜HK˜Kšžœ˜—Kšœžœ$˜.K˜K˜ š žœžœžœžœ žœžœž˜HKšœžœ ˜šžœžœžœž˜$K˜.K˜Kšžœ˜—Kšžœ˜—K˜K˜—šŸ œž œžœžœ˜?K˜*K˜—šŸœž œžœ˜HKšœžœ˜ K˜EK˜AK˜8K˜—š Ÿœžœžœžœžœ žœ˜ZK˜Kšœžœžœ˜Kšœžœ˜ Kšžœžœžœžœ˜-K˜Kšžœžœžœžœ žœžœžœ ˜QK˜"K˜šž˜Kšžœ žœžœ˜K˜0Kšœ(žœ ˜:K˜ Kšžœ žœžœ˜Kšœ(žœ ˜:K˜ Kšžœ˜—K˜K˜Kšœ˜K˜—šŸ œž œžœžœ˜?Kšœ žœ$˜3Kšœžœ˜&K˜!K˜K˜—šŸœž œžœ˜HKšœžœ4˜BKšœžœ.˜K˜6šžœžœžœ˜*K˜4Kšœžœ˜—K˜K˜—šžœžœžœ˜Kšœžœ˜Kšœžœ˜K˜>Kšžœžœžœžœ˜$Kšœžœ˜!˜€Kšœ žœžœ ˜:—Kšžœ˜Kšœ<˜<šž˜Kšœžœ˜ —K˜—šžœžœžœ˜™K˜>šžœžœžœ˜KšœW˜W——K˜—šžœžœžœ˜™ Kšœžœ˜Kšœžœ˜—Kšœ˜—K˜K˜K˜—š Ÿ œžœžœžœžœ˜-K˜DK˜K˜—šŸ œžœ˜˜6šžœ,˜/Kšœ ˜ KšΟbœ ˜ KšŸœ ˜KšŸ œž˜K˜K˜—Kšœ?˜?Kšœ"™"—K˜K˜—šŸœ™"Kšœžœ™Kšœžœ™K™K™—K˜ K™K˜K˜—K˜—K˜—…—t‚š΄