DIRECTORY Buttons USING [Button, ButtonProc], CedarProcess USING [SetPriority], ChoiceButtons, Containers USING [ChildXBound], Imager USING [black, Color, Font, MaskRectangleI, SetColor, SetFont, SetXYI, ShowRope, white], ImagerBackdoor USING [invert, MakeStipple], InputFocus USING [CaptureButtons, ReleaseButtons], Labels USING [Create, Label, Set], Menus USING [MouseButton], Process USING [Detach, Milliseconds, MsecToTicks, SetTimeout], Rope USING [ROPE, Equal], TIPUser USING [InstantiateNewTIPTable, TIPScreenCoords], VFonts USING [CharWidth, defaultFont, DefaultFont, Font, FontHeight, StringWidth], ViewerClasses USING [GetProc, NotifyProc, PaintProc, PaintRectangle, SetProc, Viewer, ViewerClass, ViewerClassRec, ViewerRec], ViewerOps USING [AddProp, CreateViewer, DestroyViewer, EnumerateChildren, EnumProc, FetchProp, MouseInViewer, MoveViewer, PaintViewer, RegisterViewerClass], ViewerPrivate USING [Document, messageWindow], ViewerTools USING [MakeNewTextViewer, SetContents, SetSelection]; ButtonsImpl: CEDAR MONITOR LOCKS data USING data: ButtonData IMPORTS CedarProcess, Containers, Imager, ImagerBackdoor, InputFocus, Labels, Process, Rope, TIPUser, VFonts, ViewerOps, ViewerPrivate, ViewerTools EXPORTS Buttons, ChoiceButtons = BEGIN OPEN Buttons, ChoiceButtons, ViewerClasses; ButtonData: TYPE = REF ButtonDataRec; ButtonDataRec: TYPE = MONITORED RECORD [ proc: ButtonProc, font: Imager.Font, clientData: REF ANY, documentation: REF ANY, greyCount: INTEGER _ 0, displayStyle: DisplayStyle _ blackOnWhite, inverted: BOOL _ FALSE, fork: BOOL, guarded: BOOL, state: GuardState ]; GuardState: TYPE = { guarded, arming, armed }; DisplayStyle: TYPE = {blackOnWhite, whiteOnBlack, blackOnGrey}; bottomOffset: INTEGER = 2; guardOffset: INTEGER = 3; sideMargin: INTEGER = 3; extraHeight: INTEGER = 3; entryHeight: CARDINAL = 15; -- how tall to make each line of items entryHSpace: CARDINAL = 10; -- horizontal space between title and selections fudge: CARDINAL = 5; -- fudge factor so that the baselines of text viewers are aligned with on: ATOM = $WhiteOnBlack; off: ATOM = $BlackOnWhite; armingTime: Process.Milliseconds _ 100; -- cover removal time. armedTime: Process.Milliseconds _ 5000; -- unguarded interval. Create: PUBLIC PROC [info: ViewerRec _ [], proc: ButtonProc, clientData: REF ANY _ NIL, fork: BOOL _ FALSE, font: Imager.Font _ NIL, documentation: REF ANY _ NIL, guarded: BOOL _ FALSE, paint: BOOL _ TRUE] RETURNS [button: Button] = { data: ButtonData _ NEW[ButtonDataRec _ [proc: proc, font: VFonts.DefaultFont[font], clientData: clientData, documentation: documentation, fork: fork, guarded: guarded, state: IF guarded THEN guarded ELSE armed]]; IF info.ww=0 THEN info.ww _ VFonts.StringWidth[info.name, data.font]+sideMargin*2; IF info.wh=0 THEN info.wh _ VFonts.FontHeight[data.font]+extraHeight; IF info.parent=NIL AND info.wx=0 AND info.wy=0 THEN { m: Viewer ~ ViewerPrivate.messageWindow; ViewerOps.MoveViewer[m, m.wx, m.wy, m.ww-info.ww, m.wh, FALSE]; info.wx _ m.wx + m.ww; info.wy _ m.wy; info.wh _ m.wh; info.column _ static; }; info.data _ data; IF documentation#NIL THEN WITH documentation SELECT FROM doc: REF TEXT => NULL; doc: REF ButtonProc => NULL; doc: Rope.ROPE => NULL; ENDCASE => ERROR; -- not valid documentation RETURN[ViewerOps.CreateViewer[$Button, info, paint]]; }; buttonGrey: Imager.Color ~ ImagerBackdoor.MakeStipple[stipple: 001010B]; ButtonPaint: PaintProc = { data: ButtonData ~ NARROW[self.data]; margin: INTEGER ~ 1; x: INTEGER ~ margin-self.cx; y: INTEGER ~ margin-self.cy; w: INTEGER ~ self.ww-2*margin; h: INTEGER ~ self.wh-2*margin; IF data = NIL THEN RETURN; IF ISTYPE[whatChanged, PaintRectangle] THEN whatChanged _ NIL; IF whatChanged=NIL THEN { background: Imager.Color _ Imager.white; IF data.greyCount#0 THEN background _ buttonGrey ELSE SELECT data.displayStyle FROM blackOnWhite => background _ Imager.white; blackOnGrey => background _ buttonGrey; whiteOnBlack => background _ Imager.black; ENDCASE; IF clear AND background=Imager.white THEN NULL ELSE { Imager.SetColor[context, background]; Imager.MaskRectangleI[context, x, y, w, h]; }; Imager.SetColor[context, IF data.displayStyle=whiteOnBlack THEN Imager.white ELSE Imager.black]; Imager.SetXYI[context, x+sideMargin, y+bottomOffset]; Imager.SetFont[context, data.font]; Imager.ShowRope[context, self.name]; IF data.guarded AND data.state#armed THEN { Imager.MaskRectangleI[context, x, y+bottomOffset+guardOffset, w, 1]; }; }; IF whatChanged=$Invert OR data.inverted THEN { -- invert to indicate highlighting Imager.SetColor[context, ImagerBackdoor.invert]; Imager.MaskRectangleI[context, x, y, w, h]; IF whatChanged=$Invert THEN data.inverted _ ~data.inverted; }; }; ButtonNotify: NotifyProc = { data: ButtonData _ NARROW[self.data]; EntryButtonNotify[self, input, data]; }; EntryButtonNotify: ENTRY PROC [self: Viewer, input: LIST OF REF ANY, data: ButtonData] = { ENABLE UNWIND => InputFocus.ReleaseButtons[]; button: Menus.MouseButton _ red; shift, control: BOOL _ FALSE; mouse: TIPUser.TIPScreenCoords; IF data = NIL THEN RETURN; FOR list: LIST OF REF ANY _ input, list.rest UNTIL list = NIL DO WITH list.first SELECT FROM x: ATOM => SELECT x FROM $Blue => button _ blue; $Control => control _ TRUE; $Documentation => IF data.documentation#NIL THEN ViewerPrivate.Document[data.documentation, self, data.clientData, button, shift, control]; $Hit => IF data.inverted THEN SELECT data.state FROM guarded => { data.state_arming; ViewerOps.PaintViewer[self, client, FALSE, $Invert]; InputFocus.ReleaseButtons[]; TRUSTED {Process.Detach[FORK ArmButtonProc[data, self]]}; IF data.documentation#NIL THEN -- post documentation ViewerPrivate.Document[data.documentation, self, data.clientData, button, shift, control]; }; arming=> NULL; -- no action armed=> { InputFocus.ReleaseButtons[]; ViewerOps.PaintViewer[self, client, FALSE, $Invert]; IF data.guarded THEN { data.state_guarded; ViewerOps.PaintViewer[self, client]; }; IF data.fork THEN TRUSTED {Process.Detach[FORK ButtonPusher[self, data, data.proc, data.clientData, button, shift, control, TRUE]]} ELSE ButtonPusher[self, data, data.proc, data.clientData, button, shift, control, FALSE]; }; ENDCASE; $Mark => IF ~data.inverted THEN { InputFocus.CaptureButtons[ButtonNotify, buttonClass.tipTable, self]; ViewerOps.PaintViewer[self, client, FALSE, $Invert]; } ELSE { v: Viewer; c: BOOL; [v, c] _ ViewerOps.MouseInViewer[mouse]; IF v=self AND c THEN RETURN; ViewerOps.PaintViewer[self, client, FALSE, $Invert]; InputFocus.ReleaseButtons[]; }; $Red => button _ red; $Shift => shift _ TRUE; $Yellow => button _ yellow; ENDCASE => NULL; z: TIPUser.TIPScreenCoords => mouse _ z; ENDCASE => ERROR; ENDLOOP; }; ArmButtonProc: ENTRY PROC [data: ButtonData, button: Buttons.Button] = { IF data = NIL THEN RETURN; ButtonWait[data, armingTime]; IF data.state = arming THEN { data.state_armed; ViewerOps.PaintViewer[button, client]; ButtonWait[data, armedTime]; }; IF data.state#guarded THEN { data.state_guarded; ViewerOps.PaintViewer[button, client]; }; }; ButtonWait: INTERNAL PROC[data: ButtonData, ticks: Process.Milliseconds] = TRUSTED { buttonWaitCondition: CONDITION; Process.SetTimeout[LONG[@buttonWaitCondition], Process.MsecToTicks[ticks]]; WAIT buttonWaitCondition; }; ButtonPusher: PROC [button: Button, myData: ButtonData, proc: ButtonProc, data: REF ANY, mouseButton: Menus.MouseButton, shift, control, normalPriority: BOOL] = { IF myData = NIL THEN RETURN; myData.greyCount _ myData.greyCount + 1; IF myData.displayStyle#blackOnGrey THEN ViewerOps.PaintViewer[button, client]; IF normalPriority THEN CedarProcess.SetPriority[normal]; proc[button, data, mouseButton, shift, control ! ABORTED => CONTINUE]; myData.greyCount _ MAX[myData.greyCount - 1, 0]; IF myData.displayStyle#blackOnGrey THEN ViewerOps.PaintViewer[button, client]; }; ButtonGet: PRIVATE GetProc = { RETURN[self.name]; }; ButtonSet: PRIVATE SetProc = { IF op=NIL THEN self.name _ NARROW[data] ELSE WITH self.data SELECT FROM myData: ButtonData => SELECT data FROM $BlackOnWhite => { myData.greyCount _ MAX[myData.greyCount - 1, 0]; IF myData.greyCount <= 0 THEN myData.displayStyle _ blackOnWhite}; $WhiteOnBlack => { myData.greyCount _ MAX[myData.greyCount - 1, 0]; IF myData.greyCount <= 0 THEN myData.displayStyle _ whiteOnBlack}; $BlackOnGrey, $BlackOnGray => { myData.greyCount _ myData.greyCount + 1; myData.displayStyle _ blackOnWhite}; ENDCASE => ERROR; ENDCASE => RETURN; IF finalise THEN ViewerOps.PaintViewer[self, all]; }; Destroy: PUBLIC PROC [button: Button] = { ViewerOps.DestroyViewer[button]; }; ReLabel: PUBLIC PROC [button: Button, newName: Rope.ROPE, paint: BOOL _ TRUE] = { button.class.set[button, newName, paint]; }; SetDisplayStyle: PUBLIC PROC [button: Button, style: ATOM, paint: BOOL _ TRUE] = { button.class.set[button, style, paint, $DisplayStyle] }; DefaultDoesntExist: PUBLIC SIGNAL = CODE; ChoiceDoesntExist: PUBLIC SIGNAL = CODE; ButtonsCannotBeUpdated: PUBLIC SIGNAL = CODE; BuildEnumTypeSelection: PUBLIC PROC [viewer: ViewerClasses.Viewer, x, y: CARDINAL, title: ROPE, buttonNames: ButtonList, default: ROPE, borderOnButtons: BOOL, notifyClientProc: SelectionNotifierProc, permit: EnumPermissionProc, clientdata: REF ANY, style: StyleChoice, allInOneRow: BOOL, maxWidth: INTEGER] RETURNS [EnumTypeRef] = { foundDefault: BOOL _ FALSE; stateInfo: EnumTypeRef _ NEW[EnumTypeRec]; DefaultFound: PROC[currentName, defaultName: ROPE] RETURNS [BOOL] = { IF Rope.Equal[currentName, defaultName, FALSE] THEN RETURN [foundDefault _ TRUE] ELSE RETURN [FALSE]; }; BuildMenuSelection: PROC = { border: INTEGER _ 10; startButtons: CARDINAL; startX: INTEGER _ 0; -- keeps a running tally of where the next x position is tempButton: Buttons.Button; eachButton: ButtonList; stateInfo.type _ menuStyle; IF title # NIL THEN { titleLabel: Labels.Label_ Labels.Create[[ name: title, parent: viewer, wx: x, wy: y, wh: entryHeight, border: FALSE ]]; startButtons _ titleLabel.wx + titleLabel.ww + entryHSpace; } ELSE startButtons _ x; startX _ startButtons; FOR eachButton _ buttonNames, eachButton.rest UNTIL eachButton = NIL DO IF ~allInOneRow THEN { IF startX + VFonts.StringWidth[eachButton.first, VFonts.defaultFont] + border >= maxWidth THEN { startX _ startButtons; stateInfo.nexty _ stateInfo.nexty + entryHeight; }; }; tempButton _ Create[info: [ name: eachButton.first, wx: startX, wy: stateInfo.nexty, wh: entryHeight, -- specify rather than defaulting so line is uniform parent: viewer, border: borderOnButtons ], proc: MenuSelectionProc, clientData: stateInfo ]; ViewerOps.AddProp[tempButton, $ChoiceButtons, stateInfo]; IF DefaultFound[eachButton.first, default] THEN { stateInfo.buttonOn _ tempButton; SetDisplayStyle[button: tempButton, style: on]; }; startX _ tempButton.wx + tempButton.ww; ENDLOOP; stateInfo.nextx _ startX; }; BuildFlipThru: PROC = { eachButton: ButtonList; titleButton: Buttons.Button; nextx: INTEGER _ x; IF title # NIL THEN { stateInfo.type _ flipThruWithTitle; titleButton _ Create[ info: [name: title, parent: viewer, wx: nextx, wy: y, wh: entryHeight, border: TRUE ], proc: FlipThruButtonProc, clientData: stateInfo ]; nextx _ titleButton.wx + titleButton.ww + 3; } ELSE stateInfo.type _ flipThruNoTitle; FOR eachButton _ buttonNames, eachButton.rest UNTIL (eachButton = NIL) OR DefaultFound[eachButton.first, default] DO -- do nothing ENDLOOP; IF title # NIL THEN stateInfo.flipLabel _ Labels.Create[[ name: eachButton.first, wx: nextx, wy: y, ww: MaxNameWidth[buttonNames], -- first find the longest name so we can set up the wh: entryHeight, parent: viewer, border: FALSE ]] ELSE stateInfo.flipLabel _ Create[ info: [name: eachButton.first, wx: nextx, wy: y, ww: MaxNameWidth[buttonNames], wh: entryHeight, parent: viewer, border: borderOnButtons ], proc: FlipThruButtonProc, clientData: stateInfo ]; stateInfo.nextx _ stateInfo.flipLabel.wx + stateInfo.flipLabel.ww; }; stateInfo.nextx _ x; stateInfo.nexty _ y; stateInfo.proc _ notifyClientProc; stateInfo.namesOfButtons _ buttonNames; stateInfo.clientdata _ clientdata; stateInfo.permission _ permit; IF default = NIL THEN default _ buttonNames.first; SELECT style FROM menuSelection => BuildMenuSelection; flipThru => BuildFlipThru; ENDCASE => ERROR; IF ~foundDefault THEN SIGNAL DefaultDoesntExist; stateInfo.nexty _ stateInfo.nexty + entryHeight; RETURN[stateInfo]; }; MenuSelectionProc: Buttons.ButtonProc = { viewer: ViewerClasses.Viewer _ NARROW[parent]; WITH clientData SELECT FROM info: EnumTypeRef => IF info.permission = NIL OR info.permission[info] THEN { SwitchButtons[info.buttonOn, viewer]; info.buttonOn _ viewer; IF info.proc # NIL THEN info.proc[viewer.name, info.clientdata]; }; ENDCASE; }; SwitchButtons: PRIVATE PROC[oldButton, newButton: Buttons.Button] = { SetDisplayStyle[button: oldButton, style: off]; SetDisplayStyle[button: newButton, style: on]; }; FlipThruButtonProc: Buttons.ButtonProc = { WITH clientData SELECT FROM info: EnumTypeRef => IF info.permission = NIL OR info.permission[info] THEN { IF mouseButton=red THEN ViewerTools.SetContents[viewer: info.flipLabel, contents: GetNextName[info.namesOfButtons, info.flipLabel.name]] ELSE ViewerTools.SetContents[viewer: info.flipLabel, contents: GetPrevName[info.namesOfButtons, info.flipLabel.name]]; IF info.proc # NIL THEN info.proc[info.flipLabel.name, info.clientdata]; }; ENDCASE; }; UpdateChoiceButtons: PUBLIC PROC [viewer: ViewerClasses.Viewer, enumTypeInfo: EnumTypeRef, newName: ROPE] = { newButton: Buttons.Button _ NIL; GetDesiredButton: ViewerOps.EnumProc = { IF (Rope.Equal[v.name, newName, FALSE]) AND (ViewerOps.FetchProp[v, $ChoiceButtons] = enumTypeInfo) THEN { newButton _ v; RETURN [FALSE]; }; }; IF enumTypeInfo = NIL THEN SIGNAL ButtonsCannotBeUpdated; SELECT enumTypeInfo.type FROM menuStyle => { ViewerOps.EnumerateChildren[viewer, GetDesiredButton]; IF newButton # NIL THEN { SwitchButtons[enumTypeInfo.buttonOn, newButton]; enumTypeInfo.buttonOn _ newButton; } ELSE SIGNAL ChoiceDoesntExist; }; flipThruWithTitle => Labels.Set[label: enumTypeInfo.flipLabel, value: newName]; flipThruNoTitle => ReLabel[button: enumTypeInfo.flipLabel, newName: newName]; ENDCASE => ERROR; }; GetSelectedButton: PUBLIC PROC [handle: EnumTypeRef] RETURNS [ROPE] = { IF handle.type = menuStyle THEN { IF handle.buttonOn = NIL THEN ERROR; RETURN [handle.buttonOn.name] } ELSE { IF handle.flipLabel = NIL THEN ERROR; RETURN[handle.flipLabel.name] }; }; GetNextName: PRIVATE PROC[listOfNames: ButtonList, currentName: ROPE] RETURNS [ROPE] = { eachButton: ButtonList _ listOfNames; WHILE (eachButton # NIL) AND (eachButton.first # currentName) DO eachButton _ eachButton.rest; ENDLOOP; IF eachButton = NIL THEN ERROR; -- This shouldn't happen; we should always be able to IF eachButton.rest = NIL THEN RETURN [listOfNames.first] ELSE RETURN [(eachButton.rest).first]; }; GetPrevName: PRIVATE PROC [listOfNames: ButtonList, currentName: ROPE] RETURNS [ROPE] = { prev: ROPE _ listOfNames.first; eachName: ChoiceButtons.ButtonList _ listOfNames.rest; WHILE (eachName # NIL) AND ~Rope.Equal[eachName.first, currentName, FALSE] DO prev _ eachName.first; eachName _ eachName.rest; ENDLOOP; RETURN[prev]; }; MaxNameWidth: PRIVATE PROC[listOfNames: ButtonList] RETURNS [CARDINAL] = { eachButton: ButtonList _ listOfNames; maxWidth: CARDINAL; IF eachButton # NIL THEN { maxWidth _ VFonts.StringWidth[string: eachButton.first, font: VFonts.defaultFont]; eachButton _ eachButton.rest } ELSE RETURN [0]; WHILE (eachButton # NIL) DO IF VFonts.StringWidth[string: eachButton.first, font: VFonts.defaultFont] > maxWidth THEN maxWidth _ VFonts.StringWidth[string: eachButton.first, font: VFonts.defaultFont]; eachButton _ eachButton.rest; ENDLOOP; maxWidth _ maxWidth + VFonts.CharWidth['M]; -- add on a little extra just to be sure RETURN[maxWidth]; }; BuildTriStateButton: PUBLIC PROC [viewer: ViewerClasses.Viewer, x,y: INTEGER, name: ROPE] RETURNS [stateInfo: ThreeStateRef, nextX: INTEGER] = { tempButton: Buttons.Button; stateInfo _ NEW[ThreeState]; tempButton _ Create[ info: [name: name, wx: x, wy: y, wh: entryHeight, -- specify rather than defaulting so line is uniform parent: viewer, border: TRUE ], proc: TriSwitchProc, clientData: stateInfo -- this will be passed to our button proc ]; stateInfo.button _ tempButton; nextX _ tempButton.wx + tempButton.ww + 4; }; SetButtonState: PUBLIC PROC [buttonSelected: Buttons.Button, state: StateType] = { SELECT state FROM on => SetDisplayStyle[button: buttonSelected, style: $WhiteOnBlack]; off => SetDisplayStyle[button: buttonSelected, style: $BlackOnWhite]; default => SetDisplayStyle[button: buttonSelected, style: $BlackOnGrey]; ENDCASE => ERROR; }; TriSwitchProc: Buttons.ButtonProc = { handle: ThreeStateRef _ NARROW[clientData]; state: StateType _ handle.state; handle.state _ state _ IF state = LAST[StateType] THEN FIRST[StateType] ELSE SUCC[state]; SetButtonState[handle.button, state]; }; BuildTextPrompt: PUBLIC PROC [viewer: ViewerClasses.Viewer, x,y: CARDINAL, title: ROPE, default: ROPE, font: VFonts.Font, textViewerWidth: INTEGER, clientdata: REF ANY, notify: SelectionNotifierProc, permit: PromptPermissionProc] RETURNS [promptData: PromptDataRef] = { height: INTEGER _ VFonts.FontHeight[font] + 6; promptData _ NEW[PromptDataRec]; promptData.promptButton _ Create[info: [name: title, wx: x, wy: y, wh: height, parent: viewer, border: FALSE], font: font, proc: PromptProc, clientData: promptData]; promptData.textViewer _ ViewerTools.MakeNewTextViewer [[ parent: viewer, wx: promptData.promptButton.wx + promptData.promptButton.ww + entryHSpace, wy: y + fudge, ww: textViewerWidth, wh: height - fudge, name: title, -- give it the name of the prompt associated with it data: default, scrollable: FALSE, border: FALSE ]]; IF textViewerWidth = LAST[INTEGER] THEN { Containers.ChildXBound[viewer, promptData.textViewer]; promptData.newx _ LAST[INTEGER]; } ELSE promptData.newx _ promptData.textViewer.wx + promptData.textViewer.ww; IF default # NIL THEN ViewerTools.SetContents[promptData.textViewer, default]; promptData.clientdata _ clientdata; promptData.notify _ notify; promptData.permission _ permit; promptData.newy _ y + height; }; PromptProc: Buttons.ButtonProc = { viewer: ViewerClasses.Viewer _ NARROW[parent]; WITH clientData SELECT FROM handle: PromptDataRef => IF handle.permission = NIL OR handle.permission[handle] THEN SELECT TRUE FROM mouseButton=red => ViewerTools.SetSelection[handle.textViewer]; handle.notify # NIL => handle.notify[viewer.name, handle.clientdata]; ENDCASE; ENDCASE; }; buttonClass: ViewerClasses.ViewerClass _ NEW[ViewerClasses.ViewerClassRec _ [ paint: ButtonPaint, get: ButtonGet, set: ButtonSet, notify: ButtonNotify, tipTable: TIPUser.InstantiateNewTIPTable["Button.tip"], cursor: bullseye ]]; ViewerOps.RegisterViewerClass[$Button, buttonClass]; -- plug in to Viewers END. ŒButtonsImpl.mesa Copyright c 1985, 1986 by Xerox Corporation. All rights reserved. Doug Wyatt, May 23, 1985 11:17:47 am PDT Russ Atkinson (RRA) May 7, 1986 0:36:03 am PDT Rick Beach, May 10, 1986 4:32:02 pm PDT Types & constants their corresponding labels Global variables procedures for Buttons x, y, w, h is a box whose edges are "margin" units inside the window (not client) area paint in label (derived from name) assert: state=arming procedure for ChoiceButtons default the width so that it will be computed for us create a title button now set up the initial button width properly (unfortunately when re-labeling a button, the width remains the same) set it to be the first name of the list of button names signal that the default didn't exist if necessary Notify client that change has taken place if the client provided a proc for doing this merely changes the physical appearance of the buttons Switch off the previously selected button switch "on" the newly selected button Display the next name in succession Display the previous name Notify client that change has taken place if the client provided a proc for doing this find the current button name in list of button names we are at the end of our list, cycle around to the beginning default the width so that it will be computed for us Indicate which state this button is in. make pending delete notify the client if proc provided. Initialization Κ – "Mesa" style˜codešœ™Kšœ Οmœ7™BK™(K™.K™'—˜šΟk ˜ Kšœžœ˜#Kšœ žœ˜!K˜Kšœ žœ˜KšœžœR˜^Kšœžœ˜+Kšœ žœ"˜2Kšœžœ˜"Kšœžœ˜Kšœžœ1˜>Kšœžœžœ ˜Kšœžœ+˜8KšœžœF˜RKšœžœk˜~Kšœ žœ˜œKšœžœ˜.Kšœ žœ0˜A——K˜Kš Πbl œžœžœžœžœ˜šœ( ˜>K˜——šœ™K˜š Οnœžœžœ6žœžœžœ˜WKš œžœžœžœžœžœžœ˜JKš œ žœžœ žœžœžœ˜GKš œžœšžœ žœ žœ ˜ΥKšžœ žœA˜RKšžœ žœ4˜Eš žœ žœžœ žœ žœ˜5Kšœ(˜(Kšœ8žœ˜?K˜K˜K˜K˜Kšœ˜—K˜š žœžœžœžœžœž˜8Kšœžœžœžœ˜Kšœžœžœ˜Kšœ žœžœ˜Kšžœžœ ˜,—Kšžœ/˜5Kšœ˜K˜—KšœH˜HK˜š‘ œ˜Kšœžœ ˜%Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜šœžœ˜K™V—Kšžœžœžœžœ˜Kšžœžœžœžœ˜>šžœ žœžœ˜Kšœ"™"Kšœ(˜(Kšžœžœ˜0šžœžœž˜"Kšœ*˜*Kšœ'˜'Kšœ*˜*Kšžœ˜—Kšžœžœžœž˜.šžœ˜Kšœ%˜%Kšœ+˜+K˜—Kšœžœ žœžœ˜`K˜5K˜#K˜$šžœžœžœ˜+KšœD˜DKšœ˜—Kšœ˜K˜—šžœžœžœ "˜QKšœ0˜0K˜+Kšžœžœ ˜;Kšœ˜—Kšœ˜K˜—š‘ œ˜Kšœžœ ˜%Kšœ%˜%Kšœ˜K˜—š‘œžœžœžœžœžœžœ˜ZKšžœžœ ˜-K˜ Kšœžœžœ˜K˜Kšžœžœžœžœ˜šžœžœžœžœžœžœžœž˜@šžœ žœž˜šœžœžœž˜K˜Kšœžœ˜šœžœžœž˜0K˜AK˜—šœžœžœžœ ž˜4˜ K˜Kšœ$žœ ˜4K˜Kšžœžœ˜9šžœžœžœ ˜4K˜AK˜—K˜—Kšœ žœ  ˜˜ K˜Kšœ$žœ ˜4šžœžœ˜K˜K˜$Kšœ˜—šžœ žœžœžœ˜AKšœ:žœ˜A—šžœ5˜9Kšœžœ˜"—Kšžœ˜——šœ žœžœ˜!KšœD˜DKšœ$žœ ˜4Kšœ˜šžœ˜K˜ Kšœžœ˜K˜(Kšžœžœžœžœ˜Kšœ$žœ ˜4K˜Kšœ˜——K˜Kšœžœ˜K˜Kšžœžœ˜—K˜(Kšžœžœ˜—Kšžœ˜—Kšœ˜K˜—š‘ œžœžœ/˜HKšœ™Kšžœžœžœžœ˜K˜šžœžœ˜K˜K˜&K˜K˜—šžœžœ˜K˜K˜&Kšœ˜—šœ˜K˜——š‘ œžœžœ2žœ˜TKšœž œ˜Kšœžœ4˜KKšžœ˜Kšœ˜K˜—š‘ œžœ>žœžœ˜XKšœ@žœ˜IKšžœ žœžœžœ˜Kšœ(˜(Kšžœ!žœ'˜NKšžœžœ"˜8Kšœ1žœžœ˜FKšœžœ˜0Kšžœ!žœ'˜NKšœ˜K˜—š‘ œžœ ˜Kšžœ ˜Kšœ˜K˜—š‘ œžœ ˜šžœž˜ Kšžœ žœ˜šžœžœ žœž˜šœ˜šžœž˜˜Kšœžœ˜0Kšžœžœ%˜B—˜Kšœžœ˜0Kšžœžœ%˜B—˜K˜(Kšœ$˜$—Kšžœžœ˜——Kšžœžœ˜——Kšžœ žœ"˜2Kšœ˜K˜—š‘œžœžœ˜)Kšœ ˜ Kšœ˜—K˜š ‘œžœžœ žœ žœžœ˜QKšœ)˜)Kšœ˜—K˜š ‘œžœžœžœ žœžœ˜RKšœ5˜5Kšœ˜—K˜—™K™Kšœžœžœžœ˜)Kšœžœžœžœ˜(Kšœžœžœžœ˜-K˜š‘œžœžœ&žœ žœ$žœžœSžœžœ#žœ žœžœ˜ΜKšœžœžœ˜Kšœžœ˜*š ‘ œžœžœžœžœ˜Eš žœ&žœžœžœžœ˜QKšžœžœžœ˜——Kšœ˜š‘œžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ 8˜MK˜K˜K˜šžœ žœžœ˜˜*K˜ K˜K˜K˜K˜Kšœž˜ K˜—K˜;K˜—Kšžœ˜K˜˜šžœ+žœžœž˜Gšžœžœ˜KšžœD˜Fšœžœ˜K˜K˜0K˜—K˜—˜K˜K˜ K˜Kšœ4™4Kšœ 4˜EK˜K˜K˜K˜K˜K˜—K˜9šžœ)žœ˜1K˜ K˜/K˜—K˜'Kšžœ˜—K˜Kšœ˜——š‘ œžœ˜K˜K˜Kšœžœ˜šžœ ž˜šžœ˜Kšœ™K˜#˜˜K˜K˜ K˜K˜Kšœž˜ K˜—K˜K˜K˜—K˜,K˜—Kšžœ"˜&—š žœ+žœžœžœ)žœ  ˜‚Kšžœ˜—Kšœ™šžœ žœžœ&˜9K˜K˜ K˜Kšœ 3˜RKšœT™TK˜K˜Kšœž˜ K˜—šžœ˜"˜K˜ K˜K˜K˜K˜K˜K˜—K˜K˜K˜—K˜BKšœ˜—K˜K˜K˜"K˜'K˜"K˜šžœ žœž˜Kšœ7™7K˜—K˜šžœž˜K˜$K˜Kšžœžœ˜—K˜Kšœ1™1Kšžœžœžœ˜0K˜K˜1Kšžœ ˜Kšœ˜K˜—š‘œ˜)Kšœžœ ˜.šžœ žœž˜šœ˜šžœžœžœžœ˜8Kšœ%˜%K˜KšœV™VKšžœ žœžœ)˜@K˜——Kšžœ˜—Kšœ˜K˜—š‘ œžœžœ*˜EKšœ5™5Kšœ)™)K˜/Kšœ%™%K˜.Kšœ˜K˜—š‘œ˜*šžœ žœž˜šœ˜šžœžœžœžœ˜8šžœ˜šžœ˜Kšœ#™#K˜p—šž˜Kšœ™K˜q——KšœV™VKšžœ žœžœ1˜HK˜——Kšžœ˜—Kšœ˜K˜—š‘œžœžœDžœ˜mKšœžœ˜ šœ(˜(šžœžœžœ:žœ˜kK˜Kšžœžœ˜K˜—Kšœ˜—Kšžœžœžœžœ˜9šžœž˜˜K˜6šžœ ž˜šžœ˜K˜0K˜"K˜—Kšžœžœ˜—K˜—K˜OK˜MKšžœžœ˜—Kšœ˜K˜—š ‘œžœžœžœžœ˜Gšžœ˜šžœ˜Kšžœžœžœžœ˜$Kšžœ˜K˜—šžœ˜Kšžœžœžœžœ˜%Kšžœ˜K˜——K˜K˜—š ‘ œžœžœ'žœžœžœ˜XK˜%šžœžœžœ"žœ˜AK˜Kšžœ˜—š žœžœžœžœ 5˜UKšœ4™4—šžœžœžœ˜Kšœ<™