DIRECTORY Feedback, FeedbackClasses, FeedbackConcreteTypes, FeedbackOps, FeedbackTypes, IO, Labels, MessageWindow, Process, RefTab, Rope, ViewerClasses, ViewerIO, ViewerOps, ViewerPrivate; FeedbackOpsImpl: CEDAR MONITOR LOCKS script USING script: Script IMPORTS Feedback, FeedbackClasses, IO, Labels, MessageWindow, Process, RefTab, Rope, ViewerIO, ViewerOps, ViewerPrivate EXPORTS FeedbackOps = BEGIN OPEN Feedback; Viewer: TYPE = ViewerClasses.Viewer; LOR: TYPE ~ LIST OF ROPE; gTypescripts: RefTab.Ref _ RefTab.Create[]; -- all of the named typescripts that FeedbackOps knows about Script: TYPE = REF ScriptObj; ScriptObj: TYPE = MONITORED RECORD [ viewer: Viewer, -- viewer can be NIL, if stream does not belong to a viewer stream: IO.STREAM, typescriptName: ATOM, storing: BOOL, queueHead, queueTail: FList _ NIL, --list of PutF tasks to do putter: PROCESS _ NIL, --the process, if any, doing PutFs change: CONDITION ]; FList: TYPE ~ REF FCons; FCons: TYPE ~ RECORD [ rest: FList, first: SELECT kind: * FROM blink => [], putf => [format: Rope.ROPE, v1, v2, v3, v4, v5: IO.Value], putc => [c: CHAR], ENDCASE]; blinkF: FCons ~ [NIL, blink[]]; CreateNamedTypescript: PUBLIC PROC [headerText: Rope.ROPE, typescriptName: ATOM, openHeight: NAT _ 120, storing: BOOL _ FALSE] RETURNS [alreadyExists: BOOL _ FALSE, typescript: Viewer] = { newStream: IO.STREAM; script: Script _ FindScript[typescriptName]; IF script=NIL OR script.viewer=NIL OR script.viewer.destroyed THEN { typescript _ ViewerOps.CreateViewer[ flavor: $TypeScript, info: [name: headerText, menu: NIL, data: NIL, iconic: TRUE, column: right, scrollable: TRUE, icon: unInit], paint: FALSE]; ViewerOps.SetOpenHeight[typescript, openHeight]; ViewerOps.OpenIcon[icon: typescript, closeOthers: FALSE, bottom: TRUE, paint: TRUE]; [, newStream] _ ViewerIO.CreateViewerStreams[headerText, typescript, NIL, TRUE]; IF script=NIL THEN { script _ NEW[ScriptObj _ [viewer: typescript, stream: newStream, typescriptName: typescriptName, storing: storing]]; TRUSTED {Process.InitializeCondition[@script.change, Process.MsecToTicks[1D4]]}; [] _ gTypescripts.Store[typescriptName, script]; } ELSE SetStuff[script, newStream, typescript, storing]; } ELSE { -- nothing wrong with the current typescript alreadyExists _ TRUE; typescript _ script.viewer}; }; CreateTypescriptFromStream: PUBLIC PROC [stream: IO.STREAM, typescriptName: ATOM, storing: BOOL _ FALSE] RETURNS [alreadyExists: BOOL _ FALSE, oldStream: IO.STREAM _ NIL] = { script: Script _ FindScript[typescriptName]; IF script=NIL THEN { newScript: Script _ NEW[ScriptObj _ [viewer: NIL, stream: stream, typescriptName: typescriptName, storing: storing]]; TRUSTED {Process.InitializeCondition[@script.change, Process.MsecToTicks[1D4]]}; [] _ gTypescripts.Store[typescriptName, newScript]; } ELSE { alreadyExists _ TRUE; oldStream _ script.stream; SetStuff[script, stream, NIL, storing]; }; }; FindScript: PROC [typescriptName: ATOM] RETURNS [script: Script _ NIL] = { found: BOOL _ FALSE; val: REF; [found, val] _ gTypescripts.Fetch[typescriptName]; IF found THEN script _ NARROW[val]; }; GetTypescriptStream: PUBLIC PROC [typescriptName: ATOM] RETURNS [IO.STREAM] = { script: Script _ FindScript[typescriptName]; IF script = NIL THEN RETURN[NIL]; RETURN[script.stream]; }; GetTypescripts: PUBLIC PROC [] RETURNS [names: LIST OF ATOM] = { AddToList: PROC [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOL _ FALSE] = { names _ CONS[NARROW[key, ATOM], names]; }; [] _ gTypescripts.Pairs[AddToList]; }; FeedbackData: TYPE = REF FeedbackDataObj; FeedbackDataObj: TYPE = RECORD [ lp: RECORD [label: Viewer, blink: BOOL] _ [NIL, FALSE], tn: ATOM _ NIL, default: FeedbackData _ NIL, bounded: BOOL _ TRUE ]; messageWindow: PUBLIC Viewer ~ ViewerPrivate.messageWindow; noLabel: Viewer ~ NEW [ViewerClasses.ViewerRec]; Iv: PROC [v: Viewer] RETURNS [Viewer] ~ INLINE {RETURN [IF v=NIL THEN noLabel ELSE v]}; Ov: PROC [v: Viewer] RETURNS [Viewer] ~ INLINE {RETURN [IF v=noLabel THEN NIL ELSE v]}; It: PROC [a: ATOM] RETURNS [ATOM] ~ INLINE {RETURN [IF a=NIL THEN $None ELSE a]}; Ot: PROC [a: ATOM] RETURNS [ATOM] ~ INLINE {RETURN [IF a=$None THEN NIL ELSE a]}; CreateViewersHandler: PUBLIC PROC [typescriptName: ATOM _ $None, label: Viewer _ NIL, blink: BOOL _ FALSE] RETURNS [MsgHandler] ~ { fd: FeedbackData ~ NEW [FeedbackDataObj _ [[Iv[label], blink], typescriptName]]; IF label=NIL THEN label _ noLabel; RETURN FeedbackClasses.CreateHandler[VPutF, VClearHerald, VBlink, fd]}; IsViewersHandler: PUBLIC PROC [mh: MsgHandler] RETURNS [is: BOOL, typescriptName: ATOM _ $None, label: Viewer _ NIL, blink: BOOL _ FALSE] ~ { WITH FeedbackClasses.GetHandlerData[mh] SELECT FROM fd: FeedbackData => RETURN [TRUE, fd.tn, Ov[fd.lp.label], fd.lp.blink]; ENDCASE => RETURN [FALSE]}; HandleToLabel: PUBLIC PROC [vh: MsgHandler, label: Viewer, blink: BOOL _ FALSE] ~ { WITH FeedbackClasses.GetHandlerData[vh] SELECT FROM fd: FeedbackData => fd.lp _ [Iv[label], blink]; ENDCASE => ERROR Problem["not a Viewers handler"]}; HandleToTypescript: PUBLIC PROC [vh: MsgHandler, typescriptName: ATOM _ $None] ~ { WITH FeedbackClasses.GetHandlerData[vh] SELECT FROM fd: FeedbackData => fd.tn _ typescriptName; ENDCASE => ERROR Problem["not a Viewers handler"]}; SetFD: PROC [router: MsgRouter, msgClass: MsgClass, label: Viewer, blink: BOOL, tn: ATOM] = { mh: MsgHandler; dh: MsgHandler _ GetHandler[router, $Default]; dd: FeedbackData _ IF dh=NIL THEN NIL ELSE WITH FeedbackClasses.GetHandlerData[dh] SELECT FROM x: FeedbackData => x, ENDCASE => NIL; IF msgClass=$Every OR msgClass=$Default THEN { e: BOOL ~ msgClass=$Every; toclear: LIST OF MsgClass _ NIL; PerDirection: PROC [msgClass: MsgClass, msgHandler: MsgHandler] RETURNS [BOOL] ~ { WITH FeedbackClasses.GetHandlerData[msgHandler] SELECT FROM x: FeedbackData => IF e THEN { IF label#NIL THEN x.lp _ [label, blink]; IF tn#NIL THEN x.tn _ tn} ELSE x.default _ dd; ENDCASE => IF e THEN toclear _ CONS[msgClass, toclear]; RETURN [FALSE]}; IF dd#NIL THEN { IF label#NIL THEN dd.lp _ [label, blink]; IF tn#NIL THEN dd.tn _ tn} ELSE { dd _ NEW [FeedbackDataObj _ [[Iv[label], blink], It[tn]]]; dh _ FeedbackClasses.CreateHandler[VPutF, VClearHerald, VBlink, dd]; [] _ SetHandler[router, $Default, dh]}; IF ScanHandlers[router, PerDirection].stopped THEN ERROR; SetMultiHandler[router, toclear, NIL]; RETURN}; mh _ GetHandler[router, msgClass]; IF mh#NIL THEN WITH FeedbackClasses.GetHandlerData[mh] SELECT FROM x: FeedbackData => { IF label#NIL THEN x.lp _ [label, blink]; IF tn#NIL THEN x.tn _ tn; RETURN}; ENDCASE => NULL; mh _ FeedbackClasses.CreateHandler[VPutF, VClearHerald, VBlink, NEW [FeedbackDataObj _ [[label, blink], tn, dd]]]; [] _ SetHandler[router, msgClass, mh]; RETURN}; GetFD: PROC [router: MsgRouter, msgClass: MsgClass] RETURNS [fd: FeedbackData] = { mh: MsgHandler _ GetHandler[router, msgClass]; IF mh#NIL THEN WITH FeedbackClasses.GetHandlerData[mh] SELECT FROM x: FeedbackData => RETURN [x]; ENDCASE => NULL; RETURN [NIL]}; SetLabel: PUBLIC PROC [router: MsgRouter, label: Viewer, blink: BOOL _ FALSE, msgClass: MsgClass _ $Every] = { SetFD[router, msgClass, Iv[label], blink, NIL]; }; SetMultiLabel: PUBLIC PROC [router: MsgRouter, label: Viewer, blink: BOOL _ FALSE, msgClasses: LIST OF ATOM] = { FOR list: LIST OF ATOM _ msgClasses, list.rest UNTIL list = NIL DO SetLabel[router, label, blink, list.first]; ENDLOOP; }; SetMessageWindow: PUBLIC PROC [router: MsgRouter, blink: BOOL _ FALSE, msgClass: MsgClass _ $Every] = { SetFD[router, msgClass, messageWindow, blink, NIL]; }; SetMultiMessageWindow: PUBLIC PROC [router: MsgRouter, blink: BOOL _ FALSE, msgClasses: LIST OF ATOM] = { FOR list: LIST OF ATOM _ msgClasses, list.rest UNTIL list = NIL DO SetMessageWindow[router, blink, list.first]; ENDLOOP; }; SetTypescript: PUBLIC PROC [router: MsgRouter, typescriptName: ATOM _ $None, msgClass: MsgClass _ $Every] = { SetFD[router, msgClass, NIL, FALSE, typescriptName]; }; SetMultiTypescript: PUBLIC PROC [router: MsgRouter, typescriptName: ATOM _ $None, msgClasses: LIST OF ATOM] = { FOR list: LIST OF ATOM _ msgClasses, list.rest UNTIL list = NIL DO SetTypescript[router, typescriptName, list.first]; ENDLOOP; }; CreateSimpleRouter: PUBLIC PROC [label: Viewer, blink: BOOL _ FALSE, typescriptName: ATOM] RETURNS [router: MsgRouter] = { router _ CreateRouter[]; SetLabel[router, label, blink, $Every]; SetTypescript[router, typescriptName, $Every]; }; CreateMultiFeedback: PUBLIC PROC [label: Viewer, blink: BOOL _ FALSE, labelClasses: LIST OF ATOM, typescriptName: ATOM, typescriptClasses: LIST OF ATOM] RETURNS [router: MsgRouter] = { router _ CreateRouter[]; SetMultiLabel[router, label, blink, labelClasses]; SetMultiTypescript[router, typescriptName, typescriptClasses]; }; GetLabel: PUBLIC PROC [router: MsgRouter, msgClass: MsgClass _ $Default] RETURNS [label: Viewer, blink: BOOL _ FALSE] = { feedback: FeedbackData ~ GetFD[router, msgClass]; IF feedback#NIL THEN RETURN [Ov[feedback.lp.label], feedback.lp.blink]; RETURN [NIL]}; GetTypescriptName: PUBLIC PROC [router: MsgRouter, msgClass: MsgClass _ $Default] RETURNS [typescriptName: ATOM _ $None] = { feedback: FeedbackData ~ GetFD[router, msgClass]; IF feedback#NIL THEN RETURN [feedback.tn]; RETURN}; VPutF: PROC [mh: MsgHandler, msgType: MsgType, msgClass: MsgClass, format: Rope.ROPE, v1, v2, v3, v4, v5: IO.Value _ [null[]] ] ~ { fd: FeedbackData ~ NARROW[FeedbackClasses.GetHandlerData[mh]]; lfd: FeedbackData ~ IF fd.lp.label#NIL OR fd.default=NIL THEN fd ELSE fd.default; tfd: FeedbackData ~ IF fd.tn#NIL OR fd.default=NIL THEN fd ELSE fd.default; lcf: BOOL ~ typeBreaksAt[msgType].begin OR lfd.bounded; tcf: BOOL ~ typeBreaksAt[msgType].begin OR tfd.bounded; msg: Rope.ROPE ~ IO.PutFR[format, v1, v2, v3, v4, v5]; IF lfd.lp.label=noLabel OR lfd.lp.label=NIL THEN NULL ELSE IF lfd.lp.label=messageWindow THEN { MessageWindow.Append[msg, lcf]; IF lfd.lp.blink THEN MessageWindow.Blink[]} ELSE { Labels.Set[lfd.lp.label, IF lcf THEN msg ELSE Rope.Concat[NARROW[lfd.lp.label.class.get[lfd.lp.label]], msg]]; IF lfd.lp.blink THEN BlinkLabel[lfd.lp.label]}; IF tfd.tn # $None THEN PutFToTypescript[tfd.tn, IF tcf THEN Rope.Concat["\n", format] ELSE format, v1, v2, v3, v4, v5]; lfd.bounded _ tfd.bounded _ typeBreaksAt[msgType].end; }; PutFToTypescript: PROC [typescriptName: ATOM, format: Rope.ROPE, v1, v2, v3, v4, v5: IO.Value _ [null[]] ] ~ { script: Script _ FindScript[typescriptName]; IF script=NIL THEN RETURN; IF format.Length[]=1 AND v1=[null[]] THEN Enqueue[script, [NIL, putc[format.Fetch[0]]]] ELSE Enqueue[script, [NIL, putf[format, v1, v2, v3, v4, v5]]]; RETURN}; Enqueue: ENTRY PROC [script: Script, fp: FCons] ~ { ENABLE UNWIND => NULL; IF script.stream=NIL AND NOT script.storing THEN RETURN; {this: FList ~ NEW [FCons _ fp]; IF script.queueHead=NIL THEN script.queueHead _ this ELSE script.queueTail.rest _ this; script.queueTail _ this; IF script.stream=NIL THEN NULL ELSE IF script.putter=NIL THEN TRUSTED {Process.Detach[script.putter _ FORK Putter[script]]} ELSE NOTIFY script.change; RETURN}}; Deque: TYPE ~ RECORD [fh: FList, stream: IO.STREAM, sv: Viewer, quit: BOOL]; Dequeue: ENTRY PROC [script: Script] RETURNS [Deque] ~ { ENABLE UNWIND => NULL; RETURN InnerDequeue[script]}; InnerDequeue: INTERNAL PROC [script: Script] RETURNS [Deque] ~ { n: INTEGER _ 2; UNTIL script.queueHead#NIL AND script.stream#NIL DO IF (n _ n.PRED) < 0 THEN { script.putter _ NIL; RETURN [[NIL, NIL, NIL, TRUE]]}; WAIT script.change; ENDLOOP; {fh: FList ~ script.queueHead; script.queueHead _ script.queueHead.rest; fh.rest _ NIL; IF script.queueHead=NIL THEN script.queueTail _ NIL; RETURN [[fh, script.stream, script.viewer, FALSE]]}}; ClearStreamAndRequeue: ENTRY PROC [script: Script, bad: IO.STREAM, fh: FList] ~ { ENABLE UNWIND => NULL; IF fh.rest # NIL THEN ERROR; IF script.stream=bad THEN script.stream _ NIL; fh.rest _ script.queueHead; script.queueHead _ fh; IF script.queueTail=NIL THEN script.queueTail _ script.queueHead; RETURN}; SetStuff: ENTRY PROC [script: Script, stream: IO.STREAM, sv: Viewer, storing: BOOL] ~ { script.stream _ stream; script.viewer _ sv; script.storing _ storing; IF script.stream=NIL THEN NULL ELSE IF script.putter=NIL THEN TRUSTED {Process.Detach[script.putter _ FORK Putter[script]]} ELSE NOTIFY script.change; RETURN}; Putter: PROC [script: Script] ~ { InnerPut[script !UNWIND => script.putter _ NIL]; RETURN}; InnerPut: PROC [script: Script] ~ { DO dq: Deque ~ Dequeue[script]; IF dq.quit THEN RETURN; InnerInnerPut[script, dq]; ENDLOOP}; InnerInnerPut: PROC [script: Script, dq: Deque] ~ { WITH dq.fh SELECT FROM x: REF blink FCons => IF dq.sv#NIL AND NOT dq.sv.destroyed THEN ViewerOps.BlinkViewer[dq.sv]; x: REF putf FCons => dq.stream.PutF[x.format, x.v1, x.v2, x.v3, x.v4, x.v5 ! IO.Error => { IF ec#StreamClosed THEN { MessageWindow.Append[IO.PutFR["FeedbackImpl: IO Err at ts %g for fmt %g", [atom[script.typescriptName]], [rope[x.format]] ]]; MessageWindow.Blink[]; } ELSE ClearStreamAndRequeue[script, stream, dq.fh]; CONTINUE; }]; x: REF putc FCons => dq.stream.PutChar[x.c ! IO.Error => { IF ec#StreamClosed THEN { MessageWindow.Append[IO.PutFR["FeedbackImpl: IO Err at ts %g for PutChar", [atom[script.typescriptName]] ]]; MessageWindow.Blink[]; } ELSE ClearStreamAndRequeue[script, stream, dq.fh]; CONTINUE; }]; ENDCASE => ERROR; RETURN}; VClearHerald: PROC [mh: MsgHandler, msgClass: MsgClass] ~ { fd: FeedbackData _ NARROW[FeedbackClasses.GetHandlerData[mh]]; IF fd.lp.label=NIL AND fd.default#NIL THEN fd _ fd.default; IF fd.lp.label=NIL OR fd.lp.label=noLabel THEN NULL ELSE IF fd.lp.label=messageWindow THEN MessageWindow.Clear[] ELSE Labels.Set[fd.lp.label, NIL]; RETURN}; VBlink: PROC [mh: MsgHandler, msgClass: MsgClass] ~ { fd: FeedbackData _ NARROW[FeedbackClasses.GetHandlerData[mh]]; IF fd.lp.label=NIL AND fd.default#NIL THEN fd _ fd.default; IF fd.lp.label=NIL OR fd.lp.label=noLabel THEN { IF fd.tn#$None THEN { script: Script ~ FindScript[fd.tn]; IF script#NIL THEN Enqueue[script, blinkF] } } ELSE IF fd.lp.label=messageWindow THEN MessageWindow.Blink[] ELSE BlinkLabel[fd.lp.label]; RETURN}; BlinkLabel: PROC [label: Viewer] = { Labels.SetDisplayStyle[label, $WhiteOnBlack]; Process.Pause[Process.MsecToTicks[150]]; Labels.SetDisplayStyle[label, $BlackOnWhite]; Process.Pause[Process.MsecToTicks[150]]; Labels.SetDisplayStyle[label, $WhiteOnBlack]; Process.Pause[Process.MsecToTicks[150]]; Labels.SetDisplayStyle[label, $BlackOnWhite]; }; END. J FeedbackOpsImpl.mesa Copyright ำ 1988, 1990 by Xerox Corporation. All rights reserved. Last edited by Bier on July 12, 1990 2:16 pm PDT Last tweaked by Mike Spreitzer on July 17, 1990 11:32 am PDT Contents: Routines that determine where a MsgRouter will send its output. Typescripts Our two-headed handlers NIL label or tn means to consult default, if any. Wiring up a MsgRouter to specific output streams Queries on routers (mostly for debugging) Viewers Output Routines This routine is forked to avoid deadlock. Deadlock can occur if a client in a paint-proc calls PutFToTypescript while another typescript is trying to paint. This routine will have the paint lock and need to acquire the typescript painting process; the other typescript will have the typescript editRepaintProcess and need to acquire the paint lock. By forking this routine, we allow our client to finish painting and release the paint lock, which then allows the other Typescript to finish painting and release the typescript editRepaintProcess. Structure contorted to let Cirio see some frame (InnerPut's). ส5™codešœ™KšœB™BKšœ0™0K™<—K˜KšœJ™JK™Kšฯk œOœb˜ผK˜šฯnœœ˜Kšœœ˜!KšœœR˜wKšœœœ ˜*—˜Kšœœ˜$Kš œœœœœ˜—K˜Ihead™ K™Kšœ,ฯc<˜hK˜Kšœœœ ˜šœ œ œœ˜$KšœŸ;˜KKšœœœ˜Kšœœ˜Kšœ œ˜KšœœŸ˜=KšœœœŸ"˜9Kšœ ˜K˜K˜—Kšœœœ˜šœœœ˜K˜ šœœ ˜K˜ Kšœœœ˜:Kšœ œ˜Kšœ˜ ——K˜Kšœœ ˜K˜šžœœœœœœœœœœœ˜ผKšœ œœ˜Kšœ,˜,š œœœœœœ˜Dšœ$˜$Kšœ˜Kš œœœ œœœ˜{—Kšœ0˜0Kšœ2œ œ œ˜TKšœEœœ˜Pšœœœ˜Kšœ œh˜tKšœI˜PKšœ0˜0K˜—Kšœ2˜6K˜—šœŸ,˜3Kšœœ˜Kšœ˜—K˜K˜—šžœœœ œœœ œœœœœ œœœ˜ฎKšœ,˜,šœœœ˜KšœœœE˜uKšœI˜PKšœ3˜3K˜—šœ˜Kšœœ˜0Kšœœ ˜'K˜—K˜K˜—š ž œœœœœ˜JKšœœœ˜Kšœœ˜ Kšœ2˜2Kšœœ œ˜#K˜K˜—šžœœœœœœœ˜OKšœ,˜,Kš œ œœœœ˜!Kšœ˜K˜K˜—šžœœœœ œœœ˜@š œ œ$œœœ˜SKšœœœœ ˜'K˜—K˜#K˜—L™Kšœœœ˜)šœœœ˜ Kš œœœœœ˜7Kšœœœ˜Kšœœ˜Kšœ œ˜Kšœ˜K™1—K˜Kšœœ&˜;Kšœœ˜0K˜šžœœ œ ˜%Kš œœœœœœ œ˜1—K˜šžœœ œ ˜%Kš œœœœ œœœ˜1—K˜š žœœœœœ˜!Kš œœœœœœœ˜/—K˜š žœœœœœ˜!Kš œœœœ œœœ˜/—K˜šžœœœœœ œœœ˜ƒKšœœ:˜PKšœœœ˜"KšœA˜G—K˜šžœœœœœœœ œœ˜šœ$œ˜3Kšœœœ'˜GKšœœœ˜——K˜š ž œœœ(œœ˜Sšœ$œ˜3Kšœ/˜/Kšœœ#˜3——K˜šžœœœ"œ ˜Ršœ$œ˜3Kšœ+˜+Kšœœ#˜3——K˜šžœœ?œœ˜]K˜Kšœ.˜.šœœœœ˜%šœœ$œ˜8Kšœ˜Kšœœ˜——šœœœ˜.Kšœœ˜Kšœ œœ œ˜ šž œœ.œœ˜Ršœ,œ˜;šœœ˜šœ˜Kšœœœ˜(Kšœœœ ˜—Kšœ˜—Kšœœœ œ˜7—Kšœœ˜—šœœœ˜Kšœœœ˜)Kšœœœ ˜—šœ˜Kšœœ2˜:KšœD˜DKšœ'˜'—Kšœ,œœ˜9Kšœ!œ˜&Kšœ˜—K˜"š œœœœ$œ˜Bšœ˜Kšœœœ˜(Kšœœœ ˜Kšœ˜—Kšœœ˜—Kšœ@œ/˜rKšœ&˜&Kšœ˜—K˜šžœœ)œ˜RK˜.š œœœœ$œ˜BKšœœ˜Kšœœ˜—Kšœœ˜—K˜Lšœ0™0K™š žœœœ+œœ"˜nKšœ*œ˜/K˜K˜—šž œœœ+œœœœœ˜pš œœœœœœ˜BKšœ+˜+Kšœ˜—K˜K˜—š žœœœœœ"˜gKšœ.œ˜3K˜K˜—šžœœœœœœœœ˜iš œœœœœœ˜BKšœ,˜,Kšœ˜—K˜—K™šž œœœ%œ*˜mKšœœœ˜4K˜—K˜šžœœœ%œœœœ˜oš œœœœœœ˜BKšœ2˜2Kšœ˜—K˜—K˜š žœ œœœœœ˜zKšœ˜Kšœ'˜'Kšœ.˜.K˜K˜—šžœœœœœœœœœœœœœ˜ธKšœ˜Kšœ2˜2Kšœ>˜>K˜—K˜L™)K™š žœœœ4œœœ˜yKšœ1˜1Kšœ œœœ,˜GKšœœ˜K˜—š žœœœ4œœ ˜|Kšœ1˜1Kšœ œœœ˜*Kšœ˜—K˜K˜L™K™šžœœEœœ˜ƒKšœœ%˜>Kš œœ œœ œœœ ˜QKš œœœœ œœœ ˜KKšœœœ ˜7Kšœœœ ˜7Kšœ œœ#˜6Kš œœœœ˜5šœœœ˜)Kšœ˜Kšœœ˜+—šœ˜Kš œœœœ œ.˜nKšœœ˜/—Kš œœœœœ˜wKšœ6˜6K˜K˜—š žœœœœœ˜nKšœ,˜,Kšœœœœ˜Kšœœ œœ˜WKšœœ%˜>Kšœ˜K˜—šžœœœ ˜3Kšœœœ˜Kš œœœœœœ˜8Kšœœ˜ šœ˜Kšœ˜Kšœ˜"—Kšœ˜Kšœœœ˜Kš œœœœœ!œ˜\Kšœœ˜Kšœ˜ K˜—Kš œœœœœœ˜LK˜šžœœœœ ˜8Kšœœœ˜Kšœ˜—K˜šž œœœœ ˜@Kšœœ˜š œœœœ˜3šœœœ˜Kšœœ˜Kš œœœœœ˜ —Kšœ˜Kšœ˜—Kšœ˜Kšœ)˜)Kšœ œ˜Kšœœœœ˜4Kšœ%œ˜5K˜—š žœœœœœ˜QKšœœœ˜Kšœ œœœ˜Kšœœœ˜.Kšœ˜Kšœ˜Kšœœœ%˜AKšœ˜K˜—š žœœœœœœ˜WK˜K˜K˜Kšœœœ˜Kš œœœœœ!œ˜\Kšœœ˜Kšœ˜K˜—šžœœ˜!Kšœค™คK™=Kšœœœ˜0Kšœ˜K˜—šžœœ˜#š˜Jšœ˜Jšœ œœ˜Jšœ˜Kšœ˜ —K˜—šž œœ ˜3šœœ˜Kš œœœœœœœ˜]šœœD˜Jšœœ ˜šœœ˜Kšœœf˜}Kšœ˜K˜—Kšœ.˜2Kšœ˜ Kšœ˜——šœœ$˜*šœœ ˜šœœ˜KšœœU˜lKšœ˜K˜—Kšœ.˜2Kšœ˜ Kšœ˜——Kšœœ˜—Kšœ˜K˜—šž œœ)˜;Kšœœ%˜>Kš œ œœ œœ˜;Kš œ œœœ˜3Kšœœœ˜Kš œ œœ œœ˜;šœ œœœ˜0šœ œ˜Kšœ#˜#Kšœœœ˜*K˜—K˜—Kšœœœ˜