DIRECTORY --BackStop,-- BasicTime, Breakpoint, BreakWorldArchitecture, Commander, Convert, Druid, DruidTool, Feedback, FeedbackClasses, IO, Menus, NumberLabels, PFS, Process, Rope, SameBreakWorld, SourceFileOps, ViewerClasses, ViewerOps, ViewerTools, VTables; DruidToolImpl: CEDAR MONITOR LOCKS displayHandle USING displayHandle: DruidTool.Handle IMPORTS --BackStop,-- BasicTime, Breakpoint, BreakWorldArchitecture, Commander, Druid, Feedback, FeedbackClasses, IO, Menus, NumberLabels, PFS, Process, Rope, SameBreakWorld, SourceFileOps, ViewerOps, ViewerTools, VTables ~ { Columns: TYPE ~ MACHINE DEPENDENT { clear (0), zero, count, location, text, max }; clearColumn: NAT ~ ORD[Columns.clear]; zeroColumn: NAT ~ ORD[Columns.zero]; countColumn: NAT ~ ORD[Columns.count]; locationColumn: NAT ~ ORD[Columns.location]; textColumn: NAT ~ ORD[Columns.text]; maxColumn: NAT ~ ORD[Columns.max]; sampleRate: Process.Milliseconds ¬ 1000; UpdateDisplayProcess: PROC ~ { displayHandle: DruidTool.Handle ¬ NEW[DruidTool.HandleRep]; Inner: PROC [displayHandle: DruidTool.Handle] ~ { newPulses: BasicTime.Pulses ¬ BasicTime.GetClockPulses[]; inverseSecs: REAL; deltaMicros: CARD ¬ BasicTime.PulsesToMicroseconds[newPulses] - BasicTime.PulsesToMicroseconds[displayHandle.samplePulses]; rowData: DruidTool.RowData ¬ DruidTool.nullRowData; index: NAT ¬ 1; changed: BOOL ¬ FALSE; newRows: NAT ¬ displayHandle.rows; subTotal: CARD ¬ 0; grandTotal: CARD ¬ 0; IF deltaMicros < 100 THEN RETURN; inverseSecs ¬ 1E6 / deltaMicros; displayHandle.samplePulses ¬ newPulses; FOR rowData ¬ displayHandle.rowData, rowData.next WHILE rowData # NIL DO { RemoveRow: PROCEDURE [displayHandle: DruidTool.Handle, row: DruidTool.RowData] ~ { rowData: DruidTool.RowData ¬ DruidTool.nullRowData; lag: DruidTool.RowData ¬ DruidTool.nullRowData; index: NAT ¬ 1; FOR rowData ¬ displayHandle.rowData, rowData.next WHILE rowData # DruidTool.nullRowData DO { IF rowData = row THEN { FOR i: NAT IN [index+1..displayHandle.rows) DO { VTables.ExchangeRows[displayHandle.vTable, i, i-1]; } ENDLOOP; IF lag = DruidTool.nullRowData THEN { displayHandle.rowData ¬ rowData.next; } ELSE { lag.next ¬ rowData.next; }; displayHandle.changed ¬ TRUE; EXIT; } ELSE { lag ¬ rowData; index ¬ index + 1; }; } ENDLOOP; RETURN; }; IF displayHandle.vTable.destroyed THEN RETURN; WITH rowData SELECT FROM subtotalRow: DruidTool.SubtotalRow => { IF subtotalRow.active THEN { nl: NumberLabels.NumberLabel ¬ VTables.GetTableEntry[ table: displayHandle.vTable, row: index, column: countColumn]; IF nl # NIL AND subTotal # subtotalRow.count THEN { subtotalRow.count ¬ subTotal; NumberLabels.NumberLabelUpdate[nl, subTotal]; }; subTotal ¬ 0; index ¬ index + 1; } ELSE { RemoveRow[displayHandle: displayHandle, row: subtotalRow]; }; }; counterRow: DruidTool.CounterRow => { IF Druid.IsActive[megalith: counterRow.megalith] THEN { nl: NumberLabels.NumberLabel ¬ VTables.GetTableEntry[ table: displayHandle.vTable, row: index, column: countColumn]; current: CARD ¬ Druid.Read[megalith: counterRow.megalith]; IF nl # NIL AND current # counterRow.count THEN { counterRow.count ¬ current; NumberLabels.NumberLabelUpdate[nl, current]; }; subTotal ¬ subTotal + current; grandTotal ¬ grandTotal + current; index ¬ index + 1; } ELSE { RemoveRow[displayHandle: displayHandle, row: counterRow]; }; }; ENDCASE => ERROR; } ENDLOOP; IF NOT displayHandle.vTable.parent.iconic THEN { NumberLabels.NumberLabelUpdate[ nl: VTables.GetTableEntry[displayHandle.vTable, 0, countColumn], new: grandTotal]; }; IF displayHandle.changed THEN { InstallNewRows[displayHandle, index]; }; }; displayHandle.vTable ¬ VTables.Create[ rows: 1, columns: maxColumn, name: "Druid", x: 0, y: 2]; displayHandle.sameBreakWorld ¬ SameBreakWorld.Create[]; displayHandle.feedbackStream ¬ FeedbackClasses.CreateStreamOnRouter[ msgRouter: Feedback.CreateRouter[], msgClass: $Default]; displayHandle.rows ¬ 0; displayHandle.rowData ¬ DruidTool.nullRowData; SetTimeout[displayHandle: displayHandle]; displayHandle.samplePulses ¬ BasicTime.GetClockPulses[]; { menu: ViewerClasses.Menu ¬ Menus.CreateMenu[]; Menus.AppendMenuEntry[menu, Menus.CreateEntry[ name: "ClearAll", proc: ClearAll, clientData: displayHandle]]; Menus.AppendMenuEntry[menu, Menus.CreateEntry[ name: "ZeroAll", proc: ZeroAll, clientData: displayHandle]]; Menus.AppendMenuEntry[menu, Menus.CreateEntry[ name: "Set", proc: SetMonitoredCountingBreak, clientData: displayHandle]]; Menus.AppendMenuEntry[menu, Menus.CreateEntry[ name: "UnmonitoredSet", proc: SetUnmonitoredCountingBreak, clientData: displayHandle]]; Menus.AppendMenuEntry[menu, Menus.CreateEntry[ name: "AddSubTotal", proc: AddSubTotal, clientData: displayHandle]]; Menus.AppendMenuEntry[menu, Menus.CreateEntry[ name: "Freeze", proc: Freeze, clientData: displayHandle]]; Menus.AppendMenuEntry[menu, Menus.CreateEntry[ name: "Sample", proc: Sample, clientData: displayHandle]]; Menus.AppendMenuEntry[menu, Menus.CreateEntry[ name: "Thaw", proc: Thaw, clientData: displayHandle]]; ViewerOps.SetMenu[displayHandle.vTable.parent, menu, FALSE]; }; VTables.SetTableEntry[ table: displayHandle.vTable, row: 0, column: countColumn, flavor: $Viewer, clientData: NumberLabels.CreateNumber[ info: [parent: displayHandle.vTable], chars: 9, paint: FALSE], useMaxSize: TRUE]; ViewerOps.ChangeColumn[displayHandle.vTable.parent, left]; InstallNewRows[displayHandle, 1]; UNTIL WaitForChange[displayHandle] DO ENABLE ABORTED => EXIT; DoUnderLock[displayHandle, Inner]; ENDLOOP; DoUnderLock[displayHandle, InnerClearAll]; DoUnderLock[displayHandle, InnerFlushCache]; InstallNewRows[displayHandle, 0]; }; SetUnmonitoredCountingBreak: Menus.MenuProc ~ { UnmonitoredInner: PROCEDURE[displayHandle: DruidTool.Handle] ~ { InnerSetCountingBreak[displayHandle: displayHandle, monitored: FALSE]; RETURN; }; DoUnderLock[clientData, UnmonitoredInner]; RETURN; }; SetMonitoredCountingBreak: Menus.MenuProc ~ { MonitoredInner: PROCEDURE[displayHandle: DruidTool.Handle] ~ { InnerSetCountingBreak[displayHandle: displayHandle, monitored: TRUE]; RETURN; }; DoUnderLock[clientData, MonitoredInner]; RETURN; }; InnerSetCountingBreak: PROC [displayHandle: DruidTool.Handle, monitored: BOOLEAN] ~ { Inner: PROC = { vtab: VTables.VTable = displayHandle.vTable; counterRow: DruidTool.CounterRow ¬ NEW[DruidTool.CounterRowRep ¬ [ feedbackStream: displayHandle.feedbackStream, details: counter[]]]; row: NAT ¬ displayHandle.rows; errorMessage: Rope.ROPE ¬ NIL; { -- extra block to contain EXITS. { GetSelection: PROCEDURE [] RETURNS [ name: Rope.ROPE ¬ NIL, label: Rope.ROPE ¬ NIL, position: INT ¬ 0, text: Rope.ROPE ¬ NIL] ~ { viewer: ViewerClasses.Viewer ~ ViewerTools.GetSelectedViewer[]; IF viewer#NIL THEN { selection: ViewerTools.SelPos ~ ViewerTools.GetSelection[viewer]; text ¬ ViewerTools.GetSelectionContents[]; RETURN [ name: viewer.name, label: IF Rope.IsEmpty[viewer.label] THEN viewer.name ELSE viewer.label, position: IF selection.caretPos = before THEN selection.start ELSE selection.start + selection.length, text: text]; }; }; [ name: counterRow.file, label: counterRow.label, position: counterRow.position, text: counterRow.text] ¬ GetSelection[]; }; { pc: CARD ¬ 0; address: BreakWorldArchitecture.Address ¬ BreakWorldArchitecture.nullAddress; [address: pc, correspondingPosition: counterRow.correspondingPosition] ¬ displayHandle.sameBreakWorld.PCFromFileAndPosition[ mesaFilename: counterRow.file, position: counterRow.position, report: displayHandle.feedbackStream ! SameBreakWorld.NotFound => { errorMessage ¬ "Can't find pc for selection."; GO TO Cant; }; ]; address ¬ BreakWorldArchitecture.NewAddress[ breakWorld: displayHandle.sameBreakWorld.BreakWorld[], address: LOOPHOLE[pc]]; counterRow.megalith ¬ Druid.Set[address: address, monitored: monitored ! Breakpoint.CantSet => { errorMessage ¬ message; GO TO Cant; }; ]; displayHandle.feedbackStream.PutF["Counting break set at %g|%g.\n", [rope[counterRow.label]], [integer[counterRow.correspondingPosition]]]; SourceFileOps.OpenSource[ desc: "Counting break loc", pos: [fileName: PFS.PathFromRope[rope: counterRow.file], index: [char: [counterRow.correspondingPosition] ]], feedBack: displayHandle.feedbackStream]; }; AppendRow[displayHandle: displayHandle, row: counterRow]; InstallNewRows[displayHandle, row + 1]; VTables.SetTableEntry[ table: vtab, row: row, column: clearColumn, name: "clear", proc: ClearBreak, clientData: counterRow, useMaxSize: TRUE]; VTables.SetTableEntry[ table: vtab, row: row, column: zeroColumn, name: "zero", proc: ZeroCount, clientData: counterRow, useMaxSize: TRUE]; VTables.SetTableEntry[ table: vtab, row: row, column: countColumn, flavor: $Viewer, clientData: NumberLabels.CreateNumber[info: [parent: vtab], chars: 9, paint: FALSE], useMaxSize: TRUE]; VTables.SetTableEntry[ table: vtab, row: row, column: locationColumn, name: IO.PutFR["%g|%g", [rope[counterRow.label]], [integer[counterRow.correspondingPosition]]], proc: ShowPosition, clientData: counterRow, useMaxSize: TRUE]; VTables.SetTableEntry[ table: vtab, row: row, column: textColumn, flavor: $Text, name: counterRow.text, useMaxSize: TRUE]; VTables.Install[vtab]; EXITS Cant => { displayHandle.feedbackStream.PutRope["Can't set counting break: "]; displayHandle.feedbackStream.PutRope[errorMessage]; displayHandle.feedbackStream.PutRope[".\n"]; }; }; RETURN; }; backStopMessage: Rope.ROPE ¬ NIL--BackStop.Call[Inner]--; Inner[]; IF backStopMessage # NIL THEN { displayHandle.feedbackStream.PutF1["Couldn't set counting break: %g.\n", [rope[backStopMessage]]]; }; RETURN; }; ClearAll: Menus.MenuProc = { DoUnderLock[clientData, InnerClearAll]; RETURN; }; InnerClearAll: PROCEDURE [displayHandle: DruidTool.Handle] ~ { vtab: VTables.VTable = displayHandle.vTable; FOR each: DruidTool.RowData ¬ displayHandle.rowData, each.next WHILE each # NIL DO { ClearBreak[parent: NIL, clientData: each]; } ENDLOOP; RETURN; }; ClearBreak: Menus.MenuProc = { errorMessage: Rope.ROPE ¬ NIL; WITH clientData SELECT FROM counterRow: DruidTool.CounterRow => { megalith: Druid.Megalith ~ counterRow.megalith; Druid.Clear[megalith: counterRow.megalith ! Breakpoint.CantClear => { errorMessage ¬ message; GO TO Cant; }; ]; counterRow.feedbackStream.PutF["Counting break cleared from %g|%g.\n", [rope[counterRow.label]], [integer[counterRow.position]]]; EXITS Cant => { counterRow.feedbackStream.PutRope["Can't clear counting break: "]; counterRow.feedbackStream.PutRope[errorMessage]; counterRow.feedbackStream.PutRope[".\n"]; }; }; subtotalRow: DruidTool.SubtotalRow => { subtotalRow.active ¬ FALSE; }; ENDCASE => NULL; RETURN; }; ZeroAll: Menus.MenuProc = { DoUnderLock[clientData, InnerZeroAllCounts]; RETURN; }; InnerZeroAllCounts: PROC [displayHandle: DruidTool.Handle] = { vtab: VTables.VTable = displayHandle.vTable; FOR each: DruidTool.RowData ¬ displayHandle.rowData, each.next WHILE each # NIL DO { ZeroCount[parent: NIL, clientData: each]; } ENDLOOP; RETURN; }; ZeroCount: Menus.MenuProc = { WITH clientData SELECT FROM counterRow: DruidTool.CounterRow => { megalith: Druid.Megalith ~ counterRow.megalith; [] ¬ Druid.Zero[megalith: counterRow.megalith]; }; ENDCASE => NULL; RETURN; }; ShowPosition: Menus.MenuProc = { WITH clientData SELECT FROM counterRow: DruidTool.CounterRow => { SourceFileOps.OpenSource[ desc: "Source", pos: [fileName: PFS.PathFromRope[rope: counterRow.file], index: [char: [counterRow.correspondingPosition] ]], feedBack: counterRow.feedbackStream]; }; ENDCASE => NULL; RETURN; }; fudge: NAT ¬ 20; InstallNewRows: PROC [displayHandle: DruidTool.Handle, rows: NAT] = { IF displayHandle # DruidTool.nullHandle THEN { vtab: VTables.VTable ¬ displayHandle.vTable; IF vtab # NIL AND NOT vtab.destroyed AND rows # displayHandle.rows THEN { parent: VTables.VTable ¬ vtab.parent; smaller: BOOL ¬ rows < displayHandle.rows; displayHandle.rows ¬ rows; VTables.SetRowsAndColumns[vtab, rows, maxColumn]; SELECT rows FROM 0 => {}; 1 => { VTables.SetTableEntry[ table: vtab, column: locationColumn, name: NIL, border: VTables.NullBorder]; VTables.SetTableEntry[ table: vtab, column: textColumn, name: NIL, border: VTables.NullBorder]; }; 2 => { VTables.SetTableEntry[ table: vtab, column: locationColumn, name: "location", border: VTables.NullBorder]; VTables.SetTableEntry[ table: vtab, column: textColumn, name: "selection", border: VTables.NullBorder]; }; ENDCASE; VTables.Install[vtab, FALSE]; ViewerOps.SetOpenHeight[parent, vtab.wh + fudge]; IF NOT parent.iconic THEN { ViewerOps.ComputeColumn[parent.column]; IF smaller THEN ViewerOps.PaintViewer[parent, all, TRUE, NIL]; }; }; }; }; AddSubTotal: Menus.MenuProc ~ { DoUnderLock[clientData, InnerAddSubTotal]; }; InnerAddSubTotal: PROC [displayHandle: DruidTool.Handle] ~ { vtab: VTables.VTable ~ displayHandle.vTable; rows: NAT ~ displayHandle.rows; subtotalRow: DruidTool.RowData ¬ NEW[DruidTool.RowDataRep ¬ [ count: 0, details: subtotal[active: TRUE]]]; AppendRow[displayHandle: displayHandle, row: subtotalRow]; InstallNewRows[displayHandle, rows + 1]; VTables.SetTableEntry[ table: vtab, row: rows, column: clearColumn, name: "clear", proc: ClearBreak, clientData: subtotalRow, useMaxSize: TRUE]; VTables.SetTableEntry[ table: vtab, row: rows, column: countColumn, flavor: $Viewer, clientData: NumberLabels.CreateNumber[info: [parent: vtab], chars: 9, paint: FALSE], useMaxSize: TRUE]; VTables.SetTableEntry[ table: vtab, row: rows, column: locationColumn, name: "subTotal"]; VTables.Install[vtab]; }; Freeze: Menus.MenuProc ~ { WITH clientData SELECT FROM displayHandle: DruidTool.Handle => { DisableTimeout[displayHandle: displayHandle]; }; ENDCASE; }; Sample: Menus.MenuProc ~ { WITH clientData SELECT FROM displayHandle: DruidTool.Handle => { CauseTimeout[displayHandle: displayHandle]; }; ENDCASE; }; Thaw: Menus.MenuProc ~ { WITH clientData SELECT FROM displayHandle: DruidTool.Handle => { SetTimeout[displayHandle: displayHandle, pause: sampleRate]; CauseTimeout[displayHandle: displayHandle]; }; ENDCASE; }; InnerFlushCache: PROCEDURE [displayHandle: DruidTool.Handle] ~ { displayHandle.sameBreakWorld.Destroy[]; displayHandle.sameBreakWorld ¬ SameBreakWorld.nullHandle; }; RopeFromEntry: PROC [vtab: VTables.VTable, row, col: NAT] RETURNS [Rope.ROPE] = { v: ViewerClasses.Viewer ¬ VTables.GetTableEntry[vtab, row, col]; IF v # NIL THEN WITH ViewerOps.GetViewer[v] SELECT FROM rope: Rope.ROPE => RETURN [rope]; ENDCASE; RETURN [NIL]; }; WaitForChange: ENTRY PROCEDURE [displayHandle: DruidTool.Handle] RETURNS [quit: BOOLEAN] ~ { ENABLE UNWIND => NULL; WAIT displayHandle.timeCondition; RETURN [quit: displayHandle.vTable.destroyed]; }; SetTimeout: ENTRY PROCEDURE [displayHandle: DruidTool.Handle, pause: Process.Milliseconds ¬ 1000] ~ TRUSTED { Process.SetTimeout[@displayHandle.timeCondition, Process.MsecToTicks[pause]]; }; DisableTimeout: ENTRY PROCEDURE [displayHandle: DruidTool.Handle] ~ TRUSTED { Process.DisableTimeout[@displayHandle.timeCondition]; }; CauseTimeout: ENTRY PROCEDURE [displayHandle: DruidTool.Handle] ~ TRUSTED { BROADCAST displayHandle.timeCondition; }; DoUnderLock: PROCEDURE [ ref: REF ANY, inner: PROCEDURE [displayHandle: DruidTool.Handle]] ~ { WITH ref SELECT FROM displayHandle: DruidTool.Handle => { Locked: ENTRY PROCEDURE [displayHandle: DruidTool.Handle] ~ { ENABLE UNWIND => NULL; inner[displayHandle]; }; Locked[displayHandle: displayHandle]; }; ENDCASE; }; AppendRow: PROCEDURE [ displayHandle: DruidTool.Handle, row: DruidTool.RowData] ~ { IF displayHandle.rowData = NIL THEN { displayHandle.rowData ¬ row; } ELSE { FOR each: DruidTool.RowData ¬ displayHandle.rowData, each.next DO { IF each.next = NIL THEN { each.next ¬ row; EXIT; }; } ENDLOOP; }; RETURN; }; StartDruidTool: Commander.CommandProc ~ { Process.Detach[FORK UpdateDisplayProcess[]]; }; Commander.Register[ key: "Druid", proc: StartDruidTool, doc: "Druid is a tool for watching counting breaks."]; }.  DruidToolImpl.mesa Copyright Σ 1990, 1992 by Xerox Corporation. All rights reserved. Peter B. Kessler, August 24, 1990 11:27 am PDT Spreitze, October 3, 1990 10:28 am PDT Willie-s, May 22, 1992 1:37 pm PDT Christian Jacobi, June 19, 1992 2:00 pm PDT update the count Update event count remove the row from the table update the count Update event count remove the row from the table PROC [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE] PROC [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE] This isn't as atomic as I'd like, but the TiogaOps interface looks too complicated. --what I'd like here is an interface to IconHacks. PROC [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE] PROC [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE] PROC [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE] PROC [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE] PROC [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE] PROC [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE] PROC [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE] PROC [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE] PROC [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE] WaitForChange waits on the timeCondition. Κ/–(cedarcode) style•NewlineDelimiter ™code™Kšœ Οeœ7™BK™.K™&K™"K™+K™šΟk ˜ K–0 bp restIndentšΟc œqžœžœžœ]˜ωK˜——unitšΠln œžœžœ˜Kšžœžœ ˜9šžœ˜K–0 bp restIndentšœjžœžœžœM˜Υ—K˜K˜šœ žœžœž œ1˜RKšœ žœžœ˜&Kšœ žœžœ˜$Kšœ žœžœ˜&Kšœžœžœ˜,Kšœ žœžœ˜$Kšœ žœžœ˜"K˜—˜(K˜—šΟnœžœ˜Kšœ"žœ˜;š‘œžœ&˜1K˜9Kšœ žœ˜šœ žœ˜Kšœh˜h—K˜3Kšœžœ˜Kšœ žœžœ˜Kšœ žœ˜"Kšœ žœ˜Kšœ žœ˜K˜Kšžœžœžœ˜!K˜ K˜'šžœ/žœ žœžœ˜Jš‘ œž œ>˜RK˜3K˜/Kšœžœ˜K˜šžœ0žœ!žœ˜]šžœ˜šžœ˜šžœžœžœžœ˜0Kšœ3˜3Kšœžœ˜ —šžœ˜šžœ˜K˜%Kšœ˜—šžœ˜K˜K˜——Kšœžœ˜Kšžœ˜K˜—šžœ˜K˜K˜K˜——Kšœžœ˜ —Kšžœ˜K˜K˜—Kšžœ žœžœ˜.šžœ žœž˜šœ'˜'šžœ˜šžœ˜Kšœ™˜5Kšœ>˜>—K˜šžœžœžœžœ˜3Kšœ™K˜Kšœ-˜-K˜—K˜ K˜K˜—šžœ˜Kšœ™Kšœ:˜:K˜——K˜—šœ%˜%šžœ.˜0šžœ˜Kšœ™˜5Kšœ>˜>—Kšœ žœ-˜:K˜šžœžœžœžœ˜1Kšœ™K˜Kšœ,˜,K˜—K˜K˜"K˜K˜—šžœ˜Kšœ™Kšœ9˜9K˜——K˜—Kšžœžœ˜—Kšœžœ˜ —šžœžœ$žœ˜0šœ˜KšœR˜R—K˜—šžœžœ˜Kšœ%˜%K˜—Kšœ˜—K˜˜&Kšœ8˜8—K˜7˜DKšœ8˜8—K˜K˜.K˜*K˜8˜K˜.K˜šœ.˜.Kšœ>˜>—šœ.˜.Kšœ<˜<—šœ.˜.Kšœ.˜.Kšœ˜—šœ.˜.Kšœ;˜;Kšœ˜—šœ.˜.KšœD˜D—šœ.˜.Kšœ:˜:—šœ.˜.Kšœ:˜:—šœ.˜.Kšœ6˜6—Kšœ5žœ˜—Kšœ žœ˜—Kšœ:˜:Kšœ!˜!šžœž˜%Kšžœžœžœ˜Kšœ"˜"Kšžœ˜—Kšœ*˜*K˜,Kšœ!˜!K˜K˜—š‘œ˜/š žœ žœžœžœžœžœ™1Kšœ0žœžœ™=—š‘œž œ%˜@Kšœ?žœ˜FKšžœ˜K˜—Kšœ*˜*Kšžœ˜K˜K˜—š‘œ˜-š žœ žœžœžœžœžœ™1Kšœ0žœžœ™=—š‘œž œ%˜>Kšœ?žœ˜EKšžœ˜K˜—Kšœ(˜(Kšžœ˜K˜K˜—š‘œžœ.žœ˜Uš‘œžœ˜Kšœ,˜,šœ#žœ˜BKšœC˜C—Kšœžœ˜Kšœžœžœ˜K˜šœŸ ˜"˜š‘ œž œžœžœžœžœžœ žœžœžœ˜ƒK™SK˜?šžœžœžœ˜K˜AK˜*šžœ˜Kšœ˜šœžœ˜%Kšžœ ˜Kšžœ˜K™2—šœ žœ˜(Kšžœ˜Kšžœ$˜(—Kšœ ˜ —K˜—K˜K˜—šœ˜K˜Kšœ˜K˜(—K˜—˜Kšœžœ˜ K˜MK˜˜Išœ3˜3Kšœ˜Kšœ˜Kšœ$˜$šœ˜K˜.Kšžœžœ˜ Kšœ˜—Kšœ˜——˜,Kšœ7˜7Kšœ žœ˜—˜Fšœ˜K˜Kšžœžœ˜ Kšœ˜—Kšœ˜—šœC˜CKšœG˜G—šœ˜K˜šœžœ&˜9Kšœ4˜4—Kšœ(˜(—K˜—Kšœ9˜9Kšœ'˜'šœ˜Kšœ+˜+Kšœ8˜8Kšœ žœ˜—šœ˜Kšœ*˜*Kšœ6˜6Kšœ žœ˜—šœ˜Kšœ<˜Kšœ,˜,šžœ=žœžœžœ˜UKšœžœ˜*Kšœžœ˜ —Kšžœ˜K˜K˜—š‘ œ˜š žœ žœžœžœžœžœ™1Kšœ0žœžœ™=—Kšœžœžœ˜šžœ žœž˜šœ%˜%K˜/K˜šœ)˜)šœ˜K˜Kšžœžœ˜ Kšœ˜—Kšœ˜—šœF˜FKšœ:˜:—šž˜˜ KšœC˜CKšœ0˜0Kšœ)˜)K˜——K˜—šœ'˜'Kšœžœ˜K˜—Kšžœžœ˜—Kšžœ˜K˜K˜—š‘œ˜š žœ žœžœžœžœžœ™1Kšœ0žœžœ™=—Kšœ,˜,Kšžœ˜K˜K˜—š‘œžœ&˜>Kšœ,˜,šžœ=žœžœžœ˜UKšœžœ˜)Kšœžœ˜ —Kšžœ˜K˜K˜—š‘ œ˜š žœ žœžœžœžœžœ™1Kšœ0žœžœ™=—šžœ žœž˜šœ%˜%K˜/K˜K˜/K˜—Kšžœžœ˜—Kšžœ˜K˜K˜—š‘ œ˜ š žœ žœžœžœžœžœ™1Kšœ0žœžœ™=—šžœ žœž˜šœ%˜%šœ˜K˜šœžœ&˜9Kšœ4˜4—Kšœ%˜%—K˜—Kšžœžœ˜—Kšžœ˜K˜K˜—Kšœžœ˜š‘œžœ)žœ˜Ešžœ&žœ˜.K˜,š žœžœžœžœžœžœ˜IK˜%Kšœ žœ˜*K˜K˜Kšœ1˜1šžœž˜K˜˜šœ˜Kšœ+žœ˜L—šœ˜Kšœ'žœ˜H—K˜—šœ˜šœ˜Kšœ7˜7Kšœ˜—šœ˜Kšœ4˜4Kšœ˜—K˜—Kšžœ˜—Kšœžœ˜Kšœ1˜1šžœžœžœ˜Kšœ'˜'Kšžœ žœ$žœžœ˜>K˜—K˜—K˜—K˜K˜—š‘ œ˜š žœ žœžœžœžœžœ™1Kšœ0žœžœ™=—Kšœ*˜*K˜K˜—š‘œžœ&˜(X_