DIRECTORY AIS, BasicTime USING [nullGMT, GMT, Period], Buttons USING [Button, ButtonProc, Create, ReLabel, SetDisplayStyle], Commander USING [CommandProc, Handle, Register, CommandObject], CommandTool USING [DoCommandRope], Containers USING [Container, Create], Convert USING [RopeFromCard, RopeFromTime], DefaultRegistry USING[UsersRegistry], FingerOps, FS USING [Error], Graphics, GraphicsOps, Icons USING [IconFlavor, NewIconFromFile], IO USING[noWhereStream], MessageWindow USING [Append, Blink], Process USING[Detach], Rope USING [Cat, Equal, Length, ROPE], UserCredentials USING [Get], VFonts, ViewerClasses, ViewerEvents, ViewerOps, ViewerTools; FingerToolImpl: CEDAR PROGRAM IMPORTS AIS, BasicTime, Buttons, Commander, CommandTool, Containers, Convert, DefaultRegistry, FingerOps, FS, Graphics, GraphicsOps, Icons, IO, MessageWindow, Process, Rope, UserCredentials, ViewerEvents, VFonts, ViewerOps, ViewerTools = BEGIN FingerHandle: TYPE = REF FingerToolRec; -- a REF to the data for a particular instance of the finger tool; multiple instances can be created. FingerToolRec: TYPE = RECORD -- the data for a particular tool instance [outer: Containers.Container _ NIL, -- handle for the enclosing container height: CARDINAL _ 0, -- height measured from the top of the container performFingerButton: Buttons.Button, -- button clicked to perform finger operation storeChangesButton: Buttons.Button, -- button clicked to make changes to finger data talkButton: Buttons.Button, -- button to connect to talk program fingerList: FingerOps.FingerList, -- list of finger data remainingFingerEntries: CARDINAL _ 0, -- number of objects remaining to be displayed fingerObject: FingerOps.FingerObject, -- the current object being displayed (name = NIL if nothing being displayed currently) name, actualName, pictureFileName, plan: SelectionData _ NEW[SelectionRecord], opt1, opt2, opt3: SelectionData _ NEW[SelectionRecord], editable: BOOL _ FALSE, -- if the current entry is the logged-in user or this machine, then the fields of the entry can be changed pictureAISFile: Rope.ROPE, pictureViewer: ViewerClasses.Viewer]; SelectionData: TYPE = REF SelectionRecord; SelectionRecord: TYPE = RECORD [parentHandle: FingerHandle, selected: BOOL, selectable: BOOL, button: Buttons.Button, result: ViewerClasses.Viewer, registration: ViewerEvents.EventRegistration _ NIL]; PictureState: TYPE = REF PictureStateRecord; PictureStateRecord: TYPE = RECORD[width, height: INT, filename: Rope.ROPE]; fingerIcon: Icons.IconFlavor = Icons.NewIconFromFile["Finger.icon", 0]; MakeFingerTool: Commander.CommandProc = BEGIN fingerHandle: FingerHandle = NEW[FingerToolRec _ [fingerObject: [type: person, name: NIL]]]; fingerHandle.outer _ Containers.Create -- construct the outer container [[name: "Finger Tool", -- name displayed in the caption icon: fingerIcon, iconic: TRUE, -- so tool will be iconic when first created column: left, -- initially in the left column scrollable: FALSE]]; -- inhibit user from scrolling contents fingerHandle.outer.class.bltContents _ none; fingerHandle.height _ 0; fingerHandle.remainingFingerEntries _ 0; SetupViewer[fingerHandle]; ViewerOps.SetOpenHeight[fingerHandle.outer, fingerHandle.height]; -- hint our desired height ViewerOps.PaintViewer[fingerHandle.outer, all]; -- reflect above change END; pictureColumnWidth: CARDINAL = 192; pictureHeight: CARDINAL = 192; entryVSpace: CARDINAL = 8; -- vertical leading space between sections entryHeight: CARDINAL = 15; -- how tall to make each line of items horizSpace: CARDINAL = 10; -- space between items on the same line firstColumnIndent: CARDINAL = 1; -- measured from left margin firstColumnWidth: CARDINAL = 110; secondColumnWidth: CARDINAL = 240; pictureFont: Graphics.FontRef = VFonts.GraphicsFont[VFonts.EstablishFont["Helvetica", 12, TRUE]]; SetupViewer: PROC [fingerHandle: FingerHandle] = BEGIN SetupButtons: PROC [name: Rope.ROPE, which: SelectionData, scroll: BOOL _ FALSE, height: CARDINAL _ entryHeight, edit: BOOL _ FALSE] = BEGIN which.button _ Buttons.Create [info: [name: name, wx: firstColumnIndent, -- keep the buttons aligned wy: fingerHandle.height, ww: firstColumnWidth, wh: entryHeight, -- specify rather than defaulting so line is uniform parent: fingerHandle.outer, border: FALSE ], proc: SelectionButtonClicked, clientData: which]; -- this will be passed to our button proc which.parentHandle _ fingerHandle; which.selected _ NOT Rope.Equal[name, "Picture Filename:"]; -- the default is not to set the Picture file as selected so that we don't fill up the FS cache with AIS files! which.selectable _ Rope.Equal[name, "Plan:"] OR Rope.Equal[name, "Picture Filename:"]; Buttons.SetDisplayStyle[which.button, IF which.selected THEN $WhiteOnBlack ELSE $BlackOnWhite]; which.result _ ViewerOps.CreateViewer [flavor: $Text, info: [wx: firstColumnIndent + firstColumnWidth + horizSpace, -- keep the buttons aligned wy: fingerHandle.height, ww: secondColumnWidth, wh: height, scrollable: scroll, parent: fingerHandle.outer, border: FALSE]]; IF NOT edit THEN ViewerTools.InhibitUserEdits[which.result]; fingerHandle.height _ fingerHandle.height + height; -- maintain total height END; fingerHandle.height _ fingerHandle.height + entryVSpace; -- space down from the top of the viewer fingerHandle.performFingerButton _ Buttons.Create -- button for performing finger [info: [name: "perform finger", wx: 0, wy: fingerHandle.height, wh: entryHeight, -- specify rather than defaulting so line is uniform parent: fingerHandle.outer, border: TRUE], clientData: fingerHandle, -- this will be passed to our button proc proc: PerformFingerAtTool]; fingerHandle.storeChangesButton _ Buttons.Create -- button for making changes to finger data [info: [name: "store changes", wx: fingerHandle.performFingerButton.wx + fingerHandle.performFingerButton.ww + horizSpace, wy: fingerHandle.height, wh: entryHeight, -- specify rather than defaulting so line is uniform parent: fingerHandle.outer, border: TRUE], clientData: fingerHandle, -- this will be passed to our button proc proc: StoreChanges]; fingerHandle.talkButton _ Buttons.Create -- button to connect to talk program [info: [name: "talk to", wx: fingerHandle.storeChangesButton.wx + fingerHandle.storeChangesButton.ww + horizSpace, wy: fingerHandle.height, wh: entryHeight, -- specify rather than defaulting so line is uniform parent: fingerHandle.outer, border: TRUE], clientData: fingerHandle, -- this will be passed to our button proc proc: TalkTo]; fingerHandle.height _ fingerHandle.height + entryHeight + entryVSpace; -- space down from the action buttons SetupButtons[name: "Grapevine ID:", which: fingerHandle.name]; SetupButtons[name: "User Name:", which: fingerHandle.actualName, edit: TRUE]; fingerHandle.actualName.registration _ ViewerEvents.RegisterEventProc[SetNew, edit, fingerHandle.actualName.result]; SetupButtons[name: "Last Login On:", which: fingerHandle.opt1]; SetupButtons[name: "Last Login At:", which: fingerHandle.opt2]; SetupButtons[name: "Last Mail Read:", which: fingerHandle.opt3]; SetupButtons[name: "Picture Filename:", which: fingerHandle.pictureFileName, edit: TRUE]; fingerHandle.pictureFileName.registration _ ViewerEvents.RegisterEventProc[SetNew, edit, fingerHandle.pictureFileName.result]; SetupButtons[name: "Plan:", which: fingerHandle.plan, scroll: TRUE, height: 8*entryHeight, edit: TRUE]; fingerHandle.plan.registration _ ViewerEvents.RegisterEventProc[SetNew, edit, fingerHandle.plan.result]; fingerHandle.pictureViewer _ ViewerOps.CreateViewer[flavor: $FingerPicture, info: [wx: firstColumnIndent + firstColumnWidth + horizSpace + secondColumnWidth + horizSpace, wy: fingerHandle.name.result.wy, ww: pictureColumnWidth, wh: pictureHeight, parent: fingerHandle.outer, border: TRUE, scrollable: FALSE], paint: TRUE]; fingerHandle.height _ fingerHandle.height + entryVSpace; -- space at bottom of finger viewer END; SetNew: ViewerEvents.EventProc = { WHILE viewer.parent # NIL DO viewer _ viewer.parent ENDLOOP; viewer.newVersion _ TRUE; TRUSTED { Process.Detach[FORK ViewerOps.PaintViewer[viewer: viewer, hint: caption]] } }; PaintPicture: ViewerClasses.PaintProc = { state: PictureState = NARROW[self.data]; box:Graphics.Box = Graphics.GetBounds[context]; IF state = NIL THEN { [] _ Graphics.SetPaintMode[self:context, mode:opaque]; Graphics.SetColor[context, Graphics.white]; Graphics.DrawBox[context, box]; Graphics.SetColor[context, Graphics.black]; Graphics.SetCP[context, 3.0, pictureHeight/2]; Graphics.DrawRope[self: context, rope: "No Picture", font: pictureFont]; RETURN }; BEGIN scaleX:REAL _ (box.xmax-box.xmin)/ state.width; scaleY:REAL _ (box.ymax-box.ymin)/ state.height; scale: REAL _ MIN[scaleX, scaleY]; Graphics.SetCP[self:context, x:0, y:0]; Graphics.Scale[self:context, sx:scale, sy:scale]; [] _ Graphics.SetPaintMode[self:context, mode:opaque]; Graphics.SetColor[self:context, color:Graphics.black]; Graphics.DrawImage[self:context, image:GraphicsOps.NewAisImage[state.filename]]; END }; fingerErrorCode: FingerOps.Reason; PerformFingerAtTool: Buttons.ButtonProc = BEGIN ENABLE FingerOps.FingerError => {fingerErrorCode _ reason; GOTO FingerProblem }; fingerHandle: FingerHandle _ NARROW[clientData]; user: Rope.ROPE = UserCredentials.Get[].name; actualName, plan, pictureFile: Rope.ROPE; data: FingerOps.ObjectData; IF fingerHandle.remainingFingerEntries = 0 THEN { userNamePattern: Rope.ROPE _ ViewerTools.GetSelectionContents[]; IF Rope.Length[userNamePattern] = 0 THEN userNamePattern _ "*"; fingerHandle.fingerList _ FingerOps.GetMatchingObjects[pattern: userNamePattern]; fingerHandle.remainingFingerEntries _ 0; FOR list: FingerOps.FingerList _ fingerHandle.fingerList, list.rest UNTIL list = NIL DO fingerHandle.remainingFingerEntries _ fingerHandle.remainingFingerEntries + 1 ENDLOOP }; IF fingerHandle.remainingFingerEntries > 0 THEN BEGIN entry: FingerOps.FingerObject = fingerHandle.fingerList.first; IF mouseButton = blue THEN { fingerHandle.fingerList _ NIL; fingerHandle.remainingFingerEntries _ 0; Buttons.ReLabel[fingerHandle.performFingerButton, "perform finger"]; RETURN }; [actualName, plan, pictureFile, data] _ FingerOps.GetProps[entry]; fingerHandle.editable _ IF entry.type = person THEN Rope.Equal[entry.name, user, FALSE] OR Rope.Equal[Rope.Cat[entry.name, DefaultRegistry.UsersRegistry[]], user, FALSE] ELSE Rope.Equal[entry.name, FingerOps.machineNameRope, FALSE]; fingerHandle.fingerObject _ entry; fingerHandle.fingerList _ fingerHandle.fingerList.rest; fingerHandle.remainingFingerEntries _ fingerHandle.remainingFingerEntries - 1; SetName[fingerHandle, entry, actualName]; IF entry.type = machine THEN SetMachineFields[fingerHandle, entry.name, data] ELSE SetPersonFields[fingerHandle, entry.name, data]; ViewerTools.SetContents[fingerHandle.pictureFileName.result, fingerHandle.pictureAISFile _ IF fingerHandle.pictureFileName.selected AND pictureFile # NIL AND NOT Rope.Equal[pictureFile, ""] THEN pictureFile ELSE NIL]; IF fingerHandle.editable AND fingerHandle.pictureFileName.selected THEN ViewerTools.EnableUserEdits[fingerHandle.pictureFileName.result] ELSE ViewerTools.InhibitUserEdits[fingerHandle.pictureFileName.result]; IF fingerHandle.pictureAISFile # NIL THEN SetPicture[fingerHandle.pictureViewer, fingerHandle.pictureAISFile] ELSE fingerHandle.pictureViewer.data _ NIL; ViewerOps.PaintViewer[fingerHandle.pictureViewer, all]; ViewerTools.SetContents[fingerHandle.plan.result, IF fingerHandle.plan.selected THEN plan ELSE ""]; IF fingerHandle.editable AND fingerHandle.plan.selected THEN ViewerTools.EnableUserEdits[fingerHandle.plan.result] ELSE ViewerTools.InhibitUserEdits[fingerHandle.plan.result]; fingerHandle.outer.newVersion _ FALSE; ViewerOps.PaintViewer[fingerHandle.outer, caption] END; IF fingerHandle.remainingFingerEntries > 0 THEN Buttons.ReLabel[fingerHandle.performFingerButton, Rope.Cat["remaining: ", Convert.RopeFromCard[fingerHandle.remainingFingerEntries]]] ELSE Buttons.ReLabel[fingerHandle.performFingerButton, "perform finger"] EXITS FingerProblem => { MessageWindow.Append[ message: SELECT fingerErrorCode FROM Aborted => "\n... Transaction Aborted; Retry Finger Operation", Error => "\n... Internal Finger Error; Contact Implementor", Failure => "\n... Connection with server broken; try again later", ENDCASE => NIL, clearFirst: TRUE ]; MessageWindow.Blink[] }; END; SetName: PROC[handle: FingerHandle, object: FingerOps.FingerObject, actualName: Rope.ROPE] ~ { IF object.type = person THEN { Buttons.ReLabel[handle.name.button, "Grapevine ID:"]; ViewerTools.SetContents[handle.name.result, object.name]; Buttons.ReLabel[handle.actualName.button, "User Name:"]; ViewerTools.SetContents[handle.actualName.result, actualName]; IF handle.editable THEN ViewerTools.EnableUserEdits[handle.actualName.result] ELSE ViewerTools.InhibitUserEdits[handle.actualName.result] } ELSE { Buttons.ReLabel[handle.name.button, "Machine Name:"]; ViewerTools.SetContents[handle.name.result, object.name]; Buttons.ReLabel[handle.actualName.button, "Net Number:"]; ViewerTools.SetContents[handle.actualName.result, actualName]; ViewerTools.InhibitUserEdits[handle.actualName.result] } }; SetMachineFields: PROC[handle: FingerHandle, name: Rope.ROPE, data: FingerOps.ObjectData] ~ TRUSTED { WITH machineData: data^ SELECT FROM machine => { Buttons.ReLabel[handle.opt1.button, "Last User:"]; ViewerTools.SetContents[handle.opt1.result, machineData.lastUser]; Buttons.ReLabel[handle.opt2.button, "Interaction Time:"]; ViewerTools.SetContents[handle.opt2.result, TimeRope[machineData.time]]; Buttons.ReLabel[handle.opt3.button, "Last Interaction:"]; ViewerTools.SetContents[handle.opt3.result, IF machineData.operation = login THEN "Login" ELSE "Logout"] }; ENDCASE }; TimeRope: PROC[time: BasicTime.GMT] RETURNS[rope: Rope.ROPE] = { rope _ IF time = BasicTime.nullGMT THEN "unknown" ELSE Convert.RopeFromTime[time] }; SetPersonFields: PROC[handle: FingerHandle, name: Rope.ROPE, data: FingerOps.ObjectData] ~ TRUSTED { lastLoginTime: BasicTime.GMT _ BasicTime.nullGMT; lastLoginMachine: Rope.ROPE; WITH personData: data^ SELECT FROM person => { Buttons.ReLabel[handle.opt1.button, "Last Mail Read:"]; ViewerTools.SetContents[handle.opt1.result, TimeRope[personData.mailRead]]; FOR mList: LIST OF FingerOps.MachineData _ personData.used, mList.rest UNTIL mList = NIL DO IF mList.first.operation = login AND (lastLoginTime = BasicTime.nullGMT OR BasicTime.Period[from: lastLoginTime, to: mList.first.time] > 0) THEN { lastLoginTime _ mList.first.time; lastLoginMachine _ mList.first.machine } ENDLOOP; Buttons.ReLabel[handle.opt2.button, "Last Login On:"]; ViewerTools.SetContents[handle.opt2.result, lastLoginMachine]; Buttons.ReLabel[handle.opt3.button, "Last Login At:"]; ViewerTools.SetContents[handle.opt3.result, TimeRope[lastLoginTime]] }; ENDCASE }; SetPicture: PROC[v: ViewerClasses.Viewer, filename: Rope.ROPE] ~ { ENABLE FS.Error => CONTINUE; fd:AIS.FRef = AIS.OpenFile[name:filename]; r:AIS.Raster = AIS.ReadRaster[fd]; AIS.CloseFile[fd]; v.data _ NEW[PictureStateRecord _ [filename: filename, height: r.scanCount, width: r.scanLength]] }; StoreChanges: Buttons.ButtonProc = BEGIN ENABLE FingerOps.FingerError => {fingerErrorCode _ reason; GOTO FingerProblem }; fingerHandle: FingerHandle = NARROW[clientData]; -- get finger viewer data name: Rope.ROPE = fingerHandle.fingerObject.name; IF Rope.Length[name] # 0 THEN BEGIN IF fingerHandle.editable THEN BEGIN actualName: Rope.ROPE = IF fingerHandle.actualName.result.newVersion THEN ViewerTools.GetContents[fingerHandle.actualName.result] ELSE NIL; plan: Rope.ROPE = IF fingerHandle.plan.result.newVersion THEN ViewerTools.GetContents[fingerHandle.plan.result] ELSE NIL; pictureFileName: Rope.ROPE = IF fingerHandle.pictureFileName.result.newVersion THEN ViewerTools.GetContents[fingerHandle.pictureFileName.result] ELSE NIL; fingerHandle.actualName.result.newVersion _ fingerHandle.plan.result.newVersion _ fingerHandle.pictureFileName.result.newVersion _ FALSE; FingerOps.SaveNewProps[object: fingerHandle.fingerObject, actualName: actualName, plan: plan, pictureFile: pictureFileName]; fingerHandle.remainingFingerEntries _ 0; fingerHandle.fingerList _ NIL; Buttons.ReLabel[fingerHandle.performFingerButton, "perform finger"]; IF Rope.Length[pictureFileName] # 0 THEN { fingerHandle.pictureAISFile _ pictureFileName; SetPicture[fingerHandle.pictureViewer, fingerHandle.pictureAISFile]; ViewerOps.PaintViewer[fingerHandle.pictureViewer, all] }; END ELSE BEGIN MessageWindow.Append[message: "You can change finger data for only yourself or your machine.", clearFirst: TRUE]; MessageWindow.Blink[]; END; fingerHandle.outer.newVersion _ FALSE; ViewerOps.PaintViewer[fingerHandle.outer, caption] END ELSE BEGIN MessageWindow.Append[message: "No object fingered!", clearFirst: TRUE]; MessageWindow.Blink[]; END; EXITS FingerProblem => { MessageWindow.Append[ message: SELECT fingerErrorCode FROM Aborted => "\n... Transaction Aborted; Retry Finger Operation", Error => "\n... Internal Finger Error; Contact Implementor", Failure => "\n... Connection with server broken; try again later", ENDCASE => NIL, clearFirst: TRUE ]; MessageWindow.Blink[] }; END; TalkTo: Buttons.ButtonProc = BEGIN fingerHandle: FingerHandle = NARROW[clientData]; -- get finger viewer data userNamePattern: Rope.ROPE = ViewerTools.GetContents[fingerHandle.name.result]; cmd: Commander.Handle _ NEW[Commander.CommandObject _ []]; cmd.out _ IO.noWhereStream; cmd.err _ IO.noWhereStream; IF Rope.Length[userNamePattern] # 0 THEN [] _ CommandTool.DoCommandRope[commandLine: Rope.Cat["///Commands/Talk ", userNamePattern, " &"], parent: cmd] ELSE BEGIN MessageWindow.Append[message: "Enter username for talk connection.", clearFirst: TRUE]; MessageWindow.Blink[]; END; END; SelectionButtonClicked: Buttons.ButtonProc = BEGIN whichButton: SelectionData _ NARROW[clientData]; -- get our data fingerHandle: FingerHandle _ whichButton.parentHandle; -- get other data relating to finger tool IF whichButton.selectable THEN IF (whichButton.selected _ NOT whichButton.selected) THEN { Buttons.SetDisplayStyle[whichButton.button, $WhiteOnBlack]; IF fingerHandle.editable THEN ViewerTools.EnableUserEdits[whichButton.result] } ELSE BEGIN ViewerTools.SetContents[whichButton.result, ""]; fingerHandle.outer.newVersion _ FALSE; ViewerOps.PaintViewer[fingerHandle.outer, caption]; Buttons.SetDisplayStyle[whichButton.button, $BlackOnWhite]; ViewerTools.InhibitUserEdits[whichButton.result] END END; ViewerOps.RegisterViewerClass[flavor: $FingerPicture, class: NEW[ViewerClasses.ViewerClassRec _ [flavor: $FingerPicture, paint: PaintPicture]]]; Commander.Register[key: "FingerTool", proc: MakeFingerTool, doc: "Create a finger tool." ]; END. ¦FingerToolImpl.mesa Last Edited by: Khall, August 17, 1984 11:21:52 am PDT Last edited by: Donahue, October 22, 1984 10:02:48 am PDT GalleryOps USING [Create, CreateGallery, Gallery, SetAis, Vp], the following hold all the data pertinent to selections for each fingered object these three entries change meaning depending on the type of the object being displayed. For machines they give the last user interaction, who the user was and the time of the interaction; for people, they give the last time mail was read, the last machine logged in to and the last login time pictureGallery: GalleryOps.Gallery, -- for when Gallery is released pictureViewPort: GalleryOps.Vp, For uniformity, some standard distances between entries in the tool are defined. fingerHandle.pictureGallery _ GalleryOps.CreateGallery -- frame for picture [viewerRec: [wx: firstColumnIndent + firstColumnWidth + horizSpace + secondColumnWidth + horizSpace, wy: fingerHandle.userName.result.wy, ww: pictureColumnWidth, wh: pictureHeight, parent: fingerHandle.outer, border: TRUE], oneVpOnly: TRUE]; fingerHandle.pictureViewPort _ GalleryOps.Create [gallery: fingerHandle.pictureGallery, sx: pictureColumnWidth, sy: pictureHeight, fixedVp: TRUE, fixedAIS: TRUE, paint: FALSE]; If there are entries remaining, treat the blue mouse button as "cancel" The user can change the plan and picture file for himself or the machine he is logged onto; he can also change his own "actual name" GalleryOps.SetAis[fingerHandle.pictureViewPort, fingerHandle.pictureAISFile ! FS.Error => CONTINUE]; force the selection into the user input field Register commands with the Exec to perform finger and create an instance of the Finger Tool. Κ_˜code– "Cedar" style™K™6K™9—K™šΟk ˜ Kšœ˜Kšœ œ œ ˜'Kšœœ8˜EKšœ œ0˜?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˜KšœœœΟcΠckž]˜Žšœœ˜šž+˜1Kšœœž%˜JKšœ œž0˜GKšœ%ž-˜RKšœ$ž0˜TKšœž$˜@Kšœ"ž˜8Kšœœž.˜TKšœ&žW˜}KšœP™PKšœ˜Kšœ ˜ Kšœ˜Kšœœ˜+Kšœ"œ˜7Kšœ₯™₯Kšœ œœžj˜‚Kšœœ˜KšœC™CKšœ™Kšœ%˜%——K˜Kšœœœ˜*K˜šœœ˜š˜Kšœ˜Kšœ œ˜Kšœ œ˜Kšœ˜Kšœ˜Kšœ/œ˜4——K˜Kšœœœ˜,Kš œœœœœ˜KK˜šœG˜GK˜—šœ'˜'š˜Kšœœ5œ˜\šœ&ž!œ˜HKšœž ˜8Kšœ˜Kšœœž,˜;Kšœž˜.Kšœ œœž'˜=—Kšœ,˜,K˜Kšœ(˜(Kšœ˜KšœCž˜]Kšœ1ž˜H—Kšœ˜—K˜KšœP™PKšœœ˜#Kšœœ˜Kšœ œž*˜EKšœ œž&˜BKšœ œž'˜BKšœœž˜=Kšœœ˜!Kšœœ˜"K˜šœ˜Kšœ:œ˜A—K˜šΟn œœ˜0š˜š  œœ œ œœ œœœ˜†š˜šœ˜šœ˜Kšœ ˜ Kšœž˜2Kšœ˜Kšœ˜Kšœž4˜FKšœ˜Kšœœ˜—Kšœ˜Kšœž)˜>—K˜"Kšœœ(žo˜«Kšœ-œ'˜VJšœ&œœœ˜_šœ%˜%Kšœ˜˜Kšœ8ž˜SKšœ˜Kšœ˜Kšœ ˜ Kšœ˜K˜Kšœœ˜——Kšœœœ,˜KšœGœ˜MKšœt˜tKšœ?˜?Kšœ?˜?Kšœ@˜@KšœSœ˜YKšœ~˜~Kšœ>œœ˜gKšœh˜hK˜šœ7ž™Kšœ ™ KšœX™XKšœ$™$Kšœ™Kšœ™Kšœ™Kšœœ™—Kšœ œ™—šœ0™0Kšœ'™'Kšœ™Kšœ™Kšœ œ™Kšœ œ™Kšœœ™—K˜šœK˜KKšœΟœœ˜θKšœœ˜ —Kšœ:ž#˜]—Kšœ˜—K˜šœ"˜"Jšœœœœ˜˜>KšœG™Gšœœ˜Kšœœ˜Kšœ(˜(KšœD˜DKšœ˜ —K˜BKšœœœœœIœœ3œ˜θKšœ„™„Kšœ"˜"Kšœ7˜7KšœN˜NK˜Kšœ)˜)K˜Kšœœ1˜MKšœ1˜5K˜Kšœ[œ'œœœœœ œœ˜Ωšœœ'˜GKšœ@˜@—KšœC˜GKšœ[œ™ešœœ˜)KšœC˜C—Kšœ#œ˜+Kšœ7˜7Kšœ2œœœ˜cšœœ˜˜>Kšœœ6˜MKšœ9˜=—šœ˜Kšœ5˜5Kšœ9˜9Kšœ9˜9Kšœ>˜>Kšœ;˜;——K˜š œœ"œ œ˜ešœœ˜#˜ Kšœ2˜2KšœB˜BKšœ9˜9KšœH˜HKšœ9˜9Kšœ,œœ œ ˜k—Kšœ˜ ——K˜š  œœœœ œ˜@šœœœ ˜1Kšœ˜"——K˜š œœ"œ œ˜dKšœœ˜1Kšœœ˜šœœ˜"˜ Kšœ7˜7KšœK˜Kš œœœ5œ œ˜[šœœ$œBœ˜’KšœK˜K—Kšœ˜—Kšœ6˜6Kšœ>˜>Kšœ6˜6KšœG˜GKšœ˜ ———K˜š  œœ)œ˜BKšœœ œ˜Jšœœœ˜*Jšœœ œ˜"Jšœ˜Jšœ œX˜d—K˜šœ"˜"š˜š˜Kšœ4œ˜I—Kšœœž˜JKšœ œ"˜1šœ˜š˜šœ˜š˜Kš œœœ+œ9œœ˜‹Kš œ œœ%œ3œœ˜yKš œœœ0œ>œœ˜šKšœƒœ˜‰Kšœ|˜|Kšœ(˜(Kšœœ˜KšœD˜Dšœ"œ˜*Kšœ.˜.KšœD˜DKšœ9˜9—Kš˜——š˜š˜Jšœkœ˜qJšœ˜—Kš˜—Kšœ œ˜&Kšœ2˜2Kš˜——š˜š˜JšœAœ˜GJšœ˜—Kšœ˜——Kšœ˜šœ˜Kšœ œ˜$Kšœ?˜?Kšœ<˜