From fc17176420796f57439085229fe270f7a513bc74 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Thu, 12 Nov 2020 09:33:31 +0000 Subject: [PATCH 1/2] Turns out there was an off-by-1 error in Table Fix this and add the filled rect test for easier comparison --- widget/table.go | 4 ++-- widget/table_test.go | 22 ++++++++++++++++++++ widget/testdata/table/filled.png | Bin 0 -> 711 bytes widget/testdata/table/hovered.png | Bin 2858 -> 2850 bytes widget/testdata/table/hovered_out.png | Bin 2314 -> 2310 bytes widget/testdata/table/selected.png | Bin 3864 -> 3753 bytes widget/testdata/table/selected_scrolled.png | Bin 4365 -> 4223 bytes widget/testdata/table/theme_changed.png | Bin 3041 -> 3013 bytes widget/testdata/table/theme_initial.png | Bin 2818 -> 2810 bytes 9 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 widget/testdata/table/filled.png diff --git a/widget/table.go b/widget/table.go index d6047db9e9..20964d2a33 100644 --- a/widget/table.go +++ b/widget/table.go @@ -460,8 +460,8 @@ func (r *tableCellsRenderer) Refresh() { continue } - c.Move(fyne.NewPos(theme.Padding()+col*r.cells.cellSize.Width+(col-1)*tableDividerThickness, - theme.Padding()+row*r.cells.cellSize.Height+(row-1)*tableDividerThickness)) + c.Move(fyne.NewPos(theme.Padding()+col*(r.cells.cellSize.Width+tableDividerThickness), + theme.Padding()+row*(r.cells.cellSize.Height+tableDividerThickness))) } if updateCell != nil { diff --git a/widget/table_test.go b/widget/table_test.go index e1cd25ae1c..8cefa84c34 100644 --- a/widget/table_test.go +++ b/widget/table_test.go @@ -2,9 +2,11 @@ package widget import ( "fmt" + "image/color" "testing" "fyne.io/fyne" + "fyne.io/fyne/canvas" "fyne.io/fyne/test" "fyne.io/fyne/theme" "github.com/stretchr/testify/assert" @@ -78,6 +80,26 @@ func TestTable_ChangeTheme(t *testing.T) { assert.Equal(t, NewLabel("placeholder").MinSize(), content.Objects()[0].(*Label).Size()) } +func TestTable_Filled(t *testing.T) { + app := test.NewApp() + defer test.NewApp() + app.Settings().SetTheme(theme.LightTheme()) + + table := NewTable( + func() (int, int) { return 5, 5 }, + func() fyne.CanvasObject { + r := canvas.NewRectangle(color.Black) + r.SetMinSize(fyne.NewSize(30, 20)) + return r + }, + func(TableCellID, fyne.CanvasObject) {}) + + w := test.NewWindow(table) + defer w.Close() + w.Resize(fyne.NewSize(180, 180)) + test.AssertImageMatches(t, "table/filled.png", w.Canvas().Capture()) +} + func TestTable_Unselect(t *testing.T) { app := test.NewApp() defer test.NewApp() diff --git a/widget/testdata/table/filled.png b/widget/testdata/table/filled.png new file mode 100644 index 0000000000000000000000000000000000000000..e14140c87fdf6a6f25b4bc71cda16413a69a252a GIT binary patch literal 711 zcmeAS@N?(olHy`uVBq!ia0vp^TR@nD2}o{QKQWbofvL~a#WAE}&YQc2S<=}u?t!lt z{;lA@*E0QqX{GUI_V9Igb{0K96;W}aS;UFyZo&_x%!G5APFvVvkHj8-IY8`&3%1Y$-L+5*RMZ+{(OIb|M&0Tw{PEm{rdIk z)2Ba97ZYLkRt71(ecxuw%^bawfBN;C9=~wy&)fdI{$+oChdH~aj7s5zBaT7@8FgRF zJ@P;0S6Ea9+S}Xjw%@mZKmYxAWxF4z@392CY0FCe3iF%AMaBI5{O#}4Wv-k1UjC?F z{AH2*^Gdtl(wBb!{(abZ-x{!GCnr=bb?03vsf6MoxX&;dZCA8yvpmiUfZS@dPHfh3|jwXg`%l5$kQh$%o1+9(kB&U>;?)4o|WNM zS0>C-L{be6YwRK^9(ykV-N6HKN0y&NkTuYe5)enmy$p2DYU_Z+6?XmLXoN~Be)Z}H zy2FLo_&|!YQ-PO(pw#~4-N%m?FIJv6fByfs{x8k~{g>(Z|G2dGV-V9*X32kM28RFt Y3wrLK*uci?227v~p00i_>zopr0PQU(rvLx| literal 0 HcmV?d00001 diff --git a/widget/testdata/table/hovered.png b/widget/testdata/table/hovered.png index 76ce6bbb1174fc1efc3434db8f494f4496a5888c..ccc0cbb1add00190b67386d61fdcd7ec31b8c6a3 100644 GIT binary patch delta 2530 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 diff --git a/widget/testdata/table/hovered_out.png b/widget/testdata/table/hovered_out.png index 3043815d71719505bc82ce13801b4f963b147e72..8a9dbdc4ae378eb7051517aeba0216dfaf3679b7 100644 GIT binary patch literal 2310 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 E0^8m{(*OVf diff --git a/widget/testdata/table/selected.png b/widget/testdata/table/selected.png index d00d3e68610aca400ad7c233da959abb5aae12c0..ee21e0db750f763291e45d9a772f3043479f6b54 100644 GIT binary patch literal 3753 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 literal 4365 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 diff --git a/widget/testdata/table/theme_initial.png b/widget/testdata/table/theme_initial.png index 09e9488797c4a7579f696de9aa9e252459e7613f..898f16b9b40fbe4d711d23eff184742622cc42ac 100644 GIT binary patch delta 2492 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 F{{)2a{YU@+ From 10446f5a3228ea531e7ab3ef7194b9f98eed0819 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Thu, 12 Nov 2020 11:07:41 +0000 Subject: [PATCH 2/2] Add support for Table.SetColumnWidth This takes the content width for a column (matching the template size). It also uncovered we were drawing more cells than required in some cases, hence a couple of test changes --- cmd/fyne_demo/tutorials/collection.go | 14 ++- widget/table.go | 165 ++++++++++++++++++++------ widget/table_test.go | 43 ++++++- widget/testdata/table/col_size.png | Bin 0 -> 2532 bytes 4 files changed, 179 insertions(+), 43 deletions(-) create mode 100644 widget/testdata/table/col_size.png diff --git a/cmd/fyne_demo/tutorials/collection.go b/cmd/fyne_demo/tutorials/collection.go index c03db41905..6cfcabc3ca 100644 --- a/cmd/fyne_demo/tutorials/collection.go +++ b/cmd/fyne_demo/tutorials/collection.go @@ -56,15 +56,25 @@ func makeListTab(_ fyne.Window) fyne.CanvasObject { } func makeTableTab(_ fyne.Window) fyne.CanvasObject { - return widget.NewTable( + t := widget.NewTable( func() (int, int) { return 500, 150 }, func() fyne.CanvasObject { return widget.NewLabel("Cell 000, 000") }, func(id widget.TableCellID, cell fyne.CanvasObject) { label := cell.(*widget.Label) - label.SetText(fmt.Sprintf("Cell %d, %d", id.Row+1, id.Col+1)) + switch id.Col { + case 0: + label.SetText(fmt.Sprintf("%d", id.Row+1)) + case 1: + label.SetText("A longer cell") + default: + label.SetText(fmt.Sprintf("Cell %d, %d", id.Row+1, id.Col+1)) + } }) + t.SetColumnWidth(0, 34) + t.SetColumnWidth(1, 102) + return t } func makeTreeTab(_ fyne.Window) fyne.CanvasObject { diff --git a/widget/table.go b/widget/table.go index 20964d2a33..67f1da7297 100644 --- a/widget/table.go +++ b/widget/table.go @@ -35,6 +35,7 @@ type Table struct { selectedCell, hoveredCell *TableCellID cells *tableCells + columnWidths map[int]int moveCallback func() offset fyne.Position scroll *ScrollContainer @@ -99,6 +100,17 @@ func (t *Table) Select(id TableCellID) { } } +// SetColumnWidth supports changing the width of the specified column. Columns normally take the width of the template +// cell returned from the CreateCell callback. The width parameter uses the same units as a fyne.Size type and refers +// to the internal content width not including any standard padding or divider size. +func (t *Table) SetColumnWidth(id, width int) { + if t.columnWidths == nil { + t.columnWidths = make(map[int]int) + } + t.columnWidths[id] = width + 2*theme.Padding() // The API uses content size so it's consistent with templates + t.Refresh() +} + // Unselect will mark the cell provided by id as unselected. func (t *Table) Unselect(id TableCellID) { if t.selectedCell == nil { @@ -121,12 +133,26 @@ func (t *Table) scrollTo(id TableCellID) { } scrollPos := t.offset - cellPadded := t.templateSize().Add(fyne.NewSize(theme.Padding()*2, theme.Padding()*2)) - cellX := id.Col * (cellPadded.Width + tableDividerThickness) + minSize := t.templateSize() + cellPadded := minSize.Add(fyne.NewSize(theme.Padding()*2, theme.Padding()*2)) + cellX := 0 + cellWidth := 0 + for i := 0; i <= id.Col; i++ { + if cellWidth > 0 { + cellX += cellWidth + tableDividerThickness + } + + width := cellPadded.Width + if w, ok := t.columnWidths[i]; ok { + width = w + } + cellWidth = width + } + if cellX < scrollPos.X { scrollPos.X = cellX - } else if cellX+cellPadded.Width > scrollPos.X+t.scroll.size.Width { - scrollPos.X = cellX + cellPadded.Width - t.scroll.size.Width + } else if cellX+cellWidth > scrollPos.X+t.scroll.size.Width { + scrollPos.X = cellX + cellWidth - t.scroll.size.Width } cellY := id.Row * (cellPadded.Height + tableDividerThickness) @@ -154,6 +180,43 @@ func (t *Table) templateSize() fyne.Size { return fyne.Size{} } +func (t *Table) visibleColumnWidths(colWidth, cols int) (visible map[int]int, offX, minCol, maxCol int) { + maxCol = cols + colOffset := 0 + isVisible := false + visible = make(map[int]int) + + if t.scroll.size.Width <= 0 { + return + } + + for i := 0; i < cols; i++ { + width := colWidth + if w, ok := t.columnWidths[i]; ok { + width = w + } + + if colOffset <= t.offset.X-width-tableDividerThickness { + // before scroll + } else if colOffset <= t.offset.X { + minCol = i + offX = colOffset + isVisible = true + } + if colOffset < t.offset.X+t.scroll.size.Width { + maxCol = i + 1 + } else { + break + } + + colOffset += width + tableDividerThickness + if isVisible { + visible[i] = width + } + } + return +} + // Declare conformity with WidgetRenderer interface. var _ fyne.WidgetRenderer = (*tableRenderer)(nil) @@ -197,13 +260,22 @@ func (t *tableRenderer) Refresh() { t.t.cells.Refresh() } -func (t *tableRenderer) moveColumnMarker(marker fyne.CanvasObject, col int) { +func (t *tableRenderer) moveColumnMarker(marker fyne.CanvasObject, col, offX, minCol int, widths map[int]int) { if col == -1 { marker.Hide() } else { - offX := col*(t.cellSize.Width+tableDividerThickness) - t.scroll.Offset.X + xPos := offX + for i := minCol; i < col; i++ { + if width, ok := widths[i]; ok { + xPos += width + } else { + xPos += t.cellSize.Width + } + xPos += tableDividerThickness + } + offX := xPos - t.scroll.Offset.X x1 := theme.Padding() + offX - x2 := x1 + t.cellSize.Width + x2 := x1 + widths[col] if x2 < theme.Padding() || x1 > t.t.size.Width { marker.Hide() } else { @@ -218,22 +290,28 @@ func (t *tableRenderer) moveColumnMarker(marker fyne.CanvasObject, col int) { } func (t *tableRenderer) moveIndicators() { + rows, cols := 0, 0 + if f := t.t.Length; f != nil { + rows, cols = t.t.Length() + } + visibleColWidths, offX, minCol, _ := t.t.visibleColumnWidths(t.cellSize.Width, cols) + if t.t.selectedCell == nil { - t.moveColumnMarker(t.colMarker, -1) + t.moveColumnMarker(t.colMarker, -1, offX, minCol, visibleColWidths) t.moveRowMarker(t.rowMarker, -1) } else { - t.moveColumnMarker(t.colMarker, t.t.selectedCell.Col) + t.moveColumnMarker(t.colMarker, t.t.selectedCell.Col, offX, minCol, visibleColWidths) t.moveRowMarker(t.rowMarker, t.t.selectedCell.Row) } if t.t.hoveredCell == nil { - t.moveColumnMarker(t.colHover, -1) + t.moveColumnMarker(t.colHover, -1, offX, minCol, visibleColWidths) t.moveRowMarker(t.rowHover, -1) } else { - t.moveColumnMarker(t.colHover, t.t.hoveredCell.Col) + t.moveColumnMarker(t.colHover, t.t.hoveredCell.Col, offX, minCol, visibleColWidths) t.moveRowMarker(t.rowHover, t.t.hoveredCell.Row) } - colDivs := int(math.Ceil(float64(t.t.size.Width+tableDividerThickness) / float64(t.cellSize.Width+1))) + colDivs := len(visibleColWidths) - 1 rowDivs := int(math.Ceil(float64(t.t.size.Height+tableDividerThickness) / float64(t.cellSize.Height+1))) if len(t.dividers) < colDivs+rowDivs { @@ -246,18 +324,11 @@ func (t *tableRenderer) moveIndicators() { } divs := 0 - i := 0 - rows, cols := 0, 0 - if f := t.t.Length; f != nil { - rows, cols = t.t.Length() - } - for x := theme.Padding() + t.scroll.Offset.X - (t.scroll.Offset.X % (t.cellSize.Width + tableDividerThickness)) - tableDividerThickness; x < t.scroll.Offset.X+t.t.size.Width && i < cols-1; x += t.cellSize.Width + tableDividerThickness { - if x <= theme.Padding()+t.scroll.Offset.X { - continue - } + i := minCol + for x := offX + visibleColWidths[i]; i < minCol+colDivs; x += visibleColWidths[i] + tableDividerThickness { i++ - t.dividers[divs].Move(fyne.NewPos(x-t.scroll.Offset.X, theme.Padding())) + t.dividers[divs].Move(fyne.NewPos(theme.Padding()+x-t.scroll.Offset.X, theme.Padding())) t.dividers[divs].Resize(fyne.NewSize(tableDividerThickness, t.t.size.Height-theme.Padding())) t.dividers[divs].Show() divs++ @@ -265,7 +336,7 @@ func (t *tableRenderer) moveIndicators() { i = 0 for y := theme.Padding() + t.scroll.Offset.Y - (t.scroll.Offset.Y % (t.cellSize.Height + tableDividerThickness)) - tableDividerThickness; y < t.scroll.Offset.Y+t.t.size.Height && i < rows-1; y += t.cellSize.Height + tableDividerThickness { - if y <= theme.Padding()+t.scroll.Offset.Y { + if y < theme.Padding()+t.scroll.Offset.Y { continue } i++ @@ -354,18 +425,36 @@ func (c *tableCells) Tapped(e *fyne.PointEvent) { return } - col := e.Position.X / (c.cellSize.Width + tableDividerThickness) + col := c.columnAt(e.Position) row := e.Position.Y / (c.cellSize.Height + tableDividerThickness) c.t.Select(TableCellID{row, col}) } +func (c *tableCells) columnAt(pos fyne.Position) int { + dataCols := 0 + if f := c.t.Length; f != nil { + _, dataCols = c.t.Length() + } + + col := -1 + visibleColWidths, offX, minCol, _ := c.t.visibleColumnWidths(c.cellSize.Width, dataCols) + i := minCol + for x := offX; i < minCol+len(visibleColWidths); x += visibleColWidths[i-1] + tableDividerThickness { + if pos.X >= x && pos.X < x+visibleColWidths[i] { + col = i + } + i++ + } + return col +} + func (c *tableCells) hoverAt(pos fyne.Position) { if pos.X < 0 || pos.X >= c.Size().Width || pos.Y < 0 || pos.Y >= c.Size().Height { c.hoverOut() return } - col := pos.X / (c.cellSize.Width + tableDividerThickness) + col := c.columnAt(pos) row := pos.Y / (c.cellSize.Height + tableDividerThickness) c.t.hoveredCell = &TableCellID{row, col} @@ -424,16 +513,16 @@ func (r *tableCellsRenderer) Refresh() { if oldSize != r.cells.cellSize { // theme changed probably r.returnAllToPool() } - contentSize := r.cells.cellSize.Subtract(fyne.NewSize(theme.Padding()*2, theme.Padding()*2)) dataRows, dataCols := 0, 0 if f := r.cells.t.Length; f != nil { dataRows, dataCols = r.cells.t.Length() } - rows, cols := r.visibleCount() - offX := r.cells.t.offset.X - (r.cells.t.offset.X % (r.cells.cellSize.Width + tableDividerThickness)) - minCol := offX / (r.cells.cellSize.Width + tableDividerThickness) - maxCol := fyne.Min(minCol+cols, dataCols) + rows := r.visibleRows() + visibleColWidths, offX, minCol, maxCol := r.cells.t.visibleColumnWidths(r.cells.cellSize.Width, dataCols) + if len(visibleColWidths) == 0 { // we can't show anything until we have some dimensions + return + } offY := r.cells.t.offset.Y - (r.cells.t.offset.Y % (r.cells.cellSize.Height + tableDividerThickness)) minRow := offY / (r.cells.cellSize.Height + tableDividerThickness) maxRow := fyne.Min(minRow+rows, dataRows) @@ -447,21 +536,23 @@ func (r *tableCellsRenderer) Refresh() { r.visible = make(map[TableCellID]fyne.CanvasObject) var cells []fyne.CanvasObject for row := minRow; row < maxRow; row++ { + cellOffset := offX for col := minCol; col < maxCol; col++ { id := TableCellID{row, col} + colWidth := visibleColWidths[col] c, ok := wasVisible[id] if !ok { c = r.pool.Obtain() if f := r.cells.t.CreateCell; f != nil && c == nil { c = f() - c.Resize(contentSize) } if c == nil { continue } - c.Move(fyne.NewPos(theme.Padding()+col*(r.cells.cellSize.Width+tableDividerThickness), + c.Move(fyne.NewPos(theme.Padding()+cellOffset, theme.Padding()+row*(r.cells.cellSize.Height+tableDividerThickness))) + c.Resize(fyne.NewSize(colWidth-theme.Padding()*2, r.cells.cellSize.Height-theme.Padding()*2)) } if updateCell != nil { @@ -469,6 +560,7 @@ func (r *tableCellsRenderer) Refresh() { } r.visible[id] = c cells = append(cells, c) + cellOffset += colWidth + tableDividerThickness } } @@ -488,13 +580,12 @@ func (r *tableCellsRenderer) returnAllToPool() { r.SetObjects(nil) } -func (r *tableCellsRenderer) visibleCount() (int, int) { - cols := math.Ceil(float64(r.cells.t.Size().Width)/float64(r.cells.cellSize.Width+tableDividerThickness) + 1) +func (r *tableCellsRenderer) visibleRows() int { rows := math.Ceil(float64(r.cells.t.Size().Height)/float64(r.cells.cellSize.Height+tableDividerThickness) + 1) - dataRows, dataCols := 0, 0 + dataRows := 0 if f := r.cells.t.Length; f != nil { - dataRows, dataCols = r.cells.t.Length() + dataRows, _ = r.cells.t.Length() } - return fyne.Min(int(rows), dataRows), fyne.Min(int(cols), dataCols) + return fyne.Min(int(rows), dataRows) } diff --git a/widget/table_test.go b/widget/table_test.go index 8cefa84c34..a5e869f4b7 100644 --- a/widget/table_test.go +++ b/widget/table_test.go @@ -5,11 +5,12 @@ import ( "image/color" "testing" + "github.com/stretchr/testify/assert" + "fyne.io/fyne" "fyne.io/fyne/canvas" "fyne.io/fyne/test" "fyne.io/fyne/theme" - "github.com/stretchr/testify/assert" ) func TestTable_Empty(t *testing.T) { @@ -39,14 +40,14 @@ func TestTable_Cache(t *testing.T) { renderer := test.WidgetRenderer(table).(*tableRenderer) cellRenderer := test.WidgetRenderer(renderer.scroll.Content.(*tableCells)) cellRenderer.Refresh() - assert.Equal(t, 9, len(cellRenderer.Objects())) + assert.Equal(t, 6, len(cellRenderer.Objects())) assert.Equal(t, "Cell 0, 0", cellRenderer.Objects()[0].(*Label).Text) objRef := cellRenderer.Objects()[0].(*Label) test.Scroll(c, fyne.NewPos(10, 10), -150, -150) assert.Equal(t, 0, renderer.scroll.Offset.Y) // we didn't scroll as data shorter assert.Equal(t, 150, renderer.scroll.Offset.X) - assert.Equal(t, 9, len(cellRenderer.Objects())) + assert.Equal(t, 6, len(cellRenderer.Objects())) assert.Equal(t, "Cell 0, 1", cellRenderer.Objects()[0].(*Label).Text) assert.NotEqual(t, objRef, cellRenderer.Objects()[0].(*Label)) // we want to re-use visible cells without rewriting them } @@ -90,6 +91,7 @@ func TestTable_Filled(t *testing.T) { func() fyne.CanvasObject { r := canvas.NewRectangle(color.Black) r.SetMinSize(fyne.NewSize(30, 20)) + r.Resize(fyne.NewSize(30, 20)) return r }, func(TableCellID, fyne.CanvasObject) {}) @@ -262,6 +264,39 @@ func TestTable_Select(t *testing.T) { test.AssertImageMatches(t, "table/selected_scrolled.png", w.Canvas().Capture()) } +func TestTable_SetColumnWidth(t *testing.T) { + app := test.NewApp() + defer test.NewApp() + app.Settings().SetTheme(theme.LightTheme()) + + table := NewTable( + func() (int, int) { return 5, 5 }, + func() fyne.CanvasObject { + return NewLabel("placeholder") + }, + func(id TableCellID, obj fyne.CanvasObject) { + if id.Col == 0 { + obj.(*Label).Text = "p" + } else { + obj.(*Label).Text = "placeholder" + } + }) + table.SetColumnWidth(0, 16) + table.Resize(fyne.NewSize(120, 120)) + table.Select(TableCellID{1, 0}) + + renderer := test.WidgetRenderer(table).(*tableRenderer) + cellRenderer := test.WidgetRenderer(renderer.scroll.Content.(*tableCells)) + cellRenderer.Refresh() + assert.Equal(t, 10, len(cellRenderer.Objects())) + assert.Equal(t, 16, cellRenderer.(*tableCellsRenderer).Objects()[0].Size().Width) + + w := test.NewWindow(table) + defer w.Close() + w.Resize(fyne.NewSize(120+(2*theme.Padding()), 120+(2*theme.Padding()))) + test.AssertImageMatches(t, "table/col_size.png", w.Canvas().Capture()) +} + func TestTable_ShowVisible(t *testing.T) { table := NewTable( func() (int, int) { return 50, 50 }, @@ -274,5 +309,5 @@ func TestTable_ShowVisible(t *testing.T) { renderer := test.WidgetRenderer(table).(*tableRenderer) cellRenderer := test.WidgetRenderer(renderer.scroll.Content.(*tableCells)) cellRenderer.Refresh() - assert.Equal(t, 15, len(cellRenderer.Objects())) + assert.Equal(t, 10, len(cellRenderer.Objects())) } diff --git a/widget/testdata/table/col_size.png b/widget/testdata/table/col_size.png new file mode 100644 index 0000000000000000000000000000000000000000..d6b05ab0da2d8316cbbb89aa45dea32b25417f57 GIT binary patch literal 2532 zcmZuz3p88l7LIr{l#EtOs)8xOs7FwOA&O22nyLw-q+TV{@u;YJRD@pjD#cCIt3l-| zRi;dk5v@mxDAk&}sCQ9Rl?}Hq_j0XBq_1ue=KBkQqvE9!|4QKhu1cI~qT_ALk|f$QA0~0}t!E>7#)(T7)TEb|=;h1y84tSDGjLhP)x+M7)gOH0e`?QIdB-&n#7n<7Jh zO>7ves;nd_MKu!Oa5(-XOe9rA2NrIeKY#x8>C=G06E~Exv6&L|cY~#) z7A>^3wzf7KcX#)zS3j<-{4{Y*A)QO5Qd=T~7)E({dA$eEGqibqe|NdRM=}AXqJn}+ zTPSCFmAO^T&(BX%HYXAj#bU@3w|xx@G&D5Wgli5CQn#O%3{?((T3A?Mv)T3aXD$@5 z3Ds2Uk-8Bbs=dkE>gwvu%uES!@jG0W%@-@*+;*xk9gfS4=ZVincZI0pws7!0YH zA)lVq?eF#U#^aI_RT9IiCH9iLd&SV=cI&PE#YV^_QI3lt9;ltTi1xEOKVCN4Xh|rYM{sluLqZ;p4Wo6|| z-{F@pU-p&S0ReAX6noYD($&R|S+Ar=!;*hsc@#LAn3;9Y@N@I>($msDvL+@bTwPs{ z964e_*EKcW`aIV&YY?`-cQXTX1qlNPdrIn{t7UhKfvuyWP}Z{0l$n+3_T3GhQGpZP zByMYk5z4qvrG};sl#yR{?bzs=llS0l(m@ z*=5eo%@sIlJaO}MaXBg{rzW4?D%kMcQC{IItvo-Z63gc*)L>-OT`yk_VY@Os|Zgj*gCj0elALw(s!Fi>ycG<+vjA<8pGhePJo>l7|o1jqw_;P3#CZCmRWR z$-bwkS}4@!zF-$$@%i)TiV7|1c7QP)u6K3*7X#_Kk>IFb$En@^%T24$WZ%BNzMPyK zTU%Ry-K4=l9*>vP?H?8v=5J`Vzoq6%-rWe%%iHbIZ*4MvCLu1^S*!_Uc|69`SivTq zr>MvRr14FexXB@rUyjd}qnwmN|=qlY#BodXNhbZqfQ5PTM*S5mL z!}apgy=tSDy#gJ3D=%#M#)` z7{H`?q1frdg?W;xm2l6f`R&~GzVB`)c*!iLrKJ@XDpewNbnbc(>qbuYs~%opbWPY{ z!Vlx(skl&%4-#O^)>bqpzkPa&AC2dA#!<$DW@csvY8}c9>95yBpSLndO3R-<(R${* z7;e+ zzjXfg-qh68_rDZl%Uo&`(RPwaZHK;4R@c|+J``J$lT%W{l)SyX(3G7s5t=zgMY{6oK|w(;Iy-|+#l7WE`Z8VUt$2gr)EZXqEd6bc3RC_FfLsV(WSxVU(CclR3c%P+r7N=nkz)s;#D zdKRGXP3W7n^z@P7$bf({OzHEm*vQDAtEzg)t!OD{Jbqwu@&T2~pH5Nfef^sC^UpMe zBoV2IjinLt=C4?FT9(zmsf9&Tef>S1?~yPdDxf0Xl=U2Y^_>s&P`vhWGhvs1?fv`r zDM3o6q_Z_c!Ydj80Xl%CzP^G~l6Sm-<*w5b&41rXyxwSGWK;(5g?p<50|QM>O})Li<)WR>mz^(NI+54&q^1U?m|;Q>naMGPFHed$$7wz4 zf84(Sh$$e-ogQ@~PVZ9tf{JjD+^S@t(70V*1F9$<#l6PR)Beb-mF^qklKb8eJ@EKhm|>6yF_`4A2~lp8S?qY;1CkmY=^>zWvk4($I)@ zjLb4?){H||ik44=d1E-54`OTiq*WQKsZggqre zpmE$ldRP)R!I5UO5`TI?g{}S^(Fi4Bt3?SkyyU@~q+WL`C{LZOE-Dw;z*ZlMSD5WH z6FYEvDyoO&*l`edU(#M$ac0N5RzV~KyB6fBBG zNlKgFsl-XM>PRS1XE=dgf~TNqgeWG7#CbS|VKnobH>k=wqB7(Iyl( zixDaR5ClzWC)QmAv*DRYFc^XW30C4Kjvx&TrfV$rV4tjRjV)?qfwvZ`>H)Q?V=^xS z!iyN~O^8*)JcxbgBgVe0E9kL^oY$Gv;FN#s%%Qa1ikiZ~4vs}Y-S_lCAfd4BRCw+D SA?zCvu(03Y&Q;s^B>V>XqN8*G literal 0 HcmV?d00001