DIRECTORY Commander USING [ CommandProc, Register ], IO, Lark, LarkSmartsMonitorImpl, Nice, Process USING [ Detach, SetTimeout, SecondsToTicks ], Rope USING [ Concat ], ThParty USING [ Advance, Alert, SetProse ], ThPartyPrivate USING [ DehandleSmarts, GetCurrentParty, SmartsBody, SmartsData ], Thrush USING [ CallUrgency, ConvEvent, ConversationHandle, Disposition, H, IntervalSpec, IntervalSpecs, PartyHandle, NB, nullConvHandle, nullHandle, ProseSpec, ProseSpecBody, ProseSpecs, Reason, ROPE, SmartsHandle, StateID, StateInConv, ThHandle ], ThSmartsPrivate USING [ ConvDesc, ConvDescBody, Deregister, EnterLarkState, LarkFailed, LarkState, OpenConversations, ParseState, SmartsInfo, SmartsInfoBody ], ThSmartsRpcControl, Triples USING [ Select ], TU, VoiceUtils USING [ Problem, ProblemFR, Report, ReportFR ] ; LarkSmartsSupImpl: CEDAR MONITOR LOCKS root IMPORTS Commander, IO, Process, root: LarkSmartsMonitorImpl, Nice, Rope, ThParty, ThPartyPrivate, Thrush, ThSmartsPrivate, Triples, TU, VoiceUtils EXPORTS ThSmartsPrivate SHARES LarkSmartsMonitorImpl = { OPEN IO; CallUrgency: TYPE = Thrush.CallUrgency; CommandEvents: TYPE = Lark.CommandEvents; ConversationHandle: TYPE = Thrush.ConversationHandle; nullConvHandle: ConversationHandle=Thrush.nullConvHandle; ConvDesc: TYPE = ThSmartsPrivate.ConvDesc; ConvEvent: TYPE = Thrush.ConvEvent; disabled: Lark.Event = Lark.disabled; enabled: Lark.Event = Lark.enabled; endNum: Lark.Event = Lark.endNum; H: PROC[r: REF] RETURNS[Thrush.ThHandle] = INLINE {RETURN[Thrush.H[r]]; }; IntervalSpec: TYPE = Thrush.IntervalSpec; IntervalSpecs: TYPE = Thrush.IntervalSpecs; ProseSpec: TYPE = Thrush.ProseSpec; ProseSpecs: TYPE = Thrush.ProseSpecs; LarkState: TYPE = ThSmartsPrivate.LarkState; NB: TYPE = Thrush.NB; nullHandle: Thrush.ThHandle = Thrush.nullHandle; OpenConversations: TYPE = ThSmartsPrivate.OpenConversations; PartyHandle: TYPE = Thrush.PartyHandle; Reason: TYPE = Thrush.Reason; ROPE: TYPE = Thrush.ROPE; SHHH: TYPE = Lark.SHHH; -- Encrypts conv. if first arg to RPC PROC SmartsHandle: TYPE = Thrush.SmartsHandle; SmartsInfo: TYPE = ThSmartsPrivate.SmartsInfo; SmartsInfoBody: TYPE = ThSmartsPrivate.SmartsInfoBody; StateInConv: TYPE = Thrush.StateInConv; StatusEvents: TYPE = Lark.StatusEvents; Ctr: TYPE = RECORD[ count: INT, stop: INT ]; PD: TYPE = RECORD [ defaultRecordLength: INT _ -1, timeoutNoAction: INTEGER _ 5, cPr: REF Ctr_NEW[Ctr_[0,1000000]], cSp: REF Ctr_NEW[Ctr_[0,1000000]], cRs: REF Ctr_NEW[Ctr_[0,1000000]], cZp: REF Ctr_NEW[Ctr_[0,1000000]], cNw: REF Ctr_NEW[Ctr_[0,1000000]], doReports: BOOL_FALSE, doNice: BOOL_FALSE ]; pd: REF PD _ NEW[PD_[]]; Report: PROC[what: ROPE, info: SmartsInfo, ctr: REF Ctr] = { IF NOT pd.doReports THEN RETURN; VoiceUtils.Report[what, $Lark, info.larkInfo]; ctr.count_ctr.count+1; IF ctr.count>ctr.stop THEN { VoiceUtils.Problem["Report overflow", $Lark, info.larkInfo]; }; }; ReportFR: PROC[what: ROPE, info: SmartsInfo, ctr: REF Ctr, a1, a2: IO.Value_rope[NIL]] = { IF NOT pd.doReports THEN RETURN; VoiceUtils.ReportFR[what, $Lark, info.larkInfo, a1, a2]; ctr.count_ctr.count+1; IF ctr.count>ctr.stop THEN { VoiceUtils.Problem["Report overflow", $Lark, info.larkInfo]; }; }; BeNice: PROC[r: REF, d: INT, info: SmartsInfo] = { IF NOT pd.doNice THEN RETURN; Nice.BeNice[r, d, $Lark, info.larkInfo]; }; LarkProgress: PUBLIC ENTRY PROC[ interface: ThSmartsRpcControl.InterfaceRecord, shh: SHHH, smartsID: Thrush.SmartsHandle, event: Thrush.ConvEvent, yourParty: BOOL, latestEvent: BOOL, informationOnly: BOOL ] RETURNS [ d: Thrush.Disposition ] = { info: SmartsInfo _ GetSmartsInfo[smartsID: smartsID]; cDesc: ThSmartsPrivate.ConvDesc; IF info=NIL THEN RETURN[pass]; d_actedAndStop; IF pd.doReports THEN Report[ Rope.Concat[ IO.PutFR["---- LkProg: %t(%d) %g %g yr=%g ", time[event.credentials.convID], int[event.credentials.stateID], refAny[NEW[StateInConv_event.state]], TU.RefAddr[info], bool[yourParty]], IO.PutFR["lt=%g in=%g, ky=%g\n", bool[latestEvent], bool[event.intervalSpecs#NIL OR event.proseSpecs#NIL], bool[event.keyTable#NIL]]], info, pd.cPr]; cDesc _ GetConv[info, event.credentials.convID, FALSE]; IF event.credentials.stateID <= cDesc.cState.credentials.stateID THEN RETURN[pass]; -- Old news! cDesc.cState.credentials.smartsID _ smartsID; cDesc.cState.credentials.stateID _ event.credentials.stateID; IF event.keyTable#NIL THEN { cDesc.cState.keyTable _ event.keyTable; cDesc.newKeys_TRUE; }; IF event.intervalSpecs#NIL THEN EnqueueIntervals[cDesc, event.intervalSpecs]; IF event.proseSpecs#NIL THEN { req: BOOL _ FALSE; FOR pSL: ProseSpecs _ event.proseSpecs, pSL.rest WHILE pSL#NIL DO IF pSL.first.type=request THEN { req _ TRUE; }; ENDLOOP; IF req OR ~info.larkInfo.textToSpeech THEN EnqueueProses[cDesc, event.proseSpecs]; }; IF event.address#NIL THEN { cDesc.cState.address_event.address; cDesc.newAddress_TRUE; }; IF yourParty THEN { cDesc.descValid _ TRUE; cDesc.cState.credentials.partyID _ event.credentials.partyID; cDesc.cState.state _ event.state; cDesc.cState.comment _ event.comment; cDesc.cState.reason _ event.reason; IF event.spec#NIL THEN { cDesc.cState.spec _ event.spec; cDesc.newSpec_TRUE; }; IF event.comment#NIL THEN cDesc.cState.comment _ event.comment; IF event.urgency#normal THEN cDesc.cState.urgency _ event.urgency; IF event.alertKind#standard THEN cDesc.cState.alertKind _ event.alertKind; SELECT event.state FROM reserved, parsing, initiating => cDesc.originator _ us; maybe => { cDesc.originator _ us; IF info.Supervise = LarkSupervise THEN info.larkInfo.ringTune _ event.ringTune; }; pending => cDesc.originator _ them; ringing => { cDesc.originator _ them; info.larkInfo.ringTune _ event.ringTune; }; ENDCASE; }; BeNice[event, 4, info]; BeNice[cDesc, 6, info]; cDesc.newEvent _ TRUE; IF latestEvent THEN Apprise[info]; -- Wait for the last report to wake process. }; LarkSupervise: PUBLIC ENTRY PROC[info: SmartsInfo ] = { TRUSTED { Process.SetTimeout[@info.thAction, Process.SecondsToTicks[pd.timeoutNoAction]]; }; IF info.apprise THEN DO ENABLE { UNWIND => NULL; ThSmartsPrivate.LarkFailed => GOTO Failing; }; prevL: OpenConversations _ NIL; nb: NB_success; convL: OpenConversations; trans: Transition; info.apprise _ FALSE; FOR convL _ info.conversations, convL.rest WHILE convL#NIL DO cDesc: ConvDesc = convL.first; stateNow: StateInConv = cDesc.cState.state; ours: BOOL _ ( cDesc.cState.credentials.convID = info.currentConvID ); IF pd.doReports THEN Report[ Rope.Concat[ IO.PutFR["**** LkSup: %t(%d) %g %g->%g", time[cDesc.cState.credentials.convID], int[cDesc.cState.credentials.stateID], TU.RefAddr[info], refAny[NEW[StateInConv_stateNow]], refAny[NEW[StateInConv_cDesc.desiredState]]], IO.PutFR[" %g%g\n", refAny[NEW[Transition_transForStates[stateNow][cDesc.desiredState]]], rope[IF ours THEN " (ours)" ELSE ""]]], info, pd.cSp]; BeNice[cDesc, 6, info]; IF NOT cDesc.descValid THEN LOOP; IF info.currentConvID = nullConvHandle --AND stateNow#idle-- THEN { ours_TRUE; info.currentConvID _ cDesc.cState.credentials.convID; }; IF stateNow=idle THEN { IF pd.doReports THEN ReportFR[" ** Zap %t\n", info, pd.cZp, time[cDesc.cState.credentials.convID]]; IF prevL#NIL THEN { prevL.rest _ convL.rest; convL _ prevL; } ELSE info.conversations_convL.rest; IF ours THEN { reason: Reason = cDesc.cState.reason; newConvID: ConversationHandle_cDesc.cState.credentials.convID; newDesc: ConvDesc; info.currentConvID _ nullConvHandle; SELECT info.larkInfo.hookState FROM onhook, spkr => SELECT reason FROM terminating, wontSay => GOTO Exit; ENDCASE => IF cDesc.originator#us THEN GOTO Exit; ENDCASE => SELECT TRUE FROM reason=terminating, reason=wontSay, cDesc.originator#us => { newConvID _ nullConvHandle; info.currentConvID _ nullConvHandle; }; ENDCASE; newDesc _ GetConv[info, newConvID, TRUE]; ChangeState[info, newDesc, reserved, cDesc.cState.reason, cDesc.cState.comment]; -- Now go around the loop once, if only to coerce Lark into idle state. EXITS Exit => NULL; }; } ELSE IF NOT ours THEN nb _ ThParty.Advance[ credentials: cDesc.cState.credentials, state: idle, reason: busy, comment: "One conversation at a time, please." ] ELSE { SELECT (trans_transForStates[stateNow][cDesc.desiredState]) FROM noop => NULL; elim => ERROR; -- handled in stateNow=idle case above. rsrv, rers, prsg, alrt => { -- placing call, or reserving conversation convID: ConversationHandle; calledPartyID: PartyHandle = IF trans#alrt THEN nullHandle ELSE cDesc.desiredPartyID; nb _ IF trans=alrt AND calledPartyID=nullHandle THEN noSuchParty2 ELSE success; IF NOT ours THEN Problem["What to do in a race?", info]; IF nb=success THEN [nb, convID] _ ThParty.Alert [ credentials: cDesc.cState.credentials, calledPartyID: calledPartyID, state: IF trans = alrt THEN initiating ELSE cDesc.desiredState, reason: cDesc.desiredReason, newConv: trans=rsrv, comment: cDesc.desiredComment ]; IF nb=success THEN { cDesc.cState.credentials.convID _ info.currentConvID _ convID; ours_TRUE; }; }; idle, actv => -- Simple transitions nb _ ThParty.Advance [ credentials: cDesc.cState.credentials, state: cDesc.desiredState, reason: cDesc.desiredReason, comment: cDesc.desiredComment ]; spvs => { -- Supervision while active. cDesc.desiredState_active; -- Reflect reality FOR iL: IntervalSpecs _ cDesc.newIntervals, iL.rest WHILE iL#NIL DO iS: IntervalSpec = iL.first; IF iS.interval.length#0 OR iS.queueIt THEN -- else flush: ignore SELECT iS.type FROM started => cDesc.desiredIntID _ iS.intID; finished => IF iL.rest=NIL AND iS.intID = cDesc.desiredIntID THEN SELECT info.larkInfo.hookState FROM spkr => ChangeState[info, cDesc, idle]; ENDCASE; ENDCASE; ENDLOOP; cDesc.newIntervals _ NIL; IF cDesc.newProses#NIL AND info.larkInfo.textToSpeech THEN { copyNewProses: ProseSpecs _ cDesc.newProses; cDesc.newProses _ NIL; EnqueueProses[cDesc, copyNewProses]; ThSmartsPrivate.EnterLarkState[ info.larkInfo, LarkStateForState[cDesc, stateNow, info.larkInfo.larkState], info]; cDesc.newProses _ copyNewProses; }; FOR pL: ProseSpecs _ cDesc.newProses, pL.rest WHILE pL#NIL DO pS: ProseSpec = pL.first; SELECT pS.type FROM request => IF info.larkInfo.textToSpeech THEN { pS.type _ started; pS.prose _ ""; }; started => cDesc.desiredProseID _ pS.intID; finished => IF ~info.larkInfo.textToSpeech AND pL.rest=NIL AND pS.intID = cDesc.desiredProseID THEN SELECT info.larkInfo.hookState FROM spkr => ChangeState[info, cDesc, idle]; ENDCASE; ENDCASE; ENDLOOP; IF cDesc.newProses#NIL AND info.larkInfo.textToSpeech THEN { nb _ ThParty.SetProse[ shhh: info.larkInfo.shh, credentials: cDesc.cState.credentials, proseSpecs: cDesc.newProses ]; IF nb=success THEN cDesc.newProses_NIL; } ELSE cDesc.newProses _ NIL; }; ring => -- This is how you say you'll ring an incoming call IF info.larkInfo.autoAnswer THEN { info.apprise_TRUE; cDesc.desiredState _ active; } ELSE nb _ ThParty.Advance [ credentials: cDesc.cState.credentials, state: ringing ]; invl => { comment: ROPE="Invalid state transition"; Problem[comment, info]; ChangeState[info, cDesc, idle, error, comment]; }; ntiy => { comment: ROPE= "Unimplemented state transition"; Problem[comment, info]; ChangeState[info, cDesc, idle, error, comment]; }; ENDCASE => ERROR; }; IF nb#success THEN ReportFR[" ** Results: nb=%g\n", info, pd.cRs, refAny[NEW[Thrush.NB_nb]]]; SELECT nb FROM success, stateMismatch => NULL; noSuchParty2, narcissism => -- Have to get to error tone here. No such party. ChangeState[info, cDesc, idle, notFound, "Called party not found, or calling self"]; partyNotEnabled => ours_FALSE; invalidTransition, convNotActive, convStillActive => { comment: ROPE="Party-level detected invalid state transition request"; Problem[comment, info]; ChangeState[info, cDesc, idle, error, comment]; }; notInConv, noSuchConv => { -- Complain, zap, go idle and repeat. comment: ROPE="NotInConv or NoSuchConv"; Problem[comment, info]; IF ours THEN info.currentConvID _ nullConvHandle; cDesc.cState.credentials.convID _ nullConvHandle; cDesc.cState.credentials.stateID _ 0; ChangeState[info, cDesc, idle, error, comment]; }; noSuchParty, noSuchSmarts => { -- Complain, deregister, we gone! Needs tuning. Problem[ "LkSmts: NoSuchParty or NoSuchSmarts reported, must try to go away", info]; GOTO Failing; }; ENDCASE => ERROR; IF ours THEN ThSmartsPrivate.EnterLarkState[ info.larkInfo, LarkStateForState[cDesc, stateNow, info.larkInfo.larkState], info]; prevL _ convL; ENDLOOP; IF NOT info.apprise THEN WAIT info.thAction; IF info.conversations = NIL THEN EXIT; REPEAT Failing => ThSmartsPrivate.Deregister[info]; -- now Failed ENDLOOP; info.thProcess _ NIL; }; GetConv: PUBLIC INTERNAL PROC[info: SmartsInfo, convID: ConversationHandle, validIfNew: BOOL ] RETURNS [ cDesc: ConvDesc_NIL ] = --INLINE-- { FOR convs: OpenConversations _ info.conversations, convs.rest WHILE convs#NIL DO IF convs.first.cState.credentials.convID = convID THEN RETURN[convs.first]; ENDLOOP; cDesc _ NEW[ThSmartsPrivate.ConvDescBody_[]]; cDesc.descValid _ validIfNew; cDesc.cState.state _ any; cDesc.cState.credentials _ [ convID: convID, smartsID: H[info.smarts], partyID: ThPartyPrivate.GetCurrentParty[smartsID: H[info.smarts]], stateID: 0 ]; info.conversations _ CONS[cDesc, info.conversations]; IF pd.doReports THEN Report[IO.PutFR[" ** NewConv %t %g, vl=%g\n", time[convID], TU.RefAddr[info], bool[validIfNew]], info, pd.cNw]; }; ChangeState: PUBLIC INTERNAL PROC[ info: SmartsInfo, cDesc: ConvDesc, state: StateInConv _ idle, reason: Reason _ wontSay, comment: ROPE_NIL ] = { IF info=NIL OR cDesc=NIL THEN RETURN; cDesc.desiredState _ state; cDesc.desiredReason _ reason; cDesc.desiredComment _ comment; Apprise[info]; }; Apprise: PUBLIC INTERNAL PROC[info: SmartsInfo] = TRUSTED --INLINE-- { IF info.thProcess=NIL THEN Process.Detach[info.thProcess _ FORK info.Supervise[info]]; info.apprise _ TRUE; NOTIFY info.thAction; }; EnqueueIntervals: INTERNAL PROC[cDesc: ConvDesc, int: IntervalSpecs] = INLINE { IF cDesc.newIntervals#NIL THEN cDesc.iTail.rest _ int ELSE cDesc.newIntervals _ int; FOR iL: IntervalSpecs _ int, iL.rest WHILE iL#NIL DO cDesc.iTail _ iL; ENDLOOP; }; EnqueueProses: INTERNAL PROC[cDesc: ConvDesc, pro: ProseSpecs] = { FOR pL: ProseSpecs _ pro, pL.rest WHILE pL#NIL DO newSpec: ProseSpecs _ LIST[NEW[Thrush.ProseSpecBody _ pL.first^]]; IF cDesc.newProses#NIL THEN cDesc.pTail.rest _ newSpec ELSE cDesc.newProses _ newSpec; cDesc.pTail _ newSpec; ENDLOOP; }; ReportProseDone: PUBLIC ENTRY PROC[info: SmartsInfo, proseSpec: ProseSpec] = { cDesc: ConvDesc _ GetConv[info, info.currentConvID, FALSE]; EnqueueProses[cDesc, LIST[proseSpec]]; cDesc.pTail.first.type _ finished; -- make sure this is okay! Apprise[info]; }; GetSmartsInfo: PUBLIC PROC[smartsID: SmartsHandle_nullHandle, smarts: ThPartyPrivate.SmartsData_NIL] RETURNS [info: SmartsInfo_NIL] = { r: REF_smarts; IF smartsID#nullHandle THEN r_ThPartyPrivate.DehandleSmarts[smartsID]; IF r#NIL THEN RETURN[NARROW[Triples.Select[$SmartsData, r, --info--]]]; }; Problem: PROC[comment: ROPE, info: SmartsInfo] = { VoiceUtils.ProblemFR[Rope.Concat["LarkSmarts(%g): ", comment], $Smarts, info, TU.RefAddr[info]]; }; larkStateForState: ARRAY StateInConv OF LarkState _ [ idle, dialTone, silence, silence, silence, ringBack, ringing, silence, talking, silence, silence ]; LarkStateForState: INTERNAL PROC[cDesc: ConvDesc, state: StateInConv, nowState: LarkState] RETURNS [larkState: LarkState] = -- INLINE -- { SELECT (larkState_larkStateForState[state]) FROM talking => { spec: Lark.ConnectionSpec = cDesc.cState.spec; IF spec=NIL THEN ERROR; IF spec.localSocket.net = spec.remoteSocket.net AND spec.localSocket.host = spec.remoteSocket.host THEN larkState _ nowState; }; dialTone => larkState _ SELECT cDesc.cState.reason FROM busy, notImportantEnough => busyTone, absent, noCircuits, noParticular, notFound, error => errorTone, ENDCASE => dialTone; ENDCASE; }; Transition: TYPE = { noop, elim, idle, rsrv, rers, prsg, alrt, ring, actv, spvs, invl, ntiy }; transForStates: ARRAY StateInConv OF ARRAY StateInConv OF Transition _ [ [ elim, invl, prsg, invl, invl, invl, invl, invl, elim, elim, elim ], -- idle (current) [ idle, noop, prsg, invl, invl, invl, invl, invl, alrt, ntiy, noop ], -- reserved [ idle, rers, noop, invl, invl, invl, invl, invl, alrt, ntiy, invl ], -- parsing [ idle, noop, invl, invl, invl, invl, invl, invl, noop, ntiy, noop ], -- initiating [ idle, invl, invl, invl, invl, invl, invl, invl, actv, ntiy, ring ], -- pending [ idle, noop, invl, invl, invl, invl, invl, invl, noop, ntiy, noop ], -- maybe [ idle, invl, invl, invl, invl, invl, invl, invl, actv, ntiy, noop ], -- ringing [ idle, invl, invl, invl, invl, invl, invl, invl, ntiy, ntiy, ntiy ], -- canActivate [ idle, spvs, invl, invl, invl, invl, invl, invl, spvs, ntiy, spvs ], -- active [ idle, invl, invl, invl, invl, invl, invl, invl, ntiy, noop, ntiy ], -- inactive [ noop, rsrv, prsg, invl, invl, invl, invl, invl, alrt, ntiy, invl ] -- any (nonex) ]; ViewCmd: Commander.CommandProc = TRUSTED { Nice.View[pd, "Lark PD"]; }; Commander.Register["VuLarkSmarts", ViewCmd, "Program Management variables for Lark Smarts"]; }. PLarkSmartsSupImpl.mesa Copyright c 1985, 1986 by Xerox Corporation. All rights reserved. Last modified by D. Swinehart, May 17, 1986 4:14:59 pm PDT Polle Zellweger (PTZ) August 27, 1985 9:07:50 pm PDT Copies Party-invoked actions Update local state information Fields always extracted <> Extracted if present May accept more later. IF ~pSL.first.queueIt AND info.larkInfo.textToSpeech THEN { Flush proseSpecs that haven't been sent yet. It doesn't matter if we remove started and finished reports here; the server doesn't care about those anyway. But what about REFs? Will no one else get to see these either? event.proseSpecs _ pSL; cDesc.newProses _ NIL; }; Extracted if the event changes our state. << When Conferencing is added, put this back in.>> cDesc.cState.conferenceHost _ event.conferenceHost; Extracted if non-standard? Yucchh! Progress is shared between Trunk and Lark smarts. Want to do it only in the Lark case. This is the only way to tell, at present! Th(e) Process <> Conv. is now idle: forget about it or re-use it, sort of. Remove dead conversation from list. Set to look like reserving brand new conversation Conv isn't the one we're interested in, and doesn't look like it's going idle: idle it. Should probably consult transForStates for validity. State and substate (below) and desired state indicate there's something to do. Do it: May do more later. For now, record the intervals that start; when you see the last one that started end, it's time to shut down the connection. EnterLarkState, below, may cause new keys to be distributed. When voice messages again supported, will need to initiate intervals here. Make another copy of the newProses -- this copy will belong only to the Lark (but it may include started and finished reports, which the Lark must ignore). We can then smash the prose ROPE of the original newProses inside the loop below. May do more later. For now, record the requests that start; when you see the last one that started end, it's time to shut down the connection. Avoid sending long RPC packets back to acknowledge things EnterLarkState, below, may cause new keys to be distributed. When voice messages again supported, will need to initiate intervals here. Analyze any results of trying to reach a different state. Complain and transition to idle Set up switching and tones to match state. Connection Management Utilities Copies, so that changes can be made in order to report back to ThParty. proseSpec.type _ finished; -- Check this one! Other Utilities State Transition Tables idle, reserved, parsing, initiating, pending, maybe, ringing, canActivate, active, inActive, any Just codes to dispatch on in Supervisor; explained there idle resrv pars init pend mayb ring canAc activ inact any -- desired NB: examine relationship to validity table in PartyOpsImpl someday. Debugging nonsense Swinehart, May 15, 1985 11:05:22 am PDT Cedar 6.0, add Prose stuff as direct copy of Interval stuff. changes to: IntervalSpecs, ProseSpec, ProseSpecs, LarkState, LarkProgress, LarkSupervise, EnqueueProses Swinehart, May 22, 1985 12:15:11 pm PDT hotLine => autoAnswer changes to: LarkSupervise Swinehart, July 2, 1985 10:09:14 am PDT Fixing up trunkTalking stuff changes to: LarkSupervise, LarkStateForState Polle Zellweger (PTZ) July 11, 1985 6:15:01 pm PDT changes to: DIRECTORY, EnqueueProses, ReportProseDone, LarkSupervise Polle Zellweger (PTZ) July 16, 1985 9:42:51 pm PDT changes to: LarkProgress, LarkSupervise, ReportProseDone Polle Zellweger (PTZ) July 30, 1985 4:41:39 pm PDT Handle copying of newProses correctly - give Lark its own copy. changes to: LarkSupervise Swinehart, August 6, 1985 2:26:39 pm PDT Merge PTZ ProseSpec changes changes to: DIRECTORY, LarkProgress, LarkSupervise, EnqueueProses Polle Zellweger (PTZ) August 14, 1985 6:12:13 pm PDT Prose flushing, also fix undesired speakerphone hangup for intervals, proseSpecs. changes to: LarkProgress, LarkSupervise Polle Zellweger (PTZ) August 22, 1985 2:04:45 pm PDT changes to: LarkProgress -- comment out some optimizing queue flushing Swinehart, May 17, 1986 4:04:37 pm PDT Cedar 6.1 changes to: DIRECTORY, LarkSmartsSupImpl, Report, ReportFR, Problem Κ!˜šœ™Icodešœ Οmœ7™BJšœ:™:K™4J™—šΟk œ˜ Jšœ žœ˜*Jšžœ˜Jšœ˜J˜J˜J˜J˜Jšœžœ(˜5Jšœžœ ˜Jšœžœ˜+Jšœžœ=˜QJš œžœ<žœ,žœLžœ1˜ψšœžœ˜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˜Jšœ žœ˜'Jšœžœ˜)šœžœ˜5Jšœ9˜9—Jšœ žœ˜*Jšœ žœ˜#Jšœ%˜%Jšœ#˜#Jšœ!˜!Jšžœžœžœžœžœžœžœ˜JJšœžœ˜)Jšœžœ˜+Jšœ žœ˜#Jšœ žœ˜%Jšœ žœ˜,Jšžœžœ žœ˜J˜0Jšœžœ%˜—šžœžœž˜J™Jšœ-˜-—šžœžœžœ˜Kšœžœžœ˜šžœ.žœžœž˜Ašžœžœ˜ Kšœžœ˜ šžœžœžœ™;Kšœά™άKšœ™Kšœžœ™K™—K˜—Kšžœ˜—šžœžœž˜*Jšœ'˜'—J˜—Jšžœžœžœ8žœ˜YJ™J™*šžœ žœ˜Jšœžœ˜Jšœ=˜=Jšœ!˜!Jšœ%˜%Jšœ#˜#J™2J™3Jšžœ žœžœ1žœ˜OJ™Jšžœžœžœ&˜?Jšžœžœ&˜BJšžœžœ*˜Jšžœ ž˜J˜7˜ J˜J™ŠJšžœ žœ)˜OJ˜—J˜#JšœQ˜QJšžœ˜—J˜—J˜J˜J˜J™Jšœžœ˜Jšžœ žœŸ,˜OJ˜—J™—™ J˜š  œž œžœ˜7šžœ˜ J˜R—šžœžœž˜šžœ˜Jšžœžœ˜Jšœžœ ˜+J˜—Jšœžœ˜Jšœžœ ˜Jšœ˜J˜Jšœžœ˜šžœ˜Jšœ žœžœž˜J˜Jšœ+˜+Jšœžœ<˜FJ˜šžœžœ˜šœ ˜ šžœ&˜(J˜MJšœžœ žœ#˜b—šžœ˜Jšœžœ;˜EJšœžœžœ žœ˜'——Jšœ˜—J˜J™Jšžœžœžœžœ˜!šžœ'žœžœ˜CJ™gJšœžœ7˜@Jšœ˜—šžœžœ˜J™:J™#šžœž˜JšœO˜O—šžœžœžœ˜Jšœ)˜)—Jšžœ˜#J˜šžœžœ˜J˜%J˜>J˜Jšœ$˜$šžœž˜#˜šžœž˜Jšœžœ˜"Jšžœžœžœžœ˜1——šžœ˜ šžœžœž˜šœ<˜Jšœžœ˜ J˜—J˜—šœŸ˜#šœ˜J˜&Jšœ˜J˜Jšœ˜Jšœ˜——šœ Ÿ˜&JšœŸ˜-šžœ1žœžœž˜CJ™J˜šžœžœ žœŸ˜@šžœ ž˜Jšœ)˜)˜ šžœ žœžœž˜5šžœž˜#Jšœ(žœ˜0———Jšžœ˜——Jšžœ˜—Jšœžœ˜Jšœ<™Jšœ˜J˜—J™—™J˜š  œžœžœ#˜=Jšœ"žœ˜&Jšžœžœ˜"Jšœžœ˜šžœž˜Jšœ*˜*—Jš žœžœžœžœžœ Ÿœ˜GJšœ˜—J˜š œžœ žœ˜2JšœNžœ˜`J˜J˜——™J˜˜5J™[J˜`J™J˜J˜—š œžœžœ:˜ZJšžœŸ œ˜/šžœ&ž˜0šœ ˜ J˜.Jšžœžœžœžœ˜šžœ-˜/Jšžœ0žœ˜M—J˜—šœžœž˜7Jšœ%˜%Jšœ?˜?Jšžœ ˜—Jšžœ˜—J˜—J˜šœ žœ˜J™8J˜FJ˜—J˜š œžœ žœžœ žœ˜HJšœO™OJ™JšœMŸ˜_JšœNŸ ˜YJšœLŸ ˜VJšœMŸ ˜ZJ˜JšœNŸ ˜XJšœMŸ˜UJšœNŸ ˜XJšœNŸ˜\J˜JšœMŸ ˜VJšœMŸ ˜XJšœMŸ˜[—˜JšΟsC™C——J˜™šœ!žœ˜*J˜Jšœ˜—Jšœ\˜\—J˜™'K™