DIRECTORY
BasicTime USING [ Update, Now ],
CardTable USING [ Create, Delete, EachPairAction, Fetch, Pairs, Ref, Store ],
DESFace USING [ GetRandomKey, Key ],
Lark USING [ KeyTable, KeyTableBody, VoiceSocket ],
MBQueue USING [ Create, QueueClientAction ],
Process USING [ Detach, SecondsToTicks, SetTimeout ],
PupTypes USING [ PupSocketID ],
RefID USING [ ID, Reseal, Unseal ],
RPC USING [ CallFailed ],
ThNet USING [ pd ],
ThParty,
ThPartyPrivate USING [
ConversationBody, ConversationData, ConvState, ConvStateBody, DoDescribeParty, PartyBody, PartyData, SmartsBody, SmartsData ],
ThPartyMonitorImpl,
Thrush USING [
AlertKind, CallUrgency, ConversationID, ConvEvent, ConvEventBody, Credentials, EncryptionKey, epoch, Machine, NB, nullConvID, nullID, nullKey, PartyID, Reason, ROPE, SHHH, SmartsID, StateID, StateInConv, unencrypted ],
ThSmartsRpcControl USING [ InterfaceRecord ],
Triples USING [ Any, Erase, Foreach, ForeachProc, Make, Select ],
TU USING [ MakeUnique ],
VoiceUtils USING [ Problem ]
;

ThPartyOpsImpl: CEDAR MONITOR LOCKS root
IMPORTS
BasicTime,
CardTable,
DESFace,
MBQueue,
Process,
RefID,
root: ThPartyMonitorImpl,
RPC,
ThNet,
ThParty,
ThPartyPrivate,
Thrush,
Triples,
TU,
VoiceUtils
EXPORTS ThParty, ThPartyPrivate
SHARES ThPartyMonitorImpl = {

ConvEvent: TYPE = Thrush.ConvEvent;
ConvState: TYPE = ThPartyPrivate.ConvState;
ConversationData: TYPE = ThPartyPrivate.ConversationData;
ConversationID: TYPE = Thrush.ConversationID;
Credentials: TYPE = Thrush.Credentials;
Reseal: PROC[r: REF] RETURNS[RefID.ID] = INLINE {RETURN[RefID.Reseal[r]]; };
NB: TYPE = Thrush.NB;
nullConvID: Thrush.ConversationID = Thrush.nullConvID;
PartyBody: TYPE = ThPartyPrivate.PartyBody;	-- Concrete
PartyData: TYPE = ThPartyPrivate.PartyData;	-- REF Concrete
PartyID: TYPE = Thrush.PartyID;	-- ID
nullID: Thrush.PartyID = Thrush.nullID;
Reason: TYPE = Thrush.Reason;
ROPE: TYPE = Thrush.ROPE;
SHHH: TYPE = Thrush.SHHH;
none: SHHH = Thrush.unencrypted;
SmartsBody: TYPE = ThPartyPrivate.SmartsBody;	-- Concrete
SmartsData: TYPE = ThPartyPrivate.SmartsData;	-- REF Concrete
SmartsID: TYPE = Thrush.SmartsID;	-- ID


nextConv: ConversationID _ Thrush.epoch;


CreateConversation: PUBLIC ENTRY PROC[
shhh: SHHH,
credentials: Credentials,
state: Thrush.StateInConv,
urgency: Thrush.CallUrgency,
alertKind: Thrush.AlertKind,
subject: ROPE
] RETURNS [ nb: NB, convEvent: ConvEvent ] = {
ENABLE UNWIND => NULL;
conv: ConversationData = NEW[ThPartyPrivate.ConversationBody _ [
timeOfID: BasicTime.Now[],
startTime: BasicTime.Now[],
subject: subject,
urgency: urgency,
alertKind: alertKind,
conferenceHost: ConferenceHost[],
keyTable: NEW[Lark.KeyTableBody[20B]]
] ];
TRUSTED { []_EnterKey[conv, DESFace.GetRandomKey[]]; };
conv.convID _ EnhandleConv[conv];
credentials.stateID _ 0;
credentials.state _ $neverWas;
credentials.convID _ conv.convID;
[nb, convEvent] _ DoAdvance[credentials: credentials, state: state, newInConv: TRUE];
IF nb # $success THEN DeleteConversation[ conv ];
};

Alert: PUBLIC ENTRY PROC[
shhh: SHHH,
credentials: Credentials,
calledPartyID: PartyID,
comment: ROPE
] RETURNS [ nb: NB ] = {
ENABLE UNWIND => NULL;
convState: ConvState;
conv: ConversationData;
callingParty: PartyData;
calledParty: PartyData;
IF calledPartyID=credentials.partyID THEN RETURN[nb: $narcissism];
[, callingParty,, nb] _ Verify[credentials];
IF nb # $success THEN RETURN;
credentials.partyID _ calledPartyID;
[conv, calledParty, convState, nb] _ Verify[credentials];
SELECT nb FROM
$notInConv => NULL;
$success => IF conv#NIL THEN RETURN[$convStillActive]; -- already in the conversation!
$noSuchParty => RETURN[$noSuchParty2];
ENDCASE=> RETURN;
credentials.stateID _ 0;
IF calledParty=NIL OR
(calledParty.type = $trunk AND calledParty.reservedBy # Reseal[callingParty]) THEN
RETURN[nb: $noSuchParty2];
nb _ DoAdvance[credentials: credentials, state: $notified, newInConv: TRUE].nb;
};

Advance: PUBLIC ENTRY PROC[
shhh: SHHH,
credentials: Credentials,
state: Thrush.StateInConv,
reportToAll: BOOL,
reason: Thrush.Reason,
comment: ROPE
] RETURNS [nb: NB, convEvent: ConvEvent] = {
ENABLE UNWIND => NULL;
[nb, convEvent] _ DoAdvance[
credentials: credentials,
state: state,
reportToAll: reportToAll,
reason: reason,
comment: comment,
newInConv: FALSE
];
};

DoAdvance: PUBLIC INTERNAL PROC [
credentials: Credentials,
state: Thrush.StateInConv,
reportToAll: BOOL_FALSE,
reason: Thrush.Reason_NIL,
comment: ROPE_NIL,
newInConv: BOOL -- if TRUE, party must not be in the conversation yet . . . and vice versa
] RETURNS [nb: NB_$success, convEvent: ConvEvent_NIL] = {
convState: ConvState;
conv: ConversationData;
party: PartyData;
[conv, party, convState, nb] _ Verify[credentials, newInConv];
SELECT nb FROM
$success => {
IF convState=NIL THEN RETURN;
IF state = $active AND party.partyActive THEN RETURN[nb: $partyAlreadyActive];
IF conv.numIdle = conv.numParties AND state # $idle THEN RETURN[nb: $convIdle];
credentials.state _ state;
};
$stateMismatch => credentials.state _ convState.state;
ENDCASE => RETURN;
convEvent _ PostConvEvent[
credentials: credentials, convState: convState,
reason: reason, comment: comment, reportToAll: reportToAll];
};

GetConversationInfo: PUBLIC ENTRY PROC [ shh: SHHH_none, convID: ConversationID ]
RETURNS [
nb: NB_$success,
cInfo: ThParty.ConversationInfo_[]
] = {
conv: ConversationData = UnsealConv[convID];
IF conv=NIL THEN RETURN[nb: $noSuchConv];
cInfo.subject _ conv.subject;
cInfo.urgency _ conv.urgency;
cInfo.alertKind _ conv.alertKind;
cInfo.startTime _ conv.startTime;
cInfo.conferenceHost _ conv.conferenceHost;
cInfo.numParties _ conv.numParties;
cInfo.numActive _ conv.numActive;
cInfo.numIdle _ conv.numIdle;
cInfo.originator _ Reseal[Triples.Select[$Originator, conv, -- originator --]];
};

GetPartyInfo: PUBLIC ENTRY PROC [
shh: SHHH_none, credentials: Credentials, nameReq: ThParty.NameReq, allParties: BOOL ]
RETURNS [
nb: NB,
pInfo: ThParty.PartyInfo_NIL
] = {
conv: ConversationData = UnsealConv[credentials.convID];
convState: ConvState;
ownParty: PartyData = UnsealParty[credentials.partyID];
GetParties: INTERNAL FinishProcType = {
index: NAT;
HowToReport _ NIL;
IF smarts.properties.role # $voiceTerminal THEN RETURN;
IF party=ownParty THEN {
index _ 0;
pInfo.numParties_MAX[1, pInfo.numParties];
}
ELSE {
index _ MAX[1, pInfo.numParties];
pInfo.numParties _ index+1;
}; 
pInfo[index] _ [
partyID: Reseal[party],
type: party.type,
state: convState.state,
name: IF nameReq=$none THEN NIL
ELSE ThPartyPrivate.DoDescribeParty[party, nameReq],
numConvs: party.numConvs,
enabled: party.enabled,
partyActive: party.partyActive,
socket:
[smarts.properties.machine.net, smarts.properties.machine.host, convState.sockID]];
};
nb _IF conv=NIL THEN $noSuchConv
ELSE IF ownParty=NIL THEN $noSuchParty ELSE $success;
IF nb=$success THEN {
convState _ GetConvState[conv, ownParty];
IF convState=NIL THEN nb _ $notInConv
};
IF nb#$success THEN RETURN;
pInfo _ NEW[ThParty.PartyInfoSeq[IF allParties THEN conv.numParties ELSE 1]];
pInfo.conferenceHost _ conv.conferenceHost;
pInfo[0] _ [];
Report[
FinishProc: GetParties, reportToAll: allParties, 
conv: conv, party: ownParty, whatToReport: NIL];
};

GetKeyTable: PUBLIC ENTRY PROC [ shh: SHHH_none, credentials: Credentials ]
RETURNS [ nb: NB, keyTable: Lark.KeyTable_NIL ] =  {
conv: ConversationData;
[conv,,,nb] _ Verify[credentials];
IF nb # $success THEN RETURN;
keyTable _ conv.keyTable;
};

RegisterKey: PUBLIC ENTRY PROC [
shh: SHHH _ none,
credentials: Credentials,
key: Thrush.EncryptionKey ]
 RETURNS [ nb: NB, keyIndex: [0..17B] _ 0 ] = {
ENABLE UNWIND => NULL;
conv: ConversationData;
[conv, , , nb] _ Verify[credentials];
IF nb=$success OR nb=$stateMismatch THEN keyIndex _ EnterKey[conv, key].keyIndex;
};


VerifyEnt: PUBLIC ENTRY PROC[ credentials: Credentials 
] RETURNS [
conv: ConversationData,
party: PartyData,
convState: ConvState,
nb: Thrush.NB ] = {
[conv, party, convState, nb] _ Verify[credentials];
};

Verify: PUBLIC INTERNAL PROC[ credentials: Credentials, newInConv: BOOL_FALSE 
] RETURNS [
conv: ConversationData_NIL,
party: PartyData_NIL,
convState: ConvState_NIL,
nb: Thrush.NB ] = {
smarts: SmartsData _ UnsealSmarts[credentials.smartsID];
conv_UnsealConv[credentials.convID];
party_UnsealParty[credentials.partyID];
nb _ SELECT NIL[REF ANY] FROM
smarts => $noSuchSmarts,
party => $noSuchParty,
conv => IF credentials.convID#nullConvID THEN $noSuchConv ELSE $success,
ENDCASE=> $success;
IF nb=$success AND ~party.enabled THEN nb _ $noSuchParty;
IF nb#$success OR conv=NIL THEN RETURN;
convState _ GetConvState[conv, party, newInConv];
IF convState=NIL THEN { nb _ $notInConv; RETURN; };
SELECT credentials.stateID FROM
< convState.stateID => nb_$stateMismatch;
> convState.stateID => nb_$interfaceError; -- really bogus behaviour!
ENDCASE;
};

GetConvState: INTERNAL PROC[ conv: ConversationData, party: PartyData, createOK: BOOL_FALSE]
RETURNS [convState: ConvState_NIL] = {
GCS: Triples.ForeachProc = {
WITH trip.att SELECT FROM cS: ConvState => { convState_cS; RETURN[FALSE]; }; ENDCASE;
};
Triples.Foreach[Triples.Any, conv, party, GCS];
IF convState#NIL OR ~createOK THEN RETURN;
convState _ NEW[ThPartyPrivate.ConvStateBody _ [sockID: NewId[]]];
Triples.Make[convState, conv, party];
Triples.Make[$Party, conv, party];
IF conv.numParties=0 THEN TU.MakeUnique[$Originator, conv, party];
party.numConvs _ party.numConvs+1;
conv.numParties _ conv.numParties+1;
};

PostConvEvent: INTERNAL PROC[
credentials: Credentials,
convState: ConvState,
reason: Thrush.Reason_NIL,
comment: Thrush.ROPE_NIL,
reportToAll: BOOL
] RETURNS [convEvent: ConvEvent ] = {
conv: ConversationData _ UnsealConv[credentials.convID];
party: PartyData _ UnsealParty[credentials.partyID];
SELECT convState.state FROM -- states that was, but will no longer be
$idle => { conv.numIdle _ conv.numIdle-1; party.numConvs _ party.numConvs+1; };
$active => { conv.numActive _ conv.numActive -1; party.partyActive _ FALSE; };
ENDCASE;
SELECT credentials.state FROM -- states that will be
$idle => { conv.numIdle _ conv.numIdle+1; party.numConvs _ party.numConvs-1; };
$active => { conv.numActive _ conv.numActive+1; party.partyActive _ TRUE; };
ENDCASE;
convState.stateID _ credentials.stateID _ convState.stateID+1;
convState.state _ credentials.state;
conv.timeOfID _ convState.time _ BasicTime.Now[];
convEvent _ NEW[ Thrush.ConvEventBody _ [
self: [ ],
other: credentials,
time: convState.time,
reason: reason,
comment: comment
] ];
Report[FinishEvent, reportToAll, conv, party, convEvent ]; -- will queue up either a report or an idle check for each recipient.
};

PackagedReport: TYPE = REF ReportBody;
ReportBody: TYPE = RECORD [
smarts: SmartsData,
whatToReport: REF
];
FinishProcType: TYPE =
PROC[party: PartyData, smarts: SmartsData, convState: ConvState,  whatToReport: REF]
RETURNS [HowToReport: PROC[r: REF]_NIL, whatToReallyReport: REF_NIL];

Report: INTERNAL PROC[
FinishProc: FinishProcType, -- provides Report proc as one of its return values
reportToAll: BOOL,
conv: ConversationData,
party: PartyData,
whatToReport: REF
] = {
ReportToOne: INTERNAL Triples.ForeachProc = {
party: PartyData = NARROW[trip.val];
ReportToParty[party, party];
};
ReportToParty: INTERNAL PROC[party: PartyData, participant: PartyData] = {
pSmarts: SmartsData;
packagedReport: PackagedReport;
realReport: REF _ whatToReport;
HowToReport: PROC[r: REF]_NIL;
IF party=NIL OR ~party.enabled THEN RETURN;
pSmarts _ NARROW[Triples.Select[$Smarts, party, --pSmarts--]];
IF pSmarts#NIL AND FinishProc#NIL THEN [HowToReport, realReport] _
FinishProc[participant, pSmarts, GetConvState[conv, participant], whatToReport];
IF HowToReport#NIL THEN {
packagedReport _ NEW[ReportBody _ [smarts: pSmarts, whatToReport: realReport] ];
IF pSmarts.notifications=NIL THEN pSmarts.notifications _ MBQueue.Create[];
conv.numReportsOut _ conv.numReportsOut + 1;
pSmarts.notifications.QueueClientAction[HowToReport, packagedReport];
};
party _ NARROW[Triples.Select[$Poaching, party, -- poachee --]];
IF party#NIL THEN ReportToParty[party, participant];
};
IF ~reportToAll THEN ReportToParty[party, party]
ELSE Triples.Foreach[$Party, conv, Triples.Any --party--, ReportToOne];
};

FinishEvent: INTERNAL FinishProcType = {
convEvent: ConvEvent = NARROW[whatToReport];
reportEvent: ConvEvent = IF (convEvent.other.smartsID = Reseal[smarts]) THEN convEvent
ELSE NEW[Thrush.ConvEventBody _ convEvent^];
reportEvent.self _ [
Reseal[party], Reseal[smarts], reportEvent.other.convID, convState.state, convState.stateID];
IF convEvent = reportEvent THEN 
RETURN[ReportCheckIdle, UnsealConv[convEvent.self.convID]] -- no report to initiator
ELSE RETURN[ReportProgress, reportEvent];
};

ReportProgress: PROC[r: REF] = {
report: PackagedReport = NARROW[r];
convEvent: ConvEvent = NARROW[report.whatToReport];
{
ENABLE RPC.CallFailed => {
IF ~report.smarts.failed THEN {
VoiceUtils.Problem["Communications to smarts failed", $System];
[]_ThParty.Deregister[smartsID: Reseal[report.smarts]];
};
report.smarts.failed_TRUE;
CONTINUE;
};
IF report.smarts.failed THEN RETURN;
report.smarts.interface.clientStubProgress[
interface: report.smarts.interface, shh: report.smarts.shh, convEvent: convEvent];
CheckIdle[UnsealConvE[convEvent.self.convID]];
};
};

ReportCheckIdle: PROC[r: REF] = {
report: PackagedReport = NARROW[r];
CheckIdle[NARROW[report.whatToReport]];
};

CheckIdle: ENTRY PROC[conv: ConversationData] = {
conv.numReportsOut _ conv.numReportsOut - 1;
IF conv.numIdle = conv.numParties AND conv.numReportsOut<=0 THEN TRUSTED {
Process.Detach[FORK IdleAfterAWhile[conv]]; };
};

IdleAfterAWhile: ENTRY PROC[conv: ConversationData] = TRUSTED {
idler: CONDITION;
Process.SetTimeout[@idler, Process.SecondsToTicks[ThNet.pd.postIdleTimeout]];
WAIT idler;
DeleteConversation[conv];
};

DeleteConversation: INTERNAL PROC[ conv: ConversationData ] = {
Triples.Erase[Triples.Any, conv, Triples.Any];
[]_convTable.Delete[LOOPHOLE[conv.convID]]; -- KillConv[conv.convID];
};

NewId: PROC RETURNS [ PupTypes.PupSocketID ] = TRUSTED {
idKey: DESFace.Key _ DESFace.GetRandomKey[]; -- connection specs.
keys: LONG POINTER TO ARRAY[0..2) OF PupTypes.PupSocketID _
LOOPHOLE[LONG[@idKey]];
RETURN[keys[0]];
};


convTable: CardTable.Ref = CardTable.Create[];

UnsealConv: PUBLIC INTERNAL PROC[ convID: ConversationID]
RETURNS [conv: ConversationData_NIL ] = {
RETURN[NARROW[convTable.Fetch[LOOPHOLE[convID]].val]]; };

EnhandleConv: INTERNAL PROC[ conv: ConversationData ]
RETURNS [ convID: ConversationID_nextConv ] = {
nextConv _ BasicTime.Update[nextConv, 1];
IF ~convTable.Store[LOOPHOLE[convID], conv] THEN ERROR;
};

ConferenceHost: INTERNAL PROC RETURNS [conferenceHost: Thrush.Machine] = {
inUse: PACKED ARRAY [0..100B) OF BOOL _ ALL[FALSE];
MarkInUse: CardTable.EachPairAction = {
conv: ConversationData = NARROW[val];
inUse[conv.conferenceHost.host] _ TRUE;
RETURN[FALSE];
};
[]_convTable.Pairs[MarkInUse];
FOR hIndex: [0..100B) IN [2..100B) DO
IF ~inUse[hIndex] THEN RETURN [[[173B], [hIndex]]];
ENDLOOP;
VoiceUtils.Problem["Out of conference hosts!", $System];
RETURN[[[173B],[1]]];
};

UnsealConvE: ENTRY PROC[convID: ConversationID]
RETURNS [conv: ConversationData_NIL ] = { RETURN[UnsealConv[convID]]; };

UnsealParty: PUBLIC PROC[partyID: Thrush.PartyID] RETURNS[party: PartyData] = {
RETURN[NARROW[RefID.Unseal[partyID]]]; };

UnsealSmarts: PUBLIC PROC[smartsID: Thrush.SmartsID] RETURNS[smarts: SmartsData] = {
RETURN[NARROW[RefID.Unseal[smartsID]]]; };

EKResults: TYPE = { new, duplicate, disagreement, full };

EnterKey: INTERNAL PROC[conv: ConversationData,
key: Thrush.EncryptionKey]
RETURNS [ keyIndex: [0..17B], results: EKResults] = {
IF key=Thrush.nullKey THEN RETURN[0, $duplicate];
FOR keyIndex IN [1..17B] DO
IF conv.keyTable[keyIndex]=key THEN RETURN[keyIndex, $duplicate]
ELSE IF conv.keyTable[keyIndex][0].b=0 AND conv.keyTable[keyIndex] = Thrush.nullKey THEN EXIT;
REPEAT FINISHED => RETURN[0, full]; ENDLOOP;
conv.keyTable[keyIndex] _ key;
RETURN[keyIndex, new];
};

}.
��.��ThPartyOpsImpl.mesa
Copyright c 1985 by Xerox Corporation.  All rights reserved.
Last modified by D. Swinehart, December 8, 1985 3:19:20 pm PST
Copies	
Conversation ID stuff
Implementation of ThParty
This conv's key, will be key index 1.
credentials.smartsID remains the originator's  this produces a strange value for convEvent.situation.other.smartsID; at present, no one uses that  if they do, they'll have to understand.
cInfo.lastTime _ conv.timeOfID;
Computes the socket values (and corresponding party/smarts ident) for each voice terminal participant in a conversation, when invoked by Report.
stateID: convState.stateID,
lastTime: convState.time,
Don't care about stateMismatch here.
Utilities
Validate parameters: existence, in conversation, state match; produce dehandled values.
Validation for smarts is only partial; verifies that it's a smarts.
Not interested in any conversation, or it doesn't exist
IF newInConv is TRUE and convState already existed, it's a logical error, but we're not checking it.
Prev. line is for protection: you're not supposed to leave idle state, or enter it twice, but this will keep the counts correct if it happens.  party.numConvs becomes 0 once a party goes idle.
Report Progress
Generic reporting routine, synchronous with ThPartyOps procedure, and protected by its monitor.   Depending on reportToAll, queues up the report to be distributed to the smarts' for all parties in the conversation (TRUE), or just to the requesting party (FALSE).  Reports are made to the indicated parties and their poachees.  $visiting will be dealt with later.  Having identified a party and smarts to which to report, calls FinishProc to complete the report (to indicate in the report the addressee of the report, for instance); FinishProc may veto the report by returning FALSE.

[trip: Triples.TripleRec] RETURNS [continue: BOOLEAN _ TRUE]
party is the one we're reporting to; it might be a poachee of the participant.  participant is the party that's actually a member of the conversation.
Called as report is being prepared to fill in addressee information
Two cases:
1) reporting to originating smarts: don't copy convEvent, and use report only to do CheckIdle asynchronously with the originating operation.
2) reporting to some other smarts: copy convEvent before filling in self field, request a ReportProgress.
Called to issue state-change progress report
Specific reporting routine, dispatched from a smarts notification queue, for reporting party state changes.
If all parties are idle in conversation, conversation can go away.
If all parties are idle in conversation, conversation can go away.
If all parties are idle in conversation, conversation can go away.
Conversation ID management
At present, called only from Verify
Called only from CreateConv.
Must be called before new conversation's ID is entered in table.  Returns an available
multicast host number.
KillConv: INTERNAL PROC[ convID: ConversationID ] = INLINE {
[]_convTable.Delete[LOOPHOLE[convID]]; };

Key Table management

Presently returns full if table is full; user should hang up and restart.
Move-to-front would work nicely here!!

Temporarily out of service at this time


Swinehart, May 15, 1985 10:46:39 am PDT
changes to: SetProse, DescribeInterval, PostConvEvent

Swinehart, May 16, 1985 10:09:48 am PDT
Switch to RedBlackTree for conversation handle stuff
changes to: DIRECTORY, ThPartyOpsImpl, nextConv, convTable, cID, ConvTableEntry, ConvTableRecord, UnsealConv, EnhandleConv, KillHandleConv, ConvCompare, ConvGet, EnterKey
Swinehart, October 25, 1985 6:24:50 pm PDT
Handle => ID, eliminate conversation class stuff!
changes to: DIRECTORY, ConversationID, Reseal, nullConvID, nullID, PartyID, SmartsID, nextConv, Alert, DoAdvance, OtherParty, FindOtherParty, CreateConversation, CreateConv, DestroyConversation, MergeConversations, RegisterKey, SetSubject, GetSubject, ConversationsForParty, PostConvEvent, GetOneActive, ConvTableRecord, cTE, UnsealConv, EnhandleConv, KillIDConv, UnsealParty, UnsealSmarts, convTable, ThPartyOpsImpl, Activate, GetEvent


Swinehart, November 4, 1985 9:59:14 pm PST
Tracking changes to Thrush types, Get/Create code
changes to: Alert, DoAdvance, r, r, OtherParty, CreateConv, SetIntervals, SetProse, DescribeInterval, RegisterKey, Verify, PostConvEvent, GetOneActive, Activate, AllIdle, EKResults, EnterKey, Validity, Advance

Swinehart, November 7, 1985 4:22:59 pm PST
Major change to basic switching methods, simplifying ThParty's role in managing them.
changes to: DIRECTORY, Alert, CreateConv, SetSubject, GetSubject, ConversationsForParty, Verify, PostConvEvent, GetOneActive, UnsealConv, UnsealParty, UnsealSmarts, ConvEvent, NB, nullConvID, PartyBody, Reason, SmartsBody, SmartsData, SmartsID, CreateConversation, Advance, DoAdvance, FindOtherParty, MergeConversations, NewId, DestroyConversation, EnterKey, VerifyEnt, GCS, PostConvEvent, RegisterKey, DeleteConversation

Swinehart, November 8, 1985 8:44:36 am PST
More of above, merge the supervisor stuff, eliminating ThPartySupervisorImpl.
changes to: PostConvEvent, PackagedReport, ReportBody, Report, ReportToOne, ReportToParty, Progress

Êá��˜�šœ™Icodešœ
Ïmœ1™<Jšœ>™>—J˜�šÏk	˜	Jšœ
žœ˜ Jšœ
žœ>˜MJšœžœ˜$Jšœžœ)˜3Jšœžœ˜,Jšœžœ(˜5Jšœ	žœ˜Jšœžœžœ˜#Jšžœžœ˜Jšœžœ˜J˜šœžœ˜Jšœ~˜~—J˜šœžœ˜Jšœ žœžœ0˜Ú—Jšœžœ˜-Jšœžœ4˜AJšžœžœ˜Jšœžœ˜J˜J˜�—šœžœžœžœ˜(šž˜Jšœ
˜
J˜
J˜J˜J˜J˜J˜Jšžœ˜J˜J˜J˜J˜J˜Jšžœ˜J˜
—Jšžœ˜Jšžœ˜J˜�—šœ™Jšœžœ˜#Jšœžœ˜+Jšœžœ#˜9Jšœžœ˜-Jšœ
žœ˜'JšÏnœžœžœžœžœžœžœ˜LJšžœžœ
žœ˜J˜6JšœžœÏc˜7Jšœžœ ˜;šœ	žœ ˜%J˜'—Jšœžœ˜Jšžœžœ
žœ˜šžœžœ
žœ˜Jšœžœ˜ —Jšœžœ ˜9Jšœžœ ˜=Jšœ
žœ ˜'J˜�—™J˜�J˜(J˜�—šœ™J˜�šŸœžœžœžœ˜&Jšœžœ˜J˜J˜Jšœ˜Jšœ˜Jšœ	ž˜
Jšœžœ%˜.Jšžœžœžœ˜šœžœ$˜@J˜J˜J˜Jšœ˜Jšœ˜J˜!Jšœ
žœ˜%Jšœ˜—šžœ0˜7Jšœ%™%—Jšœ!˜!J˜J˜J˜!JšœOžœ˜UJšžœžœ˜1Jšœ˜J˜�—šŸœžœž
œ˜Jšœžœ˜J˜J˜Jšœ	ž˜
Jšœžœžœ˜Jšžœžœžœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšžœ#žœžœ˜BJšœ,˜,Jšžœžœžœ˜J˜$Jšœ9˜9šžœž˜Jšœžœ˜Jš
œžœžœžœžœ ˜VJšœžœ˜&Jšžœžœ˜—Jšœ¼™¼J˜šžœ
žœž˜Jšœžœ0ž˜RJšžœ˜—JšœFžœ˜OJ˜—J˜�šŸœžœžœžœ˜Jšœžœ˜J˜J˜Jšœ
žœ˜J˜Jšœ	ž˜
Jšœžœžœ˜,Jšžœžœžœ˜šœ˜Jšœ˜Jšœ
˜
Jšœ˜Jšœ˜Jšœ˜Jšœž˜Jšœ˜—Jšœ˜—J˜�šŸ	œžœžœžœ˜!J˜J˜Jšœ
žœžœ˜Jšœžœ˜Jšœ	žœž˜Jšœžœ J˜ZJšœžœžœ žœ˜9Jšœ˜J˜J˜Jšœ>˜>šžœž˜˜
Jšžœžœžœžœ˜Jšžœžœžœžœ˜NJšžœ žœžœžœ˜OJ˜J˜—J˜6Jšžœžœ˜—šœ˜šœ/˜/Jšœ<˜<——Jšœ˜J˜�—šŸœžœžœ˜Qšžœ˜	Jšœžœ
˜Jšœ"˜"J˜—J˜,Jšžœžœžœžœ˜)J˜J˜J˜!J˜!J™J˜+Jšœ#˜#Jšœ!˜!Jšœ˜Jšœ< œ˜OJ˜J˜�—šŸœžœ˜!JšœžœGžœ˜Všžœ˜	Jšœžœ˜Jšœž˜J˜—J˜8J˜J˜7šÏb
œžœ˜'J™Jšœžœ˜Jšœžœ˜Jšžœ)žœžœ˜7šžœžœ˜Jšœ
˜
Jšœžœ˜*Jšœ˜—šžœ˜Jšœžœ˜!Jšœ˜Jšœ˜—šœ˜J˜J˜J˜J™J™šœžœžœž˜Jšžœ0˜4—J˜J˜J˜˜J˜S——J˜—šœžœžœžœ˜ Jš
žœžœ
žœžœžœ
˜5—šžœ
žœ˜J˜)Jšžœžœžœ˜%J˜—Jšžœ
žœžœ˜Jš	œžœžœžœžœ˜MJ˜+J˜˜Jšœ1˜1Jšœ+žœ˜0—J˜J˜�—š
Ÿœžœžœžœžœ!˜KJšžœžœžœ˜4J˜J˜"Jšžœžœžœ˜J˜J˜J˜�—šŸœžœ˜ Jšœžœ˜Jšœ˜J˜Jšœžœžœ˜/Jšžœžœžœ˜J˜Jšœ%˜%J™$Jšžœ
žœžœ)˜QJšœ˜—J˜�—™	J˜�šŸ	œžœžœ˜7šœžœ˜J˜J˜J˜Jšœžœ˜—J˜3J˜J˜�—šŸœžœžœžœ'žœžœ˜Nšœžœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜—J™WJ™CJšœ8˜8Jšœ$˜$Jšœ'˜'šœžœžœž˜J˜J˜Jšœžœžœ
žœ
˜HJšžœ˜—Jšžœ
žœžœ˜9š
žœ
žœžœžœžœ˜'Jšœ7™7—Jšœ1˜1šžœžœžœžœ˜3J™f—šžœž˜Jšœ)˜)Jšœ+ ˜EJšžœ˜—J˜J˜�—š
Ÿœžœžœ6žœžœ˜\Jšžœžœ˜&•StartOfExpansion@ -- [trip: Triples.TripleRec] RETURNS [continue: BOOLEAN _ TRUE]šžœ˜Jšžœ
žœžœ"žœžœžœ˜UJ˜—Jšœ*žœ˜/Jš
žœžœžœžœžœ˜*Jšœžœ3˜BJ˜%J˜"Jšžœžœ)˜BJ˜"J˜$J˜J˜�—šŸ
œž
œ˜J˜J˜Jšœžœ˜Jšœž	˜Jšœ
ž˜Jšœžœ˜%J˜8J˜4šžœžœ )˜E˜OJ™À—JšœEžœ˜NJšžœ˜—šžœžœ ˜4J˜OJšœDžœ˜LJšžœ˜—J˜>J˜$J˜1šœžœ˜)J˜
J˜J˜J˜J˜J˜—J™Jšœ; E˜€Jšœ˜J˜�—Jšœžœžœ˜&šœžœžœ˜J˜Jšœž˜J˜—šŸœžœ˜šžœLžœ˜TJšžœžœžœžœžœžœ˜E——J˜�Jš	œoÏoœ]žœ$žœ¾žœ™ÈJ™�šŸœž
œ˜Jšœ 3˜OJšœ
žœ˜J˜J˜Jšœž˜J˜–@ -- [trip: Triples.TripleRec] RETURNS [continue: BOOLEAN _ TRUE]šœ
žœ˜-JšÐck<™<Jšœžœ˜$Jšœ˜J˜—šŸ
œžœžœ.˜JJ™–Jšœ˜Jšœ˜Jšœžœ˜Jšœ
žœžœžœ˜Jš
žœžœžœžœžœ˜+Jšœ
žœ  œ˜>šžœ	žœžœžœ˜BJšœP˜P—šžœ
žœžœ˜Jšœžœ<˜PJšžœžœžœ*˜KJ˜,JšœE˜EJ˜—Jšœžœ" 
œ˜@Jšžœžœžœ#˜4J˜—Jšžœžœ˜0Jšžœ+ 	œ˜GJ˜—J˜�J™CšŸœžœ˜(™
J™ŒJ™i—Jšœžœ˜,šœžœ-žœ
˜VJšžœžœ$˜,—šœ˜Jšœ]˜]—šžœžœ˜ Jšžœ5 ˜T—Jšžœžœ˜)J˜J˜�—J™,šŸœžœžœ˜ J™kJšœžœ˜#Jšœžœ˜3˜šžœžœ˜šžœžœ˜J˜?Jšœ7˜7J˜—Jšœžœ˜Jšžœ˜	Jšœ˜—Jšžœžœžœ˜$šœ+˜+JšœR˜R—J˜.J˜—Jšœ˜—J˜�šŸœžœžœ˜!J™BJšœžœ˜#Jšœ
žœ˜'J˜J˜�—šŸ	œžœžœ˜1J™BKšœ,˜,šžœ žœžœžœ˜JKšœžœ˜.—J˜J˜�—šŸœžœžœžœ˜?J™BJšœž	œ˜K˜MKšžœ˜Kšœ˜J˜J˜�—šŸœžœžœ˜?J˜.Jšœžœ ˜EJšœ˜J˜�—šŸœžœžœžœ˜8Jšœ- ˜Ašœžœžœžœžœžœ˜;Jšžœžœ
˜—Jšžœ
˜Jšœ˜J˜�——™J˜�J˜.J˜�šŸ
œžœžœžœ˜9J™#Jšžœžœ˜)Jšžœžœžœ˜9—J˜�šŸœžœžœ˜5J™Jšžœ(˜/Jšœ)˜)Jšžœžœžœžœ˜7J˜—J˜�šŸœžœžœžœ%˜J™VJ™—Jš
œžœžœ
žœžœžœžœ˜3šŸ	œ˜'Jšœžœ˜%Jšœ"žœ˜'Jšžœžœ˜J˜—J˜šžœžœž˜%Jšžœžœžœ˜3Jšžœ˜—J˜8Jšžœ˜J˜J˜�—šŸœžœžœžœ™<Jšœžœ
™)J™�—šŸœžœžœ˜/Jšžœžœžœ˜HJ˜�—šŸœžœžœžœ˜OJšžœžœ˜)J˜�—šŸœžœžœžœ˜TJšžœžœ˜*J˜�——J™™�Jšœžœ*˜9J˜�šŸœžœžœ˜/Jšœ˜Jšžœ.˜5J™IJ™&Jšžœžœžœ˜1šžœ
žœ
ž˜Jšžœžœžœ˜@Jš
žœžœ žœ*žœžœ˜^Jšžœžœžœžœ˜,—Jšœ˜Jšžœ˜J˜J˜�——J˜K™�™'K™�—K™�™'KšœÏr)™5—K™�™'K™4Kšœ¤ž™ª—™*K™1Kšœ¤¨™´—K™�K™�™*K™1Kšœ¤Å™Ñ—K™�™*K™UKšœ¤™™¥—K™�™*K™MKšœ¤W™c—K™�—�…—����>V��fe��