DIRECTORY IO, Commander USING [ CommandProc, Register ], Convert USING [ IntFromRope ], Lark USING [ bStar, bThorp, CommandEvent, CommandEvents, CommandEventSequence, Device, disabled, DTMFEvent, enabled, endNum, Event, Passel, reset, StatusEvent, StatusEvents, SHHH ], LarkRpcControl, LarkSmarts, Nice, RPC USING [ CallFailed ], Rope USING [ Concat, FromChar, Length, ROPE ], Process USING [ Detach, MsecToTicks, SetTimeout, Ticks ], ThPartyPrivate USING [ SmartsData ], ThSmartsPrivate USING [ click, EnterLarkSt, flushMarker, GetSmartsInfo, HookState, indexMarkerEnd, LarkInfo, LarkProseQueue, LarkState, maxClientMarker, ProseControlDone, proseFailure, ReportProseDone, RingDetState, SmartsInfo, stopAndFlushEnd, TerminalType, TonesDone ], Thrush USING[ H, pERROR, ProseSpec, ROPE, SHHH, SmartsHandle, ThHandle ], ThNet USING [ pd ], VoiceUtils USING [ Problem, Report ] ; LarkInImpl: CEDAR MONITOR LOCKS info USING info: LarkInfo IMPORTS LarkRpcControl, Commander, Convert, IO, Nice, Process, Rope, RPC, ThNet, Thrush, ThSmartsPrivate, VoiceUtils EXPORTS LarkSmarts, ThSmartsPrivate= { OPEN IO; H: PROC[r: REF] RETURNS[Thrush.ThHandle] = INLINE {RETURN[Thrush.H[r]]; }; HookState: TYPE = ThSmartsPrivate.HookState; LarkInfo: TYPE = ThSmartsPrivate.LarkInfo; RingDetState: TYPE = ThSmartsPrivate.RingDetState; SmartsData: TYPE = ThPartyPrivate.SmartsData; SmartsInfo: TYPE = ThSmartsPrivate.SmartsInfo; SmartsHandle: TYPE = Thrush.SmartsHandle; TerminalType: TYPE = ThSmartsPrivate.TerminalType; ROPE: TYPE = Thrush.ROPE; bStar: Lark.Event = Lark.bStar; bThorp: Lark.Event = Lark.bThorp; enabled: Lark.Event = Lark.enabled; endNum: Lark.Event = Lark.endNum; disabled: Lark.Event = Lark.disabled; reset: Lark.Event = Lark.reset; PD: TYPE = RECORD [ callTimeoutOK: BOOL_FALSE -- set to keep Thrush alive when debugging a Lark. ]; pd: REF PD _ NEW[PD_[]]; DebEvent: PROC[info: SmartsInfo, ev: Lark.StatusEvent] = INLINE { s: IO.STREAM=IO.ROS[]; s.PutF["[%3B, %3B, ", card[LONG[ IF info#NIL THEN LOOPHOLE[info.larkInfo.netAddress.host,CARDINAL] ELSE LOOPHOLE[777B, CARDINAL]]], card[LONG[LOOPHOLE[ev.device, CARDINAL]]]]; IF ev.event<='z THEN s.PutF["%g] ",char[ev.event]] ELSE s.PutF["<%3B>] ", card[LONG[LOOPHOLE[ev.event, CARDINAL]]]]; VoiceUtils.Report[s.RopeFromROS[], $LarkDetailed, info.larkInfo]; }; crowbar: BOOL_FALSE; -- TRUE to check basic RPC performance from Lark. RecordEvent: PUBLIC PROC[shh: Thrush.SHHH, smartsID: Thrush.SmartsHandle, whatHappened: Lark.StatusEvents] RETURNS [ success: BOOL_TRUE ] = { smartsInfo: SmartsInfo = ThSmartsPrivate.GetSmartsInfo[smartsID: smartsID]; parseInfo: SmartsInfo _ smartsInfo; info: LarkInfo; parseSmarts: SmartsData; IF smartsInfo=NIL OR (info _ smartsInfo.larkInfo)=NIL THEN RETURN[FALSE]; parseSmarts _ smartsInfo.smarts; FOR i: Lark.Passel IN [0 .. whatHappened.length) DO sEvent: Lark.StatusEvent _ whatHappened[i]; IF ThNet.pd.debug THEN DebEvent[smartsInfo, sEvent]; IF crowbar OR info.larkState=failed OR info.larkState=recovering THEN LOOP; SELECT sEvent.device FROM ringDetect => { parseSmarts _ smartsInfo.otherSmarts; parseInfo _ ThSmartsPrivate.GetSmartsInfo[smarts: parseSmarts]; }; tones => { ThSmartsPrivate.TonesDone[smartsInfo.larkInfo, sEvent, smartsInfo]; LOOP; }; ENDCASE; SELECT sEvent.device FROM speakerSwitch => sEvent _ InterpretSpeakerSwitch[info, sEvent]; ringDetect => sEvent _ InterpretRingDetect[info, H[parseSmarts], parseInfo, sEvent]; touchPad => { IF sEvent.event=disabled THEN sEvent.event _ smartsInfo.lastTouchpadChar ELSE { smartsInfo.lastTouchpadChar _ sEvent.event; LOOP; -- down transitions of DTMF pad. }; IF sEvent.event='\000 THEN LOOP; }; keyboard => { IF info.textToSpeech THEN HandleAndReport[info, sEvent, smartsInfo]; LOOP; }; hookSwitch => NULL; ENDCASE => Thrush.pERROR; IF sEvent.device=nothing THEN LOOP; parseInfo.ParseEvent[ smartsInfo: parseInfo, sEvent: sEvent ]; ENDLOOP; }; EventRope: PUBLIC PROC[ shh: Thrush.SHHH, smartsID: SmartsHandle, time: CARDINAL, device: Lark.Device, events: ROPE] RETURNS[success: BOOL] = { NULL; }; HandleProseOutput: ENTRY PROC[info: LarkInfo, commandEvent: Lark.StatusEvent, sInfo: SmartsInfo] RETURNS [pS: Thrush.ProseSpec _ NIL] = { c: CHAR _ commandEvent.event; SELECT c FROM IO.BEL => NULL; -- take some error action? IO.ESC, ';, '\\ => info.proseResponse _ ""; -- start of some response '[ => NULL; -- peel this character off ThSmartsPrivate.stopAndFlushEnd => { ThSmartsPrivate.ProseControlDone[info, ThSmartsPrivate.flushMarker, sInfo]; info.flushJustFinished _ TRUE; }; ThSmartsPrivate.indexMarkerEnd => { marker: INT; IF Rope.Length[info.proseResponse]=0 THEN RETURN; marker _ Convert.IntFromRope[info.proseResponse]; IF marker > ThSmartsPrivate.maxClientMarker THEN ThSmartsPrivate.ProseControlDone[info, marker, sInfo] ELSE { pQ: ThSmartsPrivate.LarkProseQueue _ info.proseQueue; IF pQ=NIL THEN Thrush.pERROR; IF info.flushJustFinished THEN { FOR pSkip: ThSmartsPrivate.LarkProseQueue _ pQ, pSkip.rest WHILE pSkip#NIL DO IF pSkip.first.proseMarker = marker THEN pQ _ pSkip; ENDLOOP; info.flushJustFinished _ FALSE; }; IF pQ.first.proseMarker = marker THEN { pS _ pQ.first.proseSpec; info.proseQueue _ pQ.rest; -- Flush any skipped items. IF info.proseQueue=NIL THEN info.pTail _ NIL; } ELSE ThSmartsPrivate.ProseControlDone[info, ThSmartsPrivate.proseFailure, sInfo]; -- fail!!! }; }; ENDCASE => info.proseResponse _ Rope.Concat[info.proseResponse, Rope.FromChar[c]]; }; HandleAndReport: PROC [info: LarkInfo, commandEvent: Lark.StatusEvent, sInfo: SmartsInfo] ~ { pS: Thrush.ProseSpec _ HandleProseOutput[info, commandEvent, sInfo]; IF pS#NIL THEN ThSmartsPrivate.ReportProseDone[sInfo, pS]; }; InterpretSpeakerSwitch: PROC[info: LarkInfo, sEvent: Lark.StatusEvent] RETURNS [ processedEvent: Lark.StatusEvent] = --<>-- { interval: INTEGER = LOOPHOLE[sEvent.time-info.swOnTime]; processedEvent _ sEvent; SELECT sEvent.event FROM enabled => info.swOnTime _ sEvent.time; disabled => NULL; ENDCASE => ERROR Thrush.pERROR; IF interval < 0 OR interval > spClickInterval THEN RETURN; processedEvent.event _ ThSmartsPrivate.click; }; spClickInterval: INTEGER _ 500; InterpretRingDetect: ENTRY PROC[info: LarkInfo, smartsID: SmartsHandle, smartsInfo: SmartsInfo, sEvent: Lark.StatusEvent] RETURNS [ processedEvent: Lark.StatusEvent _ [ 0, nothing, Lark.reset ] ] = --<>-- { ENABLE UNWIND=>NULL; interval: INTEGER = LOOPHOLE[sEvent.time-info.ringChangeTime]; event: Lark.Event = sEvent.event; info.ringChangeTime _ sEvent.time; SELECT event FROM enabled => SELECT info.ringDetState FROM idle, between=>NULL; ENDCASE=>RETURN; disabled => SELECT info.ringDetState FROM idle, between=>RETURN; ENDCASE; ENDCASE=>RETURN; SELECT info.ringDetState FROM idle => TRUSTED { -- known enabled -- info.ringDetState _ maybe; info.ringDetWaitState_idle; info.ringDetInstance _ info.ringDetInstance+1; Process.Detach[FORK RingDetProc[smartsID, smartsInfo, info.ringDetInstance]]; }; maybe => { -- known disabled -- IF interval { -- known disabled -- info.ringDetState _ between; }; ring => { -- known disabled -- info.ringDetState _ IF interval > ringInterval THEN between ELSE idle; }; between => { -- known enabled -- info.ringDetState _ IF interval < breakInterval THEN ring ELSE idle; }; ENDCASE; IF info.ringDetState#info.ringDetWaitState THEN NOTIFY info.ringDetCondition; }; debounceInterval: INTEGER _ 300; -- ms. ringInterval: INTEGER = 1700; -- ms., 2 sec. nominal, 300 ms. benefit of doubt breakInterval: INTEGER = 4500; -- ms., 4 sec. nominal, 500 ms. benefit of doubt debounceIntTicks: Process.Ticks = Process.MsecToTicks[debounceInterval]; ringIntTicks: Process.Ticks = Process.MsecToTicks[ringInterval]; breakIntTicks: Process.Ticks = Process.MsecToTicks[breakInterval]; RingDetProc: PROC[smartsID: SmartsHandle, smartsInfo: SmartsInfo, instance: CARDINAL] = { info: LarkInfo = smartsInfo.larkInfo; event: Lark.Event; RingDetProcEntry: ENTRY PROC[info: LarkInfo] RETURNS[stillRunning: BOOL] = --INLINE-- { ENABLE UNWIND=>NULL; newState: RingDetState = IF info.ringDetInstance#instance THEN idle ELSE info.ringDetState; event _ reset; IF newState#idle AND newState=info.ringDetWaitState THEN -- timed out SELECT info.ringDetState FROM idle => RETURN[FALSE];--??-- maybe => { info.ringDetState _ ring1; event _ enabled; RETURN[TRUE]; }; ring1, between => info.ringDetState _ idle; ring => info.ringDetState _ between; --??-- ENDCASE; info.ringDetWaitState _ info.ringDetState; TRUSTED { SELECT info.ringDetState FROM idle => { event _ disabled; RETURN[FALSE]; }; maybe => Process.SetTimeout[@info.ringDetCondition, debounceIntTicks]; ring1 => Process.SetTimeout[@info.ringDetCondition, ringIntTicks+breakIntTicks]; ring => Process.SetTimeout[@info.ringDetCondition, ringIntTicks]; between => Process.SetTimeout[@info.ringDetCondition, breakIntTicks]; ENDCASE; }; WAIT info.ringDetCondition; RETURN[ TRUE ]; }; DO stillRunning:BOOL_ RingDetProcEntry[info]; IF event#reset THEN smartsInfo.ParseEvent[smartsInfo, [info.ringChangeTime, ringDetect, event ] ]; IF ~stillRunning THEN RETURN; ENDLOOP; }; InterpretHookState: PUBLIC ENTRY PROC [ info: LarkInfo, rawEvent: Lark.StatusEvent, sInfo: SmartsInfo ] RETURNS [ processedEvent: Lark.StatusEvent ] = { ENABLE UNWIND=>NULL; event: Lark.Event = rawEvent.event; ev: EvType; newState: HookState; oldType: TerminalType_info.terminalType; processedEvent.device _ nothing; ev _ SELECT rawEvent.device FROM hookSwitch => SELECT event FROM Lark.enabled => IF info.monitor THEN spMon ELSE tsOn, Lark.disabled => tsOff, ThSmartsPrivate.click => spClick, ENDCASE=> spNone, speakerSwitch => SELECT event FROM Lark.enabled => spOn, Lark.disabled => spOff, ThSmartsPrivate.click => spClick, ENDCASE => spNone, ENDCASE => spNone; processedEvent _ rawEvent; IF ev = spNone THEN { processedEvent.event _ SELECT rawEvent.device FROM keyboard => SELECT event FROM '[ => enabled, '] => disabled, '\n => endNum, ENDCASE => event, touchPad => SELECT event FROM bThorp => endNum, bStar => '*, IN Lark.DTMFEvent => event - (FIRST[Lark.DTMFEvent]-'0), ENDCASE=>event, ENDCASE => event; RETURN; }; newState _ newStates[info.hookState][ev]; processedEvent.device _ IF newState=onhook OR info.hookState=onhook THEN hookSwitch ELSE nothing; IF event=ThSmartsPrivate.click THEN processedEvent.event_disabled; info.hookState _ newState; info.terminalType _ std; SELECT newState FROM onhook => NULL; telset, both, bOth => IF info.radio THEN info.terminalType _ radio; spkr, sPkr, spKr => info.terminalType _ IF info.radio THEN radio ELSE spkr; monitor => info.terminalType _ monitor; ENDCASE=> VoiceUtils.Problem[, $Lark, info]; IF oldType#info.terminalType THEN ThSmartsPrivate.EnterLarkSt[info, info.larkState, sInfo]; }; CheckHookState: PUBLIC ENTRY PROC [info: LarkInfo ] RETURNS [ onHook: BOOL_TRUE ] = { ENABLE RPC.CallFailed => IF pd.callTimeoutOK THEN RESUME ELSE GOTO Failed; reverted, wasReverted: BOOL_FALSE; which: CARDINAL; DO which_0; reverted _ FALSE; DO events: Lark.StatusEvents; [which, events] _ info.interface.WhatIsStatus[info.shh, which]; FOR i: NAT IN [0..events.length) DO SELECT events[i].event FROM enabled => SELECT events[i].device FROM hookSwitch => { onHook_FALSE; info.interface.Commands[shh: info.shh, events: assertARelay]; }; revertHookswitch => IF ~wasReverted THEN reverted _ wasReverted _ TRUE; ENDCASE; ENDCASE; ENDLOOP; IF which=0 THEN EXIT; ENDLOOP; IF reverted THEN { info.interface.Commands[shh: info.shh, events: unRevHS]; LOOP; }; EXIT; ENDLOOP; EXITS Failed => onHook_FALSE; }; EvType: TYPE = { tsOn, tsOff, spOn, spOff, spClick, spMon, spNone }; newStates: ARRAY HookState OF ARRAY EvType OF HookState _ [ [ telset, onhook, sPkr, onhook, onhook, monitor, onhook ], -- onhook [ telset, onhook, bOth, telset, telset, monitor, onhook ], -- telset [ telset, spkr, spKr, onhook, onhook, monitor, onhook ], -- spkr (speakerphone mode but switch in middle) [ bOth, sPkr, sPkr, onhook, spkr, bOth, onhook ], -- sPkr (speaker switch is up) [ bOth, sPkr, sPkr, onhook, onhook, bOth, onhook ], -- spKr (sPkr, but click turns off - speaker switch in middle or up.) Scenario goes like this: we were in spkr mode and we saw an spOn. Next we might see an spClick, in which case this is a click off (=down+up) so we go onhook. However, it might also be a click on (=up), in which case this situation could persist and has to be considered the same as sPkr. [ both, spkr, both, telset, telset, both, onhook ], -- both (handset offhook, speaker switch in middle or up; click reverts to telset) [ bOth, sPkr, bOth, telset, both, bOth, onhook ], -- bOth (handset offhook, speaker switch up) [ monitor, onhook, bOth, sPkr, monitor, monitor, onhook ] ]; -- monitor ViewCmd: Commander.CommandProc = TRUSTED { Nice.View[pd, "Lark In PD"]; }; unRevHS: Lark.CommandEvents _ NEW[Lark.CommandEventSequence[1]]; assertARelay: Lark.CommandEvents _ NEW[Lark.CommandEventSequence[1]]; unRevHS[0] _ [revertHookswitch, disabled]; assertARelay[0] _ [aRelay, enabled]; Commander.Register["VuLarkIn", ViewCmd, "Program Management variables for Lark Input"]; }. ~LarkInImpl.mesa Copyright c 1985, 1986 by Xerox Corporation. All rights reserved. Last modified by D. Swinehart, May 17, 1986 4:16:22 pm PDT Polle Zellweger (PTZ) July 18, 1986 11:06:56 am PDT ***************** External Procedures ******************** Handles smarts-independent filtering, events that need timing. Interpret event, possibly filter some out. React to upstrokes, not downstrokes. 0-key Rollover is a side-effect. Try it. Only pass on index marker notifications. Swallow or handle all others. Assume Prose XON / XOFF disabled. Assume only get the following responses: On pReset: pResetConfirmOK if everything's okay cmdLeader <0-16> pResetConfirmEnd otherwise Index marker response: Undetermined problem: BEL For now, we'll assume that this was a successful dictionary entry response. It's okay to skip ahead in the queue. Except for 1st item in a conversation, which follows an initial RESET, should be to some entry with queueIt=FALSE. Don't report skipped entries as finished; FinchSmarts will take care of skipping ahead in its queue. (May want to add a proseSpec.type = flushed?) ThSmartsPrivate.pResetConfirmEnd => { -- this case is now the same as stopAndFlushEnd IF Convert.IntFromRope[info.proseResponse] # 0 THEN ThSmartsPrivate.ProseControlDone[info, ThSmartsPrivate.proseFailure, sInfo] -- fail!!!; ELSE { ThSmartsPrivate.ProseControlDone[info, ThSmartsPrivate.flushMarker, sInfo]; info.flushJustFinished _ TRUE; }; }; Avoid deadlock - shouldn't call Smarts-level entry procs while holding the LarkIn/Out lock. newly entered state Filters only events whose device codes are hookswitch and speakerSwitch Implements another state machine via SELECT Translate characters from various devices into common set Determine if either of telset or speakerphone is activated. Assert aRelay and unrevert hookswitch spOn is transition away from middle on speaker switch spOff is transition to middle if it's been more than a few hundred milliseconds spClick is transition to middle if it's been less than a few hundred milliseconds -- spClick is always preceded by spOn. Note: spNone transitions are never taken. Swinehart, August 6, 1985 12:10:40 pm PDT Incorporate PTZ changes changes to: DIRECTORY, LarkInImpl, RecordEvent, HandleProseOutput, InterpretSpeakerSwitch Polle Zellweger (PTZ) August 7, 1985 6:36:35 pm PDT Comments only. changes to: EvType, newStates Polle Zellweger (PTZ) August 22, 1985 5:20:05 pm PDT Handle Prose flushing; remove deadlock from HandleProseOutput. changes to: DIRECTORY, RecordEvent, HandleProseOutput, HandleAndReport Polle Zellweger (PTZ) August 23, 1985 2:10:02 pm PDT Input events from the Prose Lark are being interpreted as smarts-level parseable events. Raise error for odd devices. changes to: RecordEvent Polle Zellweger (PTZ) August 23, 1985 2:34:28 pm PDT changes to: RecordEvent, HandleProseOutput Polle Zellweger (PTZ) August 27, 1985 8:57:45 pm PDT Allow for Prose Reset command. changes to: DIRECTORY, HandleProseOutput Polle Zellweger (PTZ) August 29, 1985 5:46:33 pm PDT changes to: HandleProseOutput Polle Zellweger (PTZ) December 11, 1985 11:50:38 pm PST changes to: HandleProseOutput Swinehart, May 16, 1986 4:14:03 pm PDT Cedar 6.1 changes to: DIRECTORY, LarkInImpl, DebEvent, InterpretHookState Polle Zellweger (PTZ) July 17, 1986 6:26:10 pm PDT changes to: HandleProseOutput Polle Zellweger (PTZ) July 18, 1986 11:06:56 am PDT changes to: DIRECTORY Êœ™Icodešœ Ïmœ7™BJšœ:™:K™3—J˜šÏk ˜ Jšžœ˜Jšœ žœ˜*Jšœžœ˜Jšœžœ¤žœ˜µJ˜J˜ J˜Jšžœžœ˜Jšœžœžœ˜.Jšœžœ,˜9Jšœžœ˜$šœžœ˜Jšœ÷˜÷—Jš œžœžœžœžœ˜IJšœžœ˜Jšœ žœ˜$J˜J˜—šœ ž œžœžœ˜9šž˜Jšœ$žœžœ,˜l—Jšžœ˜&—Jšžœžœ˜J˜Jšžœžœžœžœžœžœžœ˜JJšœ žœ˜,Jšœ žœ˜*J˜2Jšœ žœ˜-Jšœ žœ˜.Jšœžœ˜)Jšœžœ ˜2Jšžœžœ žœ˜J˜J˜!Jšœ#˜#J˜!Jšœ%˜%J˜J˜šžœžœžœ˜JšœžœžœÏc2˜LJ˜—Jš œžœžœžœžœ˜J˜Jšœ=™=J˜J˜šÏnœžœ+žœ˜AJš œžœžœžœžœ˜šœ˜šœžœ˜ Jš žœžœžœžœžœ˜AJšžœžœžœ˜ —Jšœžœžœ žœ˜,—Jšžœžœ˜3Jšžœžœžœ žœ˜BJšœA˜AJšœ˜—J˜Jšœ žœžœŸ1˜Fš  œžœžœž œA˜jJšžœ ž œ˜J™>Jšœ˜JšœK˜KJ˜#Jšœ˜J˜Jšžœ žœžœžœžœžœžœ˜IJ˜ šžœžœž˜3J˜+Jšžœžœ˜4Jš žœ žœžœžœžœ˜KJ™*šžœž˜šœž˜J˜%J˜B—šœ ˜ JšœC˜CJšžœ˜J˜—Jšžœ˜—šžœž˜J˜?Jšœ1žœ"˜Tšœ ˜ J™OJšžœžœ+˜Hšžœ˜Jšœ,žœŸ ˜RJ˜—Jšžœžœžœ˜ J˜—šœ ˜ Kšžœžœ+˜DKšžœ˜K˜—Jšœžœ˜Jšžœ˜—Jšžœžœžœ˜#Jšœ>˜>Jšžœ˜ ——J˜š  œž œ˜Jšœ žœ žœžœ˜\Jšžœ žœ˜Jšžœ˜Jšœ˜—J˜Jšœ«ž™®š  œžœžœDžœžœ˜‰Jšœžœ˜šžœž˜ JšžœžœŸ˜*Jšžœžœ&Ÿ˜EJšœžœŸ˜'šœ$˜$JšœK˜KJšœžœ˜J˜—šœ#˜#Jšœžœ˜ šžœ#žœžœ˜1KšœK™K—Kšœ1˜1šžœ*ž˜0Jšœ5˜5—šžœ˜Kšœ5˜5Kšžœžœžœ˜šžœžœ˜ Kšœ­™­šžœ8žœžœž˜MKšžœ!žœ ˜4Kšžœ˜—Kšœžœ˜K˜—šžœžœ˜'Kšœ˜KšœŸ˜7Jšžœžœžœžœ˜-J˜—šž˜JšœMŸ ˜W—J˜—J˜—šœV™Všžœ,ž™3JšœLŸ œ™W—šžœ™JšœK™KJšœžœ™J™—J™—JšžœK˜R—Jšœ˜—J˜š œžœH˜]J™[KšœD˜DKšžœžœžœ,˜:K˜J˜—š œžœ*˜FJšžœ'Ÿœ˜>Jšœ žœžœ˜8J˜šžœž˜J˜'Jšœ žœ˜Jšžœžœ˜—Jšžœžœžœžœ˜:J˜0J˜—Jšœžœ˜J˜š œžœžœZ˜yJšžœEŸœ˜\Jšžœžœžœ˜Jšœ žœžœ"˜>J˜!J˜"šžœžœ˜Jš œ žœžœžœžœžœ˜NJš œ žœžœžœžœ˜IJšžœžœ˜—šžœž˜šœžœŸ˜%J˜J˜J˜.Jšœžœ=˜P—šœ Ÿ˜ šžœžœžœ˜?J˜J˜>——šœ Ÿœ˜!J˜—šœ Ÿ˜Jšœžœžœ žœ ˜I—šœ Ÿ˜ Jšœžœžœžœ ˜G—Jšžœ˜—Jšžœ)žœžœ˜PJ˜—JšœžœŸ˜'Jšœžœ Ÿ0˜NJšœžœ Ÿ0˜OJ˜HJ˜@J˜BJ˜J˜š  œžœ;žœ˜YJ˜%J˜š  œžœžœžœžœŸ œ˜XJšžœžœžœ˜Jšœžœžœžœ˜[J˜šžœžœ žœŸ ˜Ešžœž˜JšœžœžœŸ˜Jšœ7žœžœ˜GJšœ+˜+Jšœ%Ÿ˜+Jšžœ˜——Jšœ™Jšœ*˜*šžœžœž˜'Jšœžœžœ˜-JšœF˜FJšœP˜PJšœA˜AJšœE˜EJšžœ˜J˜—Jšžœ˜Jšžœžœ˜—šž˜Jšœ žœ˜*šžœ ž˜JšœN˜N—Jšžœžœžœžœ˜)—J˜—š œžœžœž˜%šœA˜AJšžœ)˜0—Jšœ+Ïb œ¡ ™GJšœ%¡™+Jšžœžœžœ˜J˜#J˜ J˜J˜(J˜ šœžœž˜ šœžœž˜Jšœžœžœžœ˜MJšœ"žœ ˜3—šœžœž˜"Jšœ-˜-Jšœ"žœ ˜4—Jšžœ ˜—J˜šžœ žœ˜J™9šœžœž˜2šœ žœž˜J˜J˜J˜Jšžœ ˜—šœ žœž˜J˜J˜ Jšžœžœ˜8Jšžœ˜—Jšžœ ˜—Jšžœ˜šœ˜J˜——Jšœ)˜)šœžœžœ˜CJšžœ žœ ˜—Jšžœžœ˜BJ˜Jšœ˜šžœ ž˜Jšœ žœ˜Jšœžœ žœ˜DJšœ(žœ žœžœ˜KJšœ'˜'Jšžœ%˜,—šžœž˜!Jšœ9˜9—Jšœ˜—J˜J˜š œžœžœž˜!Jšœžœ žœžœ˜3J™;Jšžœžœžœžœžœžœžœ˜JJšœžœžœ˜"Jšœžœ˜šž˜J˜Jšœ žœ˜šž˜J˜J˜?šžœžœžœž˜#šžœž˜šœ žœž˜'šœ˜Jšœžœ˜ Jšœ=˜=J˜—Jšœžœžœžœ˜GJšžœ˜—Jšžœ˜—Jšžœ˜—Jšžœ žœžœ˜Jšžœ˜—šžœ žœ˜J™%Jšœ8˜8Jšžœ˜J˜—Jšžœ˜Jšžœ˜—šž˜Jšœžœ˜—J˜J˜—šœžœ8˜DJ™5J™OJ™xJ™)—J˜š œ žœ žœžœžœ˜;Jšœ;Ÿ ˜DJšœ=Ÿ ˜FJšœ:Ÿ0˜jJšœ6Ÿ˜TJšœ5Ÿè˜Jšœ:ŸR˜ŒJšœ8Ÿ,˜dJšœ=Ÿ ˜GJ˜—J˜šœ!žœ˜*J˜Jšœ˜J˜—Jšœžœ˜@Jšœ#žœ˜EJšœ*˜*Jšœ$˜$J˜JšœW˜WJ˜™)K™Kšœ ÏrM™Y—™3K™Kšœ ¢™—™4Kšœ>™>Kšœ ¢:™F—™4K™vKšœ ¢ ™—™4Kšœ ¢™*—™4K™Kšœ ¢™(—™4Kšœ ¢™—™7Kšœ ¢™—™&K™ Kšœ ¢3™?—™2Kšœ ¢™—™3Kšœ ¢ ™—K™—…—3ÐP=