pax_global_header00006660000000000000000000000064150676525650014533gustar00rootroot0000000000000052 comment=f40ad6ee1624770d8f1ab2a60d02a3530f553259 tvxwidgets-0.12.1/000077500000000000000000000000001506765256500140245ustar00rootroot00000000000000tvxwidgets-0.12.1/.github/000077500000000000000000000000001506765256500153645ustar00rootroot00000000000000tvxwidgets-0.12.1/.github/ISSUE_TEMPLATE/000077500000000000000000000000001506765256500175475ustar00rootroot00000000000000tvxwidgets-0.12.1/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000010611506765256500222370ustar00rootroot00000000000000--- name: Bug report about: Create a report to help us improve title: '' labels: '' assignees: '' --- **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - OS [e.g. Fedora 36] - tview version **Additional context** Add any other context about the problem here. tvxwidgets-0.12.1/.github/ISSUE_TEMPLATE/feature_request.md000066400000000000000000000006451506765256500233010ustar00rootroot00000000000000--- name: Feature request about: Suggest an idea for this project title: '' labels: '' assignees: '' --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. **Describe the solution you'd like** A clear and concise description of what you want to happen. **Additional context** Add any other context or screenshots about the feature request here. tvxwidgets-0.12.1/.github/dependabot.yml000066400000000000000000000001771506765256500202210ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: gomod directory: "/" schedule: interval: daily open-pull-requests-limit: 10 tvxwidgets-0.12.1/.github/workflows/000077500000000000000000000000001506765256500174215ustar00rootroot00000000000000tvxwidgets-0.12.1/.github/workflows/go.yml000066400000000000000000000020461506765256500205530ustar00rootroot00000000000000name: Go on: push: branches: [ main ] jobs: golangci-lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: '1.24.7' cache: false - run: | make .install.golangci-lint make lint unit_test: name: Unit test runs-on: ubuntu-latest steps: - name: Set up Go uses: actions/setup-go@v5 with: go-version: '1.24.7' id: go - name: Check out code into the Go module directory uses: actions/checkout@v2 - name: Get dependencies run: | export GOBIN=$(pwd)/bin/ make .install.ginkgo - name: Generate coverage report run: | export GOBIN=$(pwd)/bin/ make test-unit - name: Upload coverage to Codecov uses: codecov/codecov-action@v3 with: file: .coverage/coverprofile name: codecov-umbrella fail_ci_if_error: true slug: navidys/tvxwidgets token: ${{ secrets.CODECOV_TOKEN }} tvxwidgets-0.12.1/.github/workflows/pr.yml000066400000000000000000000041331506765256500205660ustar00rootroot00000000000000name: validate pull requests on: pull_request: jobs: commit: runs-on: ubuntu-latest steps: - name: get pr commits id: 'get-pr-commits' uses: tim-actions/get-pr-commits@v1.1.0 with: token: ${{ secrets.GITHUB_TOKEN }} - name: DCO check uses: tim-actions/dco@master with: commits: ${{ steps.get-pr-commits.outputs.commits }} - name: check subject line length uses: tim-actions/commit-message-checker-with-regex@v0.3.1 with: commits: ${{ steps.get-pr-commits.outputs.commits }} pattern: '^.{0,72}(\n.*)*$' error: 'Subject too long (max 72)' codespell: name: codespell check runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: codespell-project/actions-codespell@master with: check_filenames: true skip: ./.git,./vendor,*_test.go,go.sum,go.mod,*_test.go golangci-lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: '1.24.7' cache: false - run: | make .install.golangci-lint make lint unit_test: name: Unit test runs-on: ubuntu-latest steps: - name: Set up Go uses: actions/setup-go@v5 with: go-version: '1.24.7' id: go - name: Check out code into the Go module directory uses: actions/checkout@v2 - name: Get dependencies run: | export GOBIN=$(pwd)/bin/ make .install.ginkgo - name: Generate coverage report run: | export GOBIN=$(pwd)/bin/ make test-unit - name: Upload coverage to Codecov uses: codecov/codecov-action@v3 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: file: .coverage/coverprofile name: codecov-umbrella fail_ci_if_error: false goreportcard: name: update reportcard if: github.event.pull_request.merged == true runs-on: ubuntu-latest steps: - uses: creekorful/goreportcard-action@v1.0 tvxwidgets-0.12.1/.github/workflows/stale.yml000066400000000000000000000013071506765256500212550ustar00rootroot00000000000000name: Mark stale issues and pull requests # Please refer to https://github.com/actions/stale/blob/master/action.yml # to see all config knobs of the stale action. on: schedule: - cron: "0 0 * * *" jobs: stale: runs-on: ubuntu-latest steps: - uses: actions/stale@v1 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: 'A friendly reminder that this issue had no activity for 30 days.' stale-pr-message: 'A friendly reminder that this PR had no activity for 30 days.' stale-issue-label: 'stale-issue' stale-pr-label: 'stale-pr' days-before-stale: 30 days-before-close: 365 remove-stale-when-updated: true tvxwidgets-0.12.1/.gitignore000066400000000000000000000004461506765256500160200ustar00rootroot00000000000000# Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib .vscode/* bin/* .coverage # Test binary, built with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out # Dependency directories (remove the comment below to include it) # vendor/ tvxwidgets-0.12.1/.golangci.yml000066400000000000000000000010751506765256500164130ustar00rootroot00000000000000version: "2" run: modules-download-mode: readonly formatters: enable: - gofmt - goimports exclusions: generated: disable linters: default: all disable: - varnamelen - exhaustruct - depguard - wsl settings: errcheck: check-blank: false exclude-functions: - fmt:.* nolintlint: require-specific: true revive: rules: - name: package-comments disabled: true exclusions: paths: - demos - ".*_test.go" issues: max-issues-per-linter: 0 max-same-issues: 0 tvxwidgets-0.12.1/.pre-commit-config.yaml000066400000000000000000000005021506765256500203020ustar00rootroot00000000000000--- exclude: ^vendor/ repos: - repo: https://github.com/pre-commit/pre-commit-hooks.git rev: v3.4.0 hooks: - id: end-of-file-fixer - id: trailing-whitespace - id: mixed-line-ending - id: check-byte-order-marker - id: check-executables-have-shebangs - id: check-merge-conflict tvxwidgets-0.12.1/CODE_OF_CONDUCT.md000066400000000000000000000121521506765256500166240ustar00rootroot00000000000000# Contributor Covenant Code of Conduct ## Our Pledge We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socioeconomic status, nationality, personal appearance, race, religion, or sexual identity and orientation. We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. ## Our Standards Examples of behavior that contributes to a positive environment for our community include: * Demonstrating empathy and kindness toward other people * Being respectful of differing opinions, viewpoints, and experiences * Giving and gracefully accepting constructive feedback * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience * Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: * The use of sexualized language or imagery, and sexual attention or advances of any kind * Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or email address, without their explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. ## Scope This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at navidys@fedoraproject.org. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the reporter of any incident. ## Enforcement Guidelines Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: ### 1. Correction **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. ### 2. Warning **Community Impact**: A violation through a single incident or series of actions. **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. ### 3. Temporary Ban **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within the community. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. tvxwidgets-0.12.1/CONTRIBUTING.md000066400000000000000000000035461506765256500162650ustar00rootroot00000000000000# Contributing To Tvxwidgets We'd love your contribution on the project! ## Developer Certificate of Origin The project enforces the Developer Certificate of Origin (DCO) on Pull Requests (PRs). This means that all commit messages must contain a signature line to indicate that the developer accepts the DCO. Here is the full [text of the DCO][0], reformatted for readability: By making a contribution to this project, I certify that: (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. Contributors indicate that they adhere to these requirements by adding a `Signed-off-by` line to their commit messages. For example: This is my commit message Signed-off-by: Random J Developer The name and email address in this line must match those of the committing author's GitHub account. [0]: https://developercertificate.org/ tvxwidgets-0.12.1/LICENSE000066400000000000000000000020571506765256500150350ustar00rootroot00000000000000MIT License Copyright (c) 2021 Navid Yaghoobi Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. tvxwidgets-0.12.1/MAINTAINERS.md000066400000000000000000000000641506765256500161200ustar00rootroot00000000000000Navid Yaghoobi (navidys@fedoraproject.org) @navidys tvxwidgets-0.12.1/Makefile000066400000000000000000000064411506765256500154710ustar00rootroot00000000000000TARGET := $(shell basename `pwd`) SRC = $(shell find . -type f -name '*.go' -not -path "./vendor/*") GO := go BIN := ./bin PRE_COMMIT = $(shell command -v bin/venv/bin/pre-commit ~/.local/bin/pre-commit pre-commit | head -n1) PKG_MANAGER ?= $(shell command -v dnf yum|head -n1) GINKO_CLI_VERSION = $(shell grep 'ginkgo/v2' go.mod | grep -o ' v.*' | sed 's/ //g' | sed 's|//indirect||g') COVERAGE_PATH ?= .coverage #================================================= # Required tools installation tartgets #================================================= .PHONY: install.tools install.tools: .install.pre-commit .install.codespell .install.golangci-lint .install.ginkgo ## Install needed tools .PHONY: .install.codespell .install.codespell: sudo ${PKG_MANAGER} -y install codespell .PHONY: .install.ginkgo .install.ginkgo: if [ ! -x "$(GOBIN)/ginkgo" ]; then \ $(GO) install -mod=mod github.com/onsi/ginkgo/v2/ginkgo@$(GINKO_CLI_VERSION) ; \ fi .PHONY: .install.pre-commit .install.pre-commit: if [ -z "$(PRE_COMMIT)" ]; then \ python3 -m pip install --user pre-commit; \ fi .PHONY: .install.golangci-lint .install.golangci-lint: VERSION=2.3.1 ./hack/install_golangci.sh #================================================= # Testing (units, functionality, ...) targets #================================================= .PHONY: test test: test-unit .PHONY: test-unit test-unit: ## Run unit tests rm -rf ${COVERAGE_PATH} && mkdir -p ${COVERAGE_PATH} $(GOBIN)/ginkgo \ -r \ --skip-package test/ \ --cover \ --covermode atomic \ --coverprofile coverprofile \ --output-dir ${COVERAGE_PATH} \ --succinct $(GO) tool cover -html=${COVERAGE_PATH}/coverprofile -o ${COVERAGE_PATH}/coverage.html $(GO) tool cover -func=${COVERAGE_PATH}/coverprofile > ${COVERAGE_PATH}/functions cat ${COVERAGE_PATH}/functions | sed -n 's/\(total:\).*\([0-9][0-9].[0-9]\)/\1 \2/p' #================================================= # Linting/Formatting/Code Validation targets #================================================= .PHONY: validate validate: gofmt lint govet pre-commit codespell ## Validate prometheus-podman-exporter code (fmt, lint, ...) .PHONY: lint lint: ## Run golangci-lint @echo "running golangci-lint" $(BIN)/golangci-lint run .PHONY: pre-commit pre-commit: ## Run pre-commit ifeq ($(PRE_COMMIT),) @echo "FATAL: pre-commit was not found, make .install.pre-commit to installing it." >&2 @exit 2 endif $(PRE_COMMIT) run -a .PHONY: gofmt gofmt: ## Run gofmt @echo -e "gofmt check and fix" @gofmt -w $(SRC) .PHONY: govet govet: ## Run govet @echo "running go vet" @go vet ../$(TARGET) .PHONY: codespell codespell: ## Run codespell @echo "running codespell" @codespell -S ./vendor,go.mod,go.sum,./.git,*_test.go #================================================= # Help menu #================================================= _HLP_TGTS_RX = '^[[:print:]]+:.*?\#\# .*$$' _HLP_TGTS_CMD = grep -E $(_HLP_TGTS_RX) $(MAKEFILE_LIST) _HLP_TGTS_LEN = $(shell $(_HLP_TGTS_CMD) | cut -d : -f 1 | wc -L) _HLPFMT = "%-$(_HLP_TGTS_LEN)s %s\n" .PHONY: help help: ## Print listing of key targets with their descriptions @printf $(_HLPFMT) "Target:" "Description:" @printf $(_HLPFMT) "--------------" "--------------------" @$(_HLP_TGTS_CMD) | sort | \ awk 'BEGIN {FS = ":(.*)?## "}; \ {printf $(_HLPFMT), $$1, $$2}' tvxwidgets-0.12.1/README.md000066400000000000000000000030071506765256500153030ustar00rootroot00000000000000# tvxwidgets [![PkgGoDev](https://pkg.go.dev/badge/github.com/navidys/tvxwidgets)](https://pkg.go.dev/github.com/navidys/tvxwidgets) ![Go](https://github.com/navidys/tvxwidgets/workflows/Go/badge.svg) [![codecov](https://codecov.io/gh/navidys/tvxwidgets/branch/main/graph/badge.svg)](https://codecov.io/gh/navidys/tvxwidgets) [![Go Report](https://img.shields.io/badge/go%20report-A%2B-brightgreen.svg)](https://goreportcard.com/report/github.com/navidys/tvxwidgets) tvxwidgets provides extra widgets for [tview](https://github.com/rivo/tview). ![Screenshot](demo.gif) ## Widgets * [bar chart](./demos/barchart/) * [activity mode gauge](./demos/gauge_am/) * [percentage mode gauge](./demos/gauge_pm/) * [utilisation mode gauge](./demos/gauge_um/) * [message dialog (info and error)](./demos/dialog/) * [spinner](./demos/spinner/) * [plot (linechart, scatter)](./demos/plot/) * [sparkline](./demos/sparkline/) ## Example ```go package main import ( "time" "github.com/gdamore/tcell/v2" "github.com/navidys/tvxwidgets" "github.com/rivo/tview" ) func main() { app := tview.NewApplication() gauge := tvxwidgets.NewActivityModeGauge() gauge.SetTitle("activity mode gauge") gauge.SetPgBgColor(tcell.ColorOrange) gauge.SetRect(10, 4, 50, 3) gauge.SetBorder(true) update := func() { tick := time.NewTicker(500 * time.Millisecond) for { select { case <-tick.C: gauge.Pulse() app.Draw() } } } go update() if err := app.SetRoot(gauge, false).EnableMouse(true).Run(); err != nil { panic(err) } } ``` tvxwidgets-0.12.1/barchart.go000066400000000000000000000124461506765256500161500ustar00rootroot00000000000000package tvxwidgets import ( "strconv" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) const ( barChartYAxisLabelWidth = 2 barGap = 2 barWidth = 3 ) // BarChartItem represents a single bar in bar chart. type BarChartItem struct { label string value int color tcell.Color } // BarChart represents bar chart primitive. type BarChart struct { *tview.Box // bar items bars []BarChartItem // maximum value of bars maxVal int // barGap gap between two bars barGap int // barWidth width of bars barWidth int // hasBorder true if primitive has border hasBorder bool axesColor tcell.Color axesLabelColor tcell.Color } // NewBarChart returns a new bar chart primitive. func NewBarChart() *BarChart { chart := &BarChart{ Box: tview.NewBox(), barGap: barGap, barWidth: barWidth, axesColor: tcell.ColorDimGray, axesLabelColor: tcell.ColorDimGray, } return chart } // Focus is called when this primitive receives focus. func (c *BarChart) Focus(delegate func(p tview.Primitive)) { delegate(c.Box) } // HasFocus returns whether or not this primitive has focus. func (c *BarChart) HasFocus() bool { return c.Box.HasFocus() } // Draw draws this primitive onto the screen. func (c *BarChart) Draw(screen tcell.Screen) { //nolint:funlen,cyclop c.DrawForSubclass(screen, c) x, y, width, height := c.GetInnerRect() maxValY := y + 1 xAxisStartY := y + height - 2 //nolint:mnd barStartY := y + height - 3 //nolint:mnd borderPadding := 0 if c.hasBorder { borderPadding = 1 } // set max value if not set c.initMaxValue() maxValueSr := strconv.Itoa(c.maxVal) maxValLenght := len(maxValueSr) + 1 if maxValLenght < barChartYAxisLabelWidth { maxValLenght = barChartYAxisLabelWidth } axesStyle := tcell.StyleDefault.Background(c.GetBackgroundColor()).Foreground(c.axesColor) axesLabelStyle := tcell.StyleDefault.Background(c.GetBackgroundColor()).Foreground(c.axesLabelColor) // draw Y axis line drawLine(screen, x+maxValLenght, y+borderPadding, height-borderPadding-1, verticalLine, axesStyle) // draw X axis line drawLine(screen, x+maxValLenght+1, xAxisStartY, width-borderPadding-maxValLenght-1, horizontalLine, axesStyle) tview.PrintJoinedSemigraphics(screen, x+maxValLenght, xAxisStartY, tview.BoxDrawingsLightUpAndRight, axesStyle) tview.PrintJoinedSemigraphics(screen, x+maxValLenght-1, xAxisStartY, '0', axesLabelStyle) mxValRune := []rune(maxValueSr) for i := range mxValRune { tview.PrintJoinedSemigraphics(screen, x+borderPadding+i, maxValY, mxValRune[i], axesLabelStyle) } // draw bars startX := x + maxValLenght + c.barGap labelY := y + height - 1 valueMaxHeight := barStartY - maxValY for _, item := range c.bars { if startX > x+width { return } // set labels r := []rune(item.label) for j := range r { tview.PrintJoinedSemigraphics(screen, startX+j, labelY, r[j], axesLabelStyle) } // bar style bStyle := tcell.StyleDefault.Background(c.GetBackgroundColor()).Foreground(item.color) barHeight := c.getHeight(valueMaxHeight, item.value) for k := range barHeight { for l := range c.barWidth { tview.PrintJoinedSemigraphics(screen, startX+l, barStartY-k, fullBlockRune, bStyle) } } // bar value vSt := strconv.Itoa(item.value) vRune := []rune(vSt) for i := range vRune { tview.PrintJoinedSemigraphics(screen, startX+i, barStartY-barHeight, vRune[i], bStyle) } // calculate next startX for next bar rWidth := len(r) if rWidth < c.barWidth { rWidth = c.barWidth } startX = startX + c.barGap + rWidth } } // SetBorder sets border for this primitive. func (c *BarChart) SetBorder(status bool) { c.hasBorder = status c.Box.SetBorder(status) } // GetRect return primitive current rect. func (c *BarChart) GetRect() (int, int, int, int) { return c.Box.GetRect() } // SetRect sets rect for this primitive. func (c *BarChart) SetRect(x, y, width, height int) { c.Box.SetRect(x, y, width, height) } // SetMaxValue sets maximum value of bars. func (c *BarChart) SetMaxValue(maxValue int) { c.maxVal = maxValue } // SetAxesColor sets axes x and y lines color. func (c *BarChart) SetAxesColor(color tcell.Color) { c.axesColor = color } // SetAxesLabelColor sets axes x and y label color. func (c *BarChart) SetAxesLabelColor(color tcell.Color) { c.axesLabelColor = color } // AddBar adds new bar item to the bar chart primitive. func (c *BarChart) AddBar(label string, value int, color tcell.Color) { c.bars = append(c.bars, BarChartItem{ label: label, value: value, color: color, }) } // RemoveBar removes a bar item from the bar chart. func (c *BarChart) RemoveBar(label string) { bars := c.bars[:0] for _, barItem := range c.bars { if barItem.label != label { bars = append(bars, barItem) } } c.bars = bars } // SetBarValue sets bar values. func (c *BarChart) SetBarValue(name string, value int) { for i := range c.bars { if c.bars[i].label == name { c.bars[i].value = value } } } func (c *BarChart) getHeight(maxHeight int, value int) int { if value >= c.maxVal { return maxHeight } height := (value * maxHeight) / c.maxVal return height } func (c *BarChart) initMaxValue() { // set max value if not set if c.maxVal == 0 { for _, b := range c.bars { if b.value > c.maxVal { c.maxVal = b.value } } } } tvxwidgets-0.12.1/barchart_test.go000066400000000000000000000026021506765256500172000ustar00rootroot00000000000000package tvxwidgets_test import ( "github.com/gdamore/tcell/v2" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/rivo/tview" "github.com/navidys/tvxwidgets" ) var _ = Describe("Barchart", Ordered, func() { var ( app *tview.Application headerBox *tview.Box barchart *tvxwidgets.BarChart screen tcell.SimulationScreen ) BeforeAll(func() { app = tview.NewApplication() headerBox = tview.NewBox().SetBorder(true) barchart = tvxwidgets.NewBarChart() screen = tcell.NewSimulationScreen("UTF-8") if err := screen.Init(); err != nil { panic(err) } go func() { appLayout := tview.NewFlex().SetDirection(tview.FlexRow) appLayout.AddItem(headerBox, 1, 0, true) appLayout.AddItem(barchart, 50, 0, true) err := app.SetScreen(screen).SetRoot(appLayout, true).Run() if err != nil { panic(err) } }() }) AfterAll(func() { app.Stop() }) Describe("Focus", func() { It("checks primitivie focus", func() { app.SetFocus(headerBox) app.Draw() Expect(barchart.HasFocus()).To(Equal(false)) app.SetFocus(barchart) app.Draw() Expect(barchart.HasFocus()).To(Equal(true)) }) }) Describe("GetRect", func() { It("primitivie size", func() { x, y, width, heigth := barchart.GetRect() Expect(x).To(Equal(0)) Expect(y).To(Equal(1)) Expect(width).To(Equal(80)) Expect(heigth).To(Equal(50)) }) }) }) tvxwidgets-0.12.1/demo.gif000066400000000000000000012613141506765256500154470ustar00rootroot00000000000000GIF89aM1!""% (#,$'*,) %L=+O>(;hXC 043  iL lM sQ!+!L"&6"zU# ,#W$$+<$b%$0&i&i''6B'7O()4(Gq)&1)5H)u*'2*{+%,)5,/<,b.+7/,70.80>Q1*1AT21:3!30<31<3BY342;53<5E\5H\7Kb97@9Pe:%:1:Qg;9D;:A;Mg;Sh<:B!)?>E?Wm@[rBXuCAJC_yDCMFDNGEOGbH=I.IHPIgKJQLhLpNBNLTOvQOXRfwTRZTV3VHVWVYX*/XU_XWa[\Zc\[]^\e_8_^`__a_`_eb`id:ddedefKfdmhXh~iiiikZkkkl23ljrlm>mnpqowrsAtrzucuxfxw~yxz{66{d{y{|z|}F}ML}{}~|}nJPK_ׇ[NzPS˗@(;hXC 043  iL lM sQ!+!L"&6"zU# ,#W$$+<$b%$0&i&i''6B'7O()4(Gq)&1)5H)u*'2*{+%,)5,/<,b.+7/,70.80>Q1*1AT21:3!30<31<3BY342;53<5E\5H\7Kb97@9Pe:%:1:Qg;9D;:A;Mg;Sh<:B!)?>E?Wm@[rBXuCAJC_yDCMFDNGEOGbH=I.IHPIgKJQLhLpNBNLTOvQOXRfwTRZTV3VHVWVYX*/XU_XWa[\Zc\[]^\e_8_^`__a_`_eb`id:ddedefKfdmhXh~iiiikZkkkl23ljrlm>mnpqowrsAtrzucuxfxw~yxz{66{d{y{|z|}F}ML}{}~|}nJPK_ׇ[NzPS˗@KE3N#~Cw@t s `Aӏw KlffgϞĸs[<2ϡGǞ]6wtnǓ N۶o6;cq@qn1GY5MʸwƠ=z;xڜByDZ /lDT 7 qAu{T: )\;wlx;rF/ :b@H+ʹ%OD2at`c%({;^(SpojB<w*-7-/IN 28a =ҳ:? c:HS; y@Nw T.;J<s"=D@O Q "*ewPL&Dbʅ̥.!]ƀw|!ܐ1}9JЌAz)M\K!f5rq<:QYu|gQAz'=Oy" )PgBς(*љtE% Њz47K4O*J ҕĤ UF#Q+-iI`ђ6)թPӡEjEkjԦڤNRRg0X T@*.JVlLP!9+\#֘ڳx\!u)XԿ#~=lBTԭC+ق0ū^+Y[6L +VК6!h+PȞj7-nڌupq[W=.V{*}nSPcgA61i>"tF`3(jТ _>Լ%s[K;k=7}A6}2إDp /-/ _(0,Lax;W;ׯ8αw!&B8ъnEօ+7Du|(dEɹ2僘 349gɖ 1-sP {|7\giʹNFh2BUo!NJUƵ.b%CO[dԤSQSWdլNcPWSdִF sN[U5nW_KDaH A(id-[k{E!`H8D{\Q $! C0Ǻ\&3 pDS:;:B?P~#w;ỹ=$GBD^ jyM^Kz?QQ.0]h'N;&'7 F<"@(@K;Kp">IMl.})Lc*ә@Ir:Z=OhT(Mo6%DL3{LyId1&E0u Tœ LijPyݫv$Hmu+]zݸ^"ꪼcc8*& 8`\"][ZFM'iO:'c Ӛ;hBѢ|!25V5 5'Jj#ga!@lFi' sp,#z#c1';n;: 9x$:c:#3 h&.c;⃻tVZq@`Gvfit 'bR%DAУ,c=gDA+x1#>A"BAgxBA @@ @$4A>@! xoҶovt4KfHHKDEA4DIOEs4I HIJ:zG~$DDHHA$I4EtIDHh8x||QjƉ_$XKk6;ިTLLDLfԸhB4&9 QtǶ_ I^JJCYy)yّ l8i(.9XV8)y)0ٓ")棐68:`> AI pWi EisKJU]5] %f O  l]yGIha^5_^` %?v_ٓ_6` P`f 0TYix5u @ }љ(91Q&a6 wP @ 2Nyj6ɒ eb-b5b2Y`;`  ѝ $/9;#dDfd p՞)d%Rɟ.)eWe )堞E ) *߹-ɡ 顰fm`zpp y7<ɣPy{g&ې  5[J597JVXL9Pi$suZ8*)zʧ}ʑ w'z 8Z6zQ9azNOzꨝJh :5QzZcjN:M::N*b.1##Zʟq $ aPՏ0ʒ !# pظګq }QaPW֪s8.p:Y h 7pxJb* I0p#)g;QP`={ !+F' )0 QzJPgQ0:@#|hjl۶0N;0 1k JP}}P%WjRxq.0g1 ~+Z[Gp0Ґ|+T 5"ب ۰#ۙ}% 倗F@+v+ڹ˻KʳF i0f˼伂 ʲWлm {z[ ەy҄ۛ8 f !J~ۿE L K _lN\W̿ .|W\#%L>,3c+-!LV2LK1dtMm6ΧF,Hl[ZL1L6iA`q$*AlQU:zaclLWg@Ko x@W e,ȃZNCw*ѡ?A|islA3qq#{(-w,/g%G3w#qQ}:g EzAf|ɴU,|9a9 B3 JBv:CGo'&^`GX%\%&,whxjWfW''zvBͬ79d,=lלɸhͪ͢24C27(C-ނ 8b-آ-&{2%r|.zRW|| lYilasAюC̠$T2<34C^~FEs4׀2 Hl-B|G є,ռԅ%3A.S l0]0: 1@b8#=;6cطc==0UXIun4eV?3$t@ ux{@ @tHpHs) BbݍvK|-~=ە\۶ԸmcII cTFpFfFbDp}-{ -I(I݌T4>Qy~HM\k7ސ mۃ6pH)> }-/1E㴆My&)Ă5xD >n@B^DN]29 p*{釢TMbd;,hNW2Ab.=a~~^뽮>_PR02^D>N^Վ9 NXV{\6~n.^?oꟵ=]}M=aڮ> #(bqe0ۅjɖnjQ4; QO !HJO&R_QOP u\?_Ř򘑩 ؤ.o 0 U  8p yQ  L 6` P10勵*UP?V~` v fo`ɚi`^{?A pjp 6p~ &P!j P:6 `P R`L j`6 p&p@ 4x0aXD(V8bƍ;bG"I42J\tfx 1]`ĩ礠;{ީ6ҭ#]BSTTRuUV]~uyOXe͂PZUWܶuśW޼W_#6SeêpL]qF+ LW2R|bj Un06C*=yen%w7JTiPl0Րej*sMQݥq0կ]͟kVzk+;Wo_|ԗ@ l\Rc\CPAd\HE^:!VMD#rRdQisQ!܀$g$N8w̱FPpi]H$|$t_n٦̮ /?<1Jo=3j͸3N9ϯM ĺX N>3PƈNL@3qX!TQFO9tEI=URWMz$`DGȆK_V\\mON0_3243M5يM7[oѪ7!F SÀL@"\%Ppz '"`Q@0Uͤ 7Eh ;<-S75TM;U"TcUmTRqQupcxi_Veavc( rg]viUkSV[n% QN9DU*b7pPE9[1>9%!COXdBEEaQD9d&ؤъ1X9θ! ]|dkD&rsxIw tI<]& 1&-k6ΣHZ̥.K6F>yե詚HVP*{qƻq3's5?|S۽wWMcbTg"EMN|lKƪ˥|D[?[WWApY_OBVu=Bn?/ O@B2d ъ sCp^MHD тsE6эo6dDKS5 |^p32 [1IK5haffD%:GoN5$g83Qd^2e 79I uRQ(C 6t-  Udi=V:}EjR,!gD@ QT]M}* EBn)OAxJ$1!6D!^eK ;jUIz4a>tMi-b$P JPZT.f@G|aqeU2*յE(S)A XDl vU &%E8"JI[ֿ! l`! a@1Ŗs(D+vB?:Zaq!{.1',CARrZi;H$z r $D! a␇@$"M{; י`P%0FU漤]3 V=gWs ?S}vqvg9& v DCa'@PZ)X ,Xz;}_R1Tع:Pc%ˠ vVeWҳ b2a 4`H$BU׻/K_F0! k#1Uwo-7sS-@wa0n,Ld6 fY~4{/vC*8mq74L@F ')Vۺbmn7;\\ry:^:,]gP Mts Y'{Ɏv{8ڶ>S>1,-׫Ky7?ޟ7g9C^Q #S@ÄG%(tR_V4?dw?'_DC.W?T:|72?죿-(ts%\&B}Z@T & |= L' p))A"A SlAB(A4Bo[JBL'l DӽȀ./B.$CwĘ(ėpE?x҇+Cf`D0|EBFfpc F`wxF`FtXuR;5A',EQt:TB(p?xCx.Q6)H))8AC9Xw}{0-uxϲȉȋHaHďtH4HHd3dtɐI,ɚL?ԇqӂ+:SQ+E9Fm"ҮF+,(8GDGb8lG(:TETBqFЇ, *-pЅymBa:} @LdLDŽLL*̗`IlLxLB| 1GLLL՜LxfO..x*=Xؐ 2( K.dN/9B/P/ldt\?)DuxK\E00QjHaIH(^$GpFMF6X Ї:͖l5PEδP UIp -TPm}e\&# 5@ 0p;KьĘz#[P2I(35$OclK|w p609p/ 5{6n1}pwpz%Do^8:SF= @S;-4T80M8)uq s-CuѴ v-CcpWr wWH Mջs;Eh 7ts( 1JB17DQFXvi`Y(V¸|e Ȁw Kׅ3dp 0+83hmx:WH;D Yu-8ZD ٠Z}W8a( uZ%Z ?Pׂ-:}K=9 8Cu9͹()/M+R\cܔKe֗paIyЭɽ`zl8Myx$ZZ?0]u %^$]޴==}[ƓˈɛL3afnoq&r q6tVqFuvwvygRz|{~g$ʀ&Fh4ffv舖h;]Bw@K- h~8Ihh&i8iiivi#h^bv4hn J *i]hjniH~XNơC0jU ־ޥ斚 hjFN "xh k CSjhxJtPuFIx`x{I6ސJD{apfIȪwx Oxu@ X~_v ɦl^lG`w0cxloqphsf[nȆi5Rlom&퓴*ntHmfm׆mm n؞I nnnno>kl@o` +͜ ]؆l, 33{Â"Ԫ0gM+op6rM_p}`S` &(?Mp`@ r0qWqdq_!Frr1)FyM<}'&wr(?TF G xHmlpЇp: _pB|`F8xgxXh?]^m ǃp s 7f_-=/x+ԄxxGyyZpGygyw zdXzӹ{P@pqgUwƹnj{]t\yu_CwJyuXyaugw0v ?Pv^P{z{{Fuɧ|_K}x_|7 ?|.h٫` x.zߕ`fHu qQ?}~">roڠz0j]Gb-gw Z_,h „ 2lA'Rh"Af f30 NVWT$  .@@ 1[m{`BF |ΏF,0g(y35#fVjNJcJi h.^@7/{OG͑%k0G/ѳ @d%is*+sw)KȻԍzj֮6zqDŽ #V\pb-cFزT{7@1 s&&˙n(=|Ώors 9dUfyPikFm g^yfXd ]w߅7^yW{7#W}5# u# AicDG*$?29ѐE>9eH%Y:dE8Rjy3P}c}9y&qa–&7'uye'}f9(ک*HJ:Hj4B)‰茘z*Tv:㧩jg*ߪz+b$}:, jz*,}UΘ{ZjmC l|).zޮ麛( b{o޺/{޼RJ<ݔ 7pckeZ;-쳏#%sC]I#,ܨ. 's3 MPC]u2}E,Ut`Z5R50a5` }^.g+mZn}x=7p}wde6h7ki7^]K޶x!~9{ʹߙߵ9bSn׮ L=Lꬻꭿ~{^0/<#;ϼE;랻)]u4 uF q0PqBAT7`GdaG?oVl$0@8#8 j`-R*0<GheK 7p3@Bʐ Zr1!} C@@0 :Q" L؀X+fVĢ-ы\ cF5эphG: "a<H1d!Ў?(` pZ|P"HHQqK80@A@T$fL:+ex1xKDd/aAч /&я46$&IQ D/4 0Û,#:D#rY.$2$10| F-$΁6P t58Ё5@SG &вF(2.$%RvAi)k7)Vҗt tb= bͅAQ1GEb<q!1H` BZW}daʮ**$ jxa leka"Xhd[P$PNv x6T6hrE] b/t` Du ^ԙ.s -[#Ya Jq/p$S{\"=-j Ё\ tD& ړvFm|JhG-0;# 4F>a`[a= Br-\.`U0M0?(| B|[vI]kq`^ "4ˬJ"@") 4HV2\!OX92>9*rElfw"e^sL5Y\mț.9Oz֝+?ks~W)yLb$E'4eJ</c%dҧcD8tX,>1Luxk/rJ-rX<.b'{FvgM`+4Jut%dG`ݐ<_^6kVb4R!I{幨э'u#g= ?x>Yaɱ,+IY}=;0$x'nJTbyA\$ T*{pr4 ~mu1=!C5fszUӤbXq_21'3ig/5iND=ח7ۙ1 +&;KSD5@q^wNOxkL,yʳM|\?MzD{v⓼GaF!ɀZM*ā\|VuyHPBXn`'B'x蒀}h t4IZ͋*Df4N| %5h܃&{2Ȋ@ҌC"E&U~IRNהȕNEk6Z6i[RDM~K L^݉)Ijə\Ff l֘xIwǝ).QV~IWVe]%IrY ^"Jʐզ٧tn٨Zb٩jݪK٫jJ^dNIe ^c*ɮ>Idv*> BdOh ;<]$)BBcDCzf ޖ1+ngo@HQ IGJ!Ҳ=+ HKLƕC}}t|"lJEhtcho1e9q@5iTUG3^s|s|4Fx5|u`:0ALh7잻z^ }0škWz;(-B6(1Eh}m&?]l?"۵k# >Suo[>wmY#~>16a_wT~Ky]TSD/64w /+*xkx^[j3![D]g>]8 FJS>3c?ߦZW 쇇Jͭ}9@8`A 0aC ,|(1>4p cGAT?&I:& eK/aƔ9fM(@&!a;Y0b ah,v41Щybj׌lͲ5kر^Kڳhee{QG: W LeF 68KŁ7oL*[-5s 7tKL2鉭;sj۷qMynF‰=>}\:eWp|q{K-ߔ͕*'ӷ7>{(_R;!sA(d 9<̚˫ CH(ŋ`I1dl(Fh<j4t R!js,*8J* r&%԰ ^L1,##{-C,4܌B̖GĜS=Ds&$#j`B r`#AΙTM;S/NA KeTSQӘMW"2Xi]y%IVLUaZVM_TYe} Y j 6H\qZu)g $"@a " ^MȄN[$HR䑤#G0X|>&xQ5X B*h7@Hgg` `VVhce$f!E4`xAvRN{W#F:j2D ::FB"j# bxR`lG *G+Gl#\sNl! % 1Ƞ(E*hTvH%FcbH)(sj|W̍yE}~-a (52BH@Z b tÂ|oo HDy ls͘FT M삫s^@ uX@ 0.N Ի!DQ&)`P@ HgaC@WaW(/{Ńh'A!24#bo;ዓ ^0<0xy қ>҂8` RzRqYE&$KA5DG%G;w4P_u>ȼc IClVx !#RR ~`~oM_-)a3%s9 PPpޫNJ!plkJ-, 9*lDШԬ50P0NpA0?meHg0q0a&L0B_#F`2B^ɠ@(0" p`0 0-#P B  p ; o"0p p_ F 3 0#Z -&B Hd2!  b2f D3WQ% .d"Bq !#NQ 8c 1CfdDQ cd#TH[b2"ffn&uB@#@ Ȁ@ #13b5Ҏq" b /1@hm0"mF 1#qsF"1fT"j! J#$qB*@!&kdlm0b$"#Q#$F ^lbR Z(#`%k#"r"+'3b()%X2#;"'wrDvKgbj-n2oJA",(oB *{#R ~@  R #R/#+?.RֆQ[َ#n +G(0SqA(r0321 B %*rk #R3'r\r"&%j#vL#bsfs5!<۶)O0Wu^"p @߬, /Tu\#S:b< N ֠ 9Q;3#ԓ=ݳ<9i#ޭ"l"(Rf">o H2#D ;@"tB+#:4AC;ra="Egx.&SFm(DgD'VEDӍ;=߶'#|0b||.b>, *J)||Ї6:pL >uIgNqM1"IÇIIqM۴Lr!a.#Fn# !  aF/bC"#DQ5RSP.H jH;T`u d#uQEU UR!UU5u"3,t"6q"@H !`  : .?b((Z \GY)6UuM5?  2Y='5_9ȃ\/]ٴ4Y@=Vo"s!Ǎ!ȭֈG'SiAAw*s.!>Vqd VGn^(b%Se#peGvq\UW1e$poP) `!> GxxQ5؁;VCxPh&#)#))#  h!rnT 8uIV"xx w"Xസ!ؘژҘ}?Bi%mAH& \"$!ځXI I0y" iI#P>hYtkk."[^yrY%#`u8vP-\H 2h aAv@ a<;[) 聺U1*:baػ!:@ ԁt"! {-a\ < ܁ʽ9<%} ! `A| :&*.d! ΋A$h;!\i!an%[!v[`vԁjGGDSBڹ$*ŝ(½Se}AݓE}5E/: Р!!b%ޭ !'@8At fA/aab ȁP&~f ,#~ T!,!0^9<E!H ??H@~~"f!>s'p b>韾q~뵞%#Ȟ@!퍀lA ^! ` a B>C^A+  !ҁ-2рaj߉~>7 ^ %Mm ѠJAW_%tA5d?~ l"y+ȁy! ‘-trA#,H,g2ȑ$K<2ʕ,[| sxm}x"t@ΑI|>8jVIDH1Гb:#4jƍR@P#r9*͘lۺ} 7ܹ0BPLaq(K;('#`06 x dW!P:լ[٘F .|$Q `gr؍p1b3G~)`gѯL>xy-WRkVxte1r_8Gr22QSFhPC9Qs !x^a&/{W_bW~ GK.!WD;SJuSvQaJ.9^y96E ҐhU%=E:M Rf#FtCN lAhXiLg1'%YeE[vbH`)P#ҕY Dr$)z#yXGw~j$9 ̤g:TBw83sq!d CIP3lQ²ZtS~L*m^_ƫ iSǭɇ^mt V )lt n c*z/>#,CR#H$.E[1FP'T,S 9:[Ŏ@sw.tӪpSts 4r'܍Y϶=ol3V!i# :4O<Ԉ)rW~VR3GFc6/8&Uq 3y" \2jNzz:G&gN[MhH|O| \,<+5ϼLBK=vlϽ_;\;/kh~ן~s~x῕~xoC⽿=f~nw ( 5 L@=5lK 悪?0.dQs$ra _-% ŗ0A(0ay(ĖтHLD%K!H&bX"h)P$#GRE"7%E\1B,r#t#1"F%ڱcǸ?jЏ $K)D*2$|d!'=Fё+d'/FOD&Q,%EHXuc*S"K$I/gZ\%[_Dd0H̓/Ӭ5ɚkj&pF/sI˙spU8m=QjG**О~HRꖥ:LejZմ%,IQKJDW׃%jk\Ր$$pj[ү,7Gְn3ιTY\fę5pt =h YYd/{CWYgvi%ʋ..Q2gˑ\ɖS{k$Qu{jR .5*;ٗ%q`UUfK;xD M~*=hM;PFm=d6 x{Ц7mT}p?V氨u'yw}y?#62_yqwv+~nmKݞ8K#o*9g_[vy9nz{\T_ tgo;!|GKߴ|O|3|M~Dwn]}w|é{7~~|x'|(g|؀~Ǘz͗v'oǁl~8xȀxr'~Vgy~(t*8%Ag!zV}hi:b@(0h,x2t xwwx÷y|el'~5[g[8'}o}Jh~G~jȀQhi&(vGdX&\t|~ rJW{shwHI؈QׄGsP|oy-sX{waV胃؅eXygh] U~4؈6艪(bxgLjɨȌivHhWѨȍHx{xh爎~ȎXldjȏ菀(I} q  ĶSIiѐɑ 0@%i')+ɒ-/ 1)3I5i79;ɓ=? A)CIEi=/p p)T i0d 萝T`Iٹ:{ * `WYp*lj 0`̮ͯ̓kPh9c<m1ln,%Isb <˾ /l! ;Tk ܲ2!3 S˵|˫!p!8rj+x RI P / {> 7 :MBae PZk8adu$>SJW-NV[-R_͑Z cIbMgGk}foD#isMumwy{}͓I ׁ)؅m؉͕! ,1 H*\ȰÇ#JHŋ3jȱǏ I"(C\ɲ˗0cʜI͛I2%Ο@ JѣHUi'PJJիAhׯ`ÊK֦V>˪]˶۷St ݻx(ӧ{ LԾ^̸KT ˘KH9ϠC ӨSIհc˞=״svCܼ 7Cē+_nḄKչBԳkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZ^[iNIlrp\'`<-;W(2ʢ@%S\c4IK!]R,VV8@Y#xGd.x.q@LtS#t1ĝ@4b F %H@Cxa1WIW-mKh --h!}ZE3  $!$G0A |ġIK0H2p c8rՒٚ|(UK(|AِDnu71*RܗT#-18=D[DSRfb&HHEԲ(/ vcx&3Z㛠 ! , 1 H*\ȰÇ#JHŋ3jȱǏ I"(C\ɲ˗0cʜI͛ I2%Ο@ JѣH;i'PJJի6hׯ`ÊK6V>˪]˶۷Ht ݻx](ӧ{ LѾ^̸KT ˘KH9ϠC[ ӨSIհc˞״sލvCܼ 7Cē+_ḄK>չBԳkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$')%ՂIh-lL#dYBn)糀Z-eL`c@-$ +bOIA,0<0,.x!&dLPf2($H ~ٜ`tIN,0FLzeFH.1G"P (NLX!̸Jd-ZВxi]  :Жt%% :R,ԥ ]I0 %U 8)*h@RE;ҁa T%Jd1iCM/L kMU2t-DIM+TØKdF8i؈5$X2p"P nqt6#! >[_G0 OclWj|9%i)]"E3Q"1J I?! e6V& %> ]ֹA/F˪]˶۷It ݻxe(ӧ{ L0Ҿ^̸KT ˘KH9ϠC_ ӨSIհc˞״sޝvCܼ 7Cē+_ḄKNչBԳkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'ǭ,Ljol'`d`6L)V(2J0A H3TO.9ʵ&>! `T 1b]jj%LPs&&Y2PlI9k)`K"NleRM/*ecXx'?3)HL dLh#b8(H,jMd4hKAT`x4ʕ0t#Zyjd:$7mȆT1 ;G C":CxiOU"]@"xf0rZyZ";;p3+T1Uܢfrّ i 0ꋼ&&*$(x>>Yלk-[T`KhA\95(n:~0\T7*.1}' #^ øT|p;Oזw&ԇ>AZȿc!4]2W7.~I.]0 n WU(5@0&#BpQ2! ,1 H*\ȰÇ#JHŋ3jȱǏ 3Iɒ\o%ː0cʜI͛8sɳΓ#M}Reˢ>*]ʴӧPJ:('"-ʏׯ`ÊKYXQ6zԥٷpʝKXhSnEj߿ w^l+^̸1 g=21˘3kXZl-sM;=lT4װc˞PU]]ͻoŶ"eУK|^ӳkauםwO C7Ͼ'/(h& 6F(Vhfv ($h(,0(4h8<@)DiH&LZPFyUT&M&TZZb%(חdI%Vf;idp։U%٥|dڸmnj衈&袌6!U))_`.@ ⤜饚~餞~i*ij@!p dezjvx#iF80 vS(UEPPPijwRdiqT@mS+VnvbθVK)F@,+ `AU#-#:٠{fD#YA!rX^K00c!L@0cD@^IIk3 Phr1 @P[;t ?%g@mtI޺sG#] ܪZ݇#u|BnS k9~w3験gzکXNJzXƞSyyE.TUnq$Ǹ"ا@]pciHPA($)Bd$x%IDc'1JVɒ@puz@146|pf x򑢃4QT`i㪴 HW:$@?C c@3 #$βI21 }: “ࢰj>%U%=*JO#5iIzR/!SѴ7iNgZSԦ=KaꗠGiRy8Y*PJUV:uJԫ?UU)`Alc'(WֺUV-+rwP*x9a2Hl  ,\c׼bdŬO3 f8cDEZZ_61qfJ[>kZx`ӎD46wmrek xt~[G@]W1l @W(6j`ݒZ dulfY#A@$UfӾ!u(큱+D eALX/ms=jU #A8gCaObK9rɫUb1ZN;=u 3\ `QLgȹ[nj5zgY{3g#γzhDτ~4X;šDGzzhI0iHvW> /8mJj7Vx=I~4y^E.ԁc)٠sL``rg+"{$A.<[2 т7zO?d{@]p@G|/>zǹ|8rI|-?ws_S4SVи/VknyA0% W9j#f9@ԚeV:ʓNh9x{n[A@[Ԗ;Na$ -P^;p a\8x$XA}ߚ|:o;YXMWq{uSPO;ЏO[Ͼ{OOOϿ8Xx ؀0 DQ_X&P h%P >!%P %+(%(8W<؃>@B8DXFx]acF@5 0==0 J,41$rC` `YY` _8!@@"(Z?vH]p3 a%attk؆⒉fhbHohqH^ ,ZZY5*ALڤNPjeT SJaZi@h1Yl8fʠɦ(W:Y8!]uZ4!ꃰs?I8Hv< * ѩr: ԙdpZ͙йQg:!1zI ѫ2*a*̪7A jߪ *: Z<:ڮQg颦*#J' Z19ѰFأs@1[GJ&{(* gœ \0p:.;6ײ<; AKCE~tt(<2ɴٯ xJ\Zњ^ ՗QA8aq:ᶿs!塷 Z Ѫ댽!0a{N;kN}! j {]xk.JPA !I k~+͋_:z 1Q=[j71K6k}Ǜtv[{~K8+  u)M8+8۾5l~9+chŸ|.}V87U۴1=>|f+h˨Da7gLi~'|3<KYl[<X늉;e85쥍Ѻ9qut!G ;j QȢJ^ÚM,z9퉞x | :32H} »ʊ7!ǟ\|81ZͶlجܫ~˧:<⌶:IQ{~a801gݔl*}f}JMn .^sTx3PNa؅-dik~f.M!Aa8 R2 1觊B~ >{KR̖n(˶!N(88e16 5AyN +>{IAUg p ^~؞"vM8t!tXw9)L_WÞyl9cM8.U\E5>}m^ ܧ0af9n,r漞l^!b^ko7!xv]m>@5qaHK NaAh\A^f^O..oϡqsύNA/=^m;A>H#v4Л.ڞKb!|Z?aOpA%iӘD진g0!A?ȯ8 !e*G>hѬq2)PQۚ>Q_oO@I0 *A- \%†=~RH9N$RJ-]nT(&L4m̉rP=kޤT(QMAb QNP*IiXFXVZ+?ؚekŠm?;hVjʥ`L0s+0d•[>FkYfΝ=Z MH4-T "Vn]c[pō{uH`]P9p,^x L^N4@GO ~ &0@$@D0AdA0B 'B /0C 7C?  J)zb#T"I4wGn:h kƺ|d2J) $"6 6r.},˜M7߄3N9礳N;3O=O?4PA%PCE4QEeQG4RI'RK/4SM7SO?5TQG%TSOE5UUWeUW_5VYgV[o5W]wW_6Xa%XcE6YeeYg6ZiZk6[m[o7\q%\sE7]ue]w߅7^y祷^{7_}_8`&`F8afa8b'b/8c7c?9dG&dOF9eWfe_9fgfo9gwg:h&hF:ifi:jj:kk;l&lF;mfm߆;n离EY;oVn(п>];g܎/="OOʗrmq+;BOOv;_sJU7|p-k\]=R3}@!H!6+*@%.QYG|ޒKkWCh1XaE ,PF dl E"G nȺ5|f|#ȝL!9#F0|"Iɦر x<@q'(I"J`dR:,#]"IR$-hK" )a2#+CAVD!&1_LHӗYt.]fodhtL`af0΁XwDf&g³sgNv1`+Ic>r|$ȄjfG9 QoJ,g1yɌN\gAyφ^$F OJ/L9K˘zvyhK%J/9iVc4DjHUN"u$AeP̎$9UNGbA.3% Vџnj%:U.U=k* z~jJQգS-˲+` կDJϽ$+G1kYu0A;Y}~6[;Qr+DJ|F5UI]WYunVj5GܾVc ,cWkP~5})D n7Q\ Mpj\5-E^ $ybmUx"Ǿ Mꪕl]|ߋ7N?;_w o}S E^4f0MOL շ .zF?,~qg/Uh[8@튥b-/c)Wsln2f|:ٰE jV-ӌCٽ=<`~vId'Ke<[Y%֮-?%׿d\:EГ&4^18\3Ŝin-nV1e*g ylUM[4ѤIhtZVpuk=WycF4oa67yy&=k6{x1{iǶt]:>_65e]tvȐ3}gn浧-U9J3{g,ynl,*ޒ;}zt!o+UKZQW.S9<rfs\$nc5?wR&矞:/<ݕ˺=3d&pN}h?zN>{=y,LP^n|cuչN9+.#tlt[7<8k;>(սu3~z|;=})yb3 og]~c3{kzʹWC'P= Kd|{v(S<># s?˸ӻ:;333;@ӿ9<8Ծ=vc? =9 @l7D@ӱc=|Ӻ 49 @@#4:L>l>$LA[ƃ! B,A&l3BkC{)d;:A%i:,;+T@;BsC%?$C43>FAAEB9C@[A/DX4CW\>?0nD> +ErS\BlFv\ƜHDk6Y .K Fe\7Ȁȁ$Ȃ4ȃDȄTȅdȆtȇȈȉȊȌȍȎȏɐɑ$ɒ4ɓDɔTɕdɖtɗɘəɚɛɜI2x,7J Jy`ȀȀ`xXʦȣT;># 2dpf( fK`cM@]2KJsp(P,H Hd̮w (.9FԼJV[(q}`hʲL0FM OX d(;QpMHʑ 6Z(FZ9 Hx9Cp$LHgO Њ?PςPtZc\wcXP0`Oi]hXm C`COQU Q@ЏHt PX ` ]0p Nup z}8NJPl T ie UeN_h 0m8STB _EF ͐M ֢Yf[ VIU\e% G-bׂP<HXqUX ؾXuXXXHXh! ,L! , 1 H*\ȰÇ#JHŋ3jȱǏ C@E~(S\ɲ˗0cʜI͛7KR%Ο@ JѣH=$y'PJJի96퉵ׯ`Ê+s)>ɪ]˶۷I͢E ݻxe(ӽ L8V\ +^̸c}):}˘G89ϠCw,ӨSI:հc˞5״s޽Cܼ طCē+_xC̣Kn9CԳkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IIӻ?2I-4&Y9K[H,p)2#|r-e|cCdMPsd0*])JJjZA1aZ`@*=pglf)}2Q?0f7Yb`0PeL(lhAK [2dCϢc$/3RK` 7)`@g'L*p#SDBї!`r lC-< "(T,j?I{,g,2 aY& "-0WPVXAԒՒ1#i1 XE `J`,}UJhC"W6H-iTٰ=π&H tA@"q(D%*܂ds5g:tc`lZyNՖ$@*w# 'Z^ %@y11@jlK}^MdsPTXgbD; "f3KD $ IBL"F:򑐌$'IJZuȤ?MV7BLB,,4eK1P҄ !C @@eSnK } uD!12[=I4tc QPWLR IBL"F:򑐌$'IJZripNSIDpl'q<x(WJs- Rp Tɖ#LNbb,2L3&>J7 ? [{/p DŽ 3Nq΄ 9Ay&GOR+\%, ?Yb{D .ePfPG KBG9PTT$$3aWI?:@QpJ+D8|*d5XM1e28IKLcA*c0YYҊ܂J-r B<| +TC2՚@TY@ 6ו"/& w]\;bT,f+l\ɯ>`qi,Lp sG.%bDF0*ӆFT_"\ hxmk+lW$:1CpLѐj]l\U1@@(c٪0m;s nde/L kɢa@+8B,W&d@lc)1kπ! , 1 H*\ȰÇ#JHŋ3jȱǏ CZ@E~(S\ɲ˗0cʜI͛8A4Y1ʜ@ JѣH IO~JJJիX d O`ÊK٤\<˶۷pMܻx#]OLlN ǐ#T,˘3k|rD˜CMZgK^ͺ5ZjQM햧ͻs; 㪅7$獕3do/ËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6P2”TUI%\]ޗVY Z@ v7ITcȆk #O p;mUSCZIٌ'  )qJa 3t 0B`ŕAZ@ P@'ĉլtkq@Dp豴(?Z<@\+^œ룸=Ͼa3X["ko>Zb,뜰5j;AA}ikiŹ ̼LsPdR @g`JsA'-4:OuJG]MRg9c=u? d@p3ĵq ٍF%qB`nͽDl ލ?I \ 8IP3}#:{g!p9`x^eEb{ \ `A⎻[R7#Q!zS_DXrl@A0BɢOH=Օr`pH o@@Ej\1:A9j#>Pbb!\x>FMwC"8Q"A|#:!It*.$ ?t8"NE`eiԣZiELыSqC=q!o  h4?GeQ"UPc0B#uGh1MJ9CH)7YN&d[$U^`K(Gr4!E@aA=H"ia+BM}(6롃# 0B=M h$(sXFY0SF,H:J4~99~SFgA z:QaCщj?2Qbt)GEѐz$ISҕ10KL⛊Z+.5NGS> *PљĨklzS-JUNժUeկ u5#hSԫjY5ZV[jW֮ mqA[Wկ/kR ¤ W+sVa*^Wղ=_YD ALbV"KtmnZ/YvQs Ey1GG¶-mkri;vVХkN` Oh9ᇀNw=.[K}n+*1 Pd{򢷹歭V;X5'0@Ā+_ŭu[J&@Rw@ À0U;aT0ߚ[&n0 Z, Bˤec.g MΠ:&b IfLfB5q2m=3o{5n14`-4#3~4+IöҚ)I&'=YC4%Hq fD-Ԩ1+]M"f}f=kRε#Ȑ\;J5lYU4Jl0ͯ` *6dBV*n_ c}H 7רuWv"}_79w7\8)^GXsB"O91S|C*׸?X9wgf6Qr]Z@> 3: M/uO=+W֝^}cdvk'{׏^v}fm{wR8_/|O;񐏼'O[ϼ7{GOқOWֻgOϽwOO|}ұ毈G7JT(E:G5pQ xt_GW#8XBap? `'g 0==0 8@A$0~vv%0!@@08592va$Hw/SGOJ(I#OH_,i]H`'}RsEJ C!Є1]m{؇ا}Wn;8}h!~g~X~緉N_(AX~߶柳yMk!Xθquvx'Z~ эdX 1IhAPVac`HPA`Xgȏ_Ɏ\8C萄@PLyX&y(7z p(h#_HH$ )}QYqB99 )=.4h8øSy9JOٓL5QfbyȔ:yCٔ2ѐ$QQpٕdqW~)`-Xxfh@(*)ٙY 2A@yt)ٚghqGvYc1Iɗpi)dW5Eٜ-!|Xa5hYGo{m(ViYזɝy ǒz6ٟ᠏z)nឰ ziZYy3J/Z.Ah**|micQcIh D*=:>:iI ؤ1y(X9Z_ziIɇjj^Z rzZi9AqZ~ڨY5 4Tѥ褙ၝZթ4ѪCb ᩏm:ɫ4!|*%:!ɤ-Z:|ڬB !#I :ZEzZ-*{VJɺjJ2FQ>حbb;j;<ٺ Ề{[wZ:032!9{!1x;Q>*Cʱ/Kz  43ɾa2D˦{];:l&k@xK"),'# Uk1072Q 3q\B@<ziK LfSQ:>{HY,]\ Aƀ)xx-a!kY x<k} zr Y!;vg ey[ Q둉<[nl˲<˴6ـQA6qC5!̕wp":̓<xYY al C x,<y|\p\s\؈t| m :ѳ\ q0.%m') +-<1m35 79ā/D!.Aԗ,"! !4" a!. zb=e==}zoqu ky|êȏ0jy^͐bL"19ăv ʚX|٦]˪ڬڮmL <1T3ᮠ!! @!z9GkΠ- 7 11G#L\ [}Iyͼ:ݔ`mg=-m:i smԉ>lQp}!1 6<~hA1a 7 H/^1YT 9;=?A. E=_msw ].a~ݵ z-Eʸ͖{Am zIK y>Py]|jܸbQʯڔ^~.D}-^~Ȝ|~Sw[I.\ݣ-ҽ+X/ݑN\6QASn[nٮ="5.r^NNi*93N,?LđX!1gCij 2Qx>R!q(t,ec5t عnq.Xh|ĽM"N]`!^`\KO˨҉z,qx?Q„OwZ?3<6_q_O5OOaZnAQO9]qGIȰĀ@hPB  A!B4HF21aG%MDEUSL5męSN=}v$P@@K  0Ќ#m @S?^4)V]~VXe͞EVZmݾW\uśW^}X`… FXbk X`<)j`J=$|ec#OLZj֭Ar?bAˮe'p @@ LuҮP &lpȕ3]x͟G^zݿ_|ǟ_~0@$@D0AdA0B 'B /0C 7C?1DG$DOD1EWdE_1FgFo1GwG2H!$H#D2I%dI'2J)J+2K-K/3L1$L3D3M5dM7߄3N9礳N;3O=O?4PA%PCE4QEeQG4RI'RK/4SM7SO?5TQG%TSOE5UUWeUW_5VYgV[o5W]wW_6Xa%XcE6YeeYg6ZiZk6[m[o7\q%\sE7]ue]w߅7^y祗JVŗ~}{ X#a‚X4~ͅxŠ{c(xbD͍XBed^i&fIWgx~seM}@cf:esF§sZo:M~.=f۞^{Mo֏gvWjēf/,R!|s\j657q¼MzKVtڹ^=I]3읣ޡZ~z^ *O~ïigOw~'I(_\o&O@(p|ջ  ! OHpӠI,.V6._,(X^n)WXC<sRBЃFbLȑ%@"?1΅yB4C)6Kx'F[a8?Pu"7=7}q_x,n/#ّDboT#8.&mG*Q6yE`$3MNlAΈHJ ϒiUT,kbʅ`-8J%2d1=ʍ1|4yaP27]^S\7͈f$*OIs%YMdp'+IrƳٴI.Nm|B|`8 Jt_?QuѝG9Ņ efMOyʔ.,CkTVlp9mlnk-)'ѻxRܽ+ Mp 3{9sc[/'>mEس|oS{몇߾ϱszp+>~twuwVl7V D(ۿ>+D/<;> l={<T=;={kK>;?SU@ /+A[ 3"@;2 D9h@ˋ \:c<&\:'">.|8òBB`|tku?> B21DC[l491IJKLMNOPQ$R4SDTTUdVtWXYZ[\]^_`a$b4cDdTedftgƵhiDjƫon 99(FǟGp m 2h2Bt$F0T1lu$ xh0Ӣx@y  | `} |0F@h艊  LyFoF4hl ЅȀZt XIҰI [X\J3Jq pЅd[.ǿ mxKoxh w P}@HЅV̆XmaZ@˓0F0<_4D0Ѕ.Xʝ [pЇ` wɂG}p̿pj@*0$ax0jtԅ`T XL}  x܈ f(pJȁaOhw0 O o$ 3Ђˀ?2Lϯ,P̍uPЉpϝ0(!FLQ<€  N$O-m(H+u %HRH12͋3%! ,1 H*\ȰÇ#JHŋ3jȱǏ C@E~(S\ɲ˗0cʜI͛84Y1ʜ@ JѣH^IO~JJJիXe2g֯`ÊK˭]]˶۷p4ݻxݛp.ŧP LaLӢ≮ǐ+8˘3,ϠC9ѨS^4Ӭc˞M뇰k[m{ N+_qɛKNѫkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZgh?6iLe$\(WAquƑcR$\ * A IX9x[vВWe9AQ]2>@1! $!l(INd>i C4t <[^$VgLa#&G@kL1 C X'H9dd?n1eD'OFfC/? K{ `-͘Pb%3؆7nт&t:x8p _# CitJ1?g(WRX;M`@\L^*p#EVArӳtj0R+< IRɲ @S Rސu%f5ab!Y' ̂dk`grM0ED d G(_<6$X2@Qnُ̕%xx3aS/8$*H tA`&HLgZSw#1v  ?`xpT~Ļ.=^n!ĂZ,QۯpDE^ IKᵘgA(Y#Qdk6 _!8,ܑ! ,1 H*\ȰÇ#JHŋ3jȱǏ C4IRɲ˗0cʜI͛8[ IBL"F:򑐌$'IJZ2gx?6Iu-$DP$ @0aJc:኱HiS!C v?PBA[n!mlE(%d -?lĖ5?!N\I]jkB|`` Ýf.@?Ab%6mz.'L?Pdo9b-< WLq@Rnb(L1NM|RB-!@`Sxb$"p?aX )f0Gapu,Ӱ%-@!Λtx(3SE n2#=u"_Ѐ1'+< b rU XMT0-A$0D0Hx#0La~D.D IBL"F:򑐌$珵ptNSɲ\'nI񈗌:IO$)/%.q=;+˚d8bb$%|3 KZ:X D8@衏p#'Zb͗l66X"6щ͋%ѰG9.d;E"[BXI;?[l5Lښ% =}Q@!&V IBL"F:򑐌$'IDz^&`dr, 30MR@pD\iO(k}I0@l:0 \\X!LlY(-x?c0N+A2 20cIB 0`'iA 9 >D-9qч?a8#'H $Znс 0:t$/Ci/aw (V`ڑ2&43PIhI?mBOAbF'@ _ë`@NcTELa "?F ΈYv:17LU'K KI`nd4FRd`X 㝺Pkbҏ!-0 GaqV&@;P{kUð+Cr0U ¬% s2< ԷܪȢeCTC3V>1;C: UMte5y4`'0lOupŶn7E͝o>wPzw+>Sb4?.LkW[D䜋Tsm}.:E߂ʢ.G~yΖCd켳^mܕM y'o?TFZįԇ{F;EWAc<QK+v׳^;-_KuHG ",I?oH2Z0x `rlaUo:H8FTBH3J ah^RE @) H0Tv  F@o;a7 6 N0=ʼnuJ4(Es-,rD`:`l%PDwQⴢ:y F`S, p6N{Ӝt^*P/#ZՐCVjDPBҶeu`OWnT(NB8LbQ`%%=JYF!ػįb,W7VVNɀ;`9#RGVV@2g_mfq+V p0ᇬxmb ִg55^W2$hs%Rn|j\^WӕuH\@ w#M|߻ۿrcЇ;nQլ4#`w;%A o"!rě|,Ox6f:aϘ(q hj9eɊ1K268oܲwTƠ;^]uvrs[7= MqpUgywApA #/+ޡ{w@QU,]>sC'x=2.PWӟoh w-/#~F}؞'ulp9p @G:i>x$ !t@ 1/<5k0IZAy'GFD`'aT@p{*B]OxG`{CP`?aQYǼ5N{o>q׼_(g?~ot8Xx ؀8Xx؁ "8$X&x(*,؂.0284X6x8:<؃>@B8D"` ` sMS+ P ZtEEb $  U?W(7rI`l8tXvxxz|؇~8`n` ! 0==0 4(@rvv(X$|@؇_aXahaGW茩H(8X8((Jh?J C`!Mb"hCx(RH9Z8 Zȅ^j7]HKi?a!)yAf0yDh.>ɓ:1X.-1c{ Aq5ra^\;[1}L骆U,L×<14L:aʄ4Q231ʚ! 묵 LûLp n<l<yL, Kٌ)׼q,ɜr|t#q"C!A\'é 0=̈;l>]Ɖ|M %vUZqy!Dҹ,9i`̿bl@=f <$ a!Ͼ)<L՜|ո ,0q ֌S,q͠Q su*{-J[wl m؃]}}8bfM},] MV}PN2|۽M91=\G, |QK L3|;-m'UmힱX=–yK1в 񚱙4a3K#= 9MR==>.ٜ6ݷ3/8,Q,}nuE=1 6clԃ64ރޫ-Uk.=S.UΎ= qWkAք|.h \obNyoqs.uw {}n^.oA a /':)8΢m)qyYζαmla~- Aݭ6QhX6K!GAh-1>Qn b2 8.~P>M #>J)T02p% Z5B^?*(ϸ@Ni ܎ގ1-;=oAnj"q+ 1yXׅ[X煎d:,qGN gAڜ~|a ]}?5qKAQ^>4A?o!޼&bʮ/ ѳ' !9o3?oNx1Ck?!"A/ O_^x1l"1j񫪋?O#O'-qDPB >QbB=~RH%MDRJ!1Hp˘:1N?eɳ(MolUfٚpѩTbպ+ҪW2tچ8HXzTv tHyOQ$Rڂ6C,Ə#/L[xhҥMFt9*y&e֮azbױAO=ߔ #4^0%_8-G׍n>+ MY;wEco8}Je|6q?)hS+?C,p~ A[ @(*%2i©80*ED1EW4́ ?2b<a?YG;dI'Li@ KR?rBH(KɓL34@< K5ٜ$&hH$iN/Oz3N>%PCE4QEeQG4RI'RK/4SM7SO?  ,Z)<z9TTTRME=A%ZڲKXvS`UL_0 `Sd` `lO6ivܖꌶ]w߅7^y祷^{7_}_8`&`F8afa8b'b/8c7c?9dG&dOF9eWfe_9fgfo9gwg:h&hF:ifi:jj:kk;l&lF;mfm߆;n离n;oox'xG>ygy矇>z駧z>{{?|'|G?}g}߇IV槟f4~WW&@@5Pl<&]Uk4VB_.l džBa2`m8/` C1:`'Dq3bA|ESaQbq$81f͉IܠMF5|#HƑK|b=^mYLX?"hR#X0DNzdD"4EvTbCL@b 6ɇSl*VɈr!,"ˣb$.-rh\'(#)Ѐ02hdi&xDM\3#d2BCg"4O"ΌS$\:ۣsi^V85M4GDAEBЀ3'B乔gFd2B(IiQV#MEx3$P} t@_ T!a(L[JԤD8JьB`NTQHAmSƝ7LKӌL-5&WU`$GTɚ֡b A+C*5HEJֻĬj**PgUIRXh*V%umHYR ꕧ-\1֥"vE,ez̞䰙LFS9U[r%leIYf'r-pC٧*V;ղYnbbvu ;KW6Hq{׳M-w;+NצUm{!fUK_u=`{D}oA֪pwa2w{]ڊ+_|C"< 6;ߢv+E_x&!RۨJ,Z`4(Y^;r,kٹo<& F[JXPe/>!hRf4"精ٵRv3#0k.,뙼~6/0,u Oǣ7-鉴ٯ0vd=b:։4Jr\Ԑs5Mh⦺ǶE}46lS|^d<.vdUvmuy(6kZFlo}/;^ mMv.o[tڂ 8kw}yKߋk24;w[p|rk~|]9os=uT~|yH餱p<\{Yľ蘭9a^z8#_wVzmBD`Z0[^'~we汯lrO?;ӟ?ӾR >;==@@TںӺ =Կ d@,+2ڋ d?|@߫@ԀȓAS3@L B 3BC;B '=H#D)#B0,AT&\?*LPԬ[C9|+41,0=>, ?B>C$$<7B9t8H@\D4DGMCI.4DK@B0553E-|@+EAATT3tTԽ6$GdB.7D=&dDaF^P6 DE;AEjhX jtFE:bCpEqddkAshFkdE|nT zG C]d>p\(]?d \_TB_dC8HrGLUSGW>mlx?t̸ǐA&8˘3GϠC6ѨS^Ӭc˞M;kk͛톹{ No+_\ɛKNsѫkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZ̤&7N+m(8Pel)ׂ%%9*J0A ְ+]PBffYZdG4p7 eK0.1!bŘ0!BA!T20ͦ-T04[- eS ^r6M?6чDN s)MiC͢Vs$ OD; Nmr3$L p `& B[$Hnӵ{iC6F0 aB'|Ao%^B[#`*/ ֚ Bc F"iStjЖ\kXU DdBlm *GG*Ӂwt-d*ZTIKw ?T .E͈݊01};0o-$U/ra[(ԇ>WU N=0NrQ+ELlaZ0L4"bX!! , 1 H*\ȰÇ#JHŋ3jȱǏ C)ɓ\I˗0cʜI͛8s IBL"F:򑐌$'IJZ̤&7Nz [z"9Q3YPy(XSeY`2 H*.@t!ː`'mѥLCeXKA VfGD0 d7a@{ $@JtĚgH;+ .I.ؙZP#nYCTbHlnG2lx/@E7k*ЂMH_%d, %43{,@6SɅi2_l_Gm<#mCb"B:}giRZ{c3v[$lI_C?aa/_WdbST ` rļ.ۄ! ,1 H*\ȰÇ#JHŋ3jȱǏ Cɓ\I˗0cʜI͛8s IBL"F:򑐌$'IJZ̤&7Nz (GIR2g] O4ʷ2s4MOj↑XbٖW΄ IA^Z%Zc,KAM#4/g 6R5xG@ \B679s2K\>JeT-/D' NR'I2 J0iC6^B]l?hA 9<*"m!yڡK7Bщ91?Z,pF*`bw%|.vZ[t$~Q"a!& ؀W)Nܱ:$hECCmB[/bF'@ _ð БH5(@.\T <.Rb +^oթlKLY(ˈVyc}vMtC`1{4ͺ5QaM2jkv-[8ޡ_μp#Kس|ٮe? y>Ͼx˟7t>f^jhIՁ 27 ~5(!E F6ᅴ=Xxሤi(a,.0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZ̤&7Nz (GIRL*WV򕰌,gIZ̥.w^ 0IbL2f:Ќ4IjZ̦6nz 8IrL:v~3e.?jRf(hgJG#=J2 dA'P0A 3ޤ%*Hy2i056%u8hn@RBȔ'ePTTI@1!Ħ9]IVBC h#̸ǐ&8˘3k89b͠C]3ϤS^ګ釨[˞MvߤhAͻoM?μs.NuNνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(ᆔM,(cAge7fV8xb.(.9*呒J!餆MTV$n7URf #R hlpb0x'ztgxy^t G蜆hQ =KJj硘3mسXujd"j8\>ʒeQM„b5%Z 3ldcHx#)Q;Z<i T  8/^q$ 'E@?,F#QO02'? `&j8PEMhB ,+?8PfP6BHDzH Y !M@B`$ыa<X2H@"F7&!+ؐ|}eJ0 zhȧd `G06R8{^$U@i2`7 ?!"8-#X"eRUTc &x& Isy5MbnLc7iVSc \;9w\X:O?9|s B)PԠDXP2(:#K<7'M,EWjv8 _T4Z1 S XJQҖʳLHa?}}vR|` P7@Y #Ȇ5.b!k3X[-"b` K(u$q,KX,@ ]* Q qZjDNkkcfgY=Uݺj">pm5I5<039# ݩuy]@ S$Uy#adC`戯|YW %UHױb \G$ĺX3ah,ֽ.FEc ""kF+|丢QQ{c 8$Ґ1))V&-x%ƒl$V\.3 f8ce-: 7;Y3~N%18a?񀼒íͫsiцlma7jvm-mQQCks'>?}qFun7}nzz^w ?xM"~{GxOθ^{%rs|D#W^r)8IsuzĜ?9ENt$b'ԡ6=OЧ^tS.Rx@P:|nCB/Ceǻ>c5 G󹯧iϻė[3H(S"go$SRy|>=jEҗ~׻wzg$X>;V=}z~V~Wҿo}c?>}OOϿ8Xx ؀8Xx؁ "8$X&x(*` ` s& P [0>3H#b u)  ;xy҂/FyRZ\؅^`b8a[rSS҃^h1$$0yvvX-bȇ!@@`c!L!00Zxn8Xh@aX&:eGH#؋!H~83H0h8B C "1]Ϩ؍a8d BHO_Ƹ8 AI(-LYԌ$H&ybaVh}M5(QX2(AP(xGȑAxU"yA9 )IQi$ix'qU 0J5@[YPg?|Ò%Qq|ٗ~ (tzjȆ(k؆ވ#!mɅ_]/a艠HyAyi'AɅȓ{ъ6h-q?9 lƉbZi'Q.zy&yXoѐq؝%);_h8EȞ[ ye9ٟ)+Jل lr Y]YJ Qq & >Izù!"A"':*8)`ظN LY-ٟ2:u/a1jɖ?ړsYyL\ڥ^'ZZ٤)!Dje:!vZFCZ01 Qɉ{JɦSGiʣ,A.*¹eIY *fJHJ zʚSѪ晦aJi≪&qvZzJg)ʊFAκE˚:j jZkѮJ*ؙNJ-z?j ^裸:3AJ7T*aJ:z*Q3q4+O#!Sa62[`B;D[V@{k:-;K+*,K)qi^K+aH<._X:!(H^0P1 I.@ 1anJo^)SK?Jz&Q/ps"O珋8{!)AnϢ|q'k.̩.zS _m^_&1ڈZyҦ ܤ>{a>xY?_jXjʘ.w칮싈xOuj㾨:ڨ/ݎ#_+N 7q\o8> _d<1K@hPB >QDp!%J0bƍMDReA^u+ƒ+mt SfC oe̙=ETRM>UTTQTZŪkMMfhYA3۸ 5H/mmȺR FW)x8d.ōfeǐJ pNFJtA +bkѵGԵm?ؚekõ‰w]8ϨN{\szߩßG^.pںJgנ{"c?@0B #-T 4B/L;pBp;ͩ 7LC_1F",<*(o(&h@fdґD2J)J+2K-K/3L1$L3D3M5dM7߄6,`,0`) J`a 3N<*PGq\цD$1ٔ4NI)eSHG%U= (@,H &g Z8GOMuU\CTa%XcE6YeeYg6ZiZk6[m[o7\q%\sE7]ue]w߅7^y祷^{7_}_8`&`F8afa8b'b/8c7c?9dG&dOF9eWfe_9fgfo9gwg:h&hF:ifi:jj:kk;l&lF;mfm߆;n离n;oox'xGsVgWj筍~陪`q{>Wj5_'o\j?_=Yl }?0\ _'-/z08 OV"œ1p"!PR(+ .ڤ˺Jr(3NP~-ؿzs%N<M"E-хbG8-R*bhZ_QF">ЌDFdldGC!~HM,"=&Hu)RkryHI҃qd",)DL^L9z DFf)B^yVjM$DHLRdIIrّa %,{9de?a,B'4;hCϬfP)Zs)dH3)FfԴ :%"O 8uN`3&6nҜ)`ā2i(4Aς|EZω3hEYQ~*3,3Oh4!I6ZGVdlY(ES>%Hٹ{Po2R0՗BmQԨ65jJZ T* <ݦQXSܴ,9NPzq}6t^^]SW:kZ:~ @*ӾB4l^TvDEjgiSٮfumS<61kCvs:mY+̒! gޚ{fjDUis޵HnK[60hiq{ٟ)LVC+^Oэ|{uov7yۂтW"=0dWR^mz\.pU {M<_%pl`#x%/Nd9bV.V'cG] Xmkc9-^۴:8"8V+%ֺ.3k_$r}V} *擀OFӨcs7"}tٜFLY>CV˺=ճw3 X +ɋt;H1<9\No 9m jޞt>g|X_wՔmڽ3 P-VmnyKȸmM`&shwOVwy z;npCuLL[G[iZg\ܐ3kljZ;{zeyf6Afc渣SpۼrM2z'};%-Jb%ĉ~b-mv26Yd.1{ ޥ虤_ /Kqo;O<:Ǘ9gGx;Z x'G;1۲?6M:_{wyL^sCH{ MYԫyBro>7?}{3v_?9}dG }O??ྍ3?[CS{?J|;ăbt@ܓù{ ܈< l?{?C :=$A#L?}3>l@DAû@*,|6V&DAA % ;6(@0- C.T;)<=>Bt<>C@'Tús=:L[ĦC6t>DBro0@DT:hňDǜAkHÑ;dJgJ\1{L˱$˲4˳D˴T˵d˶t˷˸˹˺˻˼˽˾˿$4DTdtDŽȔɤʴμKM̜ MM)Ќ(E;G \TM 8ڴ`P _uYNQ0鼅lh@}0(P)$Xqwc(c."` <vNX IBL"F:򑐌$'IJZRm7^&Ud=qC:P҄ )<)S&s,3ʙ?9Ou.x As1AV2$Iy@ZLm&J I?YNfʓG ~Di'4F,A.3RO#pFΔ-E s%x.1~ҥ  c'(F'$pi ; Օb'`?T6^4)h+X@X:&H,Bʊs]/2 b0!Jע$`>@pBYbՕ`j5gcXP8@jDF0*ͦF `"|E(-Ҫ+,w%:1C IBL"F:򑐌$'IJZbMɺlo'wd pG(+sLp2 Q?ʎxJa =#+a%K̕R&Ї?A(( )H zC+;:'ZEάNFЇ=p$t1'`$)3G3Sηd&Ȥ7K^TIB 0`KA ZaBJ`[ -)ZPܢ eL:T̄diXnс L:! %*MTdJй<A̳ OMGt d۠0@0OF`M թ,A |! \MDz"G0PU`;*b29(LnQ W#T0c52 a kXaN<]0."-T= DPV}@aX*] 1LTh#+ JYaC4nUDw% .KD+fȯ@O8dz-R]P'4[_"׶$Hpl̒w%" ږ#'1>*b+_`VBߕHx%'J"ktڢ(Ai9ʎ9I$$ ! , 1 H*\ȰÇ#JHŋ3j|GBHɓ(S\ɲ˗0cʜ9NJ"Gɳϟ@ JhM@gӧPJJjBIq.ʵׯ`ÊuUiαhӪ]˶-ڲZϺKݻx3¥i޿ uľ+^̸J;Lʐ#J̹j3C Ө~H:װcEjV۸sa L;ȓ+ۻУK/\سkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'Iɉ-d.ٖLro\'d MV2 +jePA"( +.Q?ʎ<i@-;` ,"˟؃ ᘉ@^% f|cCxIB"Q( }<>LW$VLx#&* tcO1 C xJ\$8b N=]b`0PgL(lhAK m:c-|ϒ0HDiyV1?D$ER tK%~|as,; IBL"F:򑐌$'IɆ.%Ih{%[>ٓ((m:b,Q=AP*C Ǘnt`1Lde%T ,w$ `U 1bfg@xtgJi„?qt +[Bs%.ݲRpMpde'IX sc>Dl }+3CḑK_9hED*(K *@3yd%f:!BNH5T 5&0%IU36mȆMO[0,ڑPxF`#0VޘAlMCw- S'[׋6&8)AIP_1#{[tIZ|?pAby.j _L5P&d]K^P0@SoM[T`KhA_9E̥zM ch-Eyc,B".t 03B`l?h+|`Xm~NܫWEa1\LύS1O! ,1 H*\ȰÇ#JHŋ3jxǏɱɓ(S\ɲ˗0cʜIGGɳϟ@ Jњ7=ӧPJJՖI,yׯ`ÊKa֭;˪]˶۷p4ݻx;s.EM L~'≯ǐ&8˘3k89b͠C]3ϤS^ګ釨[˞MvߤhEͻoM?μs.NuNνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF TV邔XgeYvޖTz)&y`^9O'lBD0 2p&\e G8#@+XN= DH E'QhȨ̼UԢFS \EBDzr)t@PMDԄ%%(gPT"=0jĪ>QAiJͲҬDk@պŸ.oJ 6īLz־Uq%I`u)ve^WlS$NIl" urֱm+\G5R.QN#4"xzֶy^oYNRuIFV0>1_C=11 P@+6meI+X6?yիALbV@D\F%1 H Jlw,^ּEx*/C+HX5٣X)G=! #@.0UPA08T( ~?R|8nfDqyS`*1 P/j c&P@= #M,Z&/mOP.@0(eS:7]qRP#hO`%(ERwyàĄ#sc JrhwvK4Uf8'qNKO<$XA4r Pc Ɔ;L[.zGN3 WzGP!R٫vMk;:04Q4huzF~7cxqٽGs~=z'MUݻ.rvvq85rxv\1`!|r91q?~x!ޡ-?8>R 98G X=bQ|]>P:fhA =h@P=>q;/t< ia@O_.z2 }k?UR{}aNL/ԟO]~_}'ܷIJ9tg 3*|=Ko |%;Z>]Ff P\vv|p! wzw~Wt@xx$X} cIP8y1 &spt-`V3' ;ȃ3}c@Q{2I=hRW-YP[/]؄_H*a(Ucxhjl؆npr8tXvxxz|؇~8Xx؈8Xx؉8Xx؊0>8!00PcEH ^zaHy6a Ec YؐY! 9$"*` ` s/(9=9 C`!s 1 HyC8QG P [Д+^ bP dgm=_p)Jɔe}9zٔ(AP 0$٘1qɕ险!z2!Z[;Q *K:5M[;0K1AM qK@Q @ѭ;ɻ皼ʻۼn,f[{gz늴 N.MS~4n2*+屸j4&d>8٦=< <"ˣ(^0`a!nL\. ]܁gZ(l / i ! A a. ! a/V.!! R̘j)-6~ŀ ň>n>莑 aA kQ agUMO>\2.8;= KC PL~(* ·ȽiZD 2/=(ORqxh*iA\N{:XږzQ[Z r>Hk1&Prmp/f~i{?NRKajQn-A܊_ MqИOK޼^ϖuJSQu*ak!) T yqƿr?/ q~*!QDb 1C+f` QJ-]SL5m@S,`Bρ' D(zrT; JPGUXe͞EVZmݾW\uśW^}X`… FXbƍ?Y2K(Z2 |f`J=$v2A͘϶slڵŎ,65=5B Rˮ۵Ym?b u\ &lUe\|!qQ/轛 8 @@?8A '97,to△M9([ferKE]|dlE @Isj.PCA#J<Ňx)%nJ٢FRK.0*dM7%}q2G<+93BN5OJ(c2D/i/dE;jA1R醓4 Z3-M9OLO ,> HR>uZĩKG/,auUc0Y vxXO,nu6\qrk&.p]<=W>"C)]meW_w\~k}=OO]i{uNia/8-$ȫC7ե MgcN5c_9fgfo9gwg:h~5)TD#4HkRM;kMK;hVי&a\&خ#jMCںpٯHC'ۻvpGx'xG>ygy矇>z駧z>{{?|'|G?}g}߇?~秿~?`8@ЀD`@6Ё`%8A VЂ`5AvaE8BЄ'Da UBЅ/a e8CІ7auCЇ?b8D"шGDbD&6щOb8E*VъWbE.vы_c8F2ьgDcոF6эoc8G:юw#[ðd? (!gF6$o@fM0iI9(iɲ팔$"E=O2r{eUI2Y2GrqI.X3a.%0Lg 4×L_*-)gYʚd{fo欜39'ɍs%6Myr{gܩxl?VpH?k)Pc2fjάt"!NM"HߙQ֌H Q$F)Δt5uK=StiBa͛rCL̠R|*:N$MXZdb*fj)G@ӊXK}[AԶVaL:xm[i}YX(v*e&c[XRdv'{WհK)GB5s5D< EVJzuc,Vk+V%$3W{~JJYG:v=g]]&WEmq Rٕ-X}[Î7EydnDXU.vֽ%k_nsKN[Rl,wU-+|1  6-YŽ8o?G9-kFض,?N_k r}; &6ɨA&S+,c%YzL0ovʮ eK7'I.\*X,Frb9~R,_+'+xMH3K;GZw7 ;ZQhRo&#6%=g8?5)]h<_וHm-K {tkP;u`f,o'\">r*=@pc%8Gn[ hÍ pO6ժw3XozZzMs )E|sJ]&ɟsLB5Ys=/:Dwi'=.>x}E^o8).SO\f{YOfȇ9^]6<;Om~}Mڝvþo%[ҏY>C承M;/}I1<¼6_TT4k#_u*\3>c8[D:*ABlA(@H$\ "| L請3\C7T>Ļ+/C'AKA20t1tB)D8BEBaE\B6\tH`,D/;<;BlCD>CA@=LQ 8DsDDcD#FEcE2DDA4ë;DCl;RJKLDDFEk`lDWܣi|;ߋF*eLbEsl@Kp oL \ƲGL&GX\gw v@C,FGlP^TBqƎ[Gl|<9ƃ.DE;9LHuCLGTEg*tETHPɁA HqԋdIk@Hc JzIʡ($ƪɅɌG(ˬlJDCP_E[ I TK,ɋKIIʼGjLDȒdʊH4H9 LK ̳ƫ̾ISÜJNLGdV̋̕{JKŬx ̇͝LDKpMƻJ̽ɰSɓtͻh͸DSL\DL[NM41$IRre˔,_rI͛8sɳϟ@ eHIGG<_̖O]JիXjʵ׈E ̦Qaʶ۷pʝK!ٓwԺ Lay"-k/߳KLˇŻ1ǠWbMӨ9j6gaMۆ[ ȸ NxNݜzԱhУKN],A<ËOsk5˖Ͽѷr_w& $uށ5huu7a (m2V,݀uw48<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ ꂫ.)kz䭰됼+PE+㰩[$FƊ,m&@0p0;i_ӚVmj"eOmXbj.i<2o9h߽kG0c| 1,> !SF1i ?-lȣ%3A<1: >B F?TI7=:-5PG;V],\y Eum_ 9cu u-Ktm[q}5jwt@}W.~ xނ/2xҋސRpt\W0QVKKSrw^yF&RnDe:հ y{w5|cu<䰇{.v?}C_nx @#0 m]7pÆGO =C9Q-d PJ@'H@XD '`A6V7 %:uaX<Ja(A)ʡ # C=*@Jmp 0Bdau #2 D"?*r Ds``#`D`Bay_cazd,<0D"^} `'X9RQ#_DpcT],1R Z VBʸύԁ,ia>DT3넦$H WM"`>BqnE+gLB(*v<h S_|Xh"CrBG=jQэ2@m8ϨiL'"tRk(ɧ*2jUau*WJV&"MIZH33{+\Vk\׼s+*=l]{:vm,d'+Y6 9fٽv֯hYʖֲ"lB4{XΚmhI yG(@Rv Ml[ʶ eq#D=A#8h !(CX:̵mmq\f[?1  (`zD^յ/t'u+B8 , qKaJ-IF(>ǣ/Lyۨ|/vgd&U+zDH`sIl1 ``D.%W1>뚕!t %q.g7c~d5XXyȨrg`chfAР&Rl e =$̃ a+ "#C06fVEfmat9MkD8iӢ6S"S&-r{6=nm۹E9 vlY}" ? =<0GwΨ'b'AG:>:(#3#8Oԧ@">-1qX4U~7')x8)w(|8~Ȁ8Xx؁ "8$X&x(*,؂.0284X6x8:<؃>@B8DXFxHJL؄NPR8TXVxģiA0 0(HT> P [pb3P j=  iht3\`8Xx)1`  ` VbSSD؇1$$Q8; `YY` `k؈NՊ#00#3wV4pD1qz<zψsXȍRȌ3S!PG3] Cdhh!Sgmqp(9)X+)_Y2I-Yvz(yȑ؊A0YF9x4x*Q):TaT8 YM7_3chÕ `PA7U i3h6YN|P@IPx0 9i 098'I(HHO9)>ᛈhTŨAljќi(e9HH<1)Y!ٔ(7IU9Y/y<8y J䡑bB9&H!& :q* @aY3y= Bڟ:q/JlB !:)J9A׈^CHSza K:ykT ډ@a:z[ITzyA٬@aZ:z:|JQѤJ]hls1*.j2*9ġé#z6گ.(#˯$ T:ʭ!8:8ˡp ڰrqBAၮ?R ]u4YڥT߷9ɳ|dAۍtiJka&{.K*@qبGaQ[jșlKpr;t:mxK9(o}[ȵqTaCȫ{:Bf~JoӺa ha ^`k+㺏 6kkJYQT1;zjCֻ5ܫ6{<ڻ[4aCqRB!w+K+]1[>{Zϛ+#Vi>@16QUEkI?ܖoAA\\-bK@Q̛h+)%L7u[F|H]wzÂˉV,1,/ [<]|QhS=a i kd{!̚nXki^ Jdn [;\9㯭遞<; AZߣQæNXN+ AZ ]]ԿߝAЬ>q잪-:Qm1؎n{m`i(l>:>"n.[ !>_8o94;+oa>ng@B{ǖ /]}5އ?*V~T9=0':/ۣ0E. Ţ1d,(Gx)IȦ2H- JII+2ˍX%.p ˹b<*@QK4sǜ,sM:הO?oE;eKĂ "N@OB͙ -1G/4ӽ(I0m PAc`LTӌJutPG VC]5W]wW_6Xa%XcE6YeeYg6Zi  |Azb?eZl)t\sާz&tZQֽem+t_{f8B"OmMhb}V"x F9eWfe_9fgfo9gwg:h&hF:ifi:jj:kk;l&lF;mfm߆;n离n;oox'xG>ygy矇>z駧z>{{?|'|G?}g}߇?~秿~?`8@ЀD`@6Ё`%8A VЂ`5AvaE8BЄ'D!XBbd3k! _pCuhڭ.~C 1ۡH7#reMϤt jLfiS ֬i R4#:F֓!tHJVZ5TMKҳdMC&imZTF,R׎OlTIzU W rA`X֮.[zTMY݈^:[}mڍ&X Զ.r- ] \J7!}M۪७}w8T/v w&y\[WuymWVw,:_70w?VhqZ`U1d{[z:X&| cij鱀ۻWAlUQ+d82+xB'U.A%+YF.2I *822A8hl5[xy1b!g7Yϒ3D'd>N^FT-5cͦǧlj"N bKGzřkak1sni Na5ecJps(y֢3]׹ɨ)<3Ϯ$=eúme&{Z8ٵmNnfkdھNk_%ڼ2-qeki$򤢻 7ζ7:8϶Ipœwѯr=sہ#.Ӽ?vNؤϤFoW\/S㠇uަz xG5:ʍ؇"^ :[^MGta{?c{? ܾ?3i?0=S"$Aþ:@.@$?*A|)s$ 43!#DAԸZ""(> ʋ@=,L?B ?P>\=Z̍3lC8|cAA1T.,?/,_; 'C-a 9듼V dBD IܽKDD$ÊYNO6F$E-$Ql@cC \Ƒsc4HLɈDFZ ILozF~$ITadɂD;<dWJt|FlBJG ˠŭ$! pEJy@\J`lJeʷLȗ˿$4DTdtDŽȔɤʴ$4DTdtׄؔ٤ڴMz TDތΆΌTN LBMlXNl>NN acxt ρЅ4ĈLTOnxp<+@τ`Otx xy c`Q7 ϋPP ffOhl ЅZ9P!Hx9Cp NЇtHg'gHwX=+?/u@ 4 _wcQ0 NРӕ@ЅVӂXmaZӄ0F0<_K50uФ@.(U/H1͉ќ7{,L>݋ph P$ !ujxҝVb5֤HV*GsXT5-jhO xԠ]pQ`SYSP@Q[S#S%W0xz_qӝ0QQ M 5Ћ,x i xCxo פrs]XH[cgU\םկP z}P}WX,u} T_gڍפ5t}E5ZxY\_ }Yy[  =ٔ []α .bY[ 3 xU  ! ,L! ,1 H*\ȰÇ#JHŋ3jȑ" -Iɓ(S\ɲ˗0cʜIS%ȐIɳϟ@ Jх7?ӧPJJՁI,yׯ`ÊK4֝dӪ]˶ۯfs2}Kݻx^KiS L+߉~ +^̸㔇%&~L˔#GϠj9ӨSװcڡٸs] ܛȓ+[|УK\سkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZRZZi?6YLeKIA@JR>a@r> ȥ8ʴ'>1!-UƐ/K H(aLfP Kf6K2`sƄjy1ba.'K-AX }Q?(M%V3ndƄ+6qD08<1E \ >}Q@Qt'EQT8(Q/`@Z(L@p#POҗ!`r lC-< "x&uO1DҔ&L*bd@,@,Lx(x P TPCagG U]S Ih-cXEJĮ*V6H03K΄Ȇ= T"--!Նt% q3b[L2:1C\s>Vat9ƽGj J7&Uc Toko7}t-;ݓPToev9*"B5a!<3Յۘ@+8a_m*@l?%4A! ,1 H*\ȰÇ#JHŋ3jq# -Iɓ(S\ɲ˗0cʜIS%ȐIɳϟ@ Jх7?ӧPJJՁI,yׯ`ÊK4֝dӪ]˶ۯfs2}Kݻx^KiS L+߉~ +^̸㔇%&~L˔#GϠj9ӨSװcڡٸs] ܛȓ+[|УK\سkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZRYZ?6e.>P$ @0 n1%Mp2 Q?PB&]!aL&2o!L$+L,iH$cl"<D&4aH < ́˖ToYK"^' k'LA'hKR]+q@Rxb%"p?af[@K-kϠCޘ9XY^ͺkϥ뢎۸>s ߹aZÓ+_Μ1ݲnN~﫳/ܞWH^u]=jϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZ̤&7Nz (GIRL*WV򕰌,gI"4%tG#1@0Qaӗ/  &*3ji60a1"ԉ1peD0?B$ &H jy0;:Ag/^tB&DH?A01#3!'M(h3(\X7Q!"m tA ] 'HnA Z&1f0+ S#O :PbCXV4&'u#".h`Q:FZxЀYϖ㯀M60kA:3Y6h! Ђ1# /`D\lh3{H@J2T Fm nC sKT5X)Շ>RxS&mkl;*&x, ՋƤ%j/m$"q!WxkSܿ` ݏN"}IH`< @0L[<5Qb .P 2`b~i"̃!% -㌔$hqdw2M,&(Hnu/moK 9Q*_3f 2P&:ns"^Xc G4@+@Hmf7 GtWgX! ,L! ,1 H*\ȰÇ#JHŋ3jȱD CZGǓ(S\ɲ˗0cʜI&͐"+4iϟ@ JѣqҧPJJի2݉ׯ`Ê V)<ɪ]˶۷p EK2ݻxݻrΦ| L0\:5̸ǐm"8˘3k^8Yb͠CsϤS^Zi[˞M6cͻoM?μs.NZrνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6P”TUI%\]ݗVQ# C'6H9H#S=iHTchpip@Z)lSJaC~b@6 a#AZQP |Ϧ:v0cYn#AhhFK9!Pq%}~iWk AA9Bi Q%0[ji-0©|O4z*hh1?}S:@?)2P@C=I9V#\s0? h 4:̛I[sC rja°x ’C O0SZ(2A=>lEs~^7DmC'%㔃io'yS~Yod:sN:G!@Y@}騧A~;;R (!I2߼T@@p@B FO}WI}0!t>`R)@>K?"rQa&h|Y (*@OdU a a IԦR5ojOTt,8 $b'ԁƌ XJ2um N W>UX̑l:,EPD`?أ: u-)B%&NTU<PǮ:e}5Q#Jv/-m<,6/8LЙi`5%a~,]B<<7qlf0f~t=F?3iE3qӠt)=jKZҞ>b5}jRԮuS-Uc֜57MլuaMlH/D=A,;=miZ6({(v=n]S6}MnzҴ P$#Άu]߻ܼƶa!nF+0DD\<oa@5/5k){4; Bat|;N PG7uS\~ug]yvnؿ.}d7|禽pk߳Ž& %_جuvnS$3 = O}JTB H~Dw#PxB=4@DBX}]ObH`-+1g!=hdC0GO+ e{@'n̏wJ'</WYx ؀8Xx؁ "8$X&x(*,؂.0284X6x8:<؃>@B8DXFxHJL؄0 0N$P )U#P ]#P e#P(T؆r8tXvxxz|N`{' 0==0 \և10$<$0fvvHgA8aH@e(qrh8ΈxQ{S(1 xCȍ]0%W[Y㸁%_c菻x y_x) $gkh̨!qnX8V39!W4p3-p` qU(yAP8A9QרZ*iW*@_PH}Lɓp9vyxzyv88' ǘqؗGYɕH1x^阐xH~Xiu=.ayy4)񒬉%i@kѐh!x'A蝤Z()#ُI)d=Ҟ _aI,yF2IAa1  h:iF:7=8I7;iA"zCYYN יK-1U韲] ɣ1(JzuآVey-!mߕry{\ڥ^%ȘȈb^afel8کG8L*@JBP{a8>Z i3o*Z.hYdQJ *yFjIڪJJATWџzIʚڨڡ!Daځjzậ*>ج(|ǚ:Z*j)  Zzȯ * z#kM|Z/J2%k64Aڄ kaY1˄YCfٳ!n a@[s`PR;nz-aJ\;F4;D[~zQ6Ay(Z{5:v+F= )61Z3᷂i[B315ᶣQ́RWjjzq{:*_˷,Xۡ[,:*16Q{[+Jk=!D2$IkK;K yK!)᱋KA+;T,qH3 Ѳ 0NX=A4a(1mBka.J7۴"L&|(*Ga -01z(>3)2t62A/J+1qXX4*(2A0a'1!*1V3r/A1abM<Kz,]qELګl܅»,-q?w53A4a2,џV,{,hHi f[ )A/A ƿھ px<k5,A.l4Q%3aќ3́l̙{,a.a2 <!\AL]} $85l ]Y[jhܧ?']MOGЗLl QE{8,TV^<Z{N1) W}lnAamQEZ;mlo{M}} XX M}=y]LjF*!A(a'ڄ˳M-Q ͼcj-1o ˱Ou7(KϜ|<1t{ .QA(aހ䝁]ۨ98] mqI,]>^ #M!M  > ΃.m".$^:M)DmR ⥪2P] 8^}cL^-NJw]q(!ȮWcegiknoqsuw}"Y V+!l / 鑑H+Q)yu`eb;k܃Aݑ*9I,Ch8~~FO~#HE?ܛ>8 ~ bߘn]n>^11`0^]]Ўˮ8T?x9)+r+@LI.7/e(͞C҈Ѓ߹l~')UnY^4^w]|1m.ɅOYS`o(\Ieh_synn1q0-Ş4jW/:ztI0-|QY =xOYo/놉bsc."=$jYA(+8Pzĥ8I2M?񠺛DGFjQnV]1 PB >QD%~5 ZR!Fz RJHnL5" Q  ǜtI04eQMCӈ;@-V!y׭ԖZVvlYg.L+CKśW^}lV}b;‡ atFU 9KtɗbFsB\WM!Rq۰ndڶq?>-[e۹o^M $z^9Ei99fv|ߗ&-[>&3|^ygh?UL0<D0AdZ20@.0Bd*A.̰B"B5̊C_1FbO$!6,;qƮvl;#F!dI'usq H(?s`XlɦԲH:2M7߄3N9礳N;3O=O?4PA%PCE4QE  pRI jz4eJ#F8TQK5ֽV2E!.;Hevz5Ye VZ\seH &g , E}6Zp.me߅7^y祷^{7_}_8`&`F8afa8b'b/8c7c?9dG&dOF9eWfe_9fgfo9gwg:h&hF:ifi:jj:kk;l&lF;mfm߆;n离n;oox'xG>ygy矇>z駧z>{{?|'|G?}g}߇?~f~YIWϟ_0@!=կ) \` H@ D *k`u(勄* BF0g*  "CP/ EЅcoC)4#⌈L[D1Qb EŜpQlV̼,e\!u8D4ư3|c (D^v F-LJ5>[#IG Rk#%IPj%Ipj'c%ʈ2j|YJ%D*D&l^ʖiOޓ'='XфhG/̐.s̨H<䄨K*(K͗j\I'TCdB-`NrTt!M)Kڐ40_DSڗδ!Q*Uw V~t RO΢N[Fη%UYI `ֵ:-@:jI {й68mlEɦ~*fىTH% Q2ZUk`zؿ$mIXKZVku'eqOJm#ԳCzMm^\VD .Z?YԲ 9.WH &h/]"7UHv'rֺͽt?+_7!mxneO=/wu6].d'Ծ2o@i ih!,?`>x01Zal*bvKW{eonW+XHnq)Ӹ)5b(o!2a )'y"3wN<\rV+(4KwN-f=oٸ^t%g0ӵʕmQKӛ36hB%8}d+y,FuL2Ӝ>5]T׵Nsk mFڦΦHMe 5G NLf]-RUmmeúղ5|&FtMgY6}vs{ wlkmlZ>OnzSAtPG])'KNo8v(#"2^>pUBOmc7<ȷl"=~Y.\Oduy#x=:聫ݷN]N=ovWy3. ^87(Buߋ>o>{/ý쇿l?f>>ۃ#?#@?39 @C8; $;@? 0+A? d A)̻ L7wC$!;c<i\ ,)?A@Ab{?.@AB­x̿+B\K@X(D) CBq;Úc>Ħ,4ǃ&dAT2þ9ԷB0C3/D=D E Fl=$8B>T=TR8[;P^DUEH>&|C"{hy|En)p§cFqL GCǒ"āȄ D,ELm42XykT3}GWGF^teI3HvsƦ[8oHb仗4ɛɜɝɞɟʠʡ$ʢ4ʣDʤTʥdʦtʧʨʩʪʫʬʭʮʯ˰˱$˲4˳D˴T˵d˶t˷˸K16񇻜˅K˼L|Lp6y`'\lDdX"PK f`X̍YĔ81فpL&Ȱ&$M!LĘ@c0Y$`%Q0M˾Xh}XMczЇʹLMt̷+N`&yc FaHx8%IMXM84L׫γ``[| Jop w1<0<p[촉 uh0 7HgbϮp0PЅ9uќw UO8q8@,хXQѮM0猈K3 "P( ޔЅD uN! w}LR . ]XȀ 6p`X[pT#T<14jxf@+ =ȅq4>YMZPMuXPȆQՈdM O?g`mWDT5FmcՓYV OUU ZJ WHm+ [@ҚimMC4/x1ăTzE~{ǔ (%{)XXX! ,1 H*\ȰÇ#JHŋ3jȱF CZGǓ(S\ɲ˗0cʜIĐ"+4iϟ@ JQ8AӧPJJՁI,yׯ`ÊK4VdӪ]˶ۯfu2}Kݻx^KiS L+߉~ +^̸㔇%&~L˔#GϠj9ӨSװcڡٸs] ܛȓ+[|УK\سkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZU?6Iu-DٖP$  %(Xd){b !H2}[`,A2[f(dVV˵̲&:Y˼t8C ƈZx(x PG9@!dr)Myj&L?K< CBs%T[Z?ehZ ṣ>J0UMq^%`fK0?%Xw"T'd r!\Q,,} :>y Pd "I3:%`%K L^rrmf:])_1'%'4ـA,ͳ DiC6z1𒐄E7o)Y@5ЅbwpI /%H6zټܢU1ٓ܂ZaZ ?pabn}@dpXK^ղ0@Kh);: ߎdZ8XlAG [p4*r佛M\ )a1P!uc)} =#2l)X#;ܫ#_b2l(RJ@! , 1 H*\ȰÇ#JHŋ3jȱcG CZGǓ(S\ɲ˗0cʜI&Ð"+4iϟ@ JQ8AӧPJJԤʵׯ`Ê5U+ϱhӪ]˶-ز:Kݻx1¥ȴi޿ uľ+^̸qJ;Lɐ#J̹h3C Ө~H:װc_\۸sߦж[зȓ%иУeйسkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$叶od%ɵl'n']2suR-I2Rd%\I,?CL,cb.Q2L=yP.CsL G/B}$K13Mx2iln!mD?e)=)C0Q?MqD.0WD8j1eKpsK)xD0aH\Dr(ϣH*]ʴӧPPCEʵׯ`Ê:ɆY˶۷p}ZIF˷߿p6-È+^آ`UnL˘>>0̠CM柑~.ͺעOSMu5۸s.Zkw Nރk1ʾ IBL"F:򑐌$'IJZ̤&7Nz (GIRL*WV򕰌,gIZ̥.{Lz^ t 0ęsG֕̽,LL i^h4aAN#:| 0k*܄I< =0,. D@/۹t~ĝQQ=g+L3'qC2A :Pus8{+BpB`޸E ڄ8jp" ѨG8Q ' 8>0  4&G0ش&~?|aD攉/u.GAI'$|K Ybf!+x# TcXy6#@dqb4&>_ 0pEMPڿ5. "/mF&z}Id#}\~T.-H?Q{G@/ =~W@"1Q 86Z0# x$ H!H!‡ Ѓ0'@tą/2Cp`cJH oPԟ* @B" `qbHF" `ĊT821!g|HH`A6B:f `E-d,$IɁ!`@ `? 0GIVdCDYBl4ŷZP$9I`QB!& EdE̼3hq?5MhsCM &,Yt줉; xN4"5h|sç?;hOs+hL)& mJ4fuE/zdGYҐBl+)Ibť^f1Jӓ40?} M7T)QN4E}[TxSFKS_՘ejդ:z>X:W ᰇ76m.T P*@+]'0 `]@8Ȑl*KBűSdj ^Ӫ!xah-+RPzCF]ڮ>PkV \H1 ),N*u!s:7m wrG(zz =Hzl!\/R+A@pcCLabFFɉq*( fpKU$@1x1->(b{⢤ 0ukH`C:Q4ܵ(GmOʎ Ї;n8C7 }/%s|,an^sP ,͜#iJAɄn|EkDVIl=OϙGMBR.QTԯuOZְ4C![ײ6qlbVu!l1sjSmPV /$Y{.Uv7mn禷".+=?C_y`M {0, " ڳx |D! |@9 ̀v x"" I 5! #9@1I 0+1X!3fI70 oY-`wPGzc@\H!LԆnJp4txxz|؇~8Xx؈8Xx؉8Xx؊8Xx؋o0 0 a@"P aeǘ"P Ϙ6Ѹ"P fh"(ĘIX؎8X3`K!FSS@@8 `YY` @ڸ!@@)+Dg y0gaXpa|RO4Yp? bcّM qxÈ6X!p#7]V C،ctɌH2xw9r~ia)b6Kl(ј9؍ {Fm)O Q]h,>YPRY|IpP)p !qUAP= )Kٜ!HI)PAK6  0ٞ9YycI{Qؙ.ڙ "I& Z'ɚ*+zp1y<$#A(z /ѝS'ꝽѡBI.)ey=oO:/yiUY/ [G:,!@d*ɦq1:6rQsE/D:AMy9!:5Q٣y٨dg?کq9ʑHX㩦*!ɞdYګ4}j)qIxa _*yԊz*4Q:ZڒQY-: 4J3jWa5ѭJʪꯒ9 [ $Ia JZФQڱq!(Ia$]+{-{k/NK9{{n:ZE+f5N@+KQ;SѰ.V`BCiZAb{gDZ qsKjCnK U+W~;ɷIAK9zìi:ڳ/;.aʑ6kˎBS{h4y;ۺ帯*4Qҫʯ2ἌbɈ+[K *`{+ >{K pi,aBG 54[( L?!k5L ,. 71E0Aaç ; A<CEm[,J\ILL/)Ar ٻx1=[\8K:i:PY(!y잕[Ȇ|Ȉº/T|< !M<kmk<,s\ ɍb lɶZ+i!hˢ A [ ̒X2-ǢL|̬<G,\ \[.!4<  |aQ?xL1Ͼm  $l,]}1<!?Az,q++*@1. wy4=mOlQlS 1[0ԘHg<a<3LǙ,Z!(1ʙXfǭ<~<x-q׊׀؂=/QF-m*ׄXa͔~Me}lOm֛ʉMACq[F,3&Rɼ3̸-|}̷}ЀHtb >[mQqM=-/ <[ Y)!A)q&|n N ~&NnjMz 4ݧܚ]~EA9*/Κ>=;,ALJ =.;^?~ZQQ W=2qZ݈"]APW>]z fDZZFqiȸ:h]v~x5S4*\cY.b襽 qU镎 ۚì1QܨM^N!noɔ$.9>6\YJĎ4^ ,QԾϞ߾徐~ ~QW)!|ﻎ  W5|^( `:mɮ1p]j`1A(lLC0oT^֋?AesAX=n~ qFZ\^^>a?c/|~HICOmU q~N&jE@<,ʩ0Q겾!pY~ʎښ [)(1NOfi}za>Qޛ>1H.AB[x _Pi9O+Aߚ_O/$O@ D8P$QD `HСE^4H%MDRJ-]f*4:4pAELxJ%}Ej恜;UV]~c;  (vpmVUqX`%Lav0AO $P q] `eҥMFZj֭][lڵmƝ[n޽}\pōG\9lc`@QQLǔ;o/G^Wo9j۷x%>>X0@Y &6 6X* <021D#22`2L *D"oDw:% ?fFQlŖ9Я'*mRJ*?l% 808 H;"<37s8I^JRr˰@P?=04ҔlIg})<âRL5N/ʹQA%T%p?Y5*ZRFC:+]yT$[_eDՊ|Z]r=2+lM=V.6ԮrSY08Cdw^H\u嗴<4W p%j5ā5\~'0#[ sKkx7ҸOF9<άn-l2Gl9dVޯSg:h&hF:ifi+G.bmi͋NEZ;&g jvi.~'|wG0c[ %ngqx'xG>ygy矇>z駧z>{{?|'|G?}g}߇?~秿~?`8@ЀD`@6Ё`%8A VЂ`5AvaE8BЄ'Da UBЅ/a e8CІ7auCЇ?b8D"шGDbD&6щOb8E*VъWbE.vы_c8F2ьgDcոF6эoc8G:юcEȊ mz#L@vD IAo=k"[Gf/(6H2+dwC~vPie#"+yJOe .KSN~%'ALQjt/̗0{&-˓9sL%YYDf+JXx+'a3f6}NS%9:|V2gIb- B7PuNzhG")B֊"UPQײ$O^IׂOv=_Z)AJn1]lXj?tX$Q j^#5jVVڵZ*)5{ϖv=lW= JZy>k ٪4-UUTrvR-.f9XВ1=hSY⾶Y+v# nTrr$)o[& .S]ځ4q^5]nw޶ ^-j+]OmQ_"/}7Em)im L4 kbѲkza9z'b+%ɉkcXf,crX-,钸ưzR, ȇD2Ll+ K㍅*qFIX13\&t,9V,ul;y#Y"hD42x3˷s_hF_ک5 IYΰH)PGdОlٖڷnzhc;DXl36-]_m/-NdKx^Z{mQdǜn[ڸ7fpYֻݒi6;Ӻ=xpV0|ߎ5G,p/%\ozxB#y7M)䴶/8KTa8:wS2rw@)8mhw7yͯqho0MoZs=:h$]PO ?yY;řy>;ٽ.Kszy𹦺y}w~Rgpn7<7so=䖧6CwI3|jʷW]|Akߕ٧s=E>;くr7޸)m|1/0ǽO~cއ8K}@e`G~TSvoKg~2'$<1'9@GS<᫾s>$@Hc=?3 @$\@s0Ab˻A|@ʓKě@A!=كAkc;[k*4+¿«8|fA@$0@ۊ|BaCՐC)½[2At7A5D#T !| CA8Ԋ>?ĻTA`AM L\A'DKDC6>G6Jù#WWLD\E|?9B?CN^D QDRLB5ELEZCEABU|5ĪcR F|D#Fc@F[GclLϣF\F4ÓE%NJ(L*CG8GP-v$C4CF{SkF}BE#$I,HdHXrȎW|y7@DI4 őd\Ń,N$GT@ IBL"F:򑐌$'IJZQZQN I,pLu,ID0# +( ,=Rʡ! R.%{rh,Q,,¤9tc QP3b$4@0Q% dbrnDpZ)i d@b dJWhL<wġQ@a@UѪ &8.{ьK~PD.0VD8jqF I(` <`P/ y(pF*Ԏ$KՁV#VZ!ؔ"x.1>tKLْwgH[ךU!= 1w",iEMn#tW^H(GCv%l P!ԇ՜ACKX!# p=BP)Lr1 +J*BؕE6 5x1Qw0V,m +\೷-a~zDF0B+\_"^zTELݕ@K (X!0m a{ Y:CnD싒lCنʮi?]3D+@&-x&?桧0(,s$p! IBL"F:򑐌$'IJZQZqKNɶlRpd'kd 0Z(2JA HIa1t l%LVd iL!s(@tP/p 0N,ŘƬF>|8JN2G9v6%.]Pt#mKh --h!vE3#0CB(X zs#33RT'*1;xPUn 0%jjD1?ȨU3}⎅`54"E+l-zC0x<o"w5KT9E JVZ,pZ̵h'3ъ$՜%H`Rd4@PRJݥ_*X]C,TUf< dcm  c,$GS= @0DK~5 p]΀J)\&I >1Oᖗ*pSPW -ԡ65/`&S31橾Mۘw%>yk…\Q2l $AH\$Ib!! , 1 H*\ȰÇ#JHŋ3jȱǏ iɓ S\ɲ˗0cʜI͎#IV<ϟ@ Jѣ1s,ɓҧPJJUJ0yׯ`Ê 4֞dӪ]˶[fw6}KݻxNKS L*߉~ +^̸cJϚ|LˍKLϠj9ӨS װcˮٸs] ܻȓ+[УK|سkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'YA%ׂIh-tLd%Ȁ6P MTfr)*I*糀^CL+}2# 4e0=KU01dLPf&D(9`.]+XS&LFÞo>Y"t :?ndAч@us%V3nfƄ+6qd0-0ҷ d/1 (ĠJJtqKYh%0J`<@L H*R%6ҁaC EWӰ'X:[" nr&Zd`ENզ%<()V@!6#iĒpELƺ],)Wc+mD0RLþű1>abe<_N?DYheIR[l c:tcgK;غ$W57 \,--w#ދxb/mDh1W1 C*xr>Ᏸ&iK_2.K k Bc, ŻU pXJ+8-ELK! , 1 H*\ȰÇ#JHŋ3jȱǏiɓ S\ɲ˗0cʜI͎#IV<ϟ@ Jѣ1s,ɓҧPJJUJ0yׯ`Ê 4֞dӪ]˶[fw6}KݻxNKS L*߉~ +^̸cJϚ|LˍKLϠj9ӨS װcˮٸs] ܻȓ+[УK|سkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'@G,Ljot'o<"PN^b- B@ TJVO0#%H2ya.I4tc QPVh,8C pf[/!%xG<,k&LVPq:gCsܲ%.ݲVjEpV^hhK(}d 'Vt%8OD; QK"[0K-4ţ1;xaƂ2qJAML iM)_@0)?L @=1G #FHVzU8A6d-`Z5@( a`5#F0* S4 .j ĄdX0b3bQFF%v; pD g/b F#?"\W$~Bn2³C0} tKle V7?.X:",At[Q#3@R00[TV& )&r`0 :1b? <L(nv"^t9PUcaX*% r謘W/J]b$ǘX >~1 4"#1- ! ,1 H*\ȰÇ#JHŋ3jȱǏiɓ S\ɲ˗0cʜI͛Gx%Ο@ JѣH&)dO~JJJիXd iO`ÊKY\<˶۷pMܻx˗%]OLqN ǐ#T,˘3k̐rD˜CMzgK^ͺ5ZjMMmͻ s; 㳅7$璕3dx/ËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(8qbS6N,h I/¸_4c:1ʨӏH]qdIFߑ4B#2Je}]H$F9vdڷSE6flWW myC$y'z_砄j衈&袌=ff`.Pꨤ/Fʩ饡)9e`j)jD Ufz략 Pt:U`Q =":ĬY8І= lBY?zڭV{~T04j 3nKV!ת ;V@d5rT,#g,U`$1Z/ Ua=#Ȫ7K4K4DR5+C9MAK:@Y[kd7g6RY=pvpimdu/4wp@?1'I#ÉwyKāX@σs44xPm ?Ҡ?sLCBCD8p tTN=HcC#CPQ |K=pNUQ@G(P<5 = !1Gp?V D@Q@^PXs<XtC0P# '>$ 5eBp HH $:aMT"ƞHE7 XE;]1B٢6}qJhF,э5Q&#DK9H2P`(] TBnɈ @drDUT(EK^>FR;A!%wLɢ/ H@IʒLHRZ##1EFeʆH:.| e2lO(.pGp Qyr#89+S0>6NeBhxA8~JȄ,M1h(K؋ 1i(Th, Y ؑh/"YX/ْp:c:yZU AP59xCɔIPDA4 * 0^9UjlٖnInXqDNZqj tZ1aXAq8.Y*Zj/*1fzz}b` 7Q2Q51GA4NQKS4+1,kڵQYʯqEBkl{hr[u۶5qp[x e[ڷ 4{k:E踂+{S-0aʑ`⊰/QAaJVڳɊѺKA!Z ͚1c:j8;[aK:ћ껾۾ >6;{ a+ۿ+LJ++  lk񧥢%;+HU{i 2 1a< /?[61-Q+0.CMkAa2p!\+x$̗: QHl2<bL?؎ikz;qfL1?DŽax` l\w lL><ġK[ xAB0ʸx-qQ{ .x^ /,\ǼH * | X|Ʈ\[AlX[|Ll<\ B,ڬ̭< "|ݲ&"3!}Hö˻3 +-1 {1 ҃%=ʞB mL<&|QmS]URL_l\׬]Y] X+) !I)aא,!GAIUq)!Aaِ?> RqĨN{)!S Ha%H`=0,Di&; D qFa1k#{ԽޫIfmf9-߾Qq3ATa2+h+C:~N$4'=!̀6-8} λ3}n R* ,...9 *]ԮQւ)ZlfA!A a0 o  !.A aa埪cljnq>wy{}1lچ>|aI:㑛鱼yA1 )3>Gܚ~H35N՛,ݙދ.Za޶n+.>m wH>KǍۮٮFN΂>l1n&}'~)~.l8%jxԽ~ M}ASARnb Iw!\~0 41X'~u8@^1oaPQS(BXߐ:OQcoymOo_l/ DYlaNA8"Q?dkؤjOڂêύ^~}qy@jc1.alȱ]Ќؤ.{O̥_> o/Q!` #9@M*_مIL8_K&CNh@ DPB >!Rڲp A=hƍ>D2Ō KLSL5męSN=}zV}"1áE&hSH]UkL Wao.mz] Xf툫nZ&|נ^~p߿' Nn,vč:!fAI7,:[la2kװIul} ܂ |oƗ/u8sխ_Ǟݡ S'9_z;\OT'az՞Ͽu gr_g!R\;9`H=YO} (1d  >Ig> ρ x%B$6ڪK:Aj̡VD;aCXG 7Ck bx-bBaȻ֪9žXD+ؓ4VlB=qGQl"c2AK{ XD2 1YKN$JɄ2'iGR9U2Ĕ|+xVJ䑿$,?ɏ/O)_&v%+L0r Mji2Uef݄-whr()[9rdl'ytvll=}RX~'5Nmrt&Nyq&-<{PuJ;IQ,Z# A9}9GRZRɔJPۑ@FazI(=Gќ u)i*_ϘԚ =jHT. Oi"mZ/*NjT&fG@ ԞFd(*FUSA*Y2*>CMaМUmiYXtdלu*hا*v,^JBգkX8vu+m)[ͤoً Vr5q\*/*q [2-Dj-jf cw\–8lt[)r?w¥)%J߂tWix;Ys%b{Ws'wnrAV7 I|[ּmsC\۞5/\^F*iSl߄x%_Lx'*fikwԱ-Ưu.qswZXD,S3pGO˻vL?6ϯ0 # ~OBxsFsi6wu<-K&q|.;d:5r5Y#y2N|]jORFLjFc'szg`xٙ^%}k 7Z̏pklzImi-47}7j-Fu{f7GumzZ͔jsMtySJC38h[ܦ]I/z&"7ŗD=eBB=v-mT} tF }%uY;cIhnuS\9r_ۻ@_x3.mEkϣnw\NFQ߳>s ;"F;e/yAgQ@귢x3lvw>D|NzryW"|_գƳ_'C{ף~6>ϛ7ïޡ'?5,z;s?~ʆ7 @(:=>A>;A?BӾ@[=d@A븸9 <> , L?;ӿS­{AAl-4B/( <2,6ˊ)<*L@k%LsC`$D<3@}{t?k+C"BF̿>$̽;̽lC:A?1 BQ3\4,C<9 F$StDSD |>B4*DD3\?>Lt]=C[AAܽ"AXT2\FU|FH܈G / I>c6PC(G F9,G*djFm?cFtAkTYx@yԊsDtq @H&?RBBgy$8FA(H&8C\$[E`D8#I\,A8dǎAȅm ÀS{|GYIZ$ʢ4ʣDʤTʥdʦtʧʨʩʪʫʬʭʮʯ˰˱$˲4˳D˴T˵d˶t˷˸˹˺˻˼˽˾˿3ǔL]”Č 70G PL< &P"P fĕ~ {@MVL ͏Їhp$!`q8.ռޜ "H00DH輊54Nk O 霭k(3)NsЇ!iM4Z,=P[p̭Vh( ϲO@dwHW8tϺ [hGЅЅԳO.af  aQ Ḯ8Qfww0ʼnVp[`L 2 j@9OѻЇ2]! G+%6}R  mUS04=FpY0TYRӞaM}0==|RK-HWPP_؆`RSl `TBOZ0Wty0"T̈́T>EpX?O]T,Y1HlbEc%`rMՠk͒I M]T^uLaV׬X|W-0(ЌEu~u ч! ,1 H*\ȰÇ#JHŋ3jȱǏ I"(C\ɲ˗0cʜI͛I2%Ο@ JѣHUi'PJJիAhׯ`ÊK֦V>˪]˶۷St ݻx(ӧ{ LԾ^̸KT ˘KH9ϠC ӨSIհc˞=״svCܼ 7Cē+_nḄKչBԳkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZh:^&ɚDt B@80R&Ї?A((;:Q1= }c 1@ dIc0"OVf\/?ፄPJΙῈIB 0`3iA 9x>V p `!7?Bqb)H3xH!3R/Y?pʲICbd-vw@LY?j D1 2@jH ZhG C!H`,Ket"G/$!-}C 9MPywS Sy3*C5 PҵTJJdE\!~"H>Y +M ՗& AYaC4hUD -gY"6^1tr~0!\V*/MٝPKܕ3f[kڏZKVGC_"t*PoQp`umC \xmxz>J@! , 1 H*\ȰÇ#JHŋ3jȱǏ I"(C\ɲ˗0cʜI͛I2%Ο@ JѣH=i'PJJի7hׯ`ÊKVV>˪]˶۷It ݻxe(ӧ{ L0Ҿ^̸KT ˘KH9ϠC_ ӨSIհc˞״sޝvCܼ 7Cē+_ḄKNչBԳkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IIӻ?2I';iI񈘌#ӤPA"(`+/ %KTfvi@-;*bc&\@[2>@1! $!l(ɚ G1z&x[pJd 픉-cDPn)aD<0m2sH1Yu>%V3nlƄ+6q08<1f$x00( @ks1?,ڒ8#JYlE2J`<@LQ H__/B+C@jX4IVD&( ?iSt6e,YMdU 0 X5$T ֚\S,K%1u Ka}lR H\QU!e%G0p$f%Xc3z`:$8A3[fC9kA]"@fF7і%]nH],#g@j| "D rݫxºIv_2m+[ 0n1հ7@quR\BPb1O*]ʴӧPJГD7ׯ`ÊKVgի(n=견۷pʝKٳ)"˷߿G;4o۵+^̸cf˘3kv9-õ7MiCװc?tвs+mM2g=У;TKسk7N}5ËOgɫ_>O ヷϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZ̤&7Nz (GIRL*WV򕰌,gIZe]0K`  0 إ63yD020hk~)&6Lt3$  I/6dv"h?͘lӞ˼GLnZ `rV0.@!?AbAaϐ䳣TQ1}2(9!ZOɁ)_ҹΘГL1ҏ|Na )I8SXG 4~I x(X7S"mkMc1%I3:ҘܢVipBUGIL3)_:0yD73"׷5)0]BOPx!J1[0k돔 \km`D uhabjr,gJhIہj&7༾/2 2&.aؚ0b!"0q<[˓ L]W5b.Nf0*<0֪OY~e"d7vwi#1@l-c&}0$I,\\\$D!|y&I菞gy&ƕ[rh! ,L! , 1 H*\ȰÇ#JHŋ3jȱǏ 7I"(C\ɲ˗0cʜI͛7I2%Ο@ JѣH9dO~JJJիX d iO`ÊK٤\<˶۷pMܻx#]OLlN ǐ#T,˘3k|rD˜CMZgK^ͺ5ZjOM햧ͻs; 㪅7$獕3do/ËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h("}O 7l7p`mQN=Ҡ?Ǡ$͊DbǍ%  ,@T eu6*=Ir? $t6WXό8 Y81#FY碽}ͣO( UTPO Q,T 3'7: #M([갪N8:Ф: U |P Pf[ZDc rX]p1\YB ӥ&:O!ЪhVS)4 Z 7G,Wlxdw\9dC6EKܴ1WQ"?#P5t ?`d vI-гcv-UAQ?^x@(2 s7Gό8lSN yt'#5Cô.=M;h?ِǾ8_AtQC~SC〣!, <|;C>UuWWq0{ԒzؓDG<[`BPdDbA&p =p(Jv$JY]HÙP"ijƸ0&7HSF?LbK"n+ˈ *z"92E+z#XlH8$~ aD)p6^q#Dq9oԣ DŽQ' ?"8FAGGZr I%/iLdl'oP rKѢ*wbVY,]Iːb-w N$03;Q2)r""ˌ?<<Tf3 lz!7Yrd㴣9ˉt  Os1)zf';IGz }?yPm&4lD;uF3ыj NDQEiFCj')HYZS)J#8AW!pFbp D)LәWh 9TrVU`Fm+6MS֕nj 1T)$ ש`H8@YUSIoU4V*$bX\CyWuW_S"nj"#(Yw*V,dJ5E.^Cđt=J6hp7lmkD.wF*nRZN;+C$  8 ]ר koW!bQ%2"^2M-B |dS_t@~􃃁[Tv$߭%UҔ}슇c8#=.M_#ܴh '[9&$Ȳ-w9\rmPզ5wjYFt=kj."D=‘`!gkҤKkN{;t66 Q X6^[۾-~[6E^(H!ymp[|g\?T# ?gcн'r]Gx̋cS08 =DGzY-w)C?w ~(_NqMO3{N cw@6˞t}:Tn؃ H<{=5^L: IXx%/WL1r=w-k>þ|G|GS/t]̿~v3T^k_dIׯ񢿆20ƿOC'?Q 0 ~08Kŀ(z@ [ Fc,1#H P@m)-g0x#! 㱂LxJL<肍:!RqA8-p bxdM@pQ` ? D1s(DfX,f@=>ƈux؉8Xx؊8Xx؋8XxȘʸ،8Xxؘڸ؍0 0X$P "U(P h"P MH'(䘏W ِ9YM`  `I 0==0 :v1$%F!y `YY` @Ȓ!@@?ip+ a3Jada炕q[iYT 0d=q9)xK,ᘗPWK1 iC)i]0鸎eUSY1xiؙ[)KIɚ؏y YqA<xɗjRS !a陭a)pp*$qUAP_IYlYnIٜ9P0A/$!iyڡ lّc AiiI *yџjY4깡!*!Di:!Ey;ʣM@VY6TTbQ52nٟP>yjey$ac~I٥QczF*p2a٨`ʧc*._ک!hLJq騳ئ:ѝ\idVYIqڞ-q9Jd0qY!Ѻa j+!jE:z蚮꺮ܪ#Y j(٢ʮ@ѬЪ yɯJ*N .OY11:V [`I7ZZ1 SҦyQѪ8+611:v:F[ )M ѴgqRKh2ʲ OcT Xkny(kzw[yGA ҳ H~;L7{Mg;{ZA[[.+g4ѷ[ZZ᭡[jQ+[;[I+qKd *j-Jk[ۛ9: d5ͻ˔HJﻍ&2ѱ 31+˸3[,zY\fkB Qz+qE!Fjk( H‘F )\2µ!46|8<: Fj3LHó1a0A!?AĵQRK+ƍKDaeyK  kK VTl{;:kỌ;ɔ\ɖ|R.\ ,!|012+11!˱IC3˧ ɧlk. ;+̤\lLǩ ^lA4x!1\ L|+A-,1g@ Y}W{L} }?./AJL+@,"=45;=\8!2k})FO0-j|hlUMc< M o+!m<ul!`\L?A}mָ~<4|= qɎْؐz `ʁ=\45 ڻ(pY 1;·= Ĝq9MLƨͱɺC!-cάܾmwy==Q\lI#-]Lԭ] W*!A a* !Aaa+H* Tq-Ҝ*&+-/}+2Q1Jq=,F>]D[^WQS~Unk םe4y9^ۭfb>>n}ib}芾!A2V1!AkM^v^>˄>̮x@7M aj81*ڜ[l`!Aa߄K q/ e /! A / Mߝ>."n ?1lnО<>X(L~N~+RΥ`NҸ.:-dye ޻p>.aMό~MaP_WYd_fhOޕ9f/r]>x} ꂎONύޕ{]ΐ-Z]l!/oH(P!mriwn¯QQ?.]{0oA ݏ /q(JȦ?//ze~YO@~5:4x0†DĘQF*dECRJ-](@@A$XΘ8Thʛ4Iu)`@>UTU^ŚU+ Uthn=P%أ[btp@Yz@,ّgX`… b$0 Nȇb 1 ?kYhҥM>`Ϻ ZD-@v:vōG\r͝?]tխ_Ǟ]vݽ^x͟G^}ac`[XLǔ~o⦅*@C0A4$3Ь?1D@@7` `%$D#p+oODR  Pʀр#|kH#(H+A;P* 7\z"P*,͐"b:73K$@.TO?  m y)%nJb:TRJ-QL'K$TS[%}qN,U[}@deUQ;=u%EeѧbPE X4H\JNBmjԿvZs|[i5^SrKtϩm9k5l]meja_(R R+-aۋG GZKX)["Ƒc&dv5މBw3eP^M9gswͶxްhufi:jj:kk{3#/jl ɫ,[?¦;g rYݴAx:3o&x'xG>ygy矇>z駧z>{{?|'|G?}g}߇?~秿~?`8@ЀD`@6Ё`%8A VЂ`5AvaE8BЄ'Da UBЅ/a e8CІ7auCЇ?b8D"шGDbD&6щOb8E*VъWbE.vы_c8F2ьgDcոF6эoc8G:юwcG>яd 9HBND$+7D"rUi!>;TҒv$.iGFRә'3)Q|(eJL| e$U W+}%pJYgP/3-*t_2:iQTj2u6&NZIN)<%*suӖ4yOtӗ'i3_:kWFγfP *>j2ʄ(#3 ɍRTC_vT&GRd{KbNgfڒvli8Q:Ρ9hPթԞ*y~,$LjP Hj;FXy/¤yKJzk:UfMJڒf8ayR؎(V% dJԭmI_WB͈gkٗp6"hH2c[{Wȶ# n"Z6(-p7Y6deU{M궳us#b[H-E*u {Ɩ%+wKYV,zwB\).xޔ׽݈v5"߬`7ЯUś_Fw=nYWM0F؛.  t ƿ*k'rEpKj8戃%c^Rqcr 1XG_ĉ]b\0΍k>Mpk dK*:qo*97O^ioỹ2 refY=.L2ɇֈ\8Vҏ>rJ.gAG%44U:Й03<@9InTZQ[wzor,jRqYk.7|lTYNIb ^֖ʨ-0 ;7V5YM5O9aB7o#ٴ^Yb{w6 W6这L}XѵƑ-b x+0ɔ_|WK+q7W8o|瀱uwKS9tM?všlG[^8ӧn/="ߺ=:^c.uKõ{U9v}kJAnx߽=W:Ëy্k'H(G|?;M?h#ݕt{{G2eM*$|rGE,ܩnYyߥfSc=C9#s? @qkÿ{ 4rû@k@@@{l?@ Ʃ*LT‘@AL( A As<8{A~/?B)B>7<2#$)1D?.@AdkC@+|=ųD];Bz8*+,,HBALEAdD\?UD@{E"MtpDTƗ ȘDC$?47I JJ;IȉD$JFlD|H4DD/˔˕JjI$^CI|v˳tTɊIIE|Ķ0tJ@n|K K$G Ml;JHt0J IBL"F:򑐌$'IJRl& ɵhH|r< ȥb^Ƅ1ʱ2((f^h[2>@1!x ^ "3 J1c0 <MaISL.ɀK<1a?m!xaDa9&Q1I[@1Jf oܢ-gkh! )H Q@-A(XJtH:ʦ( IBL"F:򑐌$'IJZjp?6u-dDiP"%xnr,RŔ4a@ /@^zȕ WZK,H V9.1|!`vD.)&LPs&L2%T03[Ne/ip36\?ILMr(ȉ-ٚwDJ)?%Xw&HE PXbM% 8J w:$p^XL3& 4I1H$)K _Р-TxЀMEҬ&(pEgӆl5)5-A|$0D0x#0LSnjT5Ѕ^.x,D; XjMAP#7Zz?BkВ\kXX_ "@2ُ@4[ =ۮDe;:P[dZ8WlAG \[\$AALT#Nny*y DxcwB@0_,1$T.M:}؃9PBkį]e ,Wʄcb WWʆ)$ P-BD! , 1 H*\ȰÇ#JHŋ3jȱǏ C>@E~(S\ɲ˗0cʜI͛7KR%Ο@ JѣH=$y'PJJի96퉵ׯ`Ê+s)>ɪ]˶۷I͢E ݻxe(ӽ L8V\ +^̸c}):}˘G89ϠCw,ӨSI:հc˞5״s޽Cܼ طCē+_xC̣Kn9CԳkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'II0Ez;^&qd `&B&*32J/p 8di%MCl$${3$%n" /2c 1]#d'ZBMvS60VRabwr$5`}-h ,f%*6QgӟX $$x00(J?W 8h6Wr"(Jt]c3eF s&l;bV$Wp?JfSRbPx!V0:[@SMAՏl3[x4%/g t&0A} -j@Y/T upj^3b $4-dZYu-[micǘ`:$<,(kbƸQ/ vȆ7jRBi֕@K (X!0mL $/KbJ벥2taZ`U ۨ+Hb;, - d<4fxس/Œ-XX&ׄ8&+ ݍ_rT ļ f܎k΀! , 1 H*\ȰÇ#JHŋ3jȱǏ CZ@E~(S\ɲ˗0cʜI͛7KR%Ο@ JѣH=$y'PJJի96퉵ׯ`Ê+s)>ɪ]˶۷I͢E ݻxe(ӽ L8V\ +^̸㑇):}˘7ϠCc IBL"F:򑐌$'YųE'$[07M5qB X<Pʄ IAK2*p 40Kt,/a%Y\)hG8 B$-5HVҁwt@I<((#xC:aS,t C1#:%!ygXy{ x t!ŔGapu2Bѯ&Gtcw%|.:z[t$~Hɢtß,!`D&,1KN-h gHV$ -Z(#`!x$E0j @8e :f \2xxGQ!Jw#hAfΧT0^'2^`kO ˕<i]0 4PEQrdIM^R<@Z` Phe3足͌.g@cQTKVO KPbQKKܕ3l@"Q{hxq `e x TЗ&\E1[ -D9LH C02aX(! ,1 H*\ȰÇ#JHŋ3jȱǏ C@E~(S\ɲ˗0cʜI͛8[4Y1ʜ@ JѣHIO~JJJիXd O`ÊKY\<˶۷pMܻx˗%]OLqN ǐ#T,˘3k̐rD˜CMzgK^ͺ5ZjQMmͻ s; 㳅7$璕3dx/ËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(vI"4vՍZS{>" Jr̯$P_"#w#` w7EĒ$HQ,0e#{4,'B] -IS fAYFWB &A9IkbP "́p,8׹js"L<ٹfj̔>EpړS>Oә@YP9QBqBDuYQuFP H)Zv~TJ9Z1LYf*c)OKGB5fMmMeQIRڨ4qIjՠb55*ԯJQ7jNj֌1vp}\GVծs=] ֦R!] ְaXN#TغfYn6 zE#+&mlj;X:vUE,KdQղ nk? ȭfC4"ڇ`@mI]ꖬ$mrUK^׮{L6LbV[)~Sv"y;`x͌# AoO˨_T8|[`Ne2`4@PG+1?++-]u, w8-qb1c ;>1a߶=0[@Q`Paqֲ^9X沜{Go; aiK2/fseFV3'@6h*hXnO@?jCOV]sPgCS"ðfG'!UEV._Wo6KN{+=Sg{ܷfw|7-PBjs(]IG:ַ~k"`3&QU׍N=o_^@P'w]?kwNxzgW''__G^@{)xї{{~?}y}={3_8HV@>{/OAO?_Ot۱h=ĦS*ဲ\€fHhvAܶY&`&[#n180 @@@*,/8'H)J=0 w?BHX؀F31'^`1\Uq.]q(5 Ր (p((^H*@* 0,!6UxPq,a 0` x؂s؉\ȉ5!,(6 챊E2 $"`dI0T"XYX!Π ;bb(膗xX rmmt)lh(Ȋ꘍8k ِ9Yyّ "9$Y&y(*,ْ.0294Y6y8:<ٓ>@B9DYFyHJLٔNPR` ` sMS6 P [ƕRb @7fm  co dRWn+z9Yyy`1gɴSS Qi]2@4SI `YY` y!@@"7&00@!ԋpwagqϙyQY$1ЙYKɗX闳11] C^ b%a9jɖ ymQy,c.K Q'F)ti.Z:# 8 9EIuDʠa Q'IQjS8p$qUBAPɢWZɣ:j#e AkPcA@4 Z 0Zwڨ9y*|;Zz y!*aj!ʪ)7!y.ajQj:um.zҪOGj[:1+Zi!1 zQ کZ ک3e:Ӻ q40ک*ZtSaK  ;\NKcHe"Wp{!f@kHxZsܘK6A{2|z0142 ll <K]΋,Q)yAQk\.˸l[, q1Ì kӬ,QL[ߜ <<| ,| .|[®(,09mɪ"14aI@!A mM $]&}(Y,9+- 9;= эu,A,ǿEmi .Ȅi,!Kݘ=ݴ֔Sk A!1A/qhҬL2}xm* ɋ Ō؅œɗ ],/!ڍS"͔͙@!1/AK{]]qڞLܦ:}lϠM- -'ܳ2AmZc{~-==q=)>^R%M7]4 4M10' A!@-߹^~|ߘ>-/N^]U\Ո<(=@jJ "ȍ\3dq-z/G1T"! Aa琺" !An&إ-. ͎C!۩=4a! SX`m+1Q׍խ<8\i<2=mEn+HSƋQ=a6-=>">n.ޔ .FC9I-,)^ε p?9^;N2ծ[])OoII!j RY!TLi/kQ8- ظ+d A0a ik囖*0A a^|z/:71QJL/J_.//߱o^QWs<5_c]R0^| vX\ᔾx^LP_O5$nnn{ߔ!`Ä@hPB00B-^(`ĉ=~R$C J0RG %|ȱJ5męSN=}T(Th`єC?8TlJbQJjVXe͞E;,X.@b̳Y4pv]ۖnܹ'EY~iqqQRa+|͡Y KQ© 6k8H=5lk捖WxJmI\ϣsI9tЦ j=EAgݿ_x[sTjw?"+0 <@p> +Z 2ȸĪB&IC P!?*\JN̻[|1BftF ±QG살1 k0,$4#&ID1JPk".ct;cL$; L-%@ @NЊs7CSOTȤ;$PC2*ɀ M"(ȁ tL-cSSOE5U/+KS6tHUwW_Cj`;! fJ TMT (`X[ VbWm[o7\q%\sE7]ue]w߅7^y祷^{{5aJ+P_ְF^'>5ZJVV5W8KG&Ԇ"iIժ 6XKnOn6`hw=Oܠ'rV({:.F(ipz(rŘ'D"* M^|pKmo({*,Ϣ*L\яd 9HBҐDd"HF6ґd$%9IJVҒd&5INvғe(E9JRҔDe*UJVҕe,e9KZҖe.uK^җf09LbӘDf2Lf6әτf49MjVӚf6Mnvӛg89NrӜDg:չNvӝg<9OzӞg>O~ӟh@:PԠEhBP6ԡhD%:QVԢhF5QvԣiHE:RԤ'EiJURԥ/iLe:SԦ7iNuSԧ?jP:TըGEjRT6թOjT:UVժWjVUvի_+:VV}dYVvk\C5tekYسҵ'}+. Wrs `5'#-[XBN6ll kl֎bZy6 jIQY1X6q[J>/w.$p;N*Y.cg+ڛD7E$va]qu,/kHzd z%; mԫree^—onkywqCWx/m`0ؕvKKaZ#f%G1X^&S)b@8$I^mcxwNh dBB+9GX<Wȃ%U'5Ez,eoe޲u2,( x%T6/d(7q«9mkBfb>3u,hZjƳ]=>$\dMG!4.O3'VAtӬHBmTWΒMn fZ&c]-dOЁu{Mh{ى3FQY6O~`d׾4cO{ӹN_n<2+Yթ>-b |q4MnHoR3,v-mc4OlgO3srp&<~wOqN75Z`:?r%9HNX|$uqpޖyqzqﭣzjy#.8u~u'[(mo7nmWxه{nWiN{ݹ]lϼ݃_s3>w+ ^vv-t,F'w)xᏟ.{kl}׾oKK/v{|G ^~H錗~%{$||׾ ߿~Zr%3on_5}~;<96:X?;0=x?{kK@#L C?,#=?|Ļ[= |Cc:[˓A@K?B@ l[4:A $l4؛{A ?̻2#B-3.='<d䛽=,tB37=6TAC :@TD4708ڶ6ӮHC>CË J‚DD[ $BDBTFDBLE5tDT$ÛDVG OP\QT2Q,EHNRDE$t ?0DZ$+hE{ųjw?|\Dɤ,HIFIpEoL+G8IɆ4]ȲdFRHTG4ƍ$Ǒ$I tʄʙJjK䰏0DKJʾGɵKˏPºŌHǴGt:bɪLLIJ,JKDqL4dz˴LCܣL ;D|͗lL<ΖLKD ˮL͹MEBLNNK,MLͧ IBL"F:򑐌$'IJZg\y?6e-d>ٖP$ iJHS҄ !C@O.#$0y]kq%MCY 1b c \BYYed?1)ȀNϖdP%K`Z*x^0, `/,,pq'LA 'a?*t$*Cy2] #@Nxb$"p?a}rӛ I[K-.ʒEC9I*сH#3RЈKv "F37)5l*nu &/Gɑ谇;-,=̓6mȆS72W(>miC7Tab|Ao &'K@À? %4q<1#&[T+U5sK. +E t F x?1%kI*\s]Nj$?rXKvKndH@j0]ےnҪI&;za0hX#x<``Dt) 'fIGb6ǚ2FLcB.Q JLf@4NՕ") Ppjt&A! , 1 H*\ȰÇ#JHŋ3jȱǏ CLIRɲ˗0cʜI͛8C IBL"F:򑐌$'Iɜp-<%ْIm9Mpɗ\4)g„A*Y2K=;y=v9X0?  )C`nNV/- As1/C%AG<@= `31=8'>?"[BX87[l5P2SOh HFΐØxA^qH[:j[t+;G(Htj˓`5<P"T'/!R꒥0 RPx!ʒV06J[@D̀)pThkX@X:Φ.-qjMAXY:P Wd5ZY BPL)5d݈1V*BE6 aD0&TI˸&&l^20-?zDF0غّ44K@ܳ 0hvWk+HW$:1CoL,- ,CۑҤk|نfbH`OT3`9;߂@6 }r8 g-Vp(pöuLj@Y! ,1 H*\ȰÇ#JHŋ3jȱǏ CIRɲ˗0cʜI͛8[ IBL"F:򑐌$'IJZe\NIlotOjXYFɮP3!A$V0z2+2Lr&Ї?A((+'?b@d9kVӛ-= }c 1fo<$\?zv̧?ʘchH.w6d%4Ѕ@` ="y !n,&'?{YIJnNJ+Kh `kITEU}@aAnT0; 1@A:q GYa#5w%-z7,f@O8dDx_0W&4P-zsk؏BzbU~(YߣU FL:<(d  EB|X(Bhq!wECy1P4 E|qP<! ,1 H*\ȰÇ#JHŋ3jȱǏ CIRɲ˗0cʜI͛8c̸ǐ3&8˘3ϠCѨS^MӬc˞M[kk;톹{ No+_ɛKNsѫkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZdsq$P G#/YƁJ}R( H0*HeIRVg4^+b!40]ʱy:a Y% `FqLd2$ˬ }4>T%6cr˲<1a?ZVaPΚC-̅2e&KpOX!̸Jd-ZВ@LgS<n}4Q<# $=H*^֓I0 @&& 8 q)5a*ӫ҄,əf'2AA1ϡ$ÉHdMoC-=N FCRu& StIt7u;P ijkkHtd`g 8"+KJ 5%9f Lr1F Q?nyٰi.hAJYQ~$@6Faގ@YJ, A(YYks&hZ 2W) -HaKPᵘL(ha1Ac(P%vc(! ,1 H*\ȰÇ#JHŋ3jȱǏ C IRɲ˗0cʜI͛8sZ4yʕ: JѣH*ɳ$ʟJJիX^m O`ÊKY\=˶۷pMܻx˗%]PLqN ǐ#T,˘3k̐rD˜CMzgK^ͺ5ڦjSMmͻ s; 㳅7$璕3dx/ËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(|'4#pXpB ($xA'@2hp.,@  cCv] p@.Ę! $ `x>x'OhpdX18!`g6n Lh:F*UNZ骿y Z?B0@!ȩ*ڶ  #d)X*0 RkAVfNP D@V#mk쒶/Zfw nc!hl' G,SUkWpR1DLTGuC"p&LELB. %<>#ijAM%Q!!TOItM&e3 J5RVcMc1Շbf]S3e`mGw;mh}-wCn1,w/ D9Lc0[LIm!9үK<ծz ޻LӌǞ>0% }N}_(oON1r(O! a@z"(? %:H@T;CISVxRbwt7ֱd@INOe9]pc7> F6\ `!̈\`ƼM#蠔dф[L>|ah4f Q2dtl!яA$C 2ɻH'CIJL*13򑥴*gVL#-wy?[rL"/w_0&-iLX"}ʜ%3gb0&5yMlRfMQD9Q Nc9ϩw&3'=h3Kg=y=AIτo(?;*Eh,j%' Ť_{8~%"PƦKҗ$)NIzҢ.٩QzS5r35jMzS>J- pzp%C9Q-NSg6ԶZ&D=A FUǐ Lr0PЉVjB}[ch=X Zt@bh:T௃I ylT);UVնW^}<Xơ3B!,$fmdqKTu&~Fx1t1Ӗ8FjMrňt7k aq!f QY¼D1^u|5V_Z8** 5@B8DXFxHJL؄NPR8TXVxXZ\؅^`b8D0 0 qgd8$P !im("P uȆw"P @a!fj8XxD`Aps! 0==0 ؉Q.@ `YY` !@@n"8EHaH@|p#xxqhAڈ QۨXgG؋8HJ؍1!A*`1]Њ C@Ios5rH{؇&i|+ )K) A4x1yfJi*=T):ZYqyxbQI%X!mlɒa(`cPA U@XɎy)wv&я]YPpAP&!`2Yy[8Ț xq(!vY)᜶hȨ { ш!؎sYXyɗשџT ڌFYY&! ّ:胒% A0(j .A[i2rAL3k5Iksjح2,WA(ʴOZDKl۶npKlsa_+Iԩ[ȵ0aAʋh;!j"wۯA}靁+Vho=9R} >~΅ gJ“-;>=5q ν Pmiʉ=^~AH /m.j =θn nJ!(ޥ&VK)_|x<{S-ϥ4>Tm. Yqa*qlmTQ(oQRN!ABd~@!*aN@AofpK/{n{^_D!ۇ~h=jIp/ȡ!߲]w#-J,.?WO>?;+w^>iYQo:Q@/X͏̃!>rZȟʿn߼ ۋ>^, }>ع9_hF=޿O\΃]@ D&QD-V4`ËÁ$=4p#J-]SL5m @C9fӀIMoꓩS;@s*HJȕ[ĺ5Xd͢M-UgjWoG zt8km钠^YE8rcJVjK\y-e2QPֵmƝ[nm۷QEM> '.ts-'/&x}s%_4]]v\ɯeJ)٭×x'xG>ygy矇>z駧z>{{?|'|G?}g}߇?~秿~?`8@ЀD`@6Ё`%8A Vg+4AV`0'ܠg" KBE,c k0p*$ H| u8!o<Ґh/cE MH)-1N"MщDa/*b,7hhF±Ie|a6rg#&1o IANcA=^p&%IM'D&&Qcb%M9F@ZibUG\e`\vq/ ٷ]фlIeJ{fiKDR&\4;L"H\Nh,09NJVc"ΊS"4d=O01'D鑀4gKyN5Cz% -F[(Q #GIH)i= -EQ<})BZ*MiE9Brz)i$zdSJ"?k{?ًc@Il֛??3@ÿ#@;@?[5@{@԰\@ڃT@ @><=c># 5s%;@LA'&@#Bd A1< B l@1AA?@$l?гC0t3(,>-4tRB+|7CD6DūA2\D31ğKA|B+=M,EPBlD7lCD+C/{DxDYTC2+CD4U IBL"F:򑐌$'IJZ̤&7Nz (⏷rt)'Jp+"YM jeK^9Y$)` 2zx!]E4?QpdIA24șfKVC>02qvĞ".i[`$?xegKau 8EL^% JfOG eIP_@cPh Bbёá;Ttx'L9T8tHnсB.C\*S0ğ-K10,NI ѹA(A*c0YGҊ܂X-r tb.@RB59T.uHYg5mdG BhL)>݈1 re! c )j:\DיENO3_l# oCrlx02Ib\䂔MM{D8m\R=`mj^ &ف.!<eCڱ&of%5`j MfⰠX&I [bL8l3J! ,1 H*\ȰÇ#JHŋ3jȱǏ Cɓ\I˗0cʜI͛8s IBL"F:򑐌$'IJZ̤&7Nz (GIR2g O4J2s|+ݒ`,hʼn;"LoclR$jM֖ -GP,?A<06¦-[U} =pm t8b{3$ ZaC4-VD U&z?"6>[@$1aa mImM#EYgc/f0\5KTLH'"a-`"iRc"!XU2&+`[$YmSJoO! , 1 H*\ȰÇ#JHŋ3RDZ㿎Ar(Rɓ(S\ɲ%A0c)&̙6]ɳϟ@wGdѐ%*]ʴSpҔZ3ӫXjsё^rKlVToEk۷p-9hܻx>\T \Q+&T#KܕI)k첱ھV9Maa=^z/ǯeM{ik9j͝[Ϳ_μ)#K<س|ٮm y >xDz˟7t3fjh Jځ 7 ~5(E Մ`}vQy("g"6 ,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZ̤&7Nz (GIRL*WV򕰌,gIZ̥.w^ 0IbL2f:Ќ4IjZ̦6nz 8IrL:vA=i-J! , 1 H*\ȰÇ#JHŋ3RE~ CjIɓ(S\ɲ˗0cdcŐ"gɳϟ@ JdMq+ʴӧPJJuQIqVʵׯ`n5سhӪ]˶-ٛJʝKݻ)RT߿ Nw"+^8faKLe#F̹j3C Ө~H:װcg\۸sжsзȓ%иУeйسkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'B4ٖLro\'`d 4H?+jN k$P*<32-8hn@A$`? 1b njhI&LPsD&n`i䗺 +]0 VfygQ'O^%h=WN/JD g9iRX`P(% h -V/)f,h DQʑvP:D{854;;# FbU![MV0^ґPF`#0ENͩ K/p3!ԃ(G-kLAP=IKnQ}Inсj!-G.|@`&DkvE@#ȾxhJ:$,AtؕZ`+[<,IPi7jIq՘sч:~^)a1K!@MW|prV<Ѥ>aepWN% u \W!ʈgbkV)ʊ#$ pbĵ! ,1 H*\ȰÇ#JHŋ3j,GBHɓ(S\ɲ˗0cʜIǏEɳϟ@ JQ7;ӧPJJUI,yׯ`ÊKfҭ;˪]˶۷pfE2ݻx+snN| L^65̸ǐ"8˘3k8Yb͠CMsϤS^ګi[˞McͻMq?μ.NgrνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(Wi‹2W 8A0#Xݘ0Ȩk~D ,ŒK^5WPvɜ ,dUv\z&q2•?jՖfin'UJ陕w*$0#䜁X ȰF*ihjicꪬ꫰ӠF'P/+R+yj,P +v+G))3=(0RI!RK4=b?j 7O(ApFo@`ŮLcJ 2nt!tB&3>μ tP@" 0L@ӊ9!ZO%LG@2dAL"@lps?OMHqG`Y(].!(P"k  Ӗ#仼QG!K3 - 82rcLsjF{w5-eCTCD=d,A͘A;{OT3kTn=l~51uTkKD&GprL`h@*i% FfCAܠ|)!QB-!\2BP-| wH:@?"Z8!P|*e{l` H2hL6pH:x̣> IȱT懅l!H6.t$`40ȋTIŕ@JmiaR 'fa *)-c*d ^1.\:eX ; (dB%G ydR. 3yk& rU1gJn"{$|L-CcN)Y!ZЂ[48!s(D/"xȡJD3ōr(C*[(GeSR4+LKғ0,i kJr%:E!O}:]GCuDCvҰELPST_1Y` flOڕ hGˀ9~`VHEeUf6@]!ŨO:l8 0k1 ;!6N1RGG,,KԺHx3$;Y>= >dl[ vo\ִmq\n BW-u]jW=w6@3r[rw%%,ATb쥔{xZ+?F0'Vw2puz|=[ l' 0FG qxM%1tDQ݉Քs V jwwt&>B[%NL*[Xβ.{`L2hN6pL:xγ>πMBЈNF;ѐ'Mi?JSG7J E:GԝF5pQ xt>ȩe}KgzӰ(MbN8 ,MD'S?z0d׏yv#IH0oǚ C;4͹ӽvKZ @P0| 1 v N'Ȁ/bj 8GZ+x\P#o["v}oo"Iִ0t`G7@GNB$ Ch Ԣ& Q^Yo|~5euU@d}gfָv,7>/I"/x&|1CyC9N%yAu^Imq=T!OI ͇t̍w$G%S(| 3?O[Ԇ5rr%m~qh1| n{}(Wy6qWph px{rW!wzz-ar0XKr<1}S}#4zDAx(RxTt%HWuQJ؃Svb7wpv\8c(wEhW+x!hnXo'xW_!4B,!lAGhq5zGh.A(xV{4{G{cW|wX~Xg<'!(b1hg/!~'}~Ha8Xb(KmN]፱(ƍ-aXзh'|41N( pnqHh*X,Ȋ/xr ِ0Q4hI k`qa5ф8N'/ X7U Ez>I8g EBiJgwP989sVQ‡FFJ`ٔw.a-a2AR,Aщ^فtxaї)|98q9hƑ3G9nlyYhψ-AY$َCٚ!b AY @fɘ I騀<gY9kV9-'I2hB!gY vi Z. S+Q H($q9LZ,"O/q(* ,c5 *q#:jN73@zE* 2&tGK:Q9{QxDGҩ9I8 g˹IZGJozh٦!gjyy<ћ+jZ 1v,-+3ᩄv:$AX,枫婐1jI5Xv6$Q,!)逃p9rS :*-&: ڭq$.?RnVڬQA?aR`!m(/ Jѣ?R`!u |Ȫ՚#[Mjt*%^*Ѳ1j2kh{f2[9[F(a5AV5| 5C[׳ !`b;灩3Q0KƵmlkf{=營Y xgԹڏ}:&=Qٞ뙫ƴ<ѷ{I+P*K*2ku5 +څfv{k fJ{k[zk'1S۽ ѻ!a'&%_UHQzrٺNQqȥP ˦ic4FGEKƹaG9g^;7R{~[;-L8:<qh %0Aĉ&AO 3췄k0Ѫk벇[h3x01f r*\fF>sC 5a~LH/ pɨ?1ԡY okWRT-SS$/(G>QnNm(߄]2g^z kO(Q>{}L\kޮݕ@j[ vyN Nۦ>JX) \~˪kqAZsu]-Ĕ'gza^Mq Gz9Ɛ&q$μnԁݥZޙ>ؽbʳiTV}K߷>PU+N >i8-m'_/1x*h/[>5b!`.H!CI_3>_ "?$_&(*,.02?4_68:<>@B?D_FHJLNPR?T_VXZ\^`b?d_fhjlnpr?t_vxz|~?_i 0'/bv`A!(Oa& oQo*/ͪN!/_*Oܑq* "(aB&"$aBO@ dP!+ 8QD-^ĘQF=~hGH;DRJ-iK5m\P&D9ʼTPEURMA"- T(}4Ҫ]~ +XeijV׭ikͺV\ƭW/ oϜcFč.XF41o\>fmWS7xX%3{ |ɇy/(,Ȼ=A\(¹HCՠ38C= qO,q%3Ł0QnjxƲV;#< 5"dE);r+-,HHL IT'[D7N,(7>#3#BS/; P@hPMLO:]9GRQFIԣJ3=E/*< G3LuYׄ9;5STRA% VL O f׫U[gډQlXRS%p7Ew$c7re\YWۮ]n Ɯ*u`M]ؠ,VTqYJᆹԷ[l`c6Md=a*]~mWoQHXYŷ"RtžO.%yHSLtiv*f?ju:֣lz(~wVwCRZاюk^X7l hc 5yon|gG|q.[XǷd3;x/UW||ڝAwuv9}]o1Dk'x(OܙE- =7{o|^7=vX~WoeuS{W{>m^gA^u `@0b^آ! $<hniRޖ<;sK2!1XR E oEC0:DaWXqP!Xŏ%S<`D ;1LA DClcF&H ,6GQ' /AWT CH-OdBNbR̤S,06%L0IC2S)^^5wZ报+g\bB$C1EX)nLxS]8ʺi\bP Jfm9NNs|;I{p"X"vJp<#M²ԢBYM(T<8HRxD/+ڐ`r ]'3Ԙ-gQ Θ3]hJi U}h6_*9!9XΉbt5 ƆZT6I*G/̓:$VRՏ~IúJFUn]QZ*6f=^ӵVg iS~fJtVh(XՊUXWIy󱈭G;ɢuXmn};W2e-lG t*unj|6uɅ.5e[:nO+-KoKĕejwOE-iakZ3*vH-EߛY .0꭬WϛNʚ^v +7UΞP#j_]pZUʕu1[k7$ggi?NWwd 1Kc49HݱokO.0s]cίqA<_@Mt=hBЇFthF7яt%=iJWҗt5iNwӟuE=jRԧFuUjVկue=kZַuuk^׿v=lbFvlf7φv=mjWvmnww=nrFwսnvw=ozwo~x>pGxp7 7>>C<4xlq`%Q#x\8gL^2 a?TPr.K= 4AQR:1((sA @-K^.7 UF!|%G8a@1\Mxb(`!a0"e蚙J%-h ,4Q-l(&[6YdWE 0tqV?I C =To7|k_8"51wBiTn#tQ ^OC?(Z s=ؾ wBIJ˳ ?p=Y_+> c8ңXl0>c,xc0jxf@+ L1l\P; K=P_؆`?(Aȼl+ `k*+C (PC ,0=g`ȾB@¥`gpBB0d ,+h34>ET7Nܻ+OL_\f4 dD eBCCtlh< i l,! ,1 H*\ȰÇ#JHŋ3jdGBHɓ(S\ɲ˗0cʜyNJ"Gɳϟ@ JhM@gӧPJJjCIq.ʵׯ`ÊUiαhӪ]˶-۲ZϺKݻxK¥i޿  IBL"F:򑐌$'IJZl6^&ɝt  AY#[`/A,eJ؄R&9p$耒x(x PI f¤#KVt04lQ&JN}D8C#͞؃ a?Tx3,IB 0`K7iA 9+"n!yձL;{b@II3hLJ dx.[t#~E"!` %5 IBL"F:򑐌$'IId%-$.LckcnqdY(}X'\KGL9JXVqCp?$-te(5"?LKd3y)Yq$V0gL#&G IBL"F:򑐌$'IJZ`Yi?6e->P$ %P"dIGEJ&d8x[a2}IuD)14)[0-L-iH\K Δ`\ !cs-V<ß֒Ml&+(8a9za`.l, 7 !Q$tAa2zD 1cVPt% OD; Ѭس"\ȐK-JTiJB VK ħ*&'pSG|AęJ6p0ѓX+7=Aσ57ma9r hjQ C" c-IDB1>Y*h%F8X<-o; pt mWUҁj<-`d5r#)UKu;.,h/`10QNW%XhzwD8.[:#,Ar` :j0fdH@)yMJ$+.jPڰ0Ɛ:1 g@/\]ܔLn{;L㔸t:)Pa㚸'\E23d`) /%|'ɿrS,eP.дl.4H@! ,1 H*\ȰÇ#JHŋ3jhǏɱɓ(S\ɲ˗0cʜIG!Gɳϟ@ JQ7qVԹӧPJJUIyׯ`ÊK4VdӪ]˶[f2}Kݻx^K)? L+߉~ +^̸㔇%&~L˔#GϠj9ӨSװcڡٸs] ܛȓ+[|УK\سkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZ_Za H ɵlpT'}<x(O`dW(E0 EP,@D ^%dMbff(4鏕$&>QM!( a`B#H8YNd3=gӴf0gBd@LN\$e')}Gʶ$%Acţ,FDp Z 3)hFTpmLeCQh *HN"ҖxA^q $[T}4#VZ!D?P<6EaӁaC QUծP'$i ; aו&`?ևf,酵z(,U@XD\"٪&-BЁjm&ʑോU/2 0YJXv"+J8%UZ\?9&7*v暶pA!@sr|IZ!$ޓ`碌:>Vj饘f馜v駠.zϨjꩡQꪰړ*뭸T뮹 jvYiѮZD$p@ :*m{VV$@ @X@ӦY]mQ@0`ےnt /Ejy;p 0yR4@@ K@H $WQl^Pp4_@ S$< !Xl5'}\' 2ϣZd!X P-Jw[:;u9@C5x6s†9ow|-xnxx`7]QG.p`.PP'/N7E.na~9 qDK$됣ΖˎzuEnZg{Amf zAn #@ \R' S,Q =ᐑkJ:D4E?Ls4h=,3mس仉x;"( R~{ V2.x(1}qEPX} 1 A O%C5 P8-V;y?#c z` ]208U;DB(‰`VĖ4%!t`9`*rq #2 De\Oƒyr#)->Σ4`-# AD 0*`QUW)V@H":F=P(>D"'3I@?TRđqvi^Θ̪8Sv`AjR嚨fDeқR'Ÿ'phws;{SM?!{agc jO:g} CP*1ugE-vf0 E QT#-LIyRy0+MKKĴ.3uiGzӜtOYSt1CfQsԤzs|iS սHu^2j5/\j ~dY:el}N1*Ըu$]ۊWurj? p-*pc+Ⱦee݂mmgZv]+ZNTx-leֶloK[趶oK\7EmEZvݭr+.vK]fW .skIJ5Mv vK_v%y^wo `748@ X;`#`N:ꆢ5jX1KP8 |8|ݯX?ao 0;la0P? F]Pc!{Ar fߖdRA`P^L`RƱG/b&-^xD’! m 7g=.5=0{z-ɡ(Je:'1iPzӀuM2jnL57LұJf5 @yʩ9 ` -v{ݵ=gн(EIJ*r,TX(ݽn[ך.qX: A̪$vB><ooks/GK?0h[40g[26)yHIes%y+N4\q:INU"oeU;lNץ2\Z&Kg{S}n;A>wwRٰGx[Px32R Zt@S?zV=Y -0}!Lg﫿<x1t1'^}_v o'>%bl5)Bv~{]Hax?wu}P|"A@oЀC7u|7|}1h"HxV(ydp g`b4h,]ַ~<(v>MтjvCXuEX}xՄGPhT,([ogQSf8]g.vln(HX ^ exqXsHu8~zoh^0&G{'tȁA8c ||b  ~◊牂A ~84 xlhhF #fԨɈ*1 ?9xX㨄ȃH(Xhz؏9Yy ِ9Yyّ "9$Y&y(*,ْ.0294Y6y8:<ٓ>@B9DYFy40 0 aiH:P >aALrw1{L\) 1Ͷ|w\ 0q߼,Sq/QϋBP,¬-\  &L륏W'Q=?ѓ;}Z T<P,Ϳz+M=<.1 \).ƫEi]n:mƾ&[p̫\-y /|&bse1[rє%|}}μ͢}٩/?!RAyi=? .zM-q)q|-mmh =-YPJV}ޙ =="M=l43ߪ}0]3ʝ*m2ڵz֌%AᴪA3Am .02΃]=ZQ2qŭvk@nEor=0K B}~ɋ@?X<'d*}!痽^t~P'N.覝k~n.M~n^Γ]~n>^Qq *>,]~n>mf.~noq.!QA311`^Y$ f{ү n&^~ ?(.^\ Q a*=W;v&%kNk3?_0W[.Q= lۮ$GˊiT.|\$^R1MV^b<B?{yOie4l'\/ao{NN a_wy{}> <-*a nB!b!A aW #> am1žuXV?F1L_|.ڞ_A.u")`A_/P֏ O@ DPB >QBqƃ H+^@ɑA)dȕ,7iSN=}TP,v(]hR5l*P Xe͞EVTU bdnٹuVʸWڽXbƍC40`LL._df-֜Zj֭b !/,v vͰa–=ڷy'&y[l(s%OHy᩵[ǎ;w7!QtI<$'ːK/+x)%nJق=†BPAРl.PÃ80F$DOLClIg})xbEe,cTQ5o쑠yo%0:#Bl(,$ r \JNB|P/G Uc3.4-*nOr>Kl" OQ L] L-ų@,@ӄ> uQ THTYgD.pUN: }ҁ ͫ4\0O~ӟh@:PԠEhBP6ԡhD%:QVԢhF5QvԣiHE:RԤ'EiJURԥ/iLe:SԦ7iNuSԧ?jP:TըGEjRT6թOjT:UVժWjVUvի_kX:VլgEkZպVխoX1W@+]M;կv+&.1s-,OkDs}Ml% "pe+bv4[ǍV{-iѴ$kg8L֑me‰얚" E&\n&Μ%}g%$~&U&y)^V%Ao2;w% ~9HGX{K7.DD", !a`VX X.$^k b!,Y3v# B`T\ǹM#"c(gsH̐(;dʩ r~,"_xckH{e9ɇ-eWy#nFd~dvgycF@drftf|gHΟs+6W:-QhVE4G@Mh"_<鉰z)f#!b:z[̪=]h/[49aú̇>s-j# y\Vt<4[֪6mef6}@nqgvG۰vCx-[}j|sD~xB- qC]qRh/uݏ7ANTv˯]m|!w:B'nFցSVw{to;}8K;NȯyC^Q. {hQO>]hg ;zk(2xlw^GxufcL7g?qcw/F̿Brl~-7o{K/;#y>cd=<{=[@{ s+?`@8@ڛ=SA@j; ^ l =;ÛA(Ap?{Au[B82j³BK+),5Dۮ1ls@#D3C{B(SCأ=$>0'A<-$ +CCT -K3GtLA<\@$$6Ğ;BD |BDCAR=dE?Dd SdVL,ZECE\E:DEl@P:^4OdAK?@A%B5CEDUEeFuGHIJKLMNOPQ%R5SETUUeVuWXPEHY͘Ze[ՋՄ`V( ^( D YabA h:UkacX(cֱV}s (Pp}w֑c`}A:eM x c`Abqy Vo8-fhlX NɀZv+ +0[,XZ{ [(\XqepTX0wXx]`ٯ?k5u@a0X%moxh]Yyֲt~']h%ZC`Cf_5Z@[.pY [pЇ`5wXV}NqjW#*05œjy aY] p[}5ݫ@ݱ0W^f0p١ȁa]% xC 5^UޛE 3_,?2E 5P[_5uޱ5`+٥Pߥ ]Hᢸ>m&Pebb s ! ,1 H*\ȰÇ#JHŋ3jHǏɱɓ(S\ɲ˗0cʜIGGɳϟ@ Jх7=ӧPJJՁI,yׯ`ÊK4֝dӪ]˶ۯfs2}Kݻx^KiS L+߉~ +^̸㔇%&~L˔#GϠj9ӨSװcڡٸs] ܛȓ+[|УK\سkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZ]Zq?6ILe$LI2(n` NV2 ,!JNd ]Vr>  `%L -bc0rwg.=t*AX D&L*bd@,, 7Œ]l3` wCHlXtcU  g1c.mT66 9f \-sKqTF Vn"--!w"0)M"Pȯ@@ 3F̷$M<%MD$Oa-KZnpg IBL"F:򑐌$'IJZgȤ?MV=B2G'/QJ@k @TfR /@^KAV/Yd,aeMtPӕ1@hpKhB|`` ck.@?Ab%3 gD0!B2zc'yЅ 'K, Z-[ٸA %j sÓ> Zn-0fK0?%Xw<>;GapEu,Cҗc5{g-p^Xp3&9U 4|DB=+nu@6d0d5*t ٸI Cd(BaCCF0 a~M|Ao 6xx&! ƴ1yI BMU&1!Xܢ nr[ tQ]*4Ɍܤ"+HpZ۰t.G2p Y l-+ 4/hta 8KuLl[K%ia1\!@g _,LDVeOuaЇb'! , 1 H*\ȰÇ#JHŋ3jQ -Iɓ(S\ɲ˗0cʜI#ȐIɳϟ@ Jт7?ӧPJJԤʵׯ`Ê5UαhӪ]˶-ز9Kݻx1¥ȴi޿ uľ+^̸qJ;Lɐ#J̹h3C Ө~H:װc_\۸sߦж[зȓ%иУeйسkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$ɆUyx`zavę*DK|Kj 5O͖D?q̹\nA ]`a&4 n p 0l+l"Εs%H?cH-HF/rd"I>;CGJΐԠ%fZ:0yDlֹN 9Cw'KZQ[0`)Guf^JCCh%<(H*V@!Ԗ IBL"F:򑐌$'Y>&|d]07M҅FyD023OEa?TFI0\"+b1[PYt 4HbӁwtIV7 .˙ &P\2v?f^X@Kɖj*G`Lڐ@[HI Z!h BA IH+`B+aZܹDZ:TK[AqS%;b j @=1G 0O;Qa+ |DPJ ZX*J C!J`,KՔ4@pd.%PAГ0btF,XTP"M;OoJ:P0i?Lvͫ.!'C0vas,O^`VGfeٴ -0vE;~WV%%7f`[z P[ҤEnZBዣƢͬu7r uc5INwܾ&y$ncҷ->'ނ&z7Ƃ%5EBkJ3 f⯠x&,fZrh ! ,1 H*\ȰÇ#JHŋ3jȱ" 鐟ɓNȲ˗0cʜI͛8spG>4r(ϣH*]ʴӧPn HFʵׯ`ÊK"U$j-۷pʝKWٳ%˷߿ Fx7h޶k+^̸1 _=21˘3kXrZk-sM;=LT4װc˞M8(^zͻoǪȓw ^УKNp+kν{C븝NA~/ WH|(h& 6FdhQEf!CY Oyx( ,^e0h`&(8Gc޵($@ivCxLcU6)唴AYH@Q\v`)dI&P%pƙ'ii#| ,BLp,:ܰD)?p@2hp.@!,7(Fz榼:xA,: 'ph Æ*? jp9O hA 7 !c <˻bc `&jx0 hʆXDĥ'pF.2k!*+)4H Pl#$;HQڛ{tl D0i XJ0d@e?v謁@Ts2:ra]0˷h7 !-sW=Z9.t砇3oX.^ꬋ銫.흏Nz;9^; ?ERNN"3x"Ϻ[p?Sg3TCKӽ{[i~RK1̰^ 豀f규]B( PCP?>=yMZ4C6`"a^@{)TaMX  7V@ȡKHp MؐG_ #dt9*Z;AwB%`P!1-;q99„Ijd:ϐsAd(]aR.'-O%e /iʷrql +7VR"[2"._!0iYc:!lG|!&(3A>S@Xně|8r ` )$Zәl s$e$~@~6e#X HY4@B`ýӟ e@€X'!fGИ4<0.m(<}j˙.e$B-gF8”tR?B8bQl Ӽ4H/,dLs:KgYǣ/E26@ ihCNȧ qKZq[F][Ȧa@Lt"ьo(G֌Oy}rP7VNw1 c,x)Ƨ(ADԪ+?xCmnȴh az#I?G.&'nt꤮$[Ȋ$?븀Zd/N+m9"sחښq18Ѯp@F`DEFxIHKXG(?O؄HTUȄBKWV؅LS\bXPXkHn8phq؆sRHrz؇yxvJȆh|cZ4u~(> " h'x؉؈cG XܲȋHA ̀'؋̨B04 5ɸ&͸aDHD3ҍH^Dp4H&ȊX#wP <Q@pҏ xY$i>&-+@B9DYFyHJLٔNPR9TYVyXZ\ٕ^`b9dYfyhjlٖnpr9tYvyxz|ٗ~k0 0 QU9P Q> 9P YH8P S6Ix9Yy`5`.S 0==0 )ٛ1$$0)vvə!i !@@XԚ aIY$( q zQѠy&8 !`g 1]. C:JiقPꘐٟ%y9XJLQEKD*.mnZYqy6-Z,riAbE2r'!%.ᩘjYp02کpqUAP*jZ!.ѨJ1z RA !*ުJz蚮꺮:YM 21ɬ!j{ZҞ+.izʩ< Z4A(ۯ: *<2ڰɱ/:1ZA t7!q = GKC[1UR:A~:#`ڥVk]+AQ;0fZ hŧy!Y+:!2x~kX@ Qqj0!";86Ḧ벧ݺA;D;J 10[˹Yn۸ۺa[țʻ̛z5{G;cA;[4keA걑yO˾hA9򋾳$ z*+sῒk۽\FBɿa[|;a8+I[/Ѵ(",%X˚ /L1ۼI0:L7-m 18Q+H$v|> RĊa43q?a]3aƨq1,m\o蚺N1dqjK,ʭ++1L8ʢ<ʤ\]ɽһ q lKQl̹,7..<[-qݒ]nn3!-A,aom.-!,ApaM]e1a-,oL!J!Aa𼮚|)>O7>N!O#oGA^C;О~>巜a*eg:ǞGIm^VX|7aE?m6Aj)6ʮjoD/o_lXI8T_ڎy? 'd*B"-4m8!BW Otz` REKNG|/rqCd2.)0).r(l2L13R08S l0Ѫ3\NGOFi(ԓ06n$t. 82D}4Mx)%nJC"TTUSSuid}XK%qMuLa͖tǑR|Xde6!g]V覅Z%-lѵ"TO۴S#ҭTv= RZ^|!WPXۄ.X O5<8+Ίb.>7,P$%YbR&L嬞k=j&fn9<"6h;y+xR0*Zmh:kFukPPLZkފk+RxׂiO~ӟh@:PԠEhBP6ԡhD%:QVԢhF5QvԣiHE:RԤ'EiJURԥ/iLe:SԦ7iNuSԧ?jP:TըGEjRT6թOjT:UVժWjVUvի_kX:VլgEkZպVխok\:Wծwk^Wկl`;XְElbX6ֱld%;YVֲlf5YvֳmhE;ZҖִEmjUZֵֶmle;[ֶmnu[npY157}qK;4׹v@n8Qí&L[]]ӅnvC yoJk^yw>.3^ɭw>7^̗}u_C`nv܁*Ny0A;J*r; vqUR]%Vɸ-I[;6wFƠ=H%-dPpNncqeh9fޗqfy=h>%wpnVe{9}<461bh'D?1`7!vytFe/g ӆwmqۻ"&1op$ƴ} |ù[(szORUudvGfţΕULܚ;;yoMp$;/}^%C|(s}P'\w&ݎAuX6ŎE7z#Q3wzFޗ77VAs]CWyӞc6MOO{c2k-ySvu~v'[}wYޢ_:ΫNr ė;+ox}aTiX6;~oʫ;?=;; {? |;[,:H?σ;[>=s@ cS1><+9:8S?sAd?@$D.#A(?  ;p? dyt5'|>ĉt>3AA@c+33>;ˆ…BK@!|3L65<5B(ABF=GT+=|>?=N 0,DH\4:\BKL>38|9D7C0E+ D$DD^#TĪPB؃I\Ce&T @5FFAoD`Z@(A-lDMLJEih,=XE`G G+|CaEtG G|sttEGNJƁ?b?}TzExECzǎGĉGKDI|Dȅ @tHPH. .ɜș;uLjlɢW$ɤC|ƓȡȐLIFFVǁH\mIɰ|`,Is4K.KHWlʥG;Jyl˻,:JʀLHDK*K\.d ŵJ=QAQQ]5$O6tTbΑC$eRD'JҼ&M2- =-ՠT T,MՋ Se5J#uN]UC_N)R*S8Hhd~I$ X! ,L! , 1 H*\ȰÇ#JHŋ3jȱ? CZGǓ(S\ɲ˗0cʜIÐ"+4iϟ@ JQ8AӧPJJjդʵׯ`ÊuU+ϱhӪ]˶ز:Kݻx5¥ȴi޿ uľ+^̸J;Lʐ#J̹j3C Ө~H:װcg\۸sжsзȓ%иУeйسkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'9=%'Z0 8MF)@O81OB!CTn ^pDYi\bJr&?СDAl/OLPG,I`%K +43%"// KS =$heV,#T')nFJ1 C HgJz9x΄/Q?0*P=Q"[BX5=[l5;7E IBIc-|O t:&L*%K [t +A=WI O3eK!ct6 ;AVZ`u-!ZKք ilyg]I+jr FC_- t^J$-A?T:Uv3`M;Vճ2q?B胠Pa),d*ija؎#( q YWx] \\<;+dbYLrNMym_CTFbe۔t4ިLС`(-(W @p  ,uTanL6 D UQaԗ-/v >؆bQV$+0&-L|E4!=1;̀@nKj@$GUKanLzѯkWDM^Kj=sW\! ,1 H*\ȰÇ#JHŋ3jȱ#C CZGǓ(S\ɲ˗0cʜIĐ"+4iϟ@ JQ8AӧPJJՁI,yׯ`ÊK4VdӪ]˶ۯfu2}Kݻx^KiS L+߉~ +^̸㔇%&~L˔#GϠj9ӨSװcڡٸs] ܛȓ+[|УK\سkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZXp Nɶlrpd'kXZNwr-  AZHR)Ja%Bx :)\䕿TJM!sd2I !hcTI%PLA4ɜd@GA*.s9O@$HBX [$6d%4Ѕ@` C;-9Eڑ*%9Тm*Wbw%|.F*[t$~BMӢtc1B+/;BTـD(I Z*J C!J`,Rt"PiCTUUlA*[4%+frj29ˑaC]K5 YJQ]*ʌ#Jci `ES0c&0Y,$.h@ڮ 0DK`+ە`gta 8*Hp2\,5PG?pDeI(|kJD@6/`*v-I&鳖}fЄS)U2,..⪰& VcXIz<d ! ,1 H*\ȰÇ#JHŋ3jȱD CZGǓ(S\ɲ˗0cʜIĐ"+4iϟ@ JQ8AӧPJJՁI,yׯ`ÊK4VdӪ]˶ۯfu2}Kݻx^KiS L+߉~ +^̸㔇%&~L˔#GϠj9ӨSװcڡٸs] ܛȓ+[|УK\سkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZa2Mj*G^R%8& a?T@J'I*糀^H JXqCx?-miJjDa cdJY"?L`.ɀYƈ A˷,?xƆAч@Y6蠟J f Ό %V2mx-h >aBqxb5x@lJtI?: $V ta͓%~|aBPK10 N|b%7aRU1# $bk6U%  ^+Tc njl<"@T9Jtd3!lG`,]Wf1bq#PATY:t6LmGZ ZCGAZ͘VM{ cabЮSYQqrļ*)kܽBW6 C*x0ч=Qh=Iq AFoK k B0k[rW+8CaY><$ ! ,1 H*\ȰÇ#JHŋ3jȱF CZGǓ(S\ɲ˗0cʜIM!EV,iϟ@ JѣH+9'PJJիX#.Дg֯`ÊKlح]{]˶۷p\ܻx˗%ڝN La):}zǐ#LS$@0p0;6gXDWK4K4!eO fmtk}1bS5fCTCj̶Yn8}PwJ`3 3TB8Y}-1,@t8e30entHgX??K]ǪXozB'˃<#AWon?-'W*~A@ ~Tm~lw$]V7} #x%|xEQ  .ؿ\HqA d-!H!"( p=hjmg',`!cMtGÇٰA9 @\WE j B6j{+#F(` Nģ;9拎 E F2|d?%#ٌ3)@Nuz3| iQ3QT``]:ϺVLh$B(cUKY$71E9(:uX kQj+2`2# mZl:aW,7s.Erei^ekVIx,og۪w.| ҡVkr+v]vw񊷼nz[M=U|;_֗=o~^׽ӅC_ؾ.07/+vp/aoػm-a N5l:Ї96do\P`(:bx*nq,d+%b'&8y v;D2d.KygJY$6@w?O:.t:*BkqMЈ.:5$+=Mh/9gWԁvlNv wL/HmoD{~x,-~_ww}Y`#eFOe􁹇Wճo=;O.Ћ;Ito?2]?ϞPԥ}{>=w?}++䗾?O?,C@A~$| 8~~w~d m`!߷| x'x~}+(| 0\0g8( B'2)H@hg|H|0 Ր :8%~WChBȅ[OQ,xhm`r@T`9Vƒ(X}d8FXC ~` t!v|]}-=a403X{臮P4 Ј@cI0Tu |w1 P``|ҋ򋓨8ab$|x"ۨ^뷎+Ҏ樏舎9Yy ِ9Yyّ "9$Y&y(*,ْ.0294Y6y8:<ٓ>@B9DY0 0lGUFy(P O%P WkY&P `\c"HLؖtYvyxz|ٗ~ u`f`\ 0==0 pX91$$0)vv)nəi !@+#!P-I aI?s`T5p쳜 qΩi I !y Io\li-q)1] C0 SSYC:JVVܙ [ٕ_9U^ Z Q_@ ,ʟ-zIeyiqhyyY'2*iqzDBT-JjP:1WۉV+Ytؙa~b(-+-zUHAPҹar.ږiѤ qzJ*ѧJ@P0 N 0ڥ}꧊:Zz9Rzy::z{)}E Yi"úZꪃJ˪Zjy -aJ:٫6QւϺŚI1?*42!1y'q jyѯj@*#j 룾a"0 #kf٣J<J(35kq|>!y_ڭʥ$GAwx:n kJKsZzSU y<9۵TanJ-QJ {s{;[{)a Jۘ˱UB[pk.!mUƙQZPƊKYyE`HKcQk m;[P2k Pg˷c5;+(akޛ +{񾖋2 +;& 2{l /cH-o!.a-aB ܾ7-A‘٫M"+|bR{x+W{ l4:lceA|ϛ|k+k\[z{X<Q|`b<)K)[i,AgLOILw y ڠbj\^jp ڬ5ilJ*2,\'Aɒ̜K̶ /FQ)a!RA#lݫ{ 1 /0!N̄,͡LN,,1.Qތ 171I(τzƬL  M 4l1ѪDa4ÉkD<9<Ut1> oi+QI*/ے]|NC7|W,D=M0 NP՗doA6q>=Z]Wݒ9F|Q31+,Um0<%=s})ת+ 7qN ;8q]3!,|4l֚I/1T!1ADaT,XČ(] 1ՋA?R!@i̕!6SbQ*Ή]ԝ}̼lY};0}M=1CZz6 H^¸LUQQx621q 1!'l-mAA @!*5ߐr(1=mHL616F-ܨ=H;RJLY4l,! 3*)7(!H\ݑ|~]^jyxS^Ƌ ،=؇]ؼK%6a4B~|  ^N>ٍnݮAa'_,)!('aDQ'H E~m.-'ct-1Q !AGУ>A0a&I~'>-!oĊ"N~$&_}'>ʩ,K0@B?DrܜUV21 -?qsA_xNoNqi_fhϺJ_?o~~Y71^yYEE3oY1_z?N~ľ͹oOOo˯N?oo} ȴ)???.{b/o!DPB >QD-^ĘQF=~РT "dI\0ȃ-!r@ë́.8YpM'S\ITRM>UơS5eUH j5a TZW\u}Xu w#rm0P 6*_o ƜYfΝ=ZhҥMFZj֭][lڵmƝ[n޽}=fR ڀɟG~ҧBw\v G5{jjxmw_pVl޴ 2d(tR6 H80B+AG$JR|ʽü1NOlŖ9s0QGCG#K"'m.8 ˖b$ F&K?㥔x)e &l7㜳ǁSt<?,(KdQlIg})eХ RKtJSMAEHOMo[ 5eL3鄪WKl/\JNҦ_vՄXZ5c6YR Y=Vh\6{ ہ)q,mU '  >}z܆?7aՍ\:qi[L_7w6=lef8f&hF:ifi:jj.ۨ#=V ;Fmڶ]mty{`Ս@VJ'CD6(oj1MJe%+NJ݅X?ueXvT-<$Yw׶){eѐ<ԔoJiGٱoT{x%޷\hF |MlG_Q|cL[)wJZO~ӟh@:PԠEhBP6ԡhD%:QVԢhF5QvԣiHE:RԤ'EiJURԥ/iLe:SԦ7iNuSԧ?jP:TըGEjRT6թOjT:UVժWjVUvի_kX:VլgEFYVBcJi+[uC^j.rzVENdma knl,_K׺>$%0˽Dֲ_dY^=iIؚfvT ʊa lKkEݢj p&vX4 [2In#~Inl~VuFYVݵ+"5|]^=ҷs~S^ߪƾm/kZWh/zÛ7a&a4 [`i 6/1|7G ;hF-yb #ڌ35"2،@.D_#Sdi2]\(gDrCVY\Nr+/XZ62eTY.l \dqs\ <[d^Ȗ3VlE{\WDKT?.}L6tEhaN@ PԮkhJcDSs7=[3dו̯QQ:Ӧ+E=a{u_Z_$PuLo^Xh<Ǟ6O;Ͷnc >]o#61mo\ ͝V%Kp [ʆ ( m<Ζ8۽a[-bqzC}w -;toC,vx q 9>s3<߹]s|2/w!td"S>;I6ÍHv]v7}VϷqgk}~W4ܽltf/~ȉt.BsˀW5'^yS=ޘo8Ny7>N!\ou}ޒ}OH?#?v}~ӿ̿[84{;;k;4@+A>A@+Aƣ\ 3$HA͈tzB # c+=[AsB̯$\b2BT@<<@ C$0L3r? lDALôCCCD|C@G,DTDN@ c ăDDVE,DGl+Z|EՓEM4QJ$ʪTɌ|\IɧJ8ʓæJdː8˱ɜ,,D̴d̏8LJLȌʷDDMlM\J4NdMKwdǹIRE,KMǬ˼MMTLr ,,TtJKëlTOi̮ J|LMNeMKOaO OLOLSOBJ?SL%T7%M-4S, }SHmT9|$SI}0M\]^_`a%b5cEdUeefughijklmnopq%r5sEtUuevuwxW(B{y]z |W}M~mצ׸C(CX {5؂ 2X2Y _@ YP0Uٔ8XtxX|.!00M +/ hڧ,xHq{ 0ZZNk *0Xf C} qXTd ]he?ۆgw03 2إp`#X\R p% h{mZ0[Pu(8Y8ݖh_@{paxe7ۍfڅ]ilhܙ0Z0ε\5C-2oS Uڥ*0ߖ`apX[ވpp[`_pj0FX > n6? Ѕ_Pۏ`xЇa5R f^xȀ[Zpb9p Va(⁘H8bcpc^(Xl] F02"]*_7V[`cH]*8_; F. .ȅdDf)G\LFy"K^)M&QN,_EH X! ,1 H*\ȰÇ#JHŋ3jȱǁBȯɏ(S\ɲ˗0cʜIM"GV4yϟ@ Jѣ5s$ɓҧPJJUJ0yׯ`ÊK4֞dӪ]˶ۯfw6}Kݻx^KS L+߉~ +^̸㔇%&~L˔#GϠj9ӨSװcڡٸs] ܛȓ+[|УK\سkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZRUZYN IlpTIVBO S#%JFS҄ )TW''o.y[dG417 Y |/p Ԥ2kBd@L <V%H:W≖вL&K8ib{DQ?}s) ^ |%܈nA ]`a&̈ n p/1z Q@!AU"t0+8#UEF gt%p *ҏܢZidӊ8Zʦe$5xM1  [UcA*c0[YҊ܂Ur «D*Α +T@B:VDE\sx6+Ed!_,4&TS:սZ]% YV0Z, g};+[֘ҍ`eڔl4K@PxΖonbx@=a"P-dMLd4.[`PYR U ꊳ 9`8bk4R%3Vp(p@l0(i orO! ,1 H*\ȰÇ#JHŋ3jȱGBȯɏ(S\ɲ˗0cʜIM"GV4yϟ@ Jѣ5s$ɓҧPJJUJ0yׯ`ÊK4֞dӪ]˶ۯfw6}Kݻx^KS L+߉~ +^̸㔇%&~L˔#GϠj9ӨSװcڡٸs] ܛȓ+[|УK\سkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZRTZyKNIl2pl'kd  %v- B@ *3 <`%0J%Y9Gb)h H$vAyh\Lr&?{ $ܜI~c0"OЀ?fe..̄<o%tKB 0`KA Z^?bX^Q4&- ĤH[ EIr\%YDP]`s ;͈=Jm#؁7 8t%I?j D; UӄD*J Z(+F C!J`,@P)׉4R/p 4Gp wCSURةl7y@"L}U&\KH`Nd4NR C*y0 ˒5"8)YLUPpD 8nB 0Զ%#eI2("; 򶼉 3W W@&P 2`Q[xl /Vļe-ԡ$,%G Rm/ V-PDFpQbpmC '[T<%0D1(3ը! , 1 H*\ȰÇ#JHŋ3jȱdžBȯɏ(S\ɲ˗0cʜI&M#+ IBL"F:򑐌$'y %قIh- |`<%<)3ВqX\K( Ad 첗Tc, 4ܲ2-= 4x5d$$Ōa c/I[D0 g26YA4iЇpʖd I/cĄ@hn^)aD@3Sr$5G>[ dx 3+:cB`޸E ZRPmBc-|PX#] Fi}r1?VJT#-jJYdE2iJ`<@JQIM]&HNuLP@өmHY01?pT, EcVg4`I:߂]`3f^s"wCHjҮŵ)!Jtd2,F`,He[YZ IAQw0Vh\]mA`~ĕȽH tA`&Kc:S$@6Fދ@ZB, ^ԗ+zIxSH3≖LX" ^ - Gdla.], ٶ')/bxp犽87.n=G@p+#CysS<! , 1 H*\ȰÇ#JHŋ3jȱGBȯɏ(S\ɲ˗0cʜI&M#+ IBL"F:򑐌$',ILjro'{<"RJ' 0*Pe(|!-6Xb"(?~ɒVzęlyeMtP3A qp!>00@̵P͌rBN1ԲH>"M!=1uJPdBsD)`KOԸA l(G::~0EhNVcI=≕x!ZJr"m!yԑNbҗ5g"E24IOUbҞQ)_@1D&LU/QLgXš[H9cӆl" A c! ! G0a .6%"E t!,ۑb+jXgULh+c0"EE!<+aTIf<'~ qc tc9Bݣ")xG+ B[:@ʁ-v]΀F`!B`׬ .R\FcR:Aap 0"^ Bqj~ٔiq`lGƸqQll7A ! ,1 H*\ȰÇ#JHŋ3jȱǏrȇRr%ȗ0cʜI͛8sɳ'C'@ْˢ>*]ʴӧPJ:PhID[Jׯ`ÊKUU[۷pʝ,Ь+˷߿Ś+^̸1$ k=츲˘3|Rr^CMtOC=ҴװcVjʳs;qmkAN}c&g\xسkyrַOչ_Ͼ ӷvO_}(h& 6F(Vhfv ($h(,0(4h8<@)DiH&5>:ܰ!c M C\ȍ%  2W@u)g<( ef0#R.~9"Q'~7>A298M!I@@`(V:pL!*]p q*,c>DmI@fLK BŋD"H8)$Uɇ\)&I|)(#D"AЂHlK]Rq8EX(`Ld*LWXG%+tlJِS2e$ 1)tV+i8BYG9t0|39bΥFHr,@RPahF!HMT!MPC#-iN ώ~jԜ&&H|@Peu> $-*LT*zQPYRqԪX*sKKfRZ՚VխgOpCV+[z׻ʕ5]Wm+s+"gul\30lf*ټ*ֲR#̡h ᰇ7{,d9X~]8  -mg-}T1GJ/Րq[zϝUVc~qBcbs| عVS>&!" pG zr/s[:R:F J p0wI r'ۀ6*5x1 $۸blbTx˜1[c7/3衎MBũ&3xO6 'e/ydfl[Cx,I|_7Crf~3g;:FMBػg>3hāN4'M9?q"T@JX: hM99({ip$$ kԛe2.E_]lNcj$A.]]Nu%ɸ]nжqC]^ay $'wiKc[ G4ND`2 H$>XW|Ǹ5~@!8qn%7O~錫9L5:Unt#aJʋ[}"um]Cj!w @0 In#ܛ6 øy޹1#BDp<icfC<'= hG`PA2+IBuM¾B= VOO;ЏO[Ͼ{OOOϿ8X(|` ` sYu P [=rb a]  H>HL ؀"Hl.X6x8:<؃>`d% `+AE 0==0 I(BHF 1$$0R؂vva8\`!@@ .T!P;zSthx8r(-AaGxB;d#qH]@ᆡChfy AfF0ȀC12(!P1] C@Ci$h:XXr" x;ܘK(F&*()Qxiq iDyQ+؇(MiFpp`4#qUAP(-Y))؎ "9iQٍPA#!4"ySYN9jlٖnIUEq9M~lyYiP[Z :{kR5K3+Z{8Q[;ḝ K;QگMsʿgAzk˒h79Чj* <K~4{q .{q!A {2<4\65F˽ "|Y.Y!:<|,,KMO Q~a; A|g[5W =|k85}iŗzaSU<xܐk1!y17NȵʹFL!<2QɄ \kJʡk+ɜ\ dk͜lռ|޻ǥL㜪" 816al '͙" \ϱ| 9!lz+8q H m7,.G´#L< ;޷\/1aY }mM]+OS}l< =|a}u j={Q<̮`>)p~0oA*>^"t8~.>^ގ7>u~H/[0 ~OQ7Au8QjIa. cFno~+-1O{t1$QpQڇʤb8ړN߁o~ZX_L̩nbxGʣPXIo^'N_|N_>݋1ZO@ DP?^u+!^ĘQF 6|H%MDRJ-]t9*5"E=ҴSNEz3јK$ hT8 ʳU t uWe*'wj5ZCkrڶyQf +b Uݘ5 XX-`k9 ^NysgA^(3oYҾ[kئe\p#T 2x^ { /yt.'\x3m`'G9L~{O jî;(d@V@C?1DG$DOD1EWdE_1FgFo1Gw$-w4a˧$yJ+-[|{]/xq}_wo%c?D?b1T L %A9PX,MACq?\>P<0W G"Aѐ?0 `L)ryp=~%4bCj^ܒ˽EdENܻN;t x{C q?wMzmvﭳWO]7r>2ߙvV䬫]'Alw9Sჷ7i+ϻ]1{q{DGsʞoĞcWs9=,=ķ{}<`D~㛌X?W >j{<3㷻{L?v? ? |[;ӻ{>>4 96k=Cȹ={@CS@!h?D\@B#@?ÿCB@[l d8B./{4s?1B0tC3BBSdL8+(C>d C׫üAK;+6u> ޜ$T`$)ЅVZHPZЋ0F0<%_ Q@΋NN`g4 Q- wfpЇy DWO*0O@͘%#-@ѣPNP`P}C0OЇJqX 78S2pȁa؆ShwԞ ]PN0,pc[=I6&#Pgm fxQU2_0 HT(זxIFc-`yp^@ר4~u؁M5 <! ,L! , 1 H*\ȰÇ#JHŋ3jȱǏ iɓ S\ɲ˗0cʜIM#IV<ϟ@ Jѣ0s,ɓҧPJJբJ0yׯ`Ê3֞dӪ]˶۪fw6}KݻxJKS Lx*߉~ +^̸cJϚ|LˌKLϠj9ӨS װc˦ٸs] ܻȓ+[УK|سkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'9 %݂M͓ldctqdX\(3ĔY, {2&10TeA1/]Bʵy:a Y \BL 1dP|^$HV^X~ ȔI.cDP]!hDaD;Ζ%LJ f ׌ %V2mx-hI;aBqxb52R8U^j(JWg$9Y B+|DU)H6?0D]!mD#<0 "\$-H'J̃)KdLgDbiGIB1kJ@ -D@IK+TcKꑱuz0 PZU  ^;B`,R׿TU?"aXg?ٙГ IBL"F:򑐌$'IJZO?6Iu-DٖP"$fb- bx+C ǗzZbIqCѠ?$50cqp!>00@1M S-Ą  btZKt *Ù-ѥ ޲J,Ḛg+e<%H(9 PD %;ɢ&h IBL"F:򑐌$'IJZRNhNIlrp\'o<x(=`^RB T9˔*ד@%.Ғ$*4 M s&?СDA a^$H8yTg,I%K +$"3]Bi1ɦ@{ $@;Px%dI/sc%!< %KCgRriFDp Z 3(GTpmtDg#$2x00(HIâҡHNSrh"L7*dtJ-y@ս &- RP&jUHNsCw+KZQ[0hkEn]H3^!C8b+gKz~D) VԱu&G7A}Tp?dU,lJ* 0yJذ*#,d Y8W0[V0G5 tX!vLrANµe.OfDF0$+Y_"`d$TEKݕ@K (@X!0u}iarOg Pn{ĿkI??نÒVf?B]OD+8&-D¸&?桧0o;s$p;}jX3Ev\QĪbٰLV@50E0 ``AM! ,1 H*\ȰÇ#JHŋ3jȱǏ I"(C\ɲ˗0cʜI͛8Eiɜ@ JѣH"ɳϟJJJիXd O`ÊKY\<˶۷pMܻx˗%]OLrN ǐ#T,˘3k̐rD˜CMzgK^ͺ5ZjMmͻ s; 㳅7$璕3dx/ËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(pN"G[S4h S,%uUW3j@=}(G= %\RBfiݑHve/z%iQ@!`Z\MqTdavT@\2G'q)PA=a(F=dc9/oGT.2ʑ#MSA\Iu~OڑB @9aj,k0ikakFXp1TG <v;ZAe O=|SO9s-K+ ,p]%9C0B[QŊkMLT ?VKq1#2-2++P/Ì"ljFA(@!&d3͟@DB4"+ p<O4I0U;Z08V@E;=Hm3ws#lWxs$$S DtcHGD▬M!ƓS^M/ќCb8~d=|?+DrϾXNˢ{&.$M}F#` 27 %k;gx\;$ %@ZNvPHJ~*O&!>F$#8H@:kL__t K,@z|17jbTxGad$IJv9,C D< AuSXv",qAh5 DqK8/VW61qOn'b'f F;E/ZѕP;2'Gz} `ro( P g G3( ǂ'.Wm+؁6wPR4.8X!yp"'WqJ؂:hvZȅ]^_mbpeghnx|ir8tXvxxz|؇~8Xx؈8Xx؉8Xx؊8Xxq0 0 Z'P 'C]"P ɘ<($P N"ȋ8x蘎긎؎xk`  `x( 0==0g#X@@vvIѐ !@@`<_, *x&*Y$90Aypau qD(?Oَ")3Vyɑ3 aٕQbyP؋Ng9@,W1]0i C`q4xBiX[=I ј( e)Kz)I{yPטHyԚؘmdq)[əћôiI7I!,R̩&  E`Օ^)p-$qUAPH^IX1#Q9PA3 @y 0 q1jڡx2 9Z ڢ숕y!Y 9+9:AD/<A*YG9C9.XjR 96џ$;fhy29@}MsZAI*9qaYE:p %jJbJ3j`ѪzNyRy:扞- ,퉦r dqt:ZZ,! <zꩋگ+!1yjىjފ9+YK"J 2I8'Q3ɓإJz qSJZڳcaU 01ѱ3Q H J[ٍZvu ѧbk_akصCt;:gu~x3ѩ+kW*Wʷf1+w.1-ṱzn{UK2{\ƪ1C +AK |#癶 ZjF!(ʼȴ2 ;ԫ֫z- C䛼y;[{ְFI˗1a"k+ؽ0/Ha:zl/1k% G:LQ!ٿZʧaT<}_]Z 1 ZIN q팗i+`!QGa ČaV!AaZa7 E:8>^㇎QG1A2!$3D ,]N^(mIݣݽl>^#Ua329E!^*ΡQ} .J` "[ν؞eA !AnYqnC^l O*pLQJ?J怫厪A|lZ}Y!AaZA8\NzAO=?(CnnQV]__ﻖޓ.o<-ghTԮ۾CNnNƞe1toyfhN/!rO-'NROkaU!mzpa8 o`V!/?ܨbB1,a)c^ ^KaI_O@ DPA\u6|qF=*bAMDi$)Y0ȁ+[,3Lt[lX%BFNT*T¦GFeZ*ԜS~XRYEPKӾ=Kj `m݃kۖX`… Fx*Az*6WR倁 ,c!FZj֭66g9] Ö]0mōG| *V@\7 @Mf\͟G^zݿ_|ǟ_~0@$@DH'3n+ Cl9L0DG|-xt DX7]$FoH &g -@ 9 ӑGq2J 8/ 0J KʰJ$LQLD&$ MHȊNS =⳸!@U-4>9⥔x)E"@m/M;2ESLUW%}qRl/YkuB)uOqum/*Foe,cU0Hտ][GoP @ k;͝ ]x]stͫwym̷Fk`h{ ҬeaF[D([-<ob# bv9​xDwk4O8&?9fO o} țaڮ;s.Y+hF:ifi:jj:k$R KAZkNGO~k匛յ6 ;&{mFx'xG>ygy矇>z駧z>{{?|'|G?}g}߇?~秿~?`8@ЀD`@6Ё`%8A VЂ`5AvaE8BЄ'Da UBЅ/a e8CІ7auCЇ?b8D"шGDbD&6щOb8E*VъWbE.vы_c8F2ьgDcոF6эoc8G:bw#+@{\H!GC*nԣޤIG# YIi2%'Qrhl{<ϭVCRK>Όq(9KSfie҂^rŔ%ԆeAf-;=sd-JPtě5IM]Lҹs!{g|IMfk >O̳&zOrr~gD=>q<H3Pc4I΋:Ԣ(,Uir:*RirvzF-9*jV$Lb˥jPdjP ٩'URժl5Y!׃5*dꝛUݨ Q5i+] VMuqĶt`Sr~,`;ڍpcRY#ecWȖKa-"MqW*jm;ہ݈֫q[xpm#K[ެb%.Z۾wۊbWLG[684.m~ =^~_8![~㺲8>O$sfA\eX1K2o `$x6|Yu32J/8@z,ǘ} 5[=sf͐}07r+L/˗4G5>4v}H>uc;tu:MS ugs]Zbmj4{ZV #b.;;0u^Ȯ)}턈a jzȩ/}ni˷ţy_Jantʺ lZ>1p2[[ } p9ߺ..7pyaeD lGn/krp8Os_8on7ל>q;⪽wK.r.'w43Yuc{QOSVO_ja=cYx sG˽nW]N񝚛V)>-=rg*ğDnu yyCCz.;Rg5Gx}>ʡ~Gt><ǯ^WzAwW{ĵ~\zFЕQh1>qc^Jqǟw>z?v';샸v?0>?{;Vn/ѻ? ?kp뛼 +@>ddA:@ >r!IGIuIgLEGBV\H@DJ|ʊPIXĺ4Ĺį<.|óSTcJ A4,̇KӋ0Jˬʥap5}  PeL 7e? sAU pHE[.U :1 KNEU wġ]h9%ZW]C`C_o5ZS`ЅwP{R VxhV8ZmW,M y*0jEax0VjP|mѷx-WsMW]TUPfxWWxPGQ XfUpȁa\5Xhw0؊E Vo]0phT(Y¨uU MP1ZZuPZ_XXׇ Շ8]"[0ݏ8ہZ\(-P(8ȍHU5 ! ,1 H*\ȰÇ#JHŋ3jȱǏ I"(C\ɲ˗0cʜI͛I2%Ο@ JѣHUi'PJJիAhׯ`ÊK֦V>˪]˶۷St ݻx(ӧ{ LԾ^̸KT ˘KH9ϠC ӨSIհc˞=״svCܼ 7Cē+_nḄKչBԳkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZ]X?6Le4\(C G5Jr% bDY. V%8? Z @pn<0,zINڄ1@Y"/̠C ϝ) Qs,B0q ((3&X [% h!E \ ?}Q@!&KApHE8ЭQzw$V tAT%#aK_r lC-< "|%9Npb`%4abY' +m)U[@ \abj r[jl<ln],LDp# k;U~0"LͶ2>aFGH tA`"%I[Rە"(!/ Zi 'ꮄ-|=1@x+\7Йqʞ  /eb&B5a!w5V*`QrB,{ \x&-H@! ,1 H*\ȰÇ#JHŋ3jȱǏ #I"(C\ɲ˗0cʜI͛I2%Ο@ JѣHUi'PJJիAhׯ`ÊK֦V>˪]˶۷St ݻx(ӧ{ LԾ^̸KT ˘KH9ϠC ӨSIհc˞=״svCܼ 7Cē+_nḄKչBԳkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZ2gȤ?MV7B2G$Z”&d88%S2} uD!12[4ZJK^Ih@ 4Vjg*e\ !c-V<ÞTMP&+(8a/ɀ/BsԲ%T[V 4e2 ?a2zē7%Fc˅DxJ)?l%Xwt'PE0!,q? Z46#-LB,1;xb"1ɩJxI1$*K _Р01?M @=1G T4;=΃57mMC[0R P8lF`,U_?"]@"I</Pa a0gĢ7; p ]knarj<$`bCrhUKsG.+0/R10~ $ /mbޗ@.Iс$?r` :j]dH@)wWޘHӤpz܏0:1 ?@<LnyC\N1?iSap!ȎcR11ܰ"Y HG[9'Ϥ4H@! , 1 H*\ȰÇ#JHŋ3jȱǏ )I"(C\ɲ˗0cʜI͛I2%Ο@ JѣH=i'PJJի7hׯ`ÊKVV>˪]˶۷It ݻxe(ӧ{ L0Ҿ^̸KT ˘KH9ϠC_ ӨSIհc˞״sޝvCܼ 7Cē+_ḄKNչBԳkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'Yǭe'dY08M7qN2GXP9& PJTf)-azt{R7 .e2# 4e0?X+^a 9A`&GO,D5,J<3NGr܂)gym|I5OBEIѥ*AG2 H/rl"0Jt]cF 6˪]˶۷It ݻxe(ӧ{ L0Ҿ^̸KT ˘KH9ϠC_ ӨSIհc˞״sޝvCܼ 7Cē+_ḄKNչBԳkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'ƭ4g'}d[t7M6B ͓kLp2 a?TFCO@eXtYU$9lI0@l:䉕j%Y|)Ї=؅),1#le&H)jd74N!/.;cX`2P3&- z^1;xhUnс ,:!t4#)MҎ`x4`Q"ZDATl @?Y^f$hEO=mBS+bF'@ _ì`PRcV+.x&n#bJ;)[꣩fC@s"x? ҵTJp˶dԅ\~"P>p¤61+deFG BYaC4.QD -!iY"_1vru &&4d _W6utbl nڏK;*KD0 wW7F 3>ap%ɉ! ,1 H*\ȰÇ#JHŋ3jȱǏ C@俒&[˖"cʜI͛8sɳώ(I JF*]ʴӧPJ4((&5ʏׯ`ÊKYXS6ٷpʝKXhUnMj߿ ^l+^̸1 g=21˘3kXZl-sM;= |T4װc˞PU]]ͻoŶ"fУK|^ӳkauםwO C7Ͼ'/(h& 6F(Vhfv ($h(,0(4h8<@)DiH&LiU^MF)eAOڔX6y%QWfe[ޖ֗dmUB>&txՙs֩\V矀*蠄j衈&x6d .@JxZjjgz)*ae4H9H_pF4s @\R(4'^)SYsU}s R; >>x(\FK9ђTA97HHӪ+꜑(.fi Qϸ" Ѽ.`I}F9pn/nj T=>0<{C=0 's27=F: @d4SOQk:HSO$͔Cхjv+2]xXǼO*W=yO_\jSr%n#*褷>ꀻ.{ln;$=O!Q%)#} 77ܰA8_F |IOu79ca a:nNt&L!VJv. gH8ds:\YÔ0vk- Qs~"$'~mqU9Ypi"/p beƩjUB8q=\W;>~ IB`F$#="#%IHRT3HrrOt#(HVRO8@ X #`N=@#e]IR.x%npcb@h \p,@0 !3MI`pI!`ApZ.8|7 3? err\!i$GFt'-XN\(<+Cjҙ ( u -IFT6$/=YA@ЦhNI?Iam*Gu)L 4թ5*NӁIԮ`e Ra p`k|E[O{43 tA&6VE+`в4T+TrPA2ѳR # * P 5#qdVHBFBug YP-2\+]rHmap.,1R5|ߛb׾ͼ|?XߨW~/ x 4p~ SpKa$TЇ!I`O'%86,x C4b۸£ CD(^0njix=ɀ9~rldЂhrIT@DYKr ULa Hb.-GH2$:7 )e|7~MD1ȁ1m9yӜt/-hP߮Әn,jUyD5K(Y՞FTk>4iMl@>1=]"N!Cm =6~Ru VŪCn{5oRǴ],MvjUZ~@q\o#>Su82{ GN(OW0gN8Ϲw@ЇNHOҗ;PԧN[XϺַ{`ؙ[sHQǾ$^"(jv#>Q #DE) N v~}Ҋ'O[ϼ71X`$ $S?z0Oԁ|Gh* L؀|PdR1@e@ ޸_m7ugq|ɇW|8"xhGUW~!}1]z% C!$Dvp'wVe<ws|"xw|q{wD6H(K.qYFA/8`((GxQ7 Zh|'vr!Gh%~aWpHhtT`SPAUpshNJp{HhU|1F@P'7ȇhXɨ~E؍D'{7zAw(zx{aǎHAhyw}Ǐh~I}'X5(7;Aw<(xXa;t2mX41+,؅$q)3(='AOMɆ8)„IKwMŁ \(^Yai1;Qugi8xkȕ:!A2aIx2 '76ivHqȑ}6):;׊ϸG(qX@ħ})z q-sx2!Hi"Hyq6Yz>9^9zs)FI8I9Y s;񐼙c2~S*~r2 s#%z}{:*t ٩QȚʺ̪C8z⹨ A:sJJ76Qa5R77g aY9Az ۪s*8 JMʰBG[**と_=S !&:0(*#!L>A110FXDM;OW٦DXJKgQd<^K[{rDg 5W;l{u%۶#us R9!õ!yJD^#u8J~Hy-.2:,v]_CڊܿZڰaQ/~^5.TÝcqܖ&ARR=8dnpN 9L^Q`iaqӘ>_1fXeqeQ!^>[ .fᏩ~enաrQM,[ L Hh9n7n>I=u)ɤrQ*a,<tfhn7=#y._p~Hm~a:/Ra7l::<NNr5QD-^ĘQF=~RH%MDRJ-]SL5męSN=}TPEETRM>UTU^ŚUV]~VXe͞EVZmݾW\uśW^}X`… FXbƍ?Ydʕ-_ƜYfΝ=ZhҥMFZj֭][lڵmƝ[n޽}\pōG\r͝?]tխ_Ǟ]vݽ^x͟G^zݿ_|ǟ_~0@$@D0AdA0B 'B /0C 709V>F$BDCCGgEyqFCkQOlqz2e,R#k4" IY JL27,LD1ü\Q-H17#FڼQ18cTK*ьrHdf"a{fnhz6$Zdr!jڠZv_ 'J[%6ik鄪\Yooȵj;.pvqGiU oxY& 6|l!u!=to|w2\k]jS.~v3~<܍_=?hz_HXE;"sil|ۣoQ[~/h{t_L4}YtԱo DpFZ  &B&_+CoFCa,H ̷T:2S/ꈅﳢH&oEkCl(YIf4;vqtT\J$x%#ャyEZ8.P!! '$.|IH6~7ɒM:2a#1G4Jώ a@Y)`'+K2$d08J-$#* ˋ 0iI5NH0˟%$ -\f2Ny&r#wFxFqlH&Smh4XJYBcB*͈R U)3Q!J(Ot*̧38O4EcOvQA{꒕&CT"i)M_ZVSV=sT@#شRoN#\ǴT[)2ʵC}F}SN;Gh-~%6aq)@"L!H΍R [=7ٔ{8kRZf{iZ `#*,JmRAVc*[J.lHeY[5TA",piS:w#Mыb֟жܽ.c_ U5mg+kB3 _%m^f͘xs(mի܊{)z܇Зu%^^w 7n!['p<'utq8M^*i ظ01&<޲X(0V1!&f20wdYUŰo\_DH>| .y5bR`x'X|Z_n\ɼ5K|]d:پ#2M3SZQc ЀIO-zn.sl!OZͲ,gMۚN~5YmhEYUϻ4XΨWmJסŴJE']sC?VJ۽l4[٣&aoږ{}[.wpL_ IK%.ũ[g8 ~78#f9imZ6v78)ğ#i/~z63׶[;<8zm{|ݬyӹmq4掴c>;nҫNnO6+qv* ᕜh;fS͵~7w!$G{.G}Uzַ}e?{}u{~?|G~|7χ~?}W~}w?~Gտ~_ǿ?柞$?远SG 8 J@@(@K f8 hp_X @l`L tЇ$0$A qрcPBc¦/(;9 +X  q@P@C@*0/, \ f( L Cp3;C?oЇ2TC@;@ TӅ, "f?X O pxCH &Gy0W05Al s9lHg[ Zp=\`YXD@ EWuP`T C`XEGԉrKAY&6n[Cc SP0C[m aps@`$Ǣw?bLDƆ@ہRG0FȆD.HB F PdHH,ZŭȰwɠT Y*X <~<Ѕ  X ]0pkH'H`E`cUldL5y< ]mXI`,K[+\K04K@E~(S\ɲ˗0cʜI͛5KR%Ο@ JѣH9$y'PJJի96퉵ׯ`Ê s)>ɪ]˶۷G͢E ݻxU(ӽ L8V\ +^̸c}):}˘G89ϠC_,ӨSI:հc˞=俴s޽5׼ Cē+_ָC̣K^yCԳkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$vol%Il&n'E`<:Q$)XWD`?t2=:-K?I?i_S=ց5R̖ 1B}$K77Nx%۬e,=ir޵vl]U1@8,Tܙu36]$/)_"! nR$i+J_"aŸ*3J@! ,1 H*\ȰÇ#JHŋ3jȱǏ Cj@E~(S\ɲ˗0cʜI͛84Y1ʜ@ JѣH^IO~JJJիXe2g֯`ÊK˭]]˶۷p4ݻxݛp.ŧP LaLӢ≮ǐ+8˘3,ϠC9ѨS^4Ӭc˞M뇰k[m{ N+_qɛKNѫkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZRs;^&IpX@:Y@ #$uD.@t&ALR 6xGd.x.q@PKr&, p ),1#$ ! JYxS,*3ΐ!/.dI.D-Its؄ E s&4K zf4$p^"r-IE5 BЕt"!cT#m:a<◫hMTpf 6 Itъ~d۠0@0OF\MԤ+qitK3$<&K a0XF6q@ pDӯEHEҁj<-$9a/5K5<2WG\`e1G cxGm t80;w$K8В :%WD #elAB[o9/b($031 W5ɪQշF[vP}}I=I܂ü/PA?QT31X+6EB/5YA`<7A! ,1 H*\ȰÇ#JHŋ3jȱǏ C@E~(S\ɲ˗0cʜI͛84Y1ʜ@ JѣHZIO~JJJիXc2g֯`ÊKl˭]]˶۷p4ݻx݋p.ŧP LaLӢ≮ǐ)8˘3 ,ϠC9ѨS^ 4Ӭc˞Mۡ뇰k;m{ N+_qɛKNѫkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZ(Ȥ2Mj*G^“4%8YfC<)"r> ȥb^ĕ0RbB1G'B%dI4?bKU01d/p 1!@b!A&& atI`_ƈ #ϸlC 5$ =JX[@1Jf oܢ-gkh! A)H Q@I(Q#l `@\9K4*p#Ѕ,A"Rh& 8 vØG&Af'DpYp01?`ӎ,@E[Z>B] Rz X&:@d2ҁjiYXu%X2p̵#S nَu%xJ+_`G0Nc(4mOlY~ ̗i.hxv)al @.Xq ay=KJ}dy5 |cr\nľ!YbZl?1@a tY$%^j\+g*xj` H[D\# ! , 1 H*\ȰÇ#JHŋ3jȱǏ CIRɲ˗0cʜI͛8sF4yʕ: JѣH*ɳ$ʟJJիXJm O`ÊK٤\=˶۷pMܻx#]PLlN ǐ#T,˘3k|rD˜CMZgK^ͺ5ڦjSM햧ͻs; 㪅7$獕3do/ËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h("}pBD$p@A+樣@H$ @ @& ! LfY" ` P@ b`Sh!P9@4^pbXo@Bb"p`JHX !Hd2Zꪬ꫰*무FD­뮵¯ЫGk찬 ,l̪jՒ6=(r]E<ST%?DP&D`@( ͪ{lE'u5лJM$@<.RI&pK=@ҰüRD1I3WT4g,>p|=>sS(2 32v6=?|rF$C-Oc*?NN+iYRE =?kR ,Nlp.@:pwsUC[>g`B$#ĘοP.,b9{Nn<Q4:g8ʍ% ]p: R{n4+워;gM=p? ]sûf<%Ї k Aes-I8jk"CDHBf[taBX(Cl !sCR@ XNyHla* O$_35*Z"[ĠUV c@-nQt]LEF2όg1 WW#<# HB:bt@'r $| IɃ 2pc $$*IJ\2N*PH+] KB8e395%~O%EܠP+hN4$SfDA<9XN2T鰊($„1s,#p͒ y|tq<@HS]pLhJdžrӠQAX9XXΨ/L/73H(Б1$\gyvNߔ$5xJ2 ASЅN yk:d./ö`?أ-@w[۲_ Y1?]g^6p=8V!HZeLY4ijK=4o;c'\'mE[۾w[n_/ztȘz%޸|cw-JoN S}%Ⴁ``!b@9T@,b?~x!ޑ{Gȥxa$\<_,ep!$1(xn'+kYʙӼf(dm0 QTp<d; ?xM`9ȃ.HOYA)bY,4p0wCt{2 } c|k{?<7!?3ֆ}g?mJL#H>W+_7g}~_~ons??{$/Ə"D=¡`A k{g]~䧀}W0 'r+r} (g} hP1\ps9s~| H:s'xQՐuGtK7QJ}#"H~=x0QpuYu]ݱ7bh~x"vjvnDžuOHzW7@=%sew}'AxLJMȃ~!@@px' ̆h6v``wy16ȈLX>hĸ7¸~xȌxXѸ}fX8Xx蘎긎؎8Xx؏9Yy ِ9Yyّ "9$Y&َ` ` suL P [/ :b JY  79I*+ْB9QNYVyXZ\ٕ^g% `ґSS P!di/!(@{Mvvqٔ|w )&$TxIag>aPu<qIA!ᚻ}eY.yI9ɜɹI3]a)PɒٜѝR !@ APPEf2akZ yDCj٦q~* 1@P d0 0j 0.QT ڪ#IPYAJjɖj/1yI{5dJ~Zjٺګ)ɪ#YZ-aVzʥ6Y6a&AѺ5)%¤jI9 Aiza:;"J)K+!2KK"["8/>[@)ZG90j2+ KKQSoQ2aC%{#[ 5:e.f;k;" H*lJxXoz[x5H6q:Z+W[{]ʱmk 90;w;j0 n97+[!oˎꗗKz;׻銼O®|Jڻqɭٛɼ i3a:,̐kۼR1!LD!LL"ۻW1-A-;/ 1K3Q0J4>|qQ3a1LH<JóѴKi?<R#qUK_a\aTY,ƒAPt|Da0 "%k41(k,!hD,lec\ ẏF 8ʰ˲<ˠ1B; qzkj iˀ,̬ ̥ɺLϫˬ|[t r<3!<ܕ̶ѿB1<Dyɦ,llg٤T7IqMΛa  "QL#.m)]O  7-9ʹ%׬Dq2==M]OMԗY:4 6!BAgKeK-<Q;+,mm̀tU||Anm ʍ*}٘ٚx̓ζ[ˢmly".0-ۮz\a=Ο׷)KQm=9׽=mFq!1AJ Aݱ .][|(m-mm4M=9X> n;M^JnI ~Sq Qba !.AAaa4<^>.y\sjז-{z'I2f={)A ONq\~Mqnprpmq5Q?3Q{Mlv-\~ۿ},jn}Ƚ 1l Lؓ.V~8^#QKWaFގ}N)Z$=!!aA! 0}3 BYqEq;ӥ!r1"!!A abqY   on:~A._E NKm}VBQZ솭 l61椞fi̺)?FHJLnxNMO?Q/.OYWϕ>s\aaܒnDiY7aB_y9Xl_y~ˇ:o. a1 n! AH2 o A)|4?q2! Aoa AAF!QXNQ} ->c},@n=~g!zOp:(S]N@hPB >QD-^ĘQF=~RH&4`aB-+( @JLYI: ETRM>UTU^ŚUV]~VXe͞EVZmݾW\uśW/Sz`׀kTŠ"6Wdʕ' $"GgϚ6mYjul ZR\8ئi6*o٭GGh.<@rɽ565HdOt|!~54׏r3 s MDA п" 6T*.0Lo* 5>x)%nJ٢B QFmLЫgA qG!] |1F yI)˖tǑRtJ,,/ȆL,3$3L%3 1>R% lPDS,G]F&T0GN#k>BrOOK#ORGI,B7Qj=UQJ\{( '( X*']Y`Zk: Xˁ F @avW7^ӲUMj>4}\8Ո `Rߥnub/8c7c?9dG&dOF9e))2Ƹmif|w94W#\W/ti;Af. 6HxV~+Xᤨx7ؔf뎹E;) {ef.l^z3zJWjb 5X[ )OA]jEƯUҡ1wrG tksP=)Y'5@k\;uh >vޑ,Qwu^(SZ$pGKધ)n)#>6=~۽|5o%έF;P^j_rԍ& LF@V0^CPV?80$E0(. Є'Da UBЅ/a e8Cd`%ES-{SphC"eHB)j)G,bEPP4 QuRc8F2ьgDcոF6эoc8G:юwcG>яd 9HBҐDd"HF6ґd$%9IJVҒd&5INvғe(E9JRҔDe*UJVҕe,e9KZҖe.uK^җf09LbӘDf2Lf6әτf49MjVӚf6Mnvӛg89NrӜDg:չNvӝg<9OzӞg>O~ӟh@:PԠEhBP6ԡhD%:QVԢhF5QvԣiHE:RԤ'EiJURԥ/iLe:SԦ7iNuSԧcEP u!eB-ɎԤRO:ƨBup[*Qȑ^Ud]ݪ\TqR +EUv s+rֲJi=Y\#Rc}]JDi bKV/t^Ժ#^"nV~ hJYu-g'Z˒vc]TKٖ.-l]kXٞkWێWckpyKX>dt/&]V̵o[Vn[j+-d^V7׵ayv^`M|\n-.{*7^~#`x1,{Yֺ0Y _7-JV>]FN\+w-Ȇ"#pAnlR Dl<֎*0Sl 71T Ny#A^#2Dqk/gWc6r c7)S5eY"t jghyd ey{=23+z`n󙭢3"xvwPZ4%,i0!* Cǎ Fw#~_d!VuXt䣊Բ.5O$n6R2f6F|i^ȶ0;;ڷhj':͈rmk閶nW'9͔a{"A]osTFA2[rⅾEP"|)Lj,\cAD\[ lC\(5urlg<# WJ[H_;BmO83_5cLcB_y.,2l}+>}d;~A&@'+~s[/_vCIQ/r9{̓w6 W]۞Oܯv9]oԓ]+}Ns͛Y;=NzQoa[f+x6Pg7KO>oywW>I~$u=E3_Uo㿢h9C?:K@#3??@'?6{8=<$@,@;8k t[ <dk{< =5,B4[?;@ 4°KA>&L< \+ C0DRlAQ,RDGȱKl̟D>üLKJ Lɦ ɬJDH 8DƇ„\M,KƜT$JռK̤ʵMTȏtFͥ$IGJJHKL74_BLN+,NtʼLM $O> T\GyϢN|lHϛN| IBL"F:򑐌$'IJZfp OɶlRpuD!jdV"O @q\ɞ.@tJ%4 -ibHޔ=Kd7 FLM>&8a@͐4ekNz:J6gc$!#,0o`=9rfC#Yh=܂L8b5BҏL,bHc-|P4t,J T#'I3:їԩE he$x.1R_:g˖C dJrw㭴+Bַ YimyrI+jr FCj-T^k=~d-?fT43ORюH?f5cCSY >Evղ1F`ARH,x1Qw0VkRڙbEkԎFdeې4ިLQU(- ;(W @p z 3F$ Kw[cgwjR_׾؁.+Zcs3  qG" D<4f.ǒ neAMX&XyXҵ5Yh'W 6HY3.g6g@! ,1 H*\ȰÇ#JHŋ3jȱǏ CIRɲ˗0cʜI͛8[ IBL"F:򑐌$'IJZReNIpt&md (Z(2ʙA H̨ #[`/A0ҒUd+dI+g #(@tP/p  0N4% 2I(= <&1RH:Ͳ̜&̥K 6d%4Ѕ@` C8-9NEZL:T.},Fr\PiYԁas1?ĄaY*Ta⎅ 56%E+ l-C0x<o"o5Kԣ3̸ǐ+&8˘3 ϠCѨS^ Ӭc˞Mۡkk;톹{ No+_ɛKNsѫkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZrd`?6yLe,\(Jd x)S qdX$K)qX#(*3^]ir,8hn@fb$%ռ/Ɛ15I 'M.ɀ)_ƈ ,?xJ;A̠C (;]b`0PfL(1lhAK [2`P(t$ % :PL%,bPpT$G0// C؆Y:0yD(Kj:fKd!NqĪb)GIB6uYh!„Z :pз&xD> PF#[İ?[v#zk_ʚa duecS}d]lWn?Dَ~4:GWfx@=asby,L Uf3!l+:y yY\3 C*xձ>6aK*W3Ō vâݘxAp`XX K_" JP΅lJ˄ ! , 1 H*\ȰÇ#JHŋ3jȱǏ CIRɲ˗0cʜI͛8i̸ǐ9&8˘37ϠCѨS^}Ӭc˞Mkk͛톹{ No+_<ɛKNsѫkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZ̤&㓝T\(Q"Δf)MPG#nq%,YRd, B! a2} uD!14)[0MC$n1':i9.1+p D ~ 'gH *-y?ٖ`Kx"^(LnI\d IV@t$OD; ђZc[ȰK-D꒕Ť 2;xfƂ2HO )PGR[C"3͑hS$m:a<"qFBӏp&`F<V!} -`Z=-I( a`6#F0* ST y/hĞdY0b3b1Ҡ2>; ph mMn:\-:0,-ܯ<@5Ѕ/(10xb3A)Iсz$?rXuK~dH@j0FZ˻„+)hTKܗ0h#xz<``s)l $ Mb#潊a…\$<:V2dRn%˅N`:TiL~ˈ! ,1 H*\ȰÇ#JHŋ3jȱǏ Ciɓ\I˗0cʜI͛8s,ydʕ*w JѣH*]:ϊ@2JիXj5O[ÊKٳE~e۷p-jԹx˷/ǺKÈ(8ǐ#KXbɘ3k̹`列;MtC^ͺk~M c;y\+5[n;/gդWCBiSRcWv9!Nz)6(clp)gGG9y$|}zޟA j(U')p@ ,D@fCx(fc@t8i: xj Yz)Ci^ɜ(xh^+>?>;"l d;\ʺ gm PN-bmT2ne*M2 TZPJ \,~)L4>, A1dAZ*d1Ɖ%#0E0#@rn,v>ʡ1L+-5nQOmkU_iYoF-R5Dg S:3d=vEi;Tk tr8ބ[w߂ 7r'?T7 #&Y0p^1:n(q' 7` 7O(AAnzz-8 ; 8ny:|b:ÎD?!pó ~ .,!M 86 H 0 `}m":FP>6p R/~ABqpuD`^ -B0 pJ}ʡ3HBLXXO ,A3x/*%@?&n$_?0P2RLS#ؘJO4$"yCB.N[#)HfʒOuqT'!sPBi))JǨrEjt< .-Ky+k#Y"fQ7`3F<1[:q%3L,s(faMi0&IιEe% t~ ;AϾs'_~>X JAЃ6]#(~3$xB1ьrKH/v ECU щTw!Iҍ+eHT' `H 7Ѕԣ8EhTT(m0ZZHpcHc'.>p(`kAѺҵW- 31 &( +ZX(JZvKI/C 0(%&B9pcԂK+erٜV,Lwm dcaXÝ@j4iv}z*nX {68,P G-uk]bw,+WLa2bKr$Vh.);_ַoL"t)yQkr}0d`b֪E1~C] $xQˑ϶%vy8CO86+hH1O dXɚ4|[R)4[Y*˙--3%Ld2SEg|Bwр%MhGϖ҉f#gK_zӓu1mPx#̡h8"Eg$H5&d<հѬ9MP~03tm$81^=N30 .IFZ>&!" ҹ3n~)@ot$77)s0jh Wp[-@wao5_3衎T|-yoN<Ǧw3swnJJ:ˉrRԓpI`9Ի;hz>]YLh6-= so%.wRW, φ(]kH񘗻Em]Pnye>G-nx"xt>Dz{ }uW$Z A`$R>}/N!ZЂ[y/@B8DXFxHJL؄NPR8TX0 0 TV$P aG_X"P giH$P `s("X\ՇXx؈`G`{"SSX/ȉ>8${DU `YY` @8 A؋>(@@㋲%00~t"Aֈx0ţw alaFq%HH;8DiǸ! Hȋ#9\yG1 ICH]0)!9x&-IEcXwd<@Ifȇh k؆o8nH959Q9K=y]Yy.d`i2RwNFlGYvYw|>YNX"qyF/љqbقp0-p&qUjAPؗQ Hii oɃ !'ѐ|QِS9P0A'!9יY*`Yy9َȟJٞ/ƙ)J16ijS(:A %ʛ5Q0.aI4ѣ(19ќ&!;xz!ѥL<99h:g9gRBt:+M|*aniٗmz_ɕkQѨkir9n)fbZjY1y:t陽* h{S"ɠ9y5A y6Sj<Pj׊)Z﹨a虬Uʢɛʠzگ$T* Ga  k&ð.ѐG- 03!8:.!8n24;/=*x[BjcQ@ˏ̊Aˈ";{:O(]7k: jeڲqf+0)i[e۬qCajzz` l*oK8$0zz({!񹊋WUY[˹cb:Jk _(mԚ4:Ϛ#r˛S[;Q;Kk qKB!kʼ[{;8˻i&۸1F;;8Ȳ6۹ -]khL?2Q,H2»گK ,7{AC|ElqAJ<kk#A2}W\"<\,c<9QZ<hŢa`,1C0!!fzl?l=̭%0Q$1ȿqH3!A!DɼJM׻ǴiP¦i3~<; -/Y {yȜʼ̜ ` !6Q Ĝ,! ̐I̳ͨ2ּ< !۬K[,.,-<4lPHallZ!AɬIюY T'{LO|A/Q_l579}vk).`b< bJޙ}֍m@B.Q[ ,|؛<+Q4ZTHbޯ==ݛoN1aMڀ:ٶ}芾T4hwNu~\غU7:ݭm_\M#90q9qpaVN}} L<q"퐑 / h!A*H3p FW!Aa 1 !nA aD<|˾sޤ/ͮԞξXa[A->dg~ -n>_9߈y"zV)DPR?}rd3X/VAO?  7_~-kmCZ6>A _GKA1;_|1 o֎On8bh'6..oX_ԣ~{Q5>|¾JQX:̯OoN/O__F(~/{5*e cʋZ!8?A@hPB >T`DFLh`FMDRJ-]SL5męSN=}TPEETRM>UTU^ŚUV]~VXe͞E2zLI I&Lрvwߡr̛Xb//#OnpXcH`8l3ZYj֋loc&XzsYdQurvЀ}Pp:Fᦁ8P{tG}~rH XwO`k9oヤϿJϼ8>$>1Z0!4k⥔x)e  $+K<19RDEo|іtǑRZl0,yHp\hE<i/:n>$S¥xdFj,+14/ RL3s*,so.#q7WBp&PRQ#r I9SOe<.0 8 ݔɀ 0QK=.BOoռP|VOAqBm\Ev:mR w"uB5Ym[o7\q%\sE7]ue]wW#4; ,Χy17`=5}Q Ta'8by@ٝ36hG&dOF9eWfe_9fgfo9gwg:h&hF:ifi:jj:kk;l&lF;mfm߆;n离n;oox'xG>ygy矇>z駧z>{{?|'|G?}g}߇?~秿~?`8@ЀD`@6Ё`%8A V!`Yh0T1B' e" lC2\ MXá08, EF!.\EܕY|C-$C`ETqE#QLC'態I801植zccXş͑eq!hE=v11vD Uǚ\4A 2yd"F'K2M=Td#Ir['=h,+IYґ##q w2%D0-rIerd"]AiNjVYGcڒI6=%άlg&5EiMu\ :y&OTs)0 Rx#$5IBR%5LQrԛ(DZQ2) mKTe%E%QYDjCz¡KUt#9-hGQuImLꐪBdB[늒~F ј V+`OBօlՄ]SX״t'+C. Yՠk4XŶıvlJЪ.aEEՆtWggYv#=1>g}-CkV [ٝuo5i]ֲ} n ^֨m)yM^u,k[0ՉuQ(^'{ݦ5z{+jUJB㔽X.k+[vê0|`yB׮`#g qq{GLce5qv3l$fn"[X%0t㕢9nSt[,# @fL_-nsӼ'Gީ;hb*gr9u1yh'G^lf/9İsS|c韰v-%S48'zέ4!]8Oǝ5쒒z3SL[dcPvu$⹵no g˙u=`O٘7\t]7jhZWғ}om93u=l817eCh&U{9qf:lu)7\āG3;Ek[N5_r1<0?7ҥR$'z9.T!6~衋P9ɋel;N=7oq^;|2:O3yjKtHܻ\h# 3|E|gkjJ/v;;=+W|4.1Rpun{]=jU?y/<\>KAORw?,7nϵ/<#H?{+."$&:|BԾs92 BSCA1ABA@ßk):%BY@*DI:C[GABE-B4 IBL"F:򑐌$'IJZ̤&7Nz (GIRg]i O:JsNOj֠XbiW΄ !C@ #'cR,L,g }Iс<3;LA0CH ©< L=b F Mܤ)4? PHї3#iC6^B]l'-h!fEՋBbXIK#(H.ztS~Ԗ"$1;x]>@3-:`?pdA tA`6xJZpt#q+tLV# -Z5#`!x$E0$k =,E]|S #D;`m= \zw(T G^GsjRT0f+2dgF\qN<%S ,cD`W}@a=%l;nB @h$ GLIaUCg1  ?T oE$ W$ =y#߶$pk<,]5$P:D\81J*Ɉ´ I΄HB%@vs EI6^6FQ٢L'LK@! , 1 H*\ȰÇ#JHŋ3RDZ㿎Ar(Rɓ(S\ɲ%A0c)&̙6]ɳϟ@wGdѐ%*]ʴSpҔZ3ӫXjsё^rKlVToEk۷p-9hܻx>\T \Q+&T#KܕI)k첱ھV9Maa=^z/ǯeM{ik9j͝[Ϳ_μ)#K<س|ٮm y >xDz˟7t3fjh Jځ 7 ~5(E Մ`}vQy("g"6 ,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZ̤&7Nz (GIRL*WV򕰌,gIZ̥.w^ 0IbL2f:Ќ4IjZ̦6nz 8IrL:v\j CD$V)P1'GXtS1 C GWJЦ-Ҽ\LU+PB `޸E vUB5L` <`P/*ƨKQT K ZU',"%G0 }ldr pת:  ku"'< oMQJBi c:QI ږ'>ׂd"F ݖb\ߌX-*5`:%GYfC 1]"ʎ+r.6CH(l"X!0+2^;S`zU"fxT -Ʊ6S8p`|3"-`"%^dh DEΠ@IJ5/ > 2o1d! ,1 H*\ȰÇ#JHŋ3bE~ CjIɓ(S\ɲ˗0cʄcŐ"gɳϟ@ JteMq+ʴӧPJJQIqVʵׯ`~5سhӪ]˶-A7KݻxM¥ti޿ |vľ+^̸K;L!GϠj9ӨSװcx,ٸs=C׼ ^wCē+_~8C̣KBԳkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:'H Z̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZRuX?6e-d>ٖP$ % Xd){b ! R2}[`,A2[f(dI,Q2Mr':Y˷ t8C ƈZx(x PfF9@!dr)Myğg&L?!%T0?YK̥.A5nХHPr'9!axCE/}Dl ⇏+3C<*D0 IBL"F:򑐌$'IJ")+0o$PG#/@U$)8Ɍ d.c2%0W01qXvٞDH'0IM 2B}|L7QbLx12Ykn!mD? ϶3&Ѱ9Lql 4ub$"-t<4#*6QD'X+\rѯ&?cȔ GB g,%/--:V +tq$O z3-< "xuLP`Tȡ;CPu%-at".x/ ^+Tc C?"V [i5\6 h_d@EBaN(uNe,FVvฅ,v+ fKúMB$LUZ"46A- |`U&MIFDms+QZ55:1CanGل,I~J𲅶t_,@ vE3G}4fX8.AST7;EBp4s1IBLlNcqU\ ;tvxwidgets-0.12.1/demos/000077500000000000000000000000001506765256500151335ustar00rootroot00000000000000tvxwidgets-0.12.1/demos/barchart/000077500000000000000000000000001506765256500167215ustar00rootroot00000000000000tvxwidgets-0.12.1/demos/barchart/README.md000066400000000000000000000000361506765256500201770ustar00rootroot00000000000000![Screenshot](screenshot.png) tvxwidgets-0.12.1/demos/barchart/main.go000066400000000000000000000014171506765256500201770ustar00rootroot00000000000000// Demo code for the bar chart primitive. package main import ( "github.com/gdamore/tcell/v2" "github.com/navidys/tvxwidgets" "github.com/rivo/tview" ) func main() { app := tview.NewApplication() barGraph := tvxwidgets.NewBarChart() barGraph.SetRect(4, 2, 50, 20) barGraph.SetBorder(true) barGraph.SetTitle("System Resource Usage") // display system metric usage barGraph.AddBar("cpu", 80, tcell.ColorBlue) barGraph.AddBar("mem", 20, tcell.ColorRed) barGraph.AddBar("swap", 40, tcell.ColorGreen) barGraph.AddBar("disk", 40, tcell.ColorOrange) barGraph.SetMaxValue(100) barGraph.SetAxesColor(tcell.ColorAntiqueWhite) barGraph.SetAxesLabelColor(tcell.ColorAntiqueWhite) if err := app.SetRoot(barGraph, false).EnableMouse(true).Run(); err != nil { panic(err) } } tvxwidgets-0.12.1/demos/barchart/screenshot.png000066400000000000000000000215541506765256500216130ustar00rootroot00000000000000PNG  IHDR>y^ %sBIT|dtEXtSoftwaregnome-screenshot>.tEXtCreation TimeMon 20 Dec 2021 09:34:14 PM AEDTy IDATxyul3(2(Y*[eXfi٢12sZOF_'5"* ( 20jΏc -_ǃs_}_纇e^s]=U(Xux x('| x('| x('| x('| x('| x('| x(W)wֲfS`׳#3>@P<᳅k3s8\-g|[>#ްK,fd)㮛r?5;˂E3Pߵȱ>S -PmmMW֛7qcS+=F>l~_^]x>[CwL+~+Wf1I};5.?ro?$ɱ>:wss&Lz(/Isq&Oy${c=+1d{g.;w;$61yzҵOޗ}uɧev=vgNȽ>=猾']Nߝi3'] ~97sgGݟi3'?ܒ֮usm6srs3gtNMi_-X4/‹kux|J:::$MLsJUUUCK/-ߠY={yˈI#:<9S2u}SW[sn_Ҧ|#U\%+W̥_U\yUӣGǭkqs<`xGוO?J;ȏ_:3/֖~<:W\$o)Gsd|ߨe$2dpo?(= WװarOի3ew9䐃r̞5'+x 1}F޺wvm :L̙37'pJ^|qzwUZ1l]>9ږvG/o; w +~^x1I2}ښǏͥ?'X3~oY蚫n#d֖v+eW挳>s{Kr Ε2x̘1+g~Kzk~y8}t|~{͹s5G}Dn._9'wuSZZZo|?7tz7d$wssײL25+WLG3_ݰ4l7erŕg.;?mYdi~QA$s_~Cdy/_ sKGG:9kG3<ںۦ_^|aI|./~k{1 [E'tuvv>In횱ϴgg9}G?u :7ɚK~疛5_wttj}<;4/_<~w"XK+|˵u7w;ŋ^H_"3p,Z8IҲ%ySUUUz~)E>:tǗ/9eŊIjjܼbǷvs s>K<̄TUUeѢٶ6I[[{6կ8O/kOys-P>[_38kmyiI>pD$̟l>SSSSN?ך^ݚ;[33&fʤs fvɍ7ܲc52wssX=9Zۭuuk&N~8{]N=7y|ʣ9vq]+sʩJCCzc83j29?sz%I.Os[ͮo|CdrEšo_??mmI6y9픳rSF:˙7wzo֬9gcr7׿*{<;$kvYΓOO{{{V^ο\V)> UjY,E32xyٳg<5.̘1㰉g2lVq@֞/D7fʔg u'Nh~Ϣ(F܀ןGݟֶ/Tz6]\Iz&g O}/sWz*~~~K x('| x('| x('| x'ɂE3*=>@P&|>~獙3^kruWg'sgQ#7helgɒ%х?͍7u߻ijjߒ~{ssIjkk^qel;n;/-{izʡyW.45-%\mw-f>8lhj3}̜sM~5kNFucޞfذY9 ]l9j+=bdժy`w47X:`˱ٟ3{nZ[۲#$uu61ӦX:`˱لOMMMzꮏלY';ݐS?{R6e]l96䧏yO擟:>ǟ̞dNG$ҿLyj\;93[Mk~~΂E32x+2mY^a9P<O>@P<O>@P<O>@P<O>@P<O>@P<O>@P<O>@P<O>@P<ljJMh~!+|YVz(IR]mzr~jY~mSllJZ>~T$'IpR\LC~ד [8wJMY=3sI:;Sޚo:W/IצW ڽCM:r1ऺ6=v:0ҾdVTצ}pR{IGӳ7Ck|6YeCV>֕yί%UΎ6=w}OVS:[W$u[Uzdآ SUyw%iy-}4xV:V%UI,#k_Wesߩ땖'mi[xڗMݐ҂-54sumls+;4lߩ}t箇&Jmv/ζ룩V#?Ζi]8cͥn+ҝ_O[OIAgsղ>7)INj'e]_O:*;4lFh76M׍:Ve~yOK x.u;?n ۷ g| x('| x('| x('| x('| x('| x('| x('| x('| x('| x('| x('| x('| x('| x('| x('| x('| x('| x('| x('| ]͎}硻t-ںg>^Ai[ 9%^63_to1ŕ]˪jRi{F:WYjKTl᥌3sv-UיCGEչξ٦=p`s'|6U uai{˷*JǢ:|TץcThȜȩnʏoRWә r1KMCGf-ˈA#|6xcZUmk-Ytt&5թHoY^_yi{t#qa۵f4ȜtW }S7+{e:[ړtoܷfa57vj;k{ٺSSjʨ/7&IzH* E>uమeu{ LW'흩;%5U_E͛|νCWg3wm*nߚsz3eºM>'K-V?47u3}nSZZz)ϧ!;gOۇsekf-s-̤Y=ּǶ޻4\]>Η\q{n9^aXyT>:$u&.{wdʏ丷-I?ʽ6^+ƌ_v粖4~BӬۧ.M5+4 g| x.u[ݾͦom.|+4}t/g| x('| x('| x('| x('| x('| x('| x('| x(W[x5UU;A}ҧ&/]?>?O.[$г.?՘7dv|y/vJMUz %>֎|yyiegV=2W]zT]i =M>zfm*=6lr§ {Uy-C{*3ݶOin69S~u5w7lUSVWCCMcC,oHCO9[onP^5չ͜&IVw*-y]O$IzV@Ef*SoZ>kљ[RQbf*Ѩay=NT%Yޑ{_v4|@gJ K6c{C%IaG=t&/]@P<O>@P<O>@P<O>@P<O>@P<O>@P<O>@P<Oū.}WG-+=Bod);Wz*x(^3p\{ՙ={JlbŇ.f2rޜ+\ښJlBEO^r{ޕ~<:MMr%gmeh&Tt4L>3lӯ_f͚#Wz4`*J{{{jsG>C/oNCC},}mד|^gŊɪU-5$I in^ EKֶ̞$I]]m k̴iYjU|SӻwCNIiZڔqcWz4`*:|Z)Oq}0'}Uz,`*5>IpN@@>1t(a7gl?dZﶼo6.rι&~<:<3cM;k7xkG9㳑Nߝi3']uԄ.Vn;?=z_oT'oeg8G{n΄Ie?c.)dϑ{$I .W8O>5.?ro? zix˯32y#9g%Yakݷ*OOϝyZw͜pK|[sc9rsm6s.O;d3٧_vۺ^0=j䫞F8/O8%S>7uu]#8tO? MfiiY|wќeϥ_|[FnL49 0~R9ih)I2~ܤyi]>|4/os-HҦ|#U\%+VHҽguuu.ʫ_\ʗӣG]:&]:&woϑ{1ԓ mԌt?g|6>~l.٘<ēiooϟ~$sZonH̛;?'<<,gIs,^BfLse2lXc?`|ի3ew9䐃W#C ec$MȽH]]m:6oz3r=2n܄$5WWOvYzuvکk|x.~AҺ5/U_72<'|6!C2wuojZҥK3` hoOwW{jkk2d$wssߝw{5[dU㮛rH;!{=2;* ,<({=2Ʈ Ï8,;`ں9ٝvϋ/,I[ۚExUWOLpFxg3t\?hЀx IҲ%5k⢪*{~M櫪ʳK9Cٹc?|:j,\|pֹI\|?L89k~A '|ׯo3`vx94g&5˺ύhlg}l u_/yF_|y9sͿ9^l?7yTWWMcЮ̉ih~#`dƌw}$GqXzwٳdԧsy_L^Rף.8k]B{3h$I[[[ٙUVe֬9#s}.k&Mz< immzQ8_ӧȢEw3IrqǼ45-˗x~ֵ)61g|67ݖmo\)Ss)gv7nB@ZV/rIDAT[$?.q{sfɋK^9O=|;qL89l{ ~g޼9֍{tBvCZ[#vҒY䲟wޘg]I'ϭu=#|f~pwrĉuukxG3h\@P<`ьJן,ZX8l* gzMɛ>@P<Oֳۤ}S 3>@>@P<O>@P<O>@P<O>@P<O>@P<O>@P<O>@P<O>@P<O>@P<O>@P<O>@P<O>@ZIENDB`tvxwidgets-0.12.1/demos/demo/000077500000000000000000000000001506765256500160575ustar00rootroot00000000000000tvxwidgets-0.12.1/demos/demo/main.go000066400000000000000000000234751506765256500173450ustar00rootroot00000000000000// Demo code for the bar chart primitive. package main import ( "math" "math/rand" "time" "github.com/gdamore/tcell/v2" "github.com/navidys/tvxwidgets" "github.com/rivo/tview" ) func main() { app := tview.NewApplication() // spinners spinners := []*tvxwidgets.Spinner{ tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerDotsCircling), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerDotsUpDown), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerBounce), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerLine), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerCircleQuarters), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerSquareCorners), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerCircleHalves), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerCorners), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerArrows), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerHamburger), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerStack), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerStar), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerGrowHorizontal), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerGrowVertical), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerBoxBounce), tvxwidgets.NewSpinner().SetCustomStyle([]rune{'🕛', '🕐', '🕑', '🕒', '🕓', '🕔', '🕕', '🕖', '🕗', '🕘', '🕙', '🕚'}), } spinnerRow := tview.NewFlex().SetDirection(tview.FlexColumn) spinnerRow.SetBorder(true).SetTitle("spinners") for _, spinner := range spinners { spinnerRow.AddItem(spinner, 0, 1, false) } // bar graph barGraph := newBarChart() barGraph.SetMaxValue(100) barGraph.SetAxesColor(tcell.ColorAntiqueWhite) barGraph.SetAxesLabelColor(tcell.ColorAntiqueWhite) // activity mode gauge amGauge := tvxwidgets.NewActivityModeGauge() amGauge.SetTitle("activity mode gauge") amGauge.SetPgBgColor(tcell.ColorOrange) amGauge.SetBorder(true) // percentage mode gauge pmGauge := tvxwidgets.NewPercentageModeGauge() pmGauge.SetTitle("percentage mode gauge") pmGauge.SetBorder(true) pmGauge.SetMaxValue(50) // cpu usage gauge cpuGauge := tvxwidgets.NewUtilModeGauge() cpuGauge.SetLabel("cpu usage: ") cpuGauge.SetLabelColor(tcell.ColorLightSkyBlue) cpuGauge.SetBorder(false) // memory usage gauge memGauge := tvxwidgets.NewUtilModeGauge() memGauge.SetLabel("memory usage:") memGauge.SetLabelColor(tcell.ColorLightSkyBlue) memGauge.SetBorder(false) // swap usage gauge swapGauge := tvxwidgets.NewUtilModeGauge() swapGauge.SetLabel("swap usage: ") swapGauge.SetLabelColor(tcell.ColorLightSkyBlue) swapGauge.SetBorder(false) // utilisation flex utilFlex := tview.NewFlex().SetDirection(tview.FlexRow) utilFlex.AddItem(cpuGauge, 1, 0, false) utilFlex.AddItem(memGauge, 1, 0, false) utilFlex.AddItem(swapGauge, 1, 0, false) utilFlex.SetTitle("utilisation mode gauge") utilFlex.SetBorder(true) // plot (line charts) sinData := func() [][]float64 { n := 220 data := make([][]float64, 2) data[0] = make([]float64, n) data[1] = make([]float64, n) for i := 0; i < n; i++ { data[0][i] = 1 + math.Sin(float64(i)/5) data[1][i] = 1 + math.Cos(float64(i)/5) } return data }() bmLineChart := newBrailleModeLineChart() bmLineChart.SetData(sinData) dmLineChart := newDotModeLineChart() sampleData1 := []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} sampleData2 := []float64{10, 9, 8, 7, 6, 5, 4, 3, 2, 1} dotChartData := [][]float64{sampleData1} dotChartData[0] = append(dotChartData[0], sampleData2...) dotChartData[0] = append(dotChartData[0], sampleData1[:5]...) dotChartData[0] = append(dotChartData[0], sampleData2[5:]...) dotChartData[0] = append(dotChartData[0], sampleData1[:7]...) dotChartData[0] = append(dotChartData[0], sampleData2[3:]...) dmLineChart.SetData(dotChartData) // sparkline iowaitSparkline := tvxwidgets.NewSparkline() iowaitSparkline.SetBorder(false) iowaitSparkline.SetDataTitle("Disk IO (iowait)") iowaitSparkline.SetDataTitleColor(tcell.ColorDarkOrange) iowaitSparkline.SetLineColor(tcell.ColorMediumPurple) systemSparkline := tvxwidgets.NewSparkline() systemSparkline.SetBorder(false) systemSparkline.SetDataTitle("Disk IO (system)") systemSparkline.SetDataTitleColor(tcell.ColorDarkOrange) systemSparkline.SetLineColor(tcell.ColorSteelBlue) iowaitData := []float64{4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6} systemData := []float64{0, 0, 1, 2, 9, 5, 3, 1, 2, 0, 6, 3, 2, 2, 6, 8, 5, 2, 1, 5, 8, 6, 1, 4, 1, 1, 4, 3, 6} ioSparkLineData := func() []float64 { for i := 0; i < 5; i++ { iowaitData = append(iowaitData, iowaitData...) } return iowaitData }() systemSparklineData := func() []float64 { for i := 0; i < 5; i++ { systemData = append(systemData, systemData...) } return systemData }() iowaitSparkline.SetData(ioSparkLineData) systemSparkline.SetData(systemSparklineData) sparklineGroupLayout := tview.NewFlex().SetDirection(tview.FlexColumn) sparklineGroupLayout.SetBorder(true) sparklineGroupLayout.SetTitle("sparkline") sparklineGroupLayout.AddItem(iowaitSparkline, 0, 1, false) sparklineGroupLayout.AddItem(tview.NewBox(), 1, 0, false) sparklineGroupLayout.AddItem(systemSparkline, 0, 1, false) // first row layout firstRowfirstCol := tview.NewFlex().SetDirection(tview.FlexRow) firstRowfirstCol.AddItem(barGraph, 0, 1, false) firstRowSecondCol := tview.NewFlex().SetDirection(tview.FlexRow) firstRowSecondCol.AddItem(amGauge, 0, 3, false) firstRowSecondCol.AddItem(pmGauge, 0, 3, false) firstRowSecondCol.AddItem(utilFlex, 0, 5, false) firstRow := tview.NewFlex().SetDirection(tview.FlexColumn) firstRow.AddItem(firstRowfirstCol, 0, 1, false) firstRow.AddItem(firstRowSecondCol, 0, 1, false) // second row plotRowLayout := tview.NewFlex().SetDirection(tview.FlexColumn) plotRowLayout.AddItem(bmLineChart, 0, 1, false) plotRowLayout.AddItem(dmLineChart, 0, 1, false) screenLayout := tview.NewFlex().SetDirection(tview.FlexRow) screenLayout.AddItem(firstRow, 11, 0, false) screenLayout.AddItem(plotRowLayout, 15, 0, false) screenLayout.AddItem(sparklineGroupLayout, 6, 0, false) screenLayout.AddItem(spinnerRow, 3, 0, false) screenLayout.SetRect(0, 0, 100, 40) // upgrade datat functions moveDotChartData := func() { newData := append(dotChartData[0], dotChartData[0][0]) dotChartData[0] = newData[1:] } moveDiskIOData := func() ([]float64, []float64) { newIOWaitData := ioSparkLineData[1:] newIOWaitData = append(newIOWaitData, ioSparkLineData[0]) ioSparkLineData = newIOWaitData newSystemData := systemSparklineData[1:] newSystemData = append(newSystemData, systemSparklineData[0]) systemSparklineData = newSystemData return newIOWaitData, newSystemData } moveSinData := func(data [][]float64) [][]float64 { newData := make([][]float64, 2) newData[0] = rotate(data[0], -1) newData[1] = rotate(data[1], -1) return newData } updateSpinner := func() { spinnerTick := time.NewTicker(100 * time.Millisecond) for { select { case <-spinnerTick.C: // update spinners for _, spinner := range spinners { spinner.Pulse() } // update gauge amGauge.Pulse() app.Draw() } } } // update screen ticker update := func() { value := 0 maxValue := pmGauge.GetMaxValue() rand.Seed(time.Now().UnixNano()) tick := time.NewTicker(500 * time.Millisecond) for { select { case <-tick.C: if value > maxValue { value = 0 } else { value = value + 1 } pmGauge.SetValue(value) randNum1 := float64(rand.Float64() * 100) randNum2 := float64(rand.Float64() * 100) randNum3 := float64(rand.Float64() * 100) randNum4 := float64(rand.Float64() * 100) barGraph.SetBarValue("eth0", int(randNum1)) cpuGauge.SetValue(randNum1) barGraph.SetBarValue("eth1", int(randNum2)) memGauge.SetValue(randNum2) barGraph.SetBarValue("eth2", int(randNum3)) swapGauge.SetValue(randNum3) barGraph.SetBarValue("eth3", int(randNum4)) // move line charts sinData = moveSinData(sinData) bmLineChart.SetData(sinData) moveDotChartData() dmLineChart.SetData(dotChartData) d1, d2 := moveDiskIOData() iowaitSparkline.SetData(d1) systemSparkline.SetData(d2) app.Draw() } } } go updateSpinner() go update() if err := app.SetRoot(screenLayout, false).EnableMouse(true).Run(); err != nil { panic(err) } } func newDotModeLineChart() *tvxwidgets.Plot { dmLineChart := tvxwidgets.NewPlot() dmLineChart.SetBorder(true) dmLineChart.SetTitle("line chart (dot mode)") dmLineChart.SetLineColor([]tcell.Color{ tcell.ColorDarkOrange, }) dmLineChart.SetAxesLabelColor(tcell.ColorGold) dmLineChart.SetAxesColor(tcell.ColorGold) dmLineChart.SetMarker(tvxwidgets.PlotMarkerDot) dmLineChart.SetDotMarkerRune('\u25c9') return dmLineChart } func newBrailleModeLineChart() *tvxwidgets.Plot { bmLineChart := tvxwidgets.NewPlot() bmLineChart.SetBorder(true) bmLineChart.SetTitle("line chart (braille mode)") bmLineChart.SetLineColor([]tcell.Color{ tcell.ColorSteelBlue, tcell.ColorGreen, }) bmLineChart.SetMarker(tvxwidgets.PlotMarkerBraille) return bmLineChart } func newBarChart() *tvxwidgets.BarChart { barGraph := tvxwidgets.NewBarChart() barGraph.SetBorder(true) barGraph.SetTitle("bar chart") barGraph.AddBar("eth0", 20, tcell.ColorBlue) barGraph.AddBar("eth1", 60, tcell.ColorRed) barGraph.AddBar("eth2", 80, tcell.ColorGreen) barGraph.AddBar("eth3", 100, tcell.ColorOrange) return barGraph } // Source: https://stackoverflow.com/questions/50833673/rotate-array-in-go/79079760#79079760 // rotate rotates the given slice by k positions to the left or right. func rotate[T any](slice []T, k int) []T { if len(slice) == 0 { return slice } var r int if k > 0 { r = len(slice) - k%len(slice) } else { kAbs := int(math.Abs(float64(k))) r = kAbs % len(slice) } slice = append(slice[r:], slice[:r]...) return slice } tvxwidgets-0.12.1/demos/dialog/000077500000000000000000000000001506765256500163725ustar00rootroot00000000000000tvxwidgets-0.12.1/demos/dialog/README.md000066400000000000000000000000361506765256500176500ustar00rootroot00000000000000![Screenshot](screenshot.png) tvxwidgets-0.12.1/demos/dialog/main.go000066400000000000000000000007631506765256500176530ustar00rootroot00000000000000// Demo code for the bar chart primitive. package main import ( "github.com/navidys/tvxwidgets" "github.com/rivo/tview" ) func main() { app := tview.NewApplication() dialog := tvxwidgets.NewMessageDialog(tvxwidgets.ErrorDailog) dialog.SetTitle("error dialog") dialog.SetMessage("This is first line of error\nThis is second line of the error message") dialog.SetDoneFunc(func() { app.Stop() }) if err := app.SetRoot(dialog, true).EnableMouse(true).Run(); err != nil { panic(err) } } tvxwidgets-0.12.1/demos/dialog/screenshot.png000066400000000000000000000156631506765256500212700ustar00rootroot00000000000000PNG  IHDR7F#sBIT|dtEXtSoftwaregnome-screenshot>.tEXtCreation TimeSat 25 Dec 2021 10:37:02 AM AEDTR IDATx{]U/o4VQȨ0(0(q@Ak-/q< Oq*;25Q;Ix"COtS}ڿ{:;0DM81I' PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTa@ O@]oo! P?N&kߗڏY\49{n_W@ͳEޗV%^|~- gn8w`+"fn;%ݔ\lr#Ɂ37>gArWO.[򽞷M=9e>iUɱn3J׭|Yg&?^ڝdC{WOcF-zC`s7tttĶ'O>9cz2u[etK.<䳻`jm۔:o2 #o|m_C2/%$o;69_ӧ&k^hưRk_^|F-Ķk.,I'{|dd$o:\oKImǫaFc]2'_CnnWO2~z 7$9jVkcշ89[=Xl KK&;'?zJ;$t$s1|yFmc'@k+'㦴竍[*G|vۍ)30Htw?oIߒ,_iߋJ~;[ϗYfcLh򮓒+%:6L!0$yⰗuCgY;drKOnWf\Ɂ~!Pnwei@ PpTA Un*7@ PpTA Un*7@߸dw4%o}vJr?%FM,(= t>4| Y?Kt毯y!9yLk}<;Y`}n3,9ޘ<3/&wNҪd듃Ktc=OC КK\&7<~wzw>T݅x? :{:Ї,KZӱ.Y|%5{XrcɕR8,nK&|ץ7'RkGgM|O2|d{΂dl;'-JN^Zv{{isԬd x]kvY=ZΝn3SrM&>8M=9xz{ۚfzcl[:{! w<$9dg~q} A\Zοo6Ǟ[ff'9&i?}G_;4s ^6ÓIݼ}l鲴T=g$/!g'O>9cz2u[eO6M#-ǔgw+fZcl[:[! wn:Y|/qS{nӹ\܏~.y7[_Gي_^^.dC[Kw(K M-{xf[x-ɛjf$zaٛddwVkXw: }e$#F榳/KO}bョc]MܥHvxyZǺmkCH_XLo˃ʢ%c&n}<ECĉe%ei@ PpMxG_o_>\Lع{FM,H._= cv)ޫW|s4КY?Kt毯y!9yLk}<;Y`}U/Jf>9Owr̶ oLz|17@k.zErwoǼ}_WYr̶TΩ- 6Єei@k:֕?nuy~my~M=Vr8,nˡ&|ץ7'RkGڍ)9G /|?vLY|K&힜u[ _?=6=ZqΝnzv}[Y>vͪs['͎YZz{wɗI,5Yf%3Nh{;{;Y~jeSfǥ>Ώ%+?SWr4f|mG\x9?mϡm8wZd;{s@nj3?N[.-_߷yc-3@ߓھfN~3'SNμ5Y0O|rWðmK<|Grɑ[)峻%dI<F2},>X_wmW']PBjv̺ecoؿvhѲ-m,sch݌%nu}o.I8.Ypo2o'~| f^C2/%$o;69_ӧ&k_,{m+۟@}綫'<76ʅ璇uMڽ\4xfZx-ɛ*Hg#yef$zaddw7/VqSn\%[LZU-=;?tuv %$⇚ok4+K/^4Yp2K[iW.uunH8Y$K뒟}ˏ'V0s5_sNuJqmݵK~޼{G.gI2ar1jc' 7^[87ŕ1;9y2M熖UeNywcN+c]CO?>}qigW6t4o614lہ3Jvxl 6V'VnbQrIA'w]rM[v곻v\n߮X0jio)7ͬZn\qIL_۸i[ѹ!ikkC:;ZqigzC+m~rYZ7d=edՒdKX_n` X ~ kҚmݵ{%3Rf(ȟGyonHd7 =I&V.d+yYi,z\o=L/3quwcoŊEɴZpCo5ӟǥ+=ٿm7<__e.37I'O+?#No>`<0w_Hdl_DrmgvW}$9dt}cmi7zIזC-{|Pߎ_Y.w fxK+fތ!ҧY{zۮ:.i6f|wۖ>V>c?ם4%FlY`0D!ʖڽovX[EOfK|tr,[]0duk Vp;wg]7y>f6)q̰ngw* Pr['37@ PpTA Un*7@ PpTA Un*7@ P.n Z";m+hpt͌ 07C Un*7@ PwK^]@ Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ PpTA Un*7@ P]ҵ@IENDB`tvxwidgets-0.12.1/demos/gauge_am/000077500000000000000000000000001506765256500167005ustar00rootroot00000000000000tvxwidgets-0.12.1/demos/gauge_am/README.md000066400000000000000000000000361506765256500201560ustar00rootroot00000000000000![Screenshot](screenshot.png) tvxwidgets-0.12.1/demos/gauge_am/main.go000066400000000000000000000012051506765256500201510ustar00rootroot00000000000000// Demo code for the bar chart primitive. package main import ( "time" "github.com/gdamore/tcell/v2" "github.com/navidys/tvxwidgets" "github.com/rivo/tview" ) func main() { app := tview.NewApplication() gauge := tvxwidgets.NewActivityModeGauge() gauge.SetTitle("activity mode gauge") gauge.SetPgBgColor(tcell.ColorOrange) gauge.SetRect(10, 4, 50, 3) gauge.SetBorder(true) update := func() { tick := time.NewTicker(500 * time.Millisecond) for { select { case <-tick.C: gauge.Pulse() app.Draw() } } } go update() if err := app.SetRoot(gauge, false).EnableMouse(true).Run(); err != nil { panic(err) } } tvxwidgets-0.12.1/demos/gauge_am/screenshot.png000066400000000000000000000060601506765256500215650ustar00rootroot00000000000000PNG  IHDR|eZVsBIT|dtEXtSoftwaregnome-screenshot>.tEXtCreation TimeTue 21 Dec 2021 06:10:58 PM AEDT8 IDATxy}r*j "FEP:G5Wl5(H%miӤjD E\6 jRQr_*İ,A "Vyu-o-=$$;oQw…?[[Qm2ɟ:Uv"5|Hy-c /.?YtN&O}(v#:"3fMasdƬi1kZvu$ɵCΌY=?Kl6=̩֭?x?vךs_ ӧ&W˘ʽGgN>I?a,~%O?xN|#>'O=3%ߌa};v'gO省I?qʈ^N5zgrL?;fѽ=wN'TiλϯJG?$ɠ 7˵Cʭʹm6̞~}O=vo&vyIcFf˯^oܝ~oL:t=Zqanv59vܨY#81_rȯg]"cǍOzlgSh{ܞ91x!UG` :w<8?Od9S]=/^vq3>$ OHkhhȔǞAgתsi'gٲYtG s2үѩˌf5n׳v^&K/IWgؾ)O9|wߪ|wϘrݰI6݅=~ٰaC噧OV8G׵KSWW{ܗ4xSh{lj;ٿ7ҹ-=P|3-9CҩS$ɞ{6m7ҥKxM45wykqȜ;<6iG 2yʃe?  MMM?swӦMq坷iUjҩSǬ].Yv?А$߾I=5q]eeeAlz {^qϤk={65;7-:v'nj̅_/$TTT$IV\nݺnu}CCCn/{޽{e3r yηh抜z)9ܳs%W}~_EEEV׬I۶mקjN:fujjV~=:UMZWYgfƍ|ΚޟJ6SWWt]>m~܊scUv Vں,\(Ir^{62/w^iժU;x;+WS2jԘ?: ӗSW_x|'R6<_}]̘5-={1墋`ISsb7nkKGCztϣlc\?TϟwS_=,^2d3 nm\w̜VR>lq KeYφ ach]>'$=푷v{n*vfUZzb_]jxۧz̜yYdYKTVVfWs@^k~A I+[pBa%FKUU$$?GʏcOTP3ں zcKz#}oLd[y P$ @*EIP$ @xmоG*EIP$ @*EIP$ @*EIP$ @*EIP$ @*EIP$ @*EIP$ @*EIP$ @*EIP$ @*EIP$ @*EIP$ @*EIP$ @*EIP$ @*EZ̾~IENDB`tvxwidgets-0.12.1/demos/gauge_pm/000077500000000000000000000000001506765256500167175ustar00rootroot00000000000000tvxwidgets-0.12.1/demos/gauge_pm/README.md000066400000000000000000000000361506765256500201750ustar00rootroot00000000000000![Screenshot](screenshot.png) tvxwidgets-0.12.1/demos/gauge_pm/main.go000066400000000000000000000013151506765256500201720ustar00rootroot00000000000000// Demo code for the bar chart primitive. package main import ( "time" "github.com/navidys/tvxwidgets" "github.com/rivo/tview" ) func main() { app := tview.NewApplication() gauge := tvxwidgets.NewPercentageModeGauge() gauge.SetTitle("percentage mode gauge") gauge.SetRect(10, 4, 50, 3) gauge.SetBorder(true) value := 0 gauge.SetMaxValue(50) update := func() { tick := time.NewTicker(500 * time.Millisecond) for { select { case <-tick.C: if value > gauge.GetMaxValue() { value = 0 } else { value = value + 1 } gauge.SetValue(value) app.Draw() } } } go update() if err := app.SetRoot(gauge, false).EnableMouse(true).Run(); err != nil { panic(err) } } tvxwidgets-0.12.1/demos/gauge_pm/screenshot.png000066400000000000000000000072071506765256500216100ustar00rootroot00000000000000PNG  IHDRFsBIT|dtEXtSoftwaregnome-screenshot>.tEXtCreation TimeTue 21 Dec 2021 07:56:43 PM AEDT:` IDATx{u ^ECKE EV3SKEqbj-kiDe""MsSV3.k╻" bxAtk23Lh)+Ȍs87}?s;MU^Zn`MGP @qD.GP @qD.GP @qD.GP @qD.GP @qD.GP @qD.GP @qD.GP @qD.GP @qD.GP @qD.GP @qD.GP @qD.GP @qD.GP @qD.GP @q:kthW:6@\8"xyٴ&m=6 ē˙gi1"r(ȥݙ1{j~|3yʤ?W\]]\|<дyϭo>o:w䈣˭O ?|n,xtNno˷]ޖo~L2)3fMG Mq7s<77I9"LS<:'㯳>ZYOsm9F[nʌYS3~Os2g=١_$[ʤÏʭOnCY5oZ̲km_4-[oջgO.mzQ9GI KCa|?f|ӱC! M>rYG/8|ml3Sӱfb^ʗwN?95d98`\xřt8` G^}$=C|dzo??{~֦*&_^;))UU:SVk-wt>se… $7~lfΘ>휳'uTWWgr5gmK.=oE:k=lBm,_#omR$ݐ$y'3s˞ȝS.aϲe2wvsO+QY㒋ҥI<C ^x0Irם$y*ּaMIOKKKz'UVOw9f-{)m3\|EsKrǬ,+Ϗ_IC,|dav]/m;ݺm aC)r7v͢EgM{KLSSsƏ;|fzVx~ܹњy9?huh?n+ qz*{um$-7U>W[[@Z׳g<o}~|+ӹsο}r޽.W;t̆m,}6MM?hC,_|gYܼͯ?رCmƦL}w/Yy~gkm_隭p6\ڥ=*螆?ޞO>_z)}ﴴ淾ŋnWqY|y\]]?6pHfΘ$yhTUU!xt!MMxzϪP45oC{7!]Zyw]YZ;%I^kءCe[ok=ɥ]:aҥ6w[ȢEe޼3ӹsԬSO|cr^+]_L1_j>R]]]w9z}pL~&&:7uRƦxAdg 7H,H|bqYM 2\ڥifi碉?I'Z$jesq#YJWsy3qpv{)ijnZ5dͿM̜sgf̞u]7cKߘ,~$IKKKF}|<477gٲeiY޲ڳqǞ܇gԷOϿ˗gQ'dIjqYcw2Kkھ$sС_ʯnezoM˳mgU?-_~64c1lDf֣͜jkkbqg%篭jzkJ.e %ڿJzwQn_{`-6IN8'Zލ+}XܮnWx-m1QK'#@v`mrGB;ԯ,~zAN<$Irc2c,\tn}d[_"Lʮܖc@!r1ɼyijlʰÎΠʟOLUUUN?㔜r9crNm =˙v}saQͫ'ŕ\h'Cvܩ_+|MΝsUkͿ$]2n477g~?gk'v_[@J.;/}l'̯<}vΈOMM\r3;kO7Ir .̙srݤ_ȅv˯_]+'d99w /1LN$˖-K1:uK/Ԥ*--~!?"zl=$A_|}> fΩ||OqKڜ;| ȅva#*Z$}xxAws,xOgGP+jp%\#r(8"\-V`I¶wH侍U_nW8"\#r(8"x 7tmnXC\8"\#r(8"\#r(8"\#r(8"\#r(8"\#r(8"\#r(8"\#r(8"\#r(8"\#r(8"\#r(8"\#r(8"\#r(8"\#r(8"\#r(8"\#r(8"\#r(8"\#r(8"\#r(8"\#r(M'IENDB`tvxwidgets-0.12.1/demos/gauge_um/000077500000000000000000000000001506765256500167245ustar00rootroot00000000000000tvxwidgets-0.12.1/demos/gauge_um/README.md000066400000000000000000000000361506765256500202020ustar00rootroot00000000000000![Screenshot](screenshot.png) tvxwidgets-0.12.1/demos/gauge_um/main.go000066400000000000000000000013751506765256500202050ustar00rootroot00000000000000// Demo code for the bar chart primitive. package main import ( "math/rand" "time" "github.com/gdamore/tcell/v2" "github.com/navidys/tvxwidgets" "github.com/rivo/tview" ) func main() { app := tview.NewApplication() gauge := tvxwidgets.NewUtilModeGauge() gauge.SetLabel("cpu usage:") gauge.SetLabelColor(tcell.ColorLightSkyBlue) gauge.SetRect(10, 4, 50, 3) gauge.SetWarnPercentage(65) gauge.SetCritPercentage(80) gauge.SetBorder(true) update := func() { tick := time.NewTicker(500 * time.Millisecond) for { select { case <-tick.C: randNum := float64(rand.Float64() * 100) gauge.SetValue(randNum) app.Draw() } } } go update() if err := app.SetRoot(gauge, false).EnableMouse(true).Run(); err != nil { panic(err) } } tvxwidgets-0.12.1/demos/gauge_um/screenshot.png000066400000000000000000000067671506765256500216270ustar00rootroot00000000000000PNG  IHDRsBIT|dtEXtSoftwaregnome-screenshot>.tEXtCreation TimeTue 21 Dec 2021 09:51:36 PM AEDT򚬬 OIDATxyua : -ݺVV*Zu3[nWф\*{dPna",*0 ?S&x" _gs~wC-@1`y#0 l(Ld@a" PD6&0 l(Ld@a" PD6&0 l(Ld@a" PD6&0 l(Ld@a" PD6&0 l(Ld@a" PD6&0 l(Ld@a" PD6&eee^Sݲ^ SC˲^ƕl(Ld@a" PD6~ߛ2}^ri "s&0 l(Ld@a" ~,CwYgy{Mh"gkǺKe6s-rO;[GЭѻRp% PI~wٱ6رcN?㤌X&N~* ;kjsunf6yه6X?#o27z}eO`9!> }}`Ms‹K^=$' 9&64jb\uuK3:93g&nM~vkw6rܱCr͐Ldc]~3tFz0)go;|́Wݓ57PЛMۮZt9s ׿Y{k᷏~ܘl]^қs!G爻ΡתЛׯ;r緭}+~~{xŀRd>k斛nOkkk󞴶ouRgwuLFsMܹsvv̜9+\pQzZ9xJֶw[K>Db|hݲW-C]7#JjmީJнrу~ֲogʘ'3|sپ͚ߘGnQ=θ( I]O1^HU;ֶaij.6òѧ}jj5=SCv^kkkE^[yګ32v̸4mLNyШ/> &>*=W^9>\_O:=g}j.Osgmʰ~/;}x%>DblyK2}'Gec~;2I2kʋ:O'ZZ[ӽ4'/鏵S7^ML[kk{{ZOӫqzgܸijjʽ>j><oa-d?ܓw{9w[9Ѓ2y􏏵;[0Am:us<9j]`EJbt3t[u2alnrDmkrǙf)IG.;?9'}bLi9cvk|dpԩvnȬ/SL|<~%_g):vtޘq>yKӲ`~J-?8"ruC}};1X1J< ,|_ ;wxɏӵkCgo"xr/_.r6g=e-ѱ.r/=7_zn__-IRܐ-}$ɜצ퇆_|us9{ŗ/vI&g|OO:-"ioWόw|X]d9gL6yGҺpl?˕*>Ϟ:q ?کev(Ld@a" PD6s2ee";v(Ld@a" PD6~_eSd@a" PD6&0 l(Ld@a" PD6&0 l(Ld@a" PD6&0 l(Ld@a" PD6&0 l(Ld@a" PD6&0 l(Ld@a" PD6&0 l(Ld@a" PD6&0 l(Ld@a" PD6&0 l(ZĽ/IENDB`tvxwidgets-0.12.1/demos/plot/000077500000000000000000000000001506765256500161115ustar00rootroot00000000000000tvxwidgets-0.12.1/demos/plot/README.md000066400000000000000000000000361506765256500173670ustar00rootroot00000000000000![Screenshot](screenshot.png) tvxwidgets-0.12.1/demos/plot/main.go000066400000000000000000000064521506765256500173730ustar00rootroot00000000000000package main import ( "math" "github.com/gdamore/tcell/v2" "github.com/navidys/tvxwidgets" "github.com/rivo/tview" ) func main() { app := tview.NewApplication() sinData := func() [][]float64 { n := 220 data := make([][]float64, 2) data[0] = make([]float64, n) data[1] = make([]float64, n) for i := 0; i < n; i++ { data[0][i] = 1 + math.Sin(float64(i+1)/5) // Avoid taking Cos(0) because it creates a high point of 2 that // will never be hit again and makes the graph look a little funny data[1][i] = 1 + math.Cos(float64(i+1)/5) } return data }() bmLineChart := tvxwidgets.NewPlot() bmLineChart.SetBorder(true) bmLineChart.SetTitle("line chart (braille mode)") bmLineChart.SetLineColor([]tcell.Color{ tcell.ColorSteelBlue, tcell.ColorGreen, }) bmLineChart.SetMarker(tvxwidgets.PlotMarkerBraille) bmLineChart.SetData(sinData) bmLineChart.SetDrawXAxisLabel(false) dmLineChart := tvxwidgets.NewPlot() dmLineChart.SetBorder(true) dmLineChart.SetTitle("line chart (dot mode)") dmLineChart.SetLineColor([]tcell.Color{ tcell.ColorDarkOrange, }) dmLineChart.SetAxesLabelColor(tcell.ColorGold) dmLineChart.SetAxesColor(tcell.ColorGold) dmLineChart.SetMarker(tvxwidgets.PlotMarkerDot) dmLineChart.SetDotMarkerRune('\u25c9') sampleData1 := []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} sampleData2 := []float64{10, 9, 8, 7, 6, 5, 4, 3, 2, 1} dotModeChartData := [][]float64{sampleData1} dotModeChartData[0] = append(dotModeChartData[0], sampleData2...) dotModeChartData[0] = append(dotModeChartData[0], sampleData1[:5]...) dotModeChartData[0] = append(dotModeChartData[0], sampleData2[5:]...) dotModeChartData[0] = append(dotModeChartData[0], sampleData1[:7]...) dotModeChartData[0] = append(dotModeChartData[0], sampleData2[3:]...) dmLineChart.SetData(dotModeChartData) scatterPlotData := make([][]float64, 2) scatterPlotData[0] = []float64{1, 2, 3, 4, 5} scatterPlotData[1] = sinData[1][4:] dmScatterPlot := tvxwidgets.NewPlot() dmScatterPlot.SetBorder(true) dmScatterPlot.SetTitle("scatter plot (dot mode)") dmScatterPlot.SetLineColor([]tcell.Color{ tcell.ColorMediumSlateBlue, tcell.ColorLightSkyBlue, }) dmScatterPlot.SetPlotType(tvxwidgets.PlotTypeScatter) dmScatterPlot.SetMarker(tvxwidgets.PlotMarkerDot) dmScatterPlot.SetData(scatterPlotData) dmScatterPlot.SetDrawYAxisLabel(false) bmScatterPlot := tvxwidgets.NewPlot() bmScatterPlot.SetBorder(true) bmScatterPlot.SetTitle("scatter plot (braille mode)") bmScatterPlot.SetLineColor([]tcell.Color{ tcell.ColorGold, tcell.ColorLightSkyBlue, }) bmScatterPlot.SetPlotType(tvxwidgets.PlotTypeScatter) bmScatterPlot.SetMarker(tvxwidgets.PlotMarkerBraille) bmScatterPlot.SetData(scatterPlotData) firstRow := tview.NewFlex().SetDirection(tview.FlexColumn) firstRow.AddItem(dmLineChart, 0, 1, false) firstRow.AddItem(bmLineChart, 0, 1, false) firstRow.SetRect(0, 0, 100, 15) secondRow := tview.NewFlex().SetDirection(tview.FlexColumn) secondRow.AddItem(dmScatterPlot, 0, 1, false) secondRow.AddItem(bmScatterPlot, 0, 1, false) secondRow.SetRect(0, 0, 100, 15) layout := tview.NewFlex().SetDirection(tview.FlexRow) layout.AddItem(firstRow, 0, 1, false) layout.AddItem(secondRow, 0, 1, false) layout.SetRect(0, 0, 100, 30) if err := app.SetRoot(layout, false).EnableMouse(true).Run(); err != nil { panic(err) } } tvxwidgets-0.12.1/demos/plot/screenshot.png000066400000000000000000001336701506765256500210060ustar00rootroot00000000000000PNG  IHDR,WsBIT|dtEXtSoftwaregnome-screenshot>-tEXtCreation TimeFri 29 Dec 2023 11:24:12 AM WIBy? IDATxyxTL &(" TiŊԅ(~Պ[ Uj@dE!%BɜHN2{k-}'\Ģ{ Z[1oxcX_ٙ?a !#q8oc&%(aPUg rkwr=ܷ zl wWt Vq~Cn~7eS唷-0BNh_w=Gw31OMM( Y޺5r˸g>dlN-;MֽLjWX33%%|8gpud9gJ(?o`#Wuę{v8GYYnuu9UQ̉}xTՊG}zm^e~'_]Tn%rSem*UZ0_Ìxi^\ξS%/R'!GWt3&3논)fG\Ζޏ?=?˙ß \XS׌V=5wx1Օ/P_ uUKzћ/6 '4,cPhqd3[P\YUa^Uznzu֭j)o|˾T/fD5_S֩2-BU|7R0W3OIRK}h_$I2TWu\GW?μ]M~ʜUVL\YGԻ O%vJ 5:Qw@ٺ>[V@i]Q.*P٩^BUif؝#Ջ_W3ܧ.7k#tT~ԩ-jљrO/3h婿wzˑlC9flZ@B1ڒ2KKGz\YzafOզ_(G1>כUx1:]*d3 @,Pxt9vzxM:pr知\ XWcSt]*Yj-/mC1j2 _M|FQd"Ѻܧ9q{a jہK.9ؾI"xm(CVɮ!p~]bG`| >=ccܩbڴȉ ^QD9Egϡ#%+ꆜ&rW9sx#]4+ oBWBnBCn7nllx 9}3gG_eI>L3>^"WGl?L%GuMfM#h!,f#G) 0f^SwTq5 ݾ~pf֝7/O;3߹:0˧eEkt~+B6֏1VUTUiWsڏ-Q;ldX`?~5JL6|_s7F( ( }T ]4(mR!MӴ/6n]I{M?~1vδn'Xa>8=|?,sƑ]7ЖREѾ} ֐rc>7*"*m5ex}pnEc?VŽ6'<::z1*R*vmcos?(^AO<՜я}~Esj!eQaɌu);G>]Gi?^WۨMS(2QB}}Ox|r#΂C'|:þWGׇ:ϾɊ_./0/8UنKqù|֊u}럲T9xK!/*_1s+|~<޼[)\w3IWsʑ@J.ժo?{yf֝ow+W=3_MYtlP3ƪccy{+͂xK+=ht; ѻ'6#B_jغ1aI #qcʃ<;y%z]Wrچ2 kj1Id~*(PQ0NuŦ?RTߨϟ>ԝ׫'ն({k85S: *UeI:_T_W۪=*lrUѱ/?^u!e7oR_,ReIsn>/uU+:WT҂CjoPej^;ƑFu|URRyΕw.?oTyY]ĸn~S̵s+xx˗9X=Dzu I'㠹_X5+#yܥ*K_Pg,_}l?^CېT?ld(IC%\ *Y#;IMKyTiGR@L%I VtISC&(JduQ^ڭK7e.Iغ[^B+ޥ:oI2E$IAL2~'xj1!LY/?O4?G;!CS{cyQ)eʽO>RB`3qdΜ9C!DklKถy/B!Td(B!(c(!B!D@Yj1/XaT8#t.,@q<.>ټysCBa"ZF.-¼5`/w6 2;lq𦏙{ށ͏œ̺B,fӈ`G`b61(/39>{VMnBX&_X1xn v8BE$ Al,j b>ph_[a0t *fEarf(c!C(ඁ< râcb@=M;eYRa,r#B!DDQt IZU 5 q^B!bd(Z N >"*R= :e8B!Xj8`G`R.(ҠNם-`9oWU y@\)cBabK, vB!LR,buTAmpLjKicZY>Z|ꒉBav@ϗ5iD$oz/lo\E~yK)К=Ǵ |Rc?A\DMv.!B!ZB|Ou:/*4-H!ٙ0{N00ͳZ0;2pF\Xs@Ka)z8#iiil޼9a!qq =D1zg"to`_O5z'8K : -z?\W'fe.6ι㏉C2GE}\ "9s6+f }2'|~{7cF!ͥwE &v Xz Sr4`FE«'{2 K~l fLaPMk;Ay!|~: / ۠K!|d婃ڃV qM\߫k?dUF\3Fl"+1_yIk1x8&8(~#7Nbb"-E 2,818iD)ܹ^LU)BNei<_/'`OJ>Eif )3`AEUG npj {,t`}chXZ_l~:; s`DHj ƤBNXvlK!EiV 13AU¯2 UCJ?́0=h&D+8(Q/[ %Aֶb焭 =NzmIջbۏoAL,xy,[!D (_!ą(ۉN*Z^&ps7fC+sAps7@Sb"`YK!ޕc`.˷v5Sn!=0٫ܵ nq_`{%kɒ% ix?Fȧ8rlU{sJ-0yB!oWu@Q])xm ZT!BQ]5}<}{ǡOf%OA<}Uj۳Vu>[Q>V gLB?x+Z˜4犊72UN׬ܿ|h3m)qQpUeĘB!Qcv&̖-Ad5vU8 7P\eԈ1 !άcy`!">B7-U[־}aVLp=ٷЈ1 !BY'B!2QlDFdɏu'w0(Iµ> Axܾ6THB2D111U#Oʏ8u g æ[jx4^$f!9'OY5F{FL8 BH!%}ŋf˖i|Xj(ඁ< râ ~Р`;eJ!\0ƈ1 ! \e*+q+e<'@%}ūf ik|Vf!`yIMlT 5֟ h1f!0-7Eu^ZTD#)/a]Whf_lg\Q2D+8(2T0bB!B(;i'=W蛚xUCc}FY!`ɒ%A8O3qت8x{ Q6e(G~-疗(ʊTBe(G~-疗QT@K v!2`2p%# fO-W0p4 w,Č"duL̙0B8(ZE7¦a?g.) ".#,f`wۀ***p SsUZX[X2Qr,OG=AU)8#,\@AGcĘl,fH׎iC@0 JcZ U/ZX[^2Q a BE }FY!Bh,m IDAT BJvގ>I~LUV ϰZP8x}erB!9;|ZgWu1۫@"4 EyJveFx>A3>5]Okg;( !BQM3aҠW2S*g΅`Wrޅh =}GuŴ46o0B8((:+': sb3AaN c IY0Y9Bs`X?&ɤOEb2}v̇?Zo[9SsǕː`h7Tqx~ V!D(F 4r^xI~a!)Xjө8u)=XK\eHnnn #nJg4w.W~)=74\,Ŵb6E۸ԍn' #5-a󐯷~` 낚Yg`ܫ0WD_@Ki޿5x8\3`uWt7}% >Gck`jh+X9Bbs18 Dѱ_:ûaϊz,=ZvJaMLRpₓ\&O̜9|B#2#rޅh 5!2uSa>zs֮3=>&eQ<)"d5k8p")_mt.-랃MLqn 4耓Ş+M}*< .zbVλ-Cߡ 4^-ҿ缴=۵6v:~fNSg$e󘅢$?NIIمuGmpUqɒ%~Fȧ8rlU{s<׊L0Ne< rҞ,('v) Z/AհMX[m@0Y8:ϥV1--͛y댢xЏo$-'ًlR_{cyQ)u`R"3caX$ìt ?zV0+]w&Jng38ٲ}NvPEUEeWwN< / ~DӤzgk:llKm! CÜ`y2I~y~9rB~DӤza+u(( !l04.gWu1۫@SۆX<{%k_#xCs {J˃<&wS4.؟-zOd(BXFD({#*޸*yfh1ָ/+A۪) [J ~CE KB! Rc4>gY#`jwPeӹp̓U/NPXM |/n}B1,5Q4-Uu>f}aVLp=,TH de։BLYf? .I@I<4VXx"A)Ca5l!ܿ:QLLL$77WnJg4w.W~ĩP{nh(g1JuLڦ&i&cEK-fk; H >^q5OvWŒ0x4^`b K ɓ'3g+4F{gµq*VLndzkZLڦ&iRǀ,fcL6gAnwXT Xc`YT" H\ e(&m^! \e*+q.(9BLڦWhRǀŮ(t90r"$55`L* l4%e(&m^)Z8o v^,N?3Iڦ1 W N >{%ڣ3_1 KB! RWGEttb񦾈UCc2V6/+(,Y6G>ıc9#6 ìSZ ZF$ C ֻ(f*ؚIn8Խ vC^,P]w@PXM ۼп⩇fwpF f^@$žc:5"i^Z-MٙOƥC0}-F6.R`C@y_Aъc9i9l([|,ųЄŠujD0q;`[jE3aҠW2S*g΅`8R- s8f͛BwE&vx|1H>ǚ(Xp0dTHj4 q^5H]2[zsӌVڴ%rJWMdD4Qᕜ?_ m'8^}k[;֮=$#Q@Ac 9n=O~7~^'iS^Hmŧ[Or` n{ :^zBF}u~϶  N >L2s ho'#U#wnNmz()vӵ|ZGøA(7*Ү:TB=XઑӍ[t/&^p<=yMC;7AXs7f@sAps%/PUŐE&'ur>!ern۪cwyJ M[r"h6 JK(Ӧ2 O۶#ܑ̍SQu<ѻ,Y\ixfio#f˱UeUx!L~|{F]Sõu_?)\u# WUA0X|seO`kd$ghS<+ y0BYT.ZNo¿-(4#U#6 W2th?JOr.Ivq$u';vSq'@}1,iS@$gUZ-ǔ43GX6,i?^I0{alO?w- k/r۪cŦ2q`:0e텕P݅朦OFNna[E\Ň\3`AI7|u6./|%s|3崴46o6­3lcuP)IBE$Tx.)f?I Geމ}D**Q7* ԼP93Pc?V'ᷙI9v9Z#f=c̠Ɂ %ݩp)-ر;I[񞤭 Ҧ{6H^F.Usނհ6*g$a(0-DU{@A/)f3b[5b"M$<+!j6ڏ|I=o|a6T i+^H[i)(20qmI]2rn!#U#,BL :@E)C)3b1fZv*|c 9#+ٽz;$B$m i+b6%E!BǮTc0W 2+ٕ]ӷwkV_8{q6vGہ섡>d(BLb EuiD$o9⍫uHچob6f MqQev o\̻]!BK祈?TEf̳3ChEͳ0;2pF\X*c: dޥ%-̻1Έ(BƸ >p;QF޾a}@r?*^Li(]YuEI$I$IOһ(fAVlOaP k;Ay!|1z/}lr;+i .,ySzE111`zx)V"^7?3;+?┙CBh{EREƐ06:[a0t *`,.uȼK9KwN3333'T!1e}ﭳt-4bm!PmNDQ $ n˳ ;,aX*Ȃ uȼK9Kޭw?.( o \e*+q}^ m+K@1x1C:9k0&vz guȼK9Kޭw?hu` X[9HVpQ 2TgV@]Yn !Af⨻ 4耓ޯ@W{nc3e PuȼK9KޭfXdIC0i:S 6ȱ#O͝y^QzV+w/L\@RŠxZ[ # > G֣ k7ۋ4yr[- +DX원>݉#, R^Ca_3øtH +82@[uȼK9KޭfHKK v>BEűܴ[Rhv@+{1P;12`2p%# fO-W0p4 w,YC4yr)=B+ӻ= =P')f?@i;QHE;fC\w*gjL*I4.,yGqF333aE!K(&S9 SZc::6[ ߳A+AdxjzT3 0wpKr2RΒZw(Bu`ק#u$ԱQM'mSEG1X3Lĵ(5`: dޥ%V˻B2Q n? _YNw)gkrޅU reGV{v4I zI ԱQmDQ!ֲ:U$1 EyJveFx>A3>Ol04cdoB!*ń?h IDATHEtlW ԩS j}qQev "mH́aĘCB"Ztv&ĂpիS*g΅`W&mH́aĘC24몧iiil޼9a!qzW=ixY:0+&w`uqdĶ!1c5s-(ӥHj]c2[UNh6/$uƩUpT6{6c1%B*qjD?{aX t)’7ûq{\إU\RW`Yc ~r<\ >xh(\ í{ `CVۆ,1euNs'Q)7pǨΜڶ' >u:w>b_ޟLDwGtcؘD}?ͦ =28oO HC}X7Drssu  dYLb.!a`iD)ܹ^By6C/ RV*(.Z+m <s_6}bކ]T_m@Ki{x0A|,j[ah t _g㣪?d @W HQP(+n[ ֶ}ikkEqABwT "{Bd#, d̖:0s̙gP껐$H4ƾsci"G:qz49K7vdi~NĆe9ػ;,;SG&h ~녆ÛX]dI$%Xl=K޸q2WTL&:J2NL׳*&>[qSZ4s{2&0 pn9c'@RiYsAb?ojł΀!#LERg~|0}a&Z}o(fh1z!Գ c[ lEt 7.Y,1<3bjEdBhc6vE lfaŔPV⢬wv?Z5sz<3X0[`'J8{<;i#G ⋊ی_] @-;`H)`D_h [pFX|Я5ƾ1lцP6tK1&' ѥ8\ :AjB3om讌0h~A~5Hj_t?o- tu9E#9*lj);Sa4FxjMlZ,H 36AsOBp<gX 9!2HIRmD$9.h4ci}C1Gc9ԣ mfxc7mHuJzquzPX:2[٢緞a&zw'L+W@?7ePjyJ;/ hijVpSP =êpsKwA8!+ .5ƾ1lцP6th`J((p&H(*[ҙS\[q{  r{:u%39sHmt$yykw:_% \g0vCD5#Vd8ăsڝLhy:g8rph~!)7?`Oay6 KWî0`>5ƾ1lцP6,bONkwyĘ={{Zĥbޤq ;$Rc `0P㌭˜@,CC-$+" gT Hw|*Η.H];` p?x nn 3fULsy }srǔ|  Wޭx]ʎ|0%u󎛇'] F ԟ`BN0vX }o(fh1z!Գ 9؉i#;֙C8Z[j5esqFj[+.foO'ViWmӆ1`?MYT~zzz=Jj#>_NC%lZ:-'/E/]g(ZЬ x H '-9n9~ ,p`l8^-Սq)N*VjJ'{f*3 DcfփՀlsg0AT,iaZ uROcPc66I&1eo 7;xf,gBAӡfܗa6~:75 Oxuc\jJy<``&:E<B+74ƘPDDk(r: Jo(fh14K@9p8k\V˝ENX"F#HEe)GS5׺WS'$%c[DwMϮ-{پ`.95, N*s8pFb4;?~DQDDD.xnA_NXI;C++Xodm;s!>%I- !"ЁHg v"f=}xQ<2ޝa|G0.0[xA3JCsV;PT(vg= uZhk1'c^6Cx3\2|[%sV;PئM233Fx b‰ь1/Od,w&[~>o>j^v(Uhփս~􇟿IE'< ^́Ro.a},YB5Q4iS4 i B>^}aڮv%8L&Â΀!#L?ޑ:=τ`MV!vsV;/E My e%.JKq{;O vçm/!@-aG h w1VSzmb,&_#ʟ},YD|iv/haۮv%8=+v8!2HI" qA(?X8g-a({C= -8 Y_-/mE ps~¹?%͜93!HuW<ՏŵO<mhY?/*Q<׫aWM _ I0ʂF*aǟ},YBf< RN !̾u3*gd$/a܆vxq"nOxo% ?w6~ʀpjg aA#>Q C%lZ:-'!Kmv -anLʇAY5];xG8c8z*g v{ZCDD™1HMd*skPt-&s2恾s`wüp f͘M*sV;w35qpҤIA!6bw2Ψ㌊4+pmƸԔN'-S S ]?AyDBn\#>Y,"~saXC|!m/;٦^Q)6 0-⡤\x?X8gH(6r: icܟ"+/W׶r%;bW¶gJh{Ed)GS501x\2Wzc?5'ua"hzvms)>/8pr;i\mE&P\ B8QFu~ka>1ishK ׾:(GV(z- !"ЁN_Un8ZGIpmKLYй 9wエ؟ Ӿ43 ;}ը?79$:,[,aHb0lt}J=..zvWO#WЛ&¥!% vm O-_|粢$xa)У 9 /߆/ |Mv] V/sjXM>C8Sioq8{ _/"#A;g`.%'ephv.YĪ'o'Y{zA֜˷CDD'9\~=t].H sS{۠Dž [ocLSfC.nJ \wxİt_ݏ0~p@8%afHot+_oKH[`c01!EB dX̪w01X_`Y!N9y>;S} Hmzs.[wߴM;WPyU3G6m̴@`NL%gϱMXt>ݓܙl4GS)8O=v} ~^dfl3G3 Ôaj`k0syS2 >8Z}z 7/?ógY_JHvxLM՟=vj9qz49K7vdi~NĆe96x1޼Vt>?-_=(MFnYM;fܸqLRWR1p"D5l":u0]Ϫ&og+tLҨd6Sk_?za.h34x)* 嫏'R `,3`|+!T0|4L_*l@>L8*%/?B,5mMJ3س}=/_^B߸LgAVk mӣ-ؙwtph採Ө7s53GKwDe@7k)/EYi)n]L{dz1 4xI>3 ~?J喝 0%C@ZM#BU؂3^E6v*@s5ԟkv8≥ˉnHlRv.xbPݕ1F1ۏWhHmj$:c'\MOaz[xdy&1f̀%y`zrkg\O8`h`$  丠y~:?*7ͩ?@,uro{ƻ,ӀmKXH؋8ΑM6mMO-$#']骢hxI³a+LT>~N Fν ߂SUPZ+A_kUEjg0EDSBA 7GBQ!E挦}޶%d]IkL!]M7` 8TDU3̙3t|@y@Rc&oWH!s#oq9q-#D;>K[G&9'h[O[+=x?h />aWmwT팧<׫aWM!; XU<_m?L,5)bONkwyĘ={;E\j/Mj/g+;@AhB*̢$`hF 1^/qhXQ8bpFFP(g :A2 "A5o'y;([͒>̆| |(Q 0qLt@x()|=W$f_Un )%5qCm;}U"+/R_׶r%;b]M?i{GH e)GS5׺YBn*cq4=reJ :'H,4j'~xHH0 L⹢T$f'ELڹZ_/)>( :(/-o1kpclٲ@!""AN(T#TE;&au@G ""mڴ t""B*Qz#q: !a(Hݔ(HJEDDDDDJϽ!̙3Jky) QADDBHX%O t"""5DD{*Q|hb# %""Ma(Hݔ(HJEDDDDD %""""""REBTDQDDDDDDP(""""""U8=mk Я~] ־DDD&V}p2p2^DF־DDD<Ŵq #7<{nhNl[#hH%g PҎ]4M,/o[W# \Y50{5tw_ӧ@}x#Ost3.`G׍IlX[־DDDE+ o@+`0|6ളoKDDkb[ lEt 7.Y,1܎%""RO(F$A+ gC'œlzB{g;9^Wu_?0n^^ ^WQQ^W8≥ˉnHlRv.xbPh2깯I&Uϙ3gҽ{wuƏ?7nꨎꨎA)SP/) +Ƙ^svǬYyq0L֘H0िَrbnSr_sE(ӤIqaλ6>$9v/Kuc\jJ+幐e %Xk/`U}6oKDD[܅)"x'b bBlMv}ԗgM.,ΆGaTo=䘪[G&9Io}\Q{uZƴ%KE+,R{1p`oR,ϷѾDDD媻n IDAT0uaɀAå-0 y~A?C'd_"""a]Nz<к8[[uRGk J52;d_""">`t2l1˪fjQ ^ %K'_7Vwx^ݗjlՉU!TZAaV-ZDa%b鋙ZTݗ}Սq)NY(""5,Qi&QDQDDDDDDP(""""""U(Q*(HJEDDDDD %""""""RE' E`0buC7 k%of_G5iw /[}XOp}?^ '_aҊvms?΅cc\v@{="@Dåwx5 >h ; Ϟ|F峥b8 o7Jcp$U$< \}t~iOØy^މcW.'mi^lf2G3pMR9/{x."[/A7/IlyBYuQ1[`΅cs{.S31 ~=Lϓb~C}6fLg?s}G2㠊 1.5I%(ZI0=|_-еKMRa s{y]Kʧ!gd~ ]^>&+Wы(e.틥Sk_T_ǔAY'2ؘ`sus7ӠxܰyTZUjLg3?F ?EDD3RD`q64͡}"'$;`owi%y06XR}UtXă/*%u drmp0l]<( 팊my4xxeʼn;@h3~u%vC^<|>s?CL.M|&?s]}#YDD$܅VLSGVv?Co?{wVIM %#o*s\|_`|(^>ۻCQ.աww_>¡sQcW-<}q@df<0nwLM,v?՟kǟӾ,"""!(B`îPjU}n ;7 ;aZL S7ta>>z)C(hy%``*(lK ·[}y`-}.cD-ijVpSP =êpsKC4<$DNS MZg7."""@'&oAgC#ϲX07lr|}5̀ ^kwB3gtг 9> [r<2 =^|ŹQî@zsQױϡypg~㮂to?m=\9_o־I쫨3!x؟~Fr:0L dRtЩ8eD6 lW|ԠR n}NÆusQۉ6T`J`6rRTg<9'ddA3saKכg;?m g$xۯ0 1wXOf0fc `\aֽo(& fɗjLǘ't7Jo1+0[y7!ɾ;_ΞbeC#}߬Ǹ^Ĵ?υcWvǰOt;cbv~)_%ɘN/c3g?[l g-VjJ'{f*3`Yw\DDB1N㠈ƸԔN' gEDDDDDsJEDDDDD %""""""REBTDQDDDDDDP(""""""U(Q*(HJEDDDDD %""""""R03qPDDYeYCDD$hhp[OEDDDDD %""""""REBTDQDDDDDDP(""""""U(Q*(HJEDDDDD %""""""REPh>{^/+=y ,D>xO|;Z!"XT7~Y 9mD.4,)QoϠ1пe-v +&>w(E3$![8/wjRovgoD.`>_=V:̙_G&"j-uؒp_YŢ?qRrj ΁4,)Qr+;F4N0sg8/-mwN>7EG2L =5e[޼n$MfͯN czU8~"}7Nmނ.R:۹xڨT~ 6GџoC듽dͼ_p'//xNHhk9}ͩ_Ni;+5T´X _=aO).-6wM͌N\/ʴ~y @))>l\c>t^i2Y?2/MyϬs:{\6bWkuUEExUK ˑf&/(6[~2 ;s34q6[7]Ǐӆvx46U_44t:(Q i})3e jyͦpy&'ԭmH4):a^R3r7o1uaܳeN;ja.vSr;Ҥq\e& ࿘/|w-2 K7k))<6j ƵoH:.{Jk.2 &UTTP4~ZBu:r\e0x9̤cVu#]n1|$:)OURl' \<)_fD~݉b!ƒw~|Ӫ|8b66;kXn4mYiij|7ϸM2U Qc>|G5,6>iUZ+fyAYs0.+6n2)c]/6̗V;@;&»N=~n/7s􅯛 ^59k0Q^6Y_4f7m_ƥ_JpWd~e ʹmHp޽rvTMx*8T(8eY*!^ nݕJn ۖﳽgsKsXe/c`TELlWg3N\.\..Wo^HD4R}==S:f~esn^8=j oe7;Q}ϤI !ʐvvK,vG~=n8p8,[:A44iGUig=Ssc!0~U˽oَg_{0λ>OUj Gل 󋾟ꫮO{.{7v8#:+U|-~#Oll|RDzʷڪ#)ώk hߒ'+b4?Q_c>rݘj6XgǑ@]SDL㗧B`֑/ƃ{r=n}oh</d|v]?'o< ޵#8KhWӌƑ9X־z?kVlwU*e%дi-]:k}I;JeÖ}իu)[ӫ] 8=N;`1Q2״N=qէD3 Z]~n{JV-g'<9QXd5YMyS-mh/S]Q k ڜu&m\l9rG"\}܃1q&Б:ֳrM)_G&f7hڏv'Zm`m~2!F|>g*c2ޚc6?;9ϛfa_icSiG&Y\ʩxwɬ+uDk~<Qm̺^)~;u݃'^.{*KvڧN[JIDDDDD'd23g:+),D]0'PnjhDDĎI333Bױ=O>w*v]0'B| xzcF|\:ra\]{uAQDD`zxx=XWhDD%~e(4vظh(~7lGED.<f}[Ŋn:bal^kTNawK쮹H`9!>ju`lD2%`JײKxnX`cϝ7cMeXMɁFDDjIBt19y.0 {Ne֩`KYJH@8]Aw㢰(DDD|"g%<DÁFDDP(""">eE@L4DAD[(O%{n,UElDDDDDDlٲ@ ""0<nQxBH=8z3z9^[3sxV-+Sֹu*8(""2b6m t""z0tL"2d-6yPrԳ:8<^1q¢@G$""BD~Mkd.y&9TJ$jr\)S`@D9+'%"""#s~ztؑG?#O.=Cš]Ǟ=S`: iIEDDMטZm[ssg5S'8YNˀԋ2CK@G#""DQDDDDDDЭ"""59+*&Y^BDD$(X e`DDޔ(${n,UEFI(\UUDDDDD kGׄvW28z$w3S~ Ya:KԽe0 : i(+5ٽgs1X9g7 cڷ! / Eޚ[\jk4HnKMtRM6V2bfff`(_bݝP<8nܸ@ ""!px|-;wcj^$< :уbX|p%?nHQ3}lYoes¤Oa#5G}pr",2w_R(""讌0h~'^ MD2mS#9;9hz@([,⻜٭v6x<5hwqwߧ%e˖lFX^-`x8zH I⤸SpIUj&;y2 uo L.s$C`0a"@"[^1^d˒X^u!FVKnIH?:|Y z*""}z^{4Om(>5;Ť1N7ę}iurcl\C'ԍ=9"""b+$O[ .^$S:?ua1 5nSSI6J(Jsa[}w6;vx8vQco{[OF}""')S=B|J7 .9Eߗahfzm: ;1!P~1Wj#{53{&О"N$;8tOYP,++džED$. J3B;w ?޽xpاrrQ鸓xEDDDDdL%S^^: `'>]M؈FyW ɋfB!z|[/)]hAܩvho2(Nc oؕbu^IED$F;Ns/óq'/"" Űw.qUѤҳy<(""<>wJF EpdlBnʛ>cT0Ý-;C:k/T1p S5d/QSHlB1??xwCDDʘUg{xt,]Ɋx~0ġKs6+Yʔ hv.R2x93ݟ87t̓Yʋk^WyR""2[)7nwDDoi'j;{='N&7c4R3MMMnOt+ M+ٵ8g/Sw0{/%W"aypz xaXפDD,S(D]0HKLrIvO')o) NWb+`4%E%]>Džorx큁<譧"""cbO]o{x'Xi/e/Άx0e.7ÍIO<@S`|ΩaљL.ݾ>]Q̅d6|ە#Aj ¾Zv R 6s4^oku xwADD@r?w1Nm,|z7tO[ 9ޗC\B̓7ojT35)^z㩈D.:mj [$|B\_>- [w #ƛmp XYŲ2}CJDDNέ+cԲx7ΌL硽m9,{-anR+/T4rmMirɝ-5  i?Sȝnj&c̓'๗1OFDD,BH8 7YiA8q:` u))6kR$ئe0r=mILɦd"OI6R=ߩ`}'"Ǜ??󟋈XP*~EMX۵v "Pɩ=oqj9V\`gUNI(z ADDD(͊woDD$T( TDDDh=se6ě E3N$"""Bf)B*$4=8,;II:*""""" 2W# 4fUl$43I{n|#xOEDD$ƛOn-ꌈLzF^nyibF'[X)0{9Y|=>,""A89.!󠈈$P9./hH;z??6YWlH|QEDdmZO=<XNȤeBqƍcK0'aÙn3D2<8~<0,pES""2iYP )aW~.  GLbzBDDaٌ}>3SFu66 R }zLNǻ""2Q銢}.(;YNDDDDD2Nyy0Љo`W;jL̓7ojT3',S(6449hʾ`!zCDD&AܩvhoLj(++_r? R4邢L ̓'๗W?JIK"& a\U4,o<'D2<ݱÝcJlˠ` Ϫw֋|VYnWm?DmugIfCN6tԒoYdmMAiZe Ő,< SF9s5vӾ"{Tu1GO^:gHvQ\=4w]: Rv줽k9說 LڟHZBQŷ ӠEŢư]i"Wy9g'or\'is *΅?ٞ>V߀6Nt6>'?}~ĴDYBJQD[^,Ʋ]i"_d珟DŽ`23n1{̆y=*""`#{َ̫[gƲ]i"_b=lr}^ۺڲHR%`%S?cNC+3dƦj?ze3aƉXb>62b7WsT}B]n v!}K1p-`(Lw b_ HNK#憻[s ϧH%)MӉ68+SdžuXŐ68rbշI 'PMu&}[lۅ-aO%=݅ÖNL'#@O7l9,{-anR+/T\oᲃۖeAaZOkʘ7+wyڨtr{1ҍ x8=׌6|IQa8 ʹYC|/o~Br.gwS39%yj36ڷXK2~sBoT f51Z#d; {3N*eo/ӳJ9syd%n$%ɀOKO{D""Aڌ-WW^.7?.>[GU-8=,V*߱eo)yE&0h0Msȸ>l޼9Tӕ9LvĿ4L!BmFC܇prݜhO'LY04hֲ̠0* ?6=]+2H8ۅڌHVog8KfU(GJPI&.sܝ1U?_1p/{w6pc[p{_s6qYbAcm8RҶԾE@e> I}pn+T 9*.w_g{w=91zb5N%Bh3|?xV,B#6\QaO= {+ we ?!]yq\%8 l58TNZ G*ɮ4S pP!XHSLEe(?JpHY 0t_á3zY&JHJ/ݟˡ7 zme2=x3Cꄠu*ve2}uT,bE"M1uyE&W`q}ؼys Jn&FhcO5]3d8h0!RqX8i܇pr`9*N5˳/ uPh* f>m~|my*66"8TNZb)A[w0$)V$SіD9>eNsl.xk.M<g":'HqbH "oT(Hp~;P_s{S]-S,AQg')͍}Sgj#u*PDDD-2/644M cr5Q0bշ6QTfeڏár><GcCT&HŪ0<(""V* igBqpXnPsmj[R86i:"Rj8_B5~f R ZI]q;Ks49\AMcVw_4b͵"""pb~~> -Efa sx/K@Z2YD4Vc/ K+s rKW$_ OϹ8񞇹쪢֓BޭBIDATH؜3t J0a9ڈȃcuw!IӜ {hً)!B2(nܸ1=0ps`7aQu*EcUq-[ vTIvTpn- ?&0TZ?dFZq=|6ˢOFµϧ;vp#Fj7X|~]O"Ѳ+S|e Ÿ3XЃL5(ȱx@T&hĪprAzRJ] oi8ÝNR26zi%`jfIi*CPƔX;|EA6t461,_o]dnZ3>z{ÑJRde`&-gI4,sE168rbշIe>^ M3,NeF* r \ú&)]MቶWm9,{-anR+/T ÝAF͜EQI v/WT]8l t22{ tҽ ?^>cUZΒhñw7oO?N *''F/@1{{?jS,"֎ñGI5ܾx3]tC4\.µ{򑇍UbB'VNqIr[ ~p)mv!oByPDD&ph+B?ـ+{=1v7=sS767?a CT&ƪp$=4~W_sܮP?y J^ʱuӢ G*Iv0yNJTDpT(FOcq)i)vܡd6l#h&6mYDD$,EhxTW&JLw8STn߇'6nK%^S ;)OuspoS/eޒBk`~$[>ߖϴ,Y(# |ݍر藕t"5/Q(""[&%=:IT,Z~B g:)׈#5ix_?xRWaZn6HN'R#K=y˙7or ~)'N`ƍj6j6jm~i"rJ/)SIu:Oܤtz8/AQQT4r̋4M3""b=Pml3Ѓiz7|Xo'mgW{i P c:홑ȵB帼ܢ!,uEQDD$Z>/~Rp`8qft"5/3"""79>#EA6t461,_<1j^"""+"""r \ú&)]M6],NIPxÙh%""zFQDDXQI5ܾx3]tC4]{/µ{a:KDD$|>BQDD E-BQ( *EDDDDDd""""""2 ED BQDDDDDDQ(""""""8݁I1[0mt=4Gc6.ab lr'M%jqd0w,-ejK8q5=ӊY.žF_-[Myqqz_\X~{b~‘{~*cO禲5,%NFNmE7bϣGd%Fٺ?A*AL<8 E)aÚ,Z&-] wvNx"~&| ,^ ~'FvLw7*S9:<:#3Nn\uޠ֓Bޭrý^~#ބ3t J0a๶1=Y9~;'}l]c\i%|uC@tdꏃU=T~: 2s]_}uPsX[>6b*STORTd΃PeRrk;N5í%ؘxOW!e9l[dW#{W89KԴ Dtڃ$0TZt'&>d~>'-\62ev؁k:\q4|zQ@vNMX!"˘ͺHcŽI96HubePP0g3⭗+ɺfc>!>*fb#pR?A ʃ(c[(; ֓2k|kwpnI+>9)y,( .tDO[0-IWò4O g}'/Edm{ G%۠83$Ẑ{lY\=\ࠍ"&9I{W7pupօu?[v{$;0tvqϺFC(lG',Oz}(xʃpݘyp6TzHɟJ~&H`\o L=yH g1+/ oY\ }r5{6oJʬ}{$l@{4&yܵq+c.u?`.۳xxMӢ30䞝䯿s)w8'$GOLx PNG ʃòFUAZ^Gm/~Rp`8q ւ:Iϥfg=KA \N'+˜=`OM%ـt?xi8m:+4^}K˯-!^]'^񺀑{!x]\8ן]^z?w)7_?s:]:;pmii$xOo<_ӟsXa{nʃ<(~*ypV\`kXaP9:><ٳL)]|w7O5G,*@)],|/鷬faz;G?h gr3H´(*)N{cT]8l t22{ tܺ9F-;w}ڻ{#ן0~{,c>yt Wo=tuxʺ~4\vp,?LRVhE|OXs8a<f,٢#ByPypQTU򠑗[d^l<=hi?C+\<.]:ˡ j"w7ҹy,.fl~.s`uE6A.aYOvSU7V^-6.thG_tenY+xdؾ<{ty1ҍxxDϮ\?uoȔe]ȿ|=(/ECa>F)cެ Ii}|>>!>*fk 1k<)Oy0"QT G[4$/EDDFZ[(چBQDDDDDDQ(""""""PAT( *EDDDDDd""""""2 ED BQDDDDDDQ(""""""84c EyPDDYB0XCDDdPD[OEDDDDDd""""""2 ED BQDDDDDDQ(""""""PAyEL(""""""PAT( *EDDDDDd""""""2 ED BQDDDDDD fwRIENDB`tvxwidgets-0.12.1/demos/plot_custom_range/000077500000000000000000000000001506765256500206575ustar00rootroot00000000000000tvxwidgets-0.12.1/demos/plot_custom_range/README.md000066400000000000000000000000361506765256500221350ustar00rootroot00000000000000![Screenshot](screenshot.png) tvxwidgets-0.12.1/demos/plot_custom_range/main.go000066400000000000000000000073651506765256500221450ustar00rootroot00000000000000package main import ( "github.com/gdamore/tcell/v2" "github.com/navidys/tvxwidgets" "github.com/rivo/tview" "math" ) func main() { app := tview.NewApplication() sinData := func() [][]float64 { n := 220 data := make([][]float64, 2) data[0] = make([]float64, n) data[1] = make([]float64, n) for i := 0; i < n; i++ { data[0][i] = math.Sin(float64(i+1) / 5) // Avoid taking Cos(0) because it creates a high point of 2 that // will never be hit again and makes the graph look a little funny data[1][i] = math.Cos(float64(i+1) / 5) } return data }() bmLineChart := tvxwidgets.NewPlot() bmLineChart.SetBorder(true) bmLineChart.SetTitle("line chart (braille mode)") bmLineChart.SetLineColor([]tcell.Color{ tcell.ColorSteelBlue, tcell.ColorGreen, }) bmLineChart.SetMarker(tvxwidgets.PlotMarkerBraille) bmLineChart.SetYAxisAutoScaleMin(false) bmLineChart.SetYAxisAutoScaleMax(false) bmLineChart.SetYRange(-1.5, 1.5) bmLineChart.SetData(sinData) bmLineChart.SetDrawXAxisLabel(false) dmLineChart := tvxwidgets.NewPlot() dmLineChart.SetBorder(true) dmLineChart.SetTitle("line chart (dot mode)") dmLineChart.SetLineColor([]tcell.Color{ tcell.ColorDarkOrange, }) dmLineChart.SetAxesLabelColor(tcell.ColorGold) dmLineChart.SetAxesColor(tcell.ColorGold) dmLineChart.SetMarker(tvxwidgets.PlotMarkerDot) dmLineChart.SetDotMarkerRune('\u25c9') sampleData1 := []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} sampleData2 := []float64{10, 9, 8, 7, 6, 5, 4, 3, 2, 1} dotModeChartData := [][]float64{sampleData1} dotModeChartData[0] = append(dotModeChartData[0], sampleData2...) dotModeChartData[0] = append(dotModeChartData[0], sampleData1[:5]...) dotModeChartData[0] = append(dotModeChartData[0], sampleData2[5:]...) dotModeChartData[0] = append(dotModeChartData[0], sampleData1[:7]...) dotModeChartData[0] = append(dotModeChartData[0], sampleData2[3:]...) dmLineChart.SetYAxisAutoScaleMin(false) dmLineChart.SetYAxisAutoScaleMax(false) dmLineChart.SetYRange(0, 3) dmLineChart.SetData(dotModeChartData) scatterPlotData := make([][]float64, 2) scatterPlotData[0] = []float64{1, 2, 3, 4, 5} scatterPlotData[1] = sinData[1][4:] dmScatterPlot := tvxwidgets.NewPlot() dmScatterPlot.SetBorder(true) dmScatterPlot.SetTitle("scatter plot (dot mode)") dmScatterPlot.SetLineColor([]tcell.Color{ tcell.ColorMediumSlateBlue, tcell.ColorLightSkyBlue, }) dmScatterPlot.SetPlotType(tvxwidgets.PlotTypeScatter) dmScatterPlot.SetMarker(tvxwidgets.PlotMarkerDot) dmScatterPlot.SetYAxisAutoScaleMin(false) dmScatterPlot.SetYAxisAutoScaleMax(false) dmScatterPlot.SetYRange(-1, 3) dmScatterPlot.SetData(scatterPlotData) dmScatterPlot.SetDrawYAxisLabel(false) bmScatterPlot := tvxwidgets.NewPlot() bmScatterPlot.SetBorder(true) bmScatterPlot.SetTitle("scatter plot (braille mode)") bmScatterPlot.SetLineColor([]tcell.Color{ tcell.ColorGold, tcell.ColorLightSkyBlue, }) bmScatterPlot.SetPlotType(tvxwidgets.PlotTypeScatter) bmScatterPlot.SetMarker(tvxwidgets.PlotMarkerBraille) bmScatterPlot.SetYAxisAutoScaleMin(false) bmScatterPlot.SetYAxisAutoScaleMax(false) bmScatterPlot.SetYRange(-1, 5) bmScatterPlot.SetData(scatterPlotData) firstRow := tview.NewFlex().SetDirection(tview.FlexColumn) firstRow.AddItem(dmLineChart, 0, 1, false) firstRow.AddItem(bmLineChart, 0, 1, false) firstRow.SetRect(0, 0, 100, 15) secondRow := tview.NewFlex().SetDirection(tview.FlexColumn) secondRow.AddItem(dmScatterPlot, 0, 1, false) secondRow.AddItem(bmScatterPlot, 0, 1, false) secondRow.SetRect(0, 0, 100, 15) layout := tview.NewFlex().SetDirection(tview.FlexRow) layout.AddItem(firstRow, 0, 1, false) layout.AddItem(secondRow, 0, 1, false) layout.SetRect(0, 0, 100, 30) if err := app.SetRoot(layout, false).EnableMouse(true).Run(); err != nil { panic(err) } } tvxwidgets-0.12.1/demos/plot_custom_range/screenshot.png000066400000000000000000001032701506765256500235450ustar00rootroot00000000000000PNG  IHDRQ?.IDATx^ e99Qq88d@H@!$1$" ?QYeDe0OY\E@ }_pTAeoU޾OuW}>s^'O}RUz$Ia_җ'|rq]uUC-_ Uq饗_Wnm-Lws]w]ꆺ^x_4݃Fk$֫l+SS?+g͙3}Ookzлի K/|;PVr/[xqaZ=C=v-phe _{ڧ],zF]* c۷&(c UԮzm;SH+v-phevitݎ:4݇՚v傲5R%&VS C{Aq2zJW ;?p7tSmuя~T;c+z*)|I/?34ݖԏ[>[7;(n&1FJAgysMo2۶~~~<@|}!c lyl>~;C?z=C?y͖YYwej1StA䅡DwqGk gitSR%\: w9W~A3t+WLc1WOg׾$uM.-O+t=[v[pa:.cYYz~}7ellzzM7-,{3mo~2[.4o4m\{9v,}m`}szԩ(a'_m;3}Kks >t~Zc[YfKdpg>tcܹs_:MYeBN;-=ն荇/t߮rCj-/[/fˬ{z۽]17ȧA18l ?V9$5[f5ƹ]zWaSCcP=rS/_5_Îm͖Y]\ގvSKFy{CqTQL~mb5}ْ[m̸q҃?2fn~WR;ضEeVMSGYK~;Wӄ(Ơz&%^ klnAm/ GeV=h+4IJP3gc%snkGz'Rlд ~n xE>x6_zz'/}K1Ov a@j/|%/~t~v;C!f͚.Pfl qѠrDn˗c2LYeBVoG~{h AMJL|AsAYi~t>S,k-voWL; )%lbP&!%^"9olwjSOM|/;HN<~b={Od{u1_rv7cg;96Զ|c]k-}\+ˬ&2,^!>Gt᷇Ơܤ/=*_^݁Ӯ~]MeV]1SKD04ȳk a-{5Mb !ui4q6Q- !0l0}z8%[ӄ(Ww!VOg CnNeeb\96v駟n8Vw}CfT[ӄ(:W VOgp6O|"Wմwڵ#Lo[g `8 ~3( ȧSoj!ui4q60wn ng̘Q|34!1TQgЮُcw+v2~;&D1&6vHPiVE7֭[7足oyzFIEӄ(ĆhlQGi[nIL~wÖcƌĴ,`QM Cios=]{鄛n)Li8jԨLF!@4!10(8hE߻;L'?s^~aa&DiBc9+_JZڋ'x=sɊ_i78%fwv˖-sk֬q/v;C!Fv۹ իW%K'[+b 7g7jԨ|P5qIH]&w;e1{d}w){[n'~]C%׿Aq^f1&LH ɓ'1cƸ]w5-[|g:??+~nm:}ZtΛ7Ͻ=q{Oa^2q@^ZWa(1薿vGY@ >q=@cg=̚20C+)@Q+fϞ=ͮ͘1[Ʈ:Zmm-J E{nWP|?}ifmV_''41uE7Znlz `+.:)Zw˹s e0(rc]HNںvZA7wBl]v%ZfWsѣ>Ajoya~( W6Ђ9qu+~Xl~\3V󿘸Mߘ]|偬˨.n( H6l/_xVey}t{ܸq.eԏ  !@Q6Ђ_7x;bu+^?q{O/6s1Y1ڃٿ6fя}ٸ^Yf( atҤIi7|c= 1i4CaP `+.9e$;e^}9{ncGcY:PQ+ .]v);vl6ktƞN;T;eʔ´ jؘ*uGg(UԮֿV׫,m[h66pY2XEFm>gu%WP8%ƺΟ? `l\`Cj7mݽϲ#E9ykzy`ko*qh?~Vm|3}nXS{Zv7o%[^O|_^v?Zt%(rcܬYٸFw%h-}½{Pv52% h EWR,mfM^?'Ƴ.3'cd6~к쎣-lϬ w'ӲVPEpFc)0(rc7ncviӦcۧӬ?8jӬ{ ʕ+nNҊPooַGaP Ϯ]D+_Q1_804?ظ?ޘݼ[wײ+6ŞuyQrcŜ1nɒ%1&/")i-gEݡԦٸü}#)̋hPJSbb3aq@}&|hzsh+sも$%)1 K7@FC]^ku= @%)9NJSbb3]I#丠`*IqJ U$丠pPrXulPhuln+u_7j!!GPr j9yCov׍zFm""丠PJSbbKaもCaP(9N !@!丠`*IqJ U$丠`*IqJ i1>zz'w˟kg&丠ЕPrJZDO>3N 珞?אLqAѡ0(f$ C@9.(8:㔘PB !@8%&6も$%)1ƴwQ]9}B Ġ#'f 3D\.zs. JSbbCWRBqAѡ0(Ćr\Ppt(  %)10( CBqJLl:QYi(z;(7\}B FzL1A;Ͻ3r\P08%*r\PptJ P(9NM'OqATHqA!@8%&6bX6f%D/QsFkOO1Hܘ-1!:q=X0|]FN=bKq^Sѷ}7x](,FZ,f„ i7yd7f뮻=cUO z݌3N;oرv1?)7=w޿>9n-òvT6B➺%qXڕI+@P|O ydϭ[BV㔘yٳgj[paZ tR> Í6(-:n|J:'oÏHl|%=wdXΜ{]|p9;+"/g޺s%Ɵ/XҩS5jTsܹfb rJۧ ÷mig]M]SY@ ~~~~WȽpO>qX1Ny@+2\Mӷ$S+( {Eу}yZ?_ e9Nɻm&bŊ8cG?_ + wނ ׊ӧWyQe9n-{"w1{O/Ɩ9upy5w7g[XWQqV *1|`$8%&/ UܤIn;/WڸE+ L}CJ0EaP `w)k/W,Ɵ/Xahc]~o~szqĉm zkf5~{urc~ur[ub۟{q{ `+ ^m8fYF.:)IO]GcWO,'w̭ٗv y6ZѧP+0l#B.=+2svc7|{r֕ԊR:y֋'f!:-:rϽrZO/x sX3jb[9g0Ɋ=yZܕe7}mͺ+":'BPV+YYwFw%x mVTnVX{_ץq[:VϓEY@ ̚ĽrO܍gg~mԮU>^WÖg f8~ gŝzv#04FRYSbƍ^ճnGvӦMKs?6j*?W+[o߮0Zhko~S(qvWH7$uԟWD? qX1E`;mK,Iޏ1yi?W04ǏO/|kOeԢ0($08:㔘شZ丟^b$ c-ۋOqAT㔘n3'oxbb$ c-ۋOqATHqAѡ+)@8%&6v%!PIJSb"!G+㔘شz0q@8'Dl۫TqAѡ0(ưĶzj*ݾM CBqJLlZ- AqAѡ0(Ćr\P08%*r\P08%ʪ0 ۰_۷もCWRBqJLlBVOZUm؍/u~YqAѡ0(&0.!GPr CBqAѡ0(Ćr\P08%ʪ8۴u~m]qAT㔘*[[i۶もCWRBqJLlJ P9.(8:㔘PB !@8%&6もCaP(9NMYa ~mOu6]^m?r\P08%JNڭq~mも$%)1TもCWRBqJLlʺr\P08%*r\PptbP(9NMnm~ڭ[{'}もCaP(9N !|ݺ;}\/cU7 CBqJLl CrB !@8%&6Mސ NHc7$xf1F/$[!ŘsKܳܟ_^{cP5qJ;-[֬Y/^vaBBϔ)SӘ}ǽ,j㒐.Lܫ}ܵ'O$n̖ŘfN>'NLc;v;wnZHo,̯UyO'`*4X|aIe󸃊Bq^xkw9OK&#+=wmW[ )qJ̼yٳ-\͘1[Fς ܬY_ofi|0^JZND> S9 /Ɋ:=]ā{LJ7$}g(ΏphΜeyq"m8%ƮM:QܢEҫy~le>+Vpϊ}CbaW6Ђ9q]~cŸff{eW(>W=}&qw^PXf];=hpiQ|PuFrwlM: 8+2|lܡ% 9sGaP ͺsw|XW]y{O/Ɩ Cw'຾"f>&qcG'S0+֌u5hE8%&/lߪUܤIma|vmt{^&ӧߞ{Y!@Q6Ђ32zͳ+}ִ)0|쮤vck C+8+^:]I14VYAw6+l<8% K]A0t e>V ^Eݒ%Kv%Etcʱc)W,m[hW ka֟U-c]G+8v˹{b)kZFmݝ/m/V?b4Ri&o+xc Cݽpo[ri 1։HľO9rUrZd ٍd֝\5Vmn`S{Qc7+ R8it%#_+n8@+VtzrcwSqXs~Pc7 k??ѕ(qh6~l~lc?Le_.N[g&/eT|xp& &gem,?/Ca+ʬ@n~\;t_YSbƍv=z6mZ܏~i66Пg-HcgΜN !@Q6Ѓ韺%AzWct/ݗN*N3vЮ6Zwҧ1vкphqzhrgcP1c~ɋ]v٥0M]%g} sEGPr j K*OB  >U:1 R%L'!PIJSb"!G㔘Еr\P08%*r\PptbP(9N W Ҹ7.cB !@8%&6zb^>g(Fĺ 9.(8:㔘PB !@8%&6も$%)1TもQSޑۦkpdZTE@u(9NA5:'2\~'丠Е'>5PT{⎞=bkb| CqJLlJZ_'f蕂\~'丠P9;+*gպs=# ZĆr\Ppt( .4ʋg(gUqT㔘PB aYƺfEH2%)10(  )[Ye*.3jQrjuO,u۽\nIJ 9.(`7m|^~*.3jQrj,VZ uvM,もCW}費|cPePJSbbCWRBqAѡ0l̊)+-'d*.3jPr CBqAѡ0(Ćr\Ppt(  %)102'V2֌\[sIJ_ 9.(JRrj,VR0uvXK!PIJSb"!G㔘Еr\P08%*r\PptbP(9N W .q?x4i*nn5もCaP(9N ЍĉYT`6V# 9.(8:㔘PB !@8%&6n(rWk瞼y nwϺ>wfTf9Nifwv˖-sk֬q/v;C!-^nnŊnΜ9nԨQ8TBӃ#qןSpb\#?^b6yC~sm~}M{e>*qQ~P5qjL &ɓݘ1cܮ܏m}ZPΛ7Ͻ=q{O!1>Ux4_ط_WqZl>bl^/]AОo}:mڭXӺۿ[c9jχr|a{ |]xb1|1޳.q؞İx g !@,ǩ1x@chEߒ%KcL^D.mlb^>CaP9.(8:㔘PO'THYctbr\P08%ݫ'fU6҅ۧHoも$%)1TもCWRBqJLlJ P9.(JRr@ 9.(8:\1(Ć+n+:9?gE':もCaP(9N O׍zE'^vB !@8%&6もCaP(9N !@!丠`*IqJ U$丠`D`;w׾}kLUݦhTq@U2\z3U 玸@qAŮO|jdw칝ĭ_Q&@+%ʔĆ#'oU2\J/v9.(8:V9;;IOrvҶnnOuZ(1|FqJLl(  !G C;i^4-?i{{E/; oG[5JSbbCaP9.(8:X埼 ;-zy݁V(;J?ߪQr CBqAav▟՞Y =ݢh%)1@3T%˟]3տ !c d|O~7n8ykh%)1@3UY ^ Q-]9.(8:֕䷓d :?Pv*SrB N/Nna~r@v"u^^wߎSUJSbbCaP9.(8:Z(9N !@!丠PJSbbCaVUPǾg߉も$%)1@3UP ^C\]Z;r\P08%*r\PptJ P(9N ]I !PIJSb"!G+㔘pŰZTe Q`Bv CBqJLl( !n+ݨ 0!;B !@8%&6もCaP(9N !@!8= ܭ`Yq!q/ݗ3185w-[̭Y-^FmN-ZV^F]@%8=;w;/)5boMܯILܧW%w?JO_Ľ@==q|"qc,t)[}/cQ!zM'N_,ǩ1e&Lq'OvcƌqkZ s?9sc=oTeC]ϡj+v rlEjk(NS-WY:v{č=vaYq붮O|j$w칝|_QG!zM'N_VBb̛7͞={P… ݌3 eƏv7n\arVeC]ϡj( n!;BӂgN }.NSmM:+2/wڎm__Y|=Tiځl=߃ k:we9.$u!QF]AΝ[-^{E^!@!8-@;x( ҽ{]z"/>g{{۟9q]I'+tSah'[Eуt'[Q|3D>k8帐2y7R{6۸˗+Vš[fҥG+(WZUvm qrlly's%od]@<̡˲XA̭/ޛ:qw^OӋXW-ɘ g^}p(q!1en@cݤIn5e7oh_KaP9.(x.Nܯ.7c W!uY7|e䔁[nƮP&ve'V~7-k.tr5Wc]D8MoꏱvϺ;6mJah76mZ׿ӧbQM!オ]ծĆ1ne;e9nA.rvoKy(qY3fE]-{䇉[Vn`'Y6v~>CNbַڪ~V"wmY۞{0p+)qhWfKX3jb}@9Yahc6/xmW}N.γ6]5prt;zJN֯(c-Z|J U3uĆもSIQ~rus{0<S>C%Ɵ/g2+9N !@!丠T0$ZAOg(Ãm:3Tbb*~1/㔘PB N Cc]%c'Q{0<S>C%Ɵ/g2+9N !@!丠` ('˵'Jf'K6ۢug`U c^f%)1Tも1Dv;97&o߽o$Oz ۢug`U c^f%)1TもS&}k'Ov>=?1|S>C%ƺJSbbCWRBqAѩRahN 'd'N~ۢugĠ\?YqJLl(  !Gj!`d(9N !@!丠PJSbbCaP9.(JRr@ 9.(JRr@ 9.(8:t%(ĆもCaP(9N !@!丠PJSbbCaP9.(8:㔘PB !@8%&6もCaP(9N !@!8= ܭ{a} CYScTl?~|];e˖5kָŋvءc(  !ݑHܩG 8xI1ɇ'w1on.JV?/,&GaP4qjL6M:5-X9sf!F1azj7yd7f뮻=c)  !i!qgk(N +w~{]Vp( SC[hQq8p޼ynك.\f̘Q0(Ϝ`]woHQe9.$̛V 0.V\Gs-RBӂ\`6q/ݛoIܥdW2Ec2q-brB<9y\Y QRHU\|[bEZya諝s<9!i6$w7ڃ*/2ߝ&o':aYL.Oi<9y}+q!1vvUVI&H) yssB 例e{쎣kO bklZ- .]v);vl֨0@Q6 /'[e[}n97q_@%Ǖżou[mUFmT5ut]N=ܳCe9n-w%nnֽԏ56- nq]I,DžĨp7.+Y-X]IP9N >ly^?qNNٸc??+I♉K`,pX !r\HYaۧM8}´qƥI'NFMs?~6Šgop`^/qTf6VĝjU0/ve43eʔtK,Iޏ@%丠`*IqJ U$丠`*IqJ U$丠`*IqJ U$丠`*IqJ U$丠`*IqJ U$丠`*IqJ U$丠`*IqJ U$丠`*IqJ U$丠`*IqJ U$丠| {Ľ@>q{H1f0qK_sg|IŸv =vC^/qgc}U[G1>*q_su7hx?\1wrW'zĽܷuaqZ;seO7&GcA9&NϵN9%)1Tもq$n+󊱭\__^vcN^[kOO1Hܘ-1>ó_^3%n(ƶjڎ=<}ď+w?(Ϋ-OB]NzĽ`Vc_jX}l]zJ2mۣoqP 2gىiGc[u7vŠ1+=޳ phfϯU͖tj[ީ}^]]y=;c=@cg?V(uAYөVپѩHqAѰ+[v'mݦ;VlM:V>onveWVY3;aۇ_Hw8͊ūQm}sb֥kekU1wjWXNܱ[+'.E'e(k <[eneyL\}Ss-%)1Tもa]<6{nݧw\_닱YɛwY4aWҏk=ͺyA1b>;ooFm᫷#ϛzct`w?\-c6n/fŒ]֍;DŽz<-OfHJSb"!G#?Jkwݷc~l;8!;o៹5q3'c{#VX]Ӌg5YNԨfcџnۢVu>k<]ѮuhyW}غQڿ6ΏicB2K#?+9N ;xvvkΓ +zvطvUk<^rk}n7c[etNN?b9+ӆCȕ{yhyvzov7ڻ~;oFc3/gϭקQmPly:?HJSb"!GújX";cgŔ]iNH'bl 2ݴow't"kTguxhy:-{|7`W1vΊ{qtly?ζdȏmFDŽf<\-OgulPEB QظvnMjOtWN|\TobNpN.ƶ4أq.NkFe7nBYN؝5۸6{^Y+-VvWL?1AYvPSotr)9N .e]|)FzɇnQ% 2o̺bogκ㳲1VvhWwȖ+7e\qToyL.]@8-3Bjc׮<8V(uAYөzFZJSb"!GŮp7v2a'A'}}n'NdϏkq];*_QiQiJh]wá^!fc G=+Σ-O"d;χ,Oz'<6>+8l_kKlyr؟iotb8%*r\P08%*r\P08%*r\P08%*r\P08%*r\P08%*r\P08%*r\P08%*r\P08%*r\P08%*r\P08%*r\P08%*r\P08%*r\P08%*r\1 iر;묳 ӔPi(4楗^rw 13g?]j* /ŋ3i2V+p zrSbbQ5ի gTga$%&FXvmB{#۵áiu;ꨣ XĨ*k C*1"Bzșg?_~=S.+Ĝr)'Lc?38cQFc~w_Wż꫃Ro|A1cMW^Ik_ZawIʖ}M77I/~tݟy/+;}mx ~tu=^|EwI'.袴k}{ih;̶l9~<&{8hy^Fn_V>C?yz+F}vZ*1ʾQ|6xw\-[N?@[8?4K.qoz0'|r̕W^{9vZptlX<;@}馛|M2\ҝs9u1iRxӃv!K֝;ݭ^{5wAbM%|W_.!ӟtw}4ccuuGSlI9ol߲>tzԩ(?9GvfVaۉU[Vwyصk6W3T{hFeȧt2["}О3IM;;wn|K)ˣN;$GvfVaۉU[~7S;m>ÐO+F7ʐOy"5хuHI>^{Ժݟ}v6^$F16&:$ޑojc%Ej i([lcaϣѺ.$yr8za'9$5[fl=wzxU0mhڶfav7>PcB2S(^#(]o j/_?#c"07-m$Z^xa]<[b;Hն5K K~u۰gm?\Eٺl}s&9fnw%2+̦)ˣl?鷣`䑿ukKֶvs0dFOb}  !==pX޷Xo/}K1v06=_~yo+-szhJ9o~mMjYKTvC6=9sf|b=#mߤ`˗}~YYfPf˕vDZF;j"SGY/uٷʍaG=4#U[V\͇,W؏zgY3T+F7ʐO~{`tv'+KGwȝzis4lvٳO@c]wuKP ns 'Ɨ26YRPXbo[Ϣ6ƿu5Mɖߟk*;8۶sm-M'YMdFYe'gߐ}᷇ ƺ51Oh}vW>ve(C>"5QoFUA=Ɵ^]14T v/Ą|!=ʉվ5o][@~wɟRrĎXO"丠`gT9;O7w!@38% EqA*QAl@>ݘÏȧqr\P08%*r\Ppt.Xo㔘ؐ !GP(9N yr\PptH㔘ؐ !GP(9N yr\Pp,qo{OqJ U$丠cح]P#ݓ~,@!丠҅oEa-@PrVp09.(8:$](kٕD=jRrV w9.(8:$ăf]](}{դ8%&6A@r\PptZIzIqJLlZɃ!丠லn ZG|{դ8%@\U쎤~1XkN.PMJSb09.(8:v=غw&RrV 79.(8:H[o13:h࢝^Icզ8%&6ȃ'丠 %)1!B  PrX c  .B @Caqr\P08%*r\PptbB㔘ؐ !PIJSb"!GoJ %)152"丠ĚqQrX !EqAщ5!8%&6ABqA!!JSbbC( @%)9N1V^̙SXhQAs=cP 9.(JRrcϟjC- /_f̘vi~cǎ c  nB ]h %)1;S[tg}TnFn͚5n+L Œ)  nB N, 7%5b-ʕ+oΝ;mo{[;?-$&G($08:$DBqb>яC- wyk8e˖ӧW CbrAYKCB(W;+VI_03fLZM2Ї>ɓ'ȃEY (JRr\7`&N6°+3cqkjPIJk.W[gnco^xO&jEИDaqkjG.4lfnĮ׽ulƅ6nck hHL<P4q5CB(ʺ]Kj]m4 iEIҫyr\PptH㔘\Ya8nܸΟfƏ-ZũS)Ɛ !GP(9NM,y17!PIJSbP!MqATHqAщ nJSbbC( @%)9N)(&<CもKBMqJLlbɃ7!G'㔘ؐ !GP(9N yr\P08%*r\P08% JSbb3yGqA%)1!B  Pr @!丠 %)1!B  a!Tも$%)10*r\PptBP(9N yr\PptH㔘ؐ !GP(9N yr\PptH㔘،Dd!Tも$%)10*r\P08%*r\PptF zĆ<P9.(JRr@ 9.(8:|S P(9NHA@9.(8:#գ8%&6#) zHQr @!丠 %)1!B {?n!,$_#5п"0\ \d 0V.tႅ kWK޸ӕ ʭ[w.ݝ>_ͩK?9=+tW?STwHqM 6˗/{uJ9Ųeܱc{۲eK){ײ̥KJjyAat\]Vn޼ٹsg֭[njjUJÇݙ3g޽{O?]nܸ}#+S븂pt؅P:.ꫯf]}iVVZU7ٿ6mG۷oׯ׮vу@: (. >2˗/wWξ9̧+xk֬)\r]v4gn}3+u\AP8:"@t16mv+zjA/f+{w333nݥG}2Ȋ!`XBC!J خv";w^zVmn׮] ]2Np/fY1 kP= IJ vP;>N>cgL\;.ĉ W\LlAB踠0IR:N"aK)@tM=1>S:NĦd't\P8:]" }J)ЃqAPqJ&6 @!t\P8I߬{c7mspSo_nK9Q:N"I.⾸ϯ$Yal_v_|ǿ WqJ8I踠ptvDX\),CmV+XEM\~_S2'Ŋ!qAK+EM;4sZZ*oRtM]P$t\P8:uɇ?V}|_+_~_S2A Gc @W%Ō?/J) EBVG?^Z*z?If~Q:N@? N_,:uwhU?&'E8%w@? N.4UyfR;1WUNrtMS:.(AcùA[>mMdvɾioʾCt͠P(dbCBC!J)ش݃c$t\P$)dC'$I8%@ G]ht =P IJ)R$t\P8:l)(S2i9I踠pt.D@?)dbvb$t\P8:m"S2 ѡ LlAB踠p~mR^Jd26lpW\q55U_8C]S ƉZ[[1ׅ}W2|2{ɺf ߟM[fM)W_u>tudUV~Ux븂pt q_K؊lk;@) %Ϸ/d"Jel:hݻYvm) \|[zua>i%(븂pt *}`P2|BJƟ/t1?= /߿W-iӦzj6S׃ N]!T;udrߕ?_A8%cylN;Ͽ-ĉ'ٮv;w^z1u=@qAd<҇ǿSׅ}W2|L699Y-Ċ+Ǐn3vFПVd ^p4΀j$Oj7,z\S GgP!87mlm3Q^Jd2gvܼyssv?wē'On3aseJfshg-ԃ+ GB(l۶mo|/_.@MA7nB[3޻w}G 3 @QqAPqJ&6 x:.( @S2}Ê!$I8%@ Gg]hA8%z:.( @S2H踠ptR P(db3lr!A8%a{CB3l!ƃqJ&6 @!t\P8:"@t =P&?te*tCy. t EB{>}?݂7gU%n(υA{S2)xB_B3.4'&aeElG,db4BpS2 AV `| NH!aȶ,e* P2|1LlA:.(a *},e* P2|1LlA:.(a ?;RPƪP %Q:Nf½KĊOwU%<JƟ/tI:.(+vF@X?~X XU2|1sdb8J)bK踠pt݅WUN gU%n(υA{S2A踠pt(fal۟-~2V <JP:NĦqAPqJ&6 @!t\P8:"@tMHr!/$I8%2V `|  IJ)R$t\P8:!ƗqJ&6 @!t\P$)dHqA谥P:N&9ƗqA"`|)db҃:.(B/LlAB踠pt(DB8%z:.(<~m!uS:Nɘ;wnݺp +ObxQw}bŊi6_[Qmno'mkAV NS!a_KƊlK ?hqMիW/\@tim [lqZt}h]vF݃~hyA茺?҇1 ?hqJ bh+~+{/_&&&Ç]FlΎ1yfiuA踠ptF]=U?_ AFS2fCsȑl=sL){wƿ͌ t\Px<ǿ#e906ڥt1ìn۶-;N:cc~RN>c.NNNnSp! 't\PxcES_(e906ڥt1ìnv4;񌝀8^zoa:.(.vwgCd:alG8%cYG^zu4[}>;e-[VGQ=HqAtU;d[?e[$acJ)3hp޽qqnC_yl{ӧOg }h n޼9c^x4z6ѡ 㔌bhgcOS;pvv6ܹs'[)3mvam˗/EBC!J)4 rBHqJ&%rBHqJ N.4䔎S2 $I8%@ G-qJ&6M=1qA4"9LlzC@N踠pt qJ&6 @!t\P8:"@t =PF ~mH*`S2}t EB1@//t >CETPƘ; ):.(Tv81}+~(+ǭSS%1%ϷS2IKK踠ptR)Ĺ-}+- nsd!1dqJ&6 `i N*>AܔTB(cL#LlRA:.(T ?;*@e)}tM*=XZB{X)ׯ_w6m*er;wt/M Ġ{*0[¾?>dLy 'ʘW2R:)swuVwԩl.&c+۶msSSS3'?US2|*@ʔ1dD鸦L]A[ɳC?ľeK.C@:n^P8:}*D*JƟ/SC%H2敌?ߘ(הW w}7[ ]1<}tvrVr'Oz… aІ=҇ǿ#eb11T2|)c^qM[1}vK4Ʀ=Ɋ ^reaƍnvvvѮEV Cϕ?+|7xq!;۟Ah?_,s3ٖw5OV'ɠ*O1dbt\Sfbb"۝-[܉'ch޽{A6aÆl~g9;^X1C!J ط{vqGW"?^͜:u*nۋX1aP=P(db҃t/K= BHqJ&e|xC1Ɨ{ $ ):.(]hK8%z:.( @S2H踠ptR P(db3l׫׫׫aiυjjjjn\׫׫׫릍A8%a{____?iiiiiXs____6n GgBLlAB踠pt(DB8%z:.(Խ7%5eF8%@ #!_^؟|ǿ'2FIy v)d0ZOhR.4e'&FJEE}3=kLqٔS2[ϟ?㎾cKN sZTd[9?^ڣM8%z:.( 쓟*}@sGy v).qJ&6 @!t\P8:bMq(.3eS:NĆ( #~ouGy v).qJʟO:q3c^踠0`g? M}Xg @{`)dЭ]<78慎 G]h]ʳ%5e&t =PXoǹl}@l:]P^]fqJ&6 @!t\P8:"@t =PP(dbwc8<w:.( @S28~x+8 $ ):.(BhqJ&6 @!t\P8:"@t =PP(dbCBC!J)ЃqAPqJ&6 @!t\P8:"@t =PP(7(sQwC733W((C:pt(DB鸦́܃ܑ#G֭[ݩS6g(Q29zhyAPqMk׮/.v-wR2%P(ה:;p}ݺunzzMMMM(=P4uܼptBo2e.qM|NsNw]777&|L.m\2kyAwW\2JM7/( @kؙB?En޼YyPbŊ4u>JM7/( @kLLLdx>|mٲŝ8q"ۂvݻ7ɓ۔(B4uܼ0IR:nPfrr2;Vfgg?DgLbwm| AT`$)dHqAat EBHqJ  IJ)R$t\P$)dHqAat EBHqJ  IJ)R$t\P$)dHqA=zݹs=|̸}2mذa|w.[k˲eܱc{۲eK)ӖIw1~۴iS)Ӷ;w|ʕ>|ҥ>ι1]=}r+˓{ײڠ.Ϟ={ܭ[;|p)=A]6(cEMcS:NĤPcmr҃cz.W'^uy1]碦x Ɓȑ#n֭ԩSكj0lݼy3co^pSSSl[l}9sۻw{K6؛=6(mۖ'TcT-裏K՛ިT-=F!J¶B}6 U< ux46b<+dbcmr҃S<]>TcT-^7*UCOt=B?n>ӾӶ>K/Tʴ?v0]Ad_~RvXO?|_, wֶ(]\W<{(-뗧񬌍Bao۴Q>VvV!bo?7,{ќ8qbk}n/ cF MQ]pFny|.rM1o˶lvV׶1=?v9}K6 MܦAxVRgL,~ t5V =?usk]yS<{]ЃxVRgѰ>{llAV mXv϶.7nܘlB $WW@ƾ`[|us1w=曖ǎc׀ 嶏0Mc ?vQ-T-OWY]gtR<1֖j=X<]?{ciy65-Ot5ձx6Bax&1c Ϊdkx~7| +ua 2?6{ؖg}t[ Gny|.՘7uPdon?]b8Ac6x+"g'(uyr<甎S21TX[Uӻ|.՘7G}kˠ1`t5ձx }Mlk5lk_ ۚx2:؞7x#cv5lˆ;K_JO-v${,L۪ ȶ Ķjm޼9[ /PGt\1.j76cg?>ؽ+o.s1]*Uc\tEW:X%=X^sƼ<6C/j>> Data Function <<< // With these values, the curve will start with a value of 0 and reach a // high point of 2 at x = 3.14 (Pi) and then return to 0 at x = 6.28 (2*Pi). // Play around with these values to get a feel for how they affect the curve // and how you might adapt this code to plot other functions. period := 2 * math.Pi horizontalStretchFactor := 1.0 verticalStretchFactor := 1.0 xOffset := 0.0 yOffset := 0.0 // >>> Graph View/Camera Controls <<< // These values influence which part of the curve is shown in // what "zoom level". xAxisZoomFactor := 3.0 yAxisZoomFactor := 1.0 xAxisShift := 0.0 yAxisShift := 0.0 // xFunc1 defines the x values that should be used for each vertical "slot" in the graph. xFunc1 := func(i int) float64 { return (float64(i) / xAxisZoomFactor) + xAxisShift } // yFunc1 defines the y values that result from a given input value x (this is the actual function). yFunc1 := func(x float64) float64 { return (math.Sin((x+xOffset)/horizontalStretchFactor) + yOffset) * verticalStretchFactor } // xLabelFunc1 defines a label for each vertical "slot". Which labels are shown is determined automatically // based on the available space. xLabelFunc1 := func(i int) string { xVal := xFunc1(i) labelVal := xVal label := fmt.Sprintf("%.1f", labelVal) return label } // computeDataArray computes the y values for n vertical slots based on the definitions above. computeDataArray := func() [][]float64 { n := 150 data := make([][]float64, 1) data[0] = make([]float64, n) for i := 0; i < n; i++ { xVal := xFunc1(i) yVal := yFunc1(xVal) data[0][i] = yVal } return data } data := computeDataArray() bmLineChart := tvxwidgets.NewPlot() bmLineChart.SetBorder(true) bmLineChart.SetTitle("line chart (braille mode)") bmLineChart.SetLineColor([]tcell.Color{ tcell.ColorSteelBlue, tcell.ColorGreen, }) bmLineChart.SetMarker(tvxwidgets.PlotMarkerBraille) bmLineChart.SetXAxisLabelFunc(xLabelFunc1) bmLineChart.SetYAxisAutoScaleMin(false) bmLineChart.SetYAxisAutoScaleMax(false) bmLineChart.SetYRange( (-1+yOffset+yAxisShift)/yAxisZoomFactor, (1+yOffset+yAxisShift)/yAxisZoomFactor, ) bmLineChart.SetData(data) firstRow := tview.NewFlex().SetDirection(tview.FlexColumn) firstRow.AddItem(bmLineChart, 0, 1, false) firstRow.SetRect(0, 0, 100, 15) layout := tview.NewFlex().SetDirection(tview.FlexRow) layout.AddItem(firstRow, 0, 1, false) layout.SetRect(0, 0, 100, 30) animate := true rotateDataContinuously := func() { tick := time.NewTicker(100 * time.Millisecond) go func() { initialxAxisShift := xAxisShift for { select { case <-tick.C: if !animate { continue } xAxisShift = xAxisShift + 0.1 if xAxisShift >= initialxAxisShift+period*4 { xAxisShift = initialxAxisShift } data = computeDataArray() bmLineChart.SetData(data) app.Draw() } } }() } go rotateDataContinuously() if err := app.SetRoot(layout, false).EnableMouse(true).SetMouseCapture(func(event *tcell.EventMouse, action tview.MouseAction) (*tcell.EventMouse, tview.MouseAction) { if action == tview.MouseLeftClick { animate = !animate } return event, action }).Run(); err != nil { panic(err) } } tvxwidgets-0.12.1/demos/plot_xaxis_labels/screenshot.png000066400000000000000000000570161506765256500235430ustar00rootroot00000000000000PNG  IHDRNJ]]IDATx^ylizB?fefG^` <,`c{ p|aMDʩ(J")rK;QN(}_r_NynwW?z߷Hmquz{u޿ۿooմ;??v?3?;K_.wgϞp h-R??s??;n}}OOrJ//c=TV 9㢊qYY֏&T3gɟɹfmp:HP?ֿ뿺}g|k??ݗ|ɗj, o77ڞ`?M1 /4k~}X˿KE_E_>Iq6;/ܹ6#s?ss ooc!tk26Z?֚n׆˺=?!N:hگZ;yr);߷}۷$u@Xz<?E?-[$HN//n|'~WWO *韞;>k?>/w=>>_\O?ؿ?OT777뻾˟Gz݇oor__vCCCMow3wx?7{Nȸ$||7~#?#^Z5[nVKMkCVBGքO$^d|k}~!Z`>33ȇ|ߕ;%=h EKK}o=?O:ڡEcRmue=;5 C;{>l;d:]oo__oAA>d˟M;r=r$\ov5[qxCqO'6f62jZ@899g}|O;ki}V3?3kkXآNXڨSPf ?ebcbܭʞO#r[ul q>|@cl(,\5ec#ti\2 +6f62jZE}ڧBy`g ­\/Tkǟ3?ֳ6TZPZ3::q=Ffݜwl creCfAȷ~!;MD?m0׏ͮ:潬2ֆ%seT\Zm)w\#l2Ze}JSP?cZ%[sR)e|*a5X4>TF˾'s~~dy}9|mYj?؏u1 Eܼy_Ç}؇ˑO5_5ֺͮ2v˼USڰB+,Iq.y/OCe^ܕ5=h=P@ZdXj:l ٟ~K={]/B/9ܩܷ>zw~w|8m^{ ~__s|;sg* >?.~5l;%뙊R(Xs"{=|9r?~ѣ\fN>C࠻t}HM :wt ANk1 nc@ :NǐQ{RtI-W^ir Pܵk 4ļet ANk1 nc@ :NǐQ{Rtwٶc'NAlݹzlj,NL!FY9cQpvv6w|3xxx-//$J+R@ LEm|M> k6{1Ϟ=sΝ[A;B@:%뙊Ce$MNN枳}:44eÞ&Ζ jB`Y jB`Y:Rۿ߾ysV?n0[n?Rb!UK Z!UK ZԑLE^_5!Em۶Y;v 7ol;&E~f5 l6/p'!MlK^~\ȈtQ%t||zŋ}<.R@ FY9K޽o .CyEE[Bm3+@[6;@?lemnw~ߩ%뙊P,έ[Y[6;@?lemnw~ԁLEH)YT@g*DJz`teFY밬(kueòtuXybd=SQ@5ZeFY밬(kueò3%뙊S *(YT,!蔬g*DJz"}ʽ<7I/\/ t5sr@'\s޸qýnzzڟĉmuڵk̙3MCCC}U6T嚪򵑦*T4U|m5UkWEz"w׮ '&&ܳg܎;?o۶ͭ; ehF\SU6T嚪򵑦*T4U|(YTv|,=/\VVVڎ=zm;޽{};tPB *%뙊t8෌[nntt <~x7!ovv.--r0{>!蔬g*jM ϟ!NիW۞aprrҽUN~/{.!蔬g*jM ?yxO|hLս{ǏsCQ>*_irMUHSkF\SU6T嚪򵫢d=SQn;wÇێdk[I㡨rQUHSkF\SU6T嚪򵑦*T]%뙊Xa마;}Nz6‘@}ٳ9yk淊>}ԇFѣG}|"ݹsB(Nz6BP p ybD% '֌mR#_R/= Nz`܇\k#MU*_irMUHSkF\SUvUg*&\TU6T嚪򵑦*T4U|m5UkWEz"@g* V([F TJ3"d=SQBC>Юq mv=Kh'A\B[?] zʦd=SQv=Kh'A\B[?] zOhS6%뙊J P)YT,!蔬g*DJz"aq ׈0İVbF!5" 1aapP(XUlapC k%kDbX+1\#ZJ %뙊UE (YT,!蔬g* tJ3E cF!5" 1aapC k%k솒LEhbJ ׈0İVbF!5" 1J3-S(XB)YT,!蔬g* V01\#ZJ ׈0İVbF!5vCz"apC k%kDbX+1\#ZJ %뙊R(XUl(YTLEa cF!5" 1aapC k%k솒LE"v5" 1aapC k%kDbX+1\c7g* Vbd=SQSڶmrnuu8p W399閗ښ{ۿ9%뙊q s5VwAիndd=mϏ811ᆆ̌[ZZrosB cF!5" 1aapC k%k솒LEʕ+^#n5ʝE fgg͛7?Kx\m[FcX,1\#ZJ ׈0İVbF!5vCz"k׮㹹-{掷ZYYqoV1 JUBLEm OugΜT!5?b\1^3#Ƶ5?b\1^3#Ƶ5kg*jc DŽwݻ͟oR…  xG9Nz6BnAں A(W>|w޶}בs%SfP|PFwN>?mT|ѣGs5.]AѣG 7@d=SQS?PB c@9RX )Ha-0#Z)YTTk),ƀrRʑZHa (G k!1)Jz"@g* V?@̔g*DJz`a SʑZHa (G k!1)ƀrRC+%뙊E Ia (G k!1)ƀrRʑZHa g* V?!Lz`@d=S RJ3Z SʑZHa (G k!1)ƀrRC+%뙊Տ-),ƀrRʑZHa (G k!1)Jz`#@̔g* tJ3@:%뙊j-)Ha-0#PB c@9RX )LEbHa (G k!1)ƀrRʑZHa g* [F@d=SQS(XB)YT~0#PB c@9RX )Ha-0VJ3Z !1)ƀrRʑZHa (G k!1R)%뙊Տ-3%뙊R(XCT]긠KuSt{.yy\J3@u T=qA꼧:.RT]󸔬g* V?!Lz`@d=SQa766;n5?? r nՉCUwΝs)YTԔ[XXew5w̙\x~˜UUNc:qZWu:41Uz"wg mɓ'seMLL'OGm2$UUNc:qZWu:41Uz"k׮㹹-½{'[Aϵڷo{q333} %뙊tx fgg{sZwf$)YTԦ@888{{뷢J;|}{[YYqz׻B:%뙊t;wy/o>²ż/:4uk]i4ֺiuU9yJ3);ʖQ:*/\v!wޝ2wQ w9=YږQ!蔬g*jY !OB_9166Pj݆ٚVB:%뙊Uv y_pQuk]i4ֺiuU9XNsXg*':4uk]i4ֺiuU9yJ3"d=SQ2 Q)%뙊U˜UUNc:qZWu:41Uz`Nc:qZWu:4uk]icLE*;@jg* tJ3"d=SQmļ/:4uk]i4ֺiuU9yJ3-1OrQuk]i4ֺiuU9XNsXg* VفRd=SQS(XB)YTT1 VǞ:iǞ:iǞ:iǞ:iLcW6bԲy쩪y쩪y쩪y쩪4v%뙊ŖQ)YT,!蔬g* tJ3@Ӿ^cы1Eu"~ẘzd=SQb^cы1Eu"~ẘzd=S RJ3-:%뙊R(X!ioы1Eu"~:z?p]LP(XЋ1Eu"~:z?p]LP(XBHLE"Nz6nll,wb߾}ݻӧnee?޳gOɓnnnέE7>>lNz"700দ‚#w\fmfgg= BBL[}q{'N٭s^ď9\G/c %뙊ܕ+W|3n%}ڭ^xylbb={رyL^[bni{^ď9\G/cы1bꅒLEn׮]rWo+pDǏϝ@:%뙊te˨> rKKKn޽%^z5W#SMP/x!O%;燆{dq=gΜɝ[15z?ps^ď9\G/J36w;[nyyهÇ{;wl֝={{VQ"˗/^@:%뙊l彁1佃=߿^}\oPG*Jl}atJ3@Ӿ^cы1Eu"~ẘzd=SQb^cы1Eu"~ẘzd=S RJ3-:%뙊R(X!ioO\/ ?qat'.̗.(YT,aoџ0_:KG|O\/]Q(XBHLE"Nz"@g*JByCFGGGjϔg* V-NNYYYYB홒LE*g* tJ3@:%뙊~ސѳp17ѳp17ѳp17ѳp17Ņ3%뙊䄌)))).Ԟ)YT,Nz`@d=SQS(XEayCFGGGjϔg*JB2z.8z.8z.8z.榸P{d=S RJ3ȖQ#%뙊R(XE7d,\Mq,\Mq,\Mq,\MqLz`{)))).Ԟ)YT"Hz`@d=SQa766;no>w=VVVܝ;wܞ={r5wuO>58[Q )]~=W;w;r;~ѣG͚m۶YOs333~ސѳp17ѳp17ѳp17ѳp17Ņ3%뙊ܕ+W|3n%zZz_>zZz_>zZz_Pzd=SQ@P(XB)YT,!蔬g*R(uSBOCGOCGOCGOCJOg*R(O =/=/=/=/_(=U(XlLE"Nz`@d=SQ@~ݔS%뙊JSBOCGOCGOCGOCJOg*DJz`i[Fj3"d=SQ;M =/=/=/=/_(=U(Xա壧ա壧ա壧ա J3K 5뙊E LEmXĄ[ZZrkkknaa:u*WsI777VWW6d=SpSSS>ׯj,N>C࠻tQ~_s 믻i'NȝO~ݔS%뙊ܕ+W|3n5>|ݾ} vZg3cǎ1ym i[FCi~Jiu}iu}iu}iu}B驒LEn׮]e{aoffy… nee=znݺ;j3&6cy/ 5uo۾}J?;tJ3)#6;wom Bj$Izj\@:%뙊t}?sQEg* z?sA>}UYz`if=SQS)%뙊 U:u:|:|:|:U^z`ezU,T{%뙊E LE"Nz`@d=S*@VޗVޗVޗV+YTl:zZz_>zZz_>zZz_>zZ*zd=SQ2 :%뙊E LE"Nz`WT{%뙊 USGOCGOCGOCGOSEg*DJz`etJ3"d=SQCX*@VޗVޗVޗV+YT,aXЩա壧ա壧ա壧թJ3@:%뙊E LEĄ[ZZrkkknaa:u*Wc199閗y=z}ܽ{[YYqwq{ɝ9%뙊ӧ}@;t.]Ngk5<.̌o;waÇȑ#g s! UN=/=/=/=NW۷os׮]jfgg͛7? xYɓ'W^yY366Im|l^ :u:|:|:|:U^z"ojjlᜟw[oxpp vޝ;tJ35a@ w (P'm&{\@d=SQ3{={Ν;]@xeǎs/֭[Zo*J>'S'Oa0rl+PB|h#=~-..6וO%>pT:u:|:|:|:U^z"ET[]!lyv>}Μ9|իWsTSGOCGOCGOCGOSEg*2Bח}?`Nl!};XFڹsvnŋl۶-@:%뙊| `&[Gn;.\{H ӏ=Щgbngbngbng(YT䷈>~ 4ݺukm7!|g"5O?tjYYYY17J3Oyf۱ ?eTeeWexNz"7::֍WAlȈnzz:h||`"5@:%뙊I> {57zݻw5@:%뙊E O?@)))sd=S`֏z.8z.8z.8z~̍LEH)YT,Nz"@g* wЏ}1?qat'.̗ąџ=_J3@tjO\/ ?qat'.eϗLE"Nz`@d=S RJ3]){tEu"~:z?p_sd=SQ2tEu"~:z?p_sd=SQS(XB)YT,!蔬g*Rы1Eu"~:zPz"+e/ы1Eu"~:zPz`etJ3@:%뙊E LE"ơ=1cы1Eu"~eϡLE@W^1cы1Eu"~eϡLEH)YT,Nz"@g* wPы1Eu"~:zPz`Ps^ď9\G/+{g* tJ3@:%뙊 ‚;uTb۶mnjjϻUwݻ[YYqwq{ɝ9%뙊ӧ}@;t.]Pgk7#O~իndd=vÇݑ#GϏ=ʝ({tEu"~:z?p_sd=Shon;677]Ռ-ɓ'JwrlC :f"~:z?ps^į9Tome ljd+>zٶc'Noݹz!蔬g*jnnyyٿOBaVQgvP |ٺVtvv6w\@d=SQ3H;w.Z4ʹ&''ݱc|ؓjśoo(!4 Nz"lǶ%]x|iʇ4c9ĭ=1SU9SU9SU9S*YT䷈>~]nݺU=rl޸q}|i_ :fu{egK|? K.`(V?w:B9&zq?|i):T)Ha-0#PB c@9%뙊Ç۷ێ͹k׮j-n'OܣGrpllee4EtRʑZHa (G k!1)ƀrY J3={vΙ\f>}g{|^'B)YT.*[YY0[7C`@(wn<3~'N#SesE>$w;B9;v^~~{ޓ;tJ3@&wdА?V4xX@(&s;w!rzz:wNP0#PB c@9RX )(g*AN>t``y֭[Cx7Oe?!w|-;7nȝ(CPB c@9RX )Ha-0ZP͛7ێn);v0y6 c[ ~CQ4['6 H:1\#ZJ ׈0İVbFA[+J3-?n{߭[ Rwرs@X_ڂE ׈0İVbF!5" 1a֊LESFo޼vLѧر#wɓݻ<of-Somŋ"qvdd?7==v_wCd>Esyd=S799Iؓ'!x…sA 4O>uwj@Q(Xti{C5" 1aapC k%kDd=SwڂE ׈0İVbF!5" 1a֊LEH)YT,Nz"@g* wE]Юq mv=Kh'A\B[?]d=SQ_] zOh׃~BIz`@d=SQS)%뙊 TF\SU6T嚪򵑦*T)YT,KIVHSkF\SU6T嚪6%뙊E LE"Nz`@d=S*WHSkF\SU6T嚪6%뙊 Td4U|m5Uk#MU*_iS(XlLE"Nz`@d=SQR*_irMUHSkF\SU6Ҧd=S*򵑦*T4U|m5Uk#mJ3"d=SQ2 :%뙊R(X!~kZ~~꩟kzQ(Xz_|-S?X?_ 5B=sP/J3@:%뙊E LEĄ[ZZrkkknaa:u*WSͰp֭\@d=S;}[]]uϟwҥK>lf``MMM@)!]Μ9444Cr}/ t5sr@'\s<7Jz"Cwcsss>ek5W\wS ܶm'O=Ŗz_<7I/\/ t5sr@+%뙊VQ qLVk׮c ޽{};tP,!蔬g*jn?ҹCaj@o7;;_Ws%Nzf y;w.ڋ@(K0899mtJ3@. ܻw=~8w}<7I/\/ t5sr@+%뙊Q d)c5ECتH -FQoK:幁Nzzyn^^hd=Sћ7om};rDz6 /_vo;&S^/[˖Q)YTFGGqwwE8[;22⟓zZm=… jӊ@:%뙊<ٶ)amqqY}F4£s6 bll̿?Q#U[tJ3@Xowsr@'\s<7I/\/ RR/幁Nzzyn^^褗kZ)YTLEb(蔬g*DJz`qYٽٟ;1߲0scٟ7:[vft,Fǀ~ˮϝe J3@_ٟ;1߲0scٟ7:[vft,Fǀ~ˮϝe J3@:%뙊E LEH)YTLEb(蔬g* tJ3@:%뙊E LEH)YTLEb(蔬g* tJ3@:%뙊E LEH)YTLEb(蔬g* tJ3@:%뙊E LE"Nz`@d=S711ᖖښ[XXpNXXcB)YTN>VWW࠻tk8[R@ LEÇmܵkry,5 B)YToNMM5޳gw333Z<!蔬g*jnnyy٭Xcih¬xc<1yc󸎏g*j4gϞs-BrKMCcY<1yc g 5.\{zK `sJ3"d=S RJ3"d=S RJ3"d=S RJ3"d=S RJ3"d=SQMLL%ܩSr5ea766;nm6755;p@ swuO>u+++={ruEt;":sΝsG=y$W_2ItGjRkmumK&e=߻wWֳxyh\]?'Otsssn||}7npp]t7Jgk5eb``/xL?ׯ_Xzq?|['q Y333͔9"?~__o{Çsd׮]՗9-s6Sf/HoP+ov5feoRc߇;w=|9r?~,a.{b7ٸY?je\7np:qD[quXXXUf)!8sLl]7{# bdž`6,  7}< n_3Oӝ.|gGDL#-eZ[H^q" *n=sС?ؖCu?~XV?n5VV=0ߟS% >01;wȷP>?VqѠY@W^EѦýNP'}Dvu^j+LsbϞ=>v˯B-zzϟ?ܾ}y3eg襈c%ƖT$=}֞{DD8?-L=5C4/U܈^^HPXݥwnRѣ7DwgsrɏuRf:tdTGv>]~9%QQž{DD8?)l=5K4/U܈^(^HPS>s+mT<˶P]gceeVBFoAo ~}rnݣ:Pn 9=Zz}{"+]{J(RXDdj{<9b6UWUϗA HfƢD|'"S![(ז՜vBI/0̟!f9P^cמ`^~\Aw(=2ݟʬV^jzy|YIO/UP(^HP[〭s"[~f"b2cNjIMzBP+[a(}|.ʌ=콵lMKe^ S*s :V޽{rNM/RؘDdJz,ϓp%eWNUb?5&'&JJz"5F빦[yl} gD|gKzm"zEd֔:?yK=$:n@͗UDRōQ?UИ년p7JI,yJGg2:9:3F=mQoAl~.*jZ*zeN?9%#mZ+h{)O ޜ/bȱG>QͫW5-SLKstt|ri/ɯ WMwcO2pǓ;LIDATx{tܓɅ$d.UEZ-ZE ( ϖ]w-]=uj(g?Z]5XVhEnP!&~\23G00$@l|<9|y& mrGdA@"3ss$9`SZˣj_/X49-vV)N7LkWâ.}\MIU̓$IfJ-y;O_V:͝TE]CE7VM)9`ի+$Ivy4^-ڜbeH ~V L9l1=V g۫Iֿ('`ԫj7'*hl_Oi:fә6(uXkRcϼ}6/ gLvI.ݖ8`$]]hq˸V[r$ux&OCWz<~ԀV}ySb9=!um`K=a~5J^=w0RfZSЪ)2詢hthsJlVnWKЪ*?#SB_DoFZ?Iޡ@r Hbn^[Yϗ$ez Z9MsM6>*>#F\_B{ۗX36t%zwIo#jѳ3+[uenH5[aK/?xCs&d. 2JvsPn0٬HpFwf4ӍuIvm0C?wKEk7)Ւ~-( ci]*|Q+;55'Ten]ER>'#_j9+w]Ѧ^ΨN7uɡ9ߗ=B_oN}ڰNk7ٮ[swk`Tu;. GԅX_9aBjTQֵLGԢgfͣ7ke>MNݪ.:Ak?:Eu;9ˣ'SI!m\ZE*t}}8U<=矿zQV1L0J%5nՔZ\VJN[,n}Y:<nGs?lѢ OViSɑбHztPSj&\7G6xoV\}jftc?-l e@}lz͉ F,Z6wёOj -wґO/6&nAf.yĐ\>rI>T3V}M[Jnegofβ?ױ_11TN}ft۫+tôt;b:S;.i}7OiВ~w]WW;6'U퓲=бz:=`OW$UּIWμU=}`^>sW49-XglZO_?iSs7/t֩V4r JWYގaiUx_P ;竴:t[~o˸Zm9uôv])}oꪧU&+I{Su]A~G<>֤.s͞RRe$*m\R'S J6temős-AS"WOJOSJ/|hLCK$E/ѡYa}0-ԯrhSS,Mr@?\F)j ߍ`Ģ/:ˣ-vyV]Ի3'I_DC)`U3>Vݎ'ጪ֟ܲ_S[jĴޯtRL-( (*u7);%HLFe6 < xfn]U$+g tƥ﬎{ݦ[_w7iV`bN^9GL f|OZm=nPE]eMuڂ6}aMСF2Q=}[l-|.__ޔ?IZC|#&KlΏKyri|av]g~A@YQEұ\;MwuٮfiZ٭w'j3z,=mθ Yf~2Q-ׂ€^?{ʚ4;8)_آs$I5yy­frQ,RϦC5N/ѡ{L1I-9l1埶*/=˴>bnY9aH0:%u7;55'Ten]E)v[iDtu^P?5G ]a툪ŮƓpTLofO=zcnίV`Sb,vr'z`k6,M*ok\kw+ReZduzK::9IWvމ-WiCE|_PâgP3Iٯ+r-9/_( 2:f0>Y^o,xUE*yi[׿8g*=s4>!J.LY`|Iu.w훬hu}izz9?K1}T͛GzGz`` )c- p l<F:ǀo^g0` A?! B0` A?! bm ۖ^̦ }Ά{;pm+Çsel\0` A?! B0` A?! B>5EG67l[:#pC`l\Isq$ƹ21` A?! B0` A?! B0}6haA Lkp48W08W䌕s?0` A?! B0` A?! bthH!)}söúpc++Fk/+q Jb+?! B0` A?! B0` A#=hMˆ7l[:m1s%1tǹʅa A?! B0` A?! bz&IZH%/mWm ۖLs#0VA?! B0` A?! B0` A?[czӺiz{}Fw\ I֞+$IvJպ]Ul]tD-zpJC7ҳ^/irZDVviիSz,4˛١xuŋ4wrP-v}oGO&9BڸV6OU8bIZI艽كͧon|>hcOR3VM)9`ի+)ޗSE[ˣ?h'I+洩HgX$js:E~Rfe5tE# T7kO 3:}.[An7`ZUM9Qo'Z6ۧ-G]gt䠲Rz31,z =lVAfSo$]l\oU.Igp;يIr$]wM酏2ݞ7CWL ig;vUSѭu*mth{\ߗjbjg>xM$iD=qKݪu0E9u+yrcVLr;btg؛=('I+M%]޼ҡZΟ:XlO8/ +]=fz;=婚NF*R_j6qF 7H -7=:TԲYt\nh ZdzΩ4{bHK‘qIvL$faJw\֦_9ΘB*;%}.{;eh՜VItɡ{e'Y~vPgRtt$PKm!6I>ioph Ǝ zޔ5?P0bϗhCson ݊/yBKV;C툩!`zBΨj=^:_?Y~vl[K":J|tל)O/l/9+I!1ݾEm0ˀglVK^EJR˿r8]_|@j\zm|}g~f%y ?+wophΤοh;'7ݝ#z;6>sKu ^?zR̡}%5>V]]l4= $qG+ɒ.R\Z#_آ~י_PVjTt!=PvuٮfiZ٭w'j3z,>qh&e8Z2ӯ~,5uiv8^(]ߺIf[gӂ€R1٭19l1wͮ]Ш4GT64wJP9]Y9a80z%u7;55'Ten]E)v[iDtu^P?5G ]mOoUe]';~g=zcnίV`Sd,vr'z`k6,M*ok\kw+Re=7%Qֿ\ގ?{ ]W G-ZrJگ&뱛uC5N==7c/I/JXUus3'hgf B0` A?! B0` A?! B0` A?! B0` A?! b?vMxcp?gCa<p\:08Wn<1%0` A?! B0` A?! b k}CaB9 +÷dP\m&0` A?! B0` A?! B>T^^QvvAo<M4 Mcq0` A?! B0` A?! b.~hH6Ʋx01bcL~|8_/0` A?! B0` A,^7$I+Vm]J֏͎.\3&! bod060` A?! GXU40H /=?zcAm!rG$A?/Z6MIENDB`tvxwidgets-0.12.1/demos/spinner/000077500000000000000000000000001506765256500166115ustar00rootroot00000000000000tvxwidgets-0.12.1/demos/spinner/README.md000066400000000000000000000000361506765256500200670ustar00rootroot00000000000000![Screenshot](screenshot.png) tvxwidgets-0.12.1/demos/spinner/main.go000066400000000000000000000035671506765256500200770ustar00rootroot00000000000000package main import ( "time" "github.com/navidys/tvxwidgets" "github.com/rivo/tview" ) func main() { app := tview.NewApplication() grid := tview.NewGrid() grid.SetBorder(true).SetTitle("Spinners") spinners := [][]*tvxwidgets.Spinner{ { tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerDotsCircling), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerDotsUpDown), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerBounce), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerLine), }, { tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerCircleQuarters), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerSquareCorners), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerCircleHalves), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerCorners), }, { tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerArrows), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerHamburger), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerStack), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerStar), }, { tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerGrowHorizontal), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerGrowVertical), tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerBoxBounce), tvxwidgets.NewSpinner().SetCustomStyle([]rune{'🕛', '🕐', '🕑', '🕒', '🕓', '🕔', '🕕', '🕖', '🕗', '🕘', '🕙', '🕚'}), }, } for rowIdx, row := range spinners { for colIdx, spinner := range row { grid.AddItem(spinner, rowIdx, colIdx, 1, 1, 1, 1, false) } } update := func() { tick := time.NewTicker(100 * time.Millisecond) for { select { case <-tick.C: for _, row := range spinners { for _, spinner := range row { spinner.Pulse() } } app.Draw() } } } go update() if err := app.SetRoot(grid, false).EnableMouse(true).Run(); err != nil { panic(err) } } tvxwidgets-0.12.1/demos/spinner/screenshot.png000066400000000000000000000321271506765256500215010ustar00rootroot00000000000000PNG  IHDRJ( %iCCPICC ProfileHXSTZ RBoH/kJ AŎ,*TD"ذEe],Pyos̙sΝ;b8bq6@(_"u sRLL$2tm\/@NI9rŒ|=Po:-_ Z d39g(]iJTBNLp$bp3r"PWA yTNN.d5+ViϴaN0+sQ9H(gsfߒ-6@+Y^9 EECք|MS˹K Kš&( D9I!ڣ|vr,ʓGqC̑(۔ʲ}nC> I8ѶabdUYq6 QC6Yzz{+k׳cc}mIk}g?IaAAA kdԅ􆺄 =F[vmkٽnOE""F ~iYBKZIAIIFO=b^01-obU;'L*tcOћ=TR I;S?s954vں^n w5ϏW{W?X-T zµWa3gEgmNޛCI9,eNNmۊKyyz%mRD:Yژ?/ɬdT|8tfX}dQ 9qqԖ''vjϝ 9sc5</\:˟Z][/]nlhkj~Wƾvz 7nݜtֳٷ_)w=½+?vvyңGwsx"}򹳸Ui3g!m'>|!~S_^Z<ߗz'vx]Fo[by?iϤU_4}zo g`@̑plhz:@OmP'*f AIB\@<"7!] P'6(t'G/<> 1@/[a8<E~d/ΗG7qoMA pHYs%%IR$iTXtXML:com.adobe.xmp 282 198 1 6%IDATx} xTչK@ 7!&E.4ȩXƧXִ_s[s*?^pP+R,$@1 &!\&kOv2=L沿3Z~:>$06D<##t"8Ab'01,jꗱ{kx*+Y2Dž!bU*t?YOIoL:Uv^8/}ulT[{2ߖ؇Ku7تRE|>lK{j䲏 ]CeС,`x^YnCd=/}U+Jk3B6;K >we,ǯ?Mg>B➛ ~;)sb.' ?j-#4d-쉣Qrڴy(p.NsnwW^ YE`y$ᤤ8Qؙ; S"k.8n!JS0= *`+GzAEG%¸Q=q̶|*Pa!*S=*P,,Hj'0<^Sx^"Q-F,/`Yz4UġDISbTz:ܤ;!`wk))ivaM{suU{#]蝳Yy[s蘆vmKTZmgsMn$ik?ߤ7b)=e+ceUC)gw#u/ǬK:l_8n7#Կ7:: Mu#ICA*?M&**;cޢq uyV56xiQ'0yBl mTH$$g+-x3|#X8oHy+PqpF?83Xiq=tRAL΂gM rx&6n.h,bQZ} NϟJ$VX_}8 ':?o~ǡTac{=xoCؼF|H4m9~Kxp8-.#۬*jDTgZ`ilvW*_CFļ A >>yi,̷έoe5Dط lDHHf쵿&抱Zrr;~aNsK]2?U܄]5r^^5\>1aRSomVVD+IѝIYXlʣUf7 ґjdse }XkB_\7mVX. yt{ fWbTW 68U)~!c\i:Ts(!"|clT>=oڣ1i?aj*5bjh!mUsW!N%H3MǓ(mM f1gI(PuX#a~ܚ)0/}$P=t^aʎsh'T 5a͊Ob渙XDԗcצc]wv92S½Y|ģg3*;%1dJZL˰}M\a^e9L MvnF~SE.0&UNNE Tv =^O 75.Ld؞a7,$Wӈ{eZvc.*P)a-g( a:`bpS` p G1L nN@(Fmp ( 1dƞ/ecjcmf08"p>C'0]@:QCN3n)Ubms ||ڋ~zQXM#h"uX]2 v sTj*iK::@}Bmk?u{TGB% "l5uX2Т0@a@!0p8}l82cG-NbIv9m~ۀ]&<)uLn잂M;?0bgϢ$WHEb`QdAY@>&>wLTyqWaG\Īބ/ ;k>.,>llZy/Ç] bbLطavP6L=CP/Äer ̸koIilWkik1%fncKЯQVuRJܵr{q(YEرMg%B|aw؈+tJr*<D k8^B9X x&R;W>+( hJVJXA `s)L :v=>S:u<&{|8U01tx6=L pN`bl{T"Щl01é:ESdz`bLJSuCg#p&NfGN)L :v=>S:u<&{|8U01tx6=L pN`bl{T"Щl01é:ESdz`bLJSuCg#p&NfGN)L :v=>S:u<&{|8U01tx6=L pN ஛?:MN(,ꍚuds#qj9aSDxihGɧ+MRiꐊ +o)2;ETG!׫k|̽Q֢z̵{3x OlX0dfc'> s͘>aOI~::K^oM\z̵fd> wѩo#iϭÒ5-8nzD=Dٽo- <~sP U |훹jA2 <(Ϧct=*iHUlt2JGMXo_8=Z7 8@Z8_~وQ WaDY񹂗EOQ ;|~J1o@5lv{?3pCԯ`̦ [jZ0L-]Q~zc)ފL|d|b8}Ou pqX&,XMoL0VD qF_1!( фhJk;]{u ?}@]Z'r~ ymǹ&1q209u"hd3Lj7ظ$+.{YhۺKQmOstb@Wݶύ^ 0.3 s4g*>Ć@Aފ |> 띎T9}W!ZP Ǡy{!>c0V@<71>2^1}uTsf"v&e{.|݊0,ZCŔ;)26IQ⑇"Tr٧qH"<ׅakyi*¼NMRUUVYη->RRQ^G=s$g.Q;qYrQR_z ",3omqhmBB\2~$z &o #`6]8s%vJi=>Sh1Ҋ+uxvQ~\̧ra-f:L5{\& btca򭙐,-Lu +H8Y\d;+9b\u]C2#${? Ow[%*mz8%21ɛ^R~d7v'F{;qrEo_?$%76n,ӀG -6v|IQ!FiuЂXb$UKTd4%z埾7S;EDsM+os"Zp}J"LXz s6G݆F`[!yɻ0 1;>ُE;֠H5H)*!F >˹qw~uoCJ,07 q1Lb|gfq`|}efcՌ.J5Ӱ`#tffa8Jh8,ָRUN>:R(ހj>c};-؂1 ?GM1=FFڈX%!e+,ʆ[֢YP;KFex -2v`{?$=z\g+^jK/"z Ӑٵжp mhEٗ'bIVD qɤ?~oLbd/z<؀107yNIêmږg"sݸɘ6}|vy1|~>ٳq}GR>Sp3hʛrքanXe(Ʃ(tt8ՂJSwtE E hZQ-qϰaUJC4Cxp1n:1_9 Kp/~Jv{>&nLivd~G0kAaLMdpJLL$r[lމ} Z{B% RYZa>VwnK4:ZcaO V⑅?ƾ-wYxɏ=`D=pYgnzs)&, /A|ϙ*oR P}i ؏'Ga)bVcӈ&cEN+=:BiЯpZ0N KIz8N1<(+ h.ª{s|bPРQ%n|%]>+iuvCһaBNp/DP椟Ԓ?2 moI!M?'O^qK{_JW 7av%~"' sl\ȺKTljl!f$.ŮB` HH >@I||LwO.qvf.:JLmȔ"e~QRwp Hco "E$% 갖|ZPb!Н`-012C;Z`bhAetCw.g Ђ&\kA%L ݹ ւC J,;s9&XFw01tr6X L -(`blZPb!Н`-012C;Z`bhAetCw.g Ђ&\kA%L ݹ ւC J,;s9&XFw01tr6X Ac(2G q >Æͷ*+tXu\D}MJ&?IW wVga֜{qqH"rDEEA?_#I,wtteggj64:XI!fbt'(̸_8n;1CDtW-D }D 6: qCoĐC1u,|]q}JQ!s_T@)W> `|0ׯ~y7!b ]@Ce6$/}#ʪZZԌfs+" .! DGG>o054ؚg_PRT=t(309{H\GD8 z(rvxRq\9hx22T j._ 4yU*$ԻJaͺ1;;gBrb<;OŰ#.TVsK3Z縸X v#f5߻>$u#WqtXHH$.&F8U{ JAYqqs'wPE&YH{S' DHYGxP111P+_ߞRp #nԛFUNA9#[`0(Zz9u[n@q,݌Fhe1Dob#Dm& iݔ$&F}4ܿЈdZm|nNM61p,1ɣr 4YFQhmF_KMgab8CEqhObʔ;KZhi': "&ނʄ'qhUyiRҎ1QmmH>Fкw6lš2 $UDDANEDXߡPH :Zt򂼇҂dk4F2 q0p;hū?FS6&F]lРAhi21'$Ҏu?RU" 9dbLkk+>;9hg[@l6 btCիW#%m&ZM#㫒S6##x|PM K7M Q Y =v*6ne,F%0 )!ĹZjS$#G_ $ L@DuSGRRRNdd$(YBB qW.AktNjlhZ+d.J^onQ ;#\.RC<4+1 İI3r-'DZ4v1aNԭE1DbÜ+?c5Ԫ bGyrپ=ʲ55hN r M`ct#^sq b{j#yq)wA SaTFȴV4I܋<.Nuuuh8j.VEN= " bК)xV^> ! E)jUQSwI[&]E/Qu%Sicƕ+Wh2h"|=zpJC-TW5 Rd2$\yk]o|7&F$`cܭ:$&зi^!5@L1rEmIABS!z 3-655JQ&'fZP҉LY "#8\Z& (sy sv%!]L0J|给HQG=PJpA*#ӻʉgi8E_0Ds(1 AAǰgM)n1ZO]i@-w6&gx3i7&N'i_CQsDGQ.⮬Dyk]}aW'QTRd ;#h]8~؃:hGnW͹_޿PvÅP6jS}Ĥt~  Vg*&;Tp#M0k,+/t+~Fb*&UGF);mt]o8~ier/*21BSS_&䈧:}ۏ X't@Z2 jjjq/QZ'hAp={gQT=pB#BghթegPv\o"LPtPID|D!~9oq7C.cXon1/Po`+){&b[/`bx gOWK^&Fx&rD~eD%=<`b_*/`bx gOWK^&Fx&rD~eD%=<`b_*/`bx gOWK^&Fx&rD~eD%=<`b_*/`bx gOWK^&Fx&rD~eD%=<`b_*/`bx gOWK^&Fx&rD~eD绡Ku8;#p~`- II,V1Ïs)^<Vf{ nP$]#=ƻB 5L ]w2kv? &+d8^01t~6L Wp`bl+x]#еxW01\!FԲkSIENDB`tvxwidgets-0.12.1/dialog.go000066400000000000000000000135761506765256500156260ustar00rootroot00000000000000package tvxwidgets import ( "strings" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) // represents dialog type. const ( InfoDialog = 0 + iota ErrorDailog ) // MessageDialog represents message dialog primitive. type MessageDialog struct { *tview.Box // layout message dialog layout layout *tview.Flex // message view textview *tview.TextView // dialog form buttons form *tview.Form // message dialog X x int // message dialog Y y int // message dialog width width int // message dialog heights height int // dialog type info and error // type will change the default background color for the dialog messageType int // background color bgColor tcell.Color // message dialog text message to display. message string // callback for when user clicked on the button or presses "enter" or "esc" doneHandler func() } // NewMessageDialog returns a new message dialog primitive. func NewMessageDialog(dtype int) *MessageDialog { dialog := &MessageDialog{ Box: tview.NewBox(), messageType: dtype, bgColor: tcell.ColorSteelBlue, } dialog.textview = tview.NewTextView(). SetDynamicColors(true). SetWrap(true). SetTextAlign(tview.AlignLeft) dialog.form = tview.NewForm(). AddButton("Enter", nil). SetButtonsAlign(tview.AlignRight) dialog.layout = tview.NewFlex().SetDirection(tview.FlexRow) dialog.layout.AddItem(dialog.textview, 0, 0, true) dialog.layout.AddItem(dialog.form, dialogFormHeight, 0, true) dialog.layout.SetBorder(true) dialog.setColor() return dialog } // SetType sets dialog type to info or error. func (d *MessageDialog) SetType(dtype int) { if dtype >= 0 && dtype <= 1 { d.messageType = dtype d.setColor() } } // SetTitle sets dialog title. func (d *MessageDialog) SetTitle(title string) { d.layout.SetTitle(title) } // SetBackgroundColor sets dialog background color. func (d *MessageDialog) SetBackgroundColor(color tcell.Color) { d.bgColor = color d.setColor() } // SetMessage sets the dialog message to display. func (d *MessageDialog) SetMessage(message string) { d.message = "\n" + message d.textview.Clear() d.textview.SetText(d.message) d.textview.ScrollToBeginning() d.setRect() } // Focus is called when this primitive receives focus. func (d *MessageDialog) Focus(delegate func(p tview.Primitive)) { delegate(d.form) } // HasFocus returns whether or not this primitive has focus. func (d *MessageDialog) HasFocus() bool { return d.form.HasFocus() } // SetRect sets rect for this primitive. func (d *MessageDialog) SetRect(x, y, width, height int) { d.x = x d.y = y d.width = width d.height = height d.setRect() } // SetTextColor sets dialog's message text color. func (d *MessageDialog) SetTextColor(color tcell.Color) { d.textview.SetTextColor(color) } // Draw draws this primitive onto the screen. func (d *MessageDialog) Draw(screen tcell.Screen) { d.DrawForSubclass(screen, d) x, y, width, height := d.GetInnerRect() d.layout.SetRect(x, y, width, height) d.layout.Draw(screen) } // InputHandler returns input handler function for this primitive. func (d *MessageDialog) InputHandler() func(event *tcell.EventKey, setFocus func(p tview.Primitive)) { return d.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p tview.Primitive)) { if event.Key() == tcell.KeyDown || event.Key() == tcell.KeyUp || event.Key() == tcell.KeyPgDn || event.Key() == tcell.KeyPgUp { //nolint:lll if textHandler := d.textview.InputHandler(); textHandler != nil { textHandler(event, setFocus) return } } if formHandler := d.form.InputHandler(); formHandler != nil { formHandler(event, setFocus) return } }) } // MouseHandler returns the mouse handler for this primitive. func (d *MessageDialog) MouseHandler() func(action tview.MouseAction, event *tcell.EventMouse, setFocus func(p tview.Primitive)) (consumed bool, capture tview.Primitive) { //nolint:lll return d.WrapMouseHandler(func(action tview.MouseAction, event *tcell.EventMouse, setFocus func(p tview.Primitive)) (consumed bool, capture tview.Primitive) { //nolint:lll,nonamedreturns // Pass mouse events on to the form. consumed, capture = d.form.MouseHandler()(action, event, setFocus) if !consumed && action == tview.MouseLeftClick && d.InRect(event.Position()) { setFocus(d) consumed = true } return consumed, capture }) } // SetDoneFunc sets callback function for when user clicked on // the button or presses "enter" or "esc". func (d *MessageDialog) SetDoneFunc(handler func()) *MessageDialog { d.doneHandler = handler enterButton := d.form.GetButton(d.form.GetButtonCount() - 1) enterButton.SetSelectedFunc(handler) return d } // GetBackgroundColor returns dialog background color. func (d *MessageDialog) GetBackgroundColor() tcell.Color { return d.bgColor } func (d *MessageDialog) setColor() { var bgColor tcell.Color switch d.messageType { case InfoDialog: bgColor = d.bgColor case ErrorDailog: bgColor = tcell.ColorOrangeRed } d.form.SetBackgroundColor(bgColor) d.textview.SetBackgroundColor(bgColor) d.layout.SetBackgroundColor(bgColor) d.bgColor = bgColor } func (d *MessageDialog) setRect() { maxHeight := d.height maxWidth := d.width messageHeight := len(strings.Split(d.message, "\n")) messageWidth := getMessageWidth(d.message) layoutHeight := messageHeight if maxHeight > layoutHeight+dialogFormHeight { d.height = layoutHeight + dialogFormHeight + dialogPadding } else { d.height = maxHeight layoutHeight = d.height - dialogFormHeight - dialogPadding } if maxHeight > d.height { emptyHeight := (maxHeight - d.height) / emptySpaceParts d.y += emptyHeight } if d.width > messageWidth { d.width = messageWidth + dialogPadding } if maxWidth > d.width { emptyWidth := (maxWidth - d.width) / emptySpaceParts d.x += emptyWidth } d.layout.Clear() d.layout.AddItem(d.textview, layoutHeight, 0, true) d.layout.AddItem(d.form, dialogFormHeight, 0, true) d.Box.SetRect(d.x, d.y, d.width, d.height) } tvxwidgets-0.12.1/dialog_test.go000066400000000000000000000032221506765256500166500ustar00rootroot00000000000000package tvxwidgets_test import ( "github.com/gdamore/tcell/v2" "github.com/navidys/tvxwidgets" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/rivo/tview" ) var _ = Describe("Dialog", Ordered, func() { var ( app *tview.Application headerBox *tview.Box msgDialog *tvxwidgets.MessageDialog screen tcell.SimulationScreen ) BeforeAll(func() { app = tview.NewApplication() headerBox = tview.NewBox().SetBorder(true) msgDialog = tvxwidgets.NewMessageDialog(tvxwidgets.InfoDialog) screen = tcell.NewSimulationScreen("UTF-8") if err := screen.Init(); err != nil { panic(err) } go func() { appLayout := tview.NewFlex().SetDirection(tview.FlexRow) appLayout.AddItem(headerBox, 0, 1, true) appLayout.AddItem(msgDialog, 0, 1, true) err := app.SetScreen(screen).SetRoot(appLayout, true).Run() if err != nil { panic(err) } }() }) AfterAll(func() { app.Stop() }) Describe("NewMessageDialog", func() { It("returns a new message dialog primitive", func() { tests := []struct { msgType int bgColor tcell.Color }{ {msgType: tvxwidgets.InfoDialog, bgColor: tcell.ColorSteelBlue}, {msgType: tvxwidgets.ErrorDailog, bgColor: tcell.ColorOrangeRed}, } for _, test := range tests { msgDialog.SetType(test.msgType) app.Draw() Expect(msgDialog.GetBackgroundColor()).To(Equal(test.bgColor)) } }) }) Describe("Focus", func() { It("checks primitivie focus", func() { app.SetFocus(headerBox) app.Draw() Expect(msgDialog.HasFocus()).To(Equal(false)) app.SetFocus(msgDialog) app.Draw() Expect(msgDialog.HasFocus()).To(Equal(true)) }) }) }) tvxwidgets-0.12.1/export_test.go000066400000000000000000000004411506765256500167320ustar00rootroot00000000000000package tvxwidgets var ( GetColorName = getColorName GetMessageWidth = getMessageWidth GetMaxFloat64From2dSlice = getMaxFloat64From2dSlice GetMaxFloat64FromSlice = getMaxFloat64FromSlice DrawLine = drawLine AbsInt = absInt ) tvxwidgets-0.12.1/gauge_am.go000066400000000000000000000044661506765256500161320ustar00rootroot00000000000000package tvxwidgets import ( "fmt" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) // ActivityModeGauge represents activity mode gauge permitive. type ActivityModeGauge struct { *tview.Box // counter value counter int // pgBgColor: progress block background color pgBgColor tcell.Color } // NewActivityModeGauge returns new activity mode gauge permitive. func NewActivityModeGauge() *ActivityModeGauge { gauge := &ActivityModeGauge{ Box: tview.NewBox(), counter: 0, pgBgColor: tcell.ColorBlue, } return gauge } // Draw draws this primitive onto the screen. func (g *ActivityModeGauge) Draw(screen tcell.Screen) { g.DrawForSubclass(screen, g) x, y, width, height := g.GetInnerRect() tickStr := g.tickStr(width) for i := range height { tview.Print(screen, tickStr, x, y+i, width, tview.AlignLeft, g.pgBgColor) } } // Focus is called when this primitive receives focus. func (g *ActivityModeGauge) Focus(delegate func(p tview.Primitive)) { } // HasFocus returns whether or not this primitive has focus. func (g *ActivityModeGauge) HasFocus() bool { return g.Box.HasFocus() } // GetRect return primitive current rect. func (g *ActivityModeGauge) GetRect() (int, int, int, int) { return g.Box.GetRect() } // SetRect sets rect for this primitive. func (g *ActivityModeGauge) SetRect(x, y, width, height int) { g.Box.SetRect(x, y, width, height) } // SetPgBgColor sets progress block background color. func (g *ActivityModeGauge) SetPgBgColor(color tcell.Color) { g.pgBgColor = color } // Pulse pulse update the gauge progress bar. func (g *ActivityModeGauge) Pulse() { g.counter++ } // Reset resets the gauge counter (set to 0). func (g *ActivityModeGauge) Reset() { g.counter = 0 } func (g *ActivityModeGauge) tickStr(maxCount int) string { var ( prgHeadStr string prgEndStr string prgStr string ) if g.counter >= maxCount-4 { g.counter = 0 } hWidth := 0 for range g.counter { prgHeadStr += fmt.Sprintf("[%s::]%s", getColorName(tview.Styles.PrimitiveBackgroundColor), prgCell) hWidth++ } prgStr = prgCell + prgCell + prgCell + prgCell for range maxCount + hWidth + 4 { prgEndStr += fmt.Sprintf("[%s::]%s", getColorName(tview.Styles.PrimitiveBackgroundColor), prgCell) } return fmt.Sprintf("%s[%s::]%s%s", prgHeadStr, getColorName(g.pgBgColor), prgStr, prgEndStr) } tvxwidgets-0.12.1/gauge_am_test.go000066400000000000000000000026771506765256500171730ustar00rootroot00000000000000package tvxwidgets_test import ( "github.com/gdamore/tcell/v2" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/rivo/tview" "github.com/navidys/tvxwidgets" ) var _ = Describe("GaugeAm", Ordered, func() { var ( app *tview.Application headerBox *tview.Box gaugeAm *tvxwidgets.ActivityModeGauge screen tcell.SimulationScreen ) BeforeAll(func() { app = tview.NewApplication() headerBox = tview.NewBox().SetBorder(true) gaugeAm = tvxwidgets.NewActivityModeGauge() screen = tcell.NewSimulationScreen("UTF-8") if err := screen.Init(); err != nil { panic(err) } go func() { appLayout := tview.NewFlex().SetDirection(tview.FlexRow) appLayout.AddItem(headerBox, 1, 0, true) appLayout.AddItem(gaugeAm, 50, 0, true) err := app.SetScreen(screen).SetRoot(appLayout, true).Run() if err != nil { panic(err) } }() }) AfterAll(func() { app.Stop() }) Describe("Focus", func() { It("checks primitivie focus", func() { app.SetFocus(headerBox) app.Draw() Expect(gaugeAm.HasFocus()).To(Equal(false)) app.SetFocus(gaugeAm) gaugeAm.Pulse() app.Draw() // gauge will not get focus Expect(gaugeAm.HasFocus()).To(Equal(false)) }) }) Describe("GetRect", func() { It("primitivie size", func() { x, y, width, heigth := gaugeAm.GetRect() Expect(x).To(Equal(0)) Expect(y).To(Equal(1)) Expect(width).To(Equal(80)) Expect(heigth).To(Equal(50)) }) }) }) tvxwidgets-0.12.1/gauge_pm.go000066400000000000000000000062551506765256500161470ustar00rootroot00000000000000package tvxwidgets import ( "fmt" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) // PercentageModeGauge represents percentage mode gauge permitive. type PercentageModeGauge struct { *tview.Box // maxValue value maxValue int // value is current value value int // pgBgColor: progress block background color pgBgColor tcell.Color } // NewPercentageModeGauge returns new percentage mode gauge permitive. func NewPercentageModeGauge() *PercentageModeGauge { gauge := &PercentageModeGauge{ Box: tview.NewBox(), value: 0, pgBgColor: tcell.ColorBlue, } return gauge } // Draw draws this primitive onto the screen. func (g *PercentageModeGauge) Draw(screen tcell.Screen) { g.DrawForSubclass(screen, g) if g.maxValue == 0 { return } x, y, width, height := g.GetInnerRect() pcWidth := 3 pc := g.value * gaugeMaxPc / g.maxValue pcString := fmt.Sprintf("%d%%", pc) tW := width - pcWidth tX := x + (tW / emptySpaceParts) tY := y + height/emptySpaceParts prgBlock := g.progressBlock(width) style := tcell.StyleDefault.Background(g.pgBgColor).Foreground(tview.Styles.PrimaryTextColor) for i := range height { for j := range prgBlock { screen.SetContent(x+j, y+i, ' ', nil, style) } } // print percentage in middle of box pcRune := []rune(pcString) for j := range pcRune { style = tcell.StyleDefault.Background(tview.Styles.PrimitiveBackgroundColor).Foreground(tview.Styles.PrimaryTextColor) if x+prgBlock >= tX+j { style = tcell.StyleDefault.Background(g.pgBgColor).Foreground(tview.Styles.PrimaryTextColor) } for i := range height { screen.SetContent(tX+j, y+i, ' ', nil, style) } screen.SetContent(tX+j, tY, pcRune[j], nil, style) } } // Focus is called when this primitive receives focus. func (g *PercentageModeGauge) Focus(delegate func(p tview.Primitive)) { } // HasFocus returns whether or not this primitive has focus. func (g *PercentageModeGauge) HasFocus() bool { return g.Box.HasFocus() } // GetRect return primitive current rect. func (g *PercentageModeGauge) GetRect() (int, int, int, int) { return g.Box.GetRect() } // SetRect sets rect for this primitive. func (g *PercentageModeGauge) SetRect(x, y, width, height int) { g.Box.SetRect(x, y, width, height) } // SetPgBgColor sets progress block background color. func (g *PercentageModeGauge) SetPgBgColor(color tcell.Color) { g.pgBgColor = color } // SetValue update the gauge progress. func (g *PercentageModeGauge) SetValue(value int) { if value <= g.maxValue { g.value = value } } // GetValue returns current gauge value. func (g *PercentageModeGauge) GetValue() int { return g.value } // SetMaxValue set maximum allows value for the gauge. func (g *PercentageModeGauge) SetMaxValue(value int) { if value > 0 { g.maxValue = value } } // GetMaxValue returns maximum allows value for the gauge. func (g *PercentageModeGauge) GetMaxValue() int { return g.maxValue } // Reset resets the gauge counter (set to 0). func (g *PercentageModeGauge) Reset() { g.value = 0 } func (g *PercentageModeGauge) progressBlock(maxValue int) int { if g.maxValue == 0 { return g.maxValue } pc := g.value * gaugeMaxPc / g.maxValue value := pc * maxValue / gaugeMaxPc return value } tvxwidgets-0.12.1/gauge_pm_test.go000066400000000000000000000026601506765256500172020ustar00rootroot00000000000000package tvxwidgets_test import ( "github.com/gdamore/tcell/v2" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/rivo/tview" "github.com/navidys/tvxwidgets" ) var _ = Describe("GaugePm", Ordered, func() { var ( app *tview.Application headerBox *tview.Box gaugePm *tvxwidgets.PercentageModeGauge screen tcell.SimulationScreen ) BeforeAll(func() { app = tview.NewApplication() headerBox = tview.NewBox().SetBorder(true) gaugePm = tvxwidgets.NewPercentageModeGauge() screen = tcell.NewSimulationScreen("UTF-8") if err := screen.Init(); err != nil { panic(err) } go func() { appLayout := tview.NewFlex().SetDirection(tview.FlexRow) appLayout.AddItem(headerBox, 1, 0, true) appLayout.AddItem(gaugePm, 50, 0, true) err := app.SetScreen(screen).SetRoot(appLayout, true).Run() if err != nil { panic(err) } }() }) AfterAll(func() { app.Stop() }) Describe("Focus", func() { It("checks primitivie focus", func() { app.SetFocus(headerBox) app.Draw() Expect(gaugePm.HasFocus()).To(Equal(false)) app.SetFocus(gaugePm) app.Draw() // gauge will not get focus Expect(gaugePm.HasFocus()).To(Equal(false)) }) }) Describe("GetRect", func() { It("primitivie size", func() { x, y, width, heigth := gaugePm.GetRect() Expect(x).To(Equal(0)) Expect(y).To(Equal(1)) Expect(width).To(Equal(80)) Expect(heigth).To(Equal(50)) }) }) }) tvxwidgets-0.12.1/gauge_um.go000066400000000000000000000072271506765256500161540ustar00rootroot00000000000000package tvxwidgets import ( "fmt" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) // UtilModeGauge represents utilisation mode gauge permitive. type UtilModeGauge struct { *tview.Box // pc percentage value pc float64 // warn percentage value warnPc float64 // critical percentage value critPc float64 // okColor ok color okColor tcell.Color // warnColor warning block color warnColor tcell.Color // critColor critical block color critColor tcell.Color // emptyColor empty block color emptyColor tcell.Color // label prints label on the left of the gauge label string // labelColor label and percentage text color labelColor tcell.Color } // NewUtilModeGauge returns new utilisation mode gauge permitive. func NewUtilModeGauge() *UtilModeGauge { gauge := &UtilModeGauge{ Box: tview.NewBox(), pc: gaugeMinPc, warnPc: gaugeWarnPc, critPc: gaugeCritPc, warnColor: tcell.ColorOrange, critColor: tcell.ColorRed, okColor: tcell.ColorGreen, emptyColor: tcell.ColorWhite, labelColor: tview.Styles.PrimaryTextColor, label: "", } return gauge } // SetLabel sets label for this primitive. func (g *UtilModeGauge) SetLabel(label string) { g.label = label } // SetLabelColor sets label text color. func (g *UtilModeGauge) SetLabelColor(color tcell.Color) { g.labelColor = color } // Focus is called when this primitive receives focus. func (g *UtilModeGauge) Focus(delegate func(p tview.Primitive)) { } // HasFocus returns whether or not this primitive has focus. func (g *UtilModeGauge) HasFocus() bool { return g.Box.HasFocus() } // GetRect return primitive current rect. func (g *UtilModeGauge) GetRect() (int, int, int, int) { return g.Box.GetRect() } // SetRect sets rect for this primitive. func (g *UtilModeGauge) SetRect(x, y, width, height int) { g.Box.SetRect(x, y, width, height) } // SetValue update the gauge progress. func (g *UtilModeGauge) SetValue(value float64) { if value <= float64(gaugeMaxPc) { g.pc = value } } // GetValue returns current gauge value. func (g *UtilModeGauge) GetValue() float64 { return g.pc } // Draw draws this primitive onto the screen. func (g *UtilModeGauge) Draw(screen tcell.Screen) { g.DrawForSubclass(screen, g) x, y, width, height := g.GetInnerRect() labelPCWidth := 7 labelWidth := len(g.label) barWidth := width - labelPCWidth - labelWidth for i := range barWidth { for j := range height { value := float64(i * 100 / barWidth) color := g.getBarColor(value) if value > g.pc { color = g.emptyColor } tview.Print(screen, prgCell, x+labelWidth+i, y+j, 1, tview.AlignCenter, color) } } // draw label tY := y + (height / emptySpaceParts) if labelWidth > 0 { tview.Print(screen, g.label, x, tY, labelWidth, tview.AlignLeft, g.labelColor) } // draw percentage text tview.Print(screen, fmt.Sprintf("%6.2f%%", g.pc), x+barWidth+labelWidth, tY, labelPCWidth, tview.AlignLeft, tview.Styles.PrimaryTextColor) } // SetWarnPercentage sets warning percentage start range. func (g *UtilModeGauge) SetWarnPercentage(percentage float64) { if percentage > 0 && percentage < 100 { g.warnPc = percentage } } // SetCritPercentage sets critical percentage start range. func (g *UtilModeGauge) SetCritPercentage(percentage float64) { if percentage > 0 && percentage < 100 && percentage > g.warnPc { g.critPc = percentage } } // SetEmptyColor sets empty gauge color. func (g *UtilModeGauge) SetEmptyColor(color tcell.Color) { g.emptyColor = color } func (g *UtilModeGauge) getBarColor(percentage float64) tcell.Color { if percentage < g.warnPc { return g.okColor } else if percentage < g.critPc { return g.warnColor } return g.critColor } tvxwidgets-0.12.1/gauge_um_test.go000066400000000000000000000026441506765256500172110ustar00rootroot00000000000000package tvxwidgets_test import ( "github.com/gdamore/tcell/v2" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/rivo/tview" "github.com/navidys/tvxwidgets" ) var _ = Describe("GaugeUm", Ordered, func() { var ( app *tview.Application headerBox *tview.Box gaugeUm *tvxwidgets.UtilModeGauge screen tcell.SimulationScreen ) BeforeAll(func() { app = tview.NewApplication() headerBox = tview.NewBox().SetBorder(true) gaugeUm = tvxwidgets.NewUtilModeGauge() screen = tcell.NewSimulationScreen("UTF-8") if err := screen.Init(); err != nil { panic(err) } go func() { appLayout := tview.NewFlex().SetDirection(tview.FlexRow) appLayout.AddItem(headerBox, 1, 0, true) appLayout.AddItem(gaugeUm, 50, 0, true) err := app.SetScreen(screen).SetRoot(appLayout, true).Run() if err != nil { panic(err) } }() }) AfterAll(func() { app.Stop() }) Describe("Focus", func() { It("checks primitivie focus", func() { app.SetFocus(headerBox) app.Draw() Expect(gaugeUm.HasFocus()).To(Equal(false)) app.SetFocus(gaugeUm) app.Draw() // gauge will not get focus Expect(gaugeUm.HasFocus()).To(Equal(false)) }) }) Describe("GetRect", func() { It("primitivie size", func() { x, y, width, heigth := gaugeUm.GetRect() Expect(x).To(Equal(0)) Expect(y).To(Equal(1)) Expect(width).To(Equal(80)) Expect(heigth).To(Equal(50)) }) }) }) tvxwidgets-0.12.1/go.mod000066400000000000000000000016661506765256500151430ustar00rootroot00000000000000module github.com/navidys/tvxwidgets go 1.24.7 require ( github.com/gdamore/tcell/v2 v2.9.0 github.com/onsi/ginkgo/v2 v2.25.3 github.com/onsi/gomega v1.38.2 github.com/rivo/tview v0.42.0 ) require ( github.com/Masterminds/semver/v3 v3.4.0 // indirect github.com/gdamore/encoding v1.0.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/rivo/uniseg v0.4.7 // indirect go.uber.org/automaxprocs v1.6.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/net v0.43.0 // indirect golang.org/x/sys v0.35.0 // indirect golang.org/x/term v0.34.0 // indirect golang.org/x/text v0.28.0 // indirect golang.org/x/tools v0.36.0 // indirect ) tvxwidgets-0.12.1/go.sum000066400000000000000000000176711506765256500151730ustar00rootroot00000000000000github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw= github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo= github.com/gdamore/tcell/v2 v2.9.0 h1:N6t+eqK7/xwtRPwxzs1PXeRWnm0H9l02CrgJ7DLn1ys= github.com/gdamore/tcell/v2 v2.9.0/go.mod h1:8/ZoqM9rxzYphT9tH/9LnunhV9oPBqwS8WHGYm5nrmo= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/onsi/ginkgo/v2 v2.25.3 h1:Ty8+Yi/ayDAGtk4XxmmfUy4GabvM+MegeB4cDLRi6nw= github.com/onsi/ginkgo/v2 v2.25.3/go.mod h1:43uiyQC4Ed2tkOzLsEYm7hnrb7UJTWHYNsuy3bG/snE= github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/rivo/tview v0.42.0 h1:b/ftp+RxtDsHSaynXTbJb+/n/BxDEi+W3UfF5jILK6c= github.com/rivo/tview v0.42.0/go.mod h1:cSfIYfhpSGCjp3r/ECJb+GKS7cGJnqV8vfjQPwoXyfY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg= golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= tvxwidgets-0.12.1/hack/000077500000000000000000000000001506765256500147325ustar00rootroot00000000000000tvxwidgets-0.12.1/hack/install_golangci.sh000077500000000000000000000013271506765256500206050ustar00rootroot00000000000000#!/usr/bin/env bash # code from: https://raw.githubusercontent.com/containers/podman/main/hack/install_golangci.sh die() { echo "${1:-No error message given} (from $(basename $0))"; exit 1; } [ -n "$VERSION" ] || die "\$VERSION is empty or undefined" function install() { echo "Installing golangci-lint v$VERSION into $BIN" curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v$VERSION } BIN="./bin/golangci-lint" if [ ! -x "$BIN" ]; then install else # Prints its own file name as part of --version output $BIN --version | grep "$VERSION" if [ $? -eq 0 ]; then echo "Using existing $(dirname $BIN)/$($BIN --version)" else install fi fi tvxwidgets-0.12.1/plot.go000066400000000000000000000367001506765256500153370ustar00rootroot00000000000000package tvxwidgets import ( "fmt" "image" "math" "strconv" "strings" "sync" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) // Marker represents plot drawing marker (braille or dot). type Marker uint const ( PlotMarkerBraille Marker = iota PlotMarkerDot ) // PlotYAxisLabelDataType represents plot y axis type (integer or float). type PlotYAxisLabelDataType uint const ( PlotYAxisLabelDataInt PlotYAxisLabelDataType = iota PlotYAxisLabelDataFloat ) // PlotType represents plot type (line chart or scatter). type PlotType uint const ( PlotTypeLineChart PlotType = iota PlotTypeScatter ) const ( plotHorizontalScale = 1 plotXAxisLabelsHeight = 1 plotXAxisLabelsGap = 2 plotYAxisLabelsGap = 1 gapRune = " " ) type brailleCell struct { cRune rune color tcell.Color } // Plot represents a plot primitive used for different charts. type Plot struct { *tview.Box data [][]float64 // maxVal is the maximum y-axis (vertical) value found in any of the lines in the data set. maxVal float64 // minVal is the minimum y-axis (vertical) value found in any of the lines in the data set. minVal float64 marker Marker ptype PlotType dotMarkerRune rune lineColors []tcell.Color axesColor tcell.Color axesLabelColor tcell.Color drawAxes bool drawXAxisLabel bool xAxisLabelFunc func(int) string drawYAxisLabel bool yAxisLabelDataType PlotYAxisLabelDataType yAxisAutoScaleMin bool yAxisAutoScaleMax bool brailleCellMap map[image.Point]brailleCell mu sync.Mutex } // NewPlot returns a plot widget. func NewPlot() *Plot { return &Plot{ Box: tview.NewBox(), marker: PlotMarkerDot, ptype: PlotTypeLineChart, dotMarkerRune: dotRune, axesColor: tcell.ColorDimGray, axesLabelColor: tcell.ColorDimGray, drawAxes: true, drawXAxisLabel: true, xAxisLabelFunc: strconv.Itoa, drawYAxisLabel: true, yAxisLabelDataType: PlotYAxisLabelDataFloat, yAxisAutoScaleMin: false, yAxisAutoScaleMax: true, lineColors: []tcell.Color{ tcell.ColorSteelBlue, }, } } // Draw draws this primitive onto the screen. func (plot *Plot) Draw(screen tcell.Screen) { plot.DrawForSubclass(screen, plot) switch plot.marker { case PlotMarkerDot: plot.drawDotMarkerToScreen(screen) case PlotMarkerBraille: plot.drawBrailleMarkerToScreen(screen) } plot.drawAxesToScreen(screen) } // SetRect sets rect for this primitive. func (plot *Plot) SetRect(x, y, width, height int) { plot.Box.SetRect(x, y, width, height) } // SetLineColor sets chart line color. func (plot *Plot) SetLineColor(color []tcell.Color) { plot.lineColors = color } // SetYAxisLabelDataType sets Y axis label data type (integer or float). func (plot *Plot) SetYAxisLabelDataType(dataType PlotYAxisLabelDataType) { plot.yAxisLabelDataType = dataType } // SetYAxisAutoScaleMin enables YAxis min value autoscale. func (plot *Plot) SetYAxisAutoScaleMin(autoScale bool) { plot.yAxisAutoScaleMin = autoScale } // SetYAxisAutoScaleMax enables YAxix max value autoscale. func (plot *Plot) SetYAxisAutoScaleMax(autoScale bool) { plot.yAxisAutoScaleMax = autoScale } // SetAxesColor sets axes x and y lines color. func (plot *Plot) SetAxesColor(color tcell.Color) { plot.axesColor = color } // SetAxesLabelColor sets axes x and y label color. func (plot *Plot) SetAxesLabelColor(color tcell.Color) { plot.axesLabelColor = color } // SetDrawAxes set true in order to draw axes to screen. func (plot *Plot) SetDrawAxes(draw bool) { plot.drawAxes = draw } // SetDrawXAxisLabel set true in order to draw x axis label to screen. func (plot *Plot) SetDrawXAxisLabel(draw bool) { plot.drawXAxisLabel = draw } // SetXAxisLabelFunc sets x axis label function. func (plot *Plot) SetXAxisLabelFunc(f func(int) string) { plot.xAxisLabelFunc = f } // SetDrawYAxisLabel set true in order to draw y axis label to screen. func (plot *Plot) SetDrawYAxisLabel(draw bool) { plot.drawYAxisLabel = draw } // SetMarker sets marker type braille or dot mode. func (plot *Plot) SetMarker(marker Marker) { plot.marker = marker } // SetPlotType sets plot type (linechart or scatter). func (plot *Plot) SetPlotType(ptype PlotType) { plot.ptype = ptype } // SetData sets plot data. func (plot *Plot) SetData(data [][]float64) { plot.mu.Lock() defer plot.mu.Unlock() plot.brailleCellMap = make(map[image.Point]brailleCell) plot.data = data if plot.yAxisAutoScaleMax { plot.maxVal = getMaxFloat64From2dSlice(data) } if plot.yAxisAutoScaleMin { plot.minVal = getMinFloat64From2dSlice(data) } } // SetMaxVal sets plot maximum value. func (plot *Plot) SetMaxVal(maxVal float64) { plot.maxVal = maxVal } // SetMinVal sets plot minimum value. func (plot *Plot) SetMinVal(minVal float64) { plot.minVal = minVal } // SetYRange sets plot Y range. func (plot *Plot) SetYRange(minVal float64, maxVal float64) { plot.minVal = minVal plot.maxVal = maxVal } // SetDotMarkerRune sets dot marker rune. func (plot *Plot) SetDotMarkerRune(r rune) { plot.dotMarkerRune = r } // GetPlotRect returns the rect for the inner part of the plot, ie not including axes. func (plot *Plot) GetPlotRect() (int, int, int, int) { x, y, width, height := plot.GetInnerRect() plotYAxisLabelsWidth := plot.getYAxisLabelsWidth() if plot.drawAxes { x = x + plotYAxisLabelsWidth + 1 width = width - plotYAxisLabelsWidth - 1 height = height - plotXAxisLabelsHeight - 1 } else { x++ width-- } return x, y, width, height } // Figure out the text width necessary to display the largest data value. func (plot *Plot) getYAxisLabelsWidth() int { return len(fmt.Sprintf("%.2f", plot.maxVal)) } func (plot *Plot) getData() [][]float64 { plot.mu.Lock() data := plot.data plot.mu.Unlock() return data } func (plot *Plot) drawAxesToScreen(screen tcell.Screen) { if !plot.drawAxes { return } x, y, width, height := plot.GetInnerRect() plotYAxisLabelsWidth := plot.getYAxisLabelsWidth() axesStyle := tcell.StyleDefault.Background(plot.GetBackgroundColor()).Foreground(plot.axesColor) // draw Y axis line drawLine(screen, x+plotYAxisLabelsWidth, y, height-plotXAxisLabelsHeight-1, verticalLine, axesStyle) // draw X axis line drawLine(screen, x+plotYAxisLabelsWidth+1, y+height-plotXAxisLabelsHeight-1, width-plotYAxisLabelsWidth-1, horizontalLine, axesStyle) tview.PrintJoinedSemigraphics(screen, x+plotYAxisLabelsWidth, y+height-plotXAxisLabelsHeight-1, tview.BoxDrawingsLightUpAndRight, axesStyle) if plot.drawXAxisLabel { plot.drawXAxisLabelsToScreen(screen, plotYAxisLabelsWidth, x, y, width, height) } if plot.drawYAxisLabel { plot.drawYAxisLabelsToScreen(screen, plotYAxisLabelsWidth, x, y, height) } } //nolint:funlen,cyclop func (plot *Plot) drawXAxisLabelsToScreen( screen tcell.Screen, plotYAxisLabelsWidth int, x int, y int, width int, height int, ) { xAxisAreaStartX := x + plotYAxisLabelsWidth + 1 xAxisAreaEndX := x + width xAxisAvailableWidth := xAxisAreaEndX - xAxisAreaStartX labelMap := map[int]string{} labelStartMap := map[int]int{} maxDataPoints := 0 for _, d := range plot.data { maxDataPoints = max(maxDataPoints, len(d)) } // determine the width needed for the largest label maxXAxisLabelWidth := 0 for _, d := range plot.data { for i := range d { label := plot.xAxisLabelFunc(i) labelMap[i] = label maxXAxisLabelWidth = max(maxXAxisLabelWidth, len(label)) } } // determine the start position for each label, if they were // to be centered below the data point. // Note: not all of these labels will be printed, as they would // overlap with each other for i, label := range labelMap { expectedLabelWidth := len(label) if i == 0 { expectedLabelWidth += plotXAxisLabelsGap / 2 //nolint:mnd } else { expectedLabelWidth += plotXAxisLabelsGap } currentLabelStart := i - int(math.Round(float64(expectedLabelWidth)/2)) //nolint:mnd labelStartMap[i] = currentLabelStart } // print the labels, skipping those that would overlap, // stopping when there is no more space lastUsedLabelEnd := math.MinInt initialOffset := xAxisAreaStartX for i := range maxDataPoints { labelStart := labelStartMap[i] if labelStart < lastUsedLabelEnd { // the label would overlap with the previous label continue } rawLabel := labelMap[i] labelWithGap := rawLabel if i == 0 { labelWithGap += strings.Repeat(gapRune, plotXAxisLabelsGap/2) //nolint:mnd } else { labelWithGap = strings.Repeat(gapRune, plotXAxisLabelsGap/2) + labelWithGap + strings.Repeat(gapRune, plotXAxisLabelsGap/2) //nolint:lll,mnd } expectedLabelWidth := len(labelWithGap) remainingWidth := xAxisAvailableWidth - labelStart if expectedLabelWidth > remainingWidth { // the label would be too long to fit in the remaining space if expectedLabelWidth-1 <= remainingWidth { // if we omit the last gap, it fits, so we draw that before stopping labelWithoutGap := labelWithGap[:len(labelWithGap)-1] plot.printXAxisLabel(screen, labelWithoutGap, initialOffset+labelStart, y+height-plotXAxisLabelsHeight) } break } lastUsedLabelEnd = labelStart + expectedLabelWidth plot.printXAxisLabel(screen, labelWithGap, initialOffset+labelStart, y+height-plotXAxisLabelsHeight) } } func (plot *Plot) printXAxisLabel(screen tcell.Screen, label string, x, y int) { tview.Print(screen, label, x, y, len(label), tview.AlignLeft, plot.axesLabelColor) } func (plot *Plot) drawYAxisLabelsToScreen(screen tcell.Screen, plotYAxisLabelsWidth int, x int, y int, height int) { verticalOffset := plot.minVal verticalScale := (plot.maxVal - plot.minVal) / float64(height-plotXAxisLabelsHeight-1) previousLabel := "" for i := 0; i*(plotYAxisLabelsGap+1) < height-1; i++ { var label string if plot.yAxisLabelDataType == PlotYAxisLabelDataFloat { label = fmt.Sprintf("%.2f", float64(i)*verticalScale*(plotYAxisLabelsGap+1)+verticalOffset) } else { label = strconv.Itoa(int(float64(i)*verticalScale*(plotYAxisLabelsGap+1) + verticalOffset)) } // Prevent same label being shown twice. // Mainly relevant for integer labels with small data sets (in value) if label == previousLabel { continue } previousLabel = label tview.Print(screen, label, x, y+height-(i*(plotYAxisLabelsGap+1))-2, //nolint:mnd plotYAxisLabelsWidth, tview.AlignLeft, plot.axesLabelColor) } } //nolint:cyclop,gocognit func (plot *Plot) drawDotMarkerToScreen(screen tcell.Screen) { x, y, width, height := plot.GetPlotRect() chartData := plot.getData() verticalOffset := -plot.minVal switch plot.ptype { case PlotTypeLineChart: for i, line := range chartData { style := tcell.StyleDefault.Background(plot.GetBackgroundColor()).Foreground(plot.lineColors[i]) for j := 0; j < len(line) && j*plotHorizontalScale < width; j++ { val := line[j] if math.IsNaN(val) { continue } lheight := int(((val + verticalOffset) / plot.maxVal) * float64(height-1)) if lheight > height { continue } if (x+(j*plotHorizontalScale) < x+width) && (y+height-1-lheight < y+height) { tview.PrintJoinedSemigraphics(screen, x+(j*plotHorizontalScale), y+height-1-lheight, plot.dotMarkerRune, style) } } } case PlotTypeScatter: for i, line := range chartData { style := tcell.StyleDefault.Background(plot.GetBackgroundColor()).Foreground(plot.lineColors[i]) for j, val := range line { if math.IsNaN(val) { continue } lheight := int(((val + verticalOffset) / plot.maxVal) * float64(height-1)) if lheight > height { continue } if (x+(j*plotHorizontalScale) < x+width) && (y+height-1-lheight < y+height) { tview.PrintJoinedSemigraphics(screen, x+(j*plotHorizontalScale), y+height-1-lheight, plot.dotMarkerRune, style) } } } } } func (plot *Plot) drawBrailleMarkerToScreen(screen tcell.Screen) { x, y, width, height := plot.GetPlotRect() plot.calcBrailleLines() // print to screen for point, cell := range plot.getBrailleCells() { style := tcell.StyleDefault.Background(plot.GetBackgroundColor()).Foreground(cell.color) if point.X < x+width && point.Y < y+height { tview.PrintJoinedSemigraphics(screen, point.X, point.Y, cell.cRune, style) } } } func calcDataPointHeight(val, maxVal, minVal float64, height int) int { return int(((val - minVal) / (maxVal - minVal)) * float64(height-1)) } func calcDataPointHeightIfInBounds(val float64, maxVal float64, minVal float64, height int) (int, bool) { if math.IsNaN(val) { return 0, false } result := calcDataPointHeight(val, maxVal, minVal, height) if (val > maxVal) || (val < minVal) || (result > height) { return result, false } return result, true } func (plot *Plot) calcBrailleLines() { x, y, _, height := plot.GetPlotRect() chartData := plot.getData() for i, line := range chartData { if len(line) <= 1 { continue } previousHeight := 0 lastValWasOk := false for j, val := range line { lheight, currentValIsOk := calcDataPointHeightIfInBounds(val, plot.maxVal, plot.minVal, height) if !lastValWasOk && !currentValIsOk { // nothing valid to draw, skip to next data point continue } if !lastValWasOk { //nolint:gocritic // current data point is single valid data point, draw it individually plot.setBraillePoint( calcBraillePoint(x, j+1, y, height, lheight), plot.lineColors[i], ) } else if !currentValIsOk { // last data point was single valid data point, draw it individually plot.setBraillePoint( calcBraillePoint(x, j, y, height, previousHeight), plot.lineColors[i], ) } else { // we have two valid data points, draw a line between them plot.setBrailleLine( calcBraillePoint(x, j, y, height, previousHeight), calcBraillePoint(x, j+1, y, height, lheight), plot.lineColors[i], ) } lastValWasOk = currentValIsOk previousHeight = lheight } } } func calcBraillePoint(x, j, y, maxY, height int) image.Point { return image.Pt( (x+(j*plotHorizontalScale))*2, //nolint:mnd (y+maxY-height-1)*4, //nolint:mnd ) } func (plot *Plot) setBraillePoint(p image.Point, color tcell.Color) { if p.X < 0 || p.Y < 0 { return } point := image.Pt(p.X/2, p.Y/4) //nolint:mnd plot.brailleCellMap[point] = brailleCell{ plot.brailleCellMap[point].cRune | brailleRune[p.Y%4][p.X%2], color, } } func (plot *Plot) setBrailleLine(p0, p1 image.Point, color tcell.Color) { for _, p := range plot.brailleLine(p0, p1) { plot.setBraillePoint(p, color) } } func (plot *Plot) getBrailleCells() map[image.Point]brailleCell { cellMap := make(map[image.Point]brailleCell) for point, cvCell := range plot.brailleCellMap { cellMap[point] = brailleCell{cvCell.cRune + brailleOffsetRune, cvCell.color} } return cellMap } func (plot *Plot) brailleLine(p0, p1 image.Point) []image.Point { points := []image.Point{} leftPoint, rightPoint := p0, p1 if leftPoint.X > rightPoint.X { leftPoint, rightPoint = rightPoint, leftPoint } xDistance := absInt(leftPoint.X - rightPoint.X) yDistance := absInt(leftPoint.Y - rightPoint.Y) slope := float64(yDistance) / float64(xDistance) slopeSign := 1 if rightPoint.Y < leftPoint.Y { slopeSign = -1 } targetYCoordinate := float64(leftPoint.Y) currentYCoordinate := leftPoint.Y for i := leftPoint.X; i < rightPoint.X; i++ { points = append(points, image.Pt(i, currentYCoordinate)) targetYCoordinate += (slope * float64(slopeSign)) for currentYCoordinate != int(targetYCoordinate) { points = append(points, image.Pt(i, currentYCoordinate)) currentYCoordinate += slopeSign } } return points } tvxwidgets-0.12.1/plot_test.go000066400000000000000000000025351506765256500163750ustar00rootroot00000000000000package tvxwidgets_test import ( "github.com/gdamore/tcell/v2" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/rivo/tview" "github.com/navidys/tvxwidgets" ) var _ = Describe("Plot", Ordered, func() { var ( app *tview.Application headerBox *tview.Box plot *tvxwidgets.Plot screen tcell.SimulationScreen ) BeforeAll(func() { app = tview.NewApplication() headerBox = tview.NewBox().SetBorder(true) plot = tvxwidgets.NewPlot() screen = tcell.NewSimulationScreen("UTF-8") if err := screen.Init(); err != nil { panic(err) } go func() { appLayout := tview.NewFlex().SetDirection(tview.FlexRow) appLayout.AddItem(headerBox, 1, 0, true) appLayout.AddItem(plot, 50, 0, true) err := app.SetScreen(screen).SetRoot(appLayout, true).Run() if err != nil { panic(err) } }() }) AfterAll(func() { app.Stop() }) Describe("Focus", func() { It("checks primitivie focus", func() { app.SetFocus(headerBox) app.Draw() Expect(plot.HasFocus()).To(Equal(false)) app.SetFocus(plot) app.Draw() Expect(plot.HasFocus()).To(Equal(true)) }) }) Describe("GetRect", func() { It("primitivie size", func() { x, y, width, heigth := plot.GetRect() Expect(x).To(Equal(0)) Expect(y).To(Equal(1)) Expect(width).To(Equal(80)) Expect(heigth).To(Equal(50)) }) }) }) tvxwidgets-0.12.1/sparkline.go000066400000000000000000000046201506765256500163450ustar00rootroot00000000000000package tvxwidgets import ( "math" "sync" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) // Sparkline represents a sparkline widgets. type Sparkline struct { *tview.Box data []float64 dataTitle string dataTitlecolor tcell.Color lineColor tcell.Color mu sync.Mutex } // NewSparkline returns a new sparkline widget. func NewSparkline() *Sparkline { return &Sparkline{ Box: tview.NewBox(), } } // Draw draws this primitive onto the screen. func (sl *Sparkline) Draw(screen tcell.Screen) { sl.DrawForSubclass(screen, sl) x, y, width, height := sl.GetInnerRect() barHeight := height // print label if sl.dataTitle != "" { tview.Print(screen, sl.dataTitle, x, y, width, tview.AlignLeft, sl.dataTitlecolor) barHeight-- } maxVal := getMaxFloat64FromSlice(sl.data) if maxVal < 0 { return } // print lines for i := 0; i < len(sl.data) && i+x < x+width; i++ { data := sl.data[i] if math.IsNaN(data) { continue } dHeight := int((data / maxVal) * float64(barHeight)) sparkChar := barsRune[len(barsRune)-1] style := tcell.StyleDefault.Background(sl.GetBackgroundColor()).Foreground(sl.lineColor) for j := range dHeight { tview.PrintJoinedSemigraphics(screen, i+x, y-1+height-j, sparkChar, style) } if dHeight == 0 { sparkChar = barsRune[1] tview.PrintJoinedSemigraphics(screen, i+x, y-1+height, sparkChar, style) } } } // SetRect sets rect for this primitive. func (sl *Sparkline) SetRect(x, y, width, height int) { sl.Box.SetRect(x, y, width, height) } // GetRect return primitive current rect. func (sl *Sparkline) GetRect() (int, int, int, int) { return sl.Box.GetRect() } // HasFocus returns whether or not this primitive has focus. func (sl *Sparkline) HasFocus() bool { return sl.Box.HasFocus() } // SetData sets sparkline data. func (sl *Sparkline) SetData(data []float64) { sl.mu.Lock() defer sl.mu.Unlock() sl.data = data } // SetDataTitle sets sparkline data title. func (sl *Sparkline) SetDataTitle(title string) { sl.mu.Lock() defer sl.mu.Unlock() sl.dataTitle = title } // SetDataTitleColor sets sparkline data title color. func (sl *Sparkline) SetDataTitleColor(color tcell.Color) { sl.mu.Lock() defer sl.mu.Unlock() sl.dataTitlecolor = color } // SetLineColor sets sparkline line color. func (sl *Sparkline) SetLineColor(color tcell.Color) { sl.mu.Lock() defer sl.mu.Unlock() sl.lineColor = color } tvxwidgets-0.12.1/sparkline_test.go000066400000000000000000000040201506765256500173760ustar00rootroot00000000000000package tvxwidgets_test import ( "github.com/gdamore/tcell/v2" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/rivo/tview" "github.com/navidys/tvxwidgets" ) var _ = Describe("Sparkline", Ordered, func() { var ( app *tview.Application headerBox *tview.Box sparkline *tvxwidgets.Sparkline screen tcell.SimulationScreen ) BeforeAll(func() { app = tview.NewApplication() headerBox = tview.NewBox().SetBorder(true) sparkline = tvxwidgets.NewSparkline() screen = tcell.NewSimulationScreen("UTF-8") if err := screen.Init(); err != nil { panic(err) } go func() { appLayout := tview.NewFlex().SetDirection(tview.FlexRow) appLayout.AddItem(headerBox, 1, 0, true) appLayout.AddItem(sparkline, 50, 0, true) err := app.SetScreen(screen).SetRoot(appLayout, true).Run() if err != nil { panic(err) } }() }) AfterAll(func() { app.Stop() }) Describe("Focus", func() { It("checks primitivie focus", func() { app.SetFocus(headerBox) app.Draw() Expect(sparkline.HasFocus()).To(Equal(false)) app.SetFocus(sparkline) app.Draw() Expect(sparkline.HasFocus()).To(Equal(true)) }) }) Describe("GetRect", func() { It("primitivie size", func() { x, y, width, heigth := sparkline.GetRect() Expect(x).To(Equal(0)) Expect(y).To(Equal(1)) Expect(width).To(Equal(80)) Expect(heigth).To(Equal(50)) }) }) Describe("DataTitle and Color", func() { It("checks data title text and color", func() { tests := []struct { title string color tcell.Color }{ {title: "test01", color: tcell.ColorDarkOrange}, {title: "abc123", color: tcell.ColorBlue}, } for _, test := range tests { sparkline.SetDataTitle(test.title) sparkline.SetDataTitleColor(test.color) app.Draw() for x := 0; x < len(test.title); x++ { prune, _, style, _ := screen.GetContent(x, 1) fg, _, _ := style.Decompose() Expect(fg).To(Equal(test.color)) Expect(string(prune)).To(Equal(string(test.title[x]))) } } }) }) }) tvxwidgets-0.12.1/spinner.go000066400000000000000000000053001506765256500160270ustar00rootroot00000000000000package tvxwidgets import ( "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) // Spinner represents a spinner widget. type Spinner struct { *tview.Box counter int currentStyle SpinnerStyle styles map[SpinnerStyle][]rune } // SpinnerStyle spinner style. type SpinnerStyle int const ( SpinnerDotsCircling SpinnerStyle = iota SpinnerDotsUpDown SpinnerBounce SpinnerLine SpinnerCircleQuarters SpinnerSquareCorners SpinnerCircleHalves SpinnerCorners SpinnerArrows SpinnerHamburger SpinnerStack SpinnerGrowHorizontal SpinnerGrowVertical SpinnerStar SpinnerBoxBounce spinnerCustom // non-public constant to indicate that a custom style has been set by the user. ) // NewSpinner returns a new spinner widget. func NewSpinner() *Spinner { return &Spinner{ Box: tview.NewBox(), currentStyle: SpinnerDotsCircling, styles: map[SpinnerStyle][]rune{ SpinnerDotsCircling: []rune(`⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏`), SpinnerDotsUpDown: []rune(`⠋⠙⠚⠞⠖⠦⠴⠲⠳⠓`), SpinnerBounce: []rune(`⠄⠆⠇⠋⠙⠸⠰⠠⠰⠸⠙⠋⠇⠆`), SpinnerLine: []rune(`|/-\`), SpinnerCircleQuarters: []rune(`◴◷◶◵`), SpinnerSquareCorners: []rune(`◰◳◲◱`), SpinnerCircleHalves: []rune(`◐◓◑◒`), SpinnerCorners: []rune(`⌜⌝⌟⌞`), SpinnerArrows: []rune(`⇑⇗⇒⇘⇓⇙⇐⇖`), SpinnerHamburger: []rune(`☰☱☳☷☶☴`), SpinnerStack: []rune(`䷀䷪䷡䷊䷒䷗䷁䷖䷓䷋䷠䷫`), SpinnerGrowHorizontal: []rune(`▉▊▋▌▍▎▏▎▍▌▋▊▉`), SpinnerGrowVertical: []rune(`▁▃▄▅▆▇▆▅▄▃`), SpinnerStar: []rune(`✶✸✹✺✹✷`), SpinnerBoxBounce: []rune(`▌▀▐▄`), }, } } // Draw draws this primitive onto the screen. func (s *Spinner) Draw(screen tcell.Screen) { s.DrawForSubclass(screen, s) x, y, width, _ := s.GetInnerRect() tview.Print(screen, s.getCurrentFrame(), x, y, width, tview.AlignLeft, tcell.ColorDefault) } // Pulse updates the spinner to the next frame. func (s *Spinner) Pulse() { s.counter++ } // Reset sets the frame counter to 0. func (s *Spinner) Reset() { s.counter = 0 } // SetStyle sets the spinner style. func (s *Spinner) SetStyle(style SpinnerStyle) *Spinner { s.currentStyle = style return s } // SetCustomStyle sets a list of runes as custom frames to show as the spinner. func (s *Spinner) SetCustomStyle(frames []rune) *Spinner { s.styles[spinnerCustom] = frames s.currentStyle = spinnerCustom return s } func (s *Spinner) getCurrentFrame() string { frames := s.styles[s.currentStyle] if len(frames) == 0 { return "" } return string(frames[s.counter%len(frames)]) } tvxwidgets-0.12.1/spinner_test.go000066400000000000000000000043441506765256500170750ustar00rootroot00000000000000package tvxwidgets_test import ( "github.com/gdamore/tcell/v2" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/rivo/tview" "github.com/navidys/tvxwidgets" ) var _ = Describe("Spinner", Ordered, func() { var ( app *tview.Application headerBox *tview.Box spinner *tvxwidgets.Spinner screen tcell.SimulationScreen ) BeforeAll(func() { app = tview.NewApplication() headerBox = tview.NewBox().SetBorder(true) spinner = tvxwidgets.NewSpinner() screen = tcell.NewSimulationScreen("UTF-8") if err := screen.Init(); err != nil { panic(err) } go func() { appLayout := tview.NewFlex().SetDirection(tview.FlexRow) appLayout.AddItem(headerBox, 1, 0, true) appLayout.AddItem(spinner, 50, 0, true) err := app.SetScreen(screen).SetRoot(appLayout, true).Run() if err != nil { panic(err) } }() }) AfterAll(func() { app.Stop() }) Describe("Focus", func() { It("checks primitivie focus", func() { app.SetFocus(headerBox) app.Draw() Expect(spinner.HasFocus()).To(Equal(false)) app.SetFocus(spinner) app.Draw() Expect(spinner.HasFocus()).To(Equal(true)) }) }) Describe("GetRect", func() { It("primitivie size", func() { x, y, width, heigth := spinner.GetRect() Expect(x).To(Equal(0)) Expect(y).To(Equal(1)) Expect(width).To(Equal(80)) Expect(heigth).To(Equal(50)) }) }) Describe("Style", func() { It("checks style", func() { spinner.SetStyle(tvxwidgets.SpinnerGrowHorizontal) spinner.Reset() app.Draw() prune, _, _, _ := screen.GetContent(0, 1) Expect(prune).To(Equal('▉')) spinner.Pulse() app.Draw() prune, _, _, _ = screen.GetContent(0, 1) Expect(prune).To(Equal('▊')) }) }) Describe("CustomStyle", func() { It("checks custom style", func() { customStyle := []rune{'\u2705', '\u274C'} spinner.SetCustomStyle(customStyle) spinner.Reset() app.Draw() prune, _, _, _ := screen.GetContent(0, 1) Expect(prune).To(Equal(customStyle[0])) spinner.Pulse() app.Draw() prune, _, _, _ = screen.GetContent(0, 1) Expect(prune).To(Equal(customStyle[1])) spinner.Pulse() app.Draw() prune, _, _, _ = screen.GetContent(0, 1) Expect(prune).To(Equal(customStyle[0])) }) }) }) tvxwidgets-0.12.1/tvxwidgets_suite_test.go000066400000000000000000000003161506765256500210330ustar00rootroot00000000000000package tvxwidgets_test import ( "testing" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) func TestTvxwidgets(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Tvxwidgets Suite") } tvxwidgets-0.12.1/utils.go000066400000000000000000000057631506765256500155260ustar00rootroot00000000000000package tvxwidgets import ( "math" "strings" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) type drawLineMode int const ( horizontalLine drawLineMode = iota verticalLine ) const ( // gauge cell. prgCell = "▉" // form height. dialogFormHeight = 3 // gauge warning percentage. gaugeWarnPc = 60.00 // gauge critical percentage. gaugeCritPc = 85.00 // gauge min percentage. gaugeMinPc = 0.00 // gauge max percentage. gaugeMaxPc = 100 // dialog padding. dialogPadding = 2 // empty space parts. emptySpaceParts = 2 brailleOffsetRune = '\u2800' dotRune = '\u25CF' fullBlockRune = '\u2588' ) var ( brailleRune = [4][2]rune{ //nolint:gochecknoglobals {'\u0001', '\u0008'}, {'\u0002', '\u0010'}, {'\u0004', '\u0020'}, {'\u0040', '\u0080'}, } barsRune = [...]rune{' ', '▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'} //nolint:gochecknoglobals ) // getColorName returns convert tcell color to its name. func getColorName(color tcell.Color) string { for name, c := range tcell.ColorNames { if c == color { return name } } return "" } // getMessageWidth returns width size for dialogs based on messages. func getMessageWidth(message string) int { var messageWidth int for _, msg := range strings.Split(message, "\n") { if len(msg) > messageWidth { messageWidth = len(msg) } } return messageWidth } // returns max values in 2D float64 slices. func getMaxFloat64From2dSlice(slices [][]float64) float64 { if len(slices) == 0 { return 0 } var ( maxValue float64 maxIsInit bool ) for _, slice := range slices { for _, val := range slice { if math.IsNaN(val) { continue } if !maxIsInit { maxIsInit = true maxValue = val continue } if val > maxValue { maxValue = val } } } return maxValue } func getMinFloat64From2dSlice(slices [][]float64) float64 { if len(slices) == 0 { return 0 } var ( minValue float64 minIsInit bool ) for _, slice := range slices { for _, val := range slice { if math.IsNaN(val) { continue } if !minIsInit { minIsInit = true minValue = val continue } if val < minValue { minValue = val } } } return minValue } // returns max values in float64 slices. func getMaxFloat64FromSlice(slice []float64) float64 { if len(slice) == 0 { return 0 } maxValue := -1.0 for i := range slice { if math.IsNaN(slice[i]) { continue } if slice[i] > maxValue { maxValue = slice[i] } } return maxValue } func absInt(x int) int { if x >= 0 { return x } return -x } func drawLine(screen tcell.Screen, startX int, startY int, length int, mode drawLineMode, style tcell.Style) { switch mode { case horizontalLine: for i := range length { tview.PrintJoinedSemigraphics(screen, startX+i, startY, tview.BoxDrawingsLightTripleDashHorizontal, style) } case verticalLine: for i := range length { tview.PrintJoinedSemigraphics(screen, startX, startY+i, tview.BoxDrawingsLightTripleDashVertical, style) } } } tvxwidgets-0.12.1/utils_test.go000066400000000000000000000062541506765256500165610ustar00rootroot00000000000000package tvxwidgets_test import ( "github.com/gdamore/tcell/v2" "github.com/navidys/tvxwidgets" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/rivo/tview" ) var _ = Describe("Utils", func() { Describe("getColorName", func() { It("returns color name", func() { tests := []struct { color tcell.Color colorName string }{ {color: tcell.ColorWhite, colorName: "white"}, {color: tcell.ColorBlack, colorName: "black"}, {color: tcell.NewRGBColor(0, 1, 2), colorName: ""}, } for _, test := range tests { Expect(tvxwidgets.GetColorName(test.color)).To(Equal(test.colorName)) } }) }) Describe("getMessageWidth", func() { It("returns width size for dialogs based on messages", func() { tests := []struct { msg string width int }{ {msg: "test", width: 4}, {msg: "test01\ntest001", width: 7}, {msg: "", width: 0}, } for _, test := range tests { Expect(tvxwidgets.GetMessageWidth(test.msg)).To(Equal(test.width)) } }) }) Describe("getMaxFloat64From2dSlice", func() { It("returns max values in 2D float64 slices.", func() { tests := []struct { have [][]float64 wants float64 }{ {have: [][]float64{}, wants: 0}, {have: [][]float64{ {5, -1, 0, -10, 12}, {15, -11, 0, -110, 22}, }, wants: 22}, {have: [][]float64{ {-5, -1, -2, -10, -12}, {-15, -11, -1, -110, -22}, }, wants: -1}, } for _, test := range tests { Expect(tvxwidgets.GetMaxFloat64From2dSlice(test.have)).To(Equal(test.wants)) } }) }) Describe("getMaxFloat64FromSlice", func() { It("returns max values in float64 slices", func() { tests := []struct { have []float64 wants float64 }{ {have: []float64{}, wants: 0}, {have: []float64{5, -1, 0, -10, 12}, wants: 12}, {have: []float64{-10, -20, -9, -1}, wants: -1}, } for _, test := range tests { Expect(tvxwidgets.GetMaxFloat64FromSlice(test.have)).To(Equal(test.wants)) } }) }) Describe("absInt", func() { It("return absint", func() { tests := []struct { have int wants int }{ {have: 2, wants: 2}, {have: -2, wants: 2}, {have: 0, wants: 0}, } for _, test := range tests { Expect(tvxwidgets.AbsInt(test.have)).To(Equal(test.wants)) } }) }) Describe("drawLine", func() { It("draws horizontal or vertival line on screen", func() { screen := tcell.NewSimulationScreen("UTF-8") screenWidth := 70 screenHeight := 30 lineStartX := 0 lineStartY := 0 lineLenght := 20 screen.SetSize(screenWidth, screenHeight) screen.Init() screen.Clear() // draw and test horizental line tvxwidgets.DrawLine(screen, lineStartX, lineStartY, lineLenght, 0, tcell.StyleDefault) screen.Show() cellRune, _, _, _ := screen.GetContent(lineStartX, lineStartY) Expect(cellRune).To(Equal(tview.BoxDrawingsLightTripleDashHorizontal)) // draw and test vertical line screen.Clear() tvxwidgets.DrawLine(screen, lineStartX, lineStartY, lineLenght, 1, tcell.StyleDefault) screen.Show() cellRune, _, _, _ = screen.GetContent(lineStartX, lineStartY) Expect(cellRune).To(Equal(tview.BoxDrawingsLightTripleDashVertical)) }) }) })