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, RefID USING [ ID, Reseal ], RPC USING [ CallFailed ], Rope USING [ Concat, FromChar, ROPE ], Process USING [ Detach, MsecToTicks, SetTimeout ], ThPartyPrivate USING [ SmartsData ], ThSmartsPrivate USING [ click, EnterLarkSt, flushMarker, GetSmartsInfo, HookState, indexMarkerEnd, LarkInfo, LarkProseQueue, LarkState, maxClientMarker, pResetConfirmEnd, ProseControlDone, proseFailure, ReportProseDone, RingDetState, SmartsInfo, stopAndFlushEnd, TerminalType, TonesDone ], Thrush USING[ ProseSpec, ROPE, SHHH, SmartsID ], ThNet USING [ pd ], VoiceUtils USING [ Problem, Report ] ; LarkInImpl: CEDAR MONITOR LOCKS info USING info: LarkInfo IMPORTS LarkRpcControl, Commander, Convert, IO, Nice, Process, RefID, Rope, RPC, ThNet, ThSmartsPrivate, VoiceUtils EXPORTS LarkSmarts, ThSmartsPrivate= { OPEN IO; Reseal: PROC[r: REF] RETURNS[RefID.ID] = INLINE {RETURN[RefID.Reseal[r]]; }; HookState: TYPE = ThSmartsPrivate.HookState; LarkInfo: TYPE = ThSmartsPrivate.LarkInfo; RingDetState: TYPE = ThSmartsPrivate.RingDetState; SmartsData: TYPE = ThPartyPrivate.SmartsData; SmartsInfo: TYPE = ThSmartsPrivate.SmartsInfo; SmartsID: TYPE = Thrush.SmartsID; 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. debounceInterval: INTEGER _ 300, -- ms. breakInterval: INTEGER _ 4500 -- ms., 4 sec. nominal, 500 ms. benefit of doubt ]; 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.SmartsID, whatHappened: Lark.StatusEvents] RETURNS [ success: BOOL_TRUE ] = { smartsInfo: SmartsInfo = ThSmartsPrivate.GetSmartsInfo[smartsID: smartsID]; parseInfo: SmartsInfo _ smartsInfo; info: LarkInfo; parseSmartsID: SmartsID; IF smartsInfo=NIL OR (info _ smartsInfo.larkInfo)=NIL THEN RETURN[FALSE]; parseSmartsID _ smartsInfo.smartsID; 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 => { parseSmartsID _ smartsInfo.otherSmartsID; parseInfo _ ThSmartsPrivate.GetSmartsInfo[smartsID: parseSmartsID]; }; tones => { ThSmartsPrivate.TonesDone[smartsInfo.larkInfo, sEvent]; LOOP; }; ENDCASE; SELECT sEvent.device FROM speakerSwitch => sEvent _ InterpretSpeakerSwitch[info, sEvent]; ringDetect => sEvent _ InterpretRingDetect[info, 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 => ERROR; IF sEvent.device=nothing THEN LOOP; parseInfo.ParseEvent[ smartsInfo: parseInfo, sEvent: sEvent ]; ENDLOOP; }; EventRope: PUBLIC PROC[ shh: Thrush.SHHH, smartsID: SmartsID, 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]; info.flushJustFinished _ TRUE; }; ThSmartsPrivate.indexMarkerEnd => { marker: INT _ Convert.IntFromRope[info.proseResponse]; IF marker > ThSmartsPrivate.maxClientMarker THEN ThSmartsPrivate.ProseControlDone[info, marker] ELSE { pQ: ThSmartsPrivate.LarkProseQueue _ info.proseQueue; IF pQ=NIL THEN ERROR; 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]; -- fail!!! }; }; ThSmartsPrivate.pResetConfirmEnd => { IF Convert.IntFromRope[info.proseResponse] # 0 THEN ThSmartsPrivate.ProseControlDone[info, ThSmartsPrivate.proseFailure] -- fail!!!; ELSE { ThSmartsPrivate.ProseControlDone[info, ThSmartsPrivate.flushMarker]; info.flushJustFinished _ TRUE; }; }; 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; IF interval < 0 OR interval > spClickInterval THEN RETURN; processedEvent.event _ ThSmartsPrivate.click; }; spClickInterval: INTEGER _ 500; InterpretRingDetect: ENTRY PROC[info: LarkInfo, 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; timeout: BOOL _ FALSE; 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 => info.ringDetState _ maybe; between => { info.ringDetState _ ring; processedEvent _ sEvent; }; -- generate new offhook maybe => IF interval info.ringDetState _ between; ENDCASE; info.ringDetInstance _ info.ringDetInstance+1; BROADCAST info.ringDetCondition; -- earlier timeouts zap themselves. IF info.ringDetState = $idle THEN RETURN; TRUSTED { Process.Detach[FORK RingTimeout[info, info.ringDetInstance]]; }; }; RingTimeout: PROC[info: LarkInfo, instance: INT] = { RTEntry: ENTRY PROC[info: LarkInfo] RETURNS[event: Lark.Event_reset] = TRUSTED { -- Process is unsafe ENABLE UNWIND=>NULL; timeout: INTEGER _ pd.breakInterval; IF instance#info.ringDetInstance THEN RETURN; SELECT info.ringDetState FROM $idle => RETURN; $maybe => timeout _ pd.debounceInterval; ENDCASE; Process.SetTimeout[@info.ringDetCondition, Process.MsecToTicks[timeout]]; WAIT info.ringDetCondition; IF info.ringDetInstance#instance THEN RETURN; -- events intervened SELECT info.ringDetState FROM -- timed out $idle => RETURN; -- ?? $maybe => { event _ enabled; info.ringDetState _ $ring; }; -- now ringing ENDCASE => { event _ disabled; info.ringDetState _ $idle; }; -- too long }; event: Lark.Event _ RTEntry[info]; IF event # reset THEN info.larkTrunkSmartsInfo.ParseEvent[ info.larkTrunkSmartsInfo, [info.ringChangeTime, ringDetect, event ] ]; IF event = enabled THEN RingTimeout[info, instance]; -- wait for no-longer-ringing timeout }; 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; 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 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; { ProblemBool: PROC RETURNS[TerminalType] = {VoiceUtils.Problem[,$Lark,info]; RETURN[$std];}; info.terminalType _ SELECT newState FROM onhook => std, telset, both, bOth => -- IF info.radio THEN radio ELSE -- std, spkr, sPkr, spKr => -- IF info.radio THEN radio ELSE -- spkr, monitor => monitor, ENDCASE=> ProblemBool[]; }; IF newState#onhook AND 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 by Xerox Corporation. All rights reserved. Last modified by D. Swinehart, December 8, 1985 4:02:38 pm PST Polle Zellweger (PTZ) August 29, 1985 5:46:32 pm 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 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?) Avoid deadlock - shouldn't call Smarts-level entry procs while holding the LarkIn/Out lock. Generates one "enabled" for every ring detect (with a delay for possible glitches the first time), and a single "disabled" when the last ring has been gone too long. See ThSmartsPrivate.LarkInfo. Bold states occur only when event is enabled, others only when disabled ELSE: The debounce timeout will soon occur and generate the offhook event Filters only events whose device codes are hookswitch and speakerSwitch Implements another state machine via SELECT Translate characters from various devices into common set That one needs explaining. In fact, clicks need explaining somewhere central. When newState is onhook, the lark state will soon be idle, and this is just a distraction. 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 Swinehart, October 28, 1985 11:54:20 am PST Handle => ID, Log => VoiceUtils changes to: DIRECTORY, LarkInImpl, Reseal, SmartsID, RecordEvent, EventRope, HandleProseOutput, InterpretSpeakerSwitch, InterpretRingDetect, RingDetProc, InterpretHookState, ProblemBool Swinehart, November 29, 1985 11:17:56 am PST When going on hook, don't react to changes in terminal type, since the terminal will soon be put idle by other actions. changes to: InterpretHookState ÊV˜šœ™Icodešœ Ïmœ1™™>K™4—J˜šÏk ˜ Jšžœ˜Jšœ žœ˜*Jšœžœ˜Jšœžœ¤žœ˜µJ˜J˜ J˜Jšœžœžœ ˜Jšžœžœ˜Jšœžœžœ˜&Jšœžœ%˜2Jšœžœ˜$šœžœ˜Jšœ‰˜‰—Jšœžœ žœžœ ˜0Jšœžœ˜Jšœ žœ˜$J˜J˜—šœ ž œžœžœ˜9šž˜Jšœ$žœžœ$˜k—Jšžœ˜&—Jšžœžœ˜J˜JšÏnœžœžœžœžœžœžœ˜LJšœ žœ˜,Jšœ žœ˜*J˜2Jšœ žœ˜-Jšœ žœ˜.Jšœ žœ˜!Jšœžœ ˜2Jšžœžœ žœ˜J˜J˜!Jšœ#˜#J˜!Jšœ%˜%J˜J˜šžœžœžœ˜JšœžœžœÏc2˜MJšœžœ ˜'Jšœžœ 0˜NJ˜—Jš œžœžœžœžœ˜J˜Jšœ=™=J˜J˜šŸœžœ+žœ˜AJš œžœžœžœžœ˜šœ˜šœžœ˜ Jš žœžœžœžœžœ˜AJšžœžœžœ˜ —Jšœžœžœ žœ˜,—Jšžœžœ˜3Jšžœžœžœ žœ˜BJšœA˜AJšœ˜—J˜Jšœ žœžœ 1˜FšŸ œžœžœž œ=˜fJšžœ ž œ˜J™>Jšœ˜JšœK˜KJšœ#˜#Jšœ˜J˜Jšžœ žœžœžœžœžœžœ˜IJ˜$šžœžœž˜3J˜+Jšžœžœ˜4Jš žœ žœžœžœžœ˜KJ™*šžœž˜šœ˜J˜)JšœC˜CJ˜—šœ ˜ Jšœ7˜7Jšžœ˜J˜—Jšžœ˜—šžœž˜J˜?Jšœ9˜9šœ ˜ J™OJšžœžœ+˜Hšžœ˜Jšœ,žœ  ˜RJ˜—Jšžœžœžœ˜ J˜—šœ ˜ Kšžœžœ+˜DKšžœ˜K˜—Jšœžœ˜Jšžœžœ˜—Jšžœžœžœ˜#Jšœ>˜>Jšžœ˜ ——J˜šŸ œž œ˜Jšœ žœžœžœ˜XJšžœ žœ˜Jšžœ˜Jšœ˜—J˜Jšœ«ž™®š ŸœžœžœDžœžœ˜‰Jšœžœ˜šžœž˜ Jšžœžœ ˜*Jšžœžœ ˜Jšœ žœžœ˜8J˜šžœž˜J˜'Jšœ žœ˜Jšžœžœ˜—Jšžœžœžœžœ˜:J˜0J˜—Jšœžœ˜J˜šŸœžœžœ*˜IJšžœF˜MJ™ÄJšžœžœžœ˜Jšœ žœžœ"˜>J˜!Jšœ žœžœ˜J˜"šžœžœ˜Jš œ žœžœžœžœžœ˜NJš œ žœžœžœžœ˜IJšžœžœ˜—šžœž˜JšœG™GJšÏbœ˜"Jš¡œ< ˜Zš œ žœžœžœžœ˜QJšžœE™I—Jšœ$˜$Jšžœ˜—J˜.Jšž œ;˜DJšžœžœžœ˜)Jšžœžœ-˜JJšœ˜—J˜J˜šŸ œžœžœ˜4š Ÿœžœžœžœžœ ˜eJšžœžœžœ˜Jšœ žœ˜$Jšžœžœžœ˜-šžœž˜Jšœ žœ˜Jšœ(˜(Jšžœ˜—JšœI˜IJšžœ˜Jšžœžœžœ ˜Bšžœžœ  ˜*Jšœ žœ ˜Jšœ; ˜IJšžœ6  ˜H—J˜—Jšœ"˜"šžœž˜šœ$˜$JšœF˜F——Jšžœžœ %˜ZJšœ˜J˜—šŸœžœžœž˜%šœA˜AJšžœ)˜0—Jšœ+¡ œ¡ ™GJšœ%¡™+Jšžœžœžœ˜J˜#J˜ J˜J˜(šœžœž˜ šœžœž˜Jšœ $œžœ˜=Jšœ˜Jšœ!˜!Jšžœ ˜—šœžœž˜"Jšœ˜Jšœ˜Jšœ!˜!Jšžœ ˜—Jšžœ ˜—J˜šžœ žœ˜J™9šœžœž˜2šœ žœž˜J˜J˜ Jšžœžœ˜8Jšžœ˜—Jšžœ ˜—Jšžœ˜šœ˜J˜——Jšœ)˜)šœžœžœ˜CJšžœ žœ ˜—šžœžœ˜BJ™P—J˜šœ˜JšŸ œžœžœ3žœ ˜[šœžœ ž˜(J˜Jšœ %œ˜@Jšœ !œ ˜?Jšœ˜Jšžœ˜—J˜—šžœžœž˜5J™ZJšœ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šœ ¢™—™+K™Kšœ ¢­™¹—™,K™wKšœ ¢™—K™—…—0hLê