[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create an issue about a bug you encountered\ntitle: ''\nlabels: bug\nassignees: ''\n---\n\n<!--\nHi there, sorry `tui` is not working as expected.\nPlease fill this bug report conscientiously.\nA detailed and complete issue is more likely to be processed quickly.\n-->\n\n## Description\n<!--\nA clear and concise description of what the bug is.\n-->\n\n\n## To Reproduce\n<!--\nTry to reduce the issue to a simple code sample exhibiting the problem.\nIdeally, fork the project and add a test or an example.\n-->\n\n\n## Expected behavior\n<!--\nA clear and concise description of what you expected to happen.\n-->\n\n\n## Screenshots\n<!--\nIf applicable, add screenshots, gifs or videos to help explain your problem.\n-->\n\n\n## Environment\n<!--\nAdd a description of the systems where you are observing the issue. For example:\n- OS: Linux\n- Terminal Emulator: xterm\n- Font: Inconsolata (Patched)\n- Crate version: 0.7\n- Backend: termion\n-->\n\n- OS:\n- Terminal Emulator:\n- Font:\n- Crate version:\n- Backend:\n\n## Additional context\n<!--\nAdd any other context about the problem here.\nIf you already looked into the issue, include all the leads you have explored.\n-->\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: enhancement\nassignees: ''\n\n---\n\n## Problem\n<!--\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n-->\n\n## Solution\n<!--\nA clear and concise description of what you want to happen.\nThings to consider:\n- backward compatibility\n- ease of use of the API (https://rust-lang.github.io/api-guidelines/)\n- consistency with the rest of the crate\n-->\n\n## Alternatives\n<!--\nA clear and concise description of any alternative solutions or features you've considered.\n-->\n\n## Additional context\n<!--\nAdd any other context or screenshots about the feature request here.\n-->\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "## Description\n<!--\nA clear and concise description of what this PR changes.\n-->\n\n## Testing guidelines\n<!--\nA clear and concise description of how the changes can be tested.\nFor example, you can include a command to run the relevant tests or examples.\nYou can also include screenshots of the expected behavior.\n-->\n\n## Checklist\n\n* [ ] I have read the [contributing guidelines](../CONTRIBUTING.md).\n* [ ] I have added relevant tests.\n* [ ] I have documented all new additions.\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "on:\n  push:\n    branches:\n      - master\n  pull_request:\n    branches:\n      - master\n\nname: CI\n\nenv:\n  CI_CARGO_MAKE_VERSION: 0.35.16\n\njobs:\n  linux:\n    name: Linux\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        rust: [\"1.56.1\", \"stable\"]\n    steps:\n      - uses: hecrj/setup-rust-action@967aec96c6a27a0ce15c1dac3aaba332d60565e2\n        with:\n          rust-version: ${{ matrix.rust }}\n          components: rustfmt,clippy\n      - uses: actions/checkout@v1\n      - name: \"Get cargo bin directory\"\n        id: cargo-bin-dir\n        run: echo \"::set-output name=dir::$HOME/.cargo/bin\"\n      - name: \"Cache cargo make\"\n        id: cache-cargo-make\n        uses: actions/cache@v2\n        with:\n          path: ${{ steps.cargo-bin-dir.outputs.dir }}/cargo-make\n          key: ${{ runner.os }}-${{ matrix.rust }}-cargo-make-${{ env.CI_CARGO_MAKE_VERSION }}\n      - name: \"Install cargo-make\"\n        if: steps.cache-cargo-make.outputs.cache-hit != 'true'\n        run: cargo install cargo-make --version ${{ env.CI_CARGO_MAKE_VERSION }}\n      - name: \"Format / Build / Test\"\n        run: cargo make ci\n        env:\n          RUST_BACKTRACE: full\n  windows:\n    name: Windows\n    runs-on: windows-latest\n    strategy:\n      matrix:\n        rust: [\"1.56.1\", \"stable\"]\n    steps:\n      - uses: actions/checkout@v1\n      - uses: hecrj/setup-rust-action@967aec96c6a27a0ce15c1dac3aaba332d60565e2\n        with:\n          rust-version: ${{ matrix.rust }}\n          components: rustfmt,clippy\n      - uses: actions/checkout@v1\n      - name: \"Get cargo bin directory\"\n        id: cargo-bin-dir\n        run: echo \"::set-output name=dir::$HOME\\.cargo\\bin\"\n      - name: \"Cache cargo make\"\n        id: cache-cargo-make\n        uses: actions/cache@v2\n        with:\n          path: ${{ steps.cargo-bin-dir.outputs.dir }}\\cargo-make.exe\n          key: ${{ runner.os }}-${{ matrix.rust }}-cargo-make-${{ env.CI_CARGO_MAKE_VERSION }}\n      - name: \"Install cargo-make\"\n        if: steps.cache-cargo-make.outputs.cache-hit != 'true'\n        run: cargo install cargo-make --version ${{ env.CI_CARGO_MAKE_VERSION }}\n      - name: \"Format / Build / Test\"\n        run: cargo make ci\n        env:\n          RUST_BACKTRACE: full\n"
  },
  {
    "path": ".gitignore",
    "content": "target\nCargo.lock\n*.log\n*.rs.rustfmt\n.gdb_history\n.idea/\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\n## To be released\n\n## v0.19.0 - 2022-08-14\n\n### Features\n\n* Bump `crossterm` to `0.25`\n\n## v0.18.0 - 2022-04-24\n\n### Features\n\n* Update `crossterm` to `0.23`\n\n## v0.17.0 - 2022-01-22\n\n### Features\n\n* Add option to `widgets::List` to repeat the hightlight symbol for each line of multi-line items (#533).\n* Add option to control the alignment of `Axis` labels in the `Chart` widget (#568).\n\n### Breaking changes\n\n* The minimum supported rust version is now `1.56.1`.\n\n#### New default backend and consolidated backend options (#553)\n\n* `crossterm` is now the default backend.\nIf you are already using the `crossterm` backend, you can simplify your dependency specification in `Cargo.toml`:\n```diff\n- tui = { version = \"0.16\", default-features = false, features = [\"crossterm\"] }\n+ tui = \"0.17\"\n```\nIf you are using the `termion` backend, your `Cargo` is now a bit more verbose:\n```diff\n- tui = \"0.16\"\n+ tui = { version = \"0.17\", default-features = false, features = [\"termion\"] }\n```\n\n`crossterm` has also been bumped to version `0.22`.\n\nBecause of their apparent low usage, `curses` and `rustbox` backends have been removed.\nIf you are using one of them, you can import their last implementation in your own project:\n* [curses](https://github.com/fdehau/tui-rs/blob/v0.16.0/src/backend/curses.rs)\n* [rustbox](https://github.com/fdehau/tui-rs/blob/v0.16.0/src/backend/rustbox.rs)\n\n#### Canvas labels (#543)\n\n* Labels of the `Canvas` widget are now `text::Spans`.\nThe signature of `widgets::canvas::Context::print` has thus been updated:\n```diff\n- ctx.print(x, y, \"Some text\", Color::Yellow);\n+ ctx.print(x, y, Span::styled(\"Some text\", Style::default().fg(Color::Yellow)))\n```\n\n## v0.16.0 - 2021-08-01\n\n### Features\n\n* Update `crossterm` to `0.20`.\n* Add `From<Cow<str>>` implementation for `text::Text` (#471).\n* Add option to right or center align the title of a `widgets::Block` (#462).\n\n### Fixes\n\n* Apply label style in `widgets::Gauge` and avoid panics because of overflows with long labels (#494).\n* Avoid panics because of overflows with long axis labels in `widgets::Chart` (#512).\n* Fix computation of column widths in `widgets::Table` (#514).\n* Fix panics because of invalid offset when input changes between two frames in `widgets::List` and\n  `widgets::Chart` (#516).\n\n## v0.15.0 - 2021-05-02\n\n### Features\n\n* Update `crossterm` to `0.19`.\n* Update `rand` to `0.8`.\n* Add a read-only view of the terminal state after the draw call (#440).\n\n### Fixes\n\n* Remove compile warning in `TestBackend::assert_buffer` (#466).\n\n## v0.14.0 - 2021-01-01\n\n### Breaking changes\n\n#### New API for the Table widget\n\nThe `Table` widget got a lot of improvements that should make it easier to work with:\n* It should not longer panic when rendered on small areas.\n* `Row`s are now a collection of `Cell`s, themselves wrapping a `Text`. This means you can style\nthe entire `Table`, an entire `Row`, an entire `Cell` and rely on the styling capabilities of\n`Text` to get full control over the look of your `Table`.\n* `Row`s can have multiple lines.\n* The header is now optional and is just another `Row` always visible at the top.\n* `Row`s can have a bottom margin.\n* The header alignment is no longer off when an item is selected.\n\nTaking the example of the code in `examples/demo/ui.rs`, this is what you may have to change:\n```diff\n     let failure_style = Style::default()\n         .fg(Color::Red)\n         .add_modifier(Modifier::RAPID_BLINK | Modifier::CROSSED_OUT);\n-    let header = [\"Server\", \"Location\", \"Status\"];\n     let rows = app.servers.iter().map(|s| {\n         let style = if s.status == \"Up\" {\n             up_style\n         } else {\n             failure_style\n         };\n-        Row::StyledData(vec![s.name, s.location, s.status].into_iter(), style)\n+        Row::new(vec![s.name, s.location, s.status]).style(style)\n     });\n-    let table = Table::new(header.iter(), rows)\n+    let table = Table::new(rows)\n+        .header(\n+            Row::new(vec![\"Server\", \"Location\", \"Status\"])\n+                .style(Style::default().fg(Color::Yellow))\n+                .bottom_margin(1),\n+        )\n         .block(Block::default().title(\"Servers\").borders(Borders::ALL))\n-        .header_style(Style::default().fg(Color::Yellow))\n         .widths(&[\n             Constraint::Length(15),\n             Constraint::Length(15),\n```\nHere, we had to:\n- Change the way we construct [`Row`](https://docs.rs/tui/*/tui/widgets/struct.Row.html) which is no\nlonger an `enum` but a `struct`. It accepts anything that can be converted to an iterator of things\nthat can be converted to a [`Cell`](https://docs.rs/tui/*/tui/widgets/struct.Cell.html)\n- The header is no longer a required parameter so we use\n[`Table::header`](https://docs.rs/tui/*/tui/widgets/struct.Table.html#method.header) to set it.\n`Table::header_style` has been removed since the style can be directly set using\n[`Row::style`](https://docs.rs/tui/*/tui/widgets/struct.Row.html#method.style). In addition, we want\nto preserve the old margin between the header and the rest of the rows so we add a bottom margin to\nthe header using\n[`Row::bottom_margin`](https://docs.rs/tui/*/tui/widgets/struct.Row.html#method.bottom_margin).\n\nYou may want to look at the documentation of the different types to get a better understanding:\n- [`Table`](https://docs.rs/tui/*/tui/widgets/struct.Table.html)\n- [`Row`](https://docs.rs/tui/*/tui/widgets/struct.Row.html)\n- [`Cell`](https://docs.rs/tui/*/tui/widgets/struct.Cell.html)\n\n### Fixes\n\n- Fix handling of Non Breaking Space (NBSP) in wrapped text in `Paragraph` widget.\n\n### Features\n\n- Add `Style::reset` to create a `Style` resetting all styling properties when applied.\n- Add an option to render the `Gauge` widget with unicode blocks.\n- Manage common project tasks with `cargo-make` rather than `make` for easier on-boarding.\n\n## v0.13.0 - 2020-11-14\n\n### Features\n\n* Add `LineGauge` widget which is a more compact variant of the existing `Gauge`.\n* Bump `crossterm` to 0.18\n\n### Fixes\n\n* Take into account the borders of the `Table` widget when the widths of columns is controlled by\n`Percentage` and `Ratio` constraints.\n\n## v0.12.0 - 2020-09-27\n\n### Features\n\n* Make it easier to work with string with multiple lines in `Text` (#361).\n\n### Fixes\n\n* Fix a style leak in `Graph` so components drawn on top of the plotted data (i.e legend and axis\ntitles) are not affected by the style of the `Dataset`s (#388).\n* Make sure `BarChart` shows bars with the max height only when the plotted data is actually equal\nto the max (#383).\n\n## v0.11.0 - 2020-09-20\n\n### Features\n\n* Add the dot character as a new type of canvas marker (#350).\n* Support more style modifiers on Windows (#368).\n\n### Fixes\n\n* Clearing the terminal through `Terminal::clear` will cause the whole UI to be redrawn (#380).\n* Fix incorrect output when the first diff to draw is on the second cell of the terminal (#347).\n\n## v0.10.0 - 2020-07-17\n\n### Breaking changes\n\n#### Easier cursor management\n\nA new method has been added to `Frame` called `set_cursor`. It lets you specify where the cursor\nshould be placed after the draw call. Furthermore like any other widgets, if you do not set a cursor\nposition during a draw call, the cursor is automatically hidden.\n\nFor example:\n\n```rust\nfn draw_input(f: &mut Frame, app: &App) {\n  if app.editing {\n    let input_width = app.input.width() as u16;\n    // The cursor will be placed just after the last character of the input\n    f.set_cursor((input_width + 1, 0));\n  } else {\n    // We are no longer editing, the cursor does not have to be shown, set_cursor is not called and\n    // thus automatically hidden.\n  }\n}\n```\n\nIn order to make this possible, the draw closure takes in input `&mut Frame` instead of `mut Frame`.\n\n#### Advanced text styling\n\nIt has been reported several times that the text styling capabilities were somewhat limited in many\nplaces of the crate. To solve the issue, this release includes a new set of text primitives that are\nnow used by a majority of widgets to provide flexible text styling.\n\n`Text` is replaced by the following types:\n- `Span`: a string with a unique style.\n- `Spans`: a string with multiple styles.\n- `Text`: a multi-lines string with multiple styles.\n\nHowever, you do not always need this complexity so the crate provides `From` implementations to\nlet you use simple strings as a default and switch to the previous primitives when you need\nadditional styling capabilities.\n\nFor example, the title of a `Block` can be set in the following ways:\n\n```rust\n// A title with no styling\nBlock::default().title(\"My title\");\n// A yellow title\nBlock::default().title(Span::styled(\"My title\", Style::default().fg(Color::Yellow)));\n// A title where \"My\" is bold and \"title\" is a simple string\nBlock::default().title(vec![\n    Span::styled(\"My\", Style::default().add_modifier(Modifier::BOLD)),\n    Span::from(\"title\")\n]);\n```\n\n- `Buffer::set_spans` and `Buffer::set_span` were added.\n- `Paragraph::new` expects an input that can be converted to a `Text`.\n- `Block::title_style` is deprecated.\n- `Block::title` expects a `Spans`.\n- `Tabs` expects a list of `Spans`.\n- `Gauge` custom label is now a `Span`.\n- `Axis` title and labels are `Spans` (as a consequence `Chart` no longer has generic bounds).\n\n#### Incremental styling\n\nPreviously `Style` was used to represent an exhaustive set of style rules to be applied to an UI\nelement. It implied that whenever you wanted to change even only one property you had to provide the\ncomplete style. For example, if you had a `Block` where you wanted to have a green background and\na title in bold, you had to do the following:\n\n```rust\nlet style = Style::default().bg(Color::Green);\nBlock::default()\n  .style(style)\n  .title(\"My title\")\n  // Here we reused the style otherwise the background color would have been reset\n  .title_style(style.modifier(Modifier::BOLD));\n```\n\nIn this new release, you may now write this as:\n\n```rust\nBlock::default()\n    .style(Style::default().bg(Color::Green))\n    // The style is not overidden anymore, we simply add new style rule for the title.\n    .title(Span::styled(\"My title\", Style::default().add_modifier(Modifier::BOLD)))\n```\n\nIn addition, the crate now provides a method `patch` to combine two styles into a new set of style\nrules:\n\n```rust\nlet style = Style::default().modifer(Modifier::BOLD);\nlet style = style.patch(Style::default().add_modifier(Modifier::ITALIC));\n// style.modifer == Modifier::BOLD | Modifier::ITALIC, the modifier has been enriched not overidden\n```\n\n- `Style::modifier` has been removed in favor of `Style::add_modifier` and `Style::remove_modifier`.\n- `Buffer::set_style` has been added. `Buffer::set_background` is deprecated.\n- `BarChart::style` no longer set the style of the bars. Use `BarChart::bar_style` in replacement.\n- `Gauge::style` no longer set the style of the gauge. Use `Gauge::gauge_style` in replacement.\n\n#### List with item on multiple lines\n\nThe `List` widget has been refactored once again to support items with variable heights and complex\nstyling.\n\n- `List::new` expects an input that can be converted to a `Vec<ListItem>` where `ListItem` is a\nwrapper around the item content to provide additional styling capabilities. `ListItem` contains a\n`Text`.\n- `List::items` has been removed.\n\n```rust\n// Before\nlet items = vec![\n  \"Item1\",\n  \"Item2\",\n  \"Item3\"\n];\nList::default().items(items.iters());\n\n// After\nlet items = vec![\n  ListItem::new(\"Item1\"),\n  ListItem::new(\"Item2\"),\n  ListItem::new(\"Item3\"),\n];\nList::new(items);\n```\n\nSee the examples for more advanced usages.\n\n#### More wrapping options\n\n`Paragraph::wrap` expects `Wrap` instead of `bool` to let users decided whether they want to trim\nwhitespaces when the text is wrapped.\n\n```rust\n// before\nParagraph::new(text).wrap(true)\n// after\nParagraph::new(text).wrap(Wrap { trim: true }) // to have the same behavior\nParagraph::new(text).wrap(Wrap { trim: false }) // to use the new behavior\n```\n\n#### Horizontal scrolling in paragraph\n\nYou can now scroll horizontally in `Paragraph`. The argument of `Paragraph::scroll` has thus be\nchanged from `u16` to `(u16, u16)`.\n\n### Features\n\n#### Serialization of style\n\nYou can now serialize and de-serialize `Style` using the optional `serde` feature.\n\n## v0.9.5 - 2020-05-21\n\n### Bug Fixes\n\n* Fix out of bounds panic in `widgets::Tabs` when the widget is rendered on\nsmall areas.\n\n## v0.9.4 - 2020-05-12\n\n### Bug Fixes\n\n* Ignore zero-width graphemes in `Buffer::set_stringn`.\n\n## v0.9.3 - 2020-05-11\n\n### Bug Fixes\n\n* Fix usize overflows in `widgets::Chart` when a dataset is empty.\n\n## v0.9.2 - 2020-05-10\n\n### Bug Fixes\n\n* Fix usize overflows in `widgets::canvas::Line` drawing algorithm.\n\n## v0.9.1 - 2020-04-16\n\n### Bug Fixes\n\n* The `List` widget now takes into account the width of the `highlight_symbol`\nwhen calculating the total width of its items. It prevents items to overflow\noutside of the widget area.\n\n## v0.9.0 - 2020-04-14\n\n### Features\n\n* Introduce stateful widgets, i.e widgets that can take advantage of keeping\nsome state around between two draw calls (#210 goes a bit more into the\ndetails).\n* Allow a `Table` row to be selected.\n```rust\n// State initialization\nlet mut state = TableState::default();\n\n// In the terminal.draw closure\nlet header = [\"Col1\", \"Col2\", \"Col\"];\nlet rows = [\n  Row::Data([\"Row11\", \"Row12\", \"Row13\"].into_iter())\n];\nlet table = Table::new(header.into_iter(), rows.into_iter());\nf.render_stateful_widget(table, area, &mut state);\n\n// In response to some event:\nstate.select(Some(1));\n```\n* Add a way to choose the type of border used to draw a block. You can now\nchoose from plain, rounded, double and thick lines.\n* Add a `graph_type` property on the `Dataset` of a `Chart` widget. By\ndefault it will be `Scatter` where the points are drawn as is. An other\noption is `Line` where a line will be draw between each consecutive points\nof the dataset.\n* Style methods are now const, allowing you to initialize const `Style`\nobjects.\n* Improve control over whether the legend in the `Chart` widget is shown or\nnot. You can now set custom constraints using\n`Chart::hidden_legend_constraints`.\n* Add `Table::header_gap` to add some space between the header and the first\nrow.\n* Remove `log` from the dependencies\n* Add a way to use a restricted set of unicode symbols in several widgets to\nimprove portability in exchange of a degraded output. (see `BarChart::bar_set`,\n`Sparkline::bar_set` and `Canvas::marker`). You can check how the\n`--enhanced-graphics` flag is used in the demos.\n\n### Breaking Changes\n\n* `Widget::render` has been deleted. You should now use `Frame::render_widget`\nto render a widget on the corresponding `Frame`. This makes the `Widget`\nimplementation totally decoupled from the `Frame`.\n```rust\n// Before\nBlock::default().render(&mut f, size);\n\n// After\nlet block = Block::default();\nf.render_widget(block, size);\n```\n* `Widget::draw` has been renamed to `Widget::render` and the signature has\nbeen updated to reflect that widgets are consumable objects. Thus the method\ntakes `self` instead of `&mut self`.\n```rust\n// Before\nimpl Widget for MyWidget {\n  fn draw(&mut self, area: Rect, buf: &mut Buffer) {\n  }\n}\n\n/// After\nimpl Widget for MyWidget {\n  fn render(self, arera: Rect, buf: &mut Buffer) {\n  }\n}\n```\n* `Widget::background` has been replaced by `Buffer::set_background`\n```rust\n// Before\nimpl Widget for MyWidget {\n  fn render(self, arera: Rect, buf: &mut Buffer) {\n    self.background(area, buf, self.style.bg);\n  }\n}\n\n// After\nimpl Widget for MyWidget {\n  fn render(self, arera: Rect, buf: &mut Buffer) {\n    buf.set_background(area, self.style.bg);\n  }\n}\n```\n* Update the `Shape` trait for objects that can be draw on a `Canvas` widgets.\nInstead of returning an iterator over its points, a `Shape` is given a\n`Painter` object that provides a `paint` as well as a `get_point` method. This\ngives the `Shape` more information about the surface it will be drawn to. In\nparticular, this change allows the `Line` shape to use a more precise and\nefficient drawing algorithm (Bresenham's line algorithm).\n* `SelectableList` has been deleted. You can now take advantage of the\nassociated `ListState` of the `List` widget to select an item.\n```rust\n// Before\nList::new(&[\"Item1\", \"Item2\", \"Item3\"])\n  .select(Some(1))\n  .render(&mut f, area);\n\n// After\n\n// State initialization\nlet mut state = ListState::default();\n\n// In the terminal.draw closure\nlet list = List::new(&[\"Item1\", \"Item2\", \"Item3\"]);\nf.render_stateful_widget(list, area, &mut state);\n\n// In response to some events\nstate.select(Some(1));\n```\n* `widgets::Marker` has been moved to `symbols::Marker`\n\n## v0.8.0 - 2019-12-15\n\n### Breaking Changes\n\n* Bump crossterm to 0.14.\n* Add cross symbol to the symbols list.\n\n### Bug Fixes\n\n* Use the value of `title_style` to style the title of `Axis`.\n\n## v0.7.0 - 2019-11-29\n\n### Breaking Changes\n\n* Use `Constraint` instead of integers to specify the widths of the `Table`\nwidget's columns. This will allow more responsive tables.\n\n```rust\nTable::new(header, row)\n  .widths(&[15, 15, 10])\n  .render(f, chunk);\n```\n\nbecomes:\n\n```rust\nTable::new(header, row)\n  .widths(&[\n    Constraint::Length(15),\n    Constraint::Length(15),\n    Constraint::Length(10),\n  ])\n  .render(f, chunk);\n```\n\n* Bump crossterm to 0.13.\n* Use Github Actions for CI (Travis and Azure Pipelines integrations have been deleted).\n\n### Features\n\n* Add support for horizontal and vertical margins in `Layout`.\n\n## v0.6.2 - 2019-07-16\n\n### Features\n\n* `Text` implements PartialEq\n\n### Bug Fixes\n\n* Avoid overflow errors in canvas\n\n## v0.6.1 - 2019-06-16\n\n### Bug Fixes\n\n* Avoid a division by zero when all values in a barchart are equal to 0.\n* Fix the inverted cursor position in the curses backend.\n* Ensure that the correct terminal size is returned when using the crossterm\nbackend.\n* Avoid highlighting the separator after the selected item in the Tabs widget.\n\n## v0.6.0 - 2019-05-18\n\n### Breaking Changes\n\n* Update crossterm backend\n\n## v0.5.1 - 2019-04-14\n\n### Bug Fixes\n\n* Fix a panic in the Sparkline widget\n\n## v0.5.0 - 2019-03-10\n\n### Features\n\n* Add a new curses backend (with Windows support thanks to `pancurses`).\n* Add `Backend::get_cursor` and `Backend::set_cursor` methods to query and\nset the position of the cursor.\n* Add more constructors to the `Crossterm` backend.\n* Add a demo for all backends using a shared UI and application state.\n* Add `Ratio` as a new variant of layout `Constraint`. It can be used to define\nexact ratios constraints.\n\n### Breaking Changes\n\n* Add support for multiple modifiers on the same `Style` by changing `Modifier`\nfrom an enum to a bitflags struct.\n\nSo instead of writing:\n\n```rust\nlet style = Style::default().add_modifier(Modifier::Italic);\n```\n\none should use:\n\n```rust\nlet style = Style::default().add_modifier(Modifier::ITALIC);\n// or\nlet style = Style::default().add_modifier(Modifier::ITALIC | Modifier::BOLD);\n```\n\n### Bug Fixes\n\n* Ensure correct behavoir of the alternate screens with the `Crossterm` backend.\n* Fix out of bounds panic when two `Buffer` are merged.\n\n## v0.4.0 - 2019-02-03\n\n### Features\n\n* Add a new canvas shape: `Rectangle`.\n* Official support of `Crossterm` backend.\n* Make it possible to choose the divider between `Tabs`.\n* Add word wrapping on Paragraph.\n* The gauge widget accepts a ratio (f64 between 0 and 1) in addition of a\npercentage.\n\n### Breaking Changes\n\n* Upgrade to Rust 2018 edition.\n\n### Bug Fixes\n\n* Fix rendering of double-width characters.\n* Fix race condition on the size of the terminal and expose a size that is\nsafe to use when drawing through `Frame::size`.\n* Prevent unsigned int overflow on large screens.\n\n## v0.3.0 - 2018-11-04\n\n### Features\n\n* Add experimental test backend\n\n## v0.3.0-beta.3 - 2018-09-24\n\n### Features\n\n* `show_cursor` is called when `Terminal` is dropped if the cursor is hidden.\n\n## v0.3.0-beta.2 - 2018-09-23\n\n### Breaking Changes\n\n* Remove custom `termion` backends. This is motivated by the fact that\n`termion` structs are meant to be combined/wrapped to provide additional\nfunctionalities to the terminal (e.g AlternateScreen, Mouse support, ...).\nThus providing exclusive types do not make a lot of sense and give a false\nhint that additional features cannot be used together. The recommended\napproach is now to create your own version of `stdout`:\n\n```rust\nlet stdout = io::stdout().into_raw_mode()?;\nlet stdout = MouseTerminal::from(stdout);\nlet stdout = AlternateScreen::from(stdout);\n```\n\nand then to create the corresponding `termion` backend:\n\n```rust\nlet backend = TermionBackend::new(stdout);\n```\n\nThe resulting code is more verbose but it works with all combinations of\nadditional `termion` features.\n\n## v0.3.0-beta.1 - 2018-09-08\n\n### Breaking Changes\n\n* Replace `Item` by a generic and flexible `Text` that can be used in both\n`Paragraph` and `List` widgets.\n* Remove unecessary borrows on `Style`.\n\n## v0.3.0-beta.0 - 2018-09-04\n\n### Features\n\n* Add a basic `Crossterm` backend\n\n### Breaking Changes\n\n* Remove `Group` and introduce `Layout` in its place\n  - `Terminal` is no longer required to compute a layout\n  - `Size` has been renamed `Constraint`\n* Widgets are rendered on a `Frame` instead of a `Terminal` in order to\navoid mixing `draw` and `render` calls\n* `draw` on `Terminal` expects a closure where the UI is built by rendering\nwidgets on the given `Frame`\n* Update `Widget` trait\n  - `draw` takes area by value\n  - `render` takes a `Frame` instead of a `Terminal`\n* All widgets use the consumable builder pattern\n* `SelectableList` can have no selected item and the highlight symbol is hidden\nin this case\n* Remove markup langage inside `Paragraph`. `Paragraph` now expects an iterator\nof `Text` items\n\n## v0.2.3 - 2018-06-09\n\n### Features\n\n* Add `start_corner` option for `List`\n* Add more text aligment options for `Paragraph`\n\n## v0.2.2 - 2018-05-06\n\n### Features\n\n* `Terminal` implements `Debug`\n\n### Breaking Changes\n\n* Use `FnOnce` instead of `FnMut` in Group::render\n\n## v0.2.1 - 2018-04-01\n\n### Features\n\n* Add `AlternateScreenBackend` in `termion` backend\n* Add `TermionBackend::with_stdout` in order to let an user of the library\nprovides its own termion struct\n* Add tests and documentation for `Buffer::pos_of`\n* Remove leading whitespaces when wrapping text\n\n### Bug Fixes\n\n* Fix `debug_assert` in `Buffer::pos_of`\n* Pass the style of `SelectableList` to the underlying `List`\n* Fix missing character when wrapping text\n* Fix panic when specifying layout constraints\n\n## v0.2.0 - 2017-12-26\n\n### Features\n\n* Add `MouseBackend` in `termion` backend to handle scroll and mouse events\n* Add generic `Item` for items in a `List`\n* Drop `log4rs` as a dev-dependencies in favor of `stderrlog`\n\n### Breaking Changes\n\n* Rename `TermionBackend` to `RawBackend` (to distinguish it from the `MouseBackend`)\n* Generic parameters for `List` to allow passing iterators as items\n* Generic parameters for `Table` to allow using iterators as rows and header\n* Generic parameters for `Tabs`\n* Rename `border` bitflags to `Borders`\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\n## Building\n\n[cargo-make]: https://github.com/sagiegurari/cargo-make \"cargo-make\"\n\n`tui` is an ordinary Rust project where common tasks are managed with [cargo-make].\nIt wraps common `cargo` commands with sane defaults depending on your platform of choice.\nBuilding the project should be as easy as running `cargo make build`.\n\n## :hammer_and_wrench: Pull requests\n\nAll contributions are obviously welcome.\nPlease include as many details as possible in your PR description to help the reviewer (follow the provided template).\nMake sure to highlight changes which may need additional attention or you are uncertain about.\nAny idea with a large scale impact on the crate or its users should ideally be discussed in a \"Feature Request\" issue beforehand.\n\n## Continuous Integration\n\nWe use Github Actions for the CI where we perform the following checks:\n- The code should compile on `stable` and the Minimum Supported Rust Version (MSRV).\n- The tests (docs, lib, tests and examples) should pass.\n- The code should conform to the default format enforced by `rustfmt`.\n- The code should not contain common style issues `clippy`.\n\nYou can also check most of those things yourself locally using `cargo make ci` which will offer you a shorter feedback loop.\n\n## Tests\n\nThe test coverage of the crate is far from being ideal but we already have a fair amount of tests in place.\nBeside the usual doc and unit tests, one of the most valuable test you can write for `tui` is a test again the `TestBackend`.\nIt allows you to assert the content of the output buffer that would have been flushed to the terminal after a given draw call.\nSee `widgets_block_renders` in [tests/widgets_block.rs](./tests/widget_block.rs) for an example.\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[package]\nname = \"tui\"\nversion = \"0.19.0\"\nauthors = [\"Florian Dehau <work@fdehau.com>\"]\ndescription = \"\"\"\nA library to build rich terminal user interfaces or dashboards\n\"\"\"\ndocumentation = \"https://docs.rs/tui/0.19.0/tui/\"\nkeywords = [\"tui\", \"terminal\", \"dashboard\"]\nrepository = \"https://github.com/fdehau/tui-rs\"\nreadme = \"README.md\"\nlicense = \"MIT\"\nexclude = [\"assets/*\", \".github\", \"Makefile.toml\", \"CONTRIBUTING.md\", \"*.log\", \"tags\"]\nautoexamples = true\nedition = \"2021\"\nrust-version = \"1.56.1\"\n\n[badges]\n\n[features]\ndefault = [\"crossterm\"]\n\n[dependencies]\nbitflags = \"1.3\"\ncassowary = \"0.3\"\nunicode-segmentation = \"1.2\"\nunicode-width = \"0.1\"\ntermion = { version = \"1.5\", optional = true }\ncrossterm = { version = \"0.25\", optional = true }\nserde = { version = \"1\", optional = true, features = [\"derive\"]}\n\n[dev-dependencies]\nrand = \"0.8\"\nargh = \"0.1\"\n\n[[example]]\nname = \"barchart\"\nrequired-features = [\"crossterm\"]\n\n[[example]]\nname = \"block\"\nrequired-features = [\"crossterm\"]\n\n[[example]]\nname = \"canvas\"\nrequired-features = [\"crossterm\"]\n\n[[example]]\nname = \"chart\"\nrequired-features = [\"crossterm\"]\n\n[[example]]\nname = \"custom_widget\"\nrequired-features = [\"crossterm\"]\n\n[[example]]\nname = \"gauge\"\nrequired-features = [\"crossterm\"]\n\n[[example]]\nname = \"layout\"\nrequired-features = [\"crossterm\"]\n\n[[example]]\nname = \"list\"\nrequired-features = [\"crossterm\"]\n\n[[example]]\nname = \"panic\"\nrequired-features = [\"crossterm\"]\n\n[[example]]\nname = \"paragraph\"\nrequired-features = [\"crossterm\"]\n\n[[example]]\nname = \"popup\"\nrequired-features = [\"crossterm\"]\n\n[[example]]\nname = \"sparkline\"\nrequired-features = [\"crossterm\"]\n\n[[example]]\nname = \"table\"\nrequired-features = [\"crossterm\"]\n\n[[example]]\nname = \"tabs\"\nrequired-features = [\"crossterm\"]\n\n[[example]]\nname = \"user_input\"\nrequired-features = [\"crossterm\"]\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016 Florian Dehau\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Makefile.toml",
    "content": "[config]\nskip_core_tasks = true\n\n[tasks.ci]\nrun_task = [\n    { name = \"ci-unix\", condition = { platforms = [\"linux\", \"mac\"] } },\n    { name = \"ci-windows\", condition = { platforms = [\"windows\"] } },\n]\n\n[tasks.ci-unix]\nprivate = true\ndependencies = [\n    \"fmt\",\n    \"check-crossterm\",\n    \"check-termion\",\n    \"test-crossterm\",\n    \"test-termion\",\n    \"clippy-crossterm\",\n    \"clippy-termion\",\n    \"test-doc\",\n]\n\n[tasks.ci-windows]\nprivate = true\ndependencies = [\n    \"fmt\",\n    \"check-crossterm\",\n    \"test-crossterm\",\n    \"clippy-crossterm\",\n    \"test-doc\",\n]\n\n[tasks.fmt]\ncommand = \"cargo\"\nargs = [\n  \"fmt\",\n  \"--all\",\n  \"--\",\n  \"--check\",\n]\n\n[tasks.check-crossterm]\nenv = { TUI_FEATURES = \"serde,crossterm\" }\nrun_task = \"check\"\n\n[tasks.check-termion]\nenv = { TUI_FEATURES = \"serde,termion\" }\nrun_task = \"check\"\n\n[tasks.check]\ncommand = \"cargo\"\ncondition = { env_set = [\"TUI_FEATURES\"] }\nargs = [\n  \"check\",\n  \"--no-default-features\",\n  \"--features\",\n  \"${TUI_FEATURES}\",\n  \"--all-targets\",\n]\n\n[tasks.build-crossterm]\nenv = { TUI_FEATURES = \"serde,crossterm\" }\nrun_task = \"build\"\n\n[tasks.build-termion]\nenv = { TUI_FEATURES = \"serde,termion\" }\nrun_task = \"build\"\n\n[tasks.build]\ncommand = \"cargo\"\ncondition = { env_set = [\"TUI_FEATURES\"] }\nargs = [\n  \"build\",\n  \"--no-default-features\",\n  \"--features\",\n  \"${TUI_FEATURES}\",\n  \"--all-targets\",\n]\n\n[tasks.clippy-crossterm]\nenv = { TUI_FEATURES = \"serde,crossterm\" }\nrun_task = \"clippy\"\n\n[tasks.clippy-termion]\nenv = { TUI_FEATURES = \"serde,termion\" }\nrun_task = \"clippy\"\n\n[tasks.clippy]\ncommand = \"cargo\"\ncondition = { env_set = [\"TUI_FEATURES\"] }\nargs = [\n  \"clippy\",\n  \"--all-targets\",\n  \"--no-default-features\",\n  \"--features\",\n  \"${TUI_FEATURES}\",\n  \"--\",\n  \"-D\",\n  \"warnings\",\n]\n\n[tasks.test-crossterm]\nenv = { TUI_FEATURES = \"serde,crossterm\" }\nrun_task = \"test\"\n\n[tasks.test-termion]\nenv = { TUI_FEATURES = \"serde,termion\" }\nrun_task = \"test\"\n\n[tasks.test]\ncommand = \"cargo\"\ncondition = { env_set = [\"TUI_FEATURES\"] }\nargs = [\n  \"test\",\n  \"--no-default-features\",\n  \"--features\",\n  \"${TUI_FEATURES}\",\n  \"--lib\",\n  \"--tests\",\n  \"--examples\",\n]\n\n[tasks.test-doc]\ncommand = \"cargo\"\nargs = [\n  \"test\",\n  \"--doc\",\n]\n\n[tasks.run-example]\nprivate = true\ncondition = { env_set = [\"TUI_EXAMPLE_NAME\"] }\ncommand = \"cargo\"\nargs = [\n    \"run\",\n    \"--release\",\n    \"--example\",\n    \"${TUI_EXAMPLE_NAME}\"\n]\n\n[tasks.build-examples]\ncommand = \"cargo\"\nargs = [\n    \"build\",\n    \"--examples\",\n    \"--release\"\n]\n\n[tasks.run-examples]\ndependencies = [\"build-examples\"]\nscript = '''\n#!@duckscript\nfiles = glob_array ./examples/*.rs\nfor file in ${files}\n  name = basename ${file}\n  name = substring ${name} -3\n  set_env TUI_EXAMPLE_NAME ${name}\n  cm_run_task run-example\nend\n'''\n"
  },
  {
    "path": "README.md",
    "content": "# tui-rs\n\n⚠️ **August 2023: This crate is no longer maintained. See https://github.com/ratatui-org/ratatui for an actively maintained fork.** ⚠️\n\n[![Build Status](https://github.com/fdehau/tui-rs/workflows/CI/badge.svg)](https://github.com/fdehau/tui-rs/actions?query=workflow%3ACI+)\n[![Crate Status](https://img.shields.io/crates/v/tui.svg)](https://crates.io/crates/tui)\n[![Docs Status](https://docs.rs/tui/badge.svg)](https://docs.rs/crate/tui/)\n\n<img src=\"./assets/demo.gif\" alt=\"Demo cast under Linux Termite with Inconsolata font 12pt\">\n\n`tui-rs` is a [Rust](https://www.rust-lang.org) library to build rich terminal\nuser interfaces and dashboards. It is heavily inspired by the `Javascript`\nlibrary [blessed-contrib](https://github.com/yaronn/blessed-contrib) and the\n`Go` library [termui](https://github.com/gizak/termui).\n\nThe library supports multiple backends:\n  - [crossterm](https://github.com/crossterm-rs/crossterm) [default]\n  - [termion](https://github.com/ticki/termion)\n\nThe library is based on the principle of immediate rendering with intermediate\nbuffers. This means that at each new frame you should build all widgets that are\nsupposed to be part of the UI. While providing a great flexibility for rich and\ninteractive UI, this may introduce overhead for highly dynamic content. So, the\nimplementation try to minimize the number of ansi escapes sequences generated to\ndraw the updated UI. In practice, given the speed of `Rust` the overhead rather\ncomes from the terminal emulator than the library itself.\n\nMoreover, the library does not provide any input handling nor any event system and\nyou may rely on the previously cited libraries to achieve such features.\n\n**I'm actively looking for help maintaining this crate. See [this issue](https://github.com/fdehau/tui-rs/issues/654)**\n\n### Rust version requirements\n\nSince version 0.17.0, `tui` requires **rustc version 1.56.1 or greater**.\n\n### [Documentation](https://docs.rs/tui)\n\n### Demo\n\nThe demo shown in the gif can be run with all available backends.\n\n```\n# crossterm\ncargo run --example demo --release -- --tick-rate 200\n# termion\ncargo run --example demo --no-default-features --features=termion --release -- --tick-rate 200\n```\n\nwhere `tick-rate` is the UI refresh rate in ms.\n\nThe UI code is in [examples/demo/ui.rs](https://github.com/fdehau/tui-rs/blob/v0.19.0/examples/demo/ui.rs) while the\napplication state is in [examples/demo/app.rs](https://github.com/fdehau/tui-rs/blob/v0.19.0/examples/demo/app.rs).\n\nIf the user interface contains glyphs that are not displayed correctly by your terminal, you may want to run\nthe demo without those symbols:\n\n```\ncargo run --example demo --release -- --tick-rate 200 --enhanced-graphics false\n```\n\n### Widgets\n\nThe library comes with the following list of widgets:\n\n  * [Block](https://github.com/fdehau/tui-rs/blob/v0.19.0/examples/block.rs)\n  * [Gauge](https://github.com/fdehau/tui-rs/blob/v0.19.0/examples/gauge.rs)\n  * [Sparkline](https://github.com/fdehau/tui-rs/blob/v0.19.0/examples/sparkline.rs)\n  * [Chart](https://github.com/fdehau/tui-rs/blob/v0.19.0/examples/chart.rs)\n  * [BarChart](https://github.com/fdehau/tui-rs/blob/v0.19.0/examples/barchart.rs)\n  * [List](https://github.com/fdehau/tui-rs/blob/v0.19.0/examples/list.rs)\n  * [Table](https://github.com/fdehau/tui-rs/blob/v0.19.0/examples/table.rs)\n  * [Paragraph](https://github.com/fdehau/tui-rs/blob/v0.19.0/examples/paragraph.rs)\n  * [Canvas (with line, point cloud, map)](https://github.com/fdehau/tui-rs/blob/v0.19.0/examples/canvas.rs)\n  * [Tabs](https://github.com/fdehau/tui-rs/blob/v0.19.0/examples/tabs.rs)\n\nClick on each item to see the source of the example. Run the examples with with \ncargo (e.g. to run the gauge example `cargo run --example gauge`), and quit by pressing `q`.\n\nYou can run all examples by running `cargo make run-examples` (require\n`cargo-make` that can be installed with `cargo install cargo-make`).\n\n### Third-party widgets\n\n* [tui-logger](https://github.com/gin66/tui-logger)\n* [tui-textarea](https://github.com/rhysd/tui-textarea): simple yet powerful multi-line text editor widget supporting several key shortcuts, undo/redo, text search, etc.\n* [tui-rs-tree-widgets](https://github.com/EdJoPaTo/tui-rs-tree-widget): widget for tree data structures.\n\n### Apps using tui\n\n* [spotify-tui](https://github.com/Rigellute/spotify-tui)\n* [bandwhich](https://github.com/imsnif/bandwhich)\n* [kmon](https://github.com/orhun/kmon)\n* [gpg-tui](https://github.com/orhun/gpg-tui)\n* [ytop](https://github.com/cjbassi/ytop)\n* [zenith](https://github.com/bvaisvil/zenith)\n* [bottom](https://github.com/ClementTsang/bottom)\n* [oha](https://github.com/hatoo/oha)\n* [gitui](https://github.com/extrawurst/gitui)\n* [rust-sadari-cli](https://github.com/24seconds/rust-sadari-cli)\n* [desed](https://github.com/SoptikHa2/desed)\n* [diskonaut](https://github.com/imsnif/diskonaut)\n* [tickrs](https://github.com/tarkah/tickrs)\n* [rusty-krab-manager](https://github.com/aryakaul/rusty-krab-manager)\n* [termchat](https://github.com/lemunozm/termchat)\n* [taskwarrior-tui](https://github.com/kdheepak/taskwarrior-tui)\n* [gping](https://github.com/orf/gping/)\n* [Vector](https://vector.dev)\n* [KDash](https://github.com/kdash-rs/kdash)\n* [xplr](https://github.com/sayanarijit/xplr)\n* [minesweep](https://github.com/cpcloud/minesweep-rs)\n* [Battleship.rs](https://github.com/deepu105/battleship-rs)\n* [termscp](https://github.com/veeso/termscp)\n* [joshuto](https://github.com/kamiyaa/joshuto)\n* [adsb_deku/radar](https://github.com/wcampbell0x2a/adsb_deku#radar-tui)\n* [hoard](https://github.com/Hyde46/hoard)\n* [tokio-console](https://github.com/tokio-rs/console): a diagnostics and debugging tool for asynchronous Rust programs.\n* [hwatch](https://github.com/blacknon/hwatch): a alternative watch command that records the result of command execution and can display its history and diffs.\n* [ytui-music](https://github.com/sudipghimire533/ytui-music): listen to music from youtube inside your terminal.\n* [mqttui](https://github.com/EdJoPaTo/mqttui): subscribe or publish to a MQTT Topic quickly from the terminal.\n* [meteo-tui](https://github.com/16arpi/meteo-tui): french weather via the command line.\n* [picterm](https://github.com/ksk001100/picterm): preview images in your terminal.\n* [gobang](https://github.com/TaKO8Ki/gobang): a cross-platform TUI database management tool.\n* [oxker](https://github.com/mrjackwills/oxker): a simple tui to view & control docker containers.\n* [trippy](https://github.com/fujiapple852/trippy): a network diagnostic tool.\n* [cotp](https://github.com/replydev/cotp): a trustworthy, encrypted, command-line TOTP/HOTP authenticator app with import functionality.\n* [hg-tui](https://github.com/kaixinbaba/hg-tui): view [hellogithub.com](https://hellogithub.com/) website on the terminal.\n\n### Alternatives\n\nYou might want to checkout [Cursive](https://github.com/gyscos/Cursive) for an\nalternative solution to build text user interfaces in Rust.\n\n## License\n\n[MIT](LICENSE)\n"
  },
  {
    "path": "examples/barchart.rs",
    "content": "use crossterm::{\n    event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},\n    execute,\n    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},\n};\nuse std::{\n    error::Error,\n    io,\n    time::{Duration, Instant},\n};\nuse tui::{\n    backend::{Backend, CrosstermBackend},\n    layout::{Constraint, Direction, Layout},\n    style::{Color, Modifier, Style},\n    widgets::{BarChart, Block, Borders},\n    Frame, Terminal,\n};\n\nstruct App<'a> {\n    data: Vec<(&'a str, u64)>,\n}\n\nimpl<'a> App<'a> {\n    fn new() -> App<'a> {\n        App {\n            data: vec![\n                (\"B1\", 9),\n                (\"B2\", 12),\n                (\"B3\", 5),\n                (\"B4\", 8),\n                (\"B5\", 2),\n                (\"B6\", 4),\n                (\"B7\", 5),\n                (\"B8\", 9),\n                (\"B9\", 14),\n                (\"B10\", 15),\n                (\"B11\", 1),\n                (\"B12\", 0),\n                (\"B13\", 4),\n                (\"B14\", 6),\n                (\"B15\", 4),\n                (\"B16\", 6),\n                (\"B17\", 4),\n                (\"B18\", 7),\n                (\"B19\", 13),\n                (\"B20\", 8),\n                (\"B21\", 11),\n                (\"B22\", 9),\n                (\"B23\", 3),\n                (\"B24\", 5),\n            ],\n        }\n    }\n\n    fn on_tick(&mut self) {\n        let value = self.data.pop().unwrap();\n        self.data.insert(0, value);\n    }\n}\n\nfn main() -> Result<(), Box<dyn Error>> {\n    // setup terminal\n    enable_raw_mode()?;\n    let mut stdout = io::stdout();\n    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;\n    let backend = CrosstermBackend::new(stdout);\n    let mut terminal = Terminal::new(backend)?;\n\n    // create app and run it\n    let tick_rate = Duration::from_millis(250);\n    let app = App::new();\n    let res = run_app(&mut terminal, app, tick_rate);\n\n    // restore terminal\n    disable_raw_mode()?;\n    execute!(\n        terminal.backend_mut(),\n        LeaveAlternateScreen,\n        DisableMouseCapture\n    )?;\n    terminal.show_cursor()?;\n\n    if let Err(err) = res {\n        println!(\"{:?}\", err)\n    }\n\n    Ok(())\n}\n\nfn run_app<B: Backend>(\n    terminal: &mut Terminal<B>,\n    mut app: App,\n    tick_rate: Duration,\n) -> io::Result<()> {\n    let mut last_tick = Instant::now();\n    loop {\n        terminal.draw(|f| ui(f, &app))?;\n\n        let timeout = tick_rate\n            .checked_sub(last_tick.elapsed())\n            .unwrap_or_else(|| Duration::from_secs(0));\n        if crossterm::event::poll(timeout)? {\n            if let Event::Key(key) = event::read()? {\n                if let KeyCode::Char('q') = key.code {\n                    return Ok(());\n                }\n            }\n        }\n        if last_tick.elapsed() >= tick_rate {\n            app.on_tick();\n            last_tick = Instant::now();\n        }\n    }\n}\n\nfn ui<B: Backend>(f: &mut Frame<B>, app: &App) {\n    let chunks = Layout::default()\n        .direction(Direction::Vertical)\n        .margin(2)\n        .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())\n        .split(f.size());\n    let barchart = BarChart::default()\n        .block(Block::default().title(\"Data1\").borders(Borders::ALL))\n        .data(&app.data)\n        .bar_width(9)\n        .bar_style(Style::default().fg(Color::Yellow))\n        .value_style(Style::default().fg(Color::Black).bg(Color::Yellow));\n    f.render_widget(barchart, chunks[0]);\n\n    let chunks = Layout::default()\n        .direction(Direction::Horizontal)\n        .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())\n        .split(chunks[1]);\n\n    let barchart = BarChart::default()\n        .block(Block::default().title(\"Data2\").borders(Borders::ALL))\n        .data(&app.data)\n        .bar_width(5)\n        .bar_gap(3)\n        .bar_style(Style::default().fg(Color::Green))\n        .value_style(\n            Style::default()\n                .bg(Color::Green)\n                .add_modifier(Modifier::BOLD),\n        );\n    f.render_widget(barchart, chunks[0]);\n\n    let barchart = BarChart::default()\n        .block(Block::default().title(\"Data3\").borders(Borders::ALL))\n        .data(&app.data)\n        .bar_style(Style::default().fg(Color::Red))\n        .bar_width(7)\n        .bar_gap(0)\n        .value_style(Style::default().bg(Color::Red))\n        .label_style(\n            Style::default()\n                .fg(Color::Cyan)\n                .add_modifier(Modifier::ITALIC),\n        );\n    f.render_widget(barchart, chunks[1]);\n}\n"
  },
  {
    "path": "examples/block.rs",
    "content": "use crossterm::{\n    event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},\n    execute,\n    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},\n};\nuse std::{error::Error, io};\nuse tui::{\n    backend::{Backend, CrosstermBackend},\n    layout::{Alignment, Constraint, Direction, Layout},\n    style::{Color, Modifier, Style},\n    text::Span,\n    widgets::{Block, BorderType, Borders},\n    Frame, Terminal,\n};\n\nfn main() -> Result<(), Box<dyn Error>> {\n    // setup terminal\n    enable_raw_mode()?;\n    let mut stdout = io::stdout();\n    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;\n    let backend = CrosstermBackend::new(stdout);\n    let mut terminal = Terminal::new(backend)?;\n\n    // create app and run it\n    let res = run_app(&mut terminal);\n\n    // restore terminal\n    disable_raw_mode()?;\n    execute!(\n        terminal.backend_mut(),\n        LeaveAlternateScreen,\n        DisableMouseCapture\n    )?;\n    terminal.show_cursor()?;\n\n    if let Err(err) = res {\n        println!(\"{:?}\", err)\n    }\n\n    Ok(())\n}\n\nfn run_app<B: Backend>(terminal: &mut Terminal<B>) -> io::Result<()> {\n    loop {\n        terminal.draw(ui)?;\n\n        if let Event::Key(key) = event::read()? {\n            if let KeyCode::Char('q') = key.code {\n                return Ok(());\n            }\n        }\n    }\n}\n\nfn ui<B: Backend>(f: &mut Frame<B>) {\n    // Wrapping block for a group\n    // Just draw the block and the group on the same area and build the group\n    // with at least a margin of 1\n    let size = f.size();\n\n    // Surrounding block\n    let block = Block::default()\n        .borders(Borders::ALL)\n        .title(\"Main block with round corners\")\n        .title_alignment(Alignment::Center)\n        .border_type(BorderType::Rounded);\n    f.render_widget(block, size);\n\n    let chunks = Layout::default()\n        .direction(Direction::Vertical)\n        .margin(4)\n        .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())\n        .split(f.size());\n\n    // Top two inner blocks\n    let top_chunks = Layout::default()\n        .direction(Direction::Horizontal)\n        .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())\n        .split(chunks[0]);\n\n    // Top left inner block with green background\n    let block = Block::default()\n        .title(vec![\n            Span::styled(\"With\", Style::default().fg(Color::Yellow)),\n            Span::from(\" background\"),\n        ])\n        .style(Style::default().bg(Color::Green));\n    f.render_widget(block, top_chunks[0]);\n\n    // Top right inner block with styled title aligned to the right\n    let block = Block::default()\n        .title(Span::styled(\n            \"Styled title\",\n            Style::default()\n                .fg(Color::White)\n                .bg(Color::Red)\n                .add_modifier(Modifier::BOLD),\n        ))\n        .title_alignment(Alignment::Right);\n    f.render_widget(block, top_chunks[1]);\n\n    // Bottom two inner blocks\n    let bottom_chunks = Layout::default()\n        .direction(Direction::Horizontal)\n        .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())\n        .split(chunks[1]);\n\n    // Bottom left block with all default borders\n    let block = Block::default().title(\"With borders\").borders(Borders::ALL);\n    f.render_widget(block, bottom_chunks[0]);\n\n    // Bottom right block with styled left and right border\n    let block = Block::default()\n        .title(\"With styled borders and doubled borders\")\n        .border_style(Style::default().fg(Color::Cyan))\n        .borders(Borders::LEFT | Borders::RIGHT)\n        .border_type(BorderType::Double);\n    f.render_widget(block, bottom_chunks[1]);\n}\n"
  },
  {
    "path": "examples/canvas.rs",
    "content": "use crossterm::{\n    event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},\n    execute,\n    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},\n};\nuse std::{\n    error::Error,\n    io,\n    time::{Duration, Instant},\n};\nuse tui::{\n    backend::{Backend, CrosstermBackend},\n    layout::{Constraint, Direction, Layout, Rect},\n    style::{Color, Style},\n    text::Span,\n    widgets::{\n        canvas::{Canvas, Map, MapResolution, Rectangle},\n        Block, Borders,\n    },\n    Frame, Terminal,\n};\n\nstruct App {\n    x: f64,\n    y: f64,\n    ball: Rectangle,\n    playground: Rect,\n    vx: f64,\n    vy: f64,\n    dir_x: bool,\n    dir_y: bool,\n}\n\nimpl App {\n    fn new() -> App {\n        App {\n            x: 0.0,\n            y: 0.0,\n            ball: Rectangle {\n                x: 10.0,\n                y: 30.0,\n                width: 10.0,\n                height: 10.0,\n                color: Color::Yellow,\n            },\n            playground: Rect::new(10, 10, 100, 100),\n            vx: 1.0,\n            vy: 1.0,\n            dir_x: true,\n            dir_y: true,\n        }\n    }\n\n    fn on_tick(&mut self) {\n        if self.ball.x < self.playground.left() as f64\n            || self.ball.x + self.ball.width > self.playground.right() as f64\n        {\n            self.dir_x = !self.dir_x;\n        }\n        if self.ball.y < self.playground.top() as f64\n            || self.ball.y + self.ball.height > self.playground.bottom() as f64\n        {\n            self.dir_y = !self.dir_y;\n        }\n\n        if self.dir_x {\n            self.ball.x += self.vx;\n        } else {\n            self.ball.x -= self.vx;\n        }\n\n        if self.dir_y {\n            self.ball.y += self.vy;\n        } else {\n            self.ball.y -= self.vy\n        }\n    }\n}\n\nfn main() -> Result<(), Box<dyn Error>> {\n    // setup terminal\n    enable_raw_mode()?;\n    let mut stdout = io::stdout();\n    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;\n    let backend = CrosstermBackend::new(stdout);\n    let mut terminal = Terminal::new(backend)?;\n\n    // create app and run it\n    let tick_rate = Duration::from_millis(250);\n    let app = App::new();\n    let res = run_app(&mut terminal, app, tick_rate);\n\n    // restore terminal\n    disable_raw_mode()?;\n    execute!(\n        terminal.backend_mut(),\n        LeaveAlternateScreen,\n        DisableMouseCapture\n    )?;\n    terminal.show_cursor()?;\n\n    if let Err(err) = res {\n        println!(\"{:?}\", err)\n    }\n\n    Ok(())\n}\n\nfn run_app<B: Backend>(\n    terminal: &mut Terminal<B>,\n    mut app: App,\n    tick_rate: Duration,\n) -> io::Result<()> {\n    let mut last_tick = Instant::now();\n    loop {\n        terminal.draw(|f| ui(f, &app))?;\n\n        let timeout = tick_rate\n            .checked_sub(last_tick.elapsed())\n            .unwrap_or_else(|| Duration::from_secs(0));\n        if event::poll(timeout)? {\n            if let Event::Key(key) = event::read()? {\n                match key.code {\n                    KeyCode::Char('q') => {\n                        return Ok(());\n                    }\n                    KeyCode::Down => {\n                        app.y += 1.0;\n                    }\n                    KeyCode::Up => {\n                        app.y -= 1.0;\n                    }\n                    KeyCode::Right => {\n                        app.x += 1.0;\n                    }\n                    KeyCode::Left => {\n                        app.x -= 1.0;\n                    }\n                    _ => {}\n                }\n            }\n        }\n\n        if last_tick.elapsed() >= tick_rate {\n            app.on_tick();\n            last_tick = Instant::now();\n        }\n    }\n}\n\nfn ui<B: Backend>(f: &mut Frame<B>, app: &App) {\n    let chunks = Layout::default()\n        .direction(Direction::Horizontal)\n        .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())\n        .split(f.size());\n    let canvas = Canvas::default()\n        .block(Block::default().borders(Borders::ALL).title(\"World\"))\n        .paint(|ctx| {\n            ctx.draw(&Map {\n                color: Color::White,\n                resolution: MapResolution::High,\n            });\n            ctx.print(\n                app.x,\n                -app.y,\n                Span::styled(\"You are here\", Style::default().fg(Color::Yellow)),\n            );\n        })\n        .x_bounds([-180.0, 180.0])\n        .y_bounds([-90.0, 90.0]);\n    f.render_widget(canvas, chunks[0]);\n    let canvas = Canvas::default()\n        .block(Block::default().borders(Borders::ALL).title(\"Pong\"))\n        .paint(|ctx| {\n            ctx.draw(&app.ball);\n        })\n        .x_bounds([10.0, 110.0])\n        .y_bounds([10.0, 110.0]);\n    f.render_widget(canvas, chunks[1]);\n}\n"
  },
  {
    "path": "examples/chart.rs",
    "content": "use crossterm::{\n    event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},\n    execute,\n    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},\n};\nuse std::{\n    error::Error,\n    io,\n    time::{Duration, Instant},\n};\nuse tui::{\n    backend::{Backend, CrosstermBackend},\n    layout::{Constraint, Direction, Layout},\n    style::{Color, Modifier, Style},\n    symbols,\n    text::Span,\n    widgets::{Axis, Block, Borders, Chart, Dataset, GraphType},\n    Frame, Terminal,\n};\n\nconst DATA: [(f64, f64); 5] = [(0.0, 0.0), (1.0, 1.0), (2.0, 2.0), (3.0, 3.0), (4.0, 4.0)];\nconst DATA2: [(f64, f64); 7] = [\n    (0.0, 0.0),\n    (10.0, 1.0),\n    (20.0, 0.5),\n    (30.0, 1.5),\n    (40.0, 1.0),\n    (50.0, 2.5),\n    (60.0, 3.0),\n];\n\n#[derive(Clone)]\npub struct SinSignal {\n    x: f64,\n    interval: f64,\n    period: f64,\n    scale: f64,\n}\n\nimpl SinSignal {\n    pub fn new(interval: f64, period: f64, scale: f64) -> SinSignal {\n        SinSignal {\n            x: 0.0,\n            interval,\n            period,\n            scale,\n        }\n    }\n}\n\nimpl Iterator for SinSignal {\n    type Item = (f64, f64);\n    fn next(&mut self) -> Option<Self::Item> {\n        let point = (self.x, (self.x * 1.0 / self.period).sin() * self.scale);\n        self.x += self.interval;\n        Some(point)\n    }\n}\n\nstruct App {\n    signal1: SinSignal,\n    data1: Vec<(f64, f64)>,\n    signal2: SinSignal,\n    data2: Vec<(f64, f64)>,\n    window: [f64; 2],\n}\n\nimpl App {\n    fn new() -> App {\n        let mut signal1 = SinSignal::new(0.2, 3.0, 18.0);\n        let mut signal2 = SinSignal::new(0.1, 2.0, 10.0);\n        let data1 = signal1.by_ref().take(200).collect::<Vec<(f64, f64)>>();\n        let data2 = signal2.by_ref().take(200).collect::<Vec<(f64, f64)>>();\n        App {\n            signal1,\n            data1,\n            signal2,\n            data2,\n            window: [0.0, 20.0],\n        }\n    }\n\n    fn on_tick(&mut self) {\n        for _ in 0..5 {\n            self.data1.remove(0);\n        }\n        self.data1.extend(self.signal1.by_ref().take(5));\n        for _ in 0..10 {\n            self.data2.remove(0);\n        }\n        self.data2.extend(self.signal2.by_ref().take(10));\n        self.window[0] += 1.0;\n        self.window[1] += 1.0;\n    }\n}\n\nfn main() -> Result<(), Box<dyn Error>> {\n    // setup terminal\n    enable_raw_mode()?;\n    let mut stdout = io::stdout();\n    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;\n    let backend = CrosstermBackend::new(stdout);\n    let mut terminal = Terminal::new(backend)?;\n\n    // create app and run it\n    let tick_rate = Duration::from_millis(250);\n    let app = App::new();\n    let res = run_app(&mut terminal, app, tick_rate);\n\n    // restore terminal\n    disable_raw_mode()?;\n    execute!(\n        terminal.backend_mut(),\n        LeaveAlternateScreen,\n        DisableMouseCapture\n    )?;\n    terminal.show_cursor()?;\n\n    if let Err(err) = res {\n        println!(\"{:?}\", err)\n    }\n\n    Ok(())\n}\n\nfn run_app<B: Backend>(\n    terminal: &mut Terminal<B>,\n    mut app: App,\n    tick_rate: Duration,\n) -> io::Result<()> {\n    let mut last_tick = Instant::now();\n    loop {\n        terminal.draw(|f| ui(f, &app))?;\n\n        let timeout = tick_rate\n            .checked_sub(last_tick.elapsed())\n            .unwrap_or_else(|| Duration::from_secs(0));\n        if crossterm::event::poll(timeout)? {\n            if let Event::Key(key) = event::read()? {\n                if let KeyCode::Char('q') = key.code {\n                    return Ok(());\n                }\n            }\n        }\n        if last_tick.elapsed() >= tick_rate {\n            app.on_tick();\n            last_tick = Instant::now();\n        }\n    }\n}\n\nfn ui<B: Backend>(f: &mut Frame<B>, app: &App) {\n    let size = f.size();\n    let chunks = Layout::default()\n        .direction(Direction::Vertical)\n        .constraints(\n            [\n                Constraint::Ratio(1, 3),\n                Constraint::Ratio(1, 3),\n                Constraint::Ratio(1, 3),\n            ]\n            .as_ref(),\n        )\n        .split(size);\n    let x_labels = vec![\n        Span::styled(\n            format!(\"{}\", app.window[0]),\n            Style::default().add_modifier(Modifier::BOLD),\n        ),\n        Span::raw(format!(\"{}\", (app.window[0] + app.window[1]) / 2.0)),\n        Span::styled(\n            format!(\"{}\", app.window[1]),\n            Style::default().add_modifier(Modifier::BOLD),\n        ),\n    ];\n    let datasets = vec![\n        Dataset::default()\n            .name(\"data2\")\n            .marker(symbols::Marker::Dot)\n            .style(Style::default().fg(Color::Cyan))\n            .data(&app.data1),\n        Dataset::default()\n            .name(\"data3\")\n            .marker(symbols::Marker::Braille)\n            .style(Style::default().fg(Color::Yellow))\n            .data(&app.data2),\n    ];\n\n    let chart = Chart::new(datasets)\n        .block(\n            Block::default()\n                .title(Span::styled(\n                    \"Chart 1\",\n                    Style::default()\n                        .fg(Color::Cyan)\n                        .add_modifier(Modifier::BOLD),\n                ))\n                .borders(Borders::ALL),\n        )\n        .x_axis(\n            Axis::default()\n                .title(\"X Axis\")\n                .style(Style::default().fg(Color::Gray))\n                .labels(x_labels)\n                .bounds(app.window),\n        )\n        .y_axis(\n            Axis::default()\n                .title(\"Y Axis\")\n                .style(Style::default().fg(Color::Gray))\n                .labels(vec![\n                    Span::styled(\"-20\", Style::default().add_modifier(Modifier::BOLD)),\n                    Span::raw(\"0\"),\n                    Span::styled(\"20\", Style::default().add_modifier(Modifier::BOLD)),\n                ])\n                .bounds([-20.0, 20.0]),\n        );\n    f.render_widget(chart, chunks[0]);\n\n    let datasets = vec![Dataset::default()\n        .name(\"data\")\n        .marker(symbols::Marker::Braille)\n        .style(Style::default().fg(Color::Yellow))\n        .graph_type(GraphType::Line)\n        .data(&DATA)];\n    let chart = Chart::new(datasets)\n        .block(\n            Block::default()\n                .title(Span::styled(\n                    \"Chart 2\",\n                    Style::default()\n                        .fg(Color::Cyan)\n                        .add_modifier(Modifier::BOLD),\n                ))\n                .borders(Borders::ALL),\n        )\n        .x_axis(\n            Axis::default()\n                .title(\"X Axis\")\n                .style(Style::default().fg(Color::Gray))\n                .bounds([0.0, 5.0])\n                .labels(vec![\n                    Span::styled(\"0\", Style::default().add_modifier(Modifier::BOLD)),\n                    Span::raw(\"2.5\"),\n                    Span::styled(\"5.0\", Style::default().add_modifier(Modifier::BOLD)),\n                ]),\n        )\n        .y_axis(\n            Axis::default()\n                .title(\"Y Axis\")\n                .style(Style::default().fg(Color::Gray))\n                .bounds([0.0, 5.0])\n                .labels(vec![\n                    Span::styled(\"0\", Style::default().add_modifier(Modifier::BOLD)),\n                    Span::raw(\"2.5\"),\n                    Span::styled(\"5.0\", Style::default().add_modifier(Modifier::BOLD)),\n                ]),\n        );\n    f.render_widget(chart, chunks[1]);\n\n    let datasets = vec![Dataset::default()\n        .name(\"data\")\n        .marker(symbols::Marker::Braille)\n        .style(Style::default().fg(Color::Yellow))\n        .graph_type(GraphType::Line)\n        .data(&DATA2)];\n    let chart = Chart::new(datasets)\n        .block(\n            Block::default()\n                .title(Span::styled(\n                    \"Chart 3\",\n                    Style::default()\n                        .fg(Color::Cyan)\n                        .add_modifier(Modifier::BOLD),\n                ))\n                .borders(Borders::ALL),\n        )\n        .x_axis(\n            Axis::default()\n                .title(\"X Axis\")\n                .style(Style::default().fg(Color::Gray))\n                .bounds([0.0, 50.0])\n                .labels(vec![\n                    Span::styled(\"0\", Style::default().add_modifier(Modifier::BOLD)),\n                    Span::raw(\"25\"),\n                    Span::styled(\"50\", Style::default().add_modifier(Modifier::BOLD)),\n                ]),\n        )\n        .y_axis(\n            Axis::default()\n                .title(\"Y Axis\")\n                .style(Style::default().fg(Color::Gray))\n                .bounds([0.0, 5.0])\n                .labels(vec![\n                    Span::styled(\"0\", Style::default().add_modifier(Modifier::BOLD)),\n                    Span::raw(\"2.5\"),\n                    Span::styled(\"5\", Style::default().add_modifier(Modifier::BOLD)),\n                ]),\n        );\n    f.render_widget(chart, chunks[2]);\n}\n"
  },
  {
    "path": "examples/custom_widget.rs",
    "content": "use crossterm::{\n    event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},\n    execute,\n    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},\n};\nuse std::{error::Error, io};\nuse tui::{\n    backend::{Backend, CrosstermBackend},\n    buffer::Buffer,\n    layout::Rect,\n    style::Style,\n    widgets::Widget,\n    Frame, Terminal,\n};\n\n#[derive(Default)]\nstruct Label<'a> {\n    text: &'a str,\n}\n\nimpl<'a> Widget for Label<'a> {\n    fn render(self, area: Rect, buf: &mut Buffer) {\n        buf.set_string(area.left(), area.top(), self.text, Style::default());\n    }\n}\n\nimpl<'a> Label<'a> {\n    fn text(mut self, text: &'a str) -> Label<'a> {\n        self.text = text;\n        self\n    }\n}\n\nfn main() -> Result<(), Box<dyn Error>> {\n    // setup terminal\n    enable_raw_mode()?;\n    let mut stdout = io::stdout();\n    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;\n    let backend = CrosstermBackend::new(stdout);\n    let mut terminal = Terminal::new(backend)?;\n\n    // create app and run it\n    let res = run_app(&mut terminal);\n\n    // restore terminal\n    disable_raw_mode()?;\n    execute!(\n        terminal.backend_mut(),\n        LeaveAlternateScreen,\n        DisableMouseCapture\n    )?;\n    terminal.show_cursor()?;\n\n    if let Err(err) = res {\n        println!(\"{:?}\", err)\n    }\n\n    Ok(())\n}\n\nfn run_app<B: Backend>(terminal: &mut Terminal<B>) -> io::Result<()> {\n    loop {\n        terminal.draw(ui)?;\n\n        if let Event::Key(key) = event::read()? {\n            if let KeyCode::Char('q') = key.code {\n                return Ok(());\n            }\n        }\n    }\n}\n\nfn ui<B: Backend>(f: &mut Frame<B>) {\n    let size = f.size();\n    let label = Label::default().text(\"Test\");\n    f.render_widget(label, size);\n}\n"
  },
  {
    "path": "examples/demo/app.rs",
    "content": "use rand::{\n    distributions::{Distribution, Uniform},\n    rngs::ThreadRng,\n};\nuse tui::widgets::ListState;\n\nconst TASKS: [&str; 24] = [\n    \"Item1\", \"Item2\", \"Item3\", \"Item4\", \"Item5\", \"Item6\", \"Item7\", \"Item8\", \"Item9\", \"Item10\",\n    \"Item11\", \"Item12\", \"Item13\", \"Item14\", \"Item15\", \"Item16\", \"Item17\", \"Item18\", \"Item19\",\n    \"Item20\", \"Item21\", \"Item22\", \"Item23\", \"Item24\",\n];\n\nconst LOGS: [(&str, &str); 26] = [\n    (\"Event1\", \"INFO\"),\n    (\"Event2\", \"INFO\"),\n    (\"Event3\", \"CRITICAL\"),\n    (\"Event4\", \"ERROR\"),\n    (\"Event5\", \"INFO\"),\n    (\"Event6\", \"INFO\"),\n    (\"Event7\", \"WARNING\"),\n    (\"Event8\", \"INFO\"),\n    (\"Event9\", \"INFO\"),\n    (\"Event10\", \"INFO\"),\n    (\"Event11\", \"CRITICAL\"),\n    (\"Event12\", \"INFO\"),\n    (\"Event13\", \"INFO\"),\n    (\"Event14\", \"INFO\"),\n    (\"Event15\", \"INFO\"),\n    (\"Event16\", \"INFO\"),\n    (\"Event17\", \"ERROR\"),\n    (\"Event18\", \"ERROR\"),\n    (\"Event19\", \"INFO\"),\n    (\"Event20\", \"INFO\"),\n    (\"Event21\", \"WARNING\"),\n    (\"Event22\", \"INFO\"),\n    (\"Event23\", \"INFO\"),\n    (\"Event24\", \"WARNING\"),\n    (\"Event25\", \"INFO\"),\n    (\"Event26\", \"INFO\"),\n];\n\nconst EVENTS: [(&str, u64); 24] = [\n    (\"B1\", 9),\n    (\"B2\", 12),\n    (\"B3\", 5),\n    (\"B4\", 8),\n    (\"B5\", 2),\n    (\"B6\", 4),\n    (\"B7\", 5),\n    (\"B8\", 9),\n    (\"B9\", 14),\n    (\"B10\", 15),\n    (\"B11\", 1),\n    (\"B12\", 0),\n    (\"B13\", 4),\n    (\"B14\", 6),\n    (\"B15\", 4),\n    (\"B16\", 6),\n    (\"B17\", 4),\n    (\"B18\", 7),\n    (\"B19\", 13),\n    (\"B20\", 8),\n    (\"B21\", 11),\n    (\"B22\", 9),\n    (\"B23\", 3),\n    (\"B24\", 5),\n];\n\n#[derive(Clone)]\npub struct RandomSignal {\n    distribution: Uniform<u64>,\n    rng: ThreadRng,\n}\n\nimpl RandomSignal {\n    pub fn new(lower: u64, upper: u64) -> RandomSignal {\n        RandomSignal {\n            distribution: Uniform::new(lower, upper),\n            rng: rand::thread_rng(),\n        }\n    }\n}\n\nimpl Iterator for RandomSignal {\n    type Item = u64;\n    fn next(&mut self) -> Option<u64> {\n        Some(self.distribution.sample(&mut self.rng))\n    }\n}\n\n#[derive(Clone)]\npub struct SinSignal {\n    x: f64,\n    interval: f64,\n    period: f64,\n    scale: f64,\n}\n\nimpl SinSignal {\n    pub fn new(interval: f64, period: f64, scale: f64) -> SinSignal {\n        SinSignal {\n            x: 0.0,\n            interval,\n            period,\n            scale,\n        }\n    }\n}\n\nimpl Iterator for SinSignal {\n    type Item = (f64, f64);\n    fn next(&mut self) -> Option<Self::Item> {\n        let point = (self.x, (self.x * 1.0 / self.period).sin() * self.scale);\n        self.x += self.interval;\n        Some(point)\n    }\n}\n\npub struct TabsState<'a> {\n    pub titles: Vec<&'a str>,\n    pub index: usize,\n}\n\nimpl<'a> TabsState<'a> {\n    pub fn new(titles: Vec<&'a str>) -> TabsState {\n        TabsState { titles, index: 0 }\n    }\n    pub fn next(&mut self) {\n        self.index = (self.index + 1) % self.titles.len();\n    }\n\n    pub fn previous(&mut self) {\n        if self.index > 0 {\n            self.index -= 1;\n        } else {\n            self.index = self.titles.len() - 1;\n        }\n    }\n}\n\npub struct StatefulList<T> {\n    pub state: ListState,\n    pub items: Vec<T>,\n}\n\nimpl<T> StatefulList<T> {\n    pub fn with_items(items: Vec<T>) -> StatefulList<T> {\n        StatefulList {\n            state: ListState::default(),\n            items,\n        }\n    }\n\n    pub fn next(&mut self) {\n        let i = match self.state.selected() {\n            Some(i) => {\n                if i >= self.items.len() - 1 {\n                    0\n                } else {\n                    i + 1\n                }\n            }\n            None => 0,\n        };\n        self.state.select(Some(i));\n    }\n\n    pub fn previous(&mut self) {\n        let i = match self.state.selected() {\n            Some(i) => {\n                if i == 0 {\n                    self.items.len() - 1\n                } else {\n                    i - 1\n                }\n            }\n            None => 0,\n        };\n        self.state.select(Some(i));\n    }\n}\n\npub struct Signal<S: Iterator> {\n    source: S,\n    pub points: Vec<S::Item>,\n    tick_rate: usize,\n}\n\nimpl<S> Signal<S>\nwhere\n    S: Iterator,\n{\n    fn on_tick(&mut self) {\n        for _ in 0..self.tick_rate {\n            self.points.remove(0);\n        }\n        self.points\n            .extend(self.source.by_ref().take(self.tick_rate));\n    }\n}\n\npub struct Signals {\n    pub sin1: Signal<SinSignal>,\n    pub sin2: Signal<SinSignal>,\n    pub window: [f64; 2],\n}\n\nimpl Signals {\n    fn on_tick(&mut self) {\n        self.sin1.on_tick();\n        self.sin2.on_tick();\n        self.window[0] += 1.0;\n        self.window[1] += 1.0;\n    }\n}\n\npub struct Server<'a> {\n    pub name: &'a str,\n    pub location: &'a str,\n    pub coords: (f64, f64),\n    pub status: &'a str,\n}\n\npub struct App<'a> {\n    pub title: &'a str,\n    pub should_quit: bool,\n    pub tabs: TabsState<'a>,\n    pub show_chart: bool,\n    pub progress: f64,\n    pub sparkline: Signal<RandomSignal>,\n    pub tasks: StatefulList<&'a str>,\n    pub logs: StatefulList<(&'a str, &'a str)>,\n    pub signals: Signals,\n    pub barchart: Vec<(&'a str, u64)>,\n    pub servers: Vec<Server<'a>>,\n    pub enhanced_graphics: bool,\n}\n\nimpl<'a> App<'a> {\n    pub fn new(title: &'a str, enhanced_graphics: bool) -> App<'a> {\n        let mut rand_signal = RandomSignal::new(0, 100);\n        let sparkline_points = rand_signal.by_ref().take(300).collect();\n        let mut sin_signal = SinSignal::new(0.2, 3.0, 18.0);\n        let sin1_points = sin_signal.by_ref().take(100).collect();\n        let mut sin_signal2 = SinSignal::new(0.1, 2.0, 10.0);\n        let sin2_points = sin_signal2.by_ref().take(200).collect();\n        App {\n            title,\n            should_quit: false,\n            tabs: TabsState::new(vec![\"Tab0\", \"Tab1\", \"Tab2\"]),\n            show_chart: true,\n            progress: 0.0,\n            sparkline: Signal {\n                source: rand_signal,\n                points: sparkline_points,\n                tick_rate: 1,\n            },\n            tasks: StatefulList::with_items(TASKS.to_vec()),\n            logs: StatefulList::with_items(LOGS.to_vec()),\n            signals: Signals {\n                sin1: Signal {\n                    source: sin_signal,\n                    points: sin1_points,\n                    tick_rate: 5,\n                },\n                sin2: Signal {\n                    source: sin_signal2,\n                    points: sin2_points,\n                    tick_rate: 10,\n                },\n                window: [0.0, 20.0],\n            },\n            barchart: EVENTS.to_vec(),\n            servers: vec![\n                Server {\n                    name: \"NorthAmerica-1\",\n                    location: \"New York City\",\n                    coords: (40.71, -74.00),\n                    status: \"Up\",\n                },\n                Server {\n                    name: \"Europe-1\",\n                    location: \"Paris\",\n                    coords: (48.85, 2.35),\n                    status: \"Failure\",\n                },\n                Server {\n                    name: \"SouthAmerica-1\",\n                    location: \"São Paulo\",\n                    coords: (-23.54, -46.62),\n                    status: \"Up\",\n                },\n                Server {\n                    name: \"Asia-1\",\n                    location: \"Singapore\",\n                    coords: (1.35, 103.86),\n                    status: \"Up\",\n                },\n            ],\n            enhanced_graphics,\n        }\n    }\n\n    pub fn on_up(&mut self) {\n        self.tasks.previous();\n    }\n\n    pub fn on_down(&mut self) {\n        self.tasks.next();\n    }\n\n    pub fn on_right(&mut self) {\n        self.tabs.next();\n    }\n\n    pub fn on_left(&mut self) {\n        self.tabs.previous();\n    }\n\n    pub fn on_key(&mut self, c: char) {\n        match c {\n            'q' => {\n                self.should_quit = true;\n            }\n            't' => {\n                self.show_chart = !self.show_chart;\n            }\n            _ => {}\n        }\n    }\n\n    pub fn on_tick(&mut self) {\n        // Update progress\n        self.progress += 0.001;\n        if self.progress > 1.0 {\n            self.progress = 0.0;\n        }\n\n        self.sparkline.on_tick();\n        self.signals.on_tick();\n\n        let log = self.logs.items.pop().unwrap();\n        self.logs.items.insert(0, log);\n\n        let event = self.barchart.pop().unwrap();\n        self.barchart.insert(0, event);\n    }\n}\n"
  },
  {
    "path": "examples/demo/crossterm.rs",
    "content": "use crate::{app::App, ui};\nuse crossterm::{\n    event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},\n    execute,\n    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},\n};\nuse std::{\n    error::Error,\n    io,\n    time::{Duration, Instant},\n};\nuse tui::{\n    backend::{Backend, CrosstermBackend},\n    Terminal,\n};\n\npub fn run(tick_rate: Duration, enhanced_graphics: bool) -> Result<(), Box<dyn Error>> {\n    // setup terminal\n    enable_raw_mode()?;\n    let mut stdout = io::stdout();\n    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;\n    let backend = CrosstermBackend::new(stdout);\n    let mut terminal = Terminal::new(backend)?;\n\n    // create app and run it\n    let app = App::new(\"Crossterm Demo\", enhanced_graphics);\n    let res = run_app(&mut terminal, app, tick_rate);\n\n    // restore terminal\n    disable_raw_mode()?;\n    execute!(\n        terminal.backend_mut(),\n        LeaveAlternateScreen,\n        DisableMouseCapture\n    )?;\n    terminal.show_cursor()?;\n\n    if let Err(err) = res {\n        println!(\"{:?}\", err)\n    }\n\n    Ok(())\n}\n\nfn run_app<B: Backend>(\n    terminal: &mut Terminal<B>,\n    mut app: App,\n    tick_rate: Duration,\n) -> io::Result<()> {\n    let mut last_tick = Instant::now();\n    loop {\n        terminal.draw(|f| ui::draw(f, &mut app))?;\n\n        let timeout = tick_rate\n            .checked_sub(last_tick.elapsed())\n            .unwrap_or_else(|| Duration::from_secs(0));\n        if crossterm::event::poll(timeout)? {\n            if let Event::Key(key) = event::read()? {\n                match key.code {\n                    KeyCode::Char(c) => app.on_key(c),\n                    KeyCode::Left => app.on_left(),\n                    KeyCode::Up => app.on_up(),\n                    KeyCode::Right => app.on_right(),\n                    KeyCode::Down => app.on_down(),\n                    _ => {}\n                }\n            }\n        }\n        if last_tick.elapsed() >= tick_rate {\n            app.on_tick();\n            last_tick = Instant::now();\n        }\n        if app.should_quit {\n            return Ok(());\n        }\n    }\n}\n"
  },
  {
    "path": "examples/demo/main.rs",
    "content": "mod app;\n#[cfg(feature = \"crossterm\")]\nmod crossterm;\n#[cfg(feature = \"termion\")]\nmod termion;\nmod ui;\n\n#[cfg(feature = \"crossterm\")]\nuse crate::crossterm::run;\n#[cfg(feature = \"termion\")]\nuse crate::termion::run;\nuse argh::FromArgs;\nuse std::{error::Error, time::Duration};\n\n/// Demo\n#[derive(Debug, FromArgs)]\nstruct Cli {\n    /// time in ms between two ticks.\n    #[argh(option, default = \"250\")]\n    tick_rate: u64,\n    /// whether unicode symbols are used to improve the overall look of the app\n    #[argh(option, default = \"true\")]\n    enhanced_graphics: bool,\n}\n\nfn main() -> Result<(), Box<dyn Error>> {\n    let cli: Cli = argh::from_env();\n    let tick_rate = Duration::from_millis(cli.tick_rate);\n    run(tick_rate, cli.enhanced_graphics)?;\n    Ok(())\n}\n"
  },
  {
    "path": "examples/demo/termion.rs",
    "content": "use crate::{app::App, ui};\nuse std::{error::Error, io, sync::mpsc, thread, time::Duration};\nuse termion::{\n    event::Key,\n    input::{MouseTerminal, TermRead},\n    raw::IntoRawMode,\n    screen::AlternateScreen,\n};\nuse tui::{\n    backend::{Backend, TermionBackend},\n    Terminal,\n};\n\npub fn run(tick_rate: Duration, enhanced_graphics: bool) -> Result<(), Box<dyn Error>> {\n    // setup terminal\n    let stdout = io::stdout().into_raw_mode()?;\n    let stdout = MouseTerminal::from(stdout);\n    let stdout = AlternateScreen::from(stdout);\n    let backend = TermionBackend::new(stdout);\n    let mut terminal = Terminal::new(backend)?;\n\n    // create app and run it\n    let app = App::new(\"Termion demo\", enhanced_graphics);\n    run_app(&mut terminal, app, tick_rate)?;\n\n    Ok(())\n}\n\nfn run_app<B: Backend>(\n    terminal: &mut Terminal<B>,\n    mut app: App,\n    tick_rate: Duration,\n) -> Result<(), Box<dyn Error>> {\n    let events = events(tick_rate);\n    loop {\n        terminal.draw(|f| ui::draw(f, &mut app))?;\n\n        match events.recv()? {\n            Event::Input(key) => match key {\n                Key::Char(c) => app.on_key(c),\n                Key::Up => app.on_up(),\n                Key::Down => app.on_down(),\n                Key::Left => app.on_left(),\n                Key::Right => app.on_right(),\n                _ => {}\n            },\n            Event::Tick => app.on_tick(),\n        }\n        if app.should_quit {\n            return Ok(());\n        }\n    }\n}\n\nenum Event {\n    Input(Key),\n    Tick,\n}\n\nfn events(tick_rate: Duration) -> mpsc::Receiver<Event> {\n    let (tx, rx) = mpsc::channel();\n    let keys_tx = tx.clone();\n    thread::spawn(move || {\n        let stdin = io::stdin();\n        for key in stdin.keys().flatten() {\n            if let Err(err) = keys_tx.send(Event::Input(key)) {\n                eprintln!(\"{}\", err);\n                return;\n            }\n        }\n    });\n    thread::spawn(move || loop {\n        if let Err(err) = tx.send(Event::Tick) {\n            eprintln!(\"{}\", err);\n            break;\n        }\n        thread::sleep(tick_rate);\n    });\n    rx\n}\n"
  },
  {
    "path": "examples/demo/ui.rs",
    "content": "use crate::app::App;\nuse tui::{\n    backend::Backend,\n    layout::{Constraint, Direction, Layout, Rect},\n    style::{Color, Modifier, Style},\n    symbols,\n    text::{Span, Spans},\n    widgets::canvas::{Canvas, Line, Map, MapResolution, Rectangle},\n    widgets::{\n        Axis, BarChart, Block, Borders, Cell, Chart, Dataset, Gauge, LineGauge, List, ListItem,\n        Paragraph, Row, Sparkline, Table, Tabs, Wrap,\n    },\n    Frame,\n};\n\npub fn draw<B: Backend>(f: &mut Frame<B>, app: &mut App) {\n    let chunks = Layout::default()\n        .constraints([Constraint::Length(3), Constraint::Min(0)].as_ref())\n        .split(f.size());\n    let titles = app\n        .tabs\n        .titles\n        .iter()\n        .map(|t| Spans::from(Span::styled(*t, Style::default().fg(Color::Green))))\n        .collect();\n    let tabs = Tabs::new(titles)\n        .block(Block::default().borders(Borders::ALL).title(app.title))\n        .highlight_style(Style::default().fg(Color::Yellow))\n        .select(app.tabs.index);\n    f.render_widget(tabs, chunks[0]);\n    match app.tabs.index {\n        0 => draw_first_tab(f, app, chunks[1]),\n        1 => draw_second_tab(f, app, chunks[1]),\n        2 => draw_third_tab(f, app, chunks[1]),\n        _ => {}\n    };\n}\n\nfn draw_first_tab<B>(f: &mut Frame<B>, app: &mut App, area: Rect)\nwhere\n    B: Backend,\n{\n    let chunks = Layout::default()\n        .constraints(\n            [\n                Constraint::Length(9),\n                Constraint::Min(8),\n                Constraint::Length(7),\n            ]\n            .as_ref(),\n        )\n        .split(area);\n    draw_gauges(f, app, chunks[0]);\n    draw_charts(f, app, chunks[1]);\n    draw_text(f, chunks[2]);\n}\n\nfn draw_gauges<B>(f: &mut Frame<B>, app: &mut App, area: Rect)\nwhere\n    B: Backend,\n{\n    let chunks = Layout::default()\n        .constraints(\n            [\n                Constraint::Length(2),\n                Constraint::Length(3),\n                Constraint::Length(1),\n            ]\n            .as_ref(),\n        )\n        .margin(1)\n        .split(area);\n    let block = Block::default().borders(Borders::ALL).title(\"Graphs\");\n    f.render_widget(block, area);\n\n    let label = format!(\"{:.2}%\", app.progress * 100.0);\n    let gauge = Gauge::default()\n        .block(Block::default().title(\"Gauge:\"))\n        .gauge_style(\n            Style::default()\n                .fg(Color::Magenta)\n                .bg(Color::Black)\n                .add_modifier(Modifier::ITALIC | Modifier::BOLD),\n        )\n        .label(label)\n        .ratio(app.progress);\n    f.render_widget(gauge, chunks[0]);\n\n    let sparkline = Sparkline::default()\n        .block(Block::default().title(\"Sparkline:\"))\n        .style(Style::default().fg(Color::Green))\n        .data(&app.sparkline.points)\n        .bar_set(if app.enhanced_graphics {\n            symbols::bar::NINE_LEVELS\n        } else {\n            symbols::bar::THREE_LEVELS\n        });\n    f.render_widget(sparkline, chunks[1]);\n\n    let line_gauge = LineGauge::default()\n        .block(Block::default().title(\"LineGauge:\"))\n        .gauge_style(Style::default().fg(Color::Magenta))\n        .line_set(if app.enhanced_graphics {\n            symbols::line::THICK\n        } else {\n            symbols::line::NORMAL\n        })\n        .ratio(app.progress);\n    f.render_widget(line_gauge, chunks[2]);\n}\n\nfn draw_charts<B>(f: &mut Frame<B>, app: &mut App, area: Rect)\nwhere\n    B: Backend,\n{\n    let constraints = if app.show_chart {\n        vec![Constraint::Percentage(50), Constraint::Percentage(50)]\n    } else {\n        vec![Constraint::Percentage(100)]\n    };\n    let chunks = Layout::default()\n        .constraints(constraints)\n        .direction(Direction::Horizontal)\n        .split(area);\n    {\n        let chunks = Layout::default()\n            .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())\n            .split(chunks[0]);\n        {\n            let chunks = Layout::default()\n                .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())\n                .direction(Direction::Horizontal)\n                .split(chunks[0]);\n\n            // Draw tasks\n            let tasks: Vec<ListItem> = app\n                .tasks\n                .items\n                .iter()\n                .map(|i| ListItem::new(vec![Spans::from(Span::raw(*i))]))\n                .collect();\n            let tasks = List::new(tasks)\n                .block(Block::default().borders(Borders::ALL).title(\"List\"))\n                .highlight_style(Style::default().add_modifier(Modifier::BOLD))\n                .highlight_symbol(\"> \");\n            f.render_stateful_widget(tasks, chunks[0], &mut app.tasks.state);\n\n            // Draw logs\n            let info_style = Style::default().fg(Color::Blue);\n            let warning_style = Style::default().fg(Color::Yellow);\n            let error_style = Style::default().fg(Color::Magenta);\n            let critical_style = Style::default().fg(Color::Red);\n            let logs: Vec<ListItem> = app\n                .logs\n                .items\n                .iter()\n                .map(|&(evt, level)| {\n                    let s = match level {\n                        \"ERROR\" => error_style,\n                        \"CRITICAL\" => critical_style,\n                        \"WARNING\" => warning_style,\n                        _ => info_style,\n                    };\n                    let content = vec![Spans::from(vec![\n                        Span::styled(format!(\"{:<9}\", level), s),\n                        Span::raw(evt),\n                    ])];\n                    ListItem::new(content)\n                })\n                .collect();\n            let logs = List::new(logs).block(Block::default().borders(Borders::ALL).title(\"List\"));\n            f.render_stateful_widget(logs, chunks[1], &mut app.logs.state);\n        }\n\n        let barchart = BarChart::default()\n            .block(Block::default().borders(Borders::ALL).title(\"Bar chart\"))\n            .data(&app.barchart)\n            .bar_width(3)\n            .bar_gap(2)\n            .bar_set(if app.enhanced_graphics {\n                symbols::bar::NINE_LEVELS\n            } else {\n                symbols::bar::THREE_LEVELS\n            })\n            .value_style(\n                Style::default()\n                    .fg(Color::Black)\n                    .bg(Color::Green)\n                    .add_modifier(Modifier::ITALIC),\n            )\n            .label_style(Style::default().fg(Color::Yellow))\n            .bar_style(Style::default().fg(Color::Green));\n        f.render_widget(barchart, chunks[1]);\n    }\n    if app.show_chart {\n        let x_labels = vec![\n            Span::styled(\n                format!(\"{}\", app.signals.window[0]),\n                Style::default().add_modifier(Modifier::BOLD),\n            ),\n            Span::raw(format!(\n                \"{}\",\n                (app.signals.window[0] + app.signals.window[1]) / 2.0\n            )),\n            Span::styled(\n                format!(\"{}\", app.signals.window[1]),\n                Style::default().add_modifier(Modifier::BOLD),\n            ),\n        ];\n        let datasets = vec![\n            Dataset::default()\n                .name(\"data2\")\n                .marker(symbols::Marker::Dot)\n                .style(Style::default().fg(Color::Cyan))\n                .data(&app.signals.sin1.points),\n            Dataset::default()\n                .name(\"data3\")\n                .marker(if app.enhanced_graphics {\n                    symbols::Marker::Braille\n                } else {\n                    symbols::Marker::Dot\n                })\n                .style(Style::default().fg(Color::Yellow))\n                .data(&app.signals.sin2.points),\n        ];\n        let chart = Chart::new(datasets)\n            .block(\n                Block::default()\n                    .title(Span::styled(\n                        \"Chart\",\n                        Style::default()\n                            .fg(Color::Cyan)\n                            .add_modifier(Modifier::BOLD),\n                    ))\n                    .borders(Borders::ALL),\n            )\n            .x_axis(\n                Axis::default()\n                    .title(\"X Axis\")\n                    .style(Style::default().fg(Color::Gray))\n                    .bounds(app.signals.window)\n                    .labels(x_labels),\n            )\n            .y_axis(\n                Axis::default()\n                    .title(\"Y Axis\")\n                    .style(Style::default().fg(Color::Gray))\n                    .bounds([-20.0, 20.0])\n                    .labels(vec![\n                        Span::styled(\"-20\", Style::default().add_modifier(Modifier::BOLD)),\n                        Span::raw(\"0\"),\n                        Span::styled(\"20\", Style::default().add_modifier(Modifier::BOLD)),\n                    ]),\n            );\n        f.render_widget(chart, chunks[1]);\n    }\n}\n\nfn draw_text<B>(f: &mut Frame<B>, area: Rect)\nwhere\n    B: Backend,\n{\n    let text = vec![\n        Spans::from(\"This is a paragraph with several lines. You can change style your text the way you want\"),\n        Spans::from(\"\"),\n        Spans::from(vec![\n            Span::from(\"For example: \"),\n            Span::styled(\"under\", Style::default().fg(Color::Red)),\n            Span::raw(\" \"),\n            Span::styled(\"the\", Style::default().fg(Color::Green)),\n            Span::raw(\" \"),\n            Span::styled(\"rainbow\", Style::default().fg(Color::Blue)),\n            Span::raw(\".\"),\n        ]),\n        Spans::from(vec![\n            Span::raw(\"Oh and if you didn't \"),\n            Span::styled(\"notice\", Style::default().add_modifier(Modifier::ITALIC)),\n            Span::raw(\" you can \"),\n            Span::styled(\"automatically\", Style::default().add_modifier(Modifier::BOLD)),\n            Span::raw(\" \"),\n            Span::styled(\"wrap\", Style::default().add_modifier(Modifier::REVERSED)),\n            Span::raw(\" your \"),\n            Span::styled(\"text\", Style::default().add_modifier(Modifier::UNDERLINED)),\n            Span::raw(\".\")\n        ]),\n        Spans::from(\n            \"One more thing is that it should display unicode characters: 10€\"\n        ),\n    ];\n    let block = Block::default().borders(Borders::ALL).title(Span::styled(\n        \"Footer\",\n        Style::default()\n            .fg(Color::Magenta)\n            .add_modifier(Modifier::BOLD),\n    ));\n    let paragraph = Paragraph::new(text).block(block).wrap(Wrap { trim: true });\n    f.render_widget(paragraph, area);\n}\n\nfn draw_second_tab<B>(f: &mut Frame<B>, app: &mut App, area: Rect)\nwhere\n    B: Backend,\n{\n    let chunks = Layout::default()\n        .constraints([Constraint::Percentage(30), Constraint::Percentage(70)].as_ref())\n        .direction(Direction::Horizontal)\n        .split(area);\n    let up_style = Style::default().fg(Color::Green);\n    let failure_style = Style::default()\n        .fg(Color::Red)\n        .add_modifier(Modifier::RAPID_BLINK | Modifier::CROSSED_OUT);\n    let rows = app.servers.iter().map(|s| {\n        let style = if s.status == \"Up\" {\n            up_style\n        } else {\n            failure_style\n        };\n        Row::new(vec![s.name, s.location, s.status]).style(style)\n    });\n    let table = Table::new(rows)\n        .header(\n            Row::new(vec![\"Server\", \"Location\", \"Status\"])\n                .style(Style::default().fg(Color::Yellow))\n                .bottom_margin(1),\n        )\n        .block(Block::default().title(\"Servers\").borders(Borders::ALL))\n        .widths(&[\n            Constraint::Length(15),\n            Constraint::Length(15),\n            Constraint::Length(10),\n        ]);\n    f.render_widget(table, chunks[0]);\n\n    let map = Canvas::default()\n        .block(Block::default().title(\"World\").borders(Borders::ALL))\n        .paint(|ctx| {\n            ctx.draw(&Map {\n                color: Color::White,\n                resolution: MapResolution::High,\n            });\n            ctx.layer();\n            ctx.draw(&Rectangle {\n                x: 0.0,\n                y: 30.0,\n                width: 10.0,\n                height: 10.0,\n                color: Color::Yellow,\n            });\n            for (i, s1) in app.servers.iter().enumerate() {\n                for s2 in &app.servers[i + 1..] {\n                    ctx.draw(&Line {\n                        x1: s1.coords.1,\n                        y1: s1.coords.0,\n                        y2: s2.coords.0,\n                        x2: s2.coords.1,\n                        color: Color::Yellow,\n                    });\n                }\n            }\n            for server in &app.servers {\n                let color = if server.status == \"Up\" {\n                    Color::Green\n                } else {\n                    Color::Red\n                };\n                ctx.print(\n                    server.coords.1,\n                    server.coords.0,\n                    Span::styled(\"X\", Style::default().fg(color)),\n                );\n            }\n        })\n        .marker(if app.enhanced_graphics {\n            symbols::Marker::Braille\n        } else {\n            symbols::Marker::Dot\n        })\n        .x_bounds([-180.0, 180.0])\n        .y_bounds([-90.0, 90.0]);\n    f.render_widget(map, chunks[1]);\n}\n\nfn draw_third_tab<B>(f: &mut Frame<B>, _app: &mut App, area: Rect)\nwhere\n    B: Backend,\n{\n    let chunks = Layout::default()\n        .direction(Direction::Horizontal)\n        .constraints([Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)])\n        .split(area);\n    let colors = [\n        Color::Reset,\n        Color::Black,\n        Color::Red,\n        Color::Green,\n        Color::Yellow,\n        Color::Blue,\n        Color::Magenta,\n        Color::Cyan,\n        Color::Gray,\n        Color::DarkGray,\n        Color::LightRed,\n        Color::LightGreen,\n        Color::LightYellow,\n        Color::LightBlue,\n        Color::LightMagenta,\n        Color::LightCyan,\n        Color::White,\n    ];\n    let items: Vec<Row> = colors\n        .iter()\n        .map(|c| {\n            let cells = vec![\n                Cell::from(Span::raw(format!(\"{:?}: \", c))),\n                Cell::from(Span::styled(\"Foreground\", Style::default().fg(*c))),\n                Cell::from(Span::styled(\"Background\", Style::default().bg(*c))),\n            ];\n            Row::new(cells)\n        })\n        .collect();\n    let table = Table::new(items)\n        .block(Block::default().title(\"Colors\").borders(Borders::ALL))\n        .widths(&[\n            Constraint::Ratio(1, 3),\n            Constraint::Ratio(1, 3),\n            Constraint::Ratio(1, 3),\n        ]);\n    f.render_widget(table, chunks[0]);\n}\n"
  },
  {
    "path": "examples/gauge.rs",
    "content": "use crossterm::{\n    event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},\n    execute,\n    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},\n};\nuse std::{\n    error::Error,\n    io,\n    time::{Duration, Instant},\n};\nuse tui::{\n    backend::{Backend, CrosstermBackend},\n    layout::{Constraint, Direction, Layout},\n    style::{Color, Modifier, Style},\n    text::Span,\n    widgets::{Block, Borders, Gauge},\n    Frame, Terminal,\n};\n\nstruct App {\n    progress1: u16,\n    progress2: u16,\n    progress3: f64,\n    progress4: u16,\n}\n\nimpl App {\n    fn new() -> App {\n        App {\n            progress1: 0,\n            progress2: 0,\n            progress3: 0.45,\n            progress4: 0,\n        }\n    }\n\n    fn on_tick(&mut self) {\n        self.progress1 += 1;\n        if self.progress1 > 100 {\n            self.progress1 = 0;\n        }\n        self.progress2 += 2;\n        if self.progress2 > 100 {\n            self.progress2 = 0;\n        }\n        self.progress3 += 0.001;\n        if self.progress3 > 1.0 {\n            self.progress3 = 0.0;\n        }\n        self.progress4 += 1;\n        if self.progress4 > 100 {\n            self.progress4 = 0;\n        }\n    }\n}\n\nfn main() -> Result<(), Box<dyn Error>> {\n    // setup terminal\n    enable_raw_mode()?;\n    let mut stdout = io::stdout();\n    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;\n    let backend = CrosstermBackend::new(stdout);\n    let mut terminal = Terminal::new(backend)?;\n\n    // create app and run it\n    let tick_rate = Duration::from_millis(250);\n    let app = App::new();\n    let res = run_app(&mut terminal, app, tick_rate);\n\n    // restore terminal\n    disable_raw_mode()?;\n    execute!(\n        terminal.backend_mut(),\n        LeaveAlternateScreen,\n        DisableMouseCapture\n    )?;\n    terminal.show_cursor()?;\n\n    if let Err(err) = res {\n        println!(\"{:?}\", err)\n    }\n\n    Ok(())\n}\n\nfn run_app<B: Backend>(\n    terminal: &mut Terminal<B>,\n    mut app: App,\n    tick_rate: Duration,\n) -> io::Result<()> {\n    let mut last_tick = Instant::now();\n    loop {\n        terminal.draw(|f| ui(f, &app))?;\n\n        let timeout = tick_rate\n            .checked_sub(last_tick.elapsed())\n            .unwrap_or_else(|| Duration::from_secs(0));\n        if crossterm::event::poll(timeout)? {\n            if let Event::Key(key) = event::read()? {\n                if let KeyCode::Char('q') = key.code {\n                    return Ok(());\n                }\n            }\n        }\n        if last_tick.elapsed() >= tick_rate {\n            app.on_tick();\n            last_tick = Instant::now();\n        }\n    }\n}\n\nfn ui<B: Backend>(f: &mut Frame<B>, app: &App) {\n    let chunks = Layout::default()\n        .direction(Direction::Vertical)\n        .margin(2)\n        .constraints(\n            [\n                Constraint::Percentage(25),\n                Constraint::Percentage(25),\n                Constraint::Percentage(25),\n                Constraint::Percentage(25),\n            ]\n            .as_ref(),\n        )\n        .split(f.size());\n\n    let gauge = Gauge::default()\n        .block(Block::default().title(\"Gauge1\").borders(Borders::ALL))\n        .gauge_style(Style::default().fg(Color::Yellow))\n        .percent(app.progress1);\n    f.render_widget(gauge, chunks[0]);\n\n    let label = format!(\"{}/100\", app.progress2);\n    let gauge = Gauge::default()\n        .block(Block::default().title(\"Gauge2\").borders(Borders::ALL))\n        .gauge_style(Style::default().fg(Color::Magenta).bg(Color::Green))\n        .percent(app.progress2)\n        .label(label);\n    f.render_widget(gauge, chunks[1]);\n\n    let label = Span::styled(\n        format!(\"{:.2}%\", app.progress3 * 100.0),\n        Style::default()\n            .fg(Color::Red)\n            .add_modifier(Modifier::ITALIC | Modifier::BOLD),\n    );\n    let gauge = Gauge::default()\n        .block(Block::default().title(\"Gauge3\").borders(Borders::ALL))\n        .gauge_style(Style::default().fg(Color::Yellow))\n        .ratio(app.progress3)\n        .label(label)\n        .use_unicode(true);\n    f.render_widget(gauge, chunks[2]);\n\n    let label = format!(\"{}/100\", app.progress2);\n    let gauge = Gauge::default()\n        .block(Block::default().title(\"Gauge4\"))\n        .gauge_style(\n            Style::default()\n                .fg(Color::Cyan)\n                .add_modifier(Modifier::ITALIC),\n        )\n        .percent(app.progress4)\n        .label(label);\n    f.render_widget(gauge, chunks[3]);\n}\n"
  },
  {
    "path": "examples/layout.rs",
    "content": "use crossterm::{\n    event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},\n    execute,\n    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},\n};\nuse std::{error::Error, io};\nuse tui::{\n    backend::{Backend, CrosstermBackend},\n    layout::{Constraint, Direction, Layout},\n    widgets::{Block, Borders},\n    Frame, Terminal,\n};\n\nfn main() -> Result<(), Box<dyn Error>> {\n    // setup terminal\n    enable_raw_mode()?;\n    let mut stdout = io::stdout();\n    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;\n    let backend = CrosstermBackend::new(stdout);\n    let mut terminal = Terminal::new(backend)?;\n\n    // create app and run it\n    let res = run_app(&mut terminal);\n\n    // restore terminal\n    disable_raw_mode()?;\n    execute!(\n        terminal.backend_mut(),\n        LeaveAlternateScreen,\n        DisableMouseCapture\n    )?;\n    terminal.show_cursor()?;\n\n    if let Err(err) = res {\n        println!(\"{:?}\", err)\n    }\n\n    Ok(())\n}\n\nfn run_app<B: Backend>(terminal: &mut Terminal<B>) -> io::Result<()> {\n    loop {\n        terminal.draw(|f| ui(f))?;\n\n        if let Event::Key(key) = event::read()? {\n            if let KeyCode::Char('q') = key.code {\n                return Ok(());\n            }\n        }\n    }\n}\n\nfn ui<B: Backend>(f: &mut Frame<B>) {\n    let chunks = Layout::default()\n        .direction(Direction::Vertical)\n        .constraints(\n            [\n                Constraint::Percentage(10),\n                Constraint::Percentage(80),\n                Constraint::Percentage(10),\n            ]\n            .as_ref(),\n        )\n        .split(f.size());\n\n    let block = Block::default().title(\"Block\").borders(Borders::ALL);\n    f.render_widget(block, chunks[0]);\n    let block = Block::default().title(\"Block 2\").borders(Borders::ALL);\n    f.render_widget(block, chunks[2]);\n}\n"
  },
  {
    "path": "examples/list.rs",
    "content": "use crossterm::{\n    event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},\n    execute,\n    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},\n};\nuse std::{\n    error::Error,\n    io,\n    time::{Duration, Instant},\n};\nuse tui::{\n    backend::{Backend, CrosstermBackend},\n    layout::{Constraint, Corner, Direction, Layout},\n    style::{Color, Modifier, Style},\n    text::{Span, Spans},\n    widgets::{Block, Borders, List, ListItem, ListState},\n    Frame, Terminal,\n};\n\nstruct StatefulList<T> {\n    state: ListState,\n    items: Vec<T>,\n}\n\nimpl<T> StatefulList<T> {\n    fn with_items(items: Vec<T>) -> StatefulList<T> {\n        StatefulList {\n            state: ListState::default(),\n            items,\n        }\n    }\n\n    fn next(&mut self) {\n        let i = match self.state.selected() {\n            Some(i) => {\n                if i >= self.items.len() - 1 {\n                    0\n                } else {\n                    i + 1\n                }\n            }\n            None => 0,\n        };\n        self.state.select(Some(i));\n    }\n\n    fn previous(&mut self) {\n        let i = match self.state.selected() {\n            Some(i) => {\n                if i == 0 {\n                    self.items.len() - 1\n                } else {\n                    i - 1\n                }\n            }\n            None => 0,\n        };\n        self.state.select(Some(i));\n    }\n\n    fn unselect(&mut self) {\n        self.state.select(None);\n    }\n}\n\n/// This struct holds the current state of the app. In particular, it has the `items` field which is a wrapper\n/// around `ListState`. Keeping track of the items state let us render the associated widget with its state\n/// and have access to features such as natural scrolling.\n///\n/// Check the event handling at the bottom to see how to change the state on incoming events.\n/// Check the drawing logic for items on how to specify the highlighting style for selected items.\nstruct App<'a> {\n    items: StatefulList<(&'a str, usize)>,\n    events: Vec<(&'a str, &'a str)>,\n}\n\nimpl<'a> App<'a> {\n    fn new() -> App<'a> {\n        App {\n            items: StatefulList::with_items(vec![\n                (\"Item0\", 1),\n                (\"Item1\", 2),\n                (\"Item2\", 1),\n                (\"Item3\", 3),\n                (\"Item4\", 1),\n                (\"Item5\", 4),\n                (\"Item6\", 1),\n                (\"Item7\", 3),\n                (\"Item8\", 1),\n                (\"Item9\", 6),\n                (\"Item10\", 1),\n                (\"Item11\", 3),\n                (\"Item12\", 1),\n                (\"Item13\", 2),\n                (\"Item14\", 1),\n                (\"Item15\", 1),\n                (\"Item16\", 4),\n                (\"Item17\", 1),\n                (\"Item18\", 5),\n                (\"Item19\", 4),\n                (\"Item20\", 1),\n                (\"Item21\", 2),\n                (\"Item22\", 1),\n                (\"Item23\", 3),\n                (\"Item24\", 1),\n            ]),\n            events: vec![\n                (\"Event1\", \"INFO\"),\n                (\"Event2\", \"INFO\"),\n                (\"Event3\", \"CRITICAL\"),\n                (\"Event4\", \"ERROR\"),\n                (\"Event5\", \"INFO\"),\n                (\"Event6\", \"INFO\"),\n                (\"Event7\", \"WARNING\"),\n                (\"Event8\", \"INFO\"),\n                (\"Event9\", \"INFO\"),\n                (\"Event10\", \"INFO\"),\n                (\"Event11\", \"CRITICAL\"),\n                (\"Event12\", \"INFO\"),\n                (\"Event13\", \"INFO\"),\n                (\"Event14\", \"INFO\"),\n                (\"Event15\", \"INFO\"),\n                (\"Event16\", \"INFO\"),\n                (\"Event17\", \"ERROR\"),\n                (\"Event18\", \"ERROR\"),\n                (\"Event19\", \"INFO\"),\n                (\"Event20\", \"INFO\"),\n                (\"Event21\", \"WARNING\"),\n                (\"Event22\", \"INFO\"),\n                (\"Event23\", \"INFO\"),\n                (\"Event24\", \"WARNING\"),\n                (\"Event25\", \"INFO\"),\n                (\"Event26\", \"INFO\"),\n            ],\n        }\n    }\n\n    /// Rotate through the event list.\n    /// This only exists to simulate some kind of \"progress\"\n    fn on_tick(&mut self) {\n        let event = self.events.remove(0);\n        self.events.push(event);\n    }\n}\n\nfn main() -> Result<(), Box<dyn Error>> {\n    // setup terminal\n    enable_raw_mode()?;\n    let mut stdout = io::stdout();\n    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;\n    let backend = CrosstermBackend::new(stdout);\n    let mut terminal = Terminal::new(backend)?;\n\n    // create app and run it\n    let tick_rate = Duration::from_millis(250);\n    let app = App::new();\n    let res = run_app(&mut terminal, app, tick_rate);\n\n    // restore terminal\n    disable_raw_mode()?;\n    execute!(\n        terminal.backend_mut(),\n        LeaveAlternateScreen,\n        DisableMouseCapture\n    )?;\n    terminal.show_cursor()?;\n\n    if let Err(err) = res {\n        println!(\"{:?}\", err)\n    }\n\n    Ok(())\n}\n\nfn run_app<B: Backend>(\n    terminal: &mut Terminal<B>,\n    mut app: App,\n    tick_rate: Duration,\n) -> io::Result<()> {\n    let mut last_tick = Instant::now();\n    loop {\n        terminal.draw(|f| ui(f, &mut app))?;\n\n        let timeout = tick_rate\n            .checked_sub(last_tick.elapsed())\n            .unwrap_or_else(|| Duration::from_secs(0));\n        if crossterm::event::poll(timeout)? {\n            if let Event::Key(key) = event::read()? {\n                match key.code {\n                    KeyCode::Char('q') => return Ok(()),\n                    KeyCode::Left => app.items.unselect(),\n                    KeyCode::Down => app.items.next(),\n                    KeyCode::Up => app.items.previous(),\n                    _ => {}\n                }\n            }\n        }\n        if last_tick.elapsed() >= tick_rate {\n            app.on_tick();\n            last_tick = Instant::now();\n        }\n    }\n}\n\nfn ui<B: Backend>(f: &mut Frame<B>, app: &mut App) {\n    // Create two chunks with equal horizontal screen space\n    let chunks = Layout::default()\n        .direction(Direction::Horizontal)\n        .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())\n        .split(f.size());\n\n    // Iterate through all elements in the `items` app and append some debug text to it.\n    let items: Vec<ListItem> = app\n        .items\n        .items\n        .iter()\n        .map(|i| {\n            let mut lines = vec![Spans::from(i.0)];\n            for _ in 0..i.1 {\n                lines.push(Spans::from(Span::styled(\n                    \"Lorem ipsum dolor sit amet, consectetur adipiscing elit.\",\n                    Style::default().add_modifier(Modifier::ITALIC),\n                )));\n            }\n            ListItem::new(lines).style(Style::default().fg(Color::Black).bg(Color::White))\n        })\n        .collect();\n\n    // Create a List from all list items and highlight the currently selected one\n    let items = List::new(items)\n        .block(Block::default().borders(Borders::ALL).title(\"List\"))\n        .highlight_style(\n            Style::default()\n                .bg(Color::LightGreen)\n                .add_modifier(Modifier::BOLD),\n        )\n        .highlight_symbol(\">> \");\n\n    // We can now render the item list\n    f.render_stateful_widget(items, chunks[0], &mut app.items.state);\n\n    // Let's do the same for the events.\n    // The event list doesn't have any state and only displays the current state of the list.\n    let events: Vec<ListItem> = app\n        .events\n        .iter()\n        .rev()\n        .map(|&(event, level)| {\n            // Colorcode the level depending on its type\n            let s = match level {\n                \"CRITICAL\" => Style::default().fg(Color::Red),\n                \"ERROR\" => Style::default().fg(Color::Magenta),\n                \"WARNING\" => Style::default().fg(Color::Yellow),\n                \"INFO\" => Style::default().fg(Color::Blue),\n                _ => Style::default(),\n            };\n            // Add a example datetime and apply proper spacing between them\n            let header = Spans::from(vec![\n                Span::styled(format!(\"{:<9}\", level), s),\n                Span::raw(\" \"),\n                Span::styled(\n                    \"2020-01-01 10:00:00\",\n                    Style::default().add_modifier(Modifier::ITALIC),\n                ),\n            ]);\n            // The event gets its own line\n            let log = Spans::from(vec![Span::raw(event)]);\n\n            // Here several things happen:\n            // 1. Add a `---` spacing line above the final list entry\n            // 2. Add the Level + datetime\n            // 3. Add a spacer line\n            // 4. Add the actual event\n            ListItem::new(vec![\n                Spans::from(\"-\".repeat(chunks[1].width as usize)),\n                header,\n                Spans::from(\"\"),\n                log,\n            ])\n        })\n        .collect();\n    let events_list = List::new(events)\n        .block(Block::default().borders(Borders::ALL).title(\"List\"))\n        .start_corner(Corner::BottomLeft);\n    f.render_widget(events_list, chunks[1]);\n}\n"
  },
  {
    "path": "examples/panic.rs",
    "content": "//! How to use a panic hook to reset the terminal before printing the panic to\n//! the terminal.\n//!\n//! When exiting normally or when handling `Result::Err`, we can reset the\n//! terminal manually at the end of `main` just before we print the error.\n//!\n//! Because a panic interrupts the normal control flow, manually resetting the\n//! terminal at the end of `main` won't do us any good. Instead, we need to\n//! make sure to set up a panic hook that first resets the terminal before\n//! handling the panic. This both reuses the standard panic hook to ensure a\n//! consistent panic handling UX and properly resets the terminal to not\n//! distort the output.\n//!\n//! That's why this example is set up to show both situations, with and without\n//! the chained panic hook, to see the difference.\n\n#![deny(clippy::all)]\n#![warn(clippy::pedantic, clippy::nursery)]\n\nuse std::error::Error;\nuse std::io;\n\nuse crossterm::event::{self, Event, KeyCode};\nuse crossterm::terminal::{disable_raw_mode, enable_raw_mode};\nuse crossterm::terminal::{EnterAlternateScreen, LeaveAlternateScreen};\n\nuse tui::backend::{Backend, CrosstermBackend};\nuse tui::layout::Alignment;\nuse tui::text::Spans;\nuse tui::widgets::{Block, Borders, Paragraph};\nuse tui::{Frame, Terminal};\n\ntype Result<T> = std::result::Result<T, Box<dyn Error>>;\n\n#[derive(Default)]\nstruct App {\n    hook_enabled: bool,\n}\n\nimpl App {\n    fn chain_hook(&mut self) {\n        let original_hook = std::panic::take_hook();\n\n        std::panic::set_hook(Box::new(move |panic| {\n            reset_terminal().unwrap();\n            original_hook(panic);\n        }));\n\n        self.hook_enabled = true;\n    }\n}\n\nfn main() -> Result<()> {\n    let mut terminal = init_terminal()?;\n\n    let mut app = App::default();\n    let res = run_tui(&mut terminal, &mut app);\n\n    reset_terminal()?;\n\n    if let Err(err) = res {\n        println!(\"{:?}\", err);\n    }\n\n    Ok(())\n}\n\n/// Initializes the terminal.\nfn init_terminal() -> Result<Terminal<CrosstermBackend<io::Stdout>>> {\n    crossterm::execute!(io::stdout(), EnterAlternateScreen)?;\n    enable_raw_mode()?;\n\n    let backend = CrosstermBackend::new(io::stdout());\n\n    let mut terminal = Terminal::new(backend)?;\n    terminal.hide_cursor()?;\n\n    Ok(terminal)\n}\n\n/// Resets the terminal.\nfn reset_terminal() -> Result<()> {\n    disable_raw_mode()?;\n    crossterm::execute!(io::stdout(), LeaveAlternateScreen)?;\n\n    Ok(())\n}\n\n/// Runs the TUI loop.\nfn run_tui<B: Backend>(terminal: &mut Terminal<B>, app: &mut App) -> io::Result<()> {\n    loop {\n        terminal.draw(|f| ui(f, app))?;\n\n        if let Event::Key(key) = event::read()? {\n            match key.code {\n                KeyCode::Char('p') => {\n                    panic!(\"intentional demo panic\");\n                }\n\n                KeyCode::Char('e') => {\n                    app.chain_hook();\n                }\n\n                _ => {\n                    return Ok(());\n                }\n            }\n        }\n    }\n}\n\n/// Render the TUI.\nfn ui<B: Backend>(f: &mut Frame<B>, app: &App) {\n    let text = vec![\n        if app.hook_enabled {\n            Spans::from(\"HOOK IS CURRENTLY **ENABLED**\")\n        } else {\n            Spans::from(\"HOOK IS CURRENTLY **DISABLED**\")\n        },\n        Spans::from(\"\"),\n        Spans::from(\"press `p` to panic\"),\n        Spans::from(\"press `e` to enable the terminal-resetting panic hook\"),\n        Spans::from(\"press any other key to quit without panic\"),\n        Spans::from(\"\"),\n        Spans::from(\"when you panic without the chained hook,\"),\n        Spans::from(\"you will likely have to reset your terminal afterwards\"),\n        Spans::from(\"with the `reset` command\"),\n        Spans::from(\"\"),\n        Spans::from(\"with the chained panic hook enabled,\"),\n        Spans::from(\"you should see the panic report as you would without tui\"),\n        Spans::from(\"\"),\n        Spans::from(\"try first without the panic handler to see the difference\"),\n    ];\n\n    let b = Block::default()\n        .title(\"Panic Handler Demo\")\n        .borders(Borders::ALL);\n\n    let p = Paragraph::new(text).block(b).alignment(Alignment::Center);\n\n    f.render_widget(p, f.size());\n}\n"
  },
  {
    "path": "examples/paragraph.rs",
    "content": "use crossterm::{\n    event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},\n    execute,\n    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},\n};\nuse std::{\n    error::Error,\n    io,\n    time::{Duration, Instant},\n};\nuse tui::{\n    backend::{Backend, CrosstermBackend},\n    layout::{Alignment, Constraint, Direction, Layout},\n    style::{Color, Modifier, Style},\n    text::{Span, Spans},\n    widgets::{Block, Borders, Paragraph, Wrap},\n    Frame, Terminal,\n};\n\nstruct App {\n    scroll: u16,\n}\n\nimpl App {\n    fn new() -> App {\n        App { scroll: 0 }\n    }\n\n    fn on_tick(&mut self) {\n        self.scroll += 1;\n        self.scroll %= 10;\n    }\n}\n\nfn main() -> Result<(), Box<dyn Error>> {\n    // setup terminal\n    enable_raw_mode()?;\n    let mut stdout = io::stdout();\n    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;\n    let backend = CrosstermBackend::new(stdout);\n    let mut terminal = Terminal::new(backend)?;\n\n    // create app and run it\n    let tick_rate = Duration::from_millis(250);\n    let app = App::new();\n    let res = run_app(&mut terminal, app, tick_rate);\n\n    // restore terminal\n    disable_raw_mode()?;\n    execute!(\n        terminal.backend_mut(),\n        LeaveAlternateScreen,\n        DisableMouseCapture\n    )?;\n    terminal.show_cursor()?;\n\n    if let Err(err) = res {\n        println!(\"{:?}\", err)\n    }\n\n    Ok(())\n}\n\nfn run_app<B: Backend>(\n    terminal: &mut Terminal<B>,\n    mut app: App,\n    tick_rate: Duration,\n) -> io::Result<()> {\n    let mut last_tick = Instant::now();\n    loop {\n        terminal.draw(|f| ui(f, &app))?;\n\n        let timeout = tick_rate\n            .checked_sub(last_tick.elapsed())\n            .unwrap_or_else(|| Duration::from_secs(0));\n        if crossterm::event::poll(timeout)? {\n            if let Event::Key(key) = event::read()? {\n                if let KeyCode::Char('q') = key.code {\n                    return Ok(());\n                }\n            }\n        }\n        if last_tick.elapsed() >= tick_rate {\n            app.on_tick();\n            last_tick = Instant::now();\n        }\n    }\n}\n\nfn ui<B: Backend>(f: &mut Frame<B>, app: &App) {\n    let size = f.size();\n\n    // Words made \"loooong\" to demonstrate line breaking.\n    let s = \"Veeeeeeeeeeeeeeeery    loooooooooooooooooong   striiiiiiiiiiiiiiiiiiiiiiiiiing.   \";\n    let mut long_line = s.repeat(usize::from(size.width) / s.len() + 4);\n    long_line.push('\\n');\n\n    let block = Block::default().style(Style::default().bg(Color::White).fg(Color::Black));\n    f.render_widget(block, size);\n\n    let chunks = Layout::default()\n        .direction(Direction::Vertical)\n        .margin(5)\n        .constraints(\n            [\n                Constraint::Percentage(25),\n                Constraint::Percentage(25),\n                Constraint::Percentage(25),\n                Constraint::Percentage(25),\n            ]\n            .as_ref(),\n        )\n        .split(size);\n\n    let text = vec![\n        Spans::from(\"This is a line \"),\n        Spans::from(Span::styled(\n            \"This is a line   \",\n            Style::default().fg(Color::Red),\n        )),\n        Spans::from(Span::styled(\n            \"This is a line\",\n            Style::default().bg(Color::Blue),\n        )),\n        Spans::from(Span::styled(\n            \"This is a longer line\",\n            Style::default().add_modifier(Modifier::CROSSED_OUT),\n        )),\n        Spans::from(Span::styled(&long_line, Style::default().bg(Color::Green))),\n        Spans::from(Span::styled(\n            \"This is a line\",\n            Style::default()\n                .fg(Color::Green)\n                .add_modifier(Modifier::ITALIC),\n        )),\n    ];\n\n    let create_block = |title| {\n        Block::default()\n            .borders(Borders::ALL)\n            .style(Style::default().bg(Color::White).fg(Color::Black))\n            .title(Span::styled(\n                title,\n                Style::default().add_modifier(Modifier::BOLD),\n            ))\n    };\n    let paragraph = Paragraph::new(text.clone())\n        .style(Style::default().bg(Color::White).fg(Color::Black))\n        .block(create_block(\"Left, no wrap\"))\n        .alignment(Alignment::Left);\n    f.render_widget(paragraph, chunks[0]);\n    let paragraph = Paragraph::new(text.clone())\n        .style(Style::default().bg(Color::White).fg(Color::Black))\n        .block(create_block(\"Left, wrap\"))\n        .alignment(Alignment::Left)\n        .wrap(Wrap { trim: true });\n    f.render_widget(paragraph, chunks[1]);\n    let paragraph = Paragraph::new(text.clone())\n        .style(Style::default().bg(Color::White).fg(Color::Black))\n        .block(create_block(\"Center, wrap\"))\n        .alignment(Alignment::Center)\n        .wrap(Wrap { trim: true })\n        .scroll((app.scroll, 0));\n    f.render_widget(paragraph, chunks[2]);\n    let paragraph = Paragraph::new(text)\n        .style(Style::default().bg(Color::White).fg(Color::Black))\n        .block(create_block(\"Right, wrap\"))\n        .alignment(Alignment::Right)\n        .wrap(Wrap { trim: true });\n    f.render_widget(paragraph, chunks[3]);\n}\n"
  },
  {
    "path": "examples/popup.rs",
    "content": "use std::{error::Error, io};\nuse tui::{\n    backend::{Backend, CrosstermBackend},\n    layout::{Alignment, Constraint, Direction, Layout, Rect},\n    style::{Color, Modifier, Style},\n    text::Span,\n    widgets::{Block, Borders, Clear, Paragraph, Wrap},\n    Frame, Terminal,\n};\n\nuse crossterm::{\n    event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},\n    execute,\n    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},\n};\n\nstruct App {\n    show_popup: bool,\n}\n\nimpl App {\n    fn new() -> App {\n        App { show_popup: false }\n    }\n}\n\nfn main() -> Result<(), Box<dyn Error>> {\n    // setup terminal\n    enable_raw_mode()?;\n    let mut stdout = io::stdout();\n    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;\n    let backend = CrosstermBackend::new(stdout);\n    let mut terminal = Terminal::new(backend)?;\n\n    // create app and run it\n    let app = App::new();\n    let res = run_app(&mut terminal, app);\n\n    // restore terminal\n    disable_raw_mode()?;\n    execute!(\n        terminal.backend_mut(),\n        LeaveAlternateScreen,\n        DisableMouseCapture\n    )?;\n    terminal.show_cursor()?;\n\n    if let Err(err) = res {\n        println!(\"{:?}\", err)\n    }\n\n    Ok(())\n}\n\nfn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Result<()> {\n    loop {\n        terminal.draw(|f| ui(f, &app))?;\n\n        if let Event::Key(key) = event::read()? {\n            match key.code {\n                KeyCode::Char('q') => return Ok(()),\n                KeyCode::Char('p') => app.show_popup = !app.show_popup,\n                _ => {}\n            }\n        }\n    }\n}\n\nfn ui<B: Backend>(f: &mut Frame<B>, app: &App) {\n    let size = f.size();\n\n    let chunks = Layout::default()\n        .constraints([Constraint::Percentage(20), Constraint::Percentage(80)].as_ref())\n        .split(size);\n\n    let text = if app.show_popup {\n        \"Press p to close the popup\"\n    } else {\n        \"Press p to show the popup\"\n    };\n    let paragraph = Paragraph::new(Span::styled(\n        text,\n        Style::default().add_modifier(Modifier::SLOW_BLINK),\n    ))\n    .alignment(Alignment::Center)\n    .wrap(Wrap { trim: true });\n    f.render_widget(paragraph, chunks[0]);\n\n    let block = Block::default()\n        .title(\"Content\")\n        .borders(Borders::ALL)\n        .style(Style::default().bg(Color::Blue));\n    f.render_widget(block, chunks[1]);\n\n    if app.show_popup {\n        let block = Block::default().title(\"Popup\").borders(Borders::ALL);\n        let area = centered_rect(60, 20, size);\n        f.render_widget(Clear, area); //this clears out the background\n        f.render_widget(block, area);\n    }\n}\n\n/// helper function to create a centered rect using up certain percentage of the available rect `r`\nfn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect {\n    let popup_layout = Layout::default()\n        .direction(Direction::Vertical)\n        .constraints(\n            [\n                Constraint::Percentage((100 - percent_y) / 2),\n                Constraint::Percentage(percent_y),\n                Constraint::Percentage((100 - percent_y) / 2),\n            ]\n            .as_ref(),\n        )\n        .split(r);\n\n    Layout::default()\n        .direction(Direction::Horizontal)\n        .constraints(\n            [\n                Constraint::Percentage((100 - percent_x) / 2),\n                Constraint::Percentage(percent_x),\n                Constraint::Percentage((100 - percent_x) / 2),\n            ]\n            .as_ref(),\n        )\n        .split(popup_layout[1])[1]\n}\n"
  },
  {
    "path": "examples/sparkline.rs",
    "content": "use crossterm::{\n    event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},\n    execute,\n    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},\n};\nuse rand::{\n    distributions::{Distribution, Uniform},\n    rngs::ThreadRng,\n};\nuse std::{\n    error::Error,\n    io,\n    time::{Duration, Instant},\n};\nuse tui::{\n    backend::{Backend, CrosstermBackend},\n    layout::{Constraint, Direction, Layout},\n    style::{Color, Style},\n    widgets::{Block, Borders, Sparkline},\n    Frame, Terminal,\n};\n\n#[derive(Clone)]\npub struct RandomSignal {\n    distribution: Uniform<u64>,\n    rng: ThreadRng,\n}\n\nimpl RandomSignal {\n    pub fn new(lower: u64, upper: u64) -> RandomSignal {\n        RandomSignal {\n            distribution: Uniform::new(lower, upper),\n            rng: rand::thread_rng(),\n        }\n    }\n}\n\nimpl Iterator for RandomSignal {\n    type Item = u64;\n    fn next(&mut self) -> Option<u64> {\n        Some(self.distribution.sample(&mut self.rng))\n    }\n}\n\nstruct App {\n    signal: RandomSignal,\n    data1: Vec<u64>,\n    data2: Vec<u64>,\n    data3: Vec<u64>,\n}\n\nimpl App {\n    fn new() -> App {\n        let mut signal = RandomSignal::new(0, 100);\n        let data1 = signal.by_ref().take(200).collect::<Vec<u64>>();\n        let data2 = signal.by_ref().take(200).collect::<Vec<u64>>();\n        let data3 = signal.by_ref().take(200).collect::<Vec<u64>>();\n        App {\n            signal,\n            data1,\n            data2,\n            data3,\n        }\n    }\n\n    fn on_tick(&mut self) {\n        let value = self.signal.next().unwrap();\n        self.data1.pop();\n        self.data1.insert(0, value);\n        let value = self.signal.next().unwrap();\n        self.data2.pop();\n        self.data2.insert(0, value);\n        let value = self.signal.next().unwrap();\n        self.data3.pop();\n        self.data3.insert(0, value);\n    }\n}\n\nfn main() -> Result<(), Box<dyn Error>> {\n    // setup terminal\n    enable_raw_mode()?;\n    let mut stdout = io::stdout();\n    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;\n    let backend = CrosstermBackend::new(stdout);\n    let mut terminal = Terminal::new(backend)?;\n\n    // create app and run it\n    let tick_rate = Duration::from_millis(250);\n    let app = App::new();\n    let res = run_app(&mut terminal, app, tick_rate);\n\n    // restore terminal\n    disable_raw_mode()?;\n    execute!(\n        terminal.backend_mut(),\n        LeaveAlternateScreen,\n        DisableMouseCapture\n    )?;\n    terminal.show_cursor()?;\n\n    if let Err(err) = res {\n        println!(\"{:?}\", err)\n    }\n\n    Ok(())\n}\n\nfn run_app<B: Backend>(\n    terminal: &mut Terminal<B>,\n    mut app: App,\n    tick_rate: Duration,\n) -> io::Result<()> {\n    let mut last_tick = Instant::now();\n    loop {\n        terminal.draw(|f| ui(f, &app))?;\n\n        let timeout = tick_rate\n            .checked_sub(last_tick.elapsed())\n            .unwrap_or_else(|| Duration::from_secs(0));\n        if crossterm::event::poll(timeout)? {\n            if let Event::Key(key) = event::read()? {\n                if let KeyCode::Char('q') = key.code {\n                    return Ok(());\n                }\n            }\n        }\n        if last_tick.elapsed() >= tick_rate {\n            app.on_tick();\n            last_tick = Instant::now();\n        }\n    }\n}\n\nfn ui<B: Backend>(f: &mut Frame<B>, app: &App) {\n    let chunks = Layout::default()\n        .direction(Direction::Vertical)\n        .margin(2)\n        .constraints(\n            [\n                Constraint::Length(3),\n                Constraint::Length(3),\n                Constraint::Length(7),\n                Constraint::Min(0),\n            ]\n            .as_ref(),\n        )\n        .split(f.size());\n    let sparkline = Sparkline::default()\n        .block(\n            Block::default()\n                .title(\"Data1\")\n                .borders(Borders::LEFT | Borders::RIGHT),\n        )\n        .data(&app.data1)\n        .style(Style::default().fg(Color::Yellow));\n    f.render_widget(sparkline, chunks[0]);\n    let sparkline = Sparkline::default()\n        .block(\n            Block::default()\n                .title(\"Data2\")\n                .borders(Borders::LEFT | Borders::RIGHT),\n        )\n        .data(&app.data2)\n        .style(Style::default().bg(Color::Green));\n    f.render_widget(sparkline, chunks[1]);\n    // Multiline\n    let sparkline = Sparkline::default()\n        .block(\n            Block::default()\n                .title(\"Data3\")\n                .borders(Borders::LEFT | Borders::RIGHT),\n        )\n        .data(&app.data3)\n        .style(Style::default().fg(Color::Red));\n    f.render_widget(sparkline, chunks[2]);\n}\n"
  },
  {
    "path": "examples/table.rs",
    "content": "use crossterm::{\n    event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},\n    execute,\n    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},\n};\nuse std::{error::Error, io};\nuse tui::{\n    backend::{Backend, CrosstermBackend},\n    layout::{Constraint, Layout},\n    style::{Color, Modifier, Style},\n    widgets::{Block, Borders, Cell, Row, Table, TableState},\n    Frame, Terminal,\n};\n\nstruct App<'a> {\n    state: TableState,\n    items: Vec<Vec<&'a str>>,\n}\n\nimpl<'a> App<'a> {\n    fn new() -> App<'a> {\n        App {\n            state: TableState::default(),\n            items: vec![\n                vec![\"Row11\", \"Row12\", \"Row13\"],\n                vec![\"Row21\", \"Row22\", \"Row23\"],\n                vec![\"Row31\", \"Row32\", \"Row33\"],\n                vec![\"Row41\", \"Row42\", \"Row43\"],\n                vec![\"Row51\", \"Row52\", \"Row53\"],\n                vec![\"Row61\", \"Row62\\nTest\", \"Row63\"],\n                vec![\"Row71\", \"Row72\", \"Row73\"],\n                vec![\"Row81\", \"Row82\", \"Row83\"],\n                vec![\"Row91\", \"Row92\", \"Row93\"],\n                vec![\"Row101\", \"Row102\", \"Row103\"],\n                vec![\"Row111\", \"Row112\", \"Row113\"],\n                vec![\"Row121\", \"Row122\", \"Row123\"],\n                vec![\"Row131\", \"Row132\", \"Row133\"],\n                vec![\"Row141\", \"Row142\", \"Row143\"],\n                vec![\"Row151\", \"Row152\", \"Row153\"],\n                vec![\"Row161\", \"Row162\", \"Row163\"],\n                vec![\"Row171\", \"Row172\", \"Row173\"],\n                vec![\"Row181\", \"Row182\", \"Row183\"],\n                vec![\"Row191\", \"Row192\", \"Row193\"],\n            ],\n        }\n    }\n    pub fn next(&mut self) {\n        let i = match self.state.selected() {\n            Some(i) => {\n                if i >= self.items.len() - 1 {\n                    0\n                } else {\n                    i + 1\n                }\n            }\n            None => 0,\n        };\n        self.state.select(Some(i));\n    }\n\n    pub fn previous(&mut self) {\n        let i = match self.state.selected() {\n            Some(i) => {\n                if i == 0 {\n                    self.items.len() - 1\n                } else {\n                    i - 1\n                }\n            }\n            None => 0,\n        };\n        self.state.select(Some(i));\n    }\n}\n\nfn main() -> Result<(), Box<dyn Error>> {\n    // setup terminal\n    enable_raw_mode()?;\n    let mut stdout = io::stdout();\n    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;\n    let backend = CrosstermBackend::new(stdout);\n    let mut terminal = Terminal::new(backend)?;\n\n    // create app and run it\n    let app = App::new();\n    let res = run_app(&mut terminal, app);\n\n    // restore terminal\n    disable_raw_mode()?;\n    execute!(\n        terminal.backend_mut(),\n        LeaveAlternateScreen,\n        DisableMouseCapture\n    )?;\n    terminal.show_cursor()?;\n\n    if let Err(err) = res {\n        println!(\"{:?}\", err)\n    }\n\n    Ok(())\n}\n\nfn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Result<()> {\n    loop {\n        terminal.draw(|f| ui(f, &mut app))?;\n\n        if let Event::Key(key) = event::read()? {\n            match key.code {\n                KeyCode::Char('q') => return Ok(()),\n                KeyCode::Down => app.next(),\n                KeyCode::Up => app.previous(),\n                _ => {}\n            }\n        }\n    }\n}\n\nfn ui<B: Backend>(f: &mut Frame<B>, app: &mut App) {\n    let rects = Layout::default()\n        .constraints([Constraint::Percentage(100)].as_ref())\n        .margin(5)\n        .split(f.size());\n\n    let selected_style = Style::default().add_modifier(Modifier::REVERSED);\n    let normal_style = Style::default().bg(Color::Blue);\n    let header_cells = [\"Header1\", \"Header2\", \"Header3\"]\n        .iter()\n        .map(|h| Cell::from(*h).style(Style::default().fg(Color::Red)));\n    let header = Row::new(header_cells)\n        .style(normal_style)\n        .height(1)\n        .bottom_margin(1);\n    let rows = app.items.iter().map(|item| {\n        let height = item\n            .iter()\n            .map(|content| content.chars().filter(|c| *c == '\\n').count())\n            .max()\n            .unwrap_or(0)\n            + 1;\n        let cells = item.iter().map(|c| Cell::from(*c));\n        Row::new(cells).height(height as u16).bottom_margin(1)\n    });\n    let t = Table::new(rows)\n        .header(header)\n        .block(Block::default().borders(Borders::ALL).title(\"Table\"))\n        .highlight_style(selected_style)\n        .highlight_symbol(\">> \")\n        .widths(&[\n            Constraint::Percentage(50),\n            Constraint::Length(30),\n            Constraint::Min(10),\n        ]);\n    f.render_stateful_widget(t, rects[0], &mut app.state);\n}\n"
  },
  {
    "path": "examples/tabs.rs",
    "content": "use crossterm::{\n    event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},\n    execute,\n    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},\n};\nuse std::{error::Error, io};\nuse tui::{\n    backend::{Backend, CrosstermBackend},\n    layout::{Constraint, Direction, Layout},\n    style::{Color, Modifier, Style},\n    text::{Span, Spans},\n    widgets::{Block, Borders, Tabs},\n    Frame, Terminal,\n};\n\nstruct App<'a> {\n    pub titles: Vec<&'a str>,\n    pub index: usize,\n}\n\nimpl<'a> App<'a> {\n    fn new() -> App<'a> {\n        App {\n            titles: vec![\"Tab0\", \"Tab1\", \"Tab2\", \"Tab3\"],\n            index: 0,\n        }\n    }\n\n    pub fn next(&mut self) {\n        self.index = (self.index + 1) % self.titles.len();\n    }\n\n    pub fn previous(&mut self) {\n        if self.index > 0 {\n            self.index -= 1;\n        } else {\n            self.index = self.titles.len() - 1;\n        }\n    }\n}\n\nfn main() -> Result<(), Box<dyn Error>> {\n    // setup terminal\n    enable_raw_mode()?;\n    let mut stdout = io::stdout();\n    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;\n    let backend = CrosstermBackend::new(stdout);\n    let mut terminal = Terminal::new(backend)?;\n\n    // create app and run it\n    let app = App::new();\n    let res = run_app(&mut terminal, app);\n\n    // restore terminal\n    disable_raw_mode()?;\n    execute!(\n        terminal.backend_mut(),\n        LeaveAlternateScreen,\n        DisableMouseCapture\n    )?;\n    terminal.show_cursor()?;\n\n    if let Err(err) = res {\n        println!(\"{:?}\", err)\n    }\n\n    Ok(())\n}\n\nfn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Result<()> {\n    loop {\n        terminal.draw(|f| ui(f, &app))?;\n\n        if let Event::Key(key) = event::read()? {\n            match key.code {\n                KeyCode::Char('q') => return Ok(()),\n                KeyCode::Right => app.next(),\n                KeyCode::Left => app.previous(),\n                _ => {}\n            }\n        }\n    }\n}\n\nfn ui<B: Backend>(f: &mut Frame<B>, app: &App) {\n    let size = f.size();\n    let chunks = Layout::default()\n        .direction(Direction::Vertical)\n        .margin(5)\n        .constraints([Constraint::Length(3), Constraint::Min(0)].as_ref())\n        .split(size);\n\n    let block = Block::default().style(Style::default().bg(Color::White).fg(Color::Black));\n    f.render_widget(block, size);\n    let titles = app\n        .titles\n        .iter()\n        .map(|t| {\n            let (first, rest) = t.split_at(1);\n            Spans::from(vec![\n                Span::styled(first, Style::default().fg(Color::Yellow)),\n                Span::styled(rest, Style::default().fg(Color::Green)),\n            ])\n        })\n        .collect();\n    let tabs = Tabs::new(titles)\n        .block(Block::default().borders(Borders::ALL).title(\"Tabs\"))\n        .select(app.index)\n        .style(Style::default().fg(Color::Cyan))\n        .highlight_style(\n            Style::default()\n                .add_modifier(Modifier::BOLD)\n                .bg(Color::Black),\n        );\n    f.render_widget(tabs, chunks[0]);\n    let inner = match app.index {\n        0 => Block::default().title(\"Inner 0\").borders(Borders::ALL),\n        1 => Block::default().title(\"Inner 1\").borders(Borders::ALL),\n        2 => Block::default().title(\"Inner 2\").borders(Borders::ALL),\n        3 => Block::default().title(\"Inner 3\").borders(Borders::ALL),\n        _ => unreachable!(),\n    };\n    f.render_widget(inner, chunks[1]);\n}\n"
  },
  {
    "path": "examples/user_input.rs",
    "content": "/// A simple example demonstrating how to handle user input. This is\n/// a bit out of the scope of the library as it does not provide any\n/// input handling out of the box. However, it may helps some to get\n/// started.\n///\n/// This is a very simple example:\n///   * A input box always focused. Every character you type is registered\n///   here\n///   * Pressing Backspace erases a character\n///   * Pressing Enter pushes the current input in the history of previous\n///   messages\nuse crossterm::{\n    event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},\n    execute,\n    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},\n};\nuse std::{error::Error, io};\nuse tui::{\n    backend::{Backend, CrosstermBackend},\n    layout::{Constraint, Direction, Layout},\n    style::{Color, Modifier, Style},\n    text::{Span, Spans, Text},\n    widgets::{Block, Borders, List, ListItem, Paragraph},\n    Frame, Terminal,\n};\nuse unicode_width::UnicodeWidthStr;\n\nenum InputMode {\n    Normal,\n    Editing,\n}\n\n/// App holds the state of the application\nstruct App {\n    /// Current value of the input box\n    input: String,\n    /// Current input mode\n    input_mode: InputMode,\n    /// History of recorded messages\n    messages: Vec<String>,\n}\n\nimpl Default for App {\n    fn default() -> App {\n        App {\n            input: String::new(),\n            input_mode: InputMode::Normal,\n            messages: Vec::new(),\n        }\n    }\n}\n\nfn main() -> Result<(), Box<dyn Error>> {\n    // setup terminal\n    enable_raw_mode()?;\n    let mut stdout = io::stdout();\n    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;\n    let backend = CrosstermBackend::new(stdout);\n    let mut terminal = Terminal::new(backend)?;\n\n    // create app and run it\n    let app = App::default();\n    let res = run_app(&mut terminal, app);\n\n    // restore terminal\n    disable_raw_mode()?;\n    execute!(\n        terminal.backend_mut(),\n        LeaveAlternateScreen,\n        DisableMouseCapture\n    )?;\n    terminal.show_cursor()?;\n\n    if let Err(err) = res {\n        println!(\"{:?}\", err)\n    }\n\n    Ok(())\n}\n\nfn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Result<()> {\n    loop {\n        terminal.draw(|f| ui(f, &app))?;\n\n        if let Event::Key(key) = event::read()? {\n            match app.input_mode {\n                InputMode::Normal => match key.code {\n                    KeyCode::Char('e') => {\n                        app.input_mode = InputMode::Editing;\n                    }\n                    KeyCode::Char('q') => {\n                        return Ok(());\n                    }\n                    _ => {}\n                },\n                InputMode::Editing => match key.code {\n                    KeyCode::Enter => {\n                        app.messages.push(app.input.drain(..).collect());\n                    }\n                    KeyCode::Char(c) => {\n                        app.input.push(c);\n                    }\n                    KeyCode::Backspace => {\n                        app.input.pop();\n                    }\n                    KeyCode::Esc => {\n                        app.input_mode = InputMode::Normal;\n                    }\n                    _ => {}\n                },\n            }\n        }\n    }\n}\n\nfn ui<B: Backend>(f: &mut Frame<B>, app: &App) {\n    let chunks = Layout::default()\n        .direction(Direction::Vertical)\n        .margin(2)\n        .constraints(\n            [\n                Constraint::Length(1),\n                Constraint::Length(3),\n                Constraint::Min(1),\n            ]\n            .as_ref(),\n        )\n        .split(f.size());\n\n    let (msg, style) = match app.input_mode {\n        InputMode::Normal => (\n            vec![\n                Span::raw(\"Press \"),\n                Span::styled(\"q\", Style::default().add_modifier(Modifier::BOLD)),\n                Span::raw(\" to exit, \"),\n                Span::styled(\"e\", Style::default().add_modifier(Modifier::BOLD)),\n                Span::raw(\" to start editing.\"),\n            ],\n            Style::default().add_modifier(Modifier::RAPID_BLINK),\n        ),\n        InputMode::Editing => (\n            vec![\n                Span::raw(\"Press \"),\n                Span::styled(\"Esc\", Style::default().add_modifier(Modifier::BOLD)),\n                Span::raw(\" to stop editing, \"),\n                Span::styled(\"Enter\", Style::default().add_modifier(Modifier::BOLD)),\n                Span::raw(\" to record the message\"),\n            ],\n            Style::default(),\n        ),\n    };\n    let mut text = Text::from(Spans::from(msg));\n    text.patch_style(style);\n    let help_message = Paragraph::new(text);\n    f.render_widget(help_message, chunks[0]);\n\n    let input = Paragraph::new(app.input.as_ref())\n        .style(match app.input_mode {\n            InputMode::Normal => Style::default(),\n            InputMode::Editing => Style::default().fg(Color::Yellow),\n        })\n        .block(Block::default().borders(Borders::ALL).title(\"Input\"));\n    f.render_widget(input, chunks[1]);\n    match app.input_mode {\n        InputMode::Normal =>\n            // Hide the cursor. `Frame` does this by default, so we don't need to do anything here\n            {}\n\n        InputMode::Editing => {\n            // Make the cursor visible and ask tui-rs to put it at the specified coordinates after rendering\n            f.set_cursor(\n                // Put cursor past the end of the input text\n                chunks[1].x + app.input.width() as u16 + 1,\n                // Move one line down, from the border to the input line\n                chunks[1].y + 1,\n            )\n        }\n    }\n\n    let messages: Vec<ListItem> = app\n        .messages\n        .iter()\n        .enumerate()\n        .map(|(i, m)| {\n            let content = vec![Spans::from(Span::raw(format!(\"{}: {}\", i, m)))];\n            ListItem::new(content)\n        })\n        .collect();\n    let messages =\n        List::new(messages).block(Block::default().borders(Borders::ALL).title(\"Messages\"));\n    f.render_widget(messages, chunks[2]);\n}\n"
  },
  {
    "path": "src/backend/crossterm.rs",
    "content": "use crate::{\n    backend::Backend,\n    buffer::Cell,\n    layout::Rect,\n    style::{Color, Modifier},\n};\nuse crossterm::{\n    cursor::{Hide, MoveTo, Show},\n    execute, queue,\n    style::{\n        Attribute as CAttribute, Color as CColor, Print, SetAttribute, SetBackgroundColor,\n        SetForegroundColor,\n    },\n    terminal::{self, Clear, ClearType},\n};\nuse std::io::{self, Write};\n\npub struct CrosstermBackend<W: Write> {\n    buffer: W,\n}\n\nimpl<W> CrosstermBackend<W>\nwhere\n    W: Write,\n{\n    pub fn new(buffer: W) -> CrosstermBackend<W> {\n        CrosstermBackend { buffer }\n    }\n}\n\nimpl<W> Write for CrosstermBackend<W>\nwhere\n    W: Write,\n{\n    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {\n        self.buffer.write(buf)\n    }\n\n    fn flush(&mut self) -> io::Result<()> {\n        self.buffer.flush()\n    }\n}\n\nimpl<W> Backend for CrosstermBackend<W>\nwhere\n    W: Write,\n{\n    fn draw<'a, I>(&mut self, content: I) -> io::Result<()>\n    where\n        I: Iterator<Item = (u16, u16, &'a Cell)>,\n    {\n        let mut fg = Color::Reset;\n        let mut bg = Color::Reset;\n        let mut modifier = Modifier::empty();\n        let mut last_pos: Option<(u16, u16)> = None;\n        for (x, y, cell) in content {\n            // Move the cursor if the previous location was not (x - 1, y)\n            if !matches!(last_pos, Some(p) if x == p.0 + 1 && y == p.1) {\n                map_error(queue!(self.buffer, MoveTo(x, y)))?;\n            }\n            last_pos = Some((x, y));\n            if cell.modifier != modifier {\n                let diff = ModifierDiff {\n                    from: modifier,\n                    to: cell.modifier,\n                };\n                diff.queue(&mut self.buffer)?;\n                modifier = cell.modifier;\n            }\n            if cell.fg != fg {\n                let color = CColor::from(cell.fg);\n                map_error(queue!(self.buffer, SetForegroundColor(color)))?;\n                fg = cell.fg;\n            }\n            if cell.bg != bg {\n                let color = CColor::from(cell.bg);\n                map_error(queue!(self.buffer, SetBackgroundColor(color)))?;\n                bg = cell.bg;\n            }\n\n            map_error(queue!(self.buffer, Print(&cell.symbol)))?;\n        }\n\n        map_error(queue!(\n            self.buffer,\n            SetForegroundColor(CColor::Reset),\n            SetBackgroundColor(CColor::Reset),\n            SetAttribute(CAttribute::Reset)\n        ))\n    }\n\n    fn hide_cursor(&mut self) -> io::Result<()> {\n        map_error(execute!(self.buffer, Hide))\n    }\n\n    fn show_cursor(&mut self) -> io::Result<()> {\n        map_error(execute!(self.buffer, Show))\n    }\n\n    fn get_cursor(&mut self) -> io::Result<(u16, u16)> {\n        crossterm::cursor::position()\n            .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))\n    }\n\n    fn set_cursor(&mut self, x: u16, y: u16) -> io::Result<()> {\n        map_error(execute!(self.buffer, MoveTo(x, y)))\n    }\n\n    fn clear(&mut self) -> io::Result<()> {\n        map_error(execute!(self.buffer, Clear(ClearType::All)))\n    }\n\n    fn size(&self) -> io::Result<Rect> {\n        let (width, height) =\n            terminal::size().map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;\n\n        Ok(Rect::new(0, 0, width, height))\n    }\n\n    fn flush(&mut self) -> io::Result<()> {\n        self.buffer.flush()\n    }\n}\n\nfn map_error(error: crossterm::Result<()>) -> io::Result<()> {\n    error.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))\n}\n\nimpl From<Color> for CColor {\n    fn from(color: Color) -> Self {\n        match color {\n            Color::Reset => CColor::Reset,\n            Color::Black => CColor::Black,\n            Color::Red => CColor::DarkRed,\n            Color::Green => CColor::DarkGreen,\n            Color::Yellow => CColor::DarkYellow,\n            Color::Blue => CColor::DarkBlue,\n            Color::Magenta => CColor::DarkMagenta,\n            Color::Cyan => CColor::DarkCyan,\n            Color::Gray => CColor::Grey,\n            Color::DarkGray => CColor::DarkGrey,\n            Color::LightRed => CColor::Red,\n            Color::LightGreen => CColor::Green,\n            Color::LightBlue => CColor::Blue,\n            Color::LightYellow => CColor::Yellow,\n            Color::LightMagenta => CColor::Magenta,\n            Color::LightCyan => CColor::Cyan,\n            Color::White => CColor::White,\n            Color::Indexed(i) => CColor::AnsiValue(i),\n            Color::Rgb(r, g, b) => CColor::Rgb { r, g, b },\n        }\n    }\n}\n\n#[derive(Debug)]\nstruct ModifierDiff {\n    pub from: Modifier,\n    pub to: Modifier,\n}\n\nimpl ModifierDiff {\n    fn queue<W>(&self, mut w: W) -> io::Result<()>\n    where\n        W: io::Write,\n    {\n        //use crossterm::Attribute;\n        let removed = self.from - self.to;\n        if removed.contains(Modifier::REVERSED) {\n            map_error(queue!(w, SetAttribute(CAttribute::NoReverse)))?;\n        }\n        if removed.contains(Modifier::BOLD) {\n            map_error(queue!(w, SetAttribute(CAttribute::NormalIntensity)))?;\n            if self.to.contains(Modifier::DIM) {\n                map_error(queue!(w, SetAttribute(CAttribute::Dim)))?;\n            }\n        }\n        if removed.contains(Modifier::ITALIC) {\n            map_error(queue!(w, SetAttribute(CAttribute::NoItalic)))?;\n        }\n        if removed.contains(Modifier::UNDERLINED) {\n            map_error(queue!(w, SetAttribute(CAttribute::NoUnderline)))?;\n        }\n        if removed.contains(Modifier::DIM) {\n            map_error(queue!(w, SetAttribute(CAttribute::NormalIntensity)))?;\n        }\n        if removed.contains(Modifier::CROSSED_OUT) {\n            map_error(queue!(w, SetAttribute(CAttribute::NotCrossedOut)))?;\n        }\n        if removed.contains(Modifier::SLOW_BLINK) || removed.contains(Modifier::RAPID_BLINK) {\n            map_error(queue!(w, SetAttribute(CAttribute::NoBlink)))?;\n        }\n\n        let added = self.to - self.from;\n        if added.contains(Modifier::REVERSED) {\n            map_error(queue!(w, SetAttribute(CAttribute::Reverse)))?;\n        }\n        if added.contains(Modifier::BOLD) {\n            map_error(queue!(w, SetAttribute(CAttribute::Bold)))?;\n        }\n        if added.contains(Modifier::ITALIC) {\n            map_error(queue!(w, SetAttribute(CAttribute::Italic)))?;\n        }\n        if added.contains(Modifier::UNDERLINED) {\n            map_error(queue!(w, SetAttribute(CAttribute::Underlined)))?;\n        }\n        if added.contains(Modifier::DIM) {\n            map_error(queue!(w, SetAttribute(CAttribute::Dim)))?;\n        }\n        if added.contains(Modifier::CROSSED_OUT) {\n            map_error(queue!(w, SetAttribute(CAttribute::CrossedOut)))?;\n        }\n        if added.contains(Modifier::SLOW_BLINK) {\n            map_error(queue!(w, SetAttribute(CAttribute::SlowBlink)))?;\n        }\n        if added.contains(Modifier::RAPID_BLINK) {\n            map_error(queue!(w, SetAttribute(CAttribute::RapidBlink)))?;\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "src/backend/mod.rs",
    "content": "use std::io;\n\nuse crate::buffer::Cell;\nuse crate::layout::Rect;\n\n#[cfg(feature = \"termion\")]\nmod termion;\n#[cfg(feature = \"termion\")]\npub use self::termion::TermionBackend;\n\n#[cfg(feature = \"crossterm\")]\nmod crossterm;\n#[cfg(feature = \"crossterm\")]\npub use self::crossterm::CrosstermBackend;\n\nmod test;\npub use self::test::TestBackend;\n\npub trait Backend {\n    fn draw<'a, I>(&mut self, content: I) -> Result<(), io::Error>\n    where\n        I: Iterator<Item = (u16, u16, &'a Cell)>;\n    fn hide_cursor(&mut self) -> Result<(), io::Error>;\n    fn show_cursor(&mut self) -> Result<(), io::Error>;\n    fn get_cursor(&mut self) -> Result<(u16, u16), io::Error>;\n    fn set_cursor(&mut self, x: u16, y: u16) -> Result<(), io::Error>;\n    fn clear(&mut self) -> Result<(), io::Error>;\n    fn size(&self) -> Result<Rect, io::Error>;\n    fn flush(&mut self) -> Result<(), io::Error>;\n}\n"
  },
  {
    "path": "src/backend/termion.rs",
    "content": "use super::Backend;\nuse crate::{\n    buffer::Cell,\n    layout::Rect,\n    style::{Color, Modifier},\n};\nuse std::{\n    fmt,\n    io::{self, Write},\n};\n\npub struct TermionBackend<W>\nwhere\n    W: Write,\n{\n    stdout: W,\n}\n\nimpl<W> TermionBackend<W>\nwhere\n    W: Write,\n{\n    pub fn new(stdout: W) -> TermionBackend<W> {\n        TermionBackend { stdout }\n    }\n}\n\nimpl<W> Write for TermionBackend<W>\nwhere\n    W: Write,\n{\n    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {\n        self.stdout.write(buf)\n    }\n\n    fn flush(&mut self) -> io::Result<()> {\n        self.stdout.flush()\n    }\n}\n\nimpl<W> Backend for TermionBackend<W>\nwhere\n    W: Write,\n{\n    /// Clears the entire screen and move the cursor to the top left of the screen\n    fn clear(&mut self) -> io::Result<()> {\n        write!(self.stdout, \"{}\", termion::clear::All)?;\n        write!(self.stdout, \"{}\", termion::cursor::Goto(1, 1))?;\n        self.stdout.flush()\n    }\n\n    /// Hides cursor\n    fn hide_cursor(&mut self) -> io::Result<()> {\n        write!(self.stdout, \"{}\", termion::cursor::Hide)?;\n        self.stdout.flush()\n    }\n\n    /// Shows cursor\n    fn show_cursor(&mut self) -> io::Result<()> {\n        write!(self.stdout, \"{}\", termion::cursor::Show)?;\n        self.stdout.flush()\n    }\n\n    /// Gets cursor position (0-based index)\n    fn get_cursor(&mut self) -> io::Result<(u16, u16)> {\n        termion::cursor::DetectCursorPos::cursor_pos(&mut self.stdout).map(|(x, y)| (x - 1, y - 1))\n    }\n\n    /// Sets cursor position (0-based index)\n    fn set_cursor(&mut self, x: u16, y: u16) -> io::Result<()> {\n        write!(self.stdout, \"{}\", termion::cursor::Goto(x + 1, y + 1))?;\n        self.stdout.flush()\n    }\n\n    fn draw<'a, I>(&mut self, content: I) -> io::Result<()>\n    where\n        I: Iterator<Item = (u16, u16, &'a Cell)>,\n    {\n        use std::fmt::Write;\n\n        let mut string = String::with_capacity(content.size_hint().0 * 3);\n        let mut fg = Color::Reset;\n        let mut bg = Color::Reset;\n        let mut modifier = Modifier::empty();\n        let mut last_pos: Option<(u16, u16)> = None;\n        for (x, y, cell) in content {\n            // Move the cursor if the previous location was not (x - 1, y)\n            if !matches!(last_pos, Some(p) if x == p.0 + 1 && y == p.1) {\n                write!(string, \"{}\", termion::cursor::Goto(x + 1, y + 1)).unwrap();\n            }\n            last_pos = Some((x, y));\n            if cell.modifier != modifier {\n                write!(\n                    string,\n                    \"{}\",\n                    ModifierDiff {\n                        from: modifier,\n                        to: cell.modifier\n                    }\n                )\n                .unwrap();\n                modifier = cell.modifier;\n            }\n            if cell.fg != fg {\n                write!(string, \"{}\", Fg(cell.fg)).unwrap();\n                fg = cell.fg;\n            }\n            if cell.bg != bg {\n                write!(string, \"{}\", Bg(cell.bg)).unwrap();\n                bg = cell.bg;\n            }\n            string.push_str(&cell.symbol);\n        }\n        write!(\n            self.stdout,\n            \"{}{}{}{}\",\n            string,\n            Fg(Color::Reset),\n            Bg(Color::Reset),\n            termion::style::Reset,\n        )\n    }\n\n    /// Return the size of the terminal\n    fn size(&self) -> io::Result<Rect> {\n        let terminal = termion::terminal_size()?;\n        Ok(Rect::new(0, 0, terminal.0, terminal.1))\n    }\n\n    fn flush(&mut self) -> io::Result<()> {\n        self.stdout.flush()\n    }\n}\n\nstruct Fg(Color);\n\nstruct Bg(Color);\n\nstruct ModifierDiff {\n    from: Modifier,\n    to: Modifier,\n}\n\nimpl fmt::Display for Fg {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        use termion::color::Color as TermionColor;\n        match self.0 {\n            Color::Reset => termion::color::Reset.write_fg(f),\n            Color::Black => termion::color::Black.write_fg(f),\n            Color::Red => termion::color::Red.write_fg(f),\n            Color::Green => termion::color::Green.write_fg(f),\n            Color::Yellow => termion::color::Yellow.write_fg(f),\n            Color::Blue => termion::color::Blue.write_fg(f),\n            Color::Magenta => termion::color::Magenta.write_fg(f),\n            Color::Cyan => termion::color::Cyan.write_fg(f),\n            Color::Gray => termion::color::White.write_fg(f),\n            Color::DarkGray => termion::color::LightBlack.write_fg(f),\n            Color::LightRed => termion::color::LightRed.write_fg(f),\n            Color::LightGreen => termion::color::LightGreen.write_fg(f),\n            Color::LightBlue => termion::color::LightBlue.write_fg(f),\n            Color::LightYellow => termion::color::LightYellow.write_fg(f),\n            Color::LightMagenta => termion::color::LightMagenta.write_fg(f),\n            Color::LightCyan => termion::color::LightCyan.write_fg(f),\n            Color::White => termion::color::LightWhite.write_fg(f),\n            Color::Indexed(i) => termion::color::AnsiValue(i).write_fg(f),\n            Color::Rgb(r, g, b) => termion::color::Rgb(r, g, b).write_fg(f),\n        }\n    }\n}\nimpl fmt::Display for Bg {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        use termion::color::Color as TermionColor;\n        match self.0 {\n            Color::Reset => termion::color::Reset.write_bg(f),\n            Color::Black => termion::color::Black.write_bg(f),\n            Color::Red => termion::color::Red.write_bg(f),\n            Color::Green => termion::color::Green.write_bg(f),\n            Color::Yellow => termion::color::Yellow.write_bg(f),\n            Color::Blue => termion::color::Blue.write_bg(f),\n            Color::Magenta => termion::color::Magenta.write_bg(f),\n            Color::Cyan => termion::color::Cyan.write_bg(f),\n            Color::Gray => termion::color::White.write_bg(f),\n            Color::DarkGray => termion::color::LightBlack.write_bg(f),\n            Color::LightRed => termion::color::LightRed.write_bg(f),\n            Color::LightGreen => termion::color::LightGreen.write_bg(f),\n            Color::LightBlue => termion::color::LightBlue.write_bg(f),\n            Color::LightYellow => termion::color::LightYellow.write_bg(f),\n            Color::LightMagenta => termion::color::LightMagenta.write_bg(f),\n            Color::LightCyan => termion::color::LightCyan.write_bg(f),\n            Color::White => termion::color::LightWhite.write_bg(f),\n            Color::Indexed(i) => termion::color::AnsiValue(i).write_bg(f),\n            Color::Rgb(r, g, b) => termion::color::Rgb(r, g, b).write_bg(f),\n        }\n    }\n}\n\nimpl fmt::Display for ModifierDiff {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        let remove = self.from - self.to;\n        if remove.contains(Modifier::REVERSED) {\n            write!(f, \"{}\", termion::style::NoInvert)?;\n        }\n        if remove.contains(Modifier::BOLD) {\n            // XXX: the termion NoBold flag actually enables double-underline on ECMA-48 compliant\n            // terminals, and NoFaint additionally disables bold... so we use this trick to get\n            // the right semantics.\n            write!(f, \"{}\", termion::style::NoFaint)?;\n\n            if self.to.contains(Modifier::DIM) {\n                write!(f, \"{}\", termion::style::Faint)?;\n            }\n        }\n        if remove.contains(Modifier::ITALIC) {\n            write!(f, \"{}\", termion::style::NoItalic)?;\n        }\n        if remove.contains(Modifier::UNDERLINED) {\n            write!(f, \"{}\", termion::style::NoUnderline)?;\n        }\n        if remove.contains(Modifier::DIM) {\n            write!(f, \"{}\", termion::style::NoFaint)?;\n\n            // XXX: the NoFaint flag additionally disables bold as well, so we need to re-enable it\n            // here if we want it.\n            if self.to.contains(Modifier::BOLD) {\n                write!(f, \"{}\", termion::style::Bold)?;\n            }\n        }\n        if remove.contains(Modifier::CROSSED_OUT) {\n            write!(f, \"{}\", termion::style::NoCrossedOut)?;\n        }\n        if remove.contains(Modifier::SLOW_BLINK) || remove.contains(Modifier::RAPID_BLINK) {\n            write!(f, \"{}\", termion::style::NoBlink)?;\n        }\n\n        let add = self.to - self.from;\n        if add.contains(Modifier::REVERSED) {\n            write!(f, \"{}\", termion::style::Invert)?;\n        }\n        if add.contains(Modifier::BOLD) {\n            write!(f, \"{}\", termion::style::Bold)?;\n        }\n        if add.contains(Modifier::ITALIC) {\n            write!(f, \"{}\", termion::style::Italic)?;\n        }\n        if add.contains(Modifier::UNDERLINED) {\n            write!(f, \"{}\", termion::style::Underline)?;\n        }\n        if add.contains(Modifier::DIM) {\n            write!(f, \"{}\", termion::style::Faint)?;\n        }\n        if add.contains(Modifier::CROSSED_OUT) {\n            write!(f, \"{}\", termion::style::CrossedOut)?;\n        }\n        if add.contains(Modifier::SLOW_BLINK) || add.contains(Modifier::RAPID_BLINK) {\n            write!(f, \"{}\", termion::style::Blink)?;\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "src/backend/test.rs",
    "content": "use crate::{\n    backend::Backend,\n    buffer::{Buffer, Cell},\n    layout::Rect,\n};\nuse std::{fmt::Write, io};\nuse unicode_width::UnicodeWidthStr;\n\n/// A backend used for the integration tests.\n#[derive(Debug)]\npub struct TestBackend {\n    width: u16,\n    buffer: Buffer,\n    height: u16,\n    cursor: bool,\n    pos: (u16, u16),\n}\n\n/// Returns a string representation of the given buffer for debugging purpose.\nfn buffer_view(buffer: &Buffer) -> String {\n    let mut view = String::with_capacity(buffer.content.len() + buffer.area.height as usize * 3);\n    for cells in buffer.content.chunks(buffer.area.width as usize) {\n        let mut overwritten = vec![];\n        let mut skip: usize = 0;\n        view.push('\"');\n        for (x, c) in cells.iter().enumerate() {\n            if skip == 0 {\n                view.push_str(&c.symbol);\n            } else {\n                overwritten.push((x, &c.symbol))\n            }\n            skip = std::cmp::max(skip, c.symbol.width()).saturating_sub(1);\n        }\n        view.push('\"');\n        if !overwritten.is_empty() {\n            write!(\n                &mut view,\n                \" Hidden by multi-width symbols: {:?}\",\n                overwritten\n            )\n            .unwrap();\n        }\n        view.push('\\n');\n    }\n    view\n}\n\nimpl TestBackend {\n    pub fn new(width: u16, height: u16) -> TestBackend {\n        TestBackend {\n            width,\n            height,\n            buffer: Buffer::empty(Rect::new(0, 0, width, height)),\n            cursor: false,\n            pos: (0, 0),\n        }\n    }\n\n    pub fn buffer(&self) -> &Buffer {\n        &self.buffer\n    }\n\n    pub fn resize(&mut self, width: u16, height: u16) {\n        self.buffer.resize(Rect::new(0, 0, width, height));\n        self.width = width;\n        self.height = height;\n    }\n\n    pub fn assert_buffer(&self, expected: &Buffer) {\n        assert_eq!(expected.area, self.buffer.area);\n        let diff = expected.diff(&self.buffer);\n        if diff.is_empty() {\n            return;\n        }\n\n        let mut debug_info = String::from(\"Buffers are not equal\");\n        debug_info.push('\\n');\n        debug_info.push_str(\"Expected:\");\n        debug_info.push('\\n');\n        let expected_view = buffer_view(expected);\n        debug_info.push_str(&expected_view);\n        debug_info.push('\\n');\n        debug_info.push_str(\"Got:\");\n        debug_info.push('\\n');\n        let view = buffer_view(&self.buffer);\n        debug_info.push_str(&view);\n        debug_info.push('\\n');\n\n        debug_info.push_str(\"Diff:\");\n        debug_info.push('\\n');\n        let nice_diff = diff\n            .iter()\n            .enumerate()\n            .map(|(i, (x, y, cell))| {\n                let expected_cell = expected.get(*x, *y);\n                format!(\n                    \"{}: at ({}, {}) expected {:?} got {:?}\",\n                    i, x, y, expected_cell, cell\n                )\n            })\n            .collect::<Vec<String>>()\n            .join(\"\\n\");\n        debug_info.push_str(&nice_diff);\n        panic!(\"{}\", debug_info);\n    }\n}\n\nimpl Backend for TestBackend {\n    fn draw<'a, I>(&mut self, content: I) -> Result<(), io::Error>\n    where\n        I: Iterator<Item = (u16, u16, &'a Cell)>,\n    {\n        for (x, y, c) in content {\n            let cell = self.buffer.get_mut(x, y);\n            *cell = c.clone();\n        }\n        Ok(())\n    }\n\n    fn hide_cursor(&mut self) -> Result<(), io::Error> {\n        self.cursor = false;\n        Ok(())\n    }\n\n    fn show_cursor(&mut self) -> Result<(), io::Error> {\n        self.cursor = true;\n        Ok(())\n    }\n\n    fn get_cursor(&mut self) -> Result<(u16, u16), io::Error> {\n        Ok(self.pos)\n    }\n\n    fn set_cursor(&mut self, x: u16, y: u16) -> Result<(), io::Error> {\n        self.pos = (x, y);\n        Ok(())\n    }\n\n    fn clear(&mut self) -> Result<(), io::Error> {\n        self.buffer.reset();\n        Ok(())\n    }\n\n    fn size(&self) -> Result<Rect, io::Error> {\n        Ok(Rect::new(0, 0, self.width, self.height))\n    }\n\n    fn flush(&mut self) -> Result<(), io::Error> {\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "src/buffer.rs",
    "content": "use crate::{\n    layout::Rect,\n    style::{Color, Modifier, Style},\n    text::{Span, Spans},\n};\nuse std::cmp::min;\nuse unicode_segmentation::UnicodeSegmentation;\nuse unicode_width::UnicodeWidthStr;\n\n/// A buffer cell\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct Cell {\n    pub symbol: String,\n    pub fg: Color,\n    pub bg: Color,\n    pub modifier: Modifier,\n}\n\nimpl Cell {\n    pub fn set_symbol(&mut self, symbol: &str) -> &mut Cell {\n        self.symbol.clear();\n        self.symbol.push_str(symbol);\n        self\n    }\n\n    pub fn set_char(&mut self, ch: char) -> &mut Cell {\n        self.symbol.clear();\n        self.symbol.push(ch);\n        self\n    }\n\n    pub fn set_fg(&mut self, color: Color) -> &mut Cell {\n        self.fg = color;\n        self\n    }\n\n    pub fn set_bg(&mut self, color: Color) -> &mut Cell {\n        self.bg = color;\n        self\n    }\n\n    pub fn set_style(&mut self, style: Style) -> &mut Cell {\n        if let Some(c) = style.fg {\n            self.fg = c;\n        }\n        if let Some(c) = style.bg {\n            self.bg = c;\n        }\n        self.modifier.insert(style.add_modifier);\n        self.modifier.remove(style.sub_modifier);\n        self\n    }\n\n    pub fn style(&self) -> Style {\n        Style::default()\n            .fg(self.fg)\n            .bg(self.bg)\n            .add_modifier(self.modifier)\n    }\n\n    pub fn reset(&mut self) {\n        self.symbol.clear();\n        self.symbol.push(' ');\n        self.fg = Color::Reset;\n        self.bg = Color::Reset;\n        self.modifier = Modifier::empty();\n    }\n}\n\nimpl Default for Cell {\n    fn default() -> Cell {\n        Cell {\n            symbol: \" \".into(),\n            fg: Color::Reset,\n            bg: Color::Reset,\n            modifier: Modifier::empty(),\n        }\n    }\n}\n\n/// A buffer that maps to the desired content of the terminal after the draw call\n///\n/// No widget in the library interacts directly with the terminal. Instead each of them is required\n/// to draw their state to an intermediate buffer. It is basically a grid where each cell contains\n/// a grapheme, a foreground color and a background color. This grid will then be used to output\n/// the appropriate escape sequences and characters to draw the UI as the user has defined it.\n///\n/// # Examples:\n///\n/// ```\n/// use tui::buffer::{Buffer, Cell};\n/// use tui::layout::Rect;\n/// use tui::style::{Color, Style, Modifier};\n///\n/// let mut buf = Buffer::empty(Rect{x: 0, y: 0, width: 10, height: 5});\n/// buf.get_mut(0, 2).set_symbol(\"x\");\n/// assert_eq!(buf.get(0, 2).symbol, \"x\");\n/// buf.set_string(3, 0, \"string\", Style::default().fg(Color::Red).bg(Color::White));\n/// assert_eq!(buf.get(5, 0), &Cell{\n///     symbol: String::from(\"r\"),\n///     fg: Color::Red,\n///     bg: Color::White,\n///     modifier: Modifier::empty()\n/// });\n/// buf.get_mut(5, 0).set_char('x');\n/// assert_eq!(buf.get(5, 0).symbol, \"x\");\n/// ```\n#[derive(Debug, Clone, PartialEq, Eq, Default)]\npub struct Buffer {\n    /// The area represented by this buffer\n    pub area: Rect,\n    /// The content of the buffer. The length of this Vec should always be equal to area.width *\n    /// area.height\n    pub content: Vec<Cell>,\n}\n\nimpl Buffer {\n    /// Returns a Buffer with all cells set to the default one\n    pub fn empty(area: Rect) -> Buffer {\n        let cell: Cell = Default::default();\n        Buffer::filled(area, &cell)\n    }\n\n    /// Returns a Buffer with all cells initialized with the attributes of the given Cell\n    pub fn filled(area: Rect, cell: &Cell) -> Buffer {\n        let size = area.area() as usize;\n        let mut content = Vec::with_capacity(size);\n        for _ in 0..size {\n            content.push(cell.clone());\n        }\n        Buffer { area, content }\n    }\n\n    /// Returns a Buffer containing the given lines\n    pub fn with_lines<S>(lines: Vec<S>) -> Buffer\n    where\n        S: AsRef<str>,\n    {\n        let height = lines.len() as u16;\n        let width = lines\n            .iter()\n            .map(|i| i.as_ref().width() as u16)\n            .max()\n            .unwrap_or_default();\n        let mut buffer = Buffer::empty(Rect {\n            x: 0,\n            y: 0,\n            width,\n            height,\n        });\n        for (y, line) in lines.iter().enumerate() {\n            buffer.set_string(0, y as u16, line, Style::default());\n        }\n        buffer\n    }\n\n    /// Returns the content of the buffer as a slice\n    pub fn content(&self) -> &[Cell] {\n        &self.content\n    }\n\n    /// Returns the area covered by this buffer\n    pub fn area(&self) -> &Rect {\n        &self.area\n    }\n\n    /// Returns a reference to Cell at the given coordinates\n    pub fn get(&self, x: u16, y: u16) -> &Cell {\n        let i = self.index_of(x, y);\n        &self.content[i]\n    }\n\n    /// Returns a mutable reference to Cell at the given coordinates\n    pub fn get_mut(&mut self, x: u16, y: u16) -> &mut Cell {\n        let i = self.index_of(x, y);\n        &mut self.content[i]\n    }\n\n    /// Returns the index in the Vec<Cell> for the given global (x, y) coordinates.\n    ///\n    /// Global coordinates are offset by the Buffer's area offset (`x`/`y`).\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tui::buffer::Buffer;\n    /// # use tui::layout::Rect;\n    /// let rect = Rect::new(200, 100, 10, 10);\n    /// let buffer = Buffer::empty(rect);\n    /// // Global coordinates to the top corner of this buffer's area\n    /// assert_eq!(buffer.index_of(200, 100), 0);\n    /// ```\n    ///\n    /// # Panics\n    ///\n    /// Panics when given an coordinate that is outside of this Buffer's area.\n    ///\n    /// ```should_panic\n    /// # use tui::buffer::Buffer;\n    /// # use tui::layout::Rect;\n    /// let rect = Rect::new(200, 100, 10, 10);\n    /// let buffer = Buffer::empty(rect);\n    /// // Top coordinate is outside of the buffer in global coordinate space, as the Buffer's area\n    /// // starts at (200, 100).\n    /// buffer.index_of(0, 0); // Panics\n    /// ```\n    pub fn index_of(&self, x: u16, y: u16) -> usize {\n        debug_assert!(\n            x >= self.area.left()\n                && x < self.area.right()\n                && y >= self.area.top()\n                && y < self.area.bottom(),\n            \"Trying to access position outside the buffer: x={}, y={}, area={:?}\",\n            x,\n            y,\n            self.area\n        );\n        ((y - self.area.y) * self.area.width + (x - self.area.x)) as usize\n    }\n\n    /// Returns the (global) coordinates of a cell given its index\n    ///\n    /// Global coordinates are offset by the Buffer's area offset (`x`/`y`).\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tui::buffer::Buffer;\n    /// # use tui::layout::Rect;\n    /// let rect = Rect::new(200, 100, 10, 10);\n    /// let buffer = Buffer::empty(rect);\n    /// assert_eq!(buffer.pos_of(0), (200, 100));\n    /// assert_eq!(buffer.pos_of(14), (204, 101));\n    /// ```\n    ///\n    /// # Panics\n    ///\n    /// Panics when given an index that is outside the Buffer's content.\n    ///\n    /// ```should_panic\n    /// # use tui::buffer::Buffer;\n    /// # use tui::layout::Rect;\n    /// let rect = Rect::new(0, 0, 10, 10); // 100 cells in total\n    /// let buffer = Buffer::empty(rect);\n    /// // Index 100 is the 101th cell, which lies outside of the area of this Buffer.\n    /// buffer.pos_of(100); // Panics\n    /// ```\n    pub fn pos_of(&self, i: usize) -> (u16, u16) {\n        debug_assert!(\n            i < self.content.len(),\n            \"Trying to get the coords of a cell outside the buffer: i={} len={}\",\n            i,\n            self.content.len()\n        );\n        (\n            self.area.x + i as u16 % self.area.width,\n            self.area.y + i as u16 / self.area.width,\n        )\n    }\n\n    /// Print a string, starting at the position (x, y)\n    pub fn set_string<S>(&mut self, x: u16, y: u16, string: S, style: Style)\n    where\n        S: AsRef<str>,\n    {\n        self.set_stringn(x, y, string, usize::MAX, style);\n    }\n\n    /// Print at most the first n characters of a string if enough space is available\n    /// until the end of the line\n    pub fn set_stringn<S>(\n        &mut self,\n        x: u16,\n        y: u16,\n        string: S,\n        width: usize,\n        style: Style,\n    ) -> (u16, u16)\n    where\n        S: AsRef<str>,\n    {\n        let mut index = self.index_of(x, y);\n        let mut x_offset = x as usize;\n        let graphemes = UnicodeSegmentation::graphemes(string.as_ref(), true);\n        let max_offset = min(self.area.right() as usize, width.saturating_add(x as usize));\n        for s in graphemes {\n            let width = s.width();\n            if width == 0 {\n                continue;\n            }\n            // `x_offset + width > max_offset` could be integer overflow on 32-bit machines if we\n            // change dimenstions to usize or u32 and someone resizes the terminal to 1x2^32.\n            if width > max_offset.saturating_sub(x_offset) {\n                break;\n            }\n\n            self.content[index].set_symbol(s);\n            self.content[index].set_style(style);\n            // Reset following cells if multi-width (they would be hidden by the grapheme),\n            for i in index + 1..index + width {\n                self.content[i].reset();\n            }\n            index += width;\n            x_offset += width;\n        }\n        (x_offset as u16, y)\n    }\n\n    pub fn set_spans<'a>(&mut self, x: u16, y: u16, spans: &Spans<'a>, width: u16) -> (u16, u16) {\n        let mut remaining_width = width;\n        let mut x = x;\n        for span in &spans.0 {\n            if remaining_width == 0 {\n                break;\n            }\n            let pos = self.set_stringn(\n                x,\n                y,\n                span.content.as_ref(),\n                remaining_width as usize,\n                span.style,\n            );\n            let w = pos.0.saturating_sub(x);\n            x = pos.0;\n            remaining_width = remaining_width.saturating_sub(w);\n        }\n        (x, y)\n    }\n\n    pub fn set_span<'a>(&mut self, x: u16, y: u16, span: &Span<'a>, width: u16) -> (u16, u16) {\n        self.set_stringn(x, y, span.content.as_ref(), width as usize, span.style)\n    }\n\n    #[deprecated(\n        since = \"0.10.0\",\n        note = \"You should use styling capabilities of `Buffer::set_style`\"\n    )]\n    pub fn set_background(&mut self, area: Rect, color: Color) {\n        for y in area.top()..area.bottom() {\n            for x in area.left()..area.right() {\n                self.get_mut(x, y).set_bg(color);\n            }\n        }\n    }\n\n    pub fn set_style(&mut self, area: Rect, style: Style) {\n        for y in area.top()..area.bottom() {\n            for x in area.left()..area.right() {\n                self.get_mut(x, y).set_style(style);\n            }\n        }\n    }\n\n    /// Resize the buffer so that the mapped area matches the given area and that the buffer\n    /// length is equal to area.width * area.height\n    pub fn resize(&mut self, area: Rect) {\n        let length = area.area() as usize;\n        if self.content.len() > length {\n            self.content.truncate(length);\n        } else {\n            self.content.resize(length, Default::default());\n        }\n        self.area = area;\n    }\n\n    /// Reset all cells in the buffer\n    pub fn reset(&mut self) {\n        for c in &mut self.content {\n            c.reset();\n        }\n    }\n\n    /// Merge an other buffer into this one\n    pub fn merge(&mut self, other: &Buffer) {\n        let area = self.area.union(other.area);\n        let cell: Cell = Default::default();\n        self.content.resize(area.area() as usize, cell.clone());\n\n        // Move original content to the appropriate space\n        let size = self.area.area() as usize;\n        for i in (0..size).rev() {\n            let (x, y) = self.pos_of(i);\n            // New index in content\n            let k = ((y - area.y) * area.width + x - area.x) as usize;\n            if i != k {\n                self.content[k] = self.content[i].clone();\n                self.content[i] = cell.clone();\n            }\n        }\n\n        // Push content of the other buffer into this one (may erase previous\n        // data)\n        let size = other.area.area() as usize;\n        for i in 0..size {\n            let (x, y) = other.pos_of(i);\n            // New index in content\n            let k = ((y - area.y) * area.width + x - area.x) as usize;\n            self.content[k] = other.content[i].clone();\n        }\n        self.area = area;\n    }\n\n    /// Builds a minimal sequence of coordinates and Cells necessary to update the UI from\n    /// self to other.\n    ///\n    /// We're assuming that buffers are well-formed, that is no double-width cell is followed by\n    /// a non-blank cell.\n    ///\n    /// # Multi-width characters handling:\n    ///\n    /// ```text\n    /// (Index:) `01`\n    /// Prev:    `コ`\n    /// Next:    `aa`\n    /// Updates: `0: a, 1: a'\n    /// ```\n    ///\n    /// ```text\n    /// (Index:) `01`\n    /// Prev:    `a `\n    /// Next:    `コ`\n    /// Updates: `0: コ` (double width symbol at index 0 - skip index 1)\n    /// ```\n    ///\n    /// ```text\n    /// (Index:) `012`\n    /// Prev:    `aaa`\n    /// Next:    `aコ`\n    /// Updates: `0: a, 1: コ` (double width symbol at index 1 - skip index 2)\n    /// ```\n    pub fn diff<'a>(&self, other: &'a Buffer) -> Vec<(u16, u16, &'a Cell)> {\n        let previous_buffer = &self.content;\n        let next_buffer = &other.content;\n        let width = self.area.width;\n\n        let mut updates: Vec<(u16, u16, &Cell)> = vec![];\n        // Cells invalidated by drawing/replacing preceeding multi-width characters:\n        let mut invalidated: usize = 0;\n        // Cells from the current buffer to skip due to preceeding multi-width characters taking their\n        // place (the skipped cells should be blank anyway):\n        let mut to_skip: usize = 0;\n        for (i, (current, previous)) in next_buffer.iter().zip(previous_buffer.iter()).enumerate() {\n            if (current != previous || invalidated > 0) && to_skip == 0 {\n                let x = i as u16 % width;\n                let y = i as u16 / width;\n                updates.push((x, y, &next_buffer[i]));\n            }\n\n            to_skip = current.symbol.width().saturating_sub(1);\n\n            let affected_width = std::cmp::max(current.symbol.width(), previous.symbol.width());\n            invalidated = std::cmp::max(affected_width, invalidated).saturating_sub(1);\n        }\n        updates\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    fn cell(s: &str) -> Cell {\n        let mut cell = Cell::default();\n        cell.set_symbol(s);\n        cell\n    }\n\n    #[test]\n    fn it_translates_to_and_from_coordinates() {\n        let rect = Rect::new(200, 100, 50, 80);\n        let buf = Buffer::empty(rect);\n\n        // First cell is at the upper left corner.\n        assert_eq!(buf.pos_of(0), (200, 100));\n        assert_eq!(buf.index_of(200, 100), 0);\n\n        // Last cell is in the lower right.\n        assert_eq!(buf.pos_of(buf.content.len() - 1), (249, 179));\n        assert_eq!(buf.index_of(249, 179), buf.content.len() - 1);\n    }\n\n    #[test]\n    #[should_panic(expected = \"outside the buffer\")]\n    fn pos_of_panics_on_out_of_bounds() {\n        let rect = Rect::new(0, 0, 10, 10);\n        let buf = Buffer::empty(rect);\n\n        // There are a total of 100 cells; zero-indexed means that 100 would be the 101st cell.\n        buf.pos_of(100);\n    }\n\n    #[test]\n    #[should_panic(expected = \"outside the buffer\")]\n    fn index_of_panics_on_out_of_bounds() {\n        let rect = Rect::new(0, 0, 10, 10);\n        let buf = Buffer::empty(rect);\n\n        // width is 10; zero-indexed means that 10 would be the 11th cell.\n        buf.index_of(10, 0);\n    }\n\n    #[test]\n    fn buffer_set_string() {\n        let area = Rect::new(0, 0, 5, 1);\n        let mut buffer = Buffer::empty(area);\n\n        // Zero-width\n        buffer.set_stringn(0, 0, \"aaa\", 0, Style::default());\n        assert_eq!(buffer, Buffer::with_lines(vec![\"     \"]));\n\n        buffer.set_string(0, 0, \"aaa\", Style::default());\n        assert_eq!(buffer, Buffer::with_lines(vec![\"aaa  \"]));\n\n        // Width limit:\n        buffer.set_stringn(0, 0, \"bbbbbbbbbbbbbb\", 4, Style::default());\n        assert_eq!(buffer, Buffer::with_lines(vec![\"bbbb \"]));\n\n        buffer.set_string(0, 0, \"12345\", Style::default());\n        assert_eq!(buffer, Buffer::with_lines(vec![\"12345\"]));\n\n        // Width truncation:\n        buffer.set_string(0, 0, \"123456\", Style::default());\n        assert_eq!(buffer, Buffer::with_lines(vec![\"12345\"]));\n    }\n\n    #[test]\n    fn buffer_set_string_zero_width() {\n        let area = Rect::new(0, 0, 1, 1);\n        let mut buffer = Buffer::empty(area);\n\n        // Leading grapheme with zero width\n        let s = \"\\u{1}a\";\n        buffer.set_stringn(0, 0, s, 1, Style::default());\n        assert_eq!(buffer, Buffer::with_lines(vec![\"a\"]));\n\n        // Trailing grapheme with zero with\n        let s = \"a\\u{1}\";\n        buffer.set_stringn(0, 0, s, 1, Style::default());\n        assert_eq!(buffer, Buffer::with_lines(vec![\"a\"]));\n    }\n\n    #[test]\n    fn buffer_set_string_double_width() {\n        let area = Rect::new(0, 0, 5, 1);\n        let mut buffer = Buffer::empty(area);\n        buffer.set_string(0, 0, \"コン\", Style::default());\n        assert_eq!(buffer, Buffer::with_lines(vec![\"コン \"]));\n\n        // Only 1 space left.\n        buffer.set_string(0, 0, \"コンピ\", Style::default());\n        assert_eq!(buffer, Buffer::with_lines(vec![\"コン \"]));\n    }\n\n    #[test]\n    fn buffer_with_lines() {\n        let buffer =\n            Buffer::with_lines(vec![\"┌────────┐\", \"│コンピュ│\", \"│ーa 上で│\", \"└────────┘\"]);\n        assert_eq!(buffer.area.x, 0);\n        assert_eq!(buffer.area.y, 0);\n        assert_eq!(buffer.area.width, 10);\n        assert_eq!(buffer.area.height, 4);\n    }\n\n    #[test]\n    fn buffer_diffing_empty_empty() {\n        let area = Rect::new(0, 0, 40, 40);\n        let prev = Buffer::empty(area);\n        let next = Buffer::empty(area);\n        let diff = prev.diff(&next);\n        assert_eq!(diff, vec![]);\n    }\n\n    #[test]\n    fn buffer_diffing_empty_filled() {\n        let area = Rect::new(0, 0, 40, 40);\n        let prev = Buffer::empty(area);\n        let next = Buffer::filled(area, Cell::default().set_symbol(\"a\"));\n        let diff = prev.diff(&next);\n        assert_eq!(diff.len(), 40 * 40);\n    }\n\n    #[test]\n    fn buffer_diffing_filled_filled() {\n        let area = Rect::new(0, 0, 40, 40);\n        let prev = Buffer::filled(area, Cell::default().set_symbol(\"a\"));\n        let next = Buffer::filled(area, Cell::default().set_symbol(\"a\"));\n        let diff = prev.diff(&next);\n        assert_eq!(diff, vec![]);\n    }\n\n    #[test]\n    fn buffer_diffing_single_width() {\n        let prev = Buffer::with_lines(vec![\n            \"          \",\n            \"┌Title─┐  \",\n            \"│      │  \",\n            \"│      │  \",\n            \"└──────┘  \",\n        ]);\n        let next = Buffer::with_lines(vec![\n            \"          \",\n            \"┌TITLE─┐  \",\n            \"│      │  \",\n            \"│      │  \",\n            \"└──────┘  \",\n        ]);\n        let diff = prev.diff(&next);\n        assert_eq!(\n            diff,\n            vec![\n                (2, 1, &cell(\"I\")),\n                (3, 1, &cell(\"T\")),\n                (4, 1, &cell(\"L\")),\n                (5, 1, &cell(\"E\")),\n            ]\n        );\n    }\n\n    #[test]\n    #[rustfmt::skip]\n    fn buffer_diffing_multi_width() {\n        let prev = Buffer::with_lines(vec![\n            \"┌Title─┐  \",\n            \"└──────┘  \",\n        ]);\n        let next = Buffer::with_lines(vec![\n            \"┌称号──┐  \",\n            \"└──────┘  \",\n        ]);\n        let diff = prev.diff(&next);\n        assert_eq!(\n            diff,\n            vec![\n                (1, 0, &cell(\"称\")),\n                // Skipped \"i\"\n                (3, 0, &cell(\"号\")),\n                // Skipped \"l\"\n                (5, 0, &cell(\"─\")),\n            ]\n        );\n    }\n\n    #[test]\n    fn buffer_diffing_multi_width_offset() {\n        let prev = Buffer::with_lines(vec![\"┌称号──┐\"]);\n        let next = Buffer::with_lines(vec![\"┌─称号─┐\"]);\n\n        let diff = prev.diff(&next);\n        assert_eq!(\n            diff,\n            vec![(1, 0, &cell(\"─\")), (2, 0, &cell(\"称\")), (4, 0, &cell(\"号\")),]\n        );\n    }\n\n    #[test]\n    fn buffer_merge() {\n        let mut one = Buffer::filled(\n            Rect {\n                x: 0,\n                y: 0,\n                width: 2,\n                height: 2,\n            },\n            Cell::default().set_symbol(\"1\"),\n        );\n        let two = Buffer::filled(\n            Rect {\n                x: 0,\n                y: 2,\n                width: 2,\n                height: 2,\n            },\n            Cell::default().set_symbol(\"2\"),\n        );\n        one.merge(&two);\n        assert_eq!(one, Buffer::with_lines(vec![\"11\", \"11\", \"22\", \"22\"]));\n    }\n\n    #[test]\n    fn buffer_merge2() {\n        let mut one = Buffer::filled(\n            Rect {\n                x: 2,\n                y: 2,\n                width: 2,\n                height: 2,\n            },\n            Cell::default().set_symbol(\"1\"),\n        );\n        let two = Buffer::filled(\n            Rect {\n                x: 0,\n                y: 0,\n                width: 2,\n                height: 2,\n            },\n            Cell::default().set_symbol(\"2\"),\n        );\n        one.merge(&two);\n        assert_eq!(\n            one,\n            Buffer::with_lines(vec![\"22  \", \"22  \", \"  11\", \"  11\"])\n        );\n    }\n\n    #[test]\n    fn buffer_merge3() {\n        let mut one = Buffer::filled(\n            Rect {\n                x: 3,\n                y: 3,\n                width: 2,\n                height: 2,\n            },\n            Cell::default().set_symbol(\"1\"),\n        );\n        let two = Buffer::filled(\n            Rect {\n                x: 1,\n                y: 1,\n                width: 3,\n                height: 4,\n            },\n            Cell::default().set_symbol(\"2\"),\n        );\n        one.merge(&two);\n        let mut merged = Buffer::with_lines(vec![\"222 \", \"222 \", \"2221\", \"2221\"]);\n        merged.area = Rect {\n            x: 1,\n            y: 1,\n            width: 4,\n            height: 4,\n        };\n        assert_eq!(one, merged);\n    }\n}\n"
  },
  {
    "path": "src/layout.rs",
    "content": "use std::cell::RefCell;\nuse std::cmp::{max, min};\nuse std::collections::HashMap;\n\nuse cassowary::strength::{REQUIRED, WEAK};\nuse cassowary::WeightedRelation::*;\nuse cassowary::{Constraint as CassowaryConstraint, Expression, Solver, Variable};\n\n#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]\npub enum Corner {\n    TopLeft,\n    TopRight,\n    BottomRight,\n    BottomLeft,\n}\n\n#[derive(Debug, Hash, Clone, PartialEq, Eq)]\npub enum Direction {\n    Horizontal,\n    Vertical,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\npub enum Constraint {\n    // TODO: enforce range 0 - 100\n    Percentage(u16),\n    Ratio(u32, u32),\n    Length(u16),\n    Max(u16),\n    Min(u16),\n}\n\nimpl Constraint {\n    pub fn apply(&self, length: u16) -> u16 {\n        match *self {\n            Constraint::Percentage(p) => length * p / 100,\n            Constraint::Ratio(num, den) => {\n                let r = num * u32::from(length) / den;\n                r as u16\n            }\n            Constraint::Length(l) => length.min(l),\n            Constraint::Max(m) => length.min(m),\n            Constraint::Min(m) => length.max(m),\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Hash)]\npub struct Margin {\n    pub vertical: u16,\n    pub horizontal: u16,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Alignment {\n    Left,\n    Center,\n    Right,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Hash)]\npub struct Layout {\n    direction: Direction,\n    margin: Margin,\n    constraints: Vec<Constraint>,\n    /// Whether the last chunk of the computed layout should be expanded to fill the available\n    /// space.\n    expand_to_fill: bool,\n}\n\nthread_local! {\n    static LAYOUT_CACHE: RefCell<HashMap<(Rect, Layout), Vec<Rect>>> = RefCell::new(HashMap::new());\n}\n\nimpl Default for Layout {\n    fn default() -> Layout {\n        Layout {\n            direction: Direction::Vertical,\n            margin: Margin {\n                horizontal: 0,\n                vertical: 0,\n            },\n            constraints: Vec::new(),\n            expand_to_fill: true,\n        }\n    }\n}\n\nimpl Layout {\n    pub fn constraints<C>(mut self, constraints: C) -> Layout\n    where\n        C: Into<Vec<Constraint>>,\n    {\n        self.constraints = constraints.into();\n        self\n    }\n\n    pub fn margin(mut self, margin: u16) -> Layout {\n        self.margin = Margin {\n            horizontal: margin,\n            vertical: margin,\n        };\n        self\n    }\n\n    pub fn horizontal_margin(mut self, horizontal: u16) -> Layout {\n        self.margin.horizontal = horizontal;\n        self\n    }\n\n    pub fn vertical_margin(mut self, vertical: u16) -> Layout {\n        self.margin.vertical = vertical;\n        self\n    }\n\n    pub fn direction(mut self, direction: Direction) -> Layout {\n        self.direction = direction;\n        self\n    }\n\n    pub(crate) fn expand_to_fill(mut self, expand_to_fill: bool) -> Layout {\n        self.expand_to_fill = expand_to_fill;\n        self\n    }\n\n    /// Wrapper function around the cassowary-rs solver to be able to split a given\n    /// area into smaller ones based on the preferred widths or heights and the direction.\n    ///\n    /// # Examples\n    /// ```\n    /// # use tui::layout::{Rect, Constraint, Direction, Layout};\n    /// let chunks = Layout::default()\n    ///     .direction(Direction::Vertical)\n    ///     .constraints([Constraint::Length(5), Constraint::Min(0)].as_ref())\n    ///     .split(Rect {\n    ///         x: 2,\n    ///         y: 2,\n    ///         width: 10,\n    ///         height: 10,\n    ///     });\n    /// assert_eq!(\n    ///     chunks,\n    ///     vec![\n    ///         Rect {\n    ///             x: 2,\n    ///             y: 2,\n    ///             width: 10,\n    ///             height: 5\n    ///         },\n    ///         Rect {\n    ///             x: 2,\n    ///             y: 7,\n    ///             width: 10,\n    ///             height: 5\n    ///         }\n    ///     ]\n    /// );\n    ///\n    /// let chunks = Layout::default()\n    ///     .direction(Direction::Horizontal)\n    ///     .constraints([Constraint::Ratio(1, 3), Constraint::Ratio(2, 3)].as_ref())\n    ///     .split(Rect {\n    ///         x: 0,\n    ///         y: 0,\n    ///         width: 9,\n    ///         height: 2,\n    ///     });\n    /// assert_eq!(\n    ///     chunks,\n    ///     vec![\n    ///         Rect {\n    ///             x: 0,\n    ///             y: 0,\n    ///             width: 3,\n    ///             height: 2\n    ///         },\n    ///         Rect {\n    ///             x: 3,\n    ///             y: 0,\n    ///             width: 6,\n    ///             height: 2\n    ///         }\n    ///     ]\n    /// );\n    /// ```\n    pub fn split(&self, area: Rect) -> Vec<Rect> {\n        // TODO: Maybe use a fixed size cache ?\n        LAYOUT_CACHE.with(|c| {\n            c.borrow_mut()\n                .entry((area, self.clone()))\n                .or_insert_with(|| split(area, self))\n                .clone()\n        })\n    }\n}\n\nfn split(area: Rect, layout: &Layout) -> Vec<Rect> {\n    let mut solver = Solver::new();\n    let mut vars: HashMap<Variable, (usize, usize)> = HashMap::new();\n    let elements = layout\n        .constraints\n        .iter()\n        .map(|_| Element::new())\n        .collect::<Vec<Element>>();\n    let mut results = layout\n        .constraints\n        .iter()\n        .map(|_| Rect::default())\n        .collect::<Vec<Rect>>();\n\n    let dest_area = area.inner(&layout.margin);\n    for (i, e) in elements.iter().enumerate() {\n        vars.insert(e.x, (i, 0));\n        vars.insert(e.y, (i, 1));\n        vars.insert(e.width, (i, 2));\n        vars.insert(e.height, (i, 3));\n    }\n    let mut ccs: Vec<CassowaryConstraint> =\n        Vec::with_capacity(elements.len() * 4 + layout.constraints.len() * 6);\n    for elt in &elements {\n        ccs.push(elt.width | GE(REQUIRED) | 0f64);\n        ccs.push(elt.height | GE(REQUIRED) | 0f64);\n        ccs.push(elt.left() | GE(REQUIRED) | f64::from(dest_area.left()));\n        ccs.push(elt.top() | GE(REQUIRED) | f64::from(dest_area.top()));\n        ccs.push(elt.right() | LE(REQUIRED) | f64::from(dest_area.right()));\n        ccs.push(elt.bottom() | LE(REQUIRED) | f64::from(dest_area.bottom()));\n    }\n    if let Some(first) = elements.first() {\n        ccs.push(match layout.direction {\n            Direction::Horizontal => first.left() | EQ(REQUIRED) | f64::from(dest_area.left()),\n            Direction::Vertical => first.top() | EQ(REQUIRED) | f64::from(dest_area.top()),\n        });\n    }\n    if layout.expand_to_fill {\n        if let Some(last) = elements.last() {\n            ccs.push(match layout.direction {\n                Direction::Horizontal => last.right() | EQ(REQUIRED) | f64::from(dest_area.right()),\n                Direction::Vertical => last.bottom() | EQ(REQUIRED) | f64::from(dest_area.bottom()),\n            });\n        }\n    }\n    match layout.direction {\n        Direction::Horizontal => {\n            for pair in elements.windows(2) {\n                ccs.push((pair[0].x + pair[0].width) | EQ(REQUIRED) | pair[1].x);\n            }\n            for (i, size) in layout.constraints.iter().enumerate() {\n                ccs.push(elements[i].y | EQ(REQUIRED) | f64::from(dest_area.y));\n                ccs.push(elements[i].height | EQ(REQUIRED) | f64::from(dest_area.height));\n                ccs.push(match *size {\n                    Constraint::Length(v) => elements[i].width | EQ(WEAK) | f64::from(v),\n                    Constraint::Percentage(v) => {\n                        elements[i].width | EQ(WEAK) | (f64::from(v * dest_area.width) / 100.0)\n                    }\n                    Constraint::Ratio(n, d) => {\n                        elements[i].width\n                            | EQ(WEAK)\n                            | (f64::from(dest_area.width) * f64::from(n) / f64::from(d))\n                    }\n                    Constraint::Min(v) => elements[i].width | GE(WEAK) | f64::from(v),\n                    Constraint::Max(v) => elements[i].width | LE(WEAK) | f64::from(v),\n                });\n            }\n        }\n        Direction::Vertical => {\n            for pair in elements.windows(2) {\n                ccs.push((pair[0].y + pair[0].height) | EQ(REQUIRED) | pair[1].y);\n            }\n            for (i, size) in layout.constraints.iter().enumerate() {\n                ccs.push(elements[i].x | EQ(REQUIRED) | f64::from(dest_area.x));\n                ccs.push(elements[i].width | EQ(REQUIRED) | f64::from(dest_area.width));\n                ccs.push(match *size {\n                    Constraint::Length(v) => elements[i].height | EQ(WEAK) | f64::from(v),\n                    Constraint::Percentage(v) => {\n                        elements[i].height | EQ(WEAK) | (f64::from(v * dest_area.height) / 100.0)\n                    }\n                    Constraint::Ratio(n, d) => {\n                        elements[i].height\n                            | EQ(WEAK)\n                            | (f64::from(dest_area.height) * f64::from(n) / f64::from(d))\n                    }\n                    Constraint::Min(v) => elements[i].height | GE(WEAK) | f64::from(v),\n                    Constraint::Max(v) => elements[i].height | LE(WEAK) | f64::from(v),\n                });\n            }\n        }\n    }\n    solver.add_constraints(&ccs).unwrap();\n    for &(var, value) in solver.fetch_changes() {\n        let (index, attr) = vars[&var];\n        let value = if value.is_sign_negative() {\n            0\n        } else {\n            value as u16\n        };\n        match attr {\n            0 => {\n                results[index].x = value;\n            }\n            1 => {\n                results[index].y = value;\n            }\n            2 => {\n                results[index].width = value;\n            }\n            3 => {\n                results[index].height = value;\n            }\n            _ => {}\n        }\n    }\n\n    if layout.expand_to_fill {\n        // Fix imprecision by extending the last item a bit if necessary\n        if let Some(last) = results.last_mut() {\n            match layout.direction {\n                Direction::Vertical => {\n                    last.height = dest_area.bottom() - last.y;\n                }\n                Direction::Horizontal => {\n                    last.width = dest_area.right() - last.x;\n                }\n            }\n        }\n    }\n    results\n}\n\n/// A container used by the solver inside split\nstruct Element {\n    x: Variable,\n    y: Variable,\n    width: Variable,\n    height: Variable,\n}\n\nimpl Element {\n    fn new() -> Element {\n        Element {\n            x: Variable::new(),\n            y: Variable::new(),\n            width: Variable::new(),\n            height: Variable::new(),\n        }\n    }\n\n    fn left(&self) -> Variable {\n        self.x\n    }\n\n    fn top(&self) -> Variable {\n        self.y\n    }\n\n    fn right(&self) -> Expression {\n        self.x + self.width\n    }\n\n    fn bottom(&self) -> Expression {\n        self.y + self.height\n    }\n}\n\n/// A simple rectangle used in the computation of the layout and to give widgets a hint about the\n/// area they are supposed to render to.\n#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Default)]\npub struct Rect {\n    pub x: u16,\n    pub y: u16,\n    pub width: u16,\n    pub height: u16,\n}\n\nimpl Rect {\n    /// Creates a new rect, with width and height limited to keep the area under max u16.\n    /// If clipped, aspect ratio will be preserved.\n    pub fn new(x: u16, y: u16, width: u16, height: u16) -> Rect {\n        let max_area = u16::max_value();\n        let (clipped_width, clipped_height) =\n            if u32::from(width) * u32::from(height) > u32::from(max_area) {\n                let aspect_ratio = f64::from(width) / f64::from(height);\n                let max_area_f = f64::from(max_area);\n                let height_f = (max_area_f / aspect_ratio).sqrt();\n                let width_f = height_f * aspect_ratio;\n                (width_f as u16, height_f as u16)\n            } else {\n                (width, height)\n            };\n        Rect {\n            x,\n            y,\n            width: clipped_width,\n            height: clipped_height,\n        }\n    }\n\n    pub fn area(self) -> u16 {\n        self.width * self.height\n    }\n\n    pub fn left(self) -> u16 {\n        self.x\n    }\n\n    pub fn right(self) -> u16 {\n        self.x.saturating_add(self.width)\n    }\n\n    pub fn top(self) -> u16 {\n        self.y\n    }\n\n    pub fn bottom(self) -> u16 {\n        self.y.saturating_add(self.height)\n    }\n\n    pub fn inner(self, margin: &Margin) -> Rect {\n        if self.width < 2 * margin.horizontal || self.height < 2 * margin.vertical {\n            Rect::default()\n        } else {\n            Rect {\n                x: self.x + margin.horizontal,\n                y: self.y + margin.vertical,\n                width: self.width - 2 * margin.horizontal,\n                height: self.height - 2 * margin.vertical,\n            }\n        }\n    }\n\n    pub fn union(self, other: Rect) -> Rect {\n        let x1 = min(self.x, other.x);\n        let y1 = min(self.y, other.y);\n        let x2 = max(self.x + self.width, other.x + other.width);\n        let y2 = max(self.y + self.height, other.y + other.height);\n        Rect {\n            x: x1,\n            y: y1,\n            width: x2 - x1,\n            height: y2 - y1,\n        }\n    }\n\n    pub fn intersection(self, other: Rect) -> Rect {\n        let x1 = max(self.x, other.x);\n        let y1 = max(self.y, other.y);\n        let x2 = min(self.x + self.width, other.x + other.width);\n        let y2 = min(self.y + self.height, other.y + other.height);\n        Rect {\n            x: x1,\n            y: y1,\n            width: x2 - x1,\n            height: y2 - y1,\n        }\n    }\n\n    pub fn intersects(self, other: Rect) -> bool {\n        self.x < other.x + other.width\n            && self.x + self.width > other.x\n            && self.y < other.y + other.height\n            && self.y + self.height > other.y\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_vertical_split_by_height() {\n        let target = Rect {\n            x: 2,\n            y: 2,\n            width: 10,\n            height: 10,\n        };\n\n        let chunks = Layout::default()\n            .direction(Direction::Vertical)\n            .constraints(\n                [\n                    Constraint::Percentage(10),\n                    Constraint::Max(5),\n                    Constraint::Min(1),\n                ]\n                .as_ref(),\n            )\n            .split(target);\n\n        assert_eq!(target.height, chunks.iter().map(|r| r.height).sum::<u16>());\n        chunks.windows(2).for_each(|w| assert!(w[0].y <= w[1].y));\n    }\n\n    #[test]\n    fn test_rect_size_truncation() {\n        for width in 256u16..300u16 {\n            for height in 256u16..300u16 {\n                let rect = Rect::new(0, 0, width, height);\n                rect.area(); // Should not panic.\n                assert!(rect.width < width || rect.height < height);\n                // The target dimensions are rounded down so the math will not be too precise\n                // but let's make sure the ratios don't diverge crazily.\n                assert!(\n                    (f64::from(rect.width) / f64::from(rect.height)\n                        - f64::from(width) / f64::from(height))\n                    .abs()\n                        < 1.0\n                )\n            }\n        }\n\n        // One dimension below 255, one above. Area above max u16.\n        let width = 900;\n        let height = 100;\n        let rect = Rect::new(0, 0, width, height);\n        assert_ne!(rect.width, 900);\n        assert_ne!(rect.height, 100);\n        assert!(rect.width < width || rect.height < height);\n    }\n\n    #[test]\n    fn test_rect_size_preservation() {\n        for width in 0..256u16 {\n            for height in 0..256u16 {\n                let rect = Rect::new(0, 0, width, height);\n                rect.area(); // Should not panic.\n                assert_eq!(rect.width, width);\n                assert_eq!(rect.height, height);\n            }\n        }\n\n        // One dimension below 255, one above. Area below max u16.\n        let rect = Rect::new(0, 0, 300, 100);\n        assert_eq!(rect.width, 300);\n        assert_eq!(rect.height, 100);\n    }\n}\n"
  },
  {
    "path": "src/lib.rs",
    "content": "//! [tui](https://github.com/fdehau/tui-rs) is a library used to build rich\n//! terminal users interfaces and dashboards.\n//!\n//! ![](https://raw.githubusercontent.com/fdehau/tui-rs/master/assets/demo.gif)\n//!\n//! # Get started\n//!\n//! ## Adding `tui` as a dependency\n//!\n//! ```toml\n//! [dependencies]\n//! tui = \"0.19\"\n//! crossterm = \"0.25\"\n//! ```\n//!\n//! The crate is using the `crossterm` backend by default that works on most platforms. But if for\n//! example you want to use the `termion` backend instead. This can be done by changing your\n//! dependencies specification to the following:\n//!\n//! ```toml\n//! [dependencies]\n//! termion = \"1.5\"\n//! tui = { version = \"0.19\", default-features = false, features = ['termion'] }\n//!\n//! ```\n//!\n//! The same logic applies for all other available backends.\n//!\n//! ## Creating a `Terminal`\n//!\n//! Every application using `tui` should start by instantiating a `Terminal`. It is a light\n//! abstraction over available backends that provides basic functionalities such as clearing the\n//! screen, hiding the cursor, etc.\n//!\n//! ```rust,no_run\n//! use std::io;\n//! use tui::{backend::CrosstermBackend, Terminal};\n//!\n//! fn main() -> Result<(), io::Error> {\n//!     let stdout = io::stdout();\n//!     let backend = CrosstermBackend::new(stdout);\n//!     let mut terminal = Terminal::new(backend)?;\n//!     Ok(())\n//! }\n//! ```\n//!\n//! If you had previously chosen `termion` as a backend, the terminal can be created in a similar\n//! way:\n//!\n//! ```rust,ignore\n//! use std::io;\n//! use tui::{backend::TermionBackend, Terminal};\n//! use termion::raw::IntoRawMode;\n//!\n//! fn main() -> Result<(), io::Error> {\n//!     let stdout = io::stdout().into_raw_mode()?;\n//!     let backend = TermionBackend::new(stdout);\n//!     let mut terminal = Terminal::new(backend)?;\n//!     Ok(())\n//! }\n//! ```\n//!\n//! You may also refer to the examples to find out how to create a `Terminal` for each available\n//! backend.\n//!\n//! ## Building a User Interface (UI)\n//!\n//! Every component of your interface will be implementing the `Widget` trait. The library comes\n//! with a predefined set of widgets that should meet most of your use cases. You are also free to\n//! implement your own.\n//!\n//! Each widget follows a builder pattern API providing a default configuration along with methods\n//! to customize them. The widget is then rendered using [`Frame::render_widget`] which takes\n//! your widget instance and an area to draw to.\n//!\n//! The following example renders a block of the size of the terminal:\n//!\n//! ```rust,no_run\n//! use std::{io, thread, time::Duration};\n//! use tui::{\n//!     backend::CrosstermBackend,\n//!     widgets::{Widget, Block, Borders},\n//!     layout::{Layout, Constraint, Direction},\n//!     Terminal\n//! };\n//! use crossterm::{\n//!     event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},\n//!     execute,\n//!     terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},\n//! };\n//!\n//! fn main() -> Result<(), io::Error> {\n//!     // setup terminal\n//!     enable_raw_mode()?;\n//!     let mut stdout = io::stdout();\n//!     execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;\n//!     let backend = CrosstermBackend::new(stdout);\n//!     let mut terminal = Terminal::new(backend)?;\n//!\n//!     terminal.draw(|f| {\n//!         let size = f.size();\n//!         let block = Block::default()\n//!             .title(\"Block\")\n//!             .borders(Borders::ALL);\n//!         f.render_widget(block, size);\n//!     })?;\n//!\n//!     thread::sleep(Duration::from_millis(5000));\n//!\n//!     // restore terminal\n//!     disable_raw_mode()?;\n//!     execute!(\n//!         terminal.backend_mut(),\n//!         LeaveAlternateScreen,\n//!         DisableMouseCapture\n//!     )?;\n//!     terminal.show_cursor()?;\n//!\n//!     Ok(())\n//! }\n//! ```\n//!\n//! ## Layout\n//!\n//! The library comes with a basic yet useful layout management object called `Layout`. As you may\n//! see below and in the examples, the library makes heavy use of the builder pattern to provide\n//! full customization. And `Layout` is no exception:\n//!\n//! ```rust,no_run\n//! use tui::{\n//!     backend::Backend,\n//!     layout::{Constraint, Direction, Layout},\n//!     widgets::{Block, Borders},\n//!     Frame,\n//! };\n//! fn ui<B: Backend>(f: &mut Frame<B>) {\n//!    let chunks = Layout::default()\n//!         .direction(Direction::Vertical)\n//!         .margin(1)\n//!         .constraints(\n//!             [\n//!                 Constraint::Percentage(10),\n//!                 Constraint::Percentage(80),\n//!                 Constraint::Percentage(10)\n//!             ].as_ref()\n//!         )\n//!         .split(f.size());\n//!     let block = Block::default()\n//!          .title(\"Block\")\n//!          .borders(Borders::ALL);\n//!     f.render_widget(block, chunks[0]);\n//!     let block = Block::default()\n//!          .title(\"Block 2\")\n//!          .borders(Borders::ALL);\n//!     f.render_widget(block, chunks[1]);\n//! }\n//! ```\n//!\n//! This let you describe responsive terminal UI by nesting layouts. You should note that by\n//! default the computed layout tries to fill the available space completely. So if for any reason\n//! you might need a blank space somewhere, try to pass an additional constraint and don't use the\n//! corresponding area.\n\npub mod backend;\npub mod buffer;\npub mod layout;\npub mod style;\npub mod symbols;\npub mod terminal;\npub mod text;\npub mod widgets;\n\npub use self::terminal::{Frame, Terminal, TerminalOptions, Viewport};\n"
  },
  {
    "path": "src/style.rs",
    "content": "//! `style` contains the primitives used to control how your user interface will look.\n\nuse bitflags::bitflags;\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\n#[cfg_attr(feature = \"serde\", derive(serde::Serialize, serde::Deserialize))]\npub enum Color {\n    Reset,\n    Black,\n    Red,\n    Green,\n    Yellow,\n    Blue,\n    Magenta,\n    Cyan,\n    Gray,\n    DarkGray,\n    LightRed,\n    LightGreen,\n    LightYellow,\n    LightBlue,\n    LightMagenta,\n    LightCyan,\n    White,\n    Rgb(u8, u8, u8),\n    Indexed(u8),\n}\n\nbitflags! {\n    /// Modifier changes the way a piece of text is displayed.\n    ///\n    /// They are bitflags so they can easily be composed.\n    ///\n    /// ## Examples\n    ///\n    /// ```rust\n    /// # use tui::style::Modifier;\n    ///\n    /// let m = Modifier::BOLD | Modifier::ITALIC;\n    /// ```\n    #[cfg_attr(feature = \"serde\", derive(serde::Serialize, serde::Deserialize))]\n    pub struct Modifier: u16 {\n        const BOLD              = 0b0000_0000_0001;\n        const DIM               = 0b0000_0000_0010;\n        const ITALIC            = 0b0000_0000_0100;\n        const UNDERLINED        = 0b0000_0000_1000;\n        const SLOW_BLINK        = 0b0000_0001_0000;\n        const RAPID_BLINK       = 0b0000_0010_0000;\n        const REVERSED          = 0b0000_0100_0000;\n        const HIDDEN            = 0b0000_1000_0000;\n        const CROSSED_OUT       = 0b0001_0000_0000;\n    }\n}\n\n/// Style let you control the main characteristics of the displayed elements.\n///\n/// ```rust\n/// # use tui::style::{Color, Modifier, Style};\n/// Style::default()\n///     .fg(Color::Black)\n///     .bg(Color::Green)\n///     .add_modifier(Modifier::ITALIC | Modifier::BOLD);\n/// ```\n///\n/// It represents an incremental change. If you apply the styles S1, S2, S3 to a cell of the\n/// terminal buffer, the style of this cell will be the result of the merge of S1, S2 and S3, not\n/// just S3.\n///\n/// ```rust\n/// # use tui::style::{Color, Modifier, Style};\n/// # use tui::buffer::Buffer;\n/// # use tui::layout::Rect;\n/// let styles = [\n///     Style::default().fg(Color::Blue).add_modifier(Modifier::BOLD | Modifier::ITALIC),\n///     Style::default().bg(Color::Red),\n///     Style::default().fg(Color::Yellow).remove_modifier(Modifier::ITALIC),\n/// ];\n/// let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1));\n/// for style in &styles {\n///   buffer.get_mut(0, 0).set_style(*style);\n/// }\n/// assert_eq!(\n///     Style {\n///         fg: Some(Color::Yellow),\n///         bg: Some(Color::Red),\n///         add_modifier: Modifier::BOLD,\n///         sub_modifier: Modifier::empty(),\n///     },\n///     buffer.get(0, 0).style(),\n/// );\n/// ```\n///\n/// The default implementation returns a `Style` that does not modify anything. If you wish to\n/// reset all properties until that point use [`Style::reset`].\n///\n/// ```\n/// # use tui::style::{Color, Modifier, Style};\n/// # use tui::buffer::Buffer;\n/// # use tui::layout::Rect;\n/// let styles = [\n///     Style::default().fg(Color::Blue).add_modifier(Modifier::BOLD | Modifier::ITALIC),\n///     Style::reset().fg(Color::Yellow),\n/// ];\n/// let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1));\n/// for style in &styles {\n///   buffer.get_mut(0, 0).set_style(*style);\n/// }\n/// assert_eq!(\n///     Style {\n///         fg: Some(Color::Yellow),\n///         bg: Some(Color::Reset),\n///         add_modifier: Modifier::empty(),\n///         sub_modifier: Modifier::empty(),\n///     },\n///     buffer.get(0, 0).style(),\n/// );\n/// ```\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\n#[cfg_attr(feature = \"serde\", derive(serde::Serialize, serde::Deserialize))]\npub struct Style {\n    pub fg: Option<Color>,\n    pub bg: Option<Color>,\n    pub add_modifier: Modifier,\n    pub sub_modifier: Modifier,\n}\n\nimpl Default for Style {\n    fn default() -> Style {\n        Style {\n            fg: None,\n            bg: None,\n            add_modifier: Modifier::empty(),\n            sub_modifier: Modifier::empty(),\n        }\n    }\n}\n\nimpl Style {\n    /// Returns a `Style` resetting all properties.\n    pub fn reset() -> Style {\n        Style {\n            fg: Some(Color::Reset),\n            bg: Some(Color::Reset),\n            add_modifier: Modifier::empty(),\n            sub_modifier: Modifier::all(),\n        }\n    }\n\n    /// Changes the foreground color.\n    ///\n    /// ## Examples\n    ///\n    /// ```rust\n    /// # use tui::style::{Color, Style};\n    /// let style = Style::default().fg(Color::Blue);\n    /// let diff = Style::default().fg(Color::Red);\n    /// assert_eq!(style.patch(diff), Style::default().fg(Color::Red));\n    /// ```\n    pub fn fg(mut self, color: Color) -> Style {\n        self.fg = Some(color);\n        self\n    }\n\n    /// Changes the background color.\n    ///\n    /// ## Examples\n    ///\n    /// ```rust\n    /// # use tui::style::{Color, Style};\n    /// let style = Style::default().bg(Color::Blue);\n    /// let diff = Style::default().bg(Color::Red);\n    /// assert_eq!(style.patch(diff), Style::default().bg(Color::Red));\n    /// ```\n    pub fn bg(mut self, color: Color) -> Style {\n        self.bg = Some(color);\n        self\n    }\n\n    /// Changes the text emphasis.\n    ///\n    /// When applied, it adds the given modifier to the `Style` modifiers.\n    ///\n    /// ## Examples\n    ///\n    /// ```rust\n    /// # use tui::style::{Color, Modifier, Style};\n    /// let style = Style::default().add_modifier(Modifier::BOLD);\n    /// let diff = Style::default().add_modifier(Modifier::ITALIC);\n    /// let patched = style.patch(diff);\n    /// assert_eq!(patched.add_modifier, Modifier::BOLD | Modifier::ITALIC);\n    /// assert_eq!(patched.sub_modifier, Modifier::empty());\n    /// ```\n    pub fn add_modifier(mut self, modifier: Modifier) -> Style {\n        self.sub_modifier.remove(modifier);\n        self.add_modifier.insert(modifier);\n        self\n    }\n\n    /// Changes the text emphasis.\n    ///\n    /// When applied, it removes the given modifier from the `Style` modifiers.\n    ///\n    /// ## Examples\n    ///\n    /// ```rust\n    /// # use tui::style::{Color, Modifier, Style};\n    /// let style = Style::default().add_modifier(Modifier::BOLD | Modifier::ITALIC);\n    /// let diff = Style::default().remove_modifier(Modifier::ITALIC);\n    /// let patched = style.patch(diff);\n    /// assert_eq!(patched.add_modifier, Modifier::BOLD);\n    /// assert_eq!(patched.sub_modifier, Modifier::ITALIC);\n    /// ```\n    pub fn remove_modifier(mut self, modifier: Modifier) -> Style {\n        self.add_modifier.remove(modifier);\n        self.sub_modifier.insert(modifier);\n        self\n    }\n\n    /// Results in a combined style that is equivalent to applying the two individual styles to\n    /// a style one after the other.\n    ///\n    /// ## Examples\n    /// ```\n    /// # use tui::style::{Color, Modifier, Style};\n    /// let style_1 = Style::default().fg(Color::Yellow);\n    /// let style_2 = Style::default().bg(Color::Red);\n    /// let combined = style_1.patch(style_2);\n    /// assert_eq!(\n    ///     Style::default().patch(style_1).patch(style_2),\n    ///     Style::default().patch(combined));\n    /// ```\n    pub fn patch(mut self, other: Style) -> Style {\n        self.fg = other.fg.or(self.fg);\n        self.bg = other.bg.or(self.bg);\n\n        self.add_modifier.remove(other.sub_modifier);\n        self.add_modifier.insert(other.add_modifier);\n        self.sub_modifier.remove(other.add_modifier);\n        self.sub_modifier.insert(other.sub_modifier);\n\n        self\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    fn styles() -> Vec<Style> {\n        vec![\n            Style::default(),\n            Style::default().fg(Color::Yellow),\n            Style::default().bg(Color::Yellow),\n            Style::default().add_modifier(Modifier::BOLD),\n            Style::default().remove_modifier(Modifier::BOLD),\n            Style::default().add_modifier(Modifier::ITALIC),\n            Style::default().remove_modifier(Modifier::ITALIC),\n            Style::default().add_modifier(Modifier::ITALIC | Modifier::BOLD),\n            Style::default().remove_modifier(Modifier::ITALIC | Modifier::BOLD),\n        ]\n    }\n\n    #[test]\n    fn combined_patch_gives_same_result_as_individual_patch() {\n        let styles = styles();\n        for &a in &styles {\n            for &b in &styles {\n                for &c in &styles {\n                    for &d in &styles {\n                        let combined = a.patch(b.patch(c.patch(d)));\n\n                        assert_eq!(\n                            Style::default().patch(a).patch(b).patch(c).patch(d),\n                            Style::default().patch(combined)\n                        );\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/symbols.rs",
    "content": "pub mod block {\n    pub const FULL: &str = \"█\";\n    pub const SEVEN_EIGHTHS: &str = \"▉\";\n    pub const THREE_QUARTERS: &str = \"▊\";\n    pub const FIVE_EIGHTHS: &str = \"▋\";\n    pub const HALF: &str = \"▌\";\n    pub const THREE_EIGHTHS: &str = \"▍\";\n    pub const ONE_QUARTER: &str = \"▎\";\n    pub const ONE_EIGHTH: &str = \"▏\";\n\n    #[derive(Debug, Clone)]\n    pub struct Set {\n        pub full: &'static str,\n        pub seven_eighths: &'static str,\n        pub three_quarters: &'static str,\n        pub five_eighths: &'static str,\n        pub half: &'static str,\n        pub three_eighths: &'static str,\n        pub one_quarter: &'static str,\n        pub one_eighth: &'static str,\n        pub empty: &'static str,\n    }\n\n    pub const THREE_LEVELS: Set = Set {\n        full: FULL,\n        seven_eighths: FULL,\n        three_quarters: HALF,\n        five_eighths: HALF,\n        half: HALF,\n        three_eighths: HALF,\n        one_quarter: HALF,\n        one_eighth: \" \",\n        empty: \" \",\n    };\n\n    pub const NINE_LEVELS: Set = Set {\n        full: FULL,\n        seven_eighths: SEVEN_EIGHTHS,\n        three_quarters: THREE_QUARTERS,\n        five_eighths: FIVE_EIGHTHS,\n        half: HALF,\n        three_eighths: THREE_EIGHTHS,\n        one_quarter: ONE_QUARTER,\n        one_eighth: ONE_EIGHTH,\n        empty: \" \",\n    };\n}\n\npub mod bar {\n    pub const FULL: &str = \"█\";\n    pub const SEVEN_EIGHTHS: &str = \"▇\";\n    pub const THREE_QUARTERS: &str = \"▆\";\n    pub const FIVE_EIGHTHS: &str = \"▅\";\n    pub const HALF: &str = \"▄\";\n    pub const THREE_EIGHTHS: &str = \"▃\";\n    pub const ONE_QUARTER: &str = \"▂\";\n    pub const ONE_EIGHTH: &str = \"▁\";\n\n    #[derive(Debug, Clone)]\n    pub struct Set {\n        pub full: &'static str,\n        pub seven_eighths: &'static str,\n        pub three_quarters: &'static str,\n        pub five_eighths: &'static str,\n        pub half: &'static str,\n        pub three_eighths: &'static str,\n        pub one_quarter: &'static str,\n        pub one_eighth: &'static str,\n        pub empty: &'static str,\n    }\n\n    pub const THREE_LEVELS: Set = Set {\n        full: FULL,\n        seven_eighths: FULL,\n        three_quarters: HALF,\n        five_eighths: HALF,\n        half: HALF,\n        three_eighths: HALF,\n        one_quarter: HALF,\n        one_eighth: \" \",\n        empty: \" \",\n    };\n\n    pub const NINE_LEVELS: Set = Set {\n        full: FULL,\n        seven_eighths: SEVEN_EIGHTHS,\n        three_quarters: THREE_QUARTERS,\n        five_eighths: FIVE_EIGHTHS,\n        half: HALF,\n        three_eighths: THREE_EIGHTHS,\n        one_quarter: ONE_QUARTER,\n        one_eighth: ONE_EIGHTH,\n        empty: \" \",\n    };\n}\n\npub mod line {\n    pub const VERTICAL: &str = \"│\";\n    pub const DOUBLE_VERTICAL: &str = \"║\";\n    pub const THICK_VERTICAL: &str = \"┃\";\n\n    pub const HORIZONTAL: &str = \"─\";\n    pub const DOUBLE_HORIZONTAL: &str = \"═\";\n    pub const THICK_HORIZONTAL: &str = \"━\";\n\n    pub const TOP_RIGHT: &str = \"┐\";\n    pub const ROUNDED_TOP_RIGHT: &str = \"╮\";\n    pub const DOUBLE_TOP_RIGHT: &str = \"╗\";\n    pub const THICK_TOP_RIGHT: &str = \"┓\";\n\n    pub const TOP_LEFT: &str = \"┌\";\n    pub const ROUNDED_TOP_LEFT: &str = \"╭\";\n    pub const DOUBLE_TOP_LEFT: &str = \"╔\";\n    pub const THICK_TOP_LEFT: &str = \"┏\";\n\n    pub const BOTTOM_RIGHT: &str = \"┘\";\n    pub const ROUNDED_BOTTOM_RIGHT: &str = \"╯\";\n    pub const DOUBLE_BOTTOM_RIGHT: &str = \"╝\";\n    pub const THICK_BOTTOM_RIGHT: &str = \"┛\";\n\n    pub const BOTTOM_LEFT: &str = \"└\";\n    pub const ROUNDED_BOTTOM_LEFT: &str = \"╰\";\n    pub const DOUBLE_BOTTOM_LEFT: &str = \"╚\";\n    pub const THICK_BOTTOM_LEFT: &str = \"┗\";\n\n    pub const VERTICAL_LEFT: &str = \"┤\";\n    pub const DOUBLE_VERTICAL_LEFT: &str = \"╣\";\n    pub const THICK_VERTICAL_LEFT: &str = \"┫\";\n\n    pub const VERTICAL_RIGHT: &str = \"├\";\n    pub const DOUBLE_VERTICAL_RIGHT: &str = \"╠\";\n    pub const THICK_VERTICAL_RIGHT: &str = \"┣\";\n\n    pub const HORIZONTAL_DOWN: &str = \"┬\";\n    pub const DOUBLE_HORIZONTAL_DOWN: &str = \"╦\";\n    pub const THICK_HORIZONTAL_DOWN: &str = \"┳\";\n\n    pub const HORIZONTAL_UP: &str = \"┴\";\n    pub const DOUBLE_HORIZONTAL_UP: &str = \"╩\";\n    pub const THICK_HORIZONTAL_UP: &str = \"┻\";\n\n    pub const CROSS: &str = \"┼\";\n    pub const DOUBLE_CROSS: &str = \"╬\";\n    pub const THICK_CROSS: &str = \"╋\";\n\n    #[derive(Debug, Clone)]\n    pub struct Set {\n        pub vertical: &'static str,\n        pub horizontal: &'static str,\n        pub top_right: &'static str,\n        pub top_left: &'static str,\n        pub bottom_right: &'static str,\n        pub bottom_left: &'static str,\n        pub vertical_left: &'static str,\n        pub vertical_right: &'static str,\n        pub horizontal_down: &'static str,\n        pub horizontal_up: &'static str,\n        pub cross: &'static str,\n    }\n\n    pub const NORMAL: Set = Set {\n        vertical: VERTICAL,\n        horizontal: HORIZONTAL,\n        top_right: TOP_RIGHT,\n        top_left: TOP_LEFT,\n        bottom_right: BOTTOM_RIGHT,\n        bottom_left: BOTTOM_LEFT,\n        vertical_left: VERTICAL_LEFT,\n        vertical_right: VERTICAL_RIGHT,\n        horizontal_down: HORIZONTAL_DOWN,\n        horizontal_up: HORIZONTAL_UP,\n        cross: CROSS,\n    };\n\n    pub const ROUNDED: Set = Set {\n        top_right: ROUNDED_TOP_RIGHT,\n        top_left: ROUNDED_TOP_LEFT,\n        bottom_right: ROUNDED_BOTTOM_RIGHT,\n        bottom_left: ROUNDED_BOTTOM_LEFT,\n        ..NORMAL\n    };\n\n    pub const DOUBLE: Set = Set {\n        vertical: DOUBLE_VERTICAL,\n        horizontal: DOUBLE_HORIZONTAL,\n        top_right: DOUBLE_TOP_RIGHT,\n        top_left: DOUBLE_TOP_LEFT,\n        bottom_right: DOUBLE_BOTTOM_RIGHT,\n        bottom_left: DOUBLE_BOTTOM_LEFT,\n        vertical_left: DOUBLE_VERTICAL_LEFT,\n        vertical_right: DOUBLE_VERTICAL_RIGHT,\n        horizontal_down: DOUBLE_HORIZONTAL_DOWN,\n        horizontal_up: DOUBLE_HORIZONTAL_UP,\n        cross: DOUBLE_CROSS,\n    };\n\n    pub const THICK: Set = Set {\n        vertical: THICK_VERTICAL,\n        horizontal: THICK_HORIZONTAL,\n        top_right: THICK_TOP_RIGHT,\n        top_left: THICK_TOP_LEFT,\n        bottom_right: THICK_BOTTOM_RIGHT,\n        bottom_left: THICK_BOTTOM_LEFT,\n        vertical_left: THICK_VERTICAL_LEFT,\n        vertical_right: THICK_VERTICAL_RIGHT,\n        horizontal_down: THICK_HORIZONTAL_DOWN,\n        horizontal_up: THICK_HORIZONTAL_UP,\n        cross: THICK_CROSS,\n    };\n}\n\npub const DOT: &str = \"•\";\n\npub mod braille {\n    pub const BLANK: u16 = 0x2800;\n    pub const DOTS: [[u16; 2]; 4] = [\n        [0x0001, 0x0008],\n        [0x0002, 0x0010],\n        [0x0004, 0x0020],\n        [0x0040, 0x0080],\n    ];\n}\n\n/// Marker to use when plotting data points\n#[derive(Debug, Clone, Copy)]\npub enum Marker {\n    /// One point per cell in shape of dot\n    Dot,\n    /// One point per cell in shape of a block\n    Block,\n    /// Up to 8 points per cell\n    Braille,\n}\n"
  },
  {
    "path": "src/terminal.rs",
    "content": "use crate::{\n    backend::Backend,\n    buffer::Buffer,\n    layout::Rect,\n    widgets::{StatefulWidget, Widget},\n};\nuse std::io;\n\n#[derive(Debug, Clone, PartialEq)]\n/// UNSTABLE\nenum ResizeBehavior {\n    Fixed,\n    Auto,\n}\n\n#[derive(Debug, Clone, PartialEq)]\n/// UNSTABLE\npub struct Viewport {\n    area: Rect,\n    resize_behavior: ResizeBehavior,\n}\n\nimpl Viewport {\n    /// UNSTABLE\n    pub fn fixed(area: Rect) -> Viewport {\n        Viewport {\n            area,\n            resize_behavior: ResizeBehavior::Fixed,\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq)]\n/// Options to pass to [`Terminal::with_options`]\npub struct TerminalOptions {\n    /// Viewport used to draw to the terminal\n    pub viewport: Viewport,\n}\n\n/// Interface to the terminal backed by Termion\n#[derive(Debug)]\npub struct Terminal<B>\nwhere\n    B: Backend,\n{\n    backend: B,\n    /// Holds the results of the current and previous draw calls. The two are compared at the end\n    /// of each draw pass to output the necessary updates to the terminal\n    buffers: [Buffer; 2],\n    /// Index of the current buffer in the previous array\n    current: usize,\n    /// Whether the cursor is currently hidden\n    hidden_cursor: bool,\n    /// Viewport\n    viewport: Viewport,\n}\n\n/// Represents a consistent terminal interface for rendering.\npub struct Frame<'a, B: 'a>\nwhere\n    B: Backend,\n{\n    terminal: &'a mut Terminal<B>,\n\n    /// Where should the cursor be after drawing this frame?\n    ///\n    /// If `None`, the cursor is hidden and its position is controlled by the backend. If `Some((x,\n    /// y))`, the cursor is shown and placed at `(x, y)` after the call to `Terminal::draw()`.\n    cursor_position: Option<(u16, u16)>,\n}\n\nimpl<'a, B> Frame<'a, B>\nwhere\n    B: Backend,\n{\n    /// Terminal size, guaranteed not to change when rendering.\n    pub fn size(&self) -> Rect {\n        self.terminal.viewport.area\n    }\n\n    /// Render a [`Widget`] to the current buffer using [`Widget::render`].\n    ///\n    /// # Examples\n    ///\n    /// ```rust\n    /// # use tui::Terminal;\n    /// # use tui::backend::TestBackend;\n    /// # use tui::layout::Rect;\n    /// # use tui::widgets::Block;\n    /// # let backend = TestBackend::new(5, 5);\n    /// # let mut terminal = Terminal::new(backend).unwrap();\n    /// let block = Block::default();\n    /// let area = Rect::new(0, 0, 5, 5);\n    /// let mut frame = terminal.get_frame();\n    /// frame.render_widget(block, area);\n    /// ```\n    pub fn render_widget<W>(&mut self, widget: W, area: Rect)\n    where\n        W: Widget,\n    {\n        widget.render(area, self.terminal.current_buffer_mut());\n    }\n\n    /// Render a [`StatefulWidget`] to the current buffer using [`StatefulWidget::render`].\n    ///\n    /// The last argument should be an instance of the [`StatefulWidget::State`] associated to the\n    /// given [`StatefulWidget`].\n    ///\n    /// # Examples\n    ///\n    /// ```rust\n    /// # use tui::Terminal;\n    /// # use tui::backend::TestBackend;\n    /// # use tui::layout::Rect;\n    /// # use tui::widgets::{List, ListItem, ListState};\n    /// # let backend = TestBackend::new(5, 5);\n    /// # let mut terminal = Terminal::new(backend).unwrap();\n    /// let mut state = ListState::default();\n    /// state.select(Some(1));\n    /// let items = vec![\n    ///     ListItem::new(\"Item 1\"),\n    ///     ListItem::new(\"Item 2\"),\n    /// ];\n    /// let list = List::new(items);\n    /// let area = Rect::new(0, 0, 5, 5);\n    /// let mut frame = terminal.get_frame();\n    /// frame.render_stateful_widget(list, area, &mut state);\n    /// ```\n    pub fn render_stateful_widget<W>(&mut self, widget: W, area: Rect, state: &mut W::State)\n    where\n        W: StatefulWidget,\n    {\n        widget.render(area, self.terminal.current_buffer_mut(), state);\n    }\n\n    /// After drawing this frame, make the cursor visible and put it at the specified (x, y)\n    /// coordinates. If this method is not called, the cursor will be hidden.\n    ///\n    /// Note that this will interfere with calls to `Terminal::hide_cursor()`,\n    /// `Terminal::show_cursor()`, and `Terminal::set_cursor()`. Pick one of the APIs and stick\n    /// with it.\n    pub fn set_cursor(&mut self, x: u16, y: u16) {\n        self.cursor_position = Some((x, y));\n    }\n}\n\n/// CompletedFrame represents the state of the terminal after all changes performed in the last\n/// [`Terminal::draw`] call have been applied. Therefore, it is only valid until the next call to\n/// [`Terminal::draw`].\npub struct CompletedFrame<'a> {\n    pub buffer: &'a Buffer,\n    pub area: Rect,\n}\n\nimpl<B> Drop for Terminal<B>\nwhere\n    B: Backend,\n{\n    fn drop(&mut self) {\n        // Attempt to restore the cursor state\n        if self.hidden_cursor {\n            if let Err(err) = self.show_cursor() {\n                eprintln!(\"Failed to show the cursor: {}\", err);\n            }\n        }\n    }\n}\n\nimpl<B> Terminal<B>\nwhere\n    B: Backend,\n{\n    /// Wrapper around Terminal initialization. Each buffer is initialized with a blank string and\n    /// default colors for the foreground and the background\n    pub fn new(backend: B) -> io::Result<Terminal<B>> {\n        let size = backend.size()?;\n        Terminal::with_options(\n            backend,\n            TerminalOptions {\n                viewport: Viewport {\n                    area: size,\n                    resize_behavior: ResizeBehavior::Auto,\n                },\n            },\n        )\n    }\n\n    /// UNSTABLE\n    pub fn with_options(backend: B, options: TerminalOptions) -> io::Result<Terminal<B>> {\n        Ok(Terminal {\n            backend,\n            buffers: [\n                Buffer::empty(options.viewport.area),\n                Buffer::empty(options.viewport.area),\n            ],\n            current: 0,\n            hidden_cursor: false,\n            viewport: options.viewport,\n        })\n    }\n\n    /// Get a Frame object which provides a consistent view into the terminal state for rendering.\n    pub fn get_frame(&mut self) -> Frame<B> {\n        Frame {\n            terminal: self,\n            cursor_position: None,\n        }\n    }\n\n    pub fn current_buffer_mut(&mut self) -> &mut Buffer {\n        &mut self.buffers[self.current]\n    }\n\n    pub fn backend(&self) -> &B {\n        &self.backend\n    }\n\n    pub fn backend_mut(&mut self) -> &mut B {\n        &mut self.backend\n    }\n\n    /// Obtains a difference between the previous and the current buffer and passes it to the\n    /// current backend for drawing.\n    pub fn flush(&mut self) -> io::Result<()> {\n        let previous_buffer = &self.buffers[1 - self.current];\n        let current_buffer = &self.buffers[self.current];\n        let updates = previous_buffer.diff(current_buffer);\n        self.backend.draw(updates.into_iter())\n    }\n\n    /// Updates the Terminal so that internal buffers match the requested size. Requested size will\n    /// be saved so the size can remain consistent when rendering.\n    /// This leads to a full clear of the screen.\n    pub fn resize(&mut self, area: Rect) -> io::Result<()> {\n        self.buffers[self.current].resize(area);\n        self.buffers[1 - self.current].resize(area);\n        self.viewport.area = area;\n        self.clear()\n    }\n\n    /// Queries the backend for size and resizes if it doesn't match the previous size.\n    pub fn autoresize(&mut self) -> io::Result<()> {\n        if self.viewport.resize_behavior == ResizeBehavior::Auto {\n            let size = self.size()?;\n            if size != self.viewport.area {\n                self.resize(size)?;\n            }\n        };\n        Ok(())\n    }\n\n    /// Synchronizes terminal size, calls the rendering closure, flushes the current internal state\n    /// and prepares for the next draw call.\n    pub fn draw<F>(&mut self, f: F) -> io::Result<CompletedFrame>\n    where\n        F: FnOnce(&mut Frame<B>),\n    {\n        // Autoresize - otherwise we get glitches if shrinking or potential desync between widgets\n        // and the terminal (if growing), which may OOB.\n        self.autoresize()?;\n\n        let mut frame = self.get_frame();\n        f(&mut frame);\n        // We can't change the cursor position right away because we have to flush the frame to\n        // stdout first. But we also can't keep the frame around, since it holds a &mut to\n        // Terminal. Thus, we're taking the important data out of the Frame and dropping it.\n        let cursor_position = frame.cursor_position;\n\n        // Draw to stdout\n        self.flush()?;\n\n        match cursor_position {\n            None => self.hide_cursor()?,\n            Some((x, y)) => {\n                self.show_cursor()?;\n                self.set_cursor(x, y)?;\n            }\n        }\n\n        // Swap buffers\n        self.buffers[1 - self.current].reset();\n        self.current = 1 - self.current;\n\n        // Flush\n        self.backend.flush()?;\n        Ok(CompletedFrame {\n            buffer: &self.buffers[1 - self.current],\n            area: self.viewport.area,\n        })\n    }\n\n    pub fn hide_cursor(&mut self) -> io::Result<()> {\n        self.backend.hide_cursor()?;\n        self.hidden_cursor = true;\n        Ok(())\n    }\n\n    pub fn show_cursor(&mut self) -> io::Result<()> {\n        self.backend.show_cursor()?;\n        self.hidden_cursor = false;\n        Ok(())\n    }\n\n    pub fn get_cursor(&mut self) -> io::Result<(u16, u16)> {\n        self.backend.get_cursor()\n    }\n\n    pub fn set_cursor(&mut self, x: u16, y: u16) -> io::Result<()> {\n        self.backend.set_cursor(x, y)\n    }\n\n    /// Clear the terminal and force a full redraw on the next draw call.\n    pub fn clear(&mut self) -> io::Result<()> {\n        self.backend.clear()?;\n        // Reset the back buffer to make sure the next update will redraw everything.\n        self.buffers[1 - self.current].reset();\n        Ok(())\n    }\n\n    /// Queries the real size of the backend.\n    pub fn size(&self) -> io::Result<Rect> {\n        self.backend.size()\n    }\n}\n"
  },
  {
    "path": "src/text.rs",
    "content": "//! Primitives for styled text.\n//!\n//! A terminal UI is at its root a lot of strings. In order to make it accessible and stylish,\n//! those strings may be associated to a set of styles. `tui` has three ways to represent them:\n//! - A single line string where all graphemes have the same style is represented by a [`Span`].\n//! - A single line string where each grapheme may have its own style is represented by [`Spans`].\n//! - A multiple line string where each grapheme may have its own style is represented by a\n//! [`Text`].\n//!\n//! These types form a hierarchy: [`Spans`] is a collection of [`Span`] and each line of [`Text`]\n//! is a [`Spans`].\n//!\n//! Keep it mind that a lot of widgets will use those types to advertise what kind of string is\n//! supported for their properties. Moreover, `tui` provides convenient `From` implementations so\n//! that you can start by using simple `String` or `&str` and then promote them to the previous\n//! primitives when you need additional styling capabilities.\n//!\n//! For example, for the [`crate::widgets::Block`] widget, all the following calls are valid to set\n//! its `title` property (which is a [`Spans`] under the hood):\n//!\n//! ```rust\n//! # use tui::widgets::Block;\n//! # use tui::text::{Span, Spans};\n//! # use tui::style::{Color, Style};\n//! // A simple string with no styling.\n//! // Converted to Spans(vec![\n//! //   Span { content: Cow::Borrowed(\"My title\"), style: Style { .. } }\n//! // ])\n//! let block = Block::default().title(\"My title\");\n//!\n//! // A simple string with a unique style.\n//! // Converted to Spans(vec![\n//! //   Span { content: Cow::Borrowed(\"My title\"), style: Style { fg: Some(Color::Yellow), .. }\n//! // ])\n//! let block = Block::default().title(\n//!     Span::styled(\"My title\", Style::default().fg(Color::Yellow))\n//! );\n//!\n//! // A string with multiple styles.\n//! // Converted to Spans(vec![\n//! //   Span { content: Cow::Borrowed(\"My\"), style: Style { fg: Some(Color::Yellow), .. } },\n//! //   Span { content: Cow::Borrowed(\" title\"), .. }\n//! // ])\n//! let block = Block::default().title(vec![\n//!     Span::styled(\"My\", Style::default().fg(Color::Yellow)),\n//!     Span::raw(\" title\"),\n//! ]);\n//! ```\nuse crate::style::Style;\nuse std::borrow::Cow;\nuse unicode_segmentation::UnicodeSegmentation;\nuse unicode_width::UnicodeWidthStr;\n\n/// A grapheme associated to a style.\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct StyledGrapheme<'a> {\n    pub symbol: &'a str,\n    pub style: Style,\n}\n\n/// A string where all graphemes have the same style.\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct Span<'a> {\n    pub content: Cow<'a, str>,\n    pub style: Style,\n}\n\nimpl<'a> Span<'a> {\n    /// Create a span with no style.\n    ///\n    /// ## Examples\n    ///\n    /// ```rust\n    /// # use tui::text::Span;\n    /// Span::raw(\"My text\");\n    /// Span::raw(String::from(\"My text\"));\n    /// ```\n    pub fn raw<T>(content: T) -> Span<'a>\n    where\n        T: Into<Cow<'a, str>>,\n    {\n        Span {\n            content: content.into(),\n            style: Style::default(),\n        }\n    }\n\n    /// Create a span with a style.\n    ///\n    /// # Examples\n    ///\n    /// ```rust\n    /// # use tui::text::Span;\n    /// # use tui::style::{Color, Modifier, Style};\n    /// let style = Style::default().fg(Color::Yellow).add_modifier(Modifier::ITALIC);\n    /// Span::styled(\"My text\", style);\n    /// Span::styled(String::from(\"My text\"), style);\n    /// ```\n    pub fn styled<T>(content: T, style: Style) -> Span<'a>\n    where\n        T: Into<Cow<'a, str>>,\n    {\n        Span {\n            content: content.into(),\n            style,\n        }\n    }\n\n    /// Returns the width of the content held by this span.\n    pub fn width(&self) -> usize {\n        self.content.width()\n    }\n\n    /// Returns an iterator over the graphemes held by this span.\n    ///\n    /// `base_style` is the [`Style`] that will be patched with each grapheme [`Style`] to get\n    /// the resulting [`Style`].\n    ///\n    /// ## Examples\n    ///\n    /// ```rust\n    /// # use tui::text::{Span, StyledGrapheme};\n    /// # use tui::style::{Color, Modifier, Style};\n    /// # use std::iter::Iterator;\n    /// let style = Style::default().fg(Color::Yellow);\n    /// let span = Span::styled(\"Text\", style);\n    /// let style = Style::default().fg(Color::Green).bg(Color::Black);\n    /// let styled_graphemes = span.styled_graphemes(style);\n    /// assert_eq!(\n    ///     vec![\n    ///         StyledGrapheme {\n    ///             symbol: \"T\",\n    ///             style: Style {\n    ///                 fg: Some(Color::Yellow),\n    ///                 bg: Some(Color::Black),\n    ///                 add_modifier: Modifier::empty(),\n    ///                 sub_modifier: Modifier::empty(),\n    ///             },\n    ///         },\n    ///         StyledGrapheme {\n    ///             symbol: \"e\",\n    ///             style: Style {\n    ///                 fg: Some(Color::Yellow),\n    ///                 bg: Some(Color::Black),\n    ///                 add_modifier: Modifier::empty(),\n    ///                 sub_modifier: Modifier::empty(),\n    ///             },\n    ///         },\n    ///         StyledGrapheme {\n    ///             symbol: \"x\",\n    ///             style: Style {\n    ///                 fg: Some(Color::Yellow),\n    ///                 bg: Some(Color::Black),\n    ///                 add_modifier: Modifier::empty(),\n    ///                 sub_modifier: Modifier::empty(),\n    ///             },\n    ///         },\n    ///         StyledGrapheme {\n    ///             symbol: \"t\",\n    ///             style: Style {\n    ///                 fg: Some(Color::Yellow),\n    ///                 bg: Some(Color::Black),\n    ///                 add_modifier: Modifier::empty(),\n    ///                 sub_modifier: Modifier::empty(),\n    ///             },\n    ///         },\n    ///     ],\n    ///     styled_graphemes.collect::<Vec<StyledGrapheme>>()\n    /// );\n    /// ```\n    pub fn styled_graphemes(\n        &'a self,\n        base_style: Style,\n    ) -> impl Iterator<Item = StyledGrapheme<'a>> {\n        UnicodeSegmentation::graphemes(self.content.as_ref(), true)\n            .map(move |g| StyledGrapheme {\n                symbol: g,\n                style: base_style.patch(self.style),\n            })\n            .filter(|s| s.symbol != \"\\n\")\n    }\n}\n\nimpl<'a> From<String> for Span<'a> {\n    fn from(s: String) -> Span<'a> {\n        Span::raw(s)\n    }\n}\n\nimpl<'a> From<&'a str> for Span<'a> {\n    fn from(s: &'a str) -> Span<'a> {\n        Span::raw(s)\n    }\n}\n\n/// A string composed of clusters of graphemes, each with their own style.\n#[derive(Debug, Clone, PartialEq, Default, Eq)]\npub struct Spans<'a>(pub Vec<Span<'a>>);\n\nimpl<'a> Spans<'a> {\n    /// Returns the width of the underlying string.\n    ///\n    /// ## Examples\n    ///\n    /// ```rust\n    /// # use tui::text::{Span, Spans};\n    /// # use tui::style::{Color, Style};\n    /// let spans = Spans::from(vec![\n    ///     Span::styled(\"My\", Style::default().fg(Color::Yellow)),\n    ///     Span::raw(\" text\"),\n    /// ]);\n    /// assert_eq!(7, spans.width());\n    /// ```\n    pub fn width(&self) -> usize {\n        self.0.iter().map(Span::width).sum()\n    }\n}\n\nimpl<'a> From<String> for Spans<'a> {\n    fn from(s: String) -> Spans<'a> {\n        Spans(vec![Span::from(s)])\n    }\n}\n\nimpl<'a> From<&'a str> for Spans<'a> {\n    fn from(s: &'a str) -> Spans<'a> {\n        Spans(vec![Span::from(s)])\n    }\n}\n\nimpl<'a> From<Vec<Span<'a>>> for Spans<'a> {\n    fn from(spans: Vec<Span<'a>>) -> Spans<'a> {\n        Spans(spans)\n    }\n}\n\nimpl<'a> From<Span<'a>> for Spans<'a> {\n    fn from(span: Span<'a>) -> Spans<'a> {\n        Spans(vec![span])\n    }\n}\n\nimpl<'a> From<Spans<'a>> for String {\n    fn from(line: Spans<'a>) -> String {\n        line.0.iter().fold(String::new(), |mut acc, s| {\n            acc.push_str(s.content.as_ref());\n            acc\n        })\n    }\n}\n\n/// A string split over multiple lines where each line is composed of several clusters, each with\n/// their own style.\n///\n/// A [`Text`], like a [`Span`], can be constructed using one of the many `From` implementations\n/// or via the [`Text::raw`] and [`Text::styled`] methods. Helpfully, [`Text`] also implements\n/// [`core::iter::Extend`] which enables the concatenation of several [`Text`] blocks.\n///\n/// ```rust\n/// # use tui::text::Text;\n/// # use tui::style::{Color, Modifier, Style};\n/// let style = Style::default().fg(Color::Yellow).add_modifier(Modifier::ITALIC);\n///\n/// // An initial two lines of `Text` built from a `&str`\n/// let mut text = Text::from(\"The first line\\nThe second line\");\n/// assert_eq!(2, text.height());\n///\n/// // Adding two more unstyled lines\n/// text.extend(Text::raw(\"These are two\\nmore lines!\"));\n/// assert_eq!(4, text.height());\n///\n/// // Adding a final two styled lines\n/// text.extend(Text::styled(\"Some more lines\\nnow with more style!\", style));\n/// assert_eq!(6, text.height());\n/// ```\n#[derive(Debug, Clone, PartialEq, Default, Eq)]\npub struct Text<'a> {\n    pub lines: Vec<Spans<'a>>,\n}\n\nimpl<'a> Text<'a> {\n    /// Create some text (potentially multiple lines) with no style.\n    ///\n    /// ## Examples\n    ///\n    /// ```rust\n    /// # use tui::text::Text;\n    /// Text::raw(\"The first line\\nThe second line\");\n    /// Text::raw(String::from(\"The first line\\nThe second line\"));\n    /// ```\n    pub fn raw<T>(content: T) -> Text<'a>\n    where\n        T: Into<Cow<'a, str>>,\n    {\n        Text {\n            lines: match content.into() {\n                Cow::Borrowed(s) => s.lines().map(Spans::from).collect(),\n                Cow::Owned(s) => s.lines().map(|l| Spans::from(l.to_owned())).collect(),\n            },\n        }\n    }\n\n    /// Create some text (potentially multiple lines) with a style.\n    ///\n    /// # Examples\n    ///\n    /// ```rust\n    /// # use tui::text::Text;\n    /// # use tui::style::{Color, Modifier, Style};\n    /// let style = Style::default().fg(Color::Yellow).add_modifier(Modifier::ITALIC);\n    /// Text::styled(\"The first line\\nThe second line\", style);\n    /// Text::styled(String::from(\"The first line\\nThe second line\"), style);\n    /// ```\n    pub fn styled<T>(content: T, style: Style) -> Text<'a>\n    where\n        T: Into<Cow<'a, str>>,\n    {\n        let mut text = Text::raw(content);\n        text.patch_style(style);\n        text\n    }\n\n    /// Returns the max width of all the lines.\n    ///\n    /// ## Examples\n    ///\n    /// ```rust\n    /// use tui::text::Text;\n    /// let text = Text::from(\"The first line\\nThe second line\");\n    /// assert_eq!(15, text.width());\n    /// ```\n    pub fn width(&self) -> usize {\n        self.lines\n            .iter()\n            .map(Spans::width)\n            .max()\n            .unwrap_or_default()\n    }\n\n    /// Returns the height.\n    ///\n    /// ## Examples\n    ///\n    /// ```rust\n    /// use tui::text::Text;\n    /// let text = Text::from(\"The first line\\nThe second line\");\n    /// assert_eq!(2, text.height());\n    /// ```\n    pub fn height(&self) -> usize {\n        self.lines.len()\n    }\n\n    /// Apply a new style to existing text.\n    ///\n    /// # Examples\n    ///\n    /// ```rust\n    /// # use tui::text::Text;\n    /// # use tui::style::{Color, Modifier, Style};\n    /// let style = Style::default().fg(Color::Yellow).add_modifier(Modifier::ITALIC);\n    /// let mut raw_text = Text::raw(\"The first line\\nThe second line\");\n    /// let styled_text = Text::styled(String::from(\"The first line\\nThe second line\"), style);\n    /// assert_ne!(raw_text, styled_text);\n    ///\n    /// raw_text.patch_style(style);\n    /// assert_eq!(raw_text, styled_text);\n    /// ```\n    pub fn patch_style(&mut self, style: Style) {\n        for line in &mut self.lines {\n            for span in &mut line.0 {\n                span.style = span.style.patch(style);\n            }\n        }\n    }\n}\n\nimpl<'a> From<String> for Text<'a> {\n    fn from(s: String) -> Text<'a> {\n        Text::raw(s)\n    }\n}\n\nimpl<'a> From<&'a str> for Text<'a> {\n    fn from(s: &'a str) -> Text<'a> {\n        Text::raw(s)\n    }\n}\n\nimpl<'a> From<Cow<'a, str>> for Text<'a> {\n    fn from(s: Cow<'a, str>) -> Text<'a> {\n        Text::raw(s)\n    }\n}\n\nimpl<'a> From<Span<'a>> for Text<'a> {\n    fn from(span: Span<'a>) -> Text<'a> {\n        Text {\n            lines: vec![Spans::from(span)],\n        }\n    }\n}\n\nimpl<'a> From<Spans<'a>> for Text<'a> {\n    fn from(spans: Spans<'a>) -> Text<'a> {\n        Text { lines: vec![spans] }\n    }\n}\n\nimpl<'a> From<Vec<Spans<'a>>> for Text<'a> {\n    fn from(lines: Vec<Spans<'a>>) -> Text<'a> {\n        Text { lines }\n    }\n}\n\nimpl<'a> IntoIterator for Text<'a> {\n    type Item = Spans<'a>;\n    type IntoIter = std::vec::IntoIter<Self::Item>;\n\n    fn into_iter(self) -> Self::IntoIter {\n        self.lines.into_iter()\n    }\n}\n\nimpl<'a> Extend<Spans<'a>> for Text<'a> {\n    fn extend<T: IntoIterator<Item = Spans<'a>>>(&mut self, iter: T) {\n        self.lines.extend(iter);\n    }\n}\n"
  },
  {
    "path": "src/widgets/barchart.rs",
    "content": "use crate::{\n    buffer::Buffer,\n    layout::Rect,\n    style::Style,\n    symbols,\n    widgets::{Block, Widget},\n};\nuse std::cmp::min;\nuse unicode_width::UnicodeWidthStr;\n\n/// Display multiple bars in a single widgets\n///\n/// # Examples\n///\n/// ```\n/// # use tui::widgets::{Block, Borders, BarChart};\n/// # use tui::style::{Style, Color, Modifier};\n/// BarChart::default()\n///     .block(Block::default().title(\"BarChart\").borders(Borders::ALL))\n///     .bar_width(3)\n///     .bar_gap(1)\n///     .bar_style(Style::default().fg(Color::Yellow).bg(Color::Red))\n///     .value_style(Style::default().fg(Color::Red).add_modifier(Modifier::BOLD))\n///     .label_style(Style::default().fg(Color::White))\n///     .data(&[(\"B0\", 0), (\"B1\", 2), (\"B2\", 4), (\"B3\", 3)])\n///     .max(4);\n/// ```\n#[derive(Debug, Clone)]\npub struct BarChart<'a> {\n    /// Block to wrap the widget in\n    block: Option<Block<'a>>,\n    /// The width of each bar\n    bar_width: u16,\n    /// The gap between each bar\n    bar_gap: u16,\n    /// Set of symbols used to display the data\n    bar_set: symbols::bar::Set,\n    /// Style of the bars\n    bar_style: Style,\n    /// Style of the values printed at the bottom of each bar\n    value_style: Style,\n    /// Style of the labels printed under each bar\n    label_style: Style,\n    /// Style for the widget\n    style: Style,\n    /// Slice of (label, value) pair to plot on the chart\n    data: &'a [(&'a str, u64)],\n    /// Value necessary for a bar to reach the maximum height (if no value is specified,\n    /// the maximum value in the data is taken as reference)\n    max: Option<u64>,\n    /// Values to display on the bar (computed when the data is passed to the widget)\n    values: Vec<String>,\n}\n\nimpl<'a> Default for BarChart<'a> {\n    fn default() -> BarChart<'a> {\n        BarChart {\n            block: None,\n            max: None,\n            data: &[],\n            values: Vec::new(),\n            bar_style: Style::default(),\n            bar_width: 1,\n            bar_gap: 1,\n            bar_set: symbols::bar::NINE_LEVELS,\n            value_style: Default::default(),\n            label_style: Default::default(),\n            style: Default::default(),\n        }\n    }\n}\n\nimpl<'a> BarChart<'a> {\n    pub fn data(mut self, data: &'a [(&'a str, u64)]) -> BarChart<'a> {\n        self.data = data;\n        self.values = Vec::with_capacity(self.data.len());\n        for &(_, v) in self.data {\n            self.values.push(format!(\"{}\", v));\n        }\n        self\n    }\n\n    pub fn block(mut self, block: Block<'a>) -> BarChart<'a> {\n        self.block = Some(block);\n        self\n    }\n\n    pub fn max(mut self, max: u64) -> BarChart<'a> {\n        self.max = Some(max);\n        self\n    }\n\n    pub fn bar_style(mut self, style: Style) -> BarChart<'a> {\n        self.bar_style = style;\n        self\n    }\n\n    pub fn bar_width(mut self, width: u16) -> BarChart<'a> {\n        self.bar_width = width;\n        self\n    }\n\n    pub fn bar_gap(mut self, gap: u16) -> BarChart<'a> {\n        self.bar_gap = gap;\n        self\n    }\n\n    pub fn bar_set(mut self, bar_set: symbols::bar::Set) -> BarChart<'a> {\n        self.bar_set = bar_set;\n        self\n    }\n\n    pub fn value_style(mut self, style: Style) -> BarChart<'a> {\n        self.value_style = style;\n        self\n    }\n\n    pub fn label_style(mut self, style: Style) -> BarChart<'a> {\n        self.label_style = style;\n        self\n    }\n\n    pub fn style(mut self, style: Style) -> BarChart<'a> {\n        self.style = style;\n        self\n    }\n}\n\nimpl<'a> Widget for BarChart<'a> {\n    fn render(mut self, area: Rect, buf: &mut Buffer) {\n        buf.set_style(area, self.style);\n\n        let chart_area = match self.block.take() {\n            Some(b) => {\n                let inner_area = b.inner(area);\n                b.render(area, buf);\n                inner_area\n            }\n            None => area,\n        };\n\n        if chart_area.height < 2 {\n            return;\n        }\n\n        let max = self\n            .max\n            .unwrap_or_else(|| self.data.iter().map(|t| t.1).max().unwrap_or_default());\n        let max_index = min(\n            (chart_area.width / (self.bar_width + self.bar_gap)) as usize,\n            self.data.len(),\n        );\n        let mut data = self\n            .data\n            .iter()\n            .take(max_index)\n            .map(|&(l, v)| {\n                (\n                    l,\n                    v * u64::from(chart_area.height - 1) * 8 / std::cmp::max(max, 1),\n                )\n            })\n            .collect::<Vec<(&str, u64)>>();\n        for j in (0..chart_area.height - 1).rev() {\n            for (i, d) in data.iter_mut().enumerate() {\n                let symbol = match d.1 {\n                    0 => self.bar_set.empty,\n                    1 => self.bar_set.one_eighth,\n                    2 => self.bar_set.one_quarter,\n                    3 => self.bar_set.three_eighths,\n                    4 => self.bar_set.half,\n                    5 => self.bar_set.five_eighths,\n                    6 => self.bar_set.three_quarters,\n                    7 => self.bar_set.seven_eighths,\n                    _ => self.bar_set.full,\n                };\n\n                for x in 0..self.bar_width {\n                    buf.get_mut(\n                        chart_area.left() + i as u16 * (self.bar_width + self.bar_gap) + x,\n                        chart_area.top() + j,\n                    )\n                    .set_symbol(symbol)\n                    .set_style(self.bar_style);\n                }\n\n                if d.1 > 8 {\n                    d.1 -= 8;\n                } else {\n                    d.1 = 0;\n                }\n            }\n        }\n\n        for (i, &(label, value)) in self.data.iter().take(max_index).enumerate() {\n            if value != 0 {\n                let value_label = &self.values[i];\n                let width = value_label.width() as u16;\n                if width < self.bar_width {\n                    buf.set_string(\n                        chart_area.left()\n                            + i as u16 * (self.bar_width + self.bar_gap)\n                            + (self.bar_width - width) / 2,\n                        chart_area.bottom() - 2,\n                        value_label,\n                        self.value_style,\n                    );\n                }\n            }\n            buf.set_stringn(\n                chart_area.left() + i as u16 * (self.bar_width + self.bar_gap),\n                chart_area.bottom() - 1,\n                label,\n                self.bar_width as usize,\n                self.label_style,\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "src/widgets/block.rs",
    "content": "use crate::{\n    buffer::Buffer,\n    layout::{Alignment, Rect},\n    style::Style,\n    symbols::line,\n    text::{Span, Spans},\n    widgets::{Borders, Widget},\n};\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum BorderType {\n    Plain,\n    Rounded,\n    Double,\n    Thick,\n}\n\nimpl BorderType {\n    pub fn line_symbols(border_type: BorderType) -> line::Set {\n        match border_type {\n            BorderType::Plain => line::NORMAL,\n            BorderType::Rounded => line::ROUNDED,\n            BorderType::Double => line::DOUBLE,\n            BorderType::Thick => line::THICK,\n        }\n    }\n}\n\n/// Base widget to be used with all upper level ones. It may be used to display a box border around\n/// the widget and/or add a title.\n///\n/// # Examples\n///\n/// ```\n/// # use tui::widgets::{Block, BorderType, Borders};\n/// # use tui::style::{Style, Color};\n/// Block::default()\n///     .title(\"Block\")\n///     .borders(Borders::LEFT | Borders::RIGHT)\n///     .border_style(Style::default().fg(Color::White))\n///     .border_type(BorderType::Rounded)\n///     .style(Style::default().bg(Color::Black));\n/// ```\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct Block<'a> {\n    /// Optional title place on the upper left of the block\n    title: Option<Spans<'a>>,\n    /// Title alignment. The default is top left of the block, but one can choose to place\n    /// title in the top middle, or top right of the block\n    title_alignment: Alignment,\n    /// Visible borders\n    borders: Borders,\n    /// Border style\n    border_style: Style,\n    /// Type of the border. The default is plain lines but one can choose to have rounded corners\n    /// or doubled lines instead.\n    border_type: BorderType,\n    /// Widget style\n    style: Style,\n}\n\nimpl<'a> Default for Block<'a> {\n    fn default() -> Block<'a> {\n        Block {\n            title: None,\n            title_alignment: Alignment::Left,\n            borders: Borders::NONE,\n            border_style: Default::default(),\n            border_type: BorderType::Plain,\n            style: Default::default(),\n        }\n    }\n}\n\nimpl<'a> Block<'a> {\n    pub fn title<T>(mut self, title: T) -> Block<'a>\n    where\n        T: Into<Spans<'a>>,\n    {\n        self.title = Some(title.into());\n        self\n    }\n\n    #[deprecated(\n        since = \"0.10.0\",\n        note = \"You should use styling capabilities of `text::Spans` given as argument of the `title` method to apply styling to the title.\"\n    )]\n    pub fn title_style(mut self, style: Style) -> Block<'a> {\n        if let Some(t) = self.title {\n            let title = String::from(t);\n            self.title = Some(Spans::from(Span::styled(title, style)));\n        }\n        self\n    }\n\n    pub fn title_alignment(mut self, alignment: Alignment) -> Block<'a> {\n        self.title_alignment = alignment;\n        self\n    }\n\n    pub fn border_style(mut self, style: Style) -> Block<'a> {\n        self.border_style = style;\n        self\n    }\n\n    pub fn style(mut self, style: Style) -> Block<'a> {\n        self.style = style;\n        self\n    }\n\n    pub fn borders(mut self, flag: Borders) -> Block<'a> {\n        self.borders = flag;\n        self\n    }\n\n    pub fn border_type(mut self, border_type: BorderType) -> Block<'a> {\n        self.border_type = border_type;\n        self\n    }\n\n    /// Compute the inner area of a block based on its border visibility rules.\n    pub fn inner(&self, area: Rect) -> Rect {\n        let mut inner = area;\n        if self.borders.intersects(Borders::LEFT) {\n            inner.x = inner.x.saturating_add(1).min(inner.right());\n            inner.width = inner.width.saturating_sub(1);\n        }\n        if self.borders.intersects(Borders::TOP) || self.title.is_some() {\n            inner.y = inner.y.saturating_add(1).min(inner.bottom());\n            inner.height = inner.height.saturating_sub(1);\n        }\n        if self.borders.intersects(Borders::RIGHT) {\n            inner.width = inner.width.saturating_sub(1);\n        }\n        if self.borders.intersects(Borders::BOTTOM) {\n            inner.height = inner.height.saturating_sub(1);\n        }\n        inner\n    }\n}\n\nimpl<'a> Widget for Block<'a> {\n    fn render(self, area: Rect, buf: &mut Buffer) {\n        if area.area() == 0 {\n            return;\n        }\n        buf.set_style(area, self.style);\n        let symbols = BorderType::line_symbols(self.border_type);\n\n        // Sides\n        if self.borders.intersects(Borders::LEFT) {\n            for y in area.top()..area.bottom() {\n                buf.get_mut(area.left(), y)\n                    .set_symbol(symbols.vertical)\n                    .set_style(self.border_style);\n            }\n        }\n        if self.borders.intersects(Borders::TOP) {\n            for x in area.left()..area.right() {\n                buf.get_mut(x, area.top())\n                    .set_symbol(symbols.horizontal)\n                    .set_style(self.border_style);\n            }\n        }\n        if self.borders.intersects(Borders::RIGHT) {\n            let x = area.right() - 1;\n            for y in area.top()..area.bottom() {\n                buf.get_mut(x, y)\n                    .set_symbol(symbols.vertical)\n                    .set_style(self.border_style);\n            }\n        }\n        if self.borders.intersects(Borders::BOTTOM) {\n            let y = area.bottom() - 1;\n            for x in area.left()..area.right() {\n                buf.get_mut(x, y)\n                    .set_symbol(symbols.horizontal)\n                    .set_style(self.border_style);\n            }\n        }\n\n        // Corners\n        if self.borders.contains(Borders::RIGHT | Borders::BOTTOM) {\n            buf.get_mut(area.right() - 1, area.bottom() - 1)\n                .set_symbol(symbols.bottom_right)\n                .set_style(self.border_style);\n        }\n        if self.borders.contains(Borders::RIGHT | Borders::TOP) {\n            buf.get_mut(area.right() - 1, area.top())\n                .set_symbol(symbols.top_right)\n                .set_style(self.border_style);\n        }\n        if self.borders.contains(Borders::LEFT | Borders::BOTTOM) {\n            buf.get_mut(area.left(), area.bottom() - 1)\n                .set_symbol(symbols.bottom_left)\n                .set_style(self.border_style);\n        }\n        if self.borders.contains(Borders::LEFT | Borders::TOP) {\n            buf.get_mut(area.left(), area.top())\n                .set_symbol(symbols.top_left)\n                .set_style(self.border_style);\n        }\n\n        // Title\n        if let Some(title) = self.title {\n            let left_border_dx = if self.borders.intersects(Borders::LEFT) {\n                1\n            } else {\n                0\n            };\n\n            let right_border_dx = if self.borders.intersects(Borders::RIGHT) {\n                1\n            } else {\n                0\n            };\n\n            let title_area_width = area\n                .width\n                .saturating_sub(left_border_dx)\n                .saturating_sub(right_border_dx);\n\n            let title_dx = match self.title_alignment {\n                Alignment::Left => left_border_dx,\n                Alignment::Center => area.width.saturating_sub(title.width() as u16) / 2,\n                Alignment::Right => area\n                    .width\n                    .saturating_sub(title.width() as u16)\n                    .saturating_sub(right_border_dx),\n            };\n\n            let title_x = area.left() + title_dx;\n            let title_y = area.top();\n\n            buf.set_spans(title_x, title_y, &title, title_area_width);\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::layout::Rect;\n\n    #[test]\n    fn inner_takes_into_account_the_borders() {\n        // No borders\n        assert_eq!(\n            Block::default().inner(Rect::default()),\n            Rect {\n                x: 0,\n                y: 0,\n                width: 0,\n                height: 0\n            },\n            \"no borders, width=0, height=0\"\n        );\n        assert_eq!(\n            Block::default().inner(Rect {\n                x: 0,\n                y: 0,\n                width: 1,\n                height: 1\n            }),\n            Rect {\n                x: 0,\n                y: 0,\n                width: 1,\n                height: 1\n            },\n            \"no borders, width=1, height=1\"\n        );\n\n        // Left border\n        assert_eq!(\n            Block::default().borders(Borders::LEFT).inner(Rect {\n                x: 0,\n                y: 0,\n                width: 0,\n                height: 1\n            }),\n            Rect {\n                x: 0,\n                y: 0,\n                width: 0,\n                height: 1\n            },\n            \"left, width=0\"\n        );\n        assert_eq!(\n            Block::default().borders(Borders::LEFT).inner(Rect {\n                x: 0,\n                y: 0,\n                width: 1,\n                height: 1\n            }),\n            Rect {\n                x: 1,\n                y: 0,\n                width: 0,\n                height: 1\n            },\n            \"left, width=1\"\n        );\n        assert_eq!(\n            Block::default().borders(Borders::LEFT).inner(Rect {\n                x: 0,\n                y: 0,\n                width: 2,\n                height: 1\n            }),\n            Rect {\n                x: 1,\n                y: 0,\n                width: 1,\n                height: 1\n            },\n            \"left, width=2\"\n        );\n\n        // Top border\n        assert_eq!(\n            Block::default().borders(Borders::TOP).inner(Rect {\n                x: 0,\n                y: 0,\n                width: 1,\n                height: 0\n            }),\n            Rect {\n                x: 0,\n                y: 0,\n                width: 1,\n                height: 0\n            },\n            \"top, height=0\"\n        );\n        assert_eq!(\n            Block::default().borders(Borders::TOP).inner(Rect {\n                x: 0,\n                y: 0,\n                width: 1,\n                height: 1\n            }),\n            Rect {\n                x: 0,\n                y: 1,\n                width: 1,\n                height: 0\n            },\n            \"top, height=1\"\n        );\n        assert_eq!(\n            Block::default().borders(Borders::TOP).inner(Rect {\n                x: 0,\n                y: 0,\n                width: 1,\n                height: 2\n            }),\n            Rect {\n                x: 0,\n                y: 1,\n                width: 1,\n                height: 1\n            },\n            \"top, height=2\"\n        );\n\n        // Right border\n        assert_eq!(\n            Block::default().borders(Borders::RIGHT).inner(Rect {\n                x: 0,\n                y: 0,\n                width: 0,\n                height: 1\n            }),\n            Rect {\n                x: 0,\n                y: 0,\n                width: 0,\n                height: 1\n            },\n            \"right, width=0\"\n        );\n        assert_eq!(\n            Block::default().borders(Borders::RIGHT).inner(Rect {\n                x: 0,\n                y: 0,\n                width: 1,\n                height: 1\n            }),\n            Rect {\n                x: 0,\n                y: 0,\n                width: 0,\n                height: 1\n            },\n            \"right, width=1\"\n        );\n        assert_eq!(\n            Block::default().borders(Borders::RIGHT).inner(Rect {\n                x: 0,\n                y: 0,\n                width: 2,\n                height: 1\n            }),\n            Rect {\n                x: 0,\n                y: 0,\n                width: 1,\n                height: 1\n            },\n            \"right, width=2\"\n        );\n\n        // Bottom border\n        assert_eq!(\n            Block::default().borders(Borders::BOTTOM).inner(Rect {\n                x: 0,\n                y: 0,\n                width: 1,\n                height: 0\n            }),\n            Rect {\n                x: 0,\n                y: 0,\n                width: 1,\n                height: 0\n            },\n            \"bottom, height=0\"\n        );\n        assert_eq!(\n            Block::default().borders(Borders::BOTTOM).inner(Rect {\n                x: 0,\n                y: 0,\n                width: 1,\n                height: 1\n            }),\n            Rect {\n                x: 0,\n                y: 0,\n                width: 1,\n                height: 0\n            },\n            \"bottom, height=1\"\n        );\n        assert_eq!(\n            Block::default().borders(Borders::BOTTOM).inner(Rect {\n                x: 0,\n                y: 0,\n                width: 1,\n                height: 2\n            }),\n            Rect {\n                x: 0,\n                y: 0,\n                width: 1,\n                height: 1\n            },\n            \"bottom, height=2\"\n        );\n\n        // All borders\n        assert_eq!(\n            Block::default()\n                .borders(Borders::ALL)\n                .inner(Rect::default()),\n            Rect {\n                x: 0,\n                y: 0,\n                width: 0,\n                height: 0\n            },\n            \"all borders, width=0, height=0\"\n        );\n        assert_eq!(\n            Block::default().borders(Borders::ALL).inner(Rect {\n                x: 0,\n                y: 0,\n                width: 1,\n                height: 1\n            }),\n            Rect {\n                x: 1,\n                y: 1,\n                width: 0,\n                height: 0,\n            },\n            \"all borders, width=1, height=1\"\n        );\n        assert_eq!(\n            Block::default().borders(Borders::ALL).inner(Rect {\n                x: 0,\n                y: 0,\n                width: 2,\n                height: 2,\n            }),\n            Rect {\n                x: 1,\n                y: 1,\n                width: 0,\n                height: 0,\n            },\n            \"all borders, width=2, height=2\"\n        );\n        assert_eq!(\n            Block::default().borders(Borders::ALL).inner(Rect {\n                x: 0,\n                y: 0,\n                width: 3,\n                height: 3,\n            }),\n            Rect {\n                x: 1,\n                y: 1,\n                width: 1,\n                height: 1,\n            },\n            \"all borders, width=3, height=3\"\n        );\n    }\n\n    #[test]\n    fn inner_takes_into_account_the_title() {\n        assert_eq!(\n            Block::default().title(\"Test\").inner(Rect {\n                x: 0,\n                y: 0,\n                width: 0,\n                height: 1,\n            }),\n            Rect {\n                x: 0,\n                y: 1,\n                width: 0,\n                height: 0,\n            },\n        );\n        assert_eq!(\n            Block::default()\n                .title(\"Test\")\n                .title_alignment(Alignment::Center)\n                .inner(Rect {\n                    x: 0,\n                    y: 0,\n                    width: 0,\n                    height: 1,\n                }),\n            Rect {\n                x: 0,\n                y: 1,\n                width: 0,\n                height: 0,\n            },\n        );\n        assert_eq!(\n            Block::default()\n                .title(\"Test\")\n                .title_alignment(Alignment::Right)\n                .inner(Rect {\n                    x: 0,\n                    y: 0,\n                    width: 0,\n                    height: 1,\n                }),\n            Rect {\n                x: 0,\n                y: 1,\n                width: 0,\n                height: 0,\n            },\n        );\n    }\n}\n"
  },
  {
    "path": "src/widgets/canvas/line.rs",
    "content": "use crate::{\n    style::Color,\n    widgets::canvas::{Painter, Shape},\n};\n\n/// Shape to draw a line from (x1, y1) to (x2, y2) with the given color\n#[derive(Debug, Clone)]\npub struct Line {\n    pub x1: f64,\n    pub y1: f64,\n    pub x2: f64,\n    pub y2: f64,\n    pub color: Color,\n}\n\nimpl Shape for Line {\n    fn draw(&self, painter: &mut Painter) {\n        let (x1, y1) = match painter.get_point(self.x1, self.y1) {\n            Some(c) => c,\n            None => return,\n        };\n        let (x2, y2) = match painter.get_point(self.x2, self.y2) {\n            Some(c) => c,\n            None => return,\n        };\n        let (dx, x_range) = if x2 >= x1 {\n            (x2 - x1, x1..=x2)\n        } else {\n            (x1 - x2, x2..=x1)\n        };\n        let (dy, y_range) = if y2 >= y1 {\n            (y2 - y1, y1..=y2)\n        } else {\n            (y1 - y2, y2..=y1)\n        };\n\n        if dx == 0 {\n            for y in y_range {\n                painter.paint(x1, y, self.color);\n            }\n        } else if dy == 0 {\n            for x in x_range {\n                painter.paint(x, y1, self.color);\n            }\n        } else if dy < dx {\n            if x1 > x2 {\n                draw_line_low(painter, x2, y2, x1, y1, self.color);\n            } else {\n                draw_line_low(painter, x1, y1, x2, y2, self.color);\n            }\n        } else if y1 > y2 {\n            draw_line_high(painter, x2, y2, x1, y1, self.color);\n        } else {\n            draw_line_high(painter, x1, y1, x2, y2, self.color);\n        }\n    }\n}\n\nfn draw_line_low(painter: &mut Painter, x1: usize, y1: usize, x2: usize, y2: usize, color: Color) {\n    let dx = (x2 - x1) as isize;\n    let dy = (y2 as isize - y1 as isize).abs();\n    let mut d = 2 * dy - dx;\n    let mut y = y1;\n    for x in x1..=x2 {\n        painter.paint(x, y, color);\n        if d > 0 {\n            y = if y1 > y2 {\n                y.saturating_sub(1)\n            } else {\n                y.saturating_add(1)\n            };\n            d -= 2 * dx;\n        }\n        d += 2 * dy;\n    }\n}\n\nfn draw_line_high(painter: &mut Painter, x1: usize, y1: usize, x2: usize, y2: usize, color: Color) {\n    let dx = (x2 as isize - x1 as isize).abs();\n    let dy = (y2 - y1) as isize;\n    let mut d = 2 * dx - dy;\n    let mut x = x1;\n    for y in y1..=y2 {\n        painter.paint(x, y, color);\n        if d > 0 {\n            x = if x1 > x2 {\n                x.saturating_sub(1)\n            } else {\n                x.saturating_add(1)\n            };\n            d -= 2 * dy;\n        }\n        d += 2 * dx;\n    }\n}\n"
  },
  {
    "path": "src/widgets/canvas/map.rs",
    "content": "use crate::{\n    style::Color,\n    widgets::canvas::{\n        world::{WORLD_HIGH_RESOLUTION, WORLD_LOW_RESOLUTION},\n        Painter, Shape,\n    },\n};\n\n#[derive(Debug, Clone, Copy)]\npub enum MapResolution {\n    Low,\n    High,\n}\n\nimpl MapResolution {\n    fn data(self) -> &'static [(f64, f64)] {\n        match self {\n            MapResolution::Low => &WORLD_LOW_RESOLUTION,\n            MapResolution::High => &WORLD_HIGH_RESOLUTION,\n        }\n    }\n}\n\n/// Shape to draw a world map with the given resolution and color\n#[derive(Debug, Clone)]\npub struct Map {\n    pub resolution: MapResolution,\n    pub color: Color,\n}\n\nimpl Default for Map {\n    fn default() -> Map {\n        Map {\n            resolution: MapResolution::Low,\n            color: Color::Reset,\n        }\n    }\n}\n\nimpl Shape for Map {\n    fn draw(&self, painter: &mut Painter) {\n        for (x, y) in self.resolution.data() {\n            if let Some((x, y)) = painter.get_point(*x, *y) {\n                painter.paint(x, y, self.color);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/widgets/canvas/mod.rs",
    "content": "mod line;\nmod map;\nmod points;\nmod rectangle;\nmod world;\n\npub use self::line::Line;\npub use self::map::{Map, MapResolution};\npub use self::points::Points;\npub use self::rectangle::Rectangle;\n\nuse crate::{\n    buffer::Buffer,\n    layout::Rect,\n    style::{Color, Style},\n    symbols,\n    text::Spans,\n    widgets::{Block, Widget},\n};\nuse std::fmt::Debug;\n\n/// Interface for all shapes that may be drawn on a Canvas widget.\npub trait Shape {\n    fn draw(&self, painter: &mut Painter);\n}\n\n/// Label to draw some text on the canvas\n#[derive(Debug, Clone)]\npub struct Label<'a> {\n    x: f64,\n    y: f64,\n    spans: Spans<'a>,\n}\n\n#[derive(Debug, Clone)]\nstruct Layer {\n    string: String,\n    colors: Vec<Color>,\n}\n\ntrait Grid: Debug {\n    fn width(&self) -> u16;\n    fn height(&self) -> u16;\n    fn resolution(&self) -> (f64, f64);\n    fn paint(&mut self, x: usize, y: usize, color: Color);\n    fn save(&self) -> Layer;\n    fn reset(&mut self);\n}\n\n#[derive(Debug, Clone)]\nstruct BrailleGrid {\n    width: u16,\n    height: u16,\n    cells: Vec<u16>,\n    colors: Vec<Color>,\n}\n\nimpl BrailleGrid {\n    fn new(width: u16, height: u16) -> BrailleGrid {\n        let length = usize::from(width * height);\n        BrailleGrid {\n            width,\n            height,\n            cells: vec![symbols::braille::BLANK; length],\n            colors: vec![Color::Reset; length],\n        }\n    }\n}\n\nimpl Grid for BrailleGrid {\n    fn width(&self) -> u16 {\n        self.width\n    }\n\n    fn height(&self) -> u16 {\n        self.height\n    }\n\n    fn resolution(&self) -> (f64, f64) {\n        (\n            f64::from(self.width) * 2.0 - 1.0,\n            f64::from(self.height) * 4.0 - 1.0,\n        )\n    }\n\n    fn save(&self) -> Layer {\n        Layer {\n            string: String::from_utf16(&self.cells).unwrap(),\n            colors: self.colors.clone(),\n        }\n    }\n\n    fn reset(&mut self) {\n        for c in &mut self.cells {\n            *c = symbols::braille::BLANK;\n        }\n        for c in &mut self.colors {\n            *c = Color::Reset;\n        }\n    }\n\n    fn paint(&mut self, x: usize, y: usize, color: Color) {\n        let index = y / 4 * self.width as usize + x / 2;\n        if let Some(c) = self.cells.get_mut(index) {\n            *c |= symbols::braille::DOTS[y % 4][x % 2];\n        }\n        if let Some(c) = self.colors.get_mut(index) {\n            *c = color;\n        }\n    }\n}\n\n#[derive(Debug, Clone)]\nstruct CharGrid {\n    width: u16,\n    height: u16,\n    cells: Vec<char>,\n    colors: Vec<Color>,\n    cell_char: char,\n}\n\nimpl CharGrid {\n    fn new(width: u16, height: u16, cell_char: char) -> CharGrid {\n        let length = usize::from(width * height);\n        CharGrid {\n            width,\n            height,\n            cells: vec![' '; length],\n            colors: vec![Color::Reset; length],\n            cell_char,\n        }\n    }\n}\n\nimpl Grid for CharGrid {\n    fn width(&self) -> u16 {\n        self.width\n    }\n\n    fn height(&self) -> u16 {\n        self.height\n    }\n\n    fn resolution(&self) -> (f64, f64) {\n        (f64::from(self.width) - 1.0, f64::from(self.height) - 1.0)\n    }\n\n    fn save(&self) -> Layer {\n        Layer {\n            string: self.cells.iter().collect(),\n            colors: self.colors.clone(),\n        }\n    }\n\n    fn reset(&mut self) {\n        for c in &mut self.cells {\n            *c = ' ';\n        }\n        for c in &mut self.colors {\n            *c = Color::Reset;\n        }\n    }\n\n    fn paint(&mut self, x: usize, y: usize, color: Color) {\n        let index = y * self.width as usize + x;\n        if let Some(c) = self.cells.get_mut(index) {\n            *c = self.cell_char;\n        }\n        if let Some(c) = self.colors.get_mut(index) {\n            *c = color;\n        }\n    }\n}\n\n#[derive(Debug)]\npub struct Painter<'a, 'b> {\n    context: &'a mut Context<'b>,\n    resolution: (f64, f64),\n}\n\nimpl<'a, 'b> Painter<'a, 'b> {\n    /// Convert the (x, y) coordinates to location of a point on the grid\n    ///\n    /// # Examples:\n    /// ```\n    /// use tui::{symbols, widgets::canvas::{Painter, Context}};\n    ///\n    /// let mut ctx = Context::new(2, 2, [1.0, 2.0], [0.0, 2.0], symbols::Marker::Braille);\n    /// let mut painter = Painter::from(&mut ctx);\n    /// let point = painter.get_point(1.0, 0.0);\n    /// assert_eq!(point, Some((0, 7)));\n    /// let point = painter.get_point(1.5, 1.0);\n    /// assert_eq!(point, Some((1, 3)));\n    /// let point = painter.get_point(0.0, 0.0);\n    /// assert_eq!(point, None);\n    /// let point = painter.get_point(2.0, 2.0);\n    /// assert_eq!(point, Some((3, 0)));\n    /// let point = painter.get_point(1.0, 2.0);\n    /// assert_eq!(point, Some((0, 0)));\n    /// ```\n    pub fn get_point(&self, x: f64, y: f64) -> Option<(usize, usize)> {\n        let left = self.context.x_bounds[0];\n        let right = self.context.x_bounds[1];\n        let top = self.context.y_bounds[1];\n        let bottom = self.context.y_bounds[0];\n        if x < left || x > right || y < bottom || y > top {\n            return None;\n        }\n        let width = (self.context.x_bounds[1] - self.context.x_bounds[0]).abs();\n        let height = (self.context.y_bounds[1] - self.context.y_bounds[0]).abs();\n        if width == 0.0 || height == 0.0 {\n            return None;\n        }\n        let x = ((x - left) * self.resolution.0 / width) as usize;\n        let y = ((top - y) * self.resolution.1 / height) as usize;\n        Some((x, y))\n    }\n\n    /// Paint a point of the grid\n    ///\n    /// # Examples:\n    /// ```\n    /// use tui::{style::Color, symbols, widgets::canvas::{Painter, Context}};\n    ///\n    /// let mut ctx = Context::new(1, 1, [0.0, 2.0], [0.0, 2.0], symbols::Marker::Braille);\n    /// let mut painter = Painter::from(&mut ctx);\n    /// let cell = painter.paint(1, 3, Color::Red);\n    /// ```\n    pub fn paint(&mut self, x: usize, y: usize, color: Color) {\n        self.context.grid.paint(x, y, color);\n    }\n}\n\nimpl<'a, 'b> From<&'a mut Context<'b>> for Painter<'a, 'b> {\n    fn from(context: &'a mut Context<'b>) -> Painter<'a, 'b> {\n        let resolution = context.grid.resolution();\n        Painter {\n            context,\n            resolution,\n        }\n    }\n}\n\n/// Holds the state of the Canvas when painting to it.\n#[derive(Debug)]\npub struct Context<'a> {\n    x_bounds: [f64; 2],\n    y_bounds: [f64; 2],\n    grid: Box<dyn Grid>,\n    dirty: bool,\n    layers: Vec<Layer>,\n    labels: Vec<Label<'a>>,\n}\n\nimpl<'a> Context<'a> {\n    pub fn new(\n        width: u16,\n        height: u16,\n        x_bounds: [f64; 2],\n        y_bounds: [f64; 2],\n        marker: symbols::Marker,\n    ) -> Context<'a> {\n        let grid: Box<dyn Grid> = match marker {\n            symbols::Marker::Dot => Box::new(CharGrid::new(width, height, '•')),\n            symbols::Marker::Block => Box::new(CharGrid::new(width, height, '▄')),\n            symbols::Marker::Braille => Box::new(BrailleGrid::new(width, height)),\n        };\n        Context {\n            x_bounds,\n            y_bounds,\n            grid,\n            dirty: false,\n            layers: Vec::new(),\n            labels: Vec::new(),\n        }\n    }\n\n    /// Draw any object that may implement the Shape trait\n    pub fn draw<S>(&mut self, shape: &S)\n    where\n        S: Shape,\n    {\n        self.dirty = true;\n        let mut painter = Painter::from(self);\n        shape.draw(&mut painter);\n    }\n\n    /// Go one layer above in the canvas.\n    pub fn layer(&mut self) {\n        self.layers.push(self.grid.save());\n        self.grid.reset();\n        self.dirty = false;\n    }\n\n    /// Print a string on the canvas at the given position\n    pub fn print<T>(&mut self, x: f64, y: f64, spans: T)\n    where\n        T: Into<Spans<'a>>,\n    {\n        self.labels.push(Label {\n            x,\n            y,\n            spans: spans.into(),\n        });\n    }\n\n    /// Push the last layer if necessary\n    fn finish(&mut self) {\n        if self.dirty {\n            self.layer()\n        }\n    }\n}\n\n/// The Canvas widget may be used to draw more detailed figures using braille patterns (each\n/// cell can have a braille character in 8 different positions).\n/// # Examples\n///\n/// ```\n/// # use tui::widgets::{Block, Borders};\n/// # use tui::layout::Rect;\n/// # use tui::widgets::canvas::{Canvas, Shape, Line, Rectangle, Map, MapResolution};\n/// # use tui::style::Color;\n/// Canvas::default()\n///     .block(Block::default().title(\"Canvas\").borders(Borders::ALL))\n///     .x_bounds([-180.0, 180.0])\n///     .y_bounds([-90.0, 90.0])\n///     .paint(|ctx| {\n///         ctx.draw(&Map {\n///             resolution: MapResolution::High,\n///             color: Color::White\n///         });\n///         ctx.layer();\n///         ctx.draw(&Line {\n///             x1: 0.0,\n///             y1: 10.0,\n///             x2: 10.0,\n///             y2: 10.0,\n///             color: Color::White,\n///         });\n///         ctx.draw(&Rectangle {\n///             x: 10.0,\n///             y: 20.0,\n///             width: 10.0,\n///             height: 10.0,\n///             color: Color::Red\n///         });\n///     });\n/// ```\npub struct Canvas<'a, F>\nwhere\n    F: Fn(&mut Context),\n{\n    block: Option<Block<'a>>,\n    x_bounds: [f64; 2],\n    y_bounds: [f64; 2],\n    painter: Option<F>,\n    background_color: Color,\n    marker: symbols::Marker,\n}\n\nimpl<'a, F> Default for Canvas<'a, F>\nwhere\n    F: Fn(&mut Context),\n{\n    fn default() -> Canvas<'a, F> {\n        Canvas {\n            block: None,\n            x_bounds: [0.0, 0.0],\n            y_bounds: [0.0, 0.0],\n            painter: None,\n            background_color: Color::Reset,\n            marker: symbols::Marker::Braille,\n        }\n    }\n}\n\nimpl<'a, F> Canvas<'a, F>\nwhere\n    F: Fn(&mut Context),\n{\n    pub fn block(mut self, block: Block<'a>) -> Canvas<'a, F> {\n        self.block = Some(block);\n        self\n    }\n\n    pub fn x_bounds(mut self, bounds: [f64; 2]) -> Canvas<'a, F> {\n        self.x_bounds = bounds;\n        self\n    }\n\n    pub fn y_bounds(mut self, bounds: [f64; 2]) -> Canvas<'a, F> {\n        self.y_bounds = bounds;\n        self\n    }\n\n    /// Store the closure that will be used to draw to the Canvas\n    pub fn paint(mut self, f: F) -> Canvas<'a, F> {\n        self.painter = Some(f);\n        self\n    }\n\n    pub fn background_color(mut self, color: Color) -> Canvas<'a, F> {\n        self.background_color = color;\n        self\n    }\n\n    /// Change the type of points used to draw the shapes. By default the braille patterns are used\n    /// as they provide a more fine grained result but you might want to use the simple dot or\n    /// block instead if the targeted terminal does not support those symbols.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tui::widgets::canvas::Canvas;\n    /// # use tui::symbols;\n    /// Canvas::default().marker(symbols::Marker::Braille).paint(|ctx| {});\n    ///\n    /// Canvas::default().marker(symbols::Marker::Dot).paint(|ctx| {});\n    ///\n    /// Canvas::default().marker(symbols::Marker::Block).paint(|ctx| {});\n    /// ```\n    pub fn marker(mut self, marker: symbols::Marker) -> Canvas<'a, F> {\n        self.marker = marker;\n        self\n    }\n}\n\nimpl<'a, F> Widget for Canvas<'a, F>\nwhere\n    F: Fn(&mut Context),\n{\n    fn render(mut self, area: Rect, buf: &mut Buffer) {\n        let canvas_area = match self.block.take() {\n            Some(b) => {\n                let inner_area = b.inner(area);\n                b.render(area, buf);\n                inner_area\n            }\n            None => area,\n        };\n\n        buf.set_style(canvas_area, Style::default().bg(self.background_color));\n\n        let width = canvas_area.width as usize;\n\n        let painter = match self.painter {\n            Some(ref p) => p,\n            None => return,\n        };\n\n        // Create a blank context that match the size of the canvas\n        let mut ctx = Context::new(\n            canvas_area.width,\n            canvas_area.height,\n            self.x_bounds,\n            self.y_bounds,\n            self.marker,\n        );\n        // Paint to this context\n        painter(&mut ctx);\n        ctx.finish();\n\n        // Retreive painted points for each layer\n        for layer in ctx.layers {\n            for (i, (ch, color)) in layer\n                .string\n                .chars()\n                .zip(layer.colors.into_iter())\n                .enumerate()\n            {\n                if ch != ' ' && ch != '\\u{2800}' {\n                    let (x, y) = (i % width, i / width);\n                    buf.get_mut(x as u16 + canvas_area.left(), y as u16 + canvas_area.top())\n                        .set_char(ch)\n                        .set_fg(color);\n                }\n            }\n        }\n\n        // Finally draw the labels\n        let left = self.x_bounds[0];\n        let right = self.x_bounds[1];\n        let top = self.y_bounds[1];\n        let bottom = self.y_bounds[0];\n        let width = (self.x_bounds[1] - self.x_bounds[0]).abs();\n        let height = (self.y_bounds[1] - self.y_bounds[0]).abs();\n        let resolution = {\n            let width = f64::from(canvas_area.width - 1);\n            let height = f64::from(canvas_area.height - 1);\n            (width, height)\n        };\n        for label in ctx\n            .labels\n            .iter()\n            .filter(|l| l.x >= left && l.x <= right && l.y <= top && l.y >= bottom)\n        {\n            let x = ((label.x - left) * resolution.0 / width) as u16 + canvas_area.left();\n            let y = ((top - label.y) * resolution.1 / height) as u16 + canvas_area.top();\n            buf.set_spans(x, y, &label.spans, canvas_area.right() - x);\n        }\n    }\n}\n"
  },
  {
    "path": "src/widgets/canvas/points.rs",
    "content": "use crate::{\n    style::Color,\n    widgets::canvas::{Painter, Shape},\n};\n\n/// A shape to draw a group of points with the given color\n#[derive(Debug, Clone)]\npub struct Points<'a> {\n    pub coords: &'a [(f64, f64)],\n    pub color: Color,\n}\n\nimpl<'a> Shape for Points<'a> {\n    fn draw(&self, painter: &mut Painter) {\n        for (x, y) in self.coords {\n            if let Some((x, y)) = painter.get_point(*x, *y) {\n                painter.paint(x, y, self.color);\n            }\n        }\n    }\n}\n\nimpl<'a> Default for Points<'a> {\n    fn default() -> Points<'a> {\n        Points {\n            coords: &[],\n            color: Color::Reset,\n        }\n    }\n}\n"
  },
  {
    "path": "src/widgets/canvas/rectangle.rs",
    "content": "use crate::{\n    style::Color,\n    widgets::canvas::{Line, Painter, Shape},\n};\n\n/// Shape to draw a rectangle from a `Rect` with the given color\n#[derive(Debug, Clone)]\npub struct Rectangle {\n    pub x: f64,\n    pub y: f64,\n    pub width: f64,\n    pub height: f64,\n    pub color: Color,\n}\n\nimpl Shape for Rectangle {\n    fn draw(&self, painter: &mut Painter) {\n        let lines: [Line; 4] = [\n            Line {\n                x1: self.x,\n                y1: self.y,\n                x2: self.x,\n                y2: self.y + self.height,\n                color: self.color,\n            },\n            Line {\n                x1: self.x,\n                y1: self.y + self.height,\n                x2: self.x + self.width,\n                y2: self.y + self.height,\n                color: self.color,\n            },\n            Line {\n                x1: self.x + self.width,\n                y1: self.y,\n                x2: self.x + self.width,\n                y2: self.y + self.height,\n                color: self.color,\n            },\n            Line {\n                x1: self.x,\n                y1: self.y,\n                x2: self.x + self.width,\n                y2: self.y,\n                color: self.color,\n            },\n        ];\n        for line in &lines {\n            line.draw(painter);\n        }\n    }\n}\n"
  },
  {
    "path": "src/widgets/canvas/world.rs",
    "content": "/// [Source data](http://www.gnuplotting.org/plotting-the-world-revisited)\n\npub static WORLD_HIGH_RESOLUTION: [(f64, f64); 5125] = [\n    (-163.7128, -78.5956),\n    (-163.1058, -78.2233),\n    (-161.2451, -78.3801),\n    (-160.2462, -78.6936),\n    (-159.4824, -79.0463),\n    (-159.2081, -79.4970),\n    (-161.1276, -79.6342),\n    (-162.4398, -79.2814),\n    (-163.0274, -78.9287),\n    (-163.0666, -78.8699),\n    (-163.7128, -78.5956),\n    (-6.1978, 53.8675),\n    (-6.0329, 53.1531),\n    (-6.7888, 52.2601),\n    (-8.5616, 51.6693),\n    (-9.9770, 51.8204),\n    (-9.1662, 52.8646),\n    (-9.6885, 53.8813),\n    (-8.3279, 54.6645),\n    (-7.5721, 55.1316),\n    (-6.7338, 55.1728),\n    (-5.6619, 54.5546),\n    (-6.1978, 53.8675),\n    (141.0002, -2.6001),\n    (142.7352, -3.2891),\n    (144.5839, -3.8614),\n    (145.2731, -4.3737),\n    (145.8297, -4.8764),\n    (145.9819, -5.4656),\n    (147.6480, -6.0836),\n    (147.8911, -6.6140),\n    (146.9709, -6.7216),\n    (147.1918, -7.3880),\n    (148.0846, -8.0441),\n    (148.7341, -9.1046),\n    (149.3068, -9.0714),\n    (149.2666, -9.5144),\n    (150.0387, -9.6843),\n    (149.7387, -9.8729),\n    (150.8016, -10.2936),\n    (150.6905, -10.5827),\n    (150.0283, -10.6524),\n    (149.7823, -10.3932),\n    (148.9231, -10.2809),\n    (147.9130, -10.1304),\n    (147.1354, -9.4924),\n    (146.5678, -8.9425),\n    (146.0484, -8.0674),\n    (144.7441, -7.6301),\n    (143.8970, -7.9153),\n    (143.2863, -8.2454),\n    (143.4139, -8.9830),\n    (142.6284, -9.3268),\n    (142.0682, -9.1595),\n    (141.0338, -9.1178),\n    (140.1434, -8.2971),\n    (139.1277, -8.0960),\n    (138.8814, -8.3809),\n    (137.6144, -8.4116),\n    (138.0390, -7.5978),\n    (138.6686, -7.3202),\n    (138.4079, -6.2328),\n    (137.9278, -5.3933),\n    (135.9892, -4.5465),\n    (135.1645, -4.4629),\n    (133.6628, -3.5388),\n    (133.3677, -4.0248),\n    (132.9839, -4.1129),\n    (132.7569, -3.7462),\n    (132.7537, -3.3117),\n    (131.9898, -2.8205),\n    (133.0668, -2.4604),\n    (133.7800, -2.4798),\n    (133.6962, -2.2145),\n    (132.2323, -2.2125),\n    (131.8362, -1.6171),\n    (130.9428, -1.4325),\n    (130.5195, -0.9377),\n    (131.8675, -0.6954),\n    (132.3801, -0.3695),\n    (133.9855, -0.7802),\n    (134.1433, -1.1518),\n    (134.4226, -2.7691),\n    (135.4576, -3.3677),\n    (136.2933, -2.3070),\n    (137.4407, -1.7035),\n    (138.3297, -1.7026),\n    (139.1849, -2.0512),\n    (139.9266, -2.4089),\n    (141.0002, -2.6001),\n    (114.2040, 4.5258),\n    (114.5999, 4.9000),\n    (115.4507, 5.4477),\n    (116.2207, 6.1431),\n    (116.7251, 6.9247),\n    (117.1296, 6.9280),\n    (117.6433, 6.4221),\n    (117.6890, 5.9874),\n    (118.3476, 5.7086),\n    (119.1819, 5.4078),\n    (119.1106, 5.0161),\n    (118.4397, 4.9665),\n    (118.6183, 4.4782),\n    (117.8820, 4.1375),\n    (117.3132, 3.2344),\n    (118.0483, 2.2876),\n    (117.8756, 1.8276),\n    (118.9967, 0.9022),\n    (117.8118, 0.7842),\n    (117.4783, 0.1024),\n    (117.5216, -0.8037),\n    (116.5600, -1.4876),\n    (116.5337, -2.4835),\n    (116.1480, -4.0127),\n    (116.0008, -3.6570),\n    (114.8648, -4.1069),\n    (114.4686, -3.4957),\n    (113.7556, -3.4391),\n    (113.2569, -3.1187),\n    (112.0681, -3.4783),\n    (111.7032, -2.9944),\n    (111.0482, -3.0494),\n    (110.2238, -2.9340),\n    (110.0709, -1.5928),\n    (109.5719, -1.3149),\n    (109.0918, -0.4595),\n    (108.9526, 0.4153),\n    (109.0691, 1.3419),\n    (109.6632, 2.0064),\n    (110.3961, 1.6637),\n    (111.1688, 1.8506),\n    (111.3700, 2.6973),\n    (111.7969, 2.8858),\n    (112.9956, 3.1023),\n    (113.7129, 3.8935),\n    (114.2040, 4.5258),\n    (-93.6127, 74.9799),\n    (-94.1569, 74.5923),\n    (-95.6086, 74.6668),\n    (-96.8209, 74.9276),\n    (-96.2885, 75.3778),\n    (-94.8508, 75.6472),\n    (-93.9777, 75.2964),\n    (-93.6127, 74.9799),\n    (-93.8400, 77.5199),\n    (-94.2956, 77.4913),\n    (-96.1696, 77.5551),\n    (-96.4363, 77.8346),\n    (-94.4225, 77.8200),\n    (-93.7206, 77.6343),\n    (-93.8400, 77.5199),\n    (-96.7543, 78.7658),\n    (-95.5592, 78.4183),\n    (-95.8302, 78.0569),\n    (-97.3098, 77.8505),\n    (-98.1242, 78.0828),\n    (-98.5528, 78.4581),\n    (-98.6319, 78.8719),\n    (-97.3372, 78.8319),\n    (-96.7543, 78.7658),\n    (-88.1503, 74.3923),\n    (-89.7647, 74.5155),\n    (-92.4224, 74.8377),\n    (-92.7682, 75.3868),\n    (-92.8899, 75.8826),\n    (-93.8938, 76.3192),\n    (-95.9624, 76.4413),\n    (-97.1213, 76.7510),\n    (-96.7451, 77.1613),\n    (-94.6840, 77.0978),\n    (-93.5739, 76.7762),\n    (-91.6050, 76.7785),\n    (-90.7418, 76.4495),\n    (-90.9696, 76.0740),\n    (-89.8222, 75.8477),\n    (-89.1870, 75.6101),\n    (-87.8382, 75.5661),\n    (-86.3791, 75.4824),\n    (-84.7896, 75.6992),\n    (-82.7534, 75.7843),\n    (-81.1285, 75.7139),\n    (-80.0575, 75.3368),\n    (-79.8339, 74.9231),\n    (-80.4577, 74.6573),\n    (-81.9488, 74.4424),\n    (-83.2288, 74.5640),\n    (-86.0974, 74.4100),\n    (-88.1503, 74.3923),\n    (-111.2644, 78.1529),\n    (-109.8544, 77.9963),\n    (-110.1869, 77.6970),\n    (-112.0511, 77.4092),\n    (-113.5342, 77.7322),\n    (-112.7245, 78.0510),\n    (-111.2644, 78.1529),\n    (-110.9636, 78.8044),\n    (-109.6631, 78.6019),\n    (-110.8813, 78.4069),\n    (-112.5420, 78.4079),\n    (-112.5258, 78.5505),\n    (-111.5000, 78.8499),\n    (-110.9636, 78.8044),\n    (-66.2824, 18.5147),\n    (-65.7713, 18.4266),\n    (-65.5910, 18.2280),\n    (-65.8471, 17.9759),\n    (-66.5999, 17.9818),\n    (-67.1841, 17.9465),\n    (-67.2424, 18.3744),\n    (-67.1006, 18.5206),\n    (-66.2824, 18.5147),\n    (-77.5696, 18.4905),\n    (-76.8966, 18.4008),\n    (-76.3653, 18.1607),\n    (-76.1996, 17.8868),\n    (-76.9025, 17.8682),\n    (-77.2063, 17.7011),\n    (-77.7660, 17.8615),\n    (-78.3377, 18.2259),\n    (-78.2177, 18.4545),\n    (-77.7973, 18.5242),\n    (-77.5696, 18.4905),\n    (-82.2681, 23.1886),\n    (-81.4044, 23.1172),\n    (-80.6187, 23.1060),\n    (-79.6795, 22.7653),\n    (-79.2814, 22.3992),\n    (-78.3474, 22.5121),\n    (-77.9932, 22.2771),\n    (-77.1464, 21.6578),\n    (-76.5238, 21.2068),\n    (-76.1946, 21.2205),\n    (-75.5982, 21.0166),\n    (-75.6710, 20.7350),\n    (-74.9338, 20.6939),\n    (-74.1780, 20.2846),\n    (-74.2966, 20.0503),\n    (-74.9615, 19.9234),\n    (-75.6346, 19.8737),\n    (-76.3236, 19.9528),\n    (-77.7554, 19.8554),\n    (-77.0851, 20.4133),\n    (-77.4926, 20.6731),\n    (-78.1372, 20.7399),\n    (-78.4828, 21.0286),\n    (-78.7198, 21.5981),\n    (-79.2849, 21.5591),\n    (-80.2174, 21.8273),\n    (-80.5175, 22.0370),\n    (-81.8209, 22.1920),\n    (-82.1699, 22.3871),\n    (-81.7950, 22.6369),\n    (-82.7758, 22.6881),\n    (-83.4944, 22.1685),\n    (-83.9088, 22.1545),\n    (-84.0521, 21.9105),\n    (-84.5470, 21.8012),\n    (-84.9749, 21.8960),\n    (-84.4470, 22.2049),\n    (-84.2303, 22.5657),\n    (-83.7782, 22.7881),\n    (-83.2675, 22.9830),\n    (-82.5104, 23.0787),\n    (-82.2681, 23.1886),\n    (-55.6002, 51.3170),\n    (-56.1340, 50.6870),\n    (-56.7958, 49.8123),\n    (-56.1431, 50.1501),\n    (-55.4714, 49.9358),\n    (-55.8224, 49.5871),\n    (-54.9351, 49.3130),\n    (-54.4737, 49.5566),\n    (-53.4765, 49.2491),\n    (-53.7860, 48.5167),\n    (-53.0861, 48.6878),\n    (-52.9586, 48.1571),\n    (-52.6480, 47.5355),\n    (-53.0691, 46.6554),\n    (-53.5214, 46.6182),\n    (-54.1789, 46.8070),\n    (-53.9618, 47.6252),\n    (-54.2404, 47.7522),\n    (-55.4007, 46.8849),\n    (-55.9974, 46.9197),\n    (-55.2912, 47.3895),\n    (-56.2507, 47.6325),\n    (-57.3252, 47.5728),\n    (-59.2660, 47.6033),\n    (-59.4194, 47.8994),\n    (-58.7965, 48.2515),\n    (-59.2316, 48.5231),\n    (-58.3918, 49.1255),\n    (-57.3586, 50.7182),\n    (-56.7386, 51.2874),\n    (-55.8709, 51.6320),\n    (-55.4069, 51.5882),\n    (-55.6002, 51.3170),\n    (-83.8826, 65.1096),\n    (-82.7875, 64.7666),\n    (-81.6420, 64.4551),\n    (-81.5534, 63.9796),\n    (-80.8173, 64.0574),\n    (-80.1034, 63.7259),\n    (-80.9910, 63.4112),\n    (-82.5471, 63.6517),\n    (-83.1087, 64.1018),\n    (-84.1004, 63.5697),\n    (-85.5234, 63.0523),\n    (-85.8667, 63.6372),\n    (-87.2219, 63.5412),\n    (-86.3527, 64.0358),\n    (-86.2248, 64.8229),\n    (-85.8838, 65.7387),\n    (-85.1613, 65.6572),\n    (-84.9757, 65.2175),\n    (-84.4640, 65.3717),\n    (-83.8826, 65.1096),\n    (-78.7706, 72.3521),\n    (-77.8246, 72.7496),\n    (-75.6058, 72.2436),\n    (-74.2286, 71.7671),\n    (-74.0991, 71.3308),\n    (-72.2422, 71.5569),\n    (-71.2000, 70.9200),\n    (-68.7860, 70.5250),\n    (-67.9149, 70.1219),\n    (-66.9690, 69.1860),\n    (-68.8051, 68.7201),\n    (-66.4498, 68.0671),\n    (-64.8623, 67.8475),\n    (-63.4249, 66.9284),\n    (-61.8519, 66.8621),\n    (-62.1631, 66.1602),\n    (-63.9184, 64.9986),\n    (-65.1488, 65.4260),\n    (-66.7212, 66.3880),\n    (-68.0150, 66.2627),\n    (-68.1412, 65.6897),\n    (-67.0896, 65.1084),\n    (-65.7320, 64.6484),\n    (-65.3201, 64.3827),\n    (-64.6694, 63.3929),\n    (-65.0138, 62.6741),\n    (-66.2750, 62.9450),\n    (-68.7831, 63.7456),\n    (-67.3696, 62.8839),\n    (-66.3282, 62.2800),\n    (-66.1655, 61.9308),\n    (-68.8773, 62.3301),\n    (-71.0234, 62.9107),\n    (-72.2353, 63.3978),\n    (-71.8862, 63.6799),\n    (-73.3783, 64.1939),\n    (-74.8344, 64.6791),\n    (-74.8185, 64.3890),\n    (-77.7099, 64.2295),\n    (-78.5559, 64.5729),\n    (-77.8972, 65.3091),\n    (-76.0182, 65.3269),\n    (-73.9597, 65.4547),\n    (-74.2938, 65.8117),\n    (-73.9449, 66.3105),\n    (-72.6511, 67.2845),\n    (-72.9260, 67.7269),\n    (-73.3116, 68.0694),\n    (-74.8433, 68.5546),\n    (-76.8691, 68.8947),\n    (-76.2286, 69.1477),\n    (-77.2873, 69.7695),\n    (-78.1686, 69.8264),\n    (-78.9572, 70.1668),\n    (-79.4924, 69.8718),\n    (-81.3054, 69.7431),\n    (-84.9447, 69.9666),\n    (-87.0600, 70.2600),\n    (-88.6817, 70.4107),\n    (-89.5134, 70.7620),\n    (-88.4677, 71.2181),\n    (-89.8881, 71.2225),\n    (-90.2051, 72.2350),\n    (-89.4365, 73.1294),\n    (-88.4082, 73.5378),\n    (-85.8261, 73.8038),\n    (-86.5621, 73.1574),\n    (-85.7743, 72.5341),\n    (-84.8501, 73.3402),\n    (-82.3155, 73.7509),\n    (-80.6000, 72.7165),\n    (-80.7489, 72.0619),\n    (-78.7706, 72.3521),\n    (-94.5036, 74.1349),\n    (-92.4200, 74.1000),\n    (-90.5097, 73.8567),\n    (-92.0039, 72.9662),\n    (-93.1962, 72.7719),\n    (-94.2690, 72.0245),\n    (-95.4098, 72.0618),\n    (-96.0337, 72.9402),\n    (-96.0182, 73.4374),\n    (-95.4957, 73.8624),\n    (-94.5036, 74.1349),\n    (-100.4383, 72.7058),\n    (-101.54, 73.36),\n    (-100.3564, 73.8438),\n    (-99.1638, 73.6333),\n    (-97.38, 73.76),\n    (-97.12, 73.47),\n    (-98.0535, 72.9905),\n    (-96.54, 72.56),\n    (-96.72, 71.66),\n    (-98.3596, 71.2728),\n    (-99.3228, 71.3563),\n    (-100.0148, 71.7382),\n    (-102.48, 72.4829),\n    (-102.48, 72.83),\n    (-100.4383, 72.7058),\n    (-107.8194, 75.8455),\n    (-106.9289, 76.0128),\n    (-105.8809, 75.9693),\n    (-105.7049, 75.4795),\n    (-106.3134, 75.0052),\n    (-109.6999, 74.8500),\n    (-112.2230, 74.4169),\n    (-113.7438, 74.3942),\n    (-113.8713, 74.7202),\n    (-111.7942, 75.1624),\n    (-116.3121, 75.0434),\n    (-117.7104, 75.2222),\n    (-116.3460, 76.1990),\n    (-115.4048, 76.4788),\n    (-112.5905, 76.1413),\n    (-110.8142, 75.5491),\n    (-109.0671, 75.4732),\n    (-110.4972, 76.4298),\n    (-109.5811, 76.7941),\n    (-108.5485, 76.6783),\n    (-108.2114, 76.2016),\n    (-107.8194, 75.8455),\n    (-122.8549, 76.1165),\n    (-121.1575, 76.8645),\n    (-119.1039, 77.5122),\n    (-117.5701, 77.4983),\n    (-116.1985, 77.6452),\n    (-116.3358, 76.8769),\n    (-117.1060, 76.5300),\n    (-118.0404, 76.4811),\n    (-119.8993, 76.0532),\n    (-121.4999, 75.9000),\n    (-122.8549, 76.1165),\n    (-121.5378, 74.4489),\n    (-120.1097, 74.2413),\n    (-117.5556, 74.1857),\n    (-116.5844, 73.8960),\n    (-115.5107, 73.4752),\n    (-116.7679, 73.2229),\n    (-119.22, 72.52),\n    (-120.46, 71.82),\n    (-120.46, 71.3836),\n    (-123.0921, 70.9016),\n    (-123.62, 71.34),\n    (-125.9289, 71.8686),\n    (-125.5, 72.2922),\n    (-124.8072, 73.0225),\n    (-123.94, 73.68),\n    (-124.9177, 74.2927),\n    (-121.5378, 74.4489),\n    (-166.4677, 60.3841),\n    (-165.6744, 60.2936),\n    (-165.5791, 59.9099),\n    (-166.1927, 59.7544),\n    (-166.8483, 59.9414),\n    (-167.4552, 60.2130),\n    (-166.4677, 60.3841),\n    (-153.2287, 57.9690),\n    (-152.5647, 57.9014),\n    (-152.1411, 57.5910),\n    (-153.0063, 57.1158),\n    (-154.0050, 56.7346),\n    (-154.5164, 56.9927),\n    (-154.6709, 57.4611),\n    (-153.7627, 57.8165),\n    (-153.2287, 57.9690),\n    (-132.7100, 54.0400),\n    (-131.7499, 54.1200),\n    (-132.0494, 52.9846),\n    (-131.1790, 52.1804),\n    (-131.5778, 52.1823),\n    (-132.1804, 52.6397),\n    (-132.5499, 53.1000),\n    (-133.0546, 53.4114),\n    (-133.2396, 53.8510),\n    (-133.1800, 54.1699),\n    (-132.7100, 54.0400),\n    (-125.4150, 49.9500),\n    (-124.9207, 49.4752),\n    (-123.9225, 49.0624),\n    (-123.5100, 48.5100),\n    (-124.0128, 48.3708),\n    (-125.6550, 48.8250),\n    (-125.9549, 49.1799),\n    (-126.8500, 49.5300),\n    (-127.0299, 49.8149),\n    (-128.0593, 49.9949),\n    (-128.4445, 50.5391),\n    (-128.3584, 50.7706),\n    (-127.3085, 50.5525),\n    (-126.6950, 50.4009),\n    (-125.7550, 50.2950),\n    (-125.4150, 49.9500),\n    (-171.7316, 63.7825),\n    (-171.1144, 63.5921),\n    (-170.4911, 63.6949),\n    (-169.6825, 63.4311),\n    (-168.6894, 63.2975),\n    (-168.7719, 63.1885),\n    (-169.5294, 62.9769),\n    (-170.2905, 63.1944),\n    (-170.6713, 63.3758),\n    (-171.5530, 63.3177),\n    (-171.7911, 63.4058),\n    (-171.7316, 63.7825),\n    (-105.4922, 79.3015),\n    (-103.5292, 79.1653),\n    (-100.8251, 78.8004),\n    (-100.0601, 78.3247),\n    (-99.6709, 77.9075),\n    (-101.3039, 78.0189),\n    (-102.9498, 78.3432),\n    (-105.1761, 78.3803),\n    (-104.2104, 78.6774),\n    (-105.4195, 78.9183),\n    (-105.4922, 79.3015),\n    (32.9469, 35.3867),\n    (33.6672, 35.3732),\n    (34.5764, 35.6715),\n    (33.9008, 35.2457),\n    (34.0048, 34.9780),\n    (32.9798, 34.5718),\n    (32.4902, 34.7016),\n    (32.2566, 35.1032),\n    (32.8024, 35.1455),\n    (32.9469, 35.3867),\n    (26.2900, 35.2999),\n    (26.1649, 35.0049),\n    (24.7249, 34.9199),\n    (24.7350, 35.0849),\n    (23.5149, 35.2799),\n    (23.6999, 35.7050),\n    (24.2466, 35.3680),\n    (25.0250, 35.4249),\n    (25.7692, 35.3540),\n    (25.7450, 35.1799),\n    (26.2900, 35.2999),\n    (49.5435, -12.4698),\n    (49.8089, -12.8952),\n    (50.0565, -13.5557),\n    (50.2174, -14.7587),\n    (50.4765, -15.2265),\n    (50.3771, -15.7060),\n    (50.2002, -16.0002),\n    (49.8606, -15.4142),\n    (49.6726, -15.7101),\n    (49.8633, -16.4510),\n    (49.7745, -16.8750),\n    (49.4986, -17.1060),\n    (49.4356, -17.9530),\n    (49.0417, -19.1187),\n    (48.5485, -20.4968),\n    (47.9307, -22.3915),\n    (47.5477, -23.7819),\n    (47.0957, -24.9416),\n    (46.2824, -25.1784),\n    (45.4095, -25.6014),\n    (44.8335, -25.3461),\n    (44.0397, -24.9883),\n    (43.7637, -24.4606),\n    (43.6977, -23.5741),\n    (43.3456, -22.7769),\n    (43.2541, -22.0574),\n    (43.4332, -21.3364),\n    (43.8936, -21.1633),\n    (43.8963, -20.8304),\n    (44.3743, -20.0723),\n    (44.4643, -19.4354),\n    (44.2324, -18.9619),\n    (44.0429, -18.3313),\n    (43.9630, -17.4099),\n    (44.3124, -16.8504),\n    (44.4465, -16.2162),\n    (44.9449, -16.1793),\n    (45.5027, -15.9743),\n    (45.8729, -15.7934),\n    (46.3122, -15.7800),\n    (46.8821, -15.2101),\n    (47.7051, -14.5943),\n    (48.0052, -14.0912),\n    (47.8689, -13.6638),\n    (48.2938, -13.7840),\n    (48.8450, -13.0891),\n    (48.8635, -12.4878),\n    (49.1946, -12.0405),\n    (49.5435, -12.4698),\n    (167.2168, -15.8918),\n    (167.8448, -16.4663),\n    (167.5151, -16.5978),\n    (167.1800, -16.1599),\n    (167.2168, -15.8918),\n    (166.7931, -15.6688),\n    (166.6498, -15.3927),\n    (166.6291, -14.6264),\n    (167.1077, -14.9339),\n    (167.2700, -15.7400),\n    (167.0012, -15.6146),\n    (166.7931, -15.6688),\n    (134.2101, -6.8952),\n    (134.1127, -6.1424),\n    (134.2903, -5.7830),\n    (134.4996, -5.4450),\n    (134.7270, -5.7375),\n    (134.7246, -6.2144),\n    (134.2101, -6.8952),\n    (-48.6606, -78.0470),\n    (-48.1513, -78.0470),\n    (-46.6628, -77.8314),\n    (-45.1547, -78.0470),\n    (-43.9208, -78.4781),\n    (-43.4899, -79.0855),\n    (-43.3724, -79.5166),\n    (-43.3332, -80.0261),\n    (-44.8805, -80.3396),\n    (-46.5061, -80.5943),\n    (-48.3864, -80.8294),\n    (-50.4821, -81.0254),\n    (-52.8519, -80.9666),\n    (-54.1642, -80.6335),\n    (-53.9879, -80.2220),\n    (-51.8531, -79.9477),\n    (-50.9913, -79.6146),\n    (-50.3645, -79.1834),\n    (-49.9141, -78.8112),\n    (-49.3069, -78.4585),\n    (-48.6606, -78.0470),\n    (-66.2900, -80.2557),\n    (-64.0376, -80.2948),\n    (-61.8832, -80.3928),\n    (-61.1389, -79.9813),\n    (-60.6101, -79.6286),\n    (-59.5720, -80.0401),\n    (-59.8658, -80.5496),\n    (-60.1596, -81.0003),\n    (-62.2553, -80.8631),\n    (-64.4881, -80.9219),\n    (-65.7416, -80.5888),\n    (-65.7416, -80.5496),\n    (-66.2900, -80.2557),\n    (-73.9158, -71.2693),\n    (-73.2303, -71.1517),\n    (-72.0747, -71.1909),\n    (-71.7809, -70.6814),\n    (-71.7221, -70.3091),\n    (-71.7417, -69.5057),\n    (-71.1738, -69.0354),\n    (-70.2532, -68.8787),\n    (-69.7244, -69.2510),\n    (-69.4894, -69.6233),\n    (-69.0585, -70.0740),\n    (-68.7255, -70.5051),\n    (-68.4513, -70.9558),\n    (-68.3338, -71.4064),\n    (-68.5101, -71.7984),\n    (-68.7842, -72.1706),\n    (-69.9594, -72.3078),\n    (-71.0758, -72.5038),\n    (-72.3881, -72.4842),\n    (-71.8984, -72.0923),\n    (-73.0736, -72.2294),\n    (-74.1900, -72.3666),\n    (-74.9538, -72.0727),\n    (-75.0126, -71.6612),\n    (-73.9158, -71.2693),\n    (-102.3307, -71.8941),\n    (-101.7039, -71.7177),\n    (-100.4309, -71.8549),\n    (-98.9815, -71.9333),\n    (-97.8847, -72.0705),\n    (-96.7879, -71.9529),\n    (-96.2003, -72.5212),\n    (-96.9837, -72.4428),\n    (-98.1980, -72.4820),\n    (-99.4320, -72.4428),\n    (-100.7834, -72.5016),\n    (-101.8018, -72.3056),\n    (-102.3307, -71.8941),\n    (-122.6217, -73.6577),\n    (-122.4062, -73.3246),\n    (-121.2115, -73.5009),\n    (-119.9188, -73.6577),\n    (-118.7241, -73.4813),\n    (-119.2921, -73.8340),\n    (-120.2322, -74.0888),\n    (-121.6228, -74.0104),\n    (-122.6217, -73.6577),\n    (-127.2831, -73.4617),\n    (-126.5584, -73.2462),\n    (-125.5595, -73.4813),\n    (-124.0318, -73.8732),\n    (-124.6194, -73.8340),\n    (-125.9121, -73.7361),\n    (-127.2831, -73.4617),\n    (165.7799, -21.0800),\n    (166.5999, -21.7000),\n    (167.1200, -22.1599),\n    (166.7400, -22.3999),\n    (166.1897, -22.1297),\n    (165.4743, -21.6796),\n    (164.8298, -21.1498),\n    (164.1679, -20.4447),\n    (164.0296, -20.1056),\n    (164.4599, -20.1200),\n    (165.0200, -20.4599),\n    (165.4600, -20.8000),\n    (165.7799, -21.0800),\n    (152.6400, -3.6599),\n    (153.0199, -3.9800),\n    (153.1400, -4.4999),\n    (152.8272, -4.7664),\n    (152.6386, -4.1761),\n    (152.4060, -3.7897),\n    (151.9532, -3.4620),\n    (151.3842, -3.0354),\n    (150.6620, -2.7414),\n    (150.9399, -2.5000),\n    (151.4799, -2.7799),\n    (151.8200, -2.9999),\n    (152.2399, -3.2400),\n    (152.6400, -3.6599),\n    (151.3013, -5.8407),\n    (150.7544, -6.0837),\n    (150.2411, -6.3177),\n    (149.7099, -6.3165),\n    (148.8900, -6.0260),\n    (148.3189, -5.7471),\n    (148.4018, -5.4377),\n    (149.2984, -5.5837),\n    (149.8455, -5.5055),\n    (149.9962, -5.0261),\n    (150.1397, -5.0013),\n    (150.2369, -5.5322),\n    (150.8074, -5.4558),\n    (151.0896, -5.1136),\n    (151.6478, -4.7570),\n    (151.5378, -4.1678),\n    (152.1367, -4.1487),\n    (152.3387, -4.3129),\n    (152.3186, -4.8676),\n    (151.9827, -5.4780),\n    (151.4591, -5.5602),\n    (151.3013, -5.8407),\n    (162.1190, -10.4827),\n    (162.3986, -10.8263),\n    (161.7000, -10.8200),\n    (161.3197, -10.2047),\n    (161.9173, -10.4466),\n    (162.1190, -10.4827),\n    (161.6799, -9.5999),\n    (161.5293, -9.7843),\n    (160.7882, -8.9175),\n    (160.5799, -8.3200),\n    (160.9200, -8.3200),\n    (161.2800, -9.1200),\n    (161.6799, -9.5999),\n    (160.8522, -9.8729),\n    (160.4625, -9.8952),\n    (159.8494, -9.7940),\n    (159.6400, -9.6399),\n    (159.7029, -9.2429),\n    (160.3629, -9.4003),\n    (160.6885, -9.6101),\n    (160.8522, -9.8729),\n    (159.6400, -8.0200),\n    (159.8750, -8.3373),\n    (159.9174, -8.5382),\n    (159.1336, -8.1141),\n    (158.5861, -7.7548),\n    (158.2111, -7.4218),\n    (158.3599, -7.3200),\n    (158.8200, -7.5600),\n    (159.6400, -8.0200),\n    (157.1400, -7.0216),\n    (157.5384, -7.3478),\n    (157.3394, -7.4047),\n    (156.9020, -7.1768),\n    (156.4913, -6.7659),\n    (156.5428, -6.5993),\n    (157.1400, -7.0216),\n    (154.7599, -5.3399),\n    (155.0629, -5.5667),\n    (155.5477, -6.2006),\n    (156.0199, -6.5400),\n    (155.8800, -6.8199),\n    (155.5999, -6.9199),\n    (155.1669, -6.5359),\n    (154.7291, -5.9007),\n    (154.5141, -5.1391),\n    (154.6525, -5.0423),\n    (154.7599, -5.3399),\n    (176.8858, -40.0659),\n    (176.5080, -40.6047),\n    (176.0124, -41.2896),\n    (175.2395, -41.6883),\n    (175.0678, -41.4258),\n    (174.6509, -41.2818),\n    (175.2276, -40.4592),\n    (174.9001, -39.9088),\n    (173.8240, -39.5088),\n    (173.8522, -39.1466),\n    (174.5748, -38.7976),\n    (174.7434, -38.0278),\n    (174.6969, -37.3811),\n    (174.2920, -36.7110),\n    (174.3190, -36.5348),\n    (173.8409, -36.1219),\n    (173.0541, -35.2371),\n    (172.6360, -34.5291),\n    (173.0070, -34.4506),\n    (173.5512, -35.0061),\n    (174.3293, -35.2654),\n    (174.6120, -36.1563),\n    (175.3366, -37.2090),\n    (175.3575, -36.5261),\n    (175.8088, -36.7989),\n    (175.9584, -37.5553),\n    (176.7631, -37.8812),\n    (177.4388, -37.9612),\n    (178.0103, -37.5798),\n    (178.5170, -37.6953),\n    (178.2747, -38.5828),\n    (177.9704, -39.1663),\n    (177.2069, -39.1457),\n    (176.9399, -39.4497),\n    (177.0329, -39.8799),\n    (176.8858, -40.0659),\n    (169.6678, -43.5553),\n    (170.5249, -43.0316),\n    (171.1250, -42.5127),\n    (171.5697, -41.7674),\n    (171.9487, -41.5144),\n    (172.0972, -40.9561),\n    (172.7985, -40.4939),\n    (173.0203, -40.9190),\n    (173.2472, -41.3319),\n    (173.9584, -40.9267),\n    (174.2475, -41.3491),\n    (174.2485, -41.7700),\n    (173.8764, -42.2331),\n    (173.2227, -42.9700),\n    (172.7112, -43.3722),\n    (173.0801, -43.8533),\n    (172.3085, -43.8656),\n    (171.4529, -44.2424),\n    (171.1851, -44.8971),\n    (170.6166, -45.9089),\n    (169.8314, -46.3557),\n    (169.3323, -46.6412),\n    (168.4113, -46.6199),\n    (167.7637, -46.2901),\n    (166.6768, -46.2199),\n    (166.5091, -45.8527),\n    (167.0463, -45.1109),\n    (168.3037, -44.1239),\n    (168.9494, -43.9358),\n    (169.6678, -43.5553),\n    (147.6892, -40.8082),\n    (148.2890, -40.8754),\n    (148.3598, -42.0623),\n    (148.0173, -42.4070),\n    (147.9140, -43.2115),\n    (147.5645, -42.9376),\n    (146.8703, -43.6345),\n    (146.6633, -43.5808),\n    (146.0483, -43.5497),\n    (145.4319, -42.6937),\n    (145.2950, -42.0336),\n    (144.7180, -41.1625),\n    (144.7437, -40.7039),\n    (145.3979, -40.7925),\n    (146.3641, -41.1376),\n    (146.9085, -41.0005),\n    (147.6892, -40.8082),\n    (126.1487, -32.2159),\n    (125.0886, -32.7287),\n    (124.2216, -32.9594),\n    (124.0289, -33.4838),\n    (123.6596, -33.8901),\n    (122.8110, -33.9144),\n    (122.1830, -34.0034),\n    (121.2991, -33.8210),\n    (120.5802, -33.9301),\n    (119.8936, -33.9760),\n    (119.2988, -34.5093),\n    (119.0073, -34.4641),\n    (118.5057, -34.7468),\n    (118.0249, -35.0647),\n    (117.2955, -35.0254),\n    (116.6251, -35.0250),\n    (115.5643, -34.3864),\n    (115.0268, -34.1965),\n    (115.0486, -33.6234),\n    (115.5451, -33.4872),\n    (115.7146, -33.2595),\n    (115.6793, -32.9003),\n    (115.8016, -32.2050),\n    (115.6896, -31.6124),\n    (115.1609, -30.6015),\n    (114.9970, -30.0307),\n    (115.0400, -29.4610),\n    (114.6419, -28.8102),\n    (114.6164, -28.5163),\n    (114.1735, -28.1180),\n    (114.0488, -27.3347),\n    (113.4774, -26.5431),\n    (113.3389, -26.1165),\n    (113.7783, -26.5490),\n    (113.4409, -25.6212),\n    (113.9369, -25.9112),\n    (114.2328, -26.2984),\n    (114.2161, -25.7862),\n    (113.7212, -24.9989),\n    (113.6253, -24.6839),\n    (113.3935, -24.3847),\n    (113.5020, -23.8063),\n    (113.7069, -23.5602),\n    (113.8434, -23.0599),\n    (113.7365, -22.4754),\n    (114.1497, -21.7558),\n    (114.2253, -22.5174),\n    (114.6477, -21.8295),\n    (115.4601, -21.4951),\n    (115.9473, -21.0686),\n    (116.7116, -20.7016),\n    (117.1663, -20.6235),\n    (117.4415, -20.7468),\n    (118.2295, -20.3742),\n    (118.8360, -20.2633),\n    (118.9878, -20.0442),\n    (119.2524, -19.9529),\n    (119.8052, -19.9765),\n    (120.8562, -19.6837),\n    (121.3998, -19.2397),\n    (121.6550, -18.7053),\n    (122.2416, -18.1976),\n    (122.2866, -17.7986),\n    (122.3127, -17.2549),\n    (123.0125, -16.4051),\n    (123.4337, -17.2685),\n    (123.8593, -17.0690),\n    (123.5032, -16.5965),\n    (123.8170, -16.1113),\n    (124.2582, -16.3279),\n    (124.3797, -15.5670),\n    (124.9261, -15.0751),\n    (125.1672, -14.6803),\n    (125.6700, -14.5100),\n    (125.6857, -14.2306),\n    (126.1251, -14.3473),\n    (126.1428, -14.0959),\n    (126.5825, -13.9527),\n    (127.0658, -13.8179),\n    (127.8046, -14.2769),\n    (128.3596, -14.8691),\n    (128.9855, -14.8759),\n    (129.6214, -14.9697),\n    (129.4096, -14.4206),\n    (129.8886, -13.6187),\n    (130.3394, -13.3573),\n    (130.1835, -13.1075),\n    (130.6177, -12.5363),\n    (131.2234, -12.1836),\n    (131.7350, -12.3024),\n    (132.5752, -12.1140),\n    (132.5572, -11.6030),\n    (131.8246, -11.2737),\n    (132.3572, -11.1285),\n    (133.0195, -11.3764),\n    (133.5508, -11.7865),\n    (134.3930, -12.0423),\n    (134.6786, -11.9411),\n    (135.2984, -12.2486),\n    (135.8826, -11.9622),\n    (136.2583, -12.0493),\n    (136.4924, -11.8572),\n    (136.9516, -12.3519),\n    (136.6851, -12.8872),\n    (136.3054, -13.2912),\n    (135.9617, -13.3245),\n    (136.0776, -13.7242),\n    (135.7838, -14.2239),\n    (135.4286, -14.7154),\n    (135.5001, -14.9977),\n    (136.2951, -15.5502),\n    (137.0653, -15.8707),\n    (137.5804, -16.2150),\n    (138.3032, -16.8076),\n    (138.5851, -16.8066),\n    (139.1085, -17.0626),\n    (139.2605, -17.3716),\n    (140.2151, -17.7108),\n    (140.8754, -17.3690),\n    (141.0711, -16.8320),\n    (141.2740, -16.3888),\n    (141.3982, -15.8405),\n    (141.7021, -15.0449),\n    (141.5633, -14.5613),\n    (141.6355, -14.2703),\n    (141.5198, -13.6980),\n    (141.6509, -12.9446),\n    (141.8426, -12.7415),\n    (141.6869, -12.4076),\n    (141.9286, -11.8774),\n    (142.1184, -11.3280),\n    (142.1437, -11.0427),\n    (142.5152, -10.6681),\n    (142.7973, -11.1573),\n    (142.8667, -11.7847),\n    (143.1159, -11.9056),\n    (143.1586, -12.3256),\n    (143.5221, -12.8343),\n    (143.5971, -13.4004),\n    (143.5618, -13.7636),\n    (143.9220, -14.5483),\n    (144.5637, -14.1711),\n    (144.8948, -14.5944),\n    (145.3747, -14.9849),\n    (145.2719, -15.4282),\n    (145.4852, -16.2856),\n    (145.6369, -16.7849),\n    (145.8888, -16.9069),\n    (146.1603, -17.7616),\n    (146.0636, -18.2800),\n    (146.3874, -18.9582),\n    (147.4710, -19.4807),\n    (148.1776, -19.9559),\n    (148.8484, -20.3912),\n    (148.7174, -20.6334),\n    (149.2894, -21.2605),\n    (149.6783, -22.3425),\n    (150.0773, -22.1227),\n    (150.4829, -22.5561),\n    (150.7272, -22.4023),\n    (150.8995, -23.4622),\n    (151.6091, -24.0762),\n    (152.0735, -24.4578),\n    (152.8551, -25.2675),\n    (153.1361, -26.0711),\n    (153.1619, -26.6413),\n    (153.0929, -27.2602),\n    (153.5694, -28.1100),\n    (153.5121, -28.9950),\n    (153.3390, -29.4582),\n    (153.0692, -30.3502),\n    (153.0895, -30.9236),\n    (152.8915, -31.6404),\n    (152.4500, -32.5500),\n    (151.7091, -33.0413),\n    (151.3439, -33.8160),\n    (151.0105, -34.3103),\n    (150.7141, -35.1734),\n    (150.3282, -35.6718),\n    (150.0752, -36.4202),\n    (149.9461, -37.1090),\n    (149.9972, -37.4252),\n    (149.4238, -37.7726),\n    (148.3046, -37.8090),\n    (147.3817, -38.2192),\n    (146.9221, -38.6065),\n    (146.3179, -39.0357),\n    (145.4896, -38.5937),\n    (144.8769, -38.4174),\n    (145.0322, -37.8961),\n    (144.4856, -38.0853),\n    (143.6099, -38.8094),\n    (142.7454, -38.5382),\n    (142.1783, -38.3800),\n    (141.6065, -38.3085),\n    (140.6385, -38.0193),\n    (139.9921, -37.4029),\n    (139.8065, -36.6436),\n    (139.5741, -36.1383),\n    (139.0828, -35.7327),\n    (138.1207, -35.6122),\n    (138.4494, -35.1272),\n    (138.2075, -34.3847),\n    (137.7191, -35.0768),\n    (136.8294, -35.2605),\n    (137.3523, -34.7073),\n    (137.5038, -34.1302),\n    (137.8901, -33.6404),\n    (137.8103, -32.9000),\n    (136.9968, -33.7527),\n    (136.3720, -34.0947),\n    (135.9890, -34.8901),\n    (135.2082, -34.4786),\n    (135.2392, -33.9479),\n    (134.6134, -33.2227),\n    (134.0859, -32.8480),\n    (134.2739, -32.6172),\n    (132.9907, -32.0112),\n    (132.2880, -31.9826),\n    (131.3263, -31.4958),\n    (129.5357, -31.5904),\n    (128.2409, -31.9484),\n    (127.1028, -32.2822),\n    (126.1487, -32.2159),\n    (81.7879, 7.5230),\n    (81.6373, 6.4817),\n    (81.2180, 6.1971),\n    (80.3483, 5.9683),\n    (79.8724, 6.7634),\n    (79.6951, 8.2008),\n    (80.1478, 9.8240),\n    (80.8388, 9.2684),\n    (81.3043, 8.5642),\n    (81.7879, 7.5230),\n    (129.3709, -2.8021),\n    (130.4713, -3.0937),\n    (130.8348, -3.8584),\n    (129.9905, -3.4463),\n    (129.1552, -3.3626),\n    (128.5906, -3.4286),\n    (127.8988, -3.3934),\n    (128.1358, -2.8436),\n    (129.3709, -2.8021),\n    (126.8749, -3.7909),\n    (126.1838, -3.6073),\n    (125.9890, -3.1772),\n    (127.0006, -3.1293),\n    (127.2492, -3.4590),\n    (126.8749, -3.7909),\n    (127.9323, 2.1745),\n    (128.0041, 1.6285),\n    (128.5945, 1.5408),\n    (128.6882, 1.1323),\n    (128.6359, 0.2584),\n    (128.1201, 0.3564),\n    (127.9680, -0.2520),\n    (128.3799, -0.7800),\n    (128.1000, -0.8999),\n    (127.6964, -0.2665),\n    (127.3994, 1.0117),\n    (127.6005, 1.8106),\n    (127.9323, 2.1745),\n    (122.9275, 0.8751),\n    (124.0775, 0.9171),\n    (125.0659, 1.6432),\n    (125.2405, 1.4198),\n    (124.4370, 0.4278),\n    (123.6855, 0.2355),\n    (122.7230, 0.4311),\n    (121.0567, 0.3812),\n    (120.1830, 0.2372),\n    (120.0408, -0.5196),\n    (120.9359, -1.4089),\n    (121.4758, -0.9559),\n    (123.3405, -0.6156),\n    (123.2583, -1.0762),\n    (122.8226, -0.9309),\n    (122.3885, -1.5168),\n    (121.5082, -1.9044),\n    (122.4545, -3.1860),\n    (122.2718, -3.5295),\n    (123.1709, -4.6836),\n    (123.1623, -5.3406),\n    (122.6285, -5.6345),\n    (122.2363, -5.2829),\n    (122.7195, -4.4641),\n    (121.7382, -4.8513),\n    (121.4894, -4.5745),\n    (121.6191, -4.1884),\n    (120.8981, -3.6021),\n    (120.9723, -2.6276),\n    (120.3054, -2.9316),\n    (120.3900, -4.0975),\n    (120.4307, -5.5282),\n    (119.7965, -5.6734),\n    (119.3669, -5.3798),\n    (119.6536, -4.4594),\n    (119.4988, -3.4944),\n    (119.0783, -3.4870),\n    (118.7677, -2.8019),\n    (119.1809, -2.1471),\n    (119.3233, -1.3531),\n    (119.8259, 0.1542),\n    (120.0357, 0.5664),\n    (120.8857, 1.3092),\n    (121.6668, 1.0139),\n    (122.9275, 0.8751),\n    (120.2950, -10.2586),\n    (118.9678, -9.5579),\n    (119.9003, -9.3613),\n    (120.4257, -9.6659),\n    (120.7755, -9.9696),\n    (120.7156, -10.2395),\n    (120.2950, -10.2586),\n    (121.3416, -8.5367),\n    (122.0073, -8.4606),\n    (122.9035, -8.0942),\n    (122.7569, -8.6498),\n    (121.2544, -8.9336),\n    (119.9243, -8.8104),\n    (119.9209, -8.4448),\n    (120.7150, -8.2369),\n    (121.3416, -8.5367),\n    (118.2606, -8.3623),\n    (118.8784, -8.2806),\n    (119.1265, -8.7058),\n    (117.9704, -8.9066),\n    (117.2777, -9.0408),\n    (116.7401, -9.0328),\n    (117.0837, -8.4571),\n    (117.6320, -8.4493),\n    (117.9000, -8.0956),\n    (118.2606, -8.3623),\n    (108.4868, -6.4219),\n    (108.6234, -6.7776),\n    (110.5392, -6.8773),\n    (110.7595, -6.4651),\n    (112.6148, -6.9460),\n    (112.9787, -7.5942),\n    (114.4789, -7.7765),\n    (115.7055, -8.3708),\n    (114.5645, -8.7518),\n    (113.4647, -8.3489),\n    (112.5596, -8.3761),\n    (111.5220, -8.3021),\n    (110.5861, -8.1226),\n    (109.4276, -7.7406),\n    (108.6936, -7.6416),\n    (108.2777, -7.7666),\n    (106.4541, -7.3548),\n    (106.2806, -6.9248),\n    (105.3654, -6.8514),\n    (106.0516, -5.8959),\n    (107.2650, -5.9549),\n    (108.0720, -6.3457),\n    (108.4868, -6.4219),\n    (104.3699, -1.0848),\n    (104.5394, -1.7823),\n    (104.8878, -2.3404),\n    (105.6221, -2.4288),\n    (106.1085, -3.0617),\n    (105.8574, -4.3055),\n    (105.8176, -5.8523),\n    (104.7103, -5.8732),\n    (103.8682, -5.0373),\n    (102.5842, -4.2202),\n    (102.1561, -3.6141),\n    (101.3991, -2.7997),\n    (100.9025, -2.0502),\n    (100.1419, -0.6503),\n    (99.2637, 0.1831),\n    (98.9700, 1.0428),\n    (98.6013, 1.8235),\n    (97.6995, 2.4531),\n    (97.1769, 3.3087),\n    (96.4240, 3.8688),\n    (95.3808, 4.9707),\n    (95.2930, 5.4798),\n    (95.9368, 5.4395),\n    (97.4848, 5.2463),\n    (98.3691, 4.2683),\n    (99.1425, 3.5903),\n    (99.6939, 3.1743),\n    (100.6414, 2.0993),\n    (101.6580, 2.0836),\n    (102.4982, 1.3987),\n    (103.0768, 0.5613),\n    (103.8383, 0.1045),\n    (103.4376, -0.7119),\n    (104.0107, -1.0592),\n    (104.3699, -1.0848),\n    (120.8338, 12.7044),\n    (120.3234, 13.4664),\n    (121.1801, 13.4296),\n    (121.5273, 13.0695),\n    (121.2621, 12.2055),\n    (120.8338, 12.7044),\n    (122.5860, 9.9810),\n    (122.8370, 10.2611),\n    (122.9474, 10.8818),\n    (123.4988, 10.9406),\n    (123.3377, 10.2673),\n    (124.0779, 11.2327),\n    (123.9824, 10.2787),\n    (123.6230, 9.9500),\n    (123.3099, 9.3182),\n    (122.9958, 9.0221),\n    (122.3800, 9.7133),\n    (122.5860, 9.9810),\n    (126.3768, 8.4147),\n    (126.4785, 7.7503),\n    (126.5374, 7.1894),\n    (126.1967, 6.2742),\n    (125.8314, 7.2937),\n    (125.3638, 6.7864),\n    (125.6831, 6.0496),\n    (125.3965, 5.5810),\n    (124.2197, 6.1613),\n    (123.9387, 6.8851),\n    (124.2436, 7.3606),\n    (123.6101, 7.8335),\n    (123.2960, 7.4188),\n    (122.8255, 7.4573),\n    (122.0854, 6.8994),\n    (121.9199, 7.1921),\n    (122.3123, 8.0349),\n    (122.9423, 8.3162),\n    (123.4876, 8.6930),\n    (123.8411, 8.2403),\n    (124.6014, 8.5141),\n    (124.7646, 8.9604),\n    (125.4713, 8.9869),\n    (125.4121, 9.7603),\n    (126.2227, 9.2860),\n    (126.3066, 8.7824),\n    (126.3768, 8.4147),\n    (109.4752, 18.1977),\n    (108.6552, 18.5076),\n    (108.6262, 19.3678),\n    (109.1190, 19.8210),\n    (110.2115, 20.1012),\n    (110.7865, 20.0775),\n    (111.0100, 19.6959),\n    (110.5706, 19.2558),\n    (110.3391, 18.6783),\n    (109.4752, 18.1977),\n    (121.7778, 24.3942),\n    (121.1756, 22.7908),\n    (120.7470, 21.9705),\n    (120.2200, 22.8148),\n    (120.1061, 23.5562),\n    (120.6946, 24.5384),\n    (121.4950, 25.2954),\n    (121.9512, 24.9975),\n    (121.7778, 24.3942),\n    (141.8846, 39.1808),\n    (140.9594, 38.1740),\n    (140.9763, 37.1420),\n    (140.5997, 36.3439),\n    (140.7740, 35.8428),\n    (140.2532, 35.1381),\n    (138.9755, 34.6676),\n    (137.2175, 34.6062),\n    (135.7929, 33.4648),\n    (135.1209, 33.8490),\n    (135.0794, 34.5965),\n    (133.3403, 34.3759),\n    (132.1567, 33.9049),\n    (130.9861, 33.8857),\n    (132.0000, 33.1499),\n    (131.3327, 31.4503),\n    (130.6863, 31.0295),\n    (130.2024, 31.4182),\n    (130.4476, 32.3194),\n    (129.8146, 32.6103),\n    (129.4084, 33.2960),\n    (130.3539, 33.6041),\n    (130.8784, 34.2327),\n    (131.8842, 34.7497),\n    (132.6176, 35.4333),\n    (134.6083, 35.7316),\n    (135.6775, 35.5271),\n    (136.7238, 37.3049),\n    (137.3906, 36.8273),\n    (138.8576, 37.8274),\n    (139.4264, 38.2159),\n    (140.0547, 39.4388),\n    (139.8833, 40.5633),\n    (140.3057, 41.1950),\n    (141.3689, 41.3785),\n    (141.9142, 39.9916),\n    (141.8846, 39.1808),\n    (144.6134, 43.9609),\n    (145.3208, 44.3847),\n    (145.5431, 43.2621),\n    (144.0596, 42.9883),\n    (143.1838, 41.9952),\n    (141.6114, 42.6787),\n    (141.0672, 41.5845),\n    (139.9551, 41.5695),\n    (139.8175, 42.5637),\n    (140.3120, 43.3332),\n    (141.3805, 43.3888),\n    (141.6719, 44.7721),\n    (141.9676, 45.5514),\n    (143.1428, 44.5103),\n    (143.9101, 44.1740),\n    (144.6134, 43.9609),\n    (8.7099, 40.8999),\n    (9.2100, 41.2099),\n    (9.8099, 40.5000),\n    (9.6695, 39.1773),\n    (9.2148, 39.2404),\n    (8.8069, 38.9066),\n    (8.4283, 39.1718),\n    (8.3882, 40.3783),\n    (8.1599, 40.9500),\n    (8.7099, 40.8999),\n    (8.7460, 42.6281),\n    (9.3900, 43.0099),\n    (9.5600, 42.1525),\n    (9.2297, 41.3800),\n    (8.7757, 41.5836),\n    (8.5442, 42.2565),\n    (8.7460, 42.6281),\n    (12.3709, 56.1114),\n    (12.6900, 55.6099),\n    (12.0899, 54.8000),\n    (11.0435, 55.3648),\n    (10.9039, 55.7799),\n    (12.3709, 56.1114),\n    (-4.2114, 58.5508),\n    (-3.0050, 58.6350),\n    (-4.0738, 57.5530),\n    (-3.0550, 57.6900),\n    (-1.9592, 57.6847),\n    (-2.2199, 56.8700),\n    (-3.1190, 55.9737),\n    (-2.0850, 55.9099),\n    (-1.1149, 54.6249),\n    (-0.4304, 54.4643),\n    (0.1849, 53.3250),\n    (0.4699, 52.9299),\n    (1.6815, 52.7395),\n    (1.5599, 52.0999),\n    (1.0505, 51.8067),\n    (1.4498, 51.2894),\n    (0.5503, 50.7657),\n    (-0.7875, 50.7749),\n    (-2.4899, 50.5000),\n    (-2.9562, 50.6968),\n    (-3.6174, 50.2283),\n    (-4.5425, 50.3418),\n    (-5.2450, 49.9599),\n    (-5.7765, 50.1596),\n    (-4.3099, 51.2100),\n    (-3.4148, 51.4260),\n    (-4.9843, 51.5934),\n    (-5.2672, 51.9914),\n    (-4.2223, 52.3013),\n    (-4.7700, 52.8400),\n    (-4.5799, 53.4950),\n    (-3.0920, 53.4044),\n    (-2.9450, 53.9849),\n    (-3.6300, 54.6150),\n    (-4.8441, 54.7909),\n    (-5.0825, 55.0616),\n    (-4.7191, 55.5084),\n    (-5.0479, 55.7839),\n    (-5.5863, 55.3111),\n    (-5.6449, 56.2750),\n    (-6.1499, 56.7850),\n    (-5.7868, 57.8188),\n    (-5.0099, 58.6300),\n    (-4.2114, 58.5508),\n    (-14.5086, 66.4558),\n    (-14.7396, 65.8087),\n    (-13.6097, 65.1266),\n    (-14.9098, 64.3640),\n    (-17.7944, 63.6787),\n    (-18.6562, 63.4963),\n    (-19.9727, 63.6436),\n    (-22.7629, 63.9601),\n    (-21.7784, 64.4021),\n    (-23.9550, 64.8911),\n    (-22.1844, 65.0849),\n    (-22.2274, 65.3785),\n    (-24.3261, 65.6111),\n    (-23.6505, 66.2625),\n    (-22.1349, 66.4104),\n    (-20.5762, 65.7321),\n    (-19.0568, 66.2766),\n    (-17.7986, 65.9938),\n    (-16.1678, 66.5268),\n    (-14.5086, 66.4558),\n    (142.9146, 53.7045),\n    (143.2608, 52.7407),\n    (143.2352, 51.7566),\n    (143.6480, 50.7476),\n    (144.6541, 48.9763),\n    (143.1739, 49.3065),\n    (142.5586, 47.8615),\n    (143.5334, 46.8367),\n    (143.5052, 46.1379),\n    (142.7477, 46.7407),\n    (142.0920, 45.9667),\n    (141.9069, 46.8059),\n    (142.0184, 47.7801),\n    (141.9044, 48.8591),\n    (142.1358, 49.6151),\n    (142.1799, 50.9523),\n    (141.5940, 51.9354),\n    (141.6825, 53.3019),\n    (142.6069, 53.7621),\n    (142.2097, 54.2254),\n    (142.6547, 54.3658),\n    (142.9146, 53.7045),\n    (118.5045, 9.3163),\n    (117.1742, 8.3674),\n    (117.6644, 9.0668),\n    (118.3869, 9.6844),\n    (118.9873, 10.3762),\n    (119.5114, 11.3696),\n    (119.6896, 10.5542),\n    (119.0294, 10.0036),\n    (118.5045, 9.3163),\n    (122.3369, 18.2248),\n    (122.1742, 17.8102),\n    (122.5156, 17.0935),\n    (122.2523, 16.2624),\n    (121.6627, 15.9310),\n    (121.5050, 15.1248),\n    (121.7288, 14.3283),\n    (122.2589, 14.2182),\n    (122.7012, 14.3365),\n    (123.9502, 13.7821),\n    (123.8551, 13.2377),\n    (124.1812, 12.9975),\n    (124.0774, 12.5366),\n    (123.2980, 13.0275),\n    (122.9286, 13.5529),\n    (122.6713, 13.1858),\n    (122.0346, 13.7844),\n    (121.1263, 13.6366),\n    (120.6286, 13.8576),\n    (120.6793, 14.2710),\n    (120.9918, 14.5253),\n    (120.6933, 14.7566),\n    (120.5641, 14.3962),\n    (120.0704, 14.9708),\n    (119.9209, 15.4063),\n    (119.8837, 16.3637),\n    (120.2864, 16.0346),\n    (120.3900, 17.5990),\n    (120.7158, 18.5052),\n    (121.3213, 18.5040),\n    (121.9376, 18.2185),\n    (122.2460, 18.4789),\n    (122.3369, 18.2248),\n    (122.0383, 11.4158),\n    (121.8835, 11.8917),\n    (122.4838, 11.5822),\n    (123.1202, 11.5836),\n    (123.1008, 11.1659),\n    (122.6377, 10.7413),\n    (122.0026, 10.4410),\n    (121.9673, 10.9056),\n    (122.0383, 11.4158),\n    (125.5025, 12.1626),\n    (125.7834, 11.0461),\n    (125.0118, 11.3114),\n    (125.0327, 10.9758),\n    (125.2774, 10.3587),\n    (124.8018, 10.1346),\n    (124.7601, 10.8379),\n    (124.4591, 10.8899),\n    (124.3025, 11.4953),\n    (124.8910, 11.4155),\n    (124.8779, 11.7941),\n    (124.2667, 12.5577),\n    (125.2271, 12.5357),\n    (125.5025, 12.1626),\n    (-77.3533, 8.6705),\n    (-76.8366, 8.6387),\n    (-76.0863, 9.3368),\n    (-75.6746, 9.4432),\n    (-75.6647, 9.7740),\n    (-75.4804, 10.6189),\n    (-74.9068, 11.0830),\n    (-74.2767, 11.1020),\n    (-74.1972, 11.3104),\n    (-73.4147, 11.2270),\n    (-72.6278, 11.7319),\n    (-72.2381, 11.9555),\n    (-71.7540, 12.4373),\n    (-71.3998, 12.3760),\n    (-71.1374, 12.1129),\n    (-71.3315, 11.7762),\n    (-71.3600, 11.5399),\n    (-71.9470, 11.4232),\n    (-71.6208, 10.9694),\n    (-71.6330, 10.4464),\n    (-72.0741, 9.8656),\n    (-71.6956, 9.0722),\n    (-71.2645, 9.1372),\n    (-71.0399, 9.8599),\n    (-71.3500, 10.2119),\n    (-71.4006, 10.9689),\n    (-70.1552, 11.3754),\n    (-70.2938, 11.8468),\n    (-69.9432, 12.1623),\n    (-69.5843, 11.4596),\n    (-68.8829, 11.4433),\n    (-68.2332, 10.8857),\n    (-68.1941, 10.5546),\n    (-67.2962, 10.5458),\n    (-66.2278, 10.6486),\n    (-65.6552, 10.2007),\n    (-64.8904, 10.0772),\n    (-64.3294, 10.3895),\n    (-64.3180, 10.6414),\n    (-63.0793, 10.7017),\n    (-61.8809, 10.7156),\n    (-62.7301, 10.4202),\n    (-62.3885, 9.9482),\n    (-61.5887, 9.8730),\n    (-60.8305, 9.3813),\n    (-60.6712, 8.5801),\n    (-60.1500, 8.6027),\n    (-59.7582, 8.3670),\n    (-59.1016, 7.9992),\n    (-58.4829, 7.3476),\n    (-58.4548, 6.8327),\n    (-58.0781, 6.8090),\n    (-57.5422, 6.3212),\n    (-57.1474, 5.9731),\n    (-55.9493, 5.7728),\n    (-55.8417, 5.9531),\n    (-55.0332, 6.0252),\n    (-53.9580, 5.7565),\n    (-53.6184, 5.6465),\n    (-52.8821, 5.4098),\n    (-51.8233, 4.5657),\n    (-51.6577, 4.1562),\n    (-51.2999, 4.1200),\n    (-51.0697, 3.6503),\n    (-50.5088, 1.9015),\n    (-49.9740, 1.7364),\n    (-49.9471, 1.0461),\n    (-50.6992, 0.2229),\n    (-50.3882, -0.0784),\n    (-48.6205, -0.2354),\n    (-48.5844, -1.2378),\n    (-47.8249, -0.5816),\n    (-46.5665, -0.9410),\n    (-44.9057, -1.5517),\n    (-44.4176, -2.1377),\n    (-44.5815, -2.6913),\n    (-43.4187, -2.3831),\n    (-41.4726, -2.9120),\n    (-39.9786, -2.8730),\n    (-38.5003, -3.7006),\n    (-37.2232, -4.8209),\n    (-36.4529, -5.1094),\n    (-35.5977, -5.1495),\n    (-35.2353, -5.4649),\n    (-34.8960, -6.7381),\n    (-34.7299, -7.3432),\n    (-35.1282, -8.9964),\n    (-35.6369, -9.6492),\n    (-37.0465, -11.0407),\n    (-37.6836, -12.1711),\n    (-38.4238, -13.0381),\n    (-38.6738, -13.0576),\n    (-38.9532, -13.7933),\n    (-38.8822, -15.6670),\n    (-39.1610, -17.2084),\n    (-39.2673, -17.8677),\n    (-39.5835, -18.2622),\n    (-39.7608, -19.5991),\n    (-40.7747, -20.9045),\n    (-40.9447, -21.9373),\n    (-41.7541, -22.3706),\n    (-41.9882, -22.9700),\n    (-43.0747, -22.9676),\n    (-44.6478, -23.3519),\n    (-45.3521, -23.7968),\n    (-46.4720, -24.0889),\n    (-47.6489, -24.8851),\n    (-48.4954, -25.8770),\n    (-48.6410, -26.6236),\n    (-48.4747, -27.1759),\n    (-48.6615, -28.1861),\n    (-48.8884, -28.6741),\n    (-49.5873, -29.2244),\n    (-50.6968, -30.9844),\n    (-51.5762, -31.7776),\n    (-52.2560, -32.2453),\n    (-52.7120, -33.1965),\n    (-53.3736, -33.7683),\n    (-53.8064, -34.3968),\n    (-54.9358, -34.9526),\n    (-55.6740, -34.7526),\n    (-56.2152, -34.8598),\n    (-57.1396, -34.4304),\n    (-57.8178, -34.4625),\n    (-58.4270, -33.9094),\n    (-58.4954, -34.4314),\n    (-57.2258, -35.2880),\n    (-57.3623, -35.9773),\n    (-56.7374, -36.4131),\n    (-56.7882, -36.9015),\n    (-57.7491, -38.1838),\n    (-59.2318, -38.7201),\n    (-61.2374, -38.9284),\n    (-62.3359, -38.8277),\n    (-62.1257, -39.4241),\n    (-62.3305, -40.1725),\n    (-62.1459, -40.6768),\n    (-62.7458, -41.0287),\n    (-63.7704, -41.1667),\n    (-64.7320, -40.8026),\n    (-65.1180, -41.0643),\n    (-64.9785, -42.0580),\n    (-64.3034, -42.3590),\n    (-63.7559, -42.0436),\n    (-63.4580, -42.5631),\n    (-64.3788, -42.8735),\n    (-65.1818, -43.4953),\n    (-65.3288, -44.5013),\n    (-65.5652, -45.0367),\n    (-66.5099, -45.0396),\n    (-67.2937, -45.5518),\n    (-67.5805, -46.3017),\n    (-66.5970, -47.0338),\n    (-65.6410, -47.2361),\n    (-65.9850, -48.1332),\n    (-67.1661, -48.6973),\n    (-67.8160, -49.8696),\n    (-68.7287, -50.2641),\n    (-69.1385, -50.7325),\n    (-68.8155, -51.7711),\n    (-68.1499, -52.3499),\n    (-68.5715, -52.2994),\n    (-69.4612, -52.2919),\n    (-69.9427, -52.5379),\n    (-70.8451, -52.8991),\n    (-71.0063, -53.8332),\n    (-71.4297, -53.8564),\n    (-72.5579, -53.5314),\n    (-73.7027, -52.8350),\n    (-74.9467, -52.2627),\n    (-75.2600, -51.6293),\n    (-74.9766, -51.0433),\n    (-75.4797, -50.3783),\n    (-75.6080, -48.6737),\n    (-75.1827, -47.7119),\n    (-74.1265, -46.9392),\n    (-75.6443, -46.6476),\n    (-74.6921, -45.7639),\n    (-74.3517, -44.1030),\n    (-73.2403, -44.4549),\n    (-72.7178, -42.3833),\n    (-73.3888, -42.1175),\n    (-73.7013, -43.3657),\n    (-74.3319, -43.2249),\n    (-74.0179, -41.7948),\n    (-73.6770, -39.9422),\n    (-73.2175, -39.2586),\n    (-73.5055, -38.2828),\n    (-73.5880, -37.1562),\n    (-73.1667, -37.1237),\n    (-72.5531, -35.5088),\n    (-71.8617, -33.9090),\n    (-71.4384, -32.4188),\n    (-71.6687, -30.9206),\n    (-71.3700, -30.0956),\n    (-71.4898, -28.8614),\n    (-70.9051, -27.6403),\n    (-70.7249, -25.7059),\n    (-70.4039, -23.6289),\n    (-70.0912, -21.3933),\n    (-70.1644, -19.7564),\n    (-70.3725, -18.3479),\n    (-71.3752, -17.7737),\n    (-71.4620, -17.3634),\n    (-73.4445, -16.3593),\n    (-75.2378, -15.2656),\n    (-76.0092, -14.6492),\n    (-76.4234, -13.8231),\n    (-76.2592, -13.5350),\n    (-77.1061, -12.2227),\n    (-78.0921, -10.3777),\n    (-79.0369, -8.3865),\n    (-79.4459, -7.9308),\n    (-79.7605, -7.1943),\n    (-80.5374, -6.5416),\n    (-81.2499, -6.1368),\n    (-80.9263, -5.6905),\n    (-81.4109, -4.7367),\n    (-81.0996, -4.0363),\n    (-80.3025, -3.4048),\n    (-79.7702, -2.6575),\n    (-79.9865, -2.2207),\n    (-80.3687, -2.6851),\n    (-80.9677, -2.2469),\n    (-80.7648, -1.9650),\n    (-80.9336, -1.0574),\n    (-80.5833, -0.9066),\n    (-80.3993, -0.2837),\n    (-80.0208, 0.3603),\n    (-80.0906, 0.7684),\n    (-79.5427, 0.9829),\n    (-78.8552, 1.3809),\n    (-78.9909, 1.6913),\n    (-78.6178, 1.7664),\n    (-78.6621, 2.2673),\n    (-78.4276, 2.6295),\n    (-77.9315, 2.6966),\n    (-77.5104, 3.3250),\n    (-77.1276, 3.8496),\n    (-77.4962, 4.0876),\n    (-77.3076, 4.6679),\n    (-77.5332, 5.5828),\n    (-77.3188, 5.8453),\n    (-77.4766, 6.6911),\n    (-77.8815, 7.2237),\n    (-74.6625, -52.8374),\n    (-73.8380, -53.0474),\n    (-72.4341, -53.7153),\n    (-71.1077, -54.0743),\n    (-70.5917, -53.6158),\n    (-70.2674, -52.9312),\n    (-69.3456, -52.5182),\n    (-68.6341, -52.6362),\n    (-68.2500, -53.1000),\n    (-67.7499, -53.8499),\n    (-66.4499, -54.4500),\n    (-65.0500, -54.7000),\n    (-65.5000, -55.1999),\n    (-66.4499, -55.2500),\n    (-66.9599, -54.8968),\n    (-67.2910, -55.3012),\n    (-68.1486, -55.6118),\n    (-68.6399, -55.5800),\n    (-69.2320, -55.4990),\n    (-69.9580, -55.1984),\n    (-71.0056, -55.0538),\n    (-72.2639, -54.4951),\n    (-73.2852, -53.9575),\n    (-74.6625, -52.8374),\n    (44.8469, 80.5898),\n    (46.7991, 80.7719),\n    (48.3184, 80.7840),\n    (48.5228, 80.5145),\n    (49.0971, 80.7539),\n    (50.0397, 80.9188),\n    (51.5229, 80.6997),\n    (51.1361, 80.5472),\n    (49.7936, 80.4154),\n    (48.8944, 80.3395),\n    (48.7549, 80.1754),\n    (47.5861, 80.0101),\n    (46.5028, 80.2472),\n    (47.0724, 80.5594),\n    (44.8469, 80.5898),\n    (53.5082, 73.7498),\n    (55.9024, 74.6274),\n    (55.6319, 75.0814),\n    (57.8686, 75.6093),\n    (61.1700, 76.2518),\n    (64.4983, 76.4390),\n    (66.2109, 76.8097),\n    (68.1570, 76.9396),\n    (68.8522, 76.5448),\n    (68.1805, 76.2336),\n    (64.6373, 75.7377),\n    (61.5835, 75.2608),\n    (58.4770, 74.3090),\n    (56.9867, 73.3330),\n    (55.4193, 72.3712),\n    (55.6228, 71.5405),\n    (57.5356, 70.7204),\n    (56.9449, 70.6327),\n    (53.6773, 70.7626),\n    (53.4120, 71.2066),\n    (51.6018, 71.4747),\n    (51.4557, 72.0148),\n    (52.4782, 72.2294),\n    (52.4441, 72.7747),\n    (54.4276, 73.6275),\n    (53.5082, 73.7498),\n    (27.4075, 80.0564),\n    (25.9246, 79.5178),\n    (23.0244, 79.4000),\n    (20.0751, 79.5668),\n    (19.8972, 79.8423),\n    (18.4622, 79.8598),\n    (17.3680, 80.3188),\n    (20.4559, 80.5981),\n    (21.9079, 80.3576),\n    (22.9192, 80.6571),\n    (25.4476, 80.4073),\n    (27.4075, 80.0564),\n    (24.7241, 77.8538),\n    (22.4903, 77.4449),\n    (20.7260, 77.6770),\n    (21.4160, 77.9350),\n    (20.8118, 78.2546),\n    (22.8842, 78.4549),\n    (23.2813, 78.0795),\n    (24.7241, 77.8538),\n    (15.1428, 79.6743),\n    (15.5225, 80.0160),\n    (16.9908, 80.0508),\n    (18.2518, 79.7017),\n    (21.5438, 78.9561),\n    (19.0273, 78.5625),\n    (18.4717, 77.8266),\n    (17.5944, 77.6379),\n    (17.1182, 76.8094),\n    (15.9131, 76.7704),\n    (13.7626, 77.3803),\n    (14.6695, 77.7356),\n    (13.1705, 78.0249),\n    (11.2222, 78.8692),\n    (10.4445, 79.6523),\n    (13.1707, 80.0104),\n    (13.7185, 79.6604),\n    (15.1428, 79.6743),\n    (-77.8815, 7.2237),\n    (-78.2149, 7.5122),\n    (-78.4291, 8.0520),\n    (-78.1820, 8.3191),\n    (-78.4354, 8.3877),\n    (-78.6221, 8.7181),\n    (-79.1203, 8.9960),\n    (-79.5578, 8.9323),\n    (-79.7605, 8.5845),\n    (-80.1644, 8.3333),\n    (-80.3826, 8.2984),\n    (-80.4806, 8.0903),\n    (-80.0036, 7.5475),\n    (-80.2766, 7.4197),\n    (-80.4211, 7.2715),\n    (-80.8864, 7.2205),\n    (-81.0595, 7.8179),\n    (-81.1897, 7.6479),\n    (-81.5195, 7.7066),\n    (-81.7213, 8.1089),\n    (-82.1314, 8.1753),\n    (-82.3909, 8.2923),\n    (-82.6054, 8.2916),\n    (-82.8200, 8.2908),\n    (-82.8509, 8.0738),\n    (-82.9657, 8.2250),\n    (-83.5084, 8.4469),\n    (-83.7114, 8.6568),\n    (-83.5963, 8.8304),\n    (-83.6326, 9.0513),\n    (-83.9098, 9.2908),\n    (-84.3034, 9.4873),\n    (-84.6476, 9.6155),\n    (-84.7133, 9.9080),\n    (-84.9756, 10.0867),\n    (-84.9113, 9.7959),\n    (-85.1109, 9.5570),\n    (-85.3394, 9.8345),\n    (-85.6607, 9.9333),\n    (-85.7974, 10.1348),\n    (-85.7917, 10.4393),\n    (-85.6593, 10.7543),\n    (-85.8005, 10.8247),\n    (-85.9417, 10.8952),\n    (-85.7125, 11.0884),\n    (-86.0584, 11.4034),\n    (-86.5258, 11.8068),\n    (-86.7459, 12.1439),\n    (-87.1675, 12.4582),\n    (-87.6684, 12.9099),\n    (-87.5574, 13.0645),\n    (-87.3923, 12.9140),\n    (-87.3166, 12.9846),\n    (-87.4894, 13.2975),\n    (-87.6412, 13.3410),\n    (-87.7931, 13.3844),\n    (-87.9041, 13.1490),\n    (-88.4833, 13.1639),\n    (-88.8432, 13.2597),\n    (-89.2567, 13.4585),\n    (-89.8123, 13.5206),\n    (-90.0955, 13.7353),\n    (-90.6086, 13.9097),\n    (-91.2324, 13.9278),\n    (-91.6897, 14.1262),\n    (-92.2277, 14.5388),\n    (-93.3594, 15.6154),\n    (-93.8751, 15.9401),\n    (-94.6916, 16.2009),\n    (-95.2502, 16.1283),\n    (-96.0533, 15.7520),\n    (-96.5574, 15.6535),\n    (-97.2635, 15.9170),\n    (-98.0130, 16.1073),\n    (-98.9476, 16.5660),\n    (-99.6973, 16.7061),\n    (-100.8294, 17.1710),\n    (-101.6660, 17.6490),\n    (-101.9185, 17.9160),\n    (-102.4781, 17.9757),\n    (-103.5009, 18.2922),\n    (-103.9175, 18.7485),\n    (-104.9920, 19.3161),\n    (-105.4930, 19.9467),\n    (-105.7313, 20.4341),\n    (-105.3977, 20.5317),\n    (-105.5006, 20.8168),\n    (-105.2707, 21.0762),\n    (-105.2658, 21.4221),\n    (-105.6031, 21.8711),\n    (-105.6934, 22.2690),\n    (-106.0287, 22.7737),\n    (-106.9099, 23.7678),\n    (-107.9154, 24.5489),\n    (-108.4019, 25.1723),\n    (-109.2601, 25.5806),\n    (-109.4440, 25.8248),\n    (-109.2916, 26.4429),\n    (-109.8014, 26.6761),\n    (-110.3917, 27.1621),\n    (-110.6410, 27.8598),\n    (-111.1789, 27.9412),\n    (-111.7596, 28.4679),\n    (-112.2282, 28.9544),\n    (-112.2718, 29.2668),\n    (-112.8095, 30.0211),\n    (-113.1638, 30.7868),\n    (-113.1486, 31.1709),\n    (-113.8718, 31.5676),\n    (-114.2057, 31.5240),\n    (-114.7764, 31.7995),\n    (-114.9366, 31.3934),\n    (-114.7712, 30.9136),\n    (-114.6738, 30.1626),\n    (-114.3309, 29.7504),\n    (-113.5888, 29.0616),\n    (-113.4240, 28.8261),\n    (-113.2719, 28.7547),\n    (-113.1400, 28.4112),\n    (-112.9622, 28.4251),\n    (-112.7615, 27.7802),\n    (-112.4579, 27.5258),\n    (-112.2449, 27.1717),\n    (-111.6164, 26.6628),\n    (-111.2846, 25.7325),\n    (-110.9878, 25.2946),\n    (-110.7100, 24.8260),\n    (-110.6550, 24.2985),\n    (-110.1728, 24.2655),\n    (-109.7718, 23.8111),\n    (-109.4091, 23.3646),\n    (-109.4333, 23.1855),\n    (-109.8542, 22.8182),\n    (-110.0313, 22.8230),\n    (-110.2950, 23.4309),\n    (-110.9495, 24.0009),\n    (-111.6705, 24.4844),\n    (-112.1820, 24.7384),\n    (-112.1489, 25.4701),\n    (-112.3007, 26.0120),\n    (-112.7772, 26.3219),\n    (-113.4646, 26.7681),\n    (-113.5967, 26.6394),\n    (-113.8489, 26.9000),\n    (-114.4657, 27.1420),\n    (-115.0551, 27.7227),\n    (-114.9822, 27.7982),\n    (-114.5703, 27.7414),\n    (-114.1993, 28.1150),\n    (-114.1620, 28.5661),\n    (-114.9318, 29.2794),\n    (-115.5186, 29.5563),\n    (-115.8873, 30.1807),\n    (-116.2583, 30.8364),\n    (-116.7215, 31.6357),\n    (-117.1277, 32.5353),\n    (-117.2959, 33.0462),\n    (-117.944, 33.6212),\n    (-118.4106, 33.7409),\n    (-118.5198, 34.0277),\n    (-119.081, 34.078),\n    (-119.4388, 34.3484),\n    (-120.3677, 34.4470),\n    (-120.6228, 34.6085),\n    (-120.7443, 35.1568),\n    (-121.7145, 36.1615),\n    (-122.5474, 37.5517),\n    (-122.5119, 37.7833),\n    (-122.9531, 38.1136),\n    (-123.7271, 38.9516),\n    (-123.8651, 39.7669),\n    (-124.3980, 40.3131),\n    (-124.1788, 41.1420),\n    (-124.2137, 41.9996),\n    (-124.5328, 42.7659),\n    (-124.1421, 43.7083),\n    (-124.0205, 44.6158),\n    (-123.8989, 45.5234),\n    (-124.0796, 46.8647),\n    (-124.3956, 47.7201),\n    (-124.6872, 48.1844),\n    (-124.5661, 48.3797),\n    (-123.12, 48.04),\n    (-122.5873, 47.0959),\n    (-122.3399, 47.3600),\n    (-122.5000, 48.1800),\n    (-122.84, 49.0),\n    (-122.9742, 49.0025),\n    (-124.9102, 49.9845),\n    (-125.6246, 50.4165),\n    (-127.4356, 50.8305),\n    (-127.9927, 51.7158),\n    (-127.8503, 52.3296),\n    (-129.1297, 52.7553),\n    (-129.3052, 53.5615),\n    (-130.5149, 54.2875),\n    (-130.5361, 54.8027),\n    (-131.0858, 55.1789),\n    (-131.9672, 55.4977),\n    (-132.2500, 56.3699),\n    (-133.5391, 57.1788),\n    (-134.0780, 58.1230),\n    (-135.0382, 58.1877),\n    (-136.6280, 58.2122),\n    (-137.8000, 58.4999),\n    (-139.8677, 59.5377),\n    (-140.8252, 59.7275),\n    (-142.5744, 60.0844),\n    (-143.9588, 59.9991),\n    (-145.9255, 60.4586),\n    (-147.1143, 60.8846),\n    (-148.2243, 60.6729),\n    (-148.0180, 59.9783),\n    (-148.5708, 59.9141),\n    (-149.7278, 59.7056),\n    (-150.6082, 59.3682),\n    (-151.7163, 59.1558),\n    (-151.8594, 59.7449),\n    (-151.4097, 60.7258),\n    (-150.3469, 61.0335),\n    (-150.6211, 61.2844),\n    (-151.8958, 60.7271),\n    (-152.5783, 60.0616),\n    (-154.0191, 59.3502),\n    (-153.2875, 58.8647),\n    (-154.2324, 58.1463),\n    (-155.3074, 57.7277),\n    (-156.3083, 57.4227),\n    (-156.5560, 56.9799),\n    (-158.1172, 56.4636),\n    (-158.4333, 55.9941),\n    (-159.6033, 55.5666),\n    (-160.2897, 55.6435),\n    (-161.2230, 55.3647),\n    (-162.2377, 55.0241),\n    (-163.0694, 54.6897),\n    (-164.7855, 54.4041),\n    (-164.9422, 54.5722),\n    (-163.8483, 55.0394),\n    (-162.8700, 55.3480),\n    (-161.8041, 55.8949),\n    (-160.5636, 56.0080),\n    (-160.0705, 56.4180),\n    (-158.6844, 57.0166),\n    (-158.4610, 57.2169),\n    (-157.7227, 57.5700),\n    (-157.5502, 58.3283),\n    (-157.0416, 58.9188),\n    (-158.1947, 58.6158),\n    (-158.5172, 58.7877),\n    (-159.0586, 58.4241),\n    (-159.7116, 58.9313),\n    (-159.9812, 58.5725),\n    (-160.3552, 59.0711),\n    (-161.3550, 58.6708),\n    (-161.9688, 58.6716),\n    (-162.0549, 59.2669),\n    (-161.8741, 59.6336),\n    (-162.5180, 59.9897),\n    (-163.8183, 59.7980),\n    (-164.6622, 60.2674),\n    (-165.3463, 60.5074),\n    (-165.3508, 61.0738),\n    (-166.1213, 61.5000),\n    (-165.7344, 62.0749),\n    (-164.9191, 62.6330),\n    (-164.5625, 63.1463),\n    (-163.7533, 63.2194),\n    (-163.0672, 63.0594),\n    (-162.2605, 63.5419),\n    (-161.5344, 63.4558),\n    (-160.7725, 63.7661),\n    (-160.9583, 64.2227),\n    (-161.5180, 64.4027),\n    (-160.7777, 64.7886),\n    (-161.3919, 64.7772),\n    (-162.4530, 64.5594),\n    (-162.7577, 64.3386),\n    (-163.5463, 64.5591),\n    (-164.9608, 64.4469),\n    (-166.4252, 64.6866),\n    (-166.8450, 65.0888),\n    (-168.1105, 65.6699),\n    (-166.7052, 66.0883),\n    (-164.4747, 66.5766),\n    (-163.6525, 66.5766),\n    (-163.7886, 66.0772),\n    (-161.6777, 66.1161),\n    (-162.4897, 66.7355),\n    (-163.7197, 67.1163),\n    (-164.4309, 67.6163),\n    (-165.3902, 68.0427),\n    (-166.7644, 68.3588),\n    (-166.2047, 68.8830),\n    (-164.4308, 68.9155),\n    (-163.1686, 69.3711),\n    (-162.9305, 69.8580),\n    (-161.9088, 70.3333),\n    (-160.9347, 70.4476),\n    (-159.0391, 70.8916),\n    (-158.1197, 70.8247),\n    (-156.5808, 71.3577),\n    (-155.0677, 71.1477),\n    (-154.3441, 70.6964),\n    (-153.9000, 70.8899),\n    (-152.2100, 70.8299),\n    (-152.2700, 70.6000),\n    (-150.7399, 70.4300),\n    (-149.7200, 70.5300),\n    (-147.6133, 70.2140),\n    (-145.6899, 70.1200),\n    (-144.9200, 69.9899),\n    (-143.5894, 70.1525),\n    (-142.0725, 69.8519),\n    (-140.9859, 69.7119),\n    (-139.1205, 69.4710),\n    (-137.5463, 68.9900),\n    (-136.5035, 68.8980),\n    (-135.6257, 69.3151),\n    (-134.4146, 69.6274),\n    (-132.9292, 69.5053),\n    (-131.4313, 69.9445),\n    (-129.7947, 70.1937),\n    (-129.1077, 69.7792),\n    (-128.3615, 70.0128),\n    (-128.1381, 70.4838),\n    (-127.4471, 70.3772),\n    (-125.7563, 69.4805),\n    (-124.4248, 70.1584),\n    (-124.2896, 69.3996),\n    (-123.0610, 69.5637),\n    (-122.6834, 69.8555),\n    (-121.4722, 69.7977),\n    (-119.9428, 69.3778),\n    (-117.6026, 69.0112),\n    (-116.2264, 68.8414),\n    (-115.2468, 68.9059),\n    (-113.8979, 68.3989),\n    (-115.3048, 67.9026),\n    (-113.4972, 67.6881),\n    (-110.7980, 67.8060),\n    (-109.9461, 67.9810),\n    (-108.8801, 67.3814),\n    (-107.7923, 67.8873),\n    (-108.8129, 68.3116),\n    (-108.1672, 68.6539),\n    (-106.9500, 68.6999),\n    (-106.1500, 68.7999),\n    (-105.3428, 68.5612),\n    (-104.3379, 68.0180),\n    (-103.2211, 68.0977),\n    (-101.4543, 67.6468),\n    (-99.9019, 67.8056),\n    (-98.4432, 67.7816),\n    (-98.5586, 68.4039),\n    (-97.6694, 68.5786),\n    (-96.1199, 68.2394),\n    (-96.1258, 67.2933),\n    (-95.4894, 68.0907),\n    (-94.6849, 68.0638),\n    (-94.2328, 69.0690),\n    (-95.3040, 69.6857),\n    (-96.4713, 70.0897),\n    (-96.3911, 71.1948),\n    (-95.2088, 71.9205),\n    (-93.8899, 71.7601),\n    (-92.8781, 71.3186),\n    (-91.5196, 70.1912),\n    (-92.4069, 69.6999),\n    (-90.5471, 69.4976),\n    (-90.5514, 68.4749),\n    (-89.2151, 69.2587),\n    (-88.0196, 68.6150),\n    (-88.3174, 67.8733),\n    (-87.3501, 67.1987),\n    (-86.3060, 67.9214),\n    (-85.5766, 68.7845),\n    (-85.5219, 69.8820),\n    (-84.1008, 69.8054),\n    (-82.6225, 69.6582),\n    (-81.2804, 69.1620),\n    (-81.2202, 68.6656),\n    (-81.9643, 68.1325),\n    (-81.2592, 67.5971),\n    (-81.3865, 67.1107),\n    (-83.3445, 66.4115),\n    (-84.7354, 66.2572),\n    (-85.7694, 66.5583),\n    (-86.0676, 66.0562),\n    (-87.0314, 65.2129),\n    (-87.3232, 64.7756),\n    (-88.4829, 64.0989),\n    (-89.9144, 64.0327),\n    (-90.7039, 63.6101),\n    (-90.7700, 62.9602),\n    (-91.9334, 62.8350),\n    (-93.1569, 62.0246),\n    (-94.2415, 60.8986),\n    (-94.6293, 60.1102),\n    (-94.6846, 58.9488),\n    (-93.2150, 58.7821),\n    (-92.7646, 57.8457),\n    (-92.2970, 57.0870),\n    (-90.8976, 57.2846),\n    (-89.0395, 56.8517),\n    (-88.0397, 56.4716),\n    (-87.3241, 55.9991),\n    (-86.0712, 55.7238),\n    (-85.0118, 55.3026),\n    (-83.3605, 55.2448),\n    (-82.2728, 55.1483),\n    (-82.4362, 54.2822),\n    (-82.1250, 53.2770),\n    (-81.4007, 52.1578),\n    (-79.9128, 51.2083),\n    (-79.1430, 51.5339),\n    (-78.6019, 52.5620),\n    (-79.1242, 54.1414),\n    (-79.8295, 54.6677),\n    (-78.2287, 55.1364),\n    (-77.0955, 55.8374),\n    (-76.5413, 56.5342),\n    (-76.6231, 57.2026),\n    (-77.3022, 58.0520),\n    (-78.5168, 58.8045),\n    (-77.3367, 59.8526),\n    (-77.7727, 60.7578),\n    (-78.1068, 62.3196),\n    (-77.4106, 62.5505),\n    (-75.6962, 62.2783),\n    (-74.6682, 62.1811),\n    (-73.8398, 62.4437),\n    (-72.9085, 62.1050),\n    (-71.6770, 61.5253),\n    (-71.3736, 61.1371),\n    (-69.5904, 61.0614),\n    (-69.6203, 60.2212),\n    (-69.2878, 58.9573),\n    (-68.3745, 58.8010),\n    (-67.6497, 58.2120),\n    (-66.2017, 58.7673),\n    (-65.2451, 59.8707),\n    (-64.5835, 60.3355),\n    (-63.8047, 59.4425),\n    (-62.5023, 58.1670),\n    (-61.3965, 56.9674),\n    (-61.7986, 56.3394),\n    (-60.4685, 55.7754),\n    (-59.5696, 55.2040),\n    (-57.9750, 54.9454),\n    (-57.3332, 54.6264),\n    (-56.9368, 53.7803),\n    (-56.1581, 53.6474),\n    (-55.7563, 53.2703),\n    (-55.6833, 52.1466),\n    (-56.4091, 51.7706),\n    (-57.1269, 51.4197),\n    (-58.7748, 51.0642),\n    (-60.0331, 50.2427),\n    (-61.7236, 50.0804),\n    (-63.8625, 50.2909),\n    (-65.3633, 50.2981),\n    (-66.3990, 50.2289),\n    (-67.2363, 49.5115),\n    (-68.5111, 49.0683),\n    (-69.9536, 47.7448),\n    (-71.1045, 46.8217),\n    (-70.2552, 46.9860),\n    (-68.6499, 48.2999),\n    (-66.5524, 49.1330),\n    (-65.0562, 49.2327),\n    (-64.1709, 48.7425),\n    (-65.1154, 48.0708),\n    (-64.7985, 46.9929),\n    (-64.4721, 46.2384),\n    (-63.1732, 45.7390),\n    (-61.5207, 45.8837),\n    (-60.5181, 47.0079),\n    (-60.4486, 46.2826),\n    (-59.8028, 45.9204),\n    (-61.0398, 45.2652),\n    (-63.2547, 44.6701),\n    (-64.2465, 44.2655),\n    (-65.3640, 43.5452),\n    (-66.1234, 43.6186),\n    (-66.1617, 44.4651),\n    (-64.4254, 45.2920),\n    (-66.0260, 45.2593),\n    (-67.1374, 45.1375),\n    (-66.9646, 44.8097),\n    (-68.0325, 44.3252),\n    (-69.06, 43.98),\n    (-70.1161, 43.6840),\n    (-70.6454, 43.0902),\n    (-70.8148, 42.8652),\n    (-70.8249, 42.3349),\n    (-70.4949, 41.8049),\n    (-70.0800, 41.7800),\n    (-70.1849, 42.1449),\n    (-69.8849, 41.9228),\n    (-69.9650, 41.6371),\n    (-70.6399, 41.4749),\n    (-71.1203, 41.4944),\n    (-71.8538, 41.3199),\n    (-72.2949, 41.2699),\n    (-72.8764, 41.2206),\n    (-73.71, 40.9311),\n    (-72.2412, 41.1194),\n    (-71.9450, 40.9300),\n    (-73.3450, 40.6300),\n    (-73.9819, 40.6280),\n    (-73.9523, 40.7507),\n    (-74.2567, 40.4734),\n    (-73.9624, 40.4276),\n    (-74.1783, 39.7092),\n    (-74.9060, 38.9395),\n    (-74.9804, 39.1963),\n    (-75.2000, 39.2484),\n    (-75.5280, 39.4984),\n    (-75.3199, 38.9599),\n    (-75.0718, 38.7820),\n    (-75.0567, 38.4041),\n    (-75.3774, 38.0155),\n    (-75.9402, 37.2169),\n    (-76.0312, 37.2565),\n    (-75.7220, 37.9370),\n    (-76.2328, 38.3192),\n    (-76.35, 39.15),\n    (-76.5427, 38.7176),\n    (-76.3293, 38.0832),\n    (-76.9899, 38.2399),\n    (-76.3016, 37.9179),\n    (-76.2587, 36.9664),\n    (-75.9718, 36.8972),\n    (-75.8680, 36.5512),\n    (-75.7274, 35.5507),\n    (-76.3631, 34.8085),\n    (-77.3976, 34.5120),\n    (-78.0549, 33.9254),\n    (-78.5543, 33.8613),\n    (-79.0606, 33.4939),\n    (-79.2035, 33.1583),\n    (-80.3013, 32.5093),\n    (-80.8649, 32.0333),\n    (-81.3362, 31.4404),\n    (-81.4904, 30.7299),\n    (-81.3137, 30.0355),\n    (-80.9799, 29.1800),\n    (-80.5355, 28.4721),\n    (-80.5299, 28.0399),\n    (-80.0565, 26.88),\n    (-80.0880, 26.2057),\n    (-80.1315, 25.8167),\n    (-80.3810, 25.2061),\n    (-80.6800, 25.0799),\n    (-81.1721, 25.2012),\n    (-81.3299, 25.6399),\n    (-81.7099, 25.8699),\n    (-82.2400, 26.7299),\n    (-82.7051, 27.4950),\n    (-82.8552, 27.8862),\n    (-82.6500, 28.5499),\n    (-82.93, 29.1),\n    (-83.7095, 29.9365),\n    (-84.1, 30.09),\n    (-85.1088, 29.6361),\n    (-85.2878, 29.6861),\n    (-85.7731, 30.1526),\n    (-86.3999, 30.4000),\n    (-87.5303, 30.2743),\n    (-88.4178, 30.3849),\n    (-89.1804, 30.3159),\n    (-89.5938, 30.1599),\n    (-89.4137, 29.8941),\n    (-89.43, 29.48864),\n    (-89.2176, 29.2910),\n    (-89.4082, 29.1596),\n    (-89.7792, 29.3071),\n    (-90.1546, 29.1174),\n    (-90.8802, 29.1485),\n    (-91.6267, 29.677),\n    (-92.4990, 29.5523),\n    (-93.2263, 29.7837),\n    (-93.8484, 29.7136),\n    (-94.6900, 29.4800),\n    (-95.6002, 28.7386),\n    (-96.5940, 28.3074),\n    (-97.1400, 27.8300),\n    (-97.3699, 27.3800),\n    (-97.3799, 26.6899),\n    (-97.3299, 26.2100),\n    (-97.1400, 25.8699),\n    (-97.5280, 24.9921),\n    (-97.7029, 24.2723),\n    (-97.7760, 22.9325),\n    (-97.8723, 22.4442),\n    (-97.6990, 21.8986),\n    (-97.3889, 21.4110),\n    (-97.1893, 20.6354),\n    (-96.5255, 19.8909),\n    (-96.2921, 19.3203),\n    (-95.9008, 18.8280),\n    (-94.8390, 18.5627),\n    (-94.4257, 18.1443),\n    (-93.5486, 18.4238),\n    (-92.7861, 18.5248),\n    (-92.0373, 18.7045),\n    (-91.4079, 18.8760),\n    (-90.7718, 19.2841),\n    (-90.5335, 19.8674),\n    (-90.4514, 20.7075),\n    (-90.2786, 20.9998),\n    (-89.6013, 21.2617),\n    (-88.5438, 21.4936),\n    (-87.6584, 21.4588),\n    (-87.0518, 21.5435),\n    (-86.8119, 21.3315),\n    (-86.8459, 20.8498),\n    (-87.3832, 20.2554),\n    (-87.6210, 19.6465),\n    (-87.4367, 19.4724),\n    (-87.5865, 19.0401),\n    (-87.8371, 18.2598),\n    (-88.0906, 18.5166),\n    (-88.3000, 18.4999),\n    (-88.2963, 18.3532),\n    (-88.1068, 18.3486),\n    (-88.1234, 18.0766),\n    (-88.2853, 17.6441),\n    (-88.1978, 17.4894),\n    (-88.3026, 17.1316),\n    (-88.2395, 17.0360),\n    (-88.3554, 16.5307),\n    (-88.5518, 16.2654),\n    (-88.7324, 16.2336),\n    (-88.9306, 15.8872),\n    (-88.6045, 15.7063),\n    (-88.5183, 15.8553),\n    (-88.1899, 15.7199),\n    (-88.1211, 15.6886),\n    (-87.9018, 15.8644),\n    (-87.6156, 15.8787),\n    (-87.5229, 15.7972),\n    (-87.3677, 15.8469),\n    (-86.9031, 15.7567),\n    (-86.4409, 15.7828),\n    (-86.1192, 15.8934),\n    (-86.0019, 16.0054),\n    (-85.6833, 15.9536),\n    (-85.4440, 15.8857),\n    (-85.1824, 15.9091),\n    (-84.9837, 15.9959),\n    (-84.5269, 15.8572),\n    (-84.3682, 15.8351),\n    (-84.0630, 15.6482),\n    (-83.7739, 15.4240),\n    (-83.4103, 15.2709),\n    (-83.1472, 14.9958),\n    (-83.2332, 14.8998),\n    (-83.2841, 14.6766),\n    (-83.1821, 14.3107),\n    (-83.4124, 13.9700),\n    (-83.5198, 13.5676),\n    (-83.5522, 13.1270),\n    (-83.4985, 12.8692),\n    (-83.4733, 12.4190),\n    (-83.6261, 12.3208),\n    (-83.7196, 11.8931),\n    (-83.6508, 11.6290),\n    (-83.8554, 11.3733),\n    (-83.8089, 11.1030),\n    (-83.6556, 10.9387),\n    (-83.5900, 10.7850),\n    (-83.4023, 10.3954),\n    (-83.0156, 9.9929),\n    (-82.5461, 9.5661),\n    (-82.1871, 9.2074),\n    (-82.2075, 8.9955),\n    (-81.8085, 8.9506),\n    (-81.7141, 9.0319),\n    (-81.4392, 8.7862),\n    (-80.9473, 8.8585),\n    (-80.5219, 9.1110),\n    (-79.9145, 9.3127),\n    (-79.5733, 9.6116),\n    (-79.0211, 9.5529),\n    (-79.0584, 9.4545),\n    (-78.5008, 9.4204),\n    (-78.0559, 9.2477),\n    (-77.7295, 8.9468),\n    (-77.3533, 8.6705),\n    (-71.7123, 19.7144),\n    (-71.5873, 19.8849),\n    (-71.3800, 19.9049),\n    (-70.8067, 19.8802),\n    (-70.2143, 19.6228),\n    (-69.9508, 19.6479),\n    (-69.7692, 19.2932),\n    (-69.2221, 19.3132),\n    (-69.2543, 19.0151),\n    (-68.8094, 18.9791),\n    (-68.3179, 18.6121),\n    (-68.6893, 18.2051),\n    (-69.1649, 18.4226),\n    (-69.6239, 18.3807),\n    (-69.9529, 18.4283),\n    (-70.1332, 18.2459),\n    (-70.5171, 18.1842),\n    (-70.6692, 18.4268),\n    (-70.9999, 18.2833),\n    (-71.4002, 17.5985),\n    (-71.6576, 17.7575),\n    (-71.7083, 18.0449),\n    (-72.3724, 18.2149),\n    (-72.8444, 18.1456),\n    (-73.4545, 18.2179),\n    (-73.9224, 18.0309),\n    (-74.4580, 18.3425),\n    (-74.3699, 18.6649),\n    (-73.4495, 18.5260),\n    (-72.6949, 18.4457),\n    (-72.3348, 18.6684),\n    (-72.7916, 19.1016),\n    (-72.7841, 19.4835),\n    (-73.4150, 19.6395),\n    (-73.1897, 19.9156),\n    (-72.5796, 19.8715),\n    (-71.7123, 19.7144),\n    (14.7612, 38.1438),\n    (15.5203, 38.2311),\n    (15.1602, 37.4440),\n    (15.3098, 37.1342),\n    (15.0999, 36.6199),\n    (14.3352, 36.9966),\n    (13.8267, 37.1045),\n    (12.4310, 37.6129),\n    (12.5709, 38.1263),\n    (13.7411, 38.0349),\n    (14.7612, 38.1438),\n    (37.5391, 44.6572),\n    (38.6799, 44.2799),\n    (39.9550, 43.4349),\n    (132.3711, 33.4636),\n    (132.9243, 34.0602),\n    (133.4929, 33.9446),\n    (133.9041, 34.3649),\n    (134.6384, 34.1492),\n    (134.7663, 33.8063),\n    (134.2034, 33.2011),\n    (133.7929, 33.5219),\n    (133.2802, 33.2895),\n    (133.0148, 32.7045),\n    (132.3631, 32.9893),\n    (132.3711, 33.4636),\n    (180.0000, 68.9636),\n    (178.5999, 69.4000),\n    (175.7240, 69.8772),\n    (173.6439, 69.8174),\n    (170.4534, 70.0970),\n    (170.0082, 69.6527),\n    (170.8168, 69.0136),\n    (169.5776, 68.6938),\n    (167.8629, 69.5687),\n    (165.9403, 69.4719),\n    (164.0524, 69.6682),\n    (162.2790, 69.6420),\n    (160.9405, 69.4372),\n    (159.7086, 69.7219),\n    (159.8303, 70.4532),\n    (158.9977, 70.8667),\n    (157.0068, 71.0314),\n    (152.9688, 70.8422),\n    (150.3511, 71.6064),\n    (149.5000, 72.1999),\n    (140.4681, 72.8494),\n    (139.1479, 72.4161),\n    (139.8698, 71.4878),\n    (138.2340, 71.6280),\n    (137.4975, 71.3476),\n    (135.5619, 71.6552),\n    (133.8576, 71.3864),\n    (132.2535, 71.8363),\n    (131.2885, 70.7869),\n    (129.7159, 71.1930),\n    (128.46, 71.98),\n    (129.0515, 72.3987),\n    (128.5912, 73.0387),\n    (126.9764, 73.5654),\n    (125.38, 73.56),\n    (123.2577, 73.7350),\n    (123.2006, 72.9712),\n    (119.02, 73.12),\n    (118.7763, 73.5877),\n    (115.5678, 73.7528),\n    (113.9688, 73.5948),\n    (113.5295, 73.3350),\n    (113.0195, 73.9769),\n    (112.1191, 73.7877),\n    (110.64, 74.04),\n    (109.4, 74.18),\n    (110.1512, 74.4767),\n    (112.7791, 75.0318),\n    (113.8853, 75.3277),\n    (114.1341, 75.8476),\n    (113.3315, 76.2222),\n    (111.07726, 76.71),\n    (108.1537, 76.7233),\n    (107.2399, 76.4799),\n    (106.9701, 76.9741),\n    (104.7050, 77.1273),\n    (106.0666, 77.3738),\n    (104.3515, 77.6979),\n    (101.9908, 77.2875),\n    (101.0353, 76.8618),\n    (100.7596, 76.4302),\n    (98.9225, 76.4468),\n    (96.6782, 75.9154),\n    (95.8600, 76.1400),\n    (93.2342, 76.0471),\n    (92.9006, 75.7733),\n    (90.2599, 75.6399),\n    (88.3156, 75.1439),\n    (87.1668, 75.1164),\n    (86.0095, 74.4596),\n    (86.8223, 73.9368),\n    (84.6552, 73.8059),\n    (82.2499, 73.8500),\n    (80.5110, 73.6482),\n    (80.6107, 72.5828),\n    (81.5000, 71.7499),\n    (79.6520, 72.3201),\n    (77.5766, 72.2671),\n    (75.9031, 71.8740),\n    (76.3591, 71.1528),\n    (75.2889, 71.3355),\n    (75.6835, 72.3005),\n    (75.1580, 72.8549),\n    (74.6592, 72.8322),\n    (74.8908, 72.1211),\n    (73.1011, 71.4471),\n    (74.3998, 70.6317),\n    (73.6018, 69.6276),\n    (73.8423, 69.0714),\n    (74.9358, 68.9891),\n    (74.4692, 68.3289),\n    (75.052, 67.76047),\n    (74.1865, 67.2842),\n    (73.9209, 66.7894),\n    (72.8207, 66.5326),\n    (72.4230, 66.1726),\n    (71.28, 66.32),\n    (73.2387, 67.7404),\n    (73.6678, 68.4079),\n    (72.5646, 69.0208),\n    (72.7918, 70.3911),\n    (72.4701, 71.0901),\n    (71.8481, 71.4089),\n    (72.7960, 72.2200),\n    (72.5875, 72.7762),\n    (69.94, 73.04),\n    (69.1963, 72.8433),\n    (68.5400, 71.9345),\n    (66.6946, 71.0289),\n    (66.7249, 70.7088),\n    (67.2597, 69.9287),\n    (66.9300, 69.4546),\n    (68.1352, 69.3564),\n    (68.1644, 69.1443),\n    (69.1806, 68.6156),\n    (68.5121, 68.0923),\n    (64.8881, 69.2348),\n    (63.5040, 69.5473),\n    (60.5500, 69.8500),\n    (60.03, 69.52),\n    (61.0778, 68.9406),\n    (59.9414, 68.2784),\n    (58.802, 68.88082),\n    (57.3170, 68.4662),\n    (55.4426, 68.4386),\n    (54.7530, 68.0868),\n    (53.4858, 68.2013),\n    (54.4717, 68.8081),\n    (53.7174, 68.8573),\n    (48.1387, 67.5223),\n    (47.8941, 66.8845),\n    (46.3491, 66.6676),\n    (45.5620, 67.0100),\n    (45.5551, 67.5665),\n    (46.8213, 67.6899),\n    (46.2500, 68.2499),\n    (43.4528, 68.5708),\n    (44.1747, 67.9616),\n    (43.6983, 67.3524),\n    (44.5322, 66.7563),\n    (43.9497, 66.0690),\n    (43.0160, 66.4185),\n    (42.0930, 66.4762),\n    (39.7626, 65.4968),\n    (40.4356, 64.7644),\n    (39.5934, 64.5207),\n    (37.1760, 65.1432),\n    (36.5395, 64.7644),\n    (37.1419, 64.3347),\n    (37.0127, 63.8498),\n    (36.2312, 64.1094),\n    (34.9439, 64.4143),\n    (34.8785, 65.4362),\n    (34.8147, 65.9001),\n    (33.1844, 66.6325),\n    (33.9186, 66.7595),\n    (38.3829, 65.9995),\n    (40.0158, 66.2661),\n    (41.1259, 66.7915),\n    (41.0598, 67.4571),\n    (40.2923, 67.9323),\n    (36.5139, 69.0634),\n    (33.7754, 69.3014),\n    (32.1327, 69.9059),\n    (31.1010, 69.5580),\n    (30.0054, 70.1862),\n    (31.2934, 70.4537),\n    (28.1655, 71.1854),\n    (26.3700, 70.9862),\n    (24.5465, 71.0304),\n    (23.0237, 70.2020),\n    (21.3784, 70.2551),\n    (19.1840, 69.8174),\n    (16.4359, 68.5632),\n    (14.7611, 67.8106),\n    (12.3583, 65.8797),\n    (10.5277, 64.4860),\n    (8.5534, 63.4540),\n    (5.9129, 62.6144),\n    (4.9920, 61.9709),\n    (5.3082, 59.6632),\n    (5.6658, 58.5881),\n    (7.0487, 58.0788),\n    (8.3820, 58.3132),\n    (10.3565, 59.4698),\n    (11.0273, 58.8561),\n    (11.7879, 57.4418),\n    (12.6251, 56.3070),\n    (12.9429, 55.3617),\n    (14.1007, 55.4077),\n    (14.6666, 56.2008),\n    (15.8797, 56.1043),\n    (16.4477, 57.0411),\n    (16.8291, 58.7198),\n    (17.8692, 58.9537),\n    (18.7877, 60.0819),\n    (17.8313, 60.6365),\n    (17.1195, 61.3411),\n    (17.8477, 62.7494),\n    (19.7788, 63.6095),\n    (21.3696, 64.4135),\n    (21.2135, 65.0260),\n    (22.1831, 65.7237),\n    (23.9033, 66.0069),\n    (25.2940, 65.5343),\n    (25.3980, 65.1114),\n    (24.7305, 64.9023),\n    (22.4427, 63.8178),\n    (21.5360, 63.1897),\n    (21.0592, 62.6073),\n    (21.5448, 61.7053),\n    (21.3222, 60.7201),\n    (22.2907, 60.3919),\n    (22.8696, 59.8463),\n    (24.4966, 60.0573),\n    (26.2551, 60.4239),\n    (28.0699, 60.5035),\n    (29.1176, 60.0280),\n    (27.9811, 59.4753),\n    (26.9491, 59.4458),\n    (25.8641, 59.6110),\n    (24.6042, 59.4658),\n    (23.3397, 59.1872),\n    (23.4265, 58.6127),\n    (24.0611, 58.2573),\n    (24.4289, 58.3834),\n    (24.3128, 57.7934),\n    (24.1207, 57.0256),\n    (23.3184, 57.0062),\n    (22.5243, 57.7533),\n    (21.5818, 57.4118),\n    (21.0904, 56.7838),\n    (21.0558, 56.0310),\n    (21.2684, 55.1904),\n    (19.8884, 54.8661),\n    (19.6606, 54.4260),\n    (18.6962, 54.4387),\n    (18.6208, 54.6826),\n    (17.6228, 54.8515),\n    (16.3634, 54.5131),\n    (14.8029, 54.0507),\n    (14.1196, 53.7570),\n    (13.6474, 54.0755),\n    (12.5184, 54.4703),\n    (11.9562, 54.1964),\n    (10.9394, 54.0086),\n    (10.9501, 54.3636),\n    (9.9395, 54.5966),\n    (9.9219, 54.9831),\n    (9.6499, 55.4699),\n    (10.3699, 56.1900),\n    (10.6678, 56.0813),\n    (10.9121, 56.4586),\n    (10.3699, 56.6099),\n    (10.2500, 56.8900),\n    (10.5461, 57.2157),\n    (10.5800, 57.7300),\n    (9.7755, 57.4479),\n    (9.4244, 57.1720),\n    (8.5434, 57.1100),\n    (8.2565, 56.8099),\n    (8.0899, 56.5400),\n    (8.1203, 55.5177),\n    (8.5262, 54.9627),\n    (8.5721, 54.3956),\n    (8.8007, 54.0207),\n    (8.1217, 53.5277),\n    (7.9362, 53.7482),\n    (7.1004, 53.6939),\n    (6.9051, 53.4821),\n    (6.0741, 53.5104),\n    (4.7059, 53.0917),\n    (3.8302, 51.6205),\n    (3.3149, 51.3457),\n    (2.5135, 51.1485),\n    (1.6390, 50.9466),\n    (1.3387, 50.1271),\n    (-0.9894, 49.3473),\n    (-1.9334, 49.7763),\n    (-1.6165, 48.6444),\n    (-3.2958, 48.9016),\n    (-4.5923, 48.6841),\n    (-4.4915, 47.9549),\n    (-2.9632, 47.5703),\n    (-2.2257, 47.0643),\n    (-1.1937, 46.0149),\n    (-1.3842, 44.0226),\n    (-1.9013, 43.4228),\n    (-3.5175, 43.4559),\n    (-4.3478, 43.4034),\n    (-5.4118, 43.5742),\n    (-6.7544, 43.5679),\n    (-7.9781, 43.7483),\n    (-9.3928, 43.0266),\n    (-8.9844, 42.5927),\n    (-9.0348, 41.8805),\n    (-8.9907, 41.5434),\n    (-8.7908, 41.1843),\n    (-8.7686, 40.7606),\n    (-8.9773, 40.1593),\n    (-9.0483, 39.7550),\n    (-9.4469, 39.3920),\n    (-9.5265, 38.7374),\n    (-9.2874, 38.3584),\n    (-8.8399, 38.2662),\n    (-8.7461, 37.6513),\n    (-8.8988, 36.8688),\n    (-8.3828, 36.9788),\n    (-7.8556, 36.8382),\n    (-7.4537, 37.0977),\n    (-6.5201, 36.9429),\n    (-6.2366, 36.3676),\n    (-5.8664, 36.0298),\n    (-5.3771, 35.9468),\n    (-4.9952, 36.3247),\n    (-4.3689, 36.6778),\n    (-3.4157, 36.6588),\n    (-2.1464, 36.6741),\n    (-1.4383, 37.4430),\n    (-0.6833, 37.6423),\n    (-0.4671, 38.2923),\n    (0.1112, 38.7385),\n    (-0.2787, 39.3099),\n    (0.1066, 40.1239),\n    (0.7213, 40.6783),\n    (0.8105, 41.0147),\n    (2.0918, 41.2260),\n    (3.0394, 41.8921),\n    (2.9859, 42.4730),\n    (3.1004, 43.0752),\n    (4.5569, 43.3996),\n    (6.5292, 43.1288),\n    (7.4351, 43.6938),\n    (7.8507, 43.7671),\n    (8.4285, 44.2312),\n    (8.8889, 44.3663),\n    (9.7024, 44.0362),\n    (10.2000, 43.9200),\n    (10.5119, 42.9314),\n    (11.1919, 42.3554),\n    (12.1066, 41.7045),\n    (12.8880, 41.2530),\n    (13.6279, 41.1882),\n    (14.0606, 40.7863),\n    (14.7032, 40.6045),\n    (14.9984, 40.1729),\n    (15.4136, 40.0483),\n    (15.7188, 39.5440),\n    (16.1093, 38.9645),\n    (15.8919, 38.7509),\n    (15.6879, 38.2145),\n    (15.6840, 37.9088),\n    (16.1009, 37.9858),\n    (16.6350, 38.8435),\n    (17.0528, 38.9028),\n    (17.1714, 39.4246),\n    (16.4487, 39.7954),\n    (16.8695, 40.4422),\n    (17.7383, 40.2776),\n    (18.2933, 39.8107),\n    (18.4802, 40.1688),\n    (18.3766, 40.3556),\n    (17.5191, 40.8771),\n    (16.7850, 41.1796),\n    (15.8893, 41.5410),\n    (16.1698, 41.7402),\n    (15.9261, 41.9613),\n    (15.1425, 41.9551),\n    (14.0298, 42.7610),\n    (13.5269, 43.5877),\n    (12.5892, 44.0913),\n    (12.2614, 44.6004),\n    (12.3838, 44.8853),\n    (12.3285, 45.3817),\n    (13.1416, 45.7366),\n    (13.9376, 45.5910),\n    (13.7150, 45.5003),\n    (13.6794, 45.4841),\n    (13.6569, 45.1369),\n    (13.9522, 44.8021),\n    (14.2587, 45.2337),\n    (14.9016, 45.0760),\n    (14.9203, 44.7384),\n    (15.3762, 44.3179),\n    (15.1744, 44.2431),\n    (16.0153, 43.5072),\n    (16.9300, 43.2099),\n    (17.5099, 42.8499),\n    (18.4500, 42.4799),\n    (18.8821, 42.2815),\n    (19.1624, 41.9550),\n    (19.3717, 41.8775),\n    (19.5400, 41.7199),\n    (19.4035, 41.4095),\n    (19.3190, 40.7272),\n    (19.4060, 40.2507),\n    (19.9600, 39.9150),\n    (19.9800, 39.6949),\n    (20.1500, 39.6249),\n    (20.2177, 39.3402),\n    (20.7300, 38.7699),\n    (21.1200, 38.3103),\n    (21.2950, 37.6449),\n    (21.6700, 36.8449),\n    (22.4900, 36.4100),\n    (23.1542, 36.4225),\n    (22.7749, 37.3050),\n    (23.4099, 37.4099),\n    (23.1150, 37.9200),\n    (24.0400, 37.6550),\n    (24.0250, 38.2199),\n    (23.5300, 38.5100),\n    (22.9730, 38.9709),\n    (23.3500, 39.1900),\n    (22.8497, 39.6593),\n    (22.6262, 40.2565),\n    (22.8139, 40.4760),\n    (23.3429, 39.9609),\n    (23.8999, 39.9620),\n    (24.4079, 40.1249),\n    (23.7148, 40.6871),\n    (24.9258, 40.9470),\n    (25.4476, 40.8525),\n    (26.0569, 40.8241),\n    (26.0433, 40.6177),\n    (26.3580, 40.1519),\n    (27.1923, 40.6905),\n    (27.6190, 40.9998),\n    (28.8064, 41.0549),\n    (28.9884, 41.2999),\n    (28.1155, 41.6228),\n    (27.9967, 42.0073),\n    (27.6738, 42.5778),\n    (28.0390, 43.2931),\n    (28.5580, 43.7074),\n    (28.8378, 44.9138),\n    (29.1416, 44.8202),\n    (29.6265, 45.0353),\n    (29.6032, 45.2933),\n    (30.3776, 46.0324),\n    (30.7487, 46.5831),\n    (31.6753, 46.7062),\n    (31.7441, 46.3333),\n    (33.2985, 46.0805),\n    (33.5881, 45.8515),\n    (32.6308, 45.5191),\n    (32.4541, 45.3274),\n    (33.5469, 45.0347),\n    (33.3264, 44.5648),\n    (33.8825, 44.3614),\n    (35.2399, 44.9399),\n    (36.3347, 45.1132),\n    (36.5299, 45.4699),\n    (35.5100, 45.4099),\n    (35.0207, 45.6512),\n    (34.9623, 46.2731),\n    (35.8236, 46.6459),\n    (36.7598, 46.6987),\n    (37.4251, 47.0222),\n    (38.2235, 47.1021),\n    (39.1212, 47.2633),\n    (39.1476, 47.0447),\n    (37.6737, 46.6365),\n    (38.2329, 46.2408),\n    (37.4031, 45.4045),\n    (36.6754, 45.2446),\n    (37.5391, 44.6572),\n    (38.6799, 44.2799),\n    (39.9550, 43.4349),\n    (40.3213, 43.1286),\n    (40.8754, 43.0136),\n    (41.4534, 42.6451),\n    (41.7031, 41.9629),\n    (41.5540, 41.5356),\n    (40.3734, 41.0136),\n    (39.5126, 41.1027),\n    (38.3476, 40.9485),\n    (36.9131, 41.3353),\n    (35.1677, 42.0402),\n    (33.5132, 42.0189),\n    (32.3479, 41.7362),\n    (31.1459, 41.0876),\n    (29.2400, 41.2199),\n    (28.8199, 40.4600),\n    (27.2800, 40.4200),\n    (26.1707, 39.4636),\n    (26.8047, 38.9857),\n    (26.3182, 38.2081),\n    (27.0487, 37.6533),\n    (27.6411, 36.6588),\n    (28.7329, 36.6768),\n    (29.6999, 36.1443),\n    (30.3910, 36.2629),\n    (30.6216, 36.6778),\n    (31.6995, 36.6442),\n    (32.5091, 36.1075),\n    (34.0268, 36.2199),\n    (34.7145, 36.7955),\n    (35.5509, 36.5654),\n    (36.1608, 36.6506),\n    (35.7820, 36.2749),\n    (36.1497, 35.8215),\n    (35.9050, 35.4100),\n    (35.9984, 34.6449),\n    (35.9795, 34.6100),\n    (35.4822, 33.9054),\n    (35.1260, 33.0909),\n    (35.0984, 33.0805),\n    (34.9554, 32.8273),\n    (34.7525, 32.0729),\n    (34.4881, 31.6055),\n    (34.5563, 31.5488),\n    (34.2654, 31.2193),\n    (33.7733, 30.9674),\n    (32.9939, 31.0240),\n    (32.1924, 31.2603),\n    (31.9604, 30.9336),\n    (31.6879, 31.4296),\n    (30.9769, 31.5558),\n    (30.0950, 31.4734),\n    (29.6834, 31.1868),\n    (28.9135, 30.8700),\n    (28.4504, 31.0257),\n    (27.4576, 31.3212),\n    (26.4953, 31.5856),\n    (25.1648, 31.5691),\n    (24.9211, 31.8993),\n    (23.9275, 32.0166),\n    (23.6091, 32.1872),\n    (23.2368, 32.1914),\n    (22.8957, 32.6385),\n    (21.5430, 32.8432),\n    (20.8545, 32.7067),\n    (20.1339, 32.2381),\n    (19.8203, 31.7517),\n    (20.0533, 30.9857),\n    (19.5740, 30.5258),\n    (19.0864, 30.2663),\n    (18.0211, 30.7635),\n    (16.6116, 31.1821),\n    (15.7139, 31.3762),\n    (15.2456, 32.2650),\n    (13.9186, 32.7119),\n    (13.0832, 32.8788),\n    (12.6633, 32.7927),\n    (11.4887, 33.1369),\n    (11.1085, 33.2933),\n    (10.8568, 33.7687),\n    (10.3396, 33.7857),\n    (10.1495, 34.3307),\n    (10.8078, 34.8335),\n    (10.9395, 35.6989),\n    (10.5932, 35.9474),\n    (10.6000, 36.4100),\n    (11.1000, 36.8999),\n    (11.0288, 37.0921),\n    (10.1806, 36.7240),\n    (10.2100, 37.2300),\n    (9.5099, 37.3499),\n    (8.4209, 36.9464),\n    (7.7370, 36.8857),\n    (7.3303, 37.1183),\n    (6.2618, 37.1106),\n    (5.3201, 36.7165),\n    (4.8157, 36.8650),\n    (3.1616, 36.7839),\n    (1.4669, 36.6056),\n    (0.5038, 36.3012),\n    (-0.1274, 35.8886),\n    (-1.2086, 35.7148),\n    (-2.1699, 35.1683),\n    (-2.6043, 35.1790),\n    (-3.6400, 35.3998),\n    (-4.5910, 35.3307),\n    (-5.1938, 35.7551),\n    (-5.9299, 35.7599),\n    (-6.2443, 35.1458),\n    (-6.9125, 34.1104),\n    (-7.6541, 33.6970),\n    (-8.6574, 33.2402),\n    (-9.3006, 32.5646),\n    (-9.4347, 32.0380),\n    (-9.8147, 31.1777),\n    (-9.5648, 29.9335),\n    (-10.3995, 29.0985),\n    (-10.9009, 28.8321),\n    (-11.6889, 28.1486),\n    (-12.6188, 28.0381),\n    (-13.1399, 27.6401),\n    (-13.7738, 26.6188),\n    (-14.4399, 26.2544),\n    (-14.8009, 25.6362),\n    (-14.8246, 25.1035),\n    (-15.0893, 24.5202),\n    (-15.4260, 24.3591),\n    (-15.9826, 23.7233),\n    (-16.3264, 23.0177),\n    (-16.2619, 22.6793),\n    (-16.5891, 22.1582),\n    (-16.9732, 21.8857),\n    (-17.0204, 21.4223),\n    (-17.0634, 20.9997),\n    (-16.5363, 20.5678),\n    (-16.2778, 20.0925),\n    (-16.3776, 19.5938),\n    (-16.2568, 19.0967),\n    (-16.1463, 18.1084),\n    (-16.2705, 17.1669),\n    (-16.5497, 16.6738),\n    (-16.4630, 16.1350),\n    (-16.7007, 15.6215),\n    (-17.1851, 14.9194),\n    (-17.6250, 14.7295),\n    (-17.1261, 14.3735),\n    (-16.7137, 13.5949),\n    (-16.8415, 13.1513),\n    (-16.6774, 12.3848),\n    (-16.6138, 12.1709),\n    (-16.3089, 11.9587),\n    (-16.3147, 11.8065),\n    (-16.0852, 11.5245),\n    (-15.6641, 11.4584),\n    (-15.1303, 11.0404),\n    (-14.8395, 10.8765),\n    (-14.6932, 10.6563),\n    (-14.5796, 10.2144),\n    (-14.3300, 10.0157),\n    (-14.0740, 9.8861),\n    (-13.6851, 9.4947),\n    (-13.2465, 8.9030),\n    (-13.1240, 8.1639),\n    (-12.9490, 7.7986),\n    (-12.4280, 7.2629),\n    (-11.7081, 6.8600),\n    (-11.4387, 6.7859),\n    (-10.7653, 6.1407),\n    (-9.9134, 5.5935),\n    (-9.0047, 4.8324),\n    (-7.9741, 4.3557),\n    (-7.7121, 4.3645),\n    (-7.5189, 4.3382),\n    (-6.5287, 4.7050),\n    (-5.8344, 4.9937),\n    (-4.6499, 5.1682),\n    (-4.0088, 5.1798),\n    (-3.3110, 4.9842),\n    (-2.8561, 4.9944),\n    (-1.9647, 4.7104),\n    (-1.0636, 5.0005),\n    (-0.5076, 5.3434),\n    (1.0601, 5.9288),\n    (1.8652, 6.1421),\n    (2.6917, 6.2588),\n    (3.5741, 6.2583),\n    (4.3256, 6.2706),\n    (5.0335, 5.6118),\n    (5.3628, 4.8879),\n    (5.8981, 4.2624),\n    (6.6980, 4.2405),\n    (7.0825, 4.4646),\n    (7.4621, 4.4121),\n    (8.5002, 4.7719),\n    (8.4888, 4.4956),\n    (8.7449, 4.3522),\n    (8.9481, 3.9041),\n    (9.4043, 3.7345),\n    (9.7951, 3.0734),\n    (9.6491, 2.2838),\n    (9.3056, 1.1609),\n    (9.4928, 1.0101),\n    (9.2913, 0.2686),\n    (9.0484, -0.4593),\n    (8.8300, -0.7790),\n    (8.7979, -1.1113),\n    (9.4052, -2.1443),\n    (10.0661, -2.9694),\n    (11.0937, -3.9788),\n    (11.9149, -5.0379),\n    (12.1823, -5.7899),\n    (12.3224, -6.1000),\n    (12.2273, -6.2944),\n    (12.7282, -6.9271),\n    (12.9330, -7.5965),\n    (13.2364, -8.5626),\n    (12.9290, -8.9590),\n    (12.8753, -9.1669),\n    (13.1209, -9.7668),\n    (13.3873, -10.3735),\n    (13.6863, -10.7310),\n    (13.7387, -11.2978),\n    (13.6337, -12.0386),\n    (13.3129, -12.4836),\n    (12.7384, -13.1379),\n    (12.5000, -13.5476),\n    (12.1756, -14.4491),\n    (12.1235, -14.8783),\n    (11.7785, -15.7938),\n    (11.6400, -16.6731),\n    (11.7341, -17.3018),\n    (11.7949, -18.0691),\n    (12.6085, -19.0453),\n    (12.8268, -19.6731),\n    (13.3524, -20.8728),\n    (13.8686, -21.6990),\n    (14.2577, -22.1112),\n    (14.3857, -22.6566),\n    (14.4081, -23.8530),\n    (14.7432, -25.3929),\n    (14.9897, -26.1173),\n    (15.2104, -27.0909),\n    (15.6018, -27.8212),\n    (16.3449, -28.5767),\n    (17.0629, -29.8759),\n    (17.0644, -29.8786),\n    (17.5669, -30.7257),\n    (18.2217, -31.6616),\n    (18.2479, -32.4291),\n    (17.9251, -32.6112),\n    (18.2500, -33.2814),\n    (18.2444, -33.8677),\n    (18.3774, -34.1365),\n    (18.4246, -33.9978),\n    (18.8553, -34.4443),\n    (19.1932, -34.4625),\n    (19.6164, -34.8191),\n    (20.0712, -34.7951),\n    (20.6890, -34.4171),\n    (21.5427, -34.2588),\n    (22.5741, -33.8640),\n    (22.9881, -33.9164),\n    (23.5940, -33.7944),\n    (24.6778, -33.9871),\n    (25.1728, -33.7968),\n    (25.7806, -33.9446),\n    (25.9096, -33.6670),\n    (26.4194, -33.6149),\n    (27.4646, -33.2269),\n    (28.2197, -32.7719),\n    (28.9255, -32.1720),\n    (30.0557, -31.1402),\n    (30.6228, -30.4237),\n    (30.9017, -29.9099),\n    (31.3255, -29.4019),\n    (31.5210, -29.2573),\n    (32.2033, -28.7524),\n    (32.4621, -28.3010),\n    (32.5802, -27.4701),\n    (32.8301, -26.7421),\n    (32.9159, -26.2158),\n    (32.6603, -26.1485),\n    (32.5746, -25.7273),\n    (33.0132, -25.3575),\n    (34.2158, -24.8163),\n    (35.0407, -24.4783),\n    (35.4587, -24.1226),\n    (35.6074, -23.7065),\n    (35.3717, -23.5353),\n    (35.5339, -23.0707),\n    (35.5625, -22.09),\n    (35.3858, -22.14),\n    (35.3734, -21.8408),\n    (35.1761, -21.2543),\n    (34.7018, -20.4970),\n    (34.7863, -19.7840),\n    (35.1983, -19.5528),\n    (35.8964, -18.8422),\n    (36.2812, -18.6596),\n    (37.4111, -17.5863),\n    (38.5383, -17.1010),\n    (39.4525, -16.7208),\n    (40.0892, -16.1007),\n    (40.4772, -15.4062),\n    (40.7754, -14.6917),\n    (40.5996, -14.2019),\n    (40.5608, -12.6391),\n    (40.4372, -11.7617),\n    (40.4783, -10.7654),\n    (40.3165, -10.3170),\n    (39.9495, -10.0984),\n    (39.5357, -9.1123),\n    (39.1865, -8.4855),\n    (39.2520, -8.0078),\n    (39.1946, -7.7039),\n    (39.4699, -7.0999),\n    (39.4400, -6.8399),\n    (38.7997, -6.4756),\n    (38.7405, -5.9089),\n    (39.2022, -4.6767),\n    (39.6049, -4.3465),\n    (39.8000, -3.6811),\n    (40.1211, -3.2776),\n    (40.2630, -2.5730),\n    (40.6378, -2.4997),\n    (40.8847, -2.0825),\n    (41.5851, -1.6832),\n    (41.8109, -1.4464),\n    (42.0415, -0.9191),\n    (43.1359, 0.2921),\n    (44.0681, 1.0528),\n    (45.5639, 2.0457),\n    (46.5647, 2.8552),\n    (47.7407, 4.2194),\n    (48.5945, 5.3391),\n    (49.4527, 6.8046),\n    (50.0709, 8.0817),\n    (50.5523, 9.1987),\n    (50.8341, 10.2797),\n    (51.0452, 10.6409),\n    (51.0415, 11.1665),\n    (51.1338, 11.7481),\n    (51.1112, 12.0246),\n    (50.7320, 12.0219),\n    (50.2587, 11.6795),\n    (49.7286, 11.5789),\n    (49.2677, 11.4303),\n    (48.9482, 11.4106),\n    (48.3787, 11.3754),\n    (48.0215, 11.1930),\n    (47.5256, 11.1272),\n    (46.6454, 10.8165),\n    (45.5569, 10.6980),\n    (44.6142, 10.4422),\n    (44.1178, 10.4455),\n    (43.6666, 10.8641),\n    (43.4706, 11.2777),\n    (43.1453, 11.4620),\n    (42.7158, 11.7356),\n    (43.2863, 11.9749),\n    (43.3178, 12.3901),\n    (43.0812, 12.6996),\n    (42.5895, 13.0004),\n    (42.2768, 13.3439),\n    (41.7349, 13.9210),\n    (41.1792, 14.4910),\n    (39.8142, 15.4356),\n    (39.2661, 15.9227),\n    (38.9906, 16.8406),\n    (38.4100, 17.9983),\n    (37.8627, 18.3678),\n    (37.4817, 18.6140),\n    (37.1147, 19.8079),\n    (36.9694, 20.8374),\n    (37.1887, 21.0188),\n    (36.86623, 22.0),\n    (36.6907, 22.2048),\n    (35.5259, 23.1024),\n    (35.4937, 23.7523),\n    (35.6924, 23.9267),\n    (34.7950, 25.0337),\n    (34.4738, 25.5985),\n    (34.1045, 26.1422),\n    (33.3487, 27.6998),\n    (32.7348, 28.7052),\n    (32.3204, 29.7604),\n    (32.4232, 29.8510),\n    (33.1367, 28.4176),\n    (33.5881, 27.9713),\n    (33.9213, 27.6487),\n    (34.1545, 27.8233),\n    (34.4265, 28.3439),\n    (34.6417, 29.0994),\n    (34.9226, 29.5013),\n    (34.9560, 29.3565),\n    (34.8322, 28.9574),\n    (34.7877, 28.6074),\n    (34.6323, 28.0585),\n    (35.1301, 28.0633),\n    (35.6401, 27.3765),\n    (36.2491, 26.5701),\n    (36.6396, 25.8262),\n    (36.9316, 25.6029),\n    (37.2094, 25.0845),\n    (37.1548, 24.8584),\n    (37.4836, 24.2854),\n    (38.0238, 24.0786),\n    (38.4927, 23.6884),\n    (39.0663, 22.5796),\n    (39.0236, 21.9868),\n    (39.1393, 21.2919),\n    (39.8016, 20.3388),\n    (40.2476, 20.1746),\n    (40.9393, 19.4864),\n    (41.2213, 18.6715),\n    (41.7543, 17.8330),\n    (42.2708, 17.4747),\n    (42.3479, 17.0758),\n    (42.6495, 16.7746),\n    (42.7793, 16.3478),\n    (42.8236, 15.9117),\n    (42.7024, 15.7188),\n    (42.8050, 15.2619),\n    (42.6048, 15.2133),\n    (42.8922, 14.8022),\n    (43.0879, 14.0626),\n    (43.2514, 13.7675),\n    (43.2228, 13.2209),\n    (43.4829, 12.6368),\n    (44.1751, 12.5859),\n    (44.4945, 12.7216),\n    (44.9895, 12.6995),\n    (45.1443, 12.9539),\n    (45.4064, 13.0269),\n    (45.6250, 13.2909),\n    (45.8775, 13.3477),\n    (46.7170, 13.3996),\n    (47.3544, 13.5922),\n    (47.9389, 14.0072),\n    (48.2389, 13.9480),\n    (48.6792, 14.0032),\n    (49.5745, 14.7087),\n    (51.1725, 15.1752),\n    (52.1681, 15.5974),\n    (52.1917, 15.9384),\n    (52.3852, 16.3824),\n    (53.1085, 16.6510),\n    (53.5705, 16.7076),\n    (54.2392, 17.0449),\n    (54.7910, 16.9506),\n    (55.2749, 17.2283),\n    (55.2699, 17.6323),\n    (55.6614, 17.8841),\n    (56.2835, 17.8760),\n    (56.5121, 18.0871),\n    (56.6096, 18.5742),\n    (57.2342, 18.9479),\n    (57.6943, 18.9447),\n    (57.7887, 19.0675),\n    (57.6657, 19.7360),\n    (57.8263, 20.2430),\n    (58.0343, 20.4814),\n    (58.4879, 20.4289),\n    (58.8611, 21.1140),\n    (59.2824, 21.4338),\n    (59.4421, 21.7145),\n    (59.8061, 22.3105),\n    (59.8080, 22.5336),\n    (59.4500, 22.6602),\n    (59.1805, 22.9923),\n    (58.7292, 23.5656),\n    (58.1369, 23.7479),\n    (57.4034, 23.8785),\n    (56.8451, 24.2416),\n    (56.3968, 24.9247),\n    (56.2610, 25.7146),\n    (56.3914, 25.8959),\n    (56.4856, 26.3091),\n    (56.3620, 26.3959),\n    (56.0708, 26.0554),\n    (55.4390, 25.4391),\n    (54.6930, 24.7978),\n    (54.0080, 24.1217),\n    (53.4040, 24.1513),\n    (52.5770, 24.1774),\n    (51.7943, 24.0198),\n    (51.7574, 24.2940),\n    (51.5795, 24.2454),\n    (51.3896, 24.6273),\n    (51.6067, 25.2156),\n    (51.5890, 25.8011),\n    (51.2864, 26.1145),\n    (51.0133, 26.0069),\n    (50.7439, 25.4824),\n    (50.8101, 24.7547),\n    (50.6605, 24.9998),\n    (50.5273, 25.3278),\n    (50.2398, 25.6080),\n    (50.1133, 25.9439),\n    (50.2129, 26.2770),\n    (50.1524, 26.6896),\n    (49.4709, 27.1099),\n    (49.2995, 27.4612),\n    (48.8075, 27.6896),\n    (48.4160, 28.5520),\n    (48.0939, 29.3062),\n    (48.1831, 29.5344),\n    (47.9745, 29.9758),\n    (48.5679, 29.9267),\n    (48.9413, 30.3170),\n    (49.5768, 29.9857),\n    (50.1150, 30.1477),\n    (50.8529, 28.8145),\n    (51.5207, 27.8656),\n    (52.4835, 27.5808),\n    (53.4930, 26.8123),\n    (54.7150, 26.4806),\n    (55.7237, 26.9646),\n    (56.4921, 27.1433),\n    (56.9707, 26.9661),\n    (57.3972, 25.7399),\n    (58.5257, 25.6099),\n    (59.6161, 25.3801),\n    (61.4973, 25.0782),\n    (62.9057, 25.2184),\n    (64.5304, 25.2370),\n    (66.3728, 25.4251),\n    (67.1454, 24.6636),\n    (67.4436, 23.9448),\n    (68.1766, 23.6919),\n    (69.3495, 22.8431),\n    (69.6449, 22.4507),\n    (69.1641, 22.0892),\n    (70.4704, 20.8773),\n    (71.1752, 20.7574),\n    (72.6305, 21.3560),\n    (72.8244, 20.4195),\n    (72.8209, 19.2082),\n    (73.1199, 17.9285),\n    (73.5341, 15.9906),\n    (74.4438, 14.6172),\n    (74.6167, 13.9925),\n    (74.8648, 12.7419),\n    (75.3961, 11.7812),\n    (75.7464, 11.3082),\n    (76.1300, 10.2996),\n    (76.5929, 8.8992),\n    (77.5398, 7.9655),\n    (77.9411, 8.2529),\n    (78.2779, 8.9330),\n    (79.1897, 9.2165),\n    (78.8853, 9.5461),\n    (79.3405, 10.3088),\n    (79.8579, 10.3572),\n    (79.8625, 12.0562),\n    (80.2862, 13.0062),\n    (80.2332, 13.8357),\n    (80.0250, 15.1364),\n    (80.3248, 15.8991),\n    (80.7919, 15.9519),\n    (81.6927, 16.3102),\n    (82.1912, 16.5566),\n    (82.1927, 17.0166),\n    (83.1892, 17.6712),\n    (83.9410, 18.3020),\n    (85.0602, 19.4785),\n    (86.4993, 20.1516),\n    (87.0331, 20.7433),\n    (86.9757, 21.4955),\n    (88.2084, 21.7031),\n    (88.8887, 21.6905),\n    (89.0319, 22.0557),\n    (89.4188, 21.9661),\n    (89.7020, 21.8571),\n    (89.8474, 22.0391),\n    (90.2729, 21.8363),\n    (90.5869, 22.3927),\n    (90.4960, 22.8050),\n    (91.4170, 22.7650),\n    (91.8348, 22.1829),\n    (92.0252, 21.7015),\n    (92.0828, 21.1921),\n    (92.3685, 20.6708),\n    (93.0782, 19.8551),\n    (93.6632, 19.7269),\n    (93.5409, 19.3664),\n    (94.3248, 18.2135),\n    (94.5334, 17.2772),\n    (94.1888, 16.0379),\n    (94.8084, 15.8034),\n    (95.3693, 15.7143),\n    (96.5057, 16.4272),\n    (97.1645, 16.9287),\n    (97.5970, 16.1005),\n    (97.7777, 14.8372),\n    (98.1036, 13.6404),\n    (98.5095, 13.1223),\n    (98.4283, 12.0329),\n    (98.7645, 11.4412),\n    (98.4571, 10.6752),\n    (98.5535, 9.9329),\n    (98.2591, 8.9739),\n    (98.1500, 8.3500),\n    (98.3396, 7.7945),\n    (98.5037, 8.3823),\n    (98.9882, 7.9079),\n    (99.5196, 7.3434),\n    (99.6906, 6.8482),\n    (100.0857, 6.4644),\n    (100.3062, 6.0405),\n    (100.1967, 5.3124),\n    (100.5574, 4.7672),\n    (100.6954, 3.9391),\n    (101.2735, 3.2702),\n    (101.3906, 2.7608),\n    (102.5736, 1.9671),\n    (103.5197, 1.2263),\n    (104.2288, 1.2930),\n    (104.2479, 1.6311),\n    (103.8546, 2.5154),\n    (103.5024, 2.7910),\n    (103.4294, 3.3828),\n    (103.3321, 3.7266),\n    (103.4385, 4.1816),\n    (103.3812, 4.8550),\n    (102.9617, 5.5244),\n    (102.3711, 6.1282),\n    (102.1411, 6.2216),\n    (101.6230, 6.7406),\n    (101.0173, 6.8568),\n    (100.4592, 7.4295),\n    (100.2796, 8.2951),\n    (99.8738, 9.2078),\n    (99.2223, 9.2392),\n    (99.1537, 9.9630),\n    (99.4789, 10.8463),\n    (100.0187, 12.3070),\n    (100.0977, 13.4068),\n    (100.9784, 13.4127),\n    (100.8318, 12.6270),\n    (101.6871, 12.6457),\n    (102.5849, 12.1865),\n    (103.0906, 11.1536),\n    (103.4972, 10.6325),\n    (104.3343, 10.4865),\n    (105.0762, 9.9184),\n    (104.7951, 9.2410),\n    (105.1582, 8.5997),\n    (106.4051, 9.5308),\n    (107.2209, 10.3644),\n    (108.3661, 11.0083),\n    (109.2001, 11.6668),\n    (109.3352, 13.4260),\n    (108.8771, 15.2766),\n    (108.2694, 16.0797),\n    (107.3619, 16.6974),\n    (106.4268, 18.0041),\n    (105.6620, 19.0581),\n    (105.8816, 19.7520),\n    (106.7150, 20.6968),\n    (108.0501, 21.5523),\n    (108.5228, 21.7152),\n    (109.8644, 21.3950),\n    (109.6276, 21.0082),\n    (109.8898, 20.2824),\n    (110.4440, 20.3410),\n    (110.5093, 20.5654),\n    (110.7854, 21.3971),\n    (111.8435, 21.5504),\n    (113.2410, 22.0513),\n    (113.8067, 22.5483),\n    (114.1525, 22.2237),\n    (114.7638, 22.6680),\n    (115.8907, 22.7828),\n    (117.2816, 23.6245),\n    (118.6568, 24.5473),\n    (119.5854, 25.7407),\n    (120.3954, 27.0532),\n    (121.1256, 28.1356),\n    (121.6844, 28.2255),\n    (121.9384, 29.0180),\n    (122.0921, 29.8325),\n    (121.5035, 30.1429),\n    (121.2642, 30.6762),\n    (121.8919, 30.9493),\n    (121.9081, 31.6921),\n    (121.2290, 32.4603),\n    (120.6203, 33.3767),\n    (120.2275, 34.3603),\n    (119.1512, 34.9098),\n    (119.6645, 35.6097),\n    (120.6370, 36.1114),\n    (121.1041, 36.6513),\n    (122.5199, 36.9306),\n    (122.3579, 37.4544),\n    (121.7112, 37.4811),\n    (120.8234, 37.8704),\n    (119.7028, 37.1563),\n    (118.9116, 37.4484),\n    (118.8781, 37.8973),\n    (118.0596, 38.0614),\n    (117.5327, 38.7376),\n    (118.0427, 39.2042),\n    (119.0234, 39.2523),\n    (119.6396, 39.8980),\n    (120.7686, 40.5933),\n    (121.6403, 40.9463),\n    (122.1685, 40.4224),\n    (121.3767, 39.7502),\n    (121.5859, 39.3608),\n    (121.0545, 38.8974),\n    (122.1313, 39.1704),\n    (122.8675, 39.6377),\n    (124.2656, 39.9284),\n    (124.7374, 39.6603),\n    (125.3211, 39.5513),\n    (125.3865, 39.3879),\n    (125.1328, 38.8485),\n    (125.2219, 38.6658),\n    (124.9859, 38.5484),\n    (124.7121, 38.1083),\n    (124.9810, 37.9488),\n    (125.2400, 37.8572),\n    (125.2753, 37.6690),\n    (125.5684, 37.7520),\n    (125.6891, 37.9400),\n    (126.1747, 37.7496),\n    (126.8601, 36.8939),\n    (126.1173, 36.7254),\n    (126.5592, 35.6845),\n    (126.3739, 34.9345),\n    (126.4857, 34.3900),\n    (127.3865, 34.4756),\n    (128.1858, 34.8903),\n    (129.0913, 35.0824),\n    (129.4683, 35.6321),\n    (129.4604, 36.7841),\n    (129.2129, 37.4323),\n    (128.3497, 38.6122),\n    (127.7833, 39.0508),\n    (127.3854, 39.2134),\n    (127.5021, 39.3239),\n    (127.5334, 39.7568),\n    (127.9674, 40.0254),\n    (128.6333, 40.1898),\n    (129.0103, 40.4854),\n    (129.1881, 40.6618),\n    (129.7051, 40.8828),\n    (129.6673, 41.6011),\n    (129.9659, 41.9413),\n    (130.4000, 42.2800),\n    (130.7800, 42.2200),\n    (130.9358, 42.5527),\n    (132.2780, 43.2845),\n    (132.9062, 42.7984),\n    (133.5368, 42.8114),\n    (134.8694, 43.3982),\n    (135.5153, 43.9889),\n    (136.8623, 45.1434),\n    (138.2197, 46.3079),\n    (138.5547, 46.9996),\n    (140.0619, 48.4467),\n    (140.5130, 50.0455),\n    (140.5974, 51.2396),\n    (141.3792, 52.2387),\n    (141.3453, 53.0895),\n    (139.9015, 54.1896),\n    (138.8046, 54.2545),\n    (138.1647, 53.7550),\n    (137.1934, 53.9773),\n    (136.7017, 54.6035),\n    (135.1261, 54.7295),\n    (138.9584, 57.0880),\n    (142.1978, 59.0399),\n    (145.4872, 59.3363),\n    (148.5448, 59.1644),\n    (149.7837, 59.6557),\n    (151.3381, 59.5039),\n    (151.2657, 58.7808),\n    (152.8118, 58.8838),\n    (155.0437, 59.1449),\n    (154.2180, 59.7581),\n    (156.7206, 61.4344),\n    (159.3023, 61.7739),\n    (160.1214, 60.5442),\n    (162.6579, 61.6424),\n    (163.2583, 62.4662),\n    (164.4735, 62.5506),\n    (163.6696, 61.1408),\n    (161.87204, 60.343),\n    (160.1506, 59.3147),\n    (158.3643, 58.0557),\n    (156.8103, 57.8320),\n    (156.7581, 57.3647),\n    (155.9144, 56.7679),\n    (155.4336, 55.3810),\n    (155.9918, 53.1589),\n    (156.42, 51.7),\n    (156.7897, 51.0110),\n    (158.2311, 51.9426),\n    (158.5309, 52.9586),\n    (160.0217, 53.2025),\n    (160.3687, 54.3443),\n    (162.1174, 54.8551),\n    (161.7014, 55.2856),\n    (162.1263, 56.1158),\n    (163.0579, 56.1592),\n    (163.1919, 57.6150),\n    (162.0529, 57.8391),\n    (162.0173, 58.2432),\n    (163.2171, 59.2110),\n    (163.5392, 59.8686),\n    (164.8767, 59.7316),\n    (165.84, 60.16),\n    (166.2949, 59.7885),\n    (168.9004, 60.5735),\n    (170.3308, 59.8817),\n    (170.6985, 60.3361),\n    (172.15, 60.95),\n    (173.6801, 61.6526),\n    (174.5692, 61.7691),\n    (177.3643, 62.5219),\n    (179.2282, 62.3041),\n    (179.4863, 62.5689),\n    (179.3703, 62.9826),\n    (178.9082, 63.2519),\n    (178.313, 64.07593),\n    (177.4112, 64.6082),\n    (178.7072, 64.5349),\n    (180.0, 64.9797),\n    (-177.5500, 68.1999),\n    (-179.9999, 68.9636),\n    (-179.9999, -16.0671),\n    (-179.7933, -16.0208),\n    (-179.9173, -16.5017),\n    (-179.9999, -16.5552),\n    (125.9470, -8.4320),\n    (126.6447, -8.3982),\n    (126.9572, -8.2733),\n    (127.3359, -8.3973),\n    (126.9679, -8.6682),\n    (125.9258, -9.1060),\n    (125.0885, -9.3931),\n    (124.4359, -10.1400),\n    (123.5799, -10.3599),\n    (123.4599, -10.2399),\n    (123.5500, -9.9000),\n    (123.9800, -9.2900),\n    (124.9686, -8.8927),\n    (125.0862, -8.6568),\n    (125.9470, -8.4320),\n    (-180.0, 68.9636),\n    (-177.5500, 68.1999),\n    (-174.9282, 67.2058),\n    (-175.0142, 66.5843),\n    (-174.3398, 66.3355),\n    (-174.5718, 67.0621),\n    (-171.8573, 66.9130),\n    (-169.8995, 65.9772),\n    (-170.8910, 65.5413),\n    (-172.5302, 65.4379),\n    (-172.555, 64.46079),\n    (-172.9553, 64.2526),\n    (-173.8918, 64.2826),\n    (-174.6539, 64.6312),\n    (-175.9835, 64.9228),\n    (-176.2071, 65.3566),\n    (-177.2226, 65.5202),\n    (-178.3599, 65.3905),\n    (-178.9033, 65.7404),\n    (-178.6861, 66.1121),\n    (-179.8837, 65.8745),\n    (-179.4326, 65.4041),\n    (-180.0, 64.9797),\n    (-180.0, 71.5157),\n    (-179.8718, 71.5576),\n    (-179.0243, 71.5555),\n    (-177.5779, 71.2694),\n    (-177.6635, 71.1327),\n    (-178.6937, 70.8930),\n    (-180.0, 70.8321),\n    (180.0, 70.8321),\n    (178.9034, 70.7811),\n    (178.7253, 71.0988),\n    (180.0, 71.5157),\n    (180.0, -16.5552),\n    (179.3641, -16.8013),\n    (178.7250, -17.0120),\n    (178.5968, -16.6391),\n    (179.0966, -16.4339),\n    (179.4135, -16.3790),\n    (180.0, -16.0671),\n    (-61.2, -51.85),\n    (-60.0, -51.25),\n    (-59.15, -51.5),\n    (-58.55, -51.1),\n    (-57.75, -51.55),\n    (-58.05, -51.9),\n    (-59.4, -52.2),\n    (-59.85, -51.85),\n    (-60.7, -52.3),\n    (-61.2, -51.85),\n    (68.935, -48.625),\n    (69.58, -48.94),\n    (70.525, -49.065),\n    (70.56, -49.255),\n    (70.28, -49.71),\n    (68.745, -49.775),\n    (68.72, -49.2425),\n    (68.8675, -48.83),\n    (68.935, -48.625),\n    (178.1255, -17.5048),\n    (178.3736, -17.3399),\n    (178.7180, -17.6284),\n    (178.5527, -18.1505),\n    (177.9326, -18.2879),\n    (177.3814, -18.1643),\n    (177.2850, -17.7246),\n    (177.6708, -17.3811),\n    (178.1255, -17.5048),\n    (-61.68, 10.76),\n    (-61.105, 10.89),\n    (-60.895, 10.855),\n    (-60.935, 10.11),\n    (-61.77, 10.0),\n    (-61.95, 10.09),\n    (-61.66, 10.365),\n    (-61.68, 10.76),\n    (-155.4021, 20.0797),\n    (-155.2245, 19.9930),\n    (-155.0622, 19.8591),\n    (-154.8074, 19.5087),\n    (-154.8314, 19.4532),\n    (-155.2221, 19.2397),\n    (-155.5421, 19.0834),\n    (-155.6881, 18.9161),\n    (-155.9366, 19.0593),\n    (-155.9080, 19.3388),\n    (-156.0734, 19.7029),\n    (-156.0236, 19.8142),\n    (-155.8500, 19.9772),\n    (-155.9190, 20.1739),\n    (-155.8610, 20.2672),\n    (-155.7850, 20.2487),\n    (-155.4021, 20.0797),\n    (-155.9956, 20.7640),\n    (-156.0792, 20.6439),\n    (-156.4144, 20.5724),\n    (-156.58673, 20.783),\n    (-156.7016, 20.8643),\n    (-156.7105, 20.9267),\n    (-156.6125, 21.0124),\n    (-156.2571, 20.9174),\n    (-155.9956, 20.7640),\n    (-156.7582, 21.1768),\n    (-156.7893, 21.0687),\n    (-157.3252, 21.0977),\n    (-157.2502, 21.2195),\n    (-156.7582, 21.1768),\n    (-158.0252, 21.7169),\n    (-157.9416, 21.6527),\n    (-157.6528, 21.3221),\n    (-157.7070, 21.2644),\n    (-157.7786, 21.2772),\n    (-158.1266, 21.3124),\n    (-158.2538, 21.5391),\n    (-158.2926, 21.5791),\n    (-158.0252, 21.7169),\n    (-159.3656, 22.2149),\n    (-159.34512, 21.982),\n    (-159.4637, 21.8829),\n    (-159.8005, 22.0653),\n    (-159.7487, 22.1382),\n    (-159.5962, 22.2361),\n    (-159.3656, 22.2149),\n    (-78.1908, 25.2103),\n    (-77.89, 25.17),\n    (-77.54, 24.34),\n    (-77.5346, 23.7597),\n    (-77.78, 23.71),\n    (-78.0340, 24.2861),\n    (-78.4084, 24.5756),\n    (-78.1908, 25.2103),\n    (-78.98, 26.79),\n    (-78.51, 26.87),\n    (-77.85, 26.84),\n    (-77.82, 26.58),\n    (-78.91, 26.42),\n    (-78.98, 26.79),\n    (-77.79, 27.04),\n    (-77.0, 26.59),\n    (-77.1725, 25.8791),\n    (-77.3564, 26.0073),\n    (-77.34, 26.53),\n    (-77.7880, 26.9251),\n    (-77.79, 27.04),\n    (-64.0148, 47.0360),\n    (-63.6645, 46.5500),\n    (-62.9393, 46.4158),\n    (-62.0120, 46.4431),\n    (-62.5039, 46.0333),\n    (-62.8743, 45.9681),\n    (-64.1428, 46.3926),\n    (-64.3926, 46.7274),\n    (-64.0148, 47.0360),\n    (46.6820, 44.6092),\n    (47.6759, 45.6414),\n    (48.6454, 45.8062),\n    (49.1011, 46.3993),\n    (50.0340, 46.6089),\n    (51.1919, 47.0487),\n    (52.0420, 46.8046),\n    (53.0427, 46.8530),\n    (53.2208, 46.2346),\n    (53.0408, 45.2590),\n    (52.1673, 45.4083),\n    (51.3168, 45.2459),\n    (51.2785, 44.5148),\n    (50.3056, 44.6098),\n    (50.3391, 44.2840),\n    (50.8912, 44.0310),\n    (51.3424, 43.1329),\n    (52.5014, 42.7922),\n    (52.6921, 42.4438),\n    (52.4463, 42.0271),\n    (52.5024, 41.7833),\n    (52.8146, 41.1353),\n    (52.9167, 41.8681),\n    (53.7217, 42.1231),\n    (54.0083, 41.5512),\n    (54.7368, 40.9510),\n    (53.8581, 40.6310),\n    (52.9152, 40.8765),\n    (52.6939, 40.0336),\n    (53.3578, 39.9752),\n    (53.1010, 39.2905),\n    (53.8809, 38.9520),\n    (53.7355, 37.9061),\n    (53.9215, 37.1989),\n    (53.8257, 36.9650),\n    (52.2640, 36.7004),\n    (50.8423, 36.8728),\n    (50.1477, 37.3745),\n    (49.1996, 37.5828),\n    (48.8832, 38.3202),\n    (48.8565, 38.8154),\n    (49.2232, 39.0492),\n    (49.3952, 39.3994),\n    (49.5692, 40.1761),\n    (50.3928, 40.2565),\n    (50.0848, 40.5261),\n    (49.6189, 40.5729),\n    (49.1102, 41.2822),\n    (48.5843, 41.8088),\n    (47.4925, 42.9865),\n    (47.5909, 43.6601),\n    (46.6820, 44.6092),\n    (-64.5191, 49.8730),\n    (-64.1732, 49.9571),\n    (-62.8582, 49.7064),\n    (-61.8355, 49.2885),\n    (-61.8063, 49.1050),\n    (-62.2931, 49.0871),\n    (-63.5892, 49.4006),\n    (-64.5191, 49.8730),\n    (-80.3153, 62.0855),\n    (-79.9293, 62.3856),\n    (-79.5200, 62.3637),\n    (-79.2658, 62.1586),\n    (-79.6575, 61.6330),\n    (-80.0995, 61.7181),\n    (-80.3621, 62.0164),\n    (-80.3153, 62.0855),\n    (-83.9936, 62.4528),\n    (-83.2504, 62.9140),\n    (-81.8769, 62.9045),\n    (-81.8982, 62.7108),\n    (-83.0685, 62.1592),\n    (-83.7746, 62.1823),\n    (-83.9936, 62.4528),\n    (-75.2159, 67.4442),\n    (-75.8658, 67.1488),\n    (-76.9868, 67.0987),\n    (-77.2364, 67.5880),\n    (-76.8116, 68.1485),\n    (-75.8952, 68.2872),\n    (-75.1145, 68.0103),\n    (-75.1033, 67.5820),\n    (-75.2159, 67.4442),\n    (-96.5574, 69.6800),\n    (-95.6476, 69.1076),\n    (-96.2695, 68.7570),\n    (-97.6174, 69.0600),\n    (-98.4318, 68.9507),\n    (-99.7974, 69.4000),\n    (-98.9174, 69.7100),\n    (-98.2182, 70.1435),\n    (-97.1574, 69.8600),\n    (-96.5574, 69.6800),\n    (-106.5225, 73.0760),\n    (-105.4024, 72.6725),\n    (-104.7748, 71.6984),\n    (-104.4647, 70.9929),\n    (-102.7853, 70.4977),\n    (-100.9807, 70.0243),\n    (-101.0893, 69.5844),\n    (-102.7311, 69.5040),\n    (-102.0932, 69.1196),\n    (-102.4302, 68.7528),\n    (-104.24, 68.91),\n    (-105.96, 69.18),\n    (-107.1225, 69.1192),\n    (-109.0, 68.78),\n    (-111.5341, 68.6300),\n    (-113.3132, 68.5355),\n    (-113.8549, 69.0074),\n    (-115.22, 69.28),\n    (-116.1079, 69.1682),\n    (-117.34, 69.96),\n    (-116.6747, 70.0665),\n    (-115.1311, 70.2373),\n    (-113.7213, 70.1923),\n    (-112.4161, 70.3663),\n    (-114.3499, 70.6000),\n    (-116.4868, 70.5204),\n    (-117.9048, 70.5405),\n    (-118.4323, 70.9092),\n    (-116.1131, 71.3091),\n    (-117.6556, 71.2951),\n    (-119.4019, 71.5585),\n    (-118.5626, 72.3078),\n    (-117.8664, 72.7059),\n    (-115.1890, 73.3145),\n    (-114.1671, 73.1214),\n    (-114.6663, 72.6527),\n    (-112.4410, 72.9553),\n    (-111.0503, 72.4504),\n    (-109.9203, 72.9611),\n    (-109.0065, 72.6333),\n    (-108.1883, 71.6508),\n    (-107.6859, 72.0654),\n    (-108.3964, 73.0895),\n    (-107.5164, 73.2359),\n    (-106.5225, 73.0760),\n    (-79.7758, 72.8029),\n    (-80.8760, 73.3331),\n    (-80.8338, 73.6931),\n    (-80.3530, 73.7597),\n    (-78.0644, 73.6519),\n    (-76.34, 73.1026),\n    (-76.2514, 72.8263),\n    (-77.3144, 72.8555),\n    (-78.3916, 72.8766),\n    (-79.4862, 72.7422),\n    (-79.7758, 72.8029),\n    (139.8631, 73.3698),\n    (140.8117, 73.7650),\n    (142.0620, 73.8575),\n    (143.4828, 73.4752),\n    (143.6038, 73.2124),\n    (142.0876, 73.2054),\n    (140.0381, 73.3169),\n    (139.8631, 73.3698),\n    (148.2222, 75.3458),\n    (150.7316, 75.0840),\n    (149.5759, 74.6889),\n    (147.9774, 74.7783),\n    (146.1191, 75.1729),\n    (146.3584, 75.4968),\n    (148.2222, 75.3458),\n    (138.8310, 76.1367),\n    (141.4716, 76.0928),\n    (145.0862, 75.5626),\n    (144.3, 74.82),\n    (140.6138, 74.8476),\n    (138.9554, 74.6114),\n    (136.9743, 75.2616),\n    (137.5117, 75.9491),\n    (138.8310, 76.1367),\n    (-98.5770, 76.5886),\n    (-98.5, 76.72),\n    (-97.7355, 76.2565),\n    (-97.7044, 75.7434),\n    (-98.16, 75.0),\n    (-99.8087, 74.8974),\n    (-100.8836, 75.0573),\n    (-100.8629, 75.6407),\n    (-102.5020, 75.5638),\n    (-102.5655, 76.3365),\n    (-101.4897, 76.3053),\n    (-99.9834, 76.6463),\n    (-98.5770, 76.5886),\n    (102.8378, 79.2812),\n    (105.3724, 78.7133),\n    (105.0754, 78.3068),\n    (99.43814, 77.921),\n    (101.2649, 79.2339),\n    (102.0863, 79.3464),\n    (102.8378, 79.2812),\n    (93.7776, 81.0246),\n    (95.9408, 81.2504),\n    (97.8838, 80.7469),\n    (100.1866, 79.7801),\n    (99.9397, 78.8809),\n    (97.7579, 78.7562),\n    (94.9725, 79.0447),\n    (93.3128, 79.4265),\n    (92.5454, 80.1437),\n    (91.1810, 80.3414),\n    (93.7776, 81.0246),\n    (-96.0164, 80.6023),\n    (-95.3234, 80.9072),\n    (-94.2984, 80.9772),\n    (-94.7354, 81.2064),\n    (-92.4098, 81.2573),\n    (-91.1328, 80.7234),\n    (-87.81, 80.32),\n    (-87.02, 79.66),\n    (-85.8143, 79.3369),\n    (-87.1875, 79.0393),\n    (-89.0353, 78.2872),\n    (-90.8043, 78.2153),\n    (-92.8766, 78.3433),\n    (-93.9511, 78.7510),\n    (-93.9357, 79.1137),\n    (-93.1452, 79.3801),\n    (-94.9739, 79.3724),\n    (-96.0761, 79.7050),\n    (-96.7097, 80.1577),\n    (-96.0164, 80.6023),\n    (-91.5870, 81.8942),\n    (-90.1, 82.085),\n    (-88.9322, 82.1175),\n    (-86.9702, 82.2796),\n    (-85.5, 82.6522),\n    (-84.2600, 82.6),\n    (-83.18, 82.32),\n    (-82.42, 82.86),\n    (-81.1, 83.02),\n    (-79.3066, 83.1305),\n    (-76.25, 83.1720),\n    (-75.7187, 83.0640),\n    (-72.8315, 83.2332),\n    (-70.6657, 83.1697),\n    (-68.5, 83.1063),\n    (-65.8273, 83.0280),\n    (-63.68, 82.9),\n    (-61.85, 82.6286),\n    (-61.8938, 82.3616),\n    (-64.334, 81.92775),\n    (-66.7534, 81.7252),\n    (-67.6575, 81.5014),\n    (-65.4803, 81.5065),\n    (-67.84, 80.9),\n    (-69.4697, 80.6168),\n    (-71.18, 79.8),\n    (-73.2428, 79.6341),\n    (-73.88, 79.4301),\n    (-76.9077, 79.3230),\n    (-75.5292, 79.1976),\n    (-76.2204, 79.0190),\n    (-75.3934, 78.5258),\n    (-76.3435, 78.1829),\n    (-77.8885, 77.8999),\n    (-78.3626, 77.5085),\n    (-79.7595, 77.2096),\n    (-79.6196, 76.9833),\n    (-77.9108, 77.0220),\n    (-77.8891, 76.7779),\n    (-80.5612, 76.1781),\n    (-83.1743, 76.4540),\n    (-86.1118, 76.2990),\n    (-87.6, 76.42),\n    (-89.4906, 76.4723),\n    (-89.6161, 76.9521),\n    (-87.7673, 77.1783),\n    (-88.26, 77.9),\n    (-87.65, 77.9702),\n    (-84.9763, 77.5387),\n    (-86.34, 78.18),\n    (-87.9619, 78.3718),\n    (-87.1519, 78.7586),\n    (-85.3786, 78.9969),\n    (-85.0949, 79.3454),\n    (-86.5073, 79.7362),\n    (-86.9317, 80.2514),\n    (-84.1984, 80.2083),\n    (-83.4086, 80.1),\n    (-81.8482, 80.4644),\n    (-84.1, 80.58),\n    (-87.5989, 80.5162),\n    (-89.3666, 80.8556),\n    (-90.2, 81.26),\n    (-91.3678, 81.5531),\n    (-91.5870, 81.8942),\n    (-46.7637, 82.6279),\n    (-43.4064, 83.2251),\n    (-39.8975, 83.1801),\n    (-38.6221, 83.5490),\n    (-35.0878, 83.6451),\n    (-27.1004, 83.5196),\n    (-20.8453, 82.7266),\n    (-22.6918, 82.3416),\n    (-26.5175, 82.2976),\n    (-31.9, 82.2),\n    (-31.3964, 82.0215),\n    (-27.8566, 82.1317),\n    (-24.8444, 81.7869),\n    (-22.9032, 82.0931),\n    (-22.0717, 81.7344),\n    (-23.1696, 81.1527),\n    (-20.6236, 81.5246),\n    (-15.7681, 81.9124),\n    (-12.7701, 81.7188),\n    (-12.2085, 81.2915),\n    (-16.2853, 80.5800),\n    (-16.85, 80.35),\n    (-20.0462, 80.1770),\n    (-17.7303, 80.1291),\n    (-18.9, 79.4),\n    (-19.7049, 78.7512),\n    (-19.6735, 77.6385),\n    (-18.4728, 76.9856),\n    (-20.0350, 76.9443),\n    (-21.6794, 76.6279),\n    (-19.8340, 76.0980),\n    (-19.5989, 75.2483),\n    (-20.6681, 75.1558),\n    (-19.3728, 74.2956),\n    (-21.5942, 74.2238),\n    (-20.4345, 73.8171),\n    (-20.7623, 73.4643),\n    (-22.1722, 73.3095),\n    (-23.5659, 73.3066),\n    (-22.3131, 72.6292),\n    (-22.2995, 72.1840),\n    (-24.2783, 72.5978),\n    (-24.7929, 72.3302),\n    (-23.4429, 72.0801),\n    (-22.1328, 71.4689),\n    (-21.7535, 70.6636),\n    (-23.53603, 70.471),\n    (-24.3070, 70.8564),\n    (-25.5434, 71.4309),\n    (-25.2013, 70.7522),\n    (-26.3627, 70.2264),\n    (-23.7274, 70.1840),\n    (-22.3490, 70.1294),\n    (-25.0292, 69.2588),\n    (-27.7473, 68.4704),\n    (-30.6737, 68.1250),\n    (-31.7766, 68.1207),\n    (-32.8110, 67.7354),\n    (-34.2019, 66.6797),\n    (-36.3528, 65.9789),\n    (-37.0437, 65.9376),\n    (-38.3750, 65.6921),\n    (-39.8122, 65.4584),\n    (-40.6689, 64.8399),\n    (-40.6828, 64.1390),\n    (-41.1887, 63.4824),\n    (-42.8193, 62.6823),\n    (-42.4166, 61.9009),\n    (-42.8661, 61.0740),\n    (-43.3784, 60.0977),\n    (-44.7875, 60.0367),\n    (-46.2636, 60.8532),\n    (-48.2629, 60.8584),\n    (-49.2330, 61.4068),\n    (-49.9003, 62.3833),\n    (-51.6332, 63.6269),\n    (-52.1401, 64.2784),\n    (-52.2765, 65.1767),\n    (-53.6616, 66.0995),\n    (-53.3016, 66.8365),\n    (-53.9691, 67.1889),\n    (-52.9804, 68.3575),\n    (-51.4753, 68.7295),\n    (-51.0804, 69.1478),\n    (-50.8712, 69.9291),\n    (-52.0135, 69.5749),\n    (-52.5579, 69.4261),\n    (-53.4562, 69.2836),\n    (-54.6833, 69.6100),\n    (-54.7500, 70.2893),\n    (-54.3588, 70.8213),\n    (-53.4313, 70.8357),\n    (-51.3901, 70.5697),\n    (-53.1093, 71.2048),\n    (-54.0042, 71.5471),\n    (-55.0, 71.4065),\n    (-55.8346, 71.6544),\n    (-54.7181, 72.5862),\n    (-55.3263, 72.9586),\n    (-56.1200, 73.6497),\n    (-57.3236, 74.7102),\n    (-58.5967, 75.0986),\n    (-58.5851, 75.5172),\n    (-61.2686, 76.1023),\n    (-63.3916, 76.1752),\n    (-66.0642, 76.1348),\n    (-68.5043, 76.0614),\n    (-69.6648, 76.3797),\n    (-71.4025, 77.0085),\n    (-68.7767, 77.3231),\n    (-66.7639, 77.3759),\n    (-71.0429, 77.6359),\n    (-73.297, 78.04419),\n    (-73.1593, 78.4327),\n    (-69.3734, 78.9138),\n    (-65.7107, 79.3943),\n    (-65.3239, 79.7581),\n    (-68.0229, 80.1172),\n    (-67.1512, 80.5158),\n    (-63.6892, 81.2139),\n    (-62.2344, 81.3211),\n    (-62.6511, 81.7704),\n    (-60.2824, 82.0336),\n    (-57.2074, 82.1907),\n    (-54.1344, 82.1996),\n    (-53.0432, 81.8883),\n    (-50.3906, 82.4388),\n    (-48.0038, 82.0648),\n    (-46.5998, 81.9859),\n    (-44.523, 81.6607),\n    (-46.9007, 82.1997),\n    (-46.7637, 82.6279),\n    (-106.6, 73.6),\n    (-105.26, 73.64),\n    (-104.5, 73.42),\n    (-105.38, 72.76),\n    (-106.94, 73.46),\n    (-106.6, 73.6),\n    (-180.0, -84.71338),\n    (-179.9424, -84.7214),\n    (-179.0586, -84.1394),\n    (-177.2567, -84.4529),\n    (-176.0846, -84.0992),\n    (-175.8298, -84.1179),\n    (-174.3825, -84.5343),\n    (-173.1165, -84.1179),\n    (-172.8891, -84.0610),\n    (-169.9512, -83.8846),\n    (-168.9999, -84.1179),\n    (-168.5301, -84.2373),\n    (-167.0220, -84.5704),\n    (-164.1821, -84.8252),\n    (-161.9297, -85.1387),\n    (-158.0713, -85.3739),\n    (-155.1922, -85.0995),\n    (-150.9420, -85.2955),\n    (-148.5330, -85.6090),\n    (-145.8889, -85.3151),\n    (-143.1077, -85.0407),\n    (-142.8922, -84.5704),\n    (-146.8290, -84.5312),\n    (-150.0607, -84.2961),\n    (-150.9029, -83.9042),\n    (-153.5862, -83.6886),\n    (-153.4099, -83.2380),\n    (-153.0377, -82.8265),\n    (-152.6656, -82.4541),\n    (-152.8615, -82.0426),\n    (-154.5262, -81.7683),\n    (-155.2901, -81.4156),\n    (-156.8374, -81.1021),\n    (-154.4087, -81.1609),\n    (-152.0976, -81.0041),\n    (-150.6482, -81.3373),\n    (-148.8659, -81.0433),\n    (-147.2207, -80.6710),\n    (-146.4177, -80.3379),\n    (-146.7702, -79.9264),\n    (-148.0629, -79.6520),\n    (-149.5319, -79.3582),\n    (-151.5884, -79.2993),\n    (-153.3903, -79.1622),\n    (-155.3293, -79.0642),\n    (-155.9756, -78.6919),\n    (-157.2683, -78.3784),\n    (-158.0517, -78.0256),\n    (-158.3651, -76.8892),\n    (-157.8754, -76.9872),\n    (-156.9745, -77.3007),\n    (-155.3293, -77.2027),\n    (-153.7428, -77.0655),\n    (-152.9202, -77.4966),\n    (-151.3337, -77.3987),\n    (-150.0019, -77.1831),\n    (-148.7484, -76.9088),\n    (-147.6124, -76.5757),\n    (-146.1044, -76.4777),\n    (-146.1435, -76.1054),\n    (-146.4960, -75.7331),\n    (-146.2023, -75.3804),\n    (-144.9096, -75.2040),\n    (-144.3220, -75.5371),\n    (-142.7943, -75.3412),\n    (-141.6387, -75.0864),\n    (-140.2090, -75.0668),\n    (-138.8575, -74.9689),\n    (-137.5062, -74.7337),\n    (-136.4289, -74.5182),\n    (-135.2145, -74.3026),\n    (-134.4311, -74.3614),\n    (-133.7456, -74.4398),\n    (-132.2571, -74.3026),\n    (-130.9253, -74.4790),\n    (-129.5542, -74.4594),\n    (-128.2420, -74.3222),\n    (-126.8906, -74.4202),\n    (-125.4020, -74.5182),\n    (-124.0114, -74.4790),\n    (-122.5621, -74.4986),\n    (-121.0736, -74.5182),\n    (-119.7025, -74.4790),\n    (-118.6841, -74.1850),\n    (-117.4698, -74.0283),\n    (-116.2163, -74.2438),\n    (-115.0215, -74.0675),\n    (-113.9443, -73.7148),\n    (-113.2979, -74.0283),\n    (-112.9454, -74.3810),\n    (-112.2990, -74.7141),\n    (-111.2610, -74.4202),\n    (-110.0663, -74.7925),\n    (-108.7149, -74.9101),\n    (-107.5593, -75.1844),\n    (-106.1491, -75.1256),\n    (-104.8760, -74.9493),\n    (-103.3679, -74.9884),\n    (-102.0165, -75.1256),\n    (-100.6455, -75.3020),\n    (-100.1166, -74.8709),\n    (-100.7630, -74.5378),\n    (-101.2527, -74.1850),\n    (-102.5453, -74.1067),\n    (-103.1133, -73.7344),\n    (-103.3287, -73.3620),\n    (-103.6812, -72.6175),\n    (-102.9174, -72.7546),\n    (-101.6052, -72.8134),\n    (-100.3125, -72.7546),\n    (-99.1373, -72.9114),\n    (-98.1188, -73.2053),\n    (-97.6880, -73.5580),\n    (-96.3365, -73.6168),\n    (-95.0439, -73.4797),\n    (-93.6729, -73.2837),\n    (-92.4390, -73.1661),\n    (-91.4205, -73.4013),\n    (-90.0887, -73.3229),\n    (-89.2269, -72.5587),\n    (-88.4239, -73.0093),\n    (-87.2683, -73.1857),\n    (-86.0148, -73.0877),\n    (-85.1922, -73.4797),\n    (-83.8799, -73.5188),\n    (-82.6656, -73.6364),\n    (-81.4709, -73.8519),\n    (-80.6874, -73.4797),\n    (-80.2957, -73.1269),\n    (-79.2968, -73.5188),\n    (-77.9258, -73.4208),\n    (-76.9073, -73.6364),\n    (-76.2218, -73.9695),\n    (-74.8900, -73.8716),\n    (-73.8520, -73.6560),\n    (-72.8335, -73.4013),\n    (-71.6192, -73.2641),\n    (-70.2090, -73.1465),\n    (-68.9359, -73.0093),\n    (-67.9566, -72.7938),\n    (-67.3690, -72.4803),\n    (-67.1340, -72.0492),\n    (-67.2515, -71.6377),\n    (-67.5649, -71.2458),\n    (-67.9174, -70.8539),\n    (-68.2308, -70.4620),\n    (-68.4854, -70.1093),\n    (-68.5442, -69.7173),\n    (-68.4462, -69.3255),\n    (-67.9762, -68.9532),\n    (-67.5844, -68.5417),\n    (-67.4278, -68.1498),\n    (-67.6236, -67.7187),\n    (-67.7411, -67.3268),\n    (-67.2515, -66.8761),\n    (-66.7031, -66.5822),\n    (-66.0568, -66.2099),\n    (-65.3713, -65.8963),\n    (-64.5682, -65.6025),\n    (-64.1765, -65.1714),\n    (-63.6281, -64.8970),\n    (-63.0013, -64.6423),\n    (-62.0416, -64.5835),\n    (-61.4149, -64.2700),\n    (-60.7098, -64.0740),\n    (-59.8872, -63.9565),\n    (-59.1625, -63.7017),\n    (-58.5945, -63.3882),\n    (-57.8111, -63.2706),\n    (-57.2235, -63.5254),\n    (-57.5957, -63.8585),\n    (-58.6141, -64.1524),\n    (-59.0450, -64.3680),\n    (-59.7893, -64.2112),\n    (-60.6119, -64.3092),\n    (-61.2974, -64.5443),\n    (-62.0221, -64.7990),\n    (-62.5117, -65.0930),\n    (-62.6488, -65.4849),\n    (-62.5901, -65.8572),\n    (-62.1200, -66.1903),\n    (-62.8055, -66.4255),\n    (-63.7456, -66.5038),\n    (-64.2941, -66.8370),\n    (-64.8816, -67.1504),\n    (-65.5084, -67.5816),\n    (-65.6650, -67.9538),\n    (-65.3125, -68.3653),\n    (-64.7837, -68.6789),\n    (-63.9611, -68.9139),\n    (-63.1972, -69.2275),\n    (-62.7859, -69.6194),\n    (-62.5705, -69.9917),\n    (-62.2767, -70.3836),\n    (-61.8066, -70.7167),\n    (-61.5129, -71.0890),\n    (-61.3758, -72.0100),\n    (-61.0819, -72.3823),\n    (-61.0036, -72.7742),\n    (-60.6902, -73.1661),\n    (-60.8273, -73.6952),\n    (-61.3758, -74.1067),\n    (-61.9633, -74.4398),\n    (-63.2952, -74.5769),\n    (-63.7456, -74.9297),\n    (-64.3528, -75.2628),\n    (-65.8609, -75.6351),\n    (-67.1928, -75.7919),\n    (-68.4462, -76.0074),\n    (-69.7977, -76.2229),\n    (-70.6007, -76.6344),\n    (-72.2067, -76.6736),\n    (-73.9695, -76.6344),\n    (-75.5559, -76.7128),\n    (-77.2403, -76.7128),\n    (-76.9269, -77.1048),\n    (-75.3992, -77.2810),\n    (-74.2828, -77.5554),\n    (-73.6561, -77.9081),\n    (-74.7725, -78.2216),\n    (-76.4961, -78.1236),\n    (-77.9258, -78.3784),\n    (-77.9846, -78.7899),\n    (-78.0237, -79.1818),\n    (-76.8486, -79.5149),\n    (-76.6332, -79.8872),\n    (-75.3600, -80.2595),\n    (-73.2448, -80.4163),\n    (-71.4429, -80.6906),\n    (-70.0131, -81.0041),\n    (-68.1916, -81.3176),\n    (-65.7042, -81.4744),\n    (-63.2560, -81.7487),\n    (-61.5520, -82.0426),\n    (-59.6914, -82.3758),\n    (-58.7121, -82.8461),\n    (-58.2224, -83.2184),\n    (-57.0081, -82.8656),\n    (-55.3628, -82.5717),\n    (-53.6197, -82.2582),\n    (-51.5436, -82.0035),\n    (-49.7613, -81.7291),\n    (-47.2739, -81.7095),\n    (-44.8257, -81.8467),\n    (-42.8083, -82.0819),\n    (-42.1620, -81.6508),\n    (-40.7714, -81.3568),\n    (-38.2448, -81.3373),\n    (-36.2666, -81.1217),\n    (-34.3863, -80.9061),\n    (-32.3102, -80.7690),\n    (-30.0970, -80.5926),\n    (-28.5498, -80.3379),\n    (-29.2549, -79.9851),\n    (-29.6858, -79.6325),\n    (-29.6858, -79.2602),\n    (-31.6248, -79.2993),\n    (-33.6813, -79.4561),\n    (-35.6399, -79.4561),\n    (-35.9141, -79.0838),\n    (-35.7770, -78.3392),\n    (-35.3265, -78.1236),\n    (-33.8967, -77.8885),\n    (-32.2123, -77.6534),\n    (-30.9980, -77.3595),\n    (-29.7837, -77.0655),\n    (-28.8827, -76.6736),\n    (-27.5117, -76.4973),\n    (-26.1603, -76.3601),\n    (-25.4748, -76.2818),\n    (-23.9275, -76.2425),\n    (-22.4585, -76.1054),\n    (-21.2246, -75.9094),\n    (-20.0103, -75.6743),\n    (-18.9135, -75.4392),\n    (-17.5229, -75.1256),\n    (-16.6415, -74.7925),\n    (-15.7014, -74.4986),\n    (-15.4077, -74.1067),\n    (-16.4653, -73.8716),\n    (-16.1127, -73.4601),\n    (-15.4468, -73.1465),\n    (-14.4088, -72.9505),\n    (-13.3119, -72.7154),\n    (-12.2935, -72.4019),\n    (-11.5100, -72.0100),\n    (-11.0204, -71.5397),\n    (-10.2957, -71.2654),\n    (-9.1010, -71.3242),\n    (-8.6113, -71.6573),\n    (-7.4166, -71.6965),\n    (-7.3774, -71.3242),\n    (-6.8682, -70.9323),\n    (-5.7909, -71.0302),\n    (-5.5363, -71.4026),\n    (-4.3416, -71.4613),\n    (-3.0489, -71.2850),\n    (-1.7954, -71.1674),\n    (-0.6594, -71.2262),\n    (-0.2286, -71.6377),\n    (0.8681, -71.3046),\n    (1.8866, -71.1282),\n    (3.0226, -70.9911),\n    (4.1390, -70.8539),\n    (5.1575, -70.6187),\n    (6.2739, -70.4620),\n    (7.1357, -70.2465),\n    (7.7428, -69.8937),\n    (8.4871, -70.1485),\n    (9.5251, -70.0113),\n    (10.2498, -70.4816),\n    (10.8178, -70.8343),\n    (11.9538, -70.6383),\n    (12.4042, -70.2465),\n    (13.4227, -69.9721),\n    (14.7349, -70.0309),\n    (15.1267, -70.4032),\n    (15.9493, -70.0309),\n    (17.0265, -69.9133),\n    (18.2017, -69.8741),\n    (19.2593, -69.8937),\n    (20.3757, -70.0113),\n    (21.4529, -70.0701),\n    (21.9230, -70.4032),\n    (22.5694, -70.6971),\n    (23.6661, -70.5208),\n    (24.8413, -70.4816),\n    (25.9773, -70.4816),\n    (27.0937, -70.4620),\n    (28.0925, -70.3248),\n    (29.1502, -70.2072),\n    (30.0315, -69.9329),\n    (30.9717, -69.7566),\n    (31.9901, -69.6586),\n    (32.7540, -69.3842),\n    (33.3024, -68.8356),\n    (33.8704, -68.5025),\n    (34.9084, -68.6592),\n    (35.3002, -69.0120),\n    (36.1620, -69.2471),\n    (37.2000, -69.1687),\n    (37.9051, -69.5214),\n    (38.6494, -69.7762),\n    (39.6678, -69.5410),\n    (40.0204, -69.1099),\n    (40.9213, -68.9336),\n    (41.9594, -68.6005),\n    (42.9387, -68.4633),\n    (44.1138, -68.2674),\n    (44.8972, -68.0518),\n    (45.7199, -67.8167),\n    (46.5033, -67.6011),\n    (47.4434, -67.7187),\n    (48.3444, -67.3660),\n    (48.9907, -67.0917),\n    (49.9308, -67.1113),\n    (50.7534, -66.8761),\n    (50.9493, -66.5234),\n    (51.7915, -66.2491),\n    (52.6141, -66.0531),\n    (53.6130, -65.8963),\n    (54.5335, -65.8180),\n    (55.4149, -65.8768),\n    (56.3550, -65.9747),\n    (57.1580, -66.2491),\n    (57.2559, -66.6802),\n    (58.1373, -67.0133),\n    (58.7445, -67.2876),\n    (59.9393, -67.4052),\n    (60.6052, -67.6795),\n    (61.4278, -67.9538),\n    (62.3874, -68.0126),\n    (63.1904, -67.8167),\n    (64.0523, -67.4052),\n    (64.9924, -67.6207),\n    (65.9717, -67.7383),\n    (66.9118, -67.8559),\n    (67.8911, -67.9343),\n    (68.8900, -67.9343),\n    (69.7126, -68.9727),\n    (69.6734, -69.2275),\n    (69.5559, -69.6782),\n    (68.5962, -69.9329),\n    (67.8127, -70.3052),\n    (67.9498, -70.6971),\n    (69.0663, -70.6775),\n    (68.9291, -71.0694),\n    (68.4199, -71.4417),\n    (67.9498, -71.8532),\n    (68.7137, -72.1668),\n    (69.8693, -72.2647),\n    (71.0248, -72.0884),\n    (71.5732, -71.6965),\n    (71.9062, -71.3242),\n    (72.4546, -71.0107),\n    (73.0814, -70.7167),\n    (73.3360, -70.3640),\n    (73.8648, -69.8741),\n    (74.4915, -69.7762),\n    (75.6275, -69.7370),\n    (76.6264, -69.6194),\n    (77.6449, -69.4626),\n    (78.1345, -69.0707),\n    (78.4283, -68.6984),\n    (79.1138, -68.3262),\n    (80.0931, -68.0715),\n    (80.9353, -67.8755),\n    (81.4837, -67.5423),\n    (82.0517, -67.3660),\n    (82.7764, -67.2092),\n    (83.7753, -67.3072),\n    (84.6762, -67.2092),\n    (85.6555, -67.0917),\n    (86.7523, -67.1504),\n    (87.4770, -66.8761),\n    (87.9862, -66.2099),\n    (88.3584, -66.4842),\n    (88.8284, -66.9545),\n    (89.6706, -67.1504),\n    (90.6303, -67.2288),\n    (91.5900, -67.1113),\n    (92.6085, -67.1896),\n    (93.5486, -67.2092),\n    (94.1754, -67.1113),\n    (95.0175, -67.1701),\n    (95.7814, -67.3856),\n    (96.6823, -67.2485),\n    (97.7596, -67.2485),\n    (98.6802, -67.1113),\n    (99.7181, -67.2485),\n    (100.3841, -66.9153),\n    (100.8933, -66.5822),\n    (101.5788, -66.3078),\n    (102.8324, -65.5632),\n    (103.4786, -65.7004),\n    (104.2425, -65.9747),\n    (104.9084, -66.3275),\n    (106.1815, -66.9349),\n    (107.1608, -66.9545),\n    (108.0813, -66.9545),\n    (109.1586, -66.8370),\n    (110.2358, -66.6998),\n    (111.0584, -66.4255),\n    (111.7439, -66.1315),\n    (112.8603, -66.0923),\n    (113.6046, -65.8768),\n    (114.3880, -66.0727),\n    (114.8973, -66.3862),\n    (115.6023, -66.6998),\n    (116.6991, -66.6606),\n    (117.3847, -66.9153),\n    (118.5794, -67.1701),\n    (119.8329, -67.2680),\n    (120.8709, -67.1896),\n    (121.6544, -66.8761),\n    (122.3203, -66.5626),\n    (123.2212, -66.4842),\n    (124.1222, -66.6214),\n    (125.1602, -66.7193),\n    (126.1003, -66.5626),\n    (127.0014, -66.5626),\n    (127.8827, -66.6606),\n    (128.8032, -66.7586),\n    (129.7042, -66.5822),\n    (130.7814, -66.4255),\n    (131.7999, -66.3862),\n    (132.9358, -66.3862),\n    (133.8564, -66.2883),\n    (134.7573, -66.2099),\n    (135.0315, -65.7200),\n    (135.0707, -65.3085),\n    (135.6974, -65.5828),\n    (135.8738, -66.0335),\n    (136.2067, -66.4450),\n    (136.6180, -66.7781),\n    (137.4602, -66.9545),\n    (138.5962, -66.8957),\n    (139.9084, -66.8761),\n    (140.8094, -66.8173),\n    (142.1216, -66.8173),\n    (143.0618, -66.7977),\n    (144.3740, -66.8370),\n    (145.4904, -66.9153),\n    (146.1955, -67.2288),\n    (145.9996, -67.6011),\n    (146.6460, -67.8951),\n    (147.7232, -68.1302),\n    (148.8396, -68.3850),\n    (150.1323, -68.5612),\n    (151.4837, -68.7181),\n    (152.5022, -68.8748),\n    (153.6381, -68.8945),\n    (154.2845, -68.5612),\n    (155.1658, -68.8356),\n    (155.9297, -69.1492),\n    (156.8111, -69.3842),\n    (158.0255, -69.4822),\n    (159.1810, -69.5998),\n    (159.6706, -69.9917),\n    (160.8066, -70.2268),\n    (161.5704, -70.5796),\n    (162.6868, -70.7363),\n    (163.8424, -70.7167),\n    (164.9196, -70.7755),\n    (166.1144, -70.7559),\n    (167.3090, -70.8343),\n    (168.4256, -70.9714),\n    (169.4635, -71.2066),\n    (170.5016, -71.4026),\n    (171.2067, -71.6965),\n    (171.0892, -72.0884),\n    (170.5604, -72.4411),\n    (170.1099, -72.8918),\n    (169.7573, -73.2445),\n    (169.2873, -73.6560),\n    (167.9751, -73.8128),\n    (167.3874, -74.1654),\n    (166.0948, -74.3810),\n    (165.6443, -74.7729),\n    (164.9588, -75.1452),\n    (164.2341, -75.4588),\n    (163.8227, -75.8703),\n    (163.5682, -76.2425),\n    (163.4702, -76.6933),\n    (163.4898, -77.0655),\n    (164.0578, -77.4574),\n    (164.2733, -77.8297),\n    (164.7434, -78.1825),\n    (166.6041, -78.3196),\n    (166.9957, -78.7507),\n    (165.1938, -78.9074),\n    (163.6662, -79.1230),\n    (161.7663, -79.1622),\n    (160.9241, -79.7304),\n    (160.7478, -80.2007),\n    (160.3169, -80.5730),\n    (159.7882, -80.9453),\n    (161.1200, -81.2785),\n    (161.6292, -81.6900),\n    (162.4909, -82.0622),\n    (163.7053, -82.3954),\n    (165.0959, -82.7089),\n    (166.6041, -83.0224),\n    (168.8956, -83.3359),\n    (169.4047, -83.8258),\n    (172.2839, -84.0414),\n    (172.4770, -84.1179),\n    (173.2240, -84.4137),\n    (175.9856, -84.1589),\n    (178.2772, -84.4725),\n    (180.0, -84.71338),\n];\n\npub static WORLD_LOW_RESOLUTION: [(f64, f64); 1166] = [\n    (-92.32, 48.24),\n    (-88.13, 48.92),\n    (-83.11, 46.27),\n    (-81.66, 44.76),\n    (-82.09, 42.29),\n    (-77.10, 44.00),\n    (-69.95, 46.92),\n    (-65.92, 45.32),\n    (-66.37, 44.25),\n    (-61.22, 45.43),\n    (-64.94, 47.34),\n    (-64.12, 48.52),\n    (-70.68, 47.02),\n    (-67.24, 49.33),\n    (-59.82, 50.48),\n    (-56.14, 52.46),\n    (-59.07, 53.58),\n    (-58.26, 54.21),\n    (-60.69, 55.33),\n    (-61.97, 57.41),\n    (-64.35, 59.49),\n    (-67.29, 58.15),\n    (-69.89, 59.91),\n    (-71.31, 61.45),\n    (-78.22, 61.97),\n    (-77.28, 59.53),\n    (-77.09, 55.88),\n    (-79.06, 51.68),\n    (-82.23, 52.70),\n    (-86.75, 55.72),\n    (-92.17, 56.86),\n    (-95.61, 58.82),\n    (-92.66, 62.02),\n    (-90.65, 63.24),\n    (-95.96, 64.12),\n    (-89.88, 63.98),\n    (-89.30, 65.22),\n    (-86.86, 66.12),\n    (-84.54, 66.88),\n    (-82.30, 67.76),\n    (-83.10, 69.68),\n    (-86.05, 67.98),\n    (-88.18, 68.20),\n    (-91.00, 68.82),\n    (-91.72, 69.69),\n    (-93.15, 71.09),\n    (-96.58, 71.05),\n    (-93.35, 69.52),\n    (-94.23, 68.25),\n    (-95.96, 66.73),\n    (-98.83, 68.27),\n    (-102.45, 67.69),\n    (-108.34, 68.43),\n    (-105.83, 68.05),\n    (-108.15, 66.60),\n    (-111.15, 67.63),\n    (-114.10, 68.23),\n    (-120.92, 69.44),\n    (-124.32, 69.26),\n    (-128.76, 70.50),\n    (-131.86, 69.19),\n    (-131.15, 69.79),\n    (-135.81, 69.13),\n    (-140.19, 69.37),\n    (-141.20, 69.58),\n    (-141.21, 69.56),\n    (-142.49, 69.83),\n    (-148.09, 70.26),\n    (-154.37, 70.96),\n    (-159.53, 70.38),\n    (-166.64, 68.25),\n    (-161.56, 66.55),\n    (-162.99, 65.97),\n    (-168.23, 65.49),\n    (-161.12, 64.49),\n    (-165.29, 62.57),\n    (-164.58, 60.06),\n    (-162.06, 58.36),\n    (-157.85, 58.12),\n    (-162.34, 55.06),\n    (-156.52, 57.11),\n    (-153.53, 59.32),\n    (-149.18, 60.81),\n    (-149.90, 59.50),\n    (-146.54, 60.36),\n    (-139.98, 59.73),\n    (-137.12, 58.28),\n    (-136.01, 59.12),\n    (-133.84, 57.12),\n    (-131.46, 55.98),\n    (-132.08, 57.20),\n    (-140.37, 60.25),\n    (-141.21, 60.16),\n    (-133.38, 58.93),\n    (-130.88, 54.83),\n    (-128.86, 53.90),\n    (-126.58, 52.12),\n    (-127.08, 50.80),\n    (-124.42, 49.66),\n    (-122.56, 48.91),\n    (-122.44, 48.92),\n    (-124.42, 47.18),\n    (-124.52, 42.48),\n    (-123.09, 38.45),\n    (-121.73, 36.62),\n    (-117.60, 33.34),\n    (-117.28, 32.64),\n    (-117.29, 32.48),\n    (-114.75, 27.80),\n    (-112.53, 24.80),\n    (-110.55, 24.07),\n    (-114.23, 29.59),\n    (-112.58, 29.99),\n    (-109.57, 25.94),\n    (-105.61, 21.94),\n    (-102.09, 17.87),\n    (-95.75, 15.94),\n    (-92.21, 14.97),\n    (-92.22, 14.71),\n    (-86.74, 12.06),\n    (-83.03, 8.65),\n    (-79.93, 8.74),\n    (-77.00, 7.82),\n    (-81.99, 8.97),\n    (-83.92, 12.70),\n    (-86.33, 15.80),\n    (-88.40, 15.92),\n    (-88.45, 17.42),\n    (-87.01, 21.33),\n    (-91.65, 18.72),\n    (-96.96, 20.37),\n    (-97.65, 25.67),\n    (-97.62, 25.82),\n    (-95.62, 28.84),\n    (-90.77, 29.03),\n    (-87.33, 30.22),\n    (-82.69, 28.15),\n    (-80.16, 26.66),\n    (-80.74, 32.31),\n    (-76.89, 35.43),\n    (-76.47, 38.21),\n    (-75.66, 37.67),\n    (-71.31, 41.76),\n    (-69.44, 44.17),\n    (-67.69, 47.03),\n    (-73.18, 45.14),\n    (-79.26, 43.28),\n    (-82.84, 42.59),\n    (-83.49, 45.32),\n    (-86.36, 43.65),\n    (-87.75, 43.42),\n    (-86.01, 45.96),\n    (-87.00, 46.59),\n    (-91.39, 46.79),\n    (-90.05, 47.96),\n    (-152.62, 58.41),\n    (-152.60, 58.40),\n    (-153.30, 57.80),\n    (-152.40, 57.48),\n    (-153.32, 57.79),\n    (-166.96, 53.96),\n    (-167.01, 53.95),\n    (-168.36, 53.50),\n    (-168.19, 53.36),\n    (-170.73, 52.68),\n    (-170.60, 52.55),\n    (-174.47, 51.94),\n    (-174.47, 51.92),\n    (-176.58, 51.71),\n    (-176.64, 51.73),\n    (-177.55, 51.76),\n    (-177.41, 51.63),\n    (-178.27, 51.75),\n    (177.35, 51.80),\n    (177.33, 51.76),\n    (172.44, 53.00),\n    (172.55, 53.03),\n    (-123.40, 48.33),\n    (-128.00, 50.84),\n    (-123.50, 48.34),\n    (-132.49, 52.88),\n    (-132.44, 52.91),\n    (-132.64, 53.02),\n    (-131.97, 53.71),\n    (-132.63, 53.02),\n    (-55.36, 51.56),\n    (-54.66, 49.52),\n    (-53.65, 47.48),\n    (-52.98, 46.31),\n    (-56.12, 46.84),\n    (-58.47, 47.57),\n    (-57.61, 50.38),\n    (-55.39, 51.53),\n    (-61.37, 49.01),\n    (-61.80, 49.29),\n    (-61.38, 49.03),\n    (-63.01, 46.71),\n    (-64.42, 46.61),\n    (-63.04, 46.68),\n    (-60.14, 46.48),\n    (-60.14, 46.50),\n    (-71.97, 41.11),\n    (-71.97, 41.15),\n    (-80.79, 27.03),\n    (-81.01, 26.99),\n    (-113.01, 42.09),\n    (-113.10, 42.01),\n    (-155.74, 20.02),\n    (-155.73, 19.98),\n    (-156.51, 20.78),\n    (-156.51, 20.78),\n    (-157.12, 21.21),\n    (-157.08, 20.95),\n    (-157.87, 21.42),\n    (-159.53, 22.07),\n    (-117.44, 66.46),\n    (-119.59, 65.24),\n    (-123.95, 65.03),\n    (-123.69, 66.44),\n    (-119.21, 66.22),\n    (-117.44, 66.44),\n    (-120.71, 64.03),\n    (-114.91, 62.30),\n    (-109.07, 62.72),\n    (-112.62, 61.19),\n    (-118.68, 61.19),\n    (-117.01, 61.17),\n    (-115.97, 62.56),\n    (-119.46, 64.00),\n    (-120.59, 63.94),\n    (-112.31, 58.46),\n    (-108.90, 59.44),\n    (-104.14, 58.90),\n    (-102.56, 56.72),\n    (-101.82, 58.73),\n    (-104.65, 58.91),\n    (-111.00, 58.51),\n    (-112.35, 58.62),\n    (-98.74, 50.09),\n    (-99.75, 52.24),\n    (-99.62, 51.47),\n    (-98.82, 50.39),\n    (-97.02, 50.21),\n    (-97.50, 54.02),\n    (-98.69, 52.93),\n    (-97.19, 51.09),\n    (-96.98, 50.20),\n    (-95.34, 49.04),\n    (-92.32, 50.34),\n    (-94.14, 49.47),\n    (-95.36, 48.82),\n    (-80.39, 56.16),\n    (-79.22, 55.94),\n    (-80.34, 56.08),\n    (-103.56, 58.60),\n    (-103.60, 58.58),\n    (-101.82, 58.03),\n    (-102.33, 58.10),\n    (-101.77, 58.06),\n    (-101.88, 55.79),\n    (-97.92, 57.15),\n    (-101.22, 55.85),\n    (-101.88, 55.74),\n    (-77.61, 6.80),\n    (-78.70, 0.97),\n    (-80.75, -4.47),\n    (-76.19, -14.57),\n    (-70.44, -18.75),\n    (-70.68, -26.15),\n    (-71.44, -32.03),\n    (-73.38, -37.27),\n    (-73.06, -42.11),\n    (-73.17, -46.09),\n    (-73.52, -48.05),\n    (-73.67, -51.56),\n    (-71.06, -53.88),\n    (-69.14, -50.77),\n    (-67.51, -46.59),\n    (-63.49, -42.80),\n    (-62.14, -40.16),\n    (-57.12, -36.71),\n    (-53.17, -34.15),\n    (-51.26, -32.02),\n    (-48.16, -25.48),\n    (-40.73, -22.32),\n    (-38.88, -15.24),\n    (-34.60, -7.81),\n    (-41.95, -3.42),\n    (-48.02, -1.84),\n    (-48.44, -1.57),\n    (-50.81, 0.00),\n    (-54.47, 5.39),\n    (-60.59, 8.32),\n    (-64.19, 9.88),\n    (-70.78, 10.64),\n    (-70.97, 11.89),\n    (-76.26, 8.76),\n    (-77.61, 6.80),\n    (-69.14, -52.79),\n    (-66.16, -55.08),\n    (-70.01, -54.88),\n    (-70.55, -53.85),\n    (-59.29, -51.58),\n    (-59.35, -51.54),\n    (-58.65, -51.55),\n    (-58.55, -51.56),\n    (-84.39, 21.44),\n    (-73.90, 19.73),\n    (-79.27, 21.18),\n    (-83.74, 21.80),\n    (-84.32, 21.42),\n    (-66.96, 17.95),\n    (-67.05, 17.89),\n    (-77.88, 17.22),\n    (-78.06, 16.98),\n    (-74.47, 18.08),\n    (-69.88, 18.99),\n    (-71.10, 17.76),\n    (-74.45, 17.86),\n    (-85.28, 73.74),\n    (-85.79, 70.96),\n    (-85.13, 71.94),\n    (-84.74, 72.96),\n    (-80.61, 73.10),\n    (-78.45, 72.20),\n    (-75.44, 72.55),\n    (-73.89, 71.98),\n    (-72.56, 71.04),\n    (-71.49, 70.57),\n    (-69.78, 70.29),\n    (-68.12, 69.71),\n    (-65.91, 69.19),\n    (-66.92, 68.39),\n    (-64.08, 67.68),\n    (-62.50, 66.68),\n    (-63.07, 65.33),\n    (-66.11, 66.08),\n    (-67.48, 65.41),\n    (-64.05, 63.15),\n    (-66.58, 63.26),\n    (-69.04, 62.33),\n    (-72.22, 63.77),\n    (-76.88, 64.17),\n    (-73.25, 65.54),\n    (-70.09, 66.64),\n    (-72.05, 67.44),\n    (-76.32, 68.36),\n    (-78.34, 70.17),\n    (-82.12, 69.71),\n    (-87.64, 70.12),\n    (-89.68, 71.43),\n    (-85.28, 73.74),\n    (-80.90, 76.10),\n    (-84.21, 76.28),\n    (-88.94, 76.38),\n    (-85.47, 77.40),\n    (-85.43, 77.93),\n    (-87.01, 78.54),\n    (-83.17, 78.94),\n    (-84.87, 79.93),\n    (-81.33, 79.82),\n    (-76.27, 80.92),\n    (-82.88, 80.62),\n    (-82.58, 81.16),\n    (-86.51, 81.05),\n    (-89.36, 81.21),\n    (-90.45, 81.38),\n    (-89.28, 81.86),\n    (-87.21, 82.30),\n    (-80.51, 82.05),\n    (-80.16, 82.55),\n    (-77.83, 82.86),\n    (-75.51, 83.05),\n    (-71.18, 82.90),\n    (-65.10, 82.78),\n    (-63.34, 81.80),\n    (-68.26, 81.26),\n    (-69.46, 80.34),\n    (-71.05, 79.82),\n    (-74.40, 79.46),\n    (-75.42, 79.03),\n    (-75.48, 78.92),\n    (-76.01, 78.20),\n    (-80.66, 77.28),\n    (-78.07, 76.98),\n    (-80.90, 76.13),\n    (-92.86, 74.13),\n    (-92.50, 72.70),\n    (-94.89, 73.16),\n    (-92.96, 74.14),\n    (-94.80, 76.95),\n    (-89.68, 76.04),\n    (-88.52, 75.40),\n    (-82.36, 75.67),\n    (-79.39, 74.65),\n    (-86.15, 74.22),\n    (-91.70, 74.94),\n    (-95.60, 76.91),\n    (-94.87, 76.96),\n    (-99.96, 73.74),\n    (-97.89, 72.90),\n    (-98.28, 71.13),\n    (-102.04, 72.92),\n    (-101.34, 73.14),\n    (-99.69, 73.59),\n    (-107.58, 73.25),\n    (-104.59, 71.02),\n    (-101.71, 69.56),\n    (-104.07, 68.62),\n    (-106.61, 69.12),\n    (-114.09, 69.05),\n    (-113.89, 70.12),\n    (-115.88, 70.32),\n    (-116.10, 71.32),\n    (-117.45, 72.48),\n    (-113.53, 72.44),\n    (-109.84, 72.24),\n    (-106.62, 71.71),\n    (-107.43, 73.04),\n    (-120.96, 74.29),\n    (-118.37, 72.53),\n    (-123.06, 71.18),\n    (-123.40, 73.77),\n    (-120.93, 74.27),\n    (-108.83, 76.74),\n    (-106.25, 75.54),\n    (-107.08, 74.78),\n    (-112.99, 74.16),\n    (-112.28, 74.99),\n    (-116.04, 75.33),\n    (-115.27, 76.20),\n    (-110.95, 75.56),\n    (-109.77, 76.31),\n    (-108.82, 76.70),\n    (-115.70, 77.46),\n    (-118.10, 76.30),\n    (-121.13, 76.37),\n    (-116.04, 77.28),\n    (-110.01, 77.86),\n    (-112.36, 77.68),\n    (-109.96, 77.86),\n    (-109.60, 78.48),\n    (-112.20, 78.01),\n    (-109.60, 78.48),\n    (-97.87, 76.61),\n    (-99.21, 75.31),\n    (-100.86, 75.60),\n    (-99.40, 76.26),\n    (-97.79, 76.60),\n    (-94.72, 75.53),\n    (-94.66, 75.52),\n    (-104.10, 79.01),\n    (-99.19, 77.54),\n    (-103.22, 78.08),\n    (-104.30, 78.95),\n    (-93.74, 77.52),\n    (-93.74, 77.52),\n    (-96.88, 78.50),\n    (-96.91, 77.77),\n    (-96.94, 78.48),\n    (-84.69, 65.84),\n    (-81.58, 63.87),\n    (-85.00, 62.96),\n    (-84.63, 65.71),\n    (-81.84, 62.75),\n    (-82.01, 62.63),\n    (-79.88, 62.12),\n    (-79.88, 62.12),\n    (-43.53, 59.89),\n    (-45.29, 60.67),\n    (-47.91, 60.83),\n    (-49.90, 62.41),\n    (-50.71, 64.42),\n    (-51.39, 64.94),\n    (-52.96, 66.09),\n    (-53.62, 67.19),\n    (-53.51, 67.51),\n    (-51.84, 68.65),\n    (-52.19, 70.00),\n    (-51.85, 71.03),\n    (-55.41, 71.41),\n    (-54.63, 72.97),\n    (-56.98, 74.70),\n    (-61.95, 76.09),\n    (-66.38, 75.83),\n    (-71.13, 77.00),\n    (-66.81, 77.60),\n    (-70.78, 77.78),\n    (-64.96, 79.70),\n    (-63.38, 81.16),\n    (-56.89, 82.17),\n    (-48.18, 82.15),\n    (-42.08, 82.74),\n    (-38.02, 83.54),\n    (-23.96, 82.94),\n    (-25.97, 81.97),\n    (-25.99, 80.64),\n    (-13.57, 80.97),\n    (-16.60, 80.16),\n    (-19.82, 78.82),\n    (-18.80, 77.54),\n    (-21.98, 76.46),\n    (-20.69, 75.12),\n    (-21.78, 74.40),\n    (-24.10, 73.69),\n    (-26.54, 73.08),\n    (-24.63, 72.69),\n    (-21.84, 71.69),\n    (-24.62, 71.24),\n    (-27.16, 70.89),\n    (-27.21, 70.00),\n    (-24.10, 69.35),\n    (-28.35, 68.43),\n    (-32.48, 68.56),\n    (-35.26, 66.26),\n    (-37.90, 65.90),\n    (-40.04, 65.00),\n    (-40.49, 64.04),\n    (-42.01, 63.14),\n    (-42.88, 61.15),\n    (-43.09, 60.07),\n    (-43.56, 59.90),\n    (-16.26, 66.41),\n    (-15.32, 64.29),\n    (-20.14, 63.47),\n    (-21.76, 64.21),\n    (-21.33, 64.97),\n    (-23.04, 65.62),\n    (-21.76, 66.26),\n    (-18.77, 66.12),\n    (-16.23, 66.35),\n    (0.56, 51.47),\n    (-1.71, 54.94),\n    (-3.41, 57.52),\n    (-5.42, 58.14),\n    (-5.77, 55.59),\n    (-3.48, 54.82),\n    (-4.68, 52.88),\n    (-2.68, 51.58),\n    (-3.80, 50.08),\n    (1.26, 51.14),\n    (0.65, 51.41),\n    (-7.17, 54.91),\n    (-9.97, 53.47),\n    (-8.52, 51.76),\n    (-5.69, 54.79),\n    (-7.34, 55.25),\n    (-1.33, 60.66),\n    (-1.17, 60.38),\n    (-6.18, 58.44),\n    (-6.09, 58.36),\n    (-6.47, 57.58),\n    (-6.33, 57.54),\n    (-7.30, 57.54),\n    (-7.46, 57.05),\n    (-6.54, 56.94),\n    (-6.00, 55.94),\n    (-5.09, 55.55),\n    (-4.44, 54.38),\n    (-4.30, 54.19),\n    (-8.08, 71.02),\n    (-8.21, 70.86),\n    (16.92, 79.52),\n    (22.26, 78.46),\n    (16.86, 76.41),\n    (16.00, 77.39),\n    (16.03, 77.92),\n    (16.81, 79.50),\n    (14.71, 79.40),\n    (16.05, 79.12),\n    (14.02, 77.80),\n    (13.56, 78.46),\n    (12.63, 79.26),\n    (14.68, 79.40),\n    (22.01, 78.24),\n    (21.86, 78.23),\n    (21.54, 77.75),\n    (23.88, 77.26),\n    (21.53, 77.67),\n    (22.79, 77.79),\n    (23.50, 79.97),\n    (28.24, 79.54),\n    (20.85, 78.94),\n    (19.00, 79.34),\n    (21.05, 79.88),\n    (23.41, 79.96),\n    (46.98, 80.23),\n    (43.13, 79.97),\n    (47.18, 80.22),\n    (50.43, 80.19),\n    (50.55, 79.88),\n    (47.77, 79.86),\n    (50.45, 80.14),\n    (61.79, 80.18),\n    (61.79, 80.18),\n    (65.08, 80.69),\n    (64.27, 80.59),\n    (65.13, 80.68),\n    (-5.13, 35.66),\n    (4.06, 36.63),\n    (10.40, 37.12),\n    (11.36, 33.61),\n    (20.10, 30.10),\n    (23.49, 32.17),\n    (31.65, 30.80),\n    (35.76, 23.74),\n    (39.75, 14.82),\n    (42.93, 11.34),\n    (51.52, 11.45),\n    (49.82, 6.99),\n    (43.13, -0.62),\n    (39.15, -7.58),\n    (40.37, -13.20),\n    (37.74, -18.17),\n    (35.33, -22.71),\n    (32.84, -28.15),\n    (26.50, -34.39),\n    (19.55, -35.51),\n    (17.50, -30.88),\n    (12.24, -18.75),\n    (13.89, -12.81),\n    (12.05, -5.55),\n    (9.67, 0.14),\n    (7.19, 3.79),\n    (1.74, 5.39),\n    (-4.77, 4.59),\n    (-12.00, 6.75),\n    (-15.54, 10.98),\n    (-16.33, 15.50),\n    (-16.10, 22.29),\n    (-12.90, 27.12),\n    (-9.52, 31.09),\n    (-5.41, 35.58),\n    (33.71, 0.00),\n    (33.48, -3.42),\n    (33.34, -0.20),\n    (33.71, 0.00),\n    (49.30, -12.50),\n    (49.28, -18.79),\n    (43.95, -25.50),\n    (44.37, -20.08),\n    (46.34, -16.31),\n    (47.91, -14.08),\n    (49.30, -12.50),\n    (178.88, 69.10),\n    (181.20, 68.42),\n    (183.52, 67.78),\n    (188.87, 66.38),\n    (186.54, 64.74),\n    (182.87, 65.63),\n    (180.13, 65.14),\n    (179.48, 64.88),\n    (178.20, 64.29),\n    (177.46, 62.62),\n    (170.42, 60.17),\n    (164.48, 59.89),\n    (162.92, 57.34),\n    (161.82, 54.88),\n    (156.42, 51.09),\n    (156.40, 57.76),\n    (163.79, 61.73),\n    (159.90, 60.73),\n    (156.81, 61.68),\n    (153.83, 59.10),\n    (148.57, 59.46),\n    (140.77, 58.39),\n    (137.10, 54.07),\n    (140.72, 52.43),\n    (138.77, 47.30),\n    (129.92, 42.04),\n    (128.33, 38.46),\n    (126.15, 35.18),\n    (125.12, 39.08),\n    (121.62, 40.15),\n    (117.58, 38.21),\n    (121.77, 36.90),\n    (120.73, 32.65),\n    (121.28, 30.25),\n    (118.83, 24.93),\n    (112.69, 21.81),\n    (108.53, 21.73),\n    (107.55, 16.34),\n    (107.32, 10.45),\n    (104.39, 10.37),\n    (100.01, 13.52),\n    (100.26, 8.30),\n    (103.22, 1.56),\n    (98.21, 9.17),\n    (97.66, 15.36),\n    (94.21, 17.79),\n    (90.05, 21.74),\n    (90.06, 21.03),\n    (82.06, 15.95),\n    (80.05, 11.72),\n    (76.41, 8.60),\n    (72.79, 17.43),\n    (72.02, 20.00),\n    (68.98, 21.99),\n    (64.62, 24.41),\n    (57.83, 24.77),\n    (53.11, 26.20),\n    (49.67, 29.41),\n    (50.96, 25.15),\n    (54.33, 23.44),\n    (59.03, 22.57),\n    (57.87, 18.86),\n    (52.95, 15.74),\n    (47.26, 12.96),\n    (42.75, 14.68),\n    (39.93, 19.61),\n    (36.92, 25.78),\n    (33.30, 28.46),\n    (32.60, 30.63),\n    (32.18, 30.58),\n    (36.08, 35.03),\n    (32.53, 36.17),\n    (27.77, 36.94),\n    (26.51, 39.18),\n    (31.54, 40.82),\n    (38.53, 40.48),\n    (40.35, 43.17),\n    (39.88, 46.45),\n    (35.18, 44.99),\n    (33.50, 44.96),\n    (30.24, 45.14),\n    (28.70, 41.48),\n    (26.55, 39.84),\n    (23.62, 39.67),\n    (23.80, 37.34),\n    (21.90, 36.92),\n    (18.79, 42.02),\n    (14.52, 44.31),\n    (14.58, 42.25),\n    (18.32, 39.57),\n    (16.05, 39.35),\n    (11.52, 42.36),\n    (6.87, 43.08),\n    (2.80, 41.09),\n    (-1.11, 37.14),\n    (-6.24, 36.70),\n    (-8.67, 39.57),\n    (-6.51, 43.13),\n    (-0.84, 45.55),\n    (-3.93, 48.40),\n    (0.48, 49.09),\n    (4.20, 51.29),\n    (6.44, 52.92),\n    (8.42, 55.94),\n    (11.72, 55.49),\n    (11.73, 53.66),\n    (16.78, 54.14),\n    (21.40, 56.32),\n    (24.67, 57.20),\n    (28.94, 59.18),\n    (24.16, 59.52),\n    (22.07, 62.66),\n    (23.76, 65.35),\n    (18.70, 62.54),\n    (19.11, 59.67),\n    (18.40, 58.54),\n    (15.34, 55.73),\n    (11.74, 58.08),\n    (8.37, 57.68),\n    (5.80, 59.20),\n    (7.38, 60.86),\n    (7.51, 61.86),\n    (9.62, 62.99),\n    (13.37, 65.46),\n    (15.46, 67.12),\n    (18.54, 68.62),\n    (22.32, 69.64),\n    (24.77, 70.17),\n    (25.93, 69.79),\n    (28.56, 70.46),\n    (29.75, 69.76),\n    (33.83, 69.11),\n    (41.90, 66.85),\n    (35.14, 66.25),\n    (33.30, 66.07),\n    (35.46, 64.15),\n    (37.68, 64.03),\n    (41.71, 64.09),\n    (44.80, 65.58),\n    (44.87, 68.16),\n    (45.92, 66.83),\n    (51.79, 67.85),\n    (53.70, 67.89),\n    (59.68, 68.09),\n    (65.07, 69.08),\n    (68.56, 69.19),\n    (68.38, 70.97),\n    (73.03, 71.62),\n    (73.80, 68.29),\n    (69.42, 66.45),\n    (73.43, 66.36),\n    (77.51, 68.36),\n    (80.74, 66.74),\n    (75.27, 68.67),\n    (75.11, 71.80),\n    (78.62, 70.56),\n    (78.43, 71.90),\n    (82.72, 71.23),\n    (84.25, 70.03),\n    (81.40, 72.76),\n    (86.50, 74.01),\n    (87.68, 74.78),\n    (90.25, 75.23),\n    (89.68, 75.57),\n    (95.12, 75.95),\n    (99.69, 76.09),\n    (104.10, 77.52),\n    (106.34, 76.40),\n    (112.99, 75.60),\n    (107.88, 73.72),\n    (110.43, 73.71),\n    (113.34, 73.37),\n    (123.10, 73.28),\n    (128.94, 73.02),\n    (126.10, 72.24),\n    (130.53, 70.86),\n    (135.49, 71.51),\n    (139.60, 72.23),\n    (146.04, 72.39),\n    (146.92, 72.21),\n    (150.77, 71.28),\n    (159.92, 70.14),\n    (167.68, 69.63),\n    (170.20, 69.99),\n    (178.88, 69.10),\n    (68.33, 76.71),\n    (66.03, 75.62),\n    (59.10, 74.11),\n    (54.92, 73.03),\n    (56.67, 74.10),\n    (58.56, 75.09),\n    (63.86, 75.87),\n    (68.19, 76.70),\n    (53.04, 72.57),\n    (58.29, 70.39),\n    (55.03, 70.78),\n    (53.44, 72.26),\n    (53.63, 72.61),\n    (52.22, 46.50),\n    (51.73, 44.73),\n    (52.56, 41.80),\n    (53.43, 40.40),\n    (54.22, 37.86),\n    (49.04, 38.45),\n    (48.17, 42.76),\n    (49.33, 45.64),\n    (52.22, 46.50),\n    (62.32, 46.32),\n    (60.32, 43.06),\n    (59.57, 45.58),\n    (61.94, 46.33),\n    (79.55, 46.12),\n    (74.30, 44.44),\n    (78.62, 45.79),\n    (79.66, 46.07),\n    (76.81, 41.96),\n    (76.73, 41.86),\n    (35.15, 35.15),\n    (34.61, 34.84),\n    (35.18, 35.17),\n    (23.84, 35.33),\n    (24.30, 34.91),\n    (24.09, 35.39),\n    (15.54, 37.89),\n    (13.47, 37.89),\n    (15.54, 37.89),\n    (9.56, 40.95),\n    (8.46, 39.99),\n    (9.12, 40.69),\n    (9.72, 42.60),\n    (9.54, 42.35),\n    (80.60, 8.95),\n    (79.73, 5.96),\n    (80.10, 8.30),\n    (11.04, 57.44),\n    (10.67, 57.25),\n    (-77.92, 24.67),\n    (-77.98, 24.22),\n    (-77.61, 23.62),\n    (-77.18, 23.64),\n    (-75.55, 24.13),\n    (-75.41, 24.31),\n    (-91.40, -0.17),\n    (-91.52, -0.26),\n    (-60.25, 46.68),\n    (-60.71, 46.33),\n    (-63.89, 49.47),\n    (-63.45, 49.43),\n    (142.53, -10.60),\n    (145.62, -16.34),\n    (149.79, -22.09),\n    (153.21, -26.82),\n    (150.52, -35.19),\n    (145.60, -38.53),\n    (140.13, -37.69),\n    (137.34, -34.77),\n    (135.76, -34.56),\n    (131.50, -31.34),\n    (121.72, -33.65),\n    (115.62, -33.25),\n    (114.09, -26.01),\n    (114.88, -21.27),\n    (122.34, -18.13),\n    (125.32, -14.53),\n    (128.39, -14.90),\n    (132.35, -11.42),\n    (136.16, -12.43),\n    (138.07, -16.45),\n    (142.25, -10.78),\n    (144.72, -40.68),\n    (148.32, -42.14),\n    (145.57, -42.77),\n    (146.47, -41.19),\n    (172.86, -34.23),\n    (176.10, -37.52),\n    (177.06, -39.49),\n    (174.77, -38.03),\n    (172.83, -34.27),\n    (172.36, -40.53),\n    (172.92, -43.81),\n    (168.41, -46.13),\n    (170.26, -43.21),\n    (173.69, -40.94),\n    (150.74, -10.18),\n    (143.04, -8.26),\n    (138.48, -6.97),\n    (131.95, -2.94),\n    (130.91, -1.35),\n    (134.38, -2.64),\n    (141.24, -2.62),\n    (148.19, -8.15),\n    (150.75, -10.27),\n    (117.24, 7.01),\n    (117.90, 0.76),\n    (113.89, -3.50),\n    (109.44, -0.82),\n    (113.13, 3.38),\n    (117.24, 7.01),\n    (95.31, 5.75),\n    (102.32, 1.40),\n    (106.03, -2.98),\n    (101.46, -2.81),\n    (95.20, 5.73),\n    (140.91, 41.53),\n    (140.79, 35.75),\n    (136.82, 34.56),\n    (133.56, 34.72),\n    (132.49, 35.41),\n    (136.73, 37.20),\n    (139.82, 40.00),\n    (140.68, 41.43),\n    (133.71, 34.30),\n    (131.41, 31.58),\n    (129.38, 33.10),\n    (133.90, 34.37),\n    (141.89, 45.50),\n    (144.12, 42.92),\n    (140.30, 41.64),\n    (141.53, 45.30),\n    (141.89, 45.53),\n    (142.57, 54.36),\n    (143.64, 49.19),\n    (141.99, 45.88),\n    (141.92, 50.85),\n    (142.60, 54.34),\n    (121.92, 25.48),\n    (120.53, 24.70),\n    (121.70, 25.51),\n    (110.81, 20.07),\n    (109.20, 19.66),\n    (110.81, 20.07),\n    (106.51, -6.16),\n    (114.15, -7.72),\n    (108.71, -7.89),\n    (106.51, -6.16),\n    (164.27, -20.01),\n    (164.16, -20.27),\n    (178.61, -17.04),\n    (178.61, -17.04),\n    (179.45, -16.43),\n    (179.35, -16.43),\n    (-172.55, -13.39),\n    (-172.61, -13.78),\n    (122.26, 18.67),\n    (123.05, 13.86),\n    (120.73, 13.80),\n    (120.43, 16.43),\n    (121.72, 18.40),\n    (125.34, 9.79),\n    #[allow(clippy::approx_constant)]\n    (125.56, 6.28),\n    (122.38, 7.00),\n    (125.10, 9.38),\n    (119.64, 11.35),\n    (118.81, 10.16),\n    (119.59, 10.86),\n    (119.64, 11.35),\n    (-179.87, 65.14),\n    (-177.13, 65.63),\n    (-173.46, 64.74),\n    (-171.13, 66.38),\n    (-176.48, 67.78),\n    (-178.80, 68.42),\n    (101.96, 79.08),\n    (101.31, 77.86),\n    (101.22, 79.04),\n    (94.29, 79.29),\n    (95.31, 78.68),\n    (100.02, 79.43),\n    (97.26, 79.62),\n    (95.44, 79.65),\n    (95.46, 80.62),\n    (92.39, 79.66),\n    (95.07, 80.54),\n    (138.54, 76.05),\n    (144.93, 75.45),\n    (140.30, 74.99),\n    (137.27, 75.44),\n    (138.29, 75.98),\n    (146.08, 75.29),\n    (147.75, 74.73),\n    (145.85, 75.06),\n    (141.44, 73.88),\n    (141.48, 73.84),\n    (0.01, -71.68),\n    (6.57, -70.57),\n    (15.04, -70.44),\n    (25.10, -70.75),\n    (33.37, -69.10),\n    (38.46, -69.77),\n    (42.85, -68.16),\n    (46.59, -67.23),\n    (49.35, -66.96),\n    (52.90, -65.97),\n    (58.46, -67.20),\n    (63.60, -67.58),\n    (70.63, -68.41),\n    (69.24, -70.36),\n    (76.20, -69.44),\n    (88.08, -66.64),\n    (94.98, -66.52),\n    (101.53, -66.09),\n    (111.31, -65.91),\n    (118.64, -66.87),\n    (126.24, -66.24),\n    (133.09, -66.18),\n    (139.85, -66.72),\n    (146.86, -67.96),\n    (153.65, -68.82),\n    (159.94, -69.57),\n    (164.10, -70.67),\n    (170.19, -71.94),\n    (165.68, -74.64),\n    (163.82, -77.60),\n    (162.10, -78.95),\n    (166.72, -82.84),\n    (175.58, -83.86),\n    (-178.56, -84.37),\n    (-147.96, -85.40),\n    (-152.96, -81.12),\n    (-153.95, -79.50),\n    (-151.24, -77.48),\n    (-146.74, -76.44),\n    (-137.68, -75.16),\n    (-131.63, -74.63),\n    (-123.05, -74.41),\n    (-114.76, -73.97),\n    (-111.91, -75.41),\n    (-105.05, -74.77),\n    (-100.90, -74.21),\n    (-101.04, -73.18),\n    (-100.28, -73.06),\n    (-93.06, -73.33),\n    (-85.40, -73.18),\n    (-79.82, -73.04),\n    (-78.21, -72.52),\n    (-71.90, -73.41),\n    (-67.51, -71.10),\n    (-67.57, -68.92),\n    (-66.65, -66.83),\n    (-64.30, -65.28),\n    (-59.14, -63.74),\n    (-59.58, -64.37),\n    (-62.50, -65.94),\n    (-62.48, -66.66),\n    (-65.64, -68.02),\n    (-63.85, -69.07),\n    (-61.69, -70.87),\n    (-60.89, -72.71),\n    (-61.07, -74.30),\n    (-63.33, -75.88),\n    (-76.05, -77.06),\n    (-83.04, -77.12),\n    (-74.30, -80.83),\n    (-56.40, -82.14),\n    (-42.46, -81.65),\n    (-31.60, -80.17),\n    (-34.01, -79.20),\n    (-32.48, -77.28),\n    (-26.28, -76.18),\n    (-17.18, -73.45),\n    (-11.20, -72.01),\n    (-8.67, -71.98),\n    (-5.45, -71.45),\n    (-0.82, -71.74),\n    (0.07, -71.68),\n    (164.65, -77.89),\n    (170.95, -77.37),\n    (179.67, -78.25),\n    (-178.74, -78.24),\n    (-165.76, -78.47),\n    (-158.42, -77.73),\n    (-58.98, -64.63),\n    (-60.99, -68.62),\n    (-61.02, -71.70),\n    (-62.01, -74.94),\n    (-52.00, -77.07),\n    (-42.23, -77.80),\n    (-36.22, -78.03),\n    (-35.03, -77.81),\n    (-26.13, -75.54),\n    (-19.35, -73.04),\n    (-12.16, -71.86),\n    (-6.15, -70.65),\n    (-0.57, -69.14),\n    (4.93, -70.25),\n    (10.91, -69.99),\n    (16.52, -69.87),\n    (25.41, -70.22),\n    (32.13, -69.29),\n    (33.62, -69.58),\n    (70.56, -68.53),\n    (73.91, -69.51),\n    (81.42, -67.87),\n    (84.67, -66.41),\n    (89.07, -66.73),\n    (-135.79, -74.67),\n    (-124.34, -73.22),\n    (-116.65, -74.08),\n    (-109.93, -74.64),\n    (-105.36, -74.56),\n    (-105.83, -74.77),\n    (-69.30, -70.06),\n    (-71.33, -72.68),\n    (-71.42, -71.85),\n    (-75.10, -71.46),\n    (-71.79, -70.55),\n    (-70.34, -69.26),\n    (-69.34, -70.13),\n    (-49.20, -77.83),\n    (-44.59, -78.79),\n    (-44.14, -80.13),\n    (-59.04, -79.95),\n    (-49.28, -77.84),\n    (-48.24, -77.81),\n    (-58.13, -80.12),\n    (-63.25, -80.20),\n    (-58.32, -80.12),\n    (-163.64, -78.74),\n    (-161.20, -79.93),\n    (-163.62, -78.74),\n    (66.82, 66.82),\n    (66.82, 66.82),\n];\n"
  },
  {
    "path": "src/widgets/chart.rs",
    "content": "use std::{borrow::Cow, cmp::max};\n\nuse unicode_width::UnicodeWidthStr;\n\nuse crate::layout::Alignment;\nuse crate::{\n    buffer::Buffer,\n    layout::{Constraint, Rect},\n    style::{Color, Style},\n    symbols,\n    text::{Span, Spans},\n    widgets::{\n        canvas::{Canvas, Line, Points},\n        Block, Borders, Widget,\n    },\n};\n\n/// An X or Y axis for the chart widget\n#[derive(Debug, Clone)]\npub struct Axis<'a> {\n    /// Title displayed next to axis end\n    title: Option<Spans<'a>>,\n    /// Bounds for the axis (all data points outside these limits will not be represented)\n    bounds: [f64; 2],\n    /// A list of labels to put to the left or below the axis\n    labels: Option<Vec<Span<'a>>>,\n    /// The style used to draw the axis itself\n    style: Style,\n    /// The alignment of the labels of the Axis\n    labels_alignment: Alignment,\n}\n\nimpl<'a> Default for Axis<'a> {\n    fn default() -> Axis<'a> {\n        Axis {\n            title: None,\n            bounds: [0.0, 0.0],\n            labels: None,\n            style: Default::default(),\n            labels_alignment: Alignment::Left,\n        }\n    }\n}\n\nimpl<'a> Axis<'a> {\n    pub fn title<T>(mut self, title: T) -> Axis<'a>\n    where\n        T: Into<Spans<'a>>,\n    {\n        self.title = Some(title.into());\n        self\n    }\n\n    #[deprecated(\n        since = \"0.10.0\",\n        note = \"You should use styling capabilities of `text::Spans` given as argument of the `title` method to apply styling to the title.\"\n    )]\n    pub fn title_style(mut self, style: Style) -> Axis<'a> {\n        if let Some(t) = self.title {\n            let title = String::from(t);\n            self.title = Some(Spans::from(Span::styled(title, style)));\n        }\n        self\n    }\n\n    pub fn bounds(mut self, bounds: [f64; 2]) -> Axis<'a> {\n        self.bounds = bounds;\n        self\n    }\n\n    pub fn labels(mut self, labels: Vec<Span<'a>>) -> Axis<'a> {\n        self.labels = Some(labels);\n        self\n    }\n\n    pub fn style(mut self, style: Style) -> Axis<'a> {\n        self.style = style;\n        self\n    }\n\n    /// Defines the alignment of the labels of the axis.\n    /// The alignment behaves differently based on the axis:\n    /// - Y-Axis: The labels are aligned within the area on the left of the axis\n    /// - X-Axis: The first X-axis label is aligned relative to the Y-axis\n    pub fn labels_alignment(mut self, alignment: Alignment) -> Axis<'a> {\n        self.labels_alignment = alignment;\n        self\n    }\n}\n\n/// Used to determine which style of graphing to use\n#[derive(Debug, Clone, Copy)]\npub enum GraphType {\n    /// Draw each point\n    Scatter,\n    /// Draw each point and lines between each point using the same marker\n    Line,\n}\n\n/// A group of data points\n#[derive(Debug, Clone)]\npub struct Dataset<'a> {\n    /// Name of the dataset (used in the legend if shown)\n    name: Cow<'a, str>,\n    /// A reference to the actual data\n    data: &'a [(f64, f64)],\n    /// Symbol used for each points of this dataset\n    marker: symbols::Marker,\n    /// Determines graph type used for drawing points\n    graph_type: GraphType,\n    /// Style used to plot this dataset\n    style: Style,\n}\n\nimpl<'a> Default for Dataset<'a> {\n    fn default() -> Dataset<'a> {\n        Dataset {\n            name: Cow::from(\"\"),\n            data: &[],\n            marker: symbols::Marker::Dot,\n            graph_type: GraphType::Scatter,\n            style: Style::default(),\n        }\n    }\n}\n\nimpl<'a> Dataset<'a> {\n    pub fn name<S>(mut self, name: S) -> Dataset<'a>\n    where\n        S: Into<Cow<'a, str>>,\n    {\n        self.name = name.into();\n        self\n    }\n\n    pub fn data(mut self, data: &'a [(f64, f64)]) -> Dataset<'a> {\n        self.data = data;\n        self\n    }\n\n    pub fn marker(mut self, marker: symbols::Marker) -> Dataset<'a> {\n        self.marker = marker;\n        self\n    }\n\n    pub fn graph_type(mut self, graph_type: GraphType) -> Dataset<'a> {\n        self.graph_type = graph_type;\n        self\n    }\n\n    pub fn style(mut self, style: Style) -> Dataset<'a> {\n        self.style = style;\n        self\n    }\n}\n\n/// A container that holds all the infos about where to display each elements of the chart (axis,\n/// labels, legend, ...).\n#[derive(Debug, Clone, PartialEq, Default)]\nstruct ChartLayout {\n    /// Location of the title of the x axis\n    title_x: Option<(u16, u16)>,\n    /// Location of the title of the y axis\n    title_y: Option<(u16, u16)>,\n    /// Location of the first label of the x axis\n    label_x: Option<u16>,\n    /// Location of the first label of the y axis\n    label_y: Option<u16>,\n    /// Y coordinate of the horizontal axis\n    axis_x: Option<u16>,\n    /// X coordinate of the vertical axis\n    axis_y: Option<u16>,\n    /// Area of the legend\n    legend_area: Option<Rect>,\n    /// Area of the graph\n    graph_area: Rect,\n}\n\n/// A widget to plot one or more dataset in a cartesian coordinate system\n///\n/// # Examples\n///\n/// ```\n/// # use tui::symbols;\n/// # use tui::widgets::{Block, Borders, Chart, Axis, Dataset, GraphType};\n/// # use tui::style::{Style, Color};\n/// # use tui::text::Span;\n/// let datasets = vec![\n///     Dataset::default()\n///         .name(\"data1\")\n///         .marker(symbols::Marker::Dot)\n///         .graph_type(GraphType::Scatter)\n///         .style(Style::default().fg(Color::Cyan))\n///         .data(&[(0.0, 5.0), (1.0, 6.0), (1.5, 6.434)]),\n///     Dataset::default()\n///         .name(\"data2\")\n///         .marker(symbols::Marker::Braille)\n///         .graph_type(GraphType::Line)\n///         .style(Style::default().fg(Color::Magenta))\n///         .data(&[(4.0, 5.0), (5.0, 8.0), (7.66, 13.5)]),\n/// ];\n/// Chart::new(datasets)\n///     .block(Block::default().title(\"Chart\"))\n///     .x_axis(Axis::default()\n///         .title(Span::styled(\"X Axis\", Style::default().fg(Color::Red)))\n///         .style(Style::default().fg(Color::White))\n///         .bounds([0.0, 10.0])\n///         .labels([\"0.0\", \"5.0\", \"10.0\"].iter().cloned().map(Span::from).collect()))\n///     .y_axis(Axis::default()\n///         .title(Span::styled(\"Y Axis\", Style::default().fg(Color::Red)))\n///         .style(Style::default().fg(Color::White))\n///         .bounds([0.0, 10.0])\n///         .labels([\"0.0\", \"5.0\", \"10.0\"].iter().cloned().map(Span::from).collect()));\n/// ```\n#[derive(Debug, Clone)]\npub struct Chart<'a> {\n    /// A block to display around the widget eventually\n    block: Option<Block<'a>>,\n    /// The horizontal axis\n    x_axis: Axis<'a>,\n    /// The vertical axis\n    y_axis: Axis<'a>,\n    /// A reference to the datasets\n    datasets: Vec<Dataset<'a>>,\n    /// The widget base style\n    style: Style,\n    /// Constraints used to determine whether the legend should be shown or not\n    hidden_legend_constraints: (Constraint, Constraint),\n}\n\nimpl<'a> Chart<'a> {\n    pub fn new(datasets: Vec<Dataset<'a>>) -> Chart<'a> {\n        Chart {\n            block: None,\n            x_axis: Axis::default(),\n            y_axis: Axis::default(),\n            style: Default::default(),\n            datasets,\n            hidden_legend_constraints: (Constraint::Ratio(1, 4), Constraint::Ratio(1, 4)),\n        }\n    }\n\n    pub fn block(mut self, block: Block<'a>) -> Chart<'a> {\n        self.block = Some(block);\n        self\n    }\n\n    pub fn style(mut self, style: Style) -> Chart<'a> {\n        self.style = style;\n        self\n    }\n\n    pub fn x_axis(mut self, axis: Axis<'a>) -> Chart<'a> {\n        self.x_axis = axis;\n        self\n    }\n\n    pub fn y_axis(mut self, axis: Axis<'a>) -> Chart<'a> {\n        self.y_axis = axis;\n        self\n    }\n\n    /// Set the constraints used to determine whether the legend should be shown or not.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tui::widgets::Chart;\n    /// # use tui::layout::Constraint;\n    /// let constraints = (\n    ///     Constraint::Ratio(1, 3),\n    ///     Constraint::Ratio(1, 4)\n    /// );\n    /// // Hide the legend when either its width is greater than 33% of the total widget width\n    /// // or if its height is greater than 25% of the total widget height.\n    /// let _chart: Chart = Chart::new(vec![])\n    ///     .hidden_legend_constraints(constraints);\n    /// ```\n    pub fn hidden_legend_constraints(mut self, constraints: (Constraint, Constraint)) -> Chart<'a> {\n        self.hidden_legend_constraints = constraints;\n        self\n    }\n\n    /// Compute the internal layout of the chart given the area. If the area is too small some\n    /// elements may be automatically hidden\n    fn layout(&self, area: Rect) -> ChartLayout {\n        let mut layout = ChartLayout::default();\n        if area.height == 0 || area.width == 0 {\n            return layout;\n        }\n        let mut x = area.left();\n        let mut y = area.bottom() - 1;\n\n        if self.x_axis.labels.is_some() && y > area.top() {\n            layout.label_x = Some(y);\n            y -= 1;\n        }\n\n        layout.label_y = self.y_axis.labels.as_ref().and(Some(x));\n        x += self.max_width_of_labels_left_of_y_axis(area, self.y_axis.labels.is_some());\n\n        if self.x_axis.labels.is_some() && y > area.top() {\n            layout.axis_x = Some(y);\n            y -= 1;\n        }\n\n        if self.y_axis.labels.is_some() && x + 1 < area.right() {\n            layout.axis_y = Some(x);\n            x += 1;\n        }\n\n        if x < area.right() && y > 1 {\n            layout.graph_area = Rect::new(x, area.top(), area.right() - x, y - area.top() + 1);\n        }\n\n        if let Some(ref title) = self.x_axis.title {\n            let w = title.width() as u16;\n            if w < layout.graph_area.width && layout.graph_area.height > 2 {\n                layout.title_x = Some((x + layout.graph_area.width - w, y));\n            }\n        }\n\n        if let Some(ref title) = self.y_axis.title {\n            let w = title.width() as u16;\n            if w + 1 < layout.graph_area.width && layout.graph_area.height > 2 {\n                layout.title_y = Some((x, area.top()));\n            }\n        }\n\n        if let Some(inner_width) = self.datasets.iter().map(|d| d.name.width() as u16).max() {\n            let legend_width = inner_width + 2;\n            let legend_height = self.datasets.len() as u16 + 2;\n            let max_legend_width = self\n                .hidden_legend_constraints\n                .0\n                .apply(layout.graph_area.width);\n            let max_legend_height = self\n                .hidden_legend_constraints\n                .1\n                .apply(layout.graph_area.height);\n            if inner_width > 0\n                && legend_width < max_legend_width\n                && legend_height < max_legend_height\n            {\n                layout.legend_area = Some(Rect::new(\n                    layout.graph_area.right() - legend_width,\n                    layout.graph_area.top(),\n                    legend_width,\n                    legend_height,\n                ));\n            }\n        }\n        layout\n    }\n\n    fn max_width_of_labels_left_of_y_axis(&self, area: Rect, has_y_axis: bool) -> u16 {\n        let mut max_width = self\n            .y_axis\n            .labels\n            .as_ref()\n            .map(|l| l.iter().map(Span::width).max().unwrap_or_default() as u16)\n            .unwrap_or_default();\n\n        if let Some(first_x_label) = self.x_axis.labels.as_ref().and_then(|labels| labels.get(0)) {\n            let first_label_width = first_x_label.content.width() as u16;\n            let width_left_of_y_axis = match self.x_axis.labels_alignment {\n                Alignment::Left => {\n                    // The last character of the label should be below the Y-Axis when it exists, not on its left\n                    let y_axis_offset = if has_y_axis { 1 } else { 0 };\n                    first_label_width.saturating_sub(y_axis_offset)\n                }\n                Alignment::Center => first_label_width / 2,\n                Alignment::Right => 0,\n            };\n            max_width = max(max_width, width_left_of_y_axis);\n        }\n        // labels of y axis and first label of x axis can take at most 1/3rd of the total width\n        max_width.min(area.width / 3)\n    }\n\n    fn render_x_labels(\n        &mut self,\n        buf: &mut Buffer,\n        layout: &ChartLayout,\n        chart_area: Rect,\n        graph_area: Rect,\n    ) {\n        let y = match layout.label_x {\n            Some(y) => y,\n            None => return,\n        };\n        let labels = self.x_axis.labels.as_ref().unwrap();\n        let labels_len = labels.len() as u16;\n        if labels_len < 2 {\n            return;\n        }\n\n        let width_between_ticks = graph_area.width / labels_len;\n\n        let label_area = self.first_x_label_area(\n            y,\n            labels.first().unwrap().width() as u16,\n            width_between_ticks,\n            chart_area,\n            graph_area,\n        );\n\n        let label_alignment = match self.x_axis.labels_alignment {\n            Alignment::Left => Alignment::Right,\n            Alignment::Center => Alignment::Center,\n            Alignment::Right => Alignment::Left,\n        };\n\n        Self::render_label(buf, labels.first().unwrap(), label_area, label_alignment);\n\n        for (i, label) in labels[1..labels.len() - 1].iter().enumerate() {\n            // We add 1 to x (and width-1 below) to leave at least one space before each intermediate labels\n            let x = graph_area.left() + (i + 1) as u16 * width_between_ticks + 1;\n            let label_area = Rect::new(x, y, width_between_ticks.saturating_sub(1), 1);\n\n            Self::render_label(buf, label, label_area, Alignment::Center);\n        }\n\n        let x = graph_area.right() - width_between_ticks;\n        let label_area = Rect::new(x, y, width_between_ticks, 1);\n        // The last label should be aligned Right to be at the edge of the graph area\n        Self::render_label(buf, labels.last().unwrap(), label_area, Alignment::Right);\n    }\n\n    fn first_x_label_area(\n        &self,\n        y: u16,\n        label_width: u16,\n        max_width_after_y_axis: u16,\n        chart_area: Rect,\n        graph_area: Rect,\n    ) -> Rect {\n        let (min_x, max_x) = match self.x_axis.labels_alignment {\n            Alignment::Left => (chart_area.left(), graph_area.left()),\n            Alignment::Center => (\n                chart_area.left(),\n                graph_area.left() + max_width_after_y_axis.min(label_width),\n            ),\n            Alignment::Right => (\n                graph_area.left().saturating_sub(1),\n                graph_area.left() + max_width_after_y_axis,\n            ),\n        };\n\n        Rect::new(min_x, y, max_x - min_x, 1)\n    }\n\n    fn render_label(buf: &mut Buffer, label: &Span, label_area: Rect, alignment: Alignment) {\n        let label_width = label.width() as u16;\n        let bounded_label_width = label_area.width.min(label_width);\n\n        let x = match alignment {\n            Alignment::Left => label_area.left(),\n            Alignment::Center => label_area.left() + label_area.width / 2 - bounded_label_width / 2,\n            Alignment::Right => label_area.right() - bounded_label_width,\n        };\n\n        buf.set_span(x, label_area.top(), label, bounded_label_width);\n    }\n\n    fn render_y_labels(\n        &mut self,\n        buf: &mut Buffer,\n        layout: &ChartLayout,\n        chart_area: Rect,\n        graph_area: Rect,\n    ) {\n        let x = match layout.label_y {\n            Some(x) => x,\n            None => return,\n        };\n        let labels = self.y_axis.labels.as_ref().unwrap();\n        let labels_len = labels.len() as u16;\n        for (i, label) in labels.iter().enumerate() {\n            let dy = i as u16 * (graph_area.height - 1) / (labels_len - 1);\n            if dy < graph_area.bottom() {\n                let label_area = Rect::new(\n                    x,\n                    graph_area.bottom().saturating_sub(1) - dy,\n                    (graph_area.left() - chart_area.left()).saturating_sub(1),\n                    1,\n                );\n                Self::render_label(buf, label, label_area, self.y_axis.labels_alignment);\n            }\n        }\n    }\n}\n\nimpl<'a> Widget for Chart<'a> {\n    fn render(mut self, area: Rect, buf: &mut Buffer) {\n        if area.area() == 0 {\n            return;\n        }\n        buf.set_style(area, self.style);\n        // Sample the style of the entire widget. This sample will be used to reset the style of\n        // the cells that are part of the components put on top of the grah area (i.e legend and\n        // axis names).\n        let original_style = buf.get(area.left(), area.top()).style();\n\n        let chart_area = match self.block.take() {\n            Some(b) => {\n                let inner_area = b.inner(area);\n                b.render(area, buf);\n                inner_area\n            }\n            None => area,\n        };\n\n        let layout = self.layout(chart_area);\n        let graph_area = layout.graph_area;\n        if graph_area.width < 1 || graph_area.height < 1 {\n            return;\n        }\n\n        self.render_x_labels(buf, &layout, chart_area, graph_area);\n        self.render_y_labels(buf, &layout, chart_area, graph_area);\n\n        if let Some(y) = layout.axis_x {\n            for x in graph_area.left()..graph_area.right() {\n                buf.get_mut(x, y)\n                    .set_symbol(symbols::line::HORIZONTAL)\n                    .set_style(self.x_axis.style);\n            }\n        }\n\n        if let Some(x) = layout.axis_y {\n            for y in graph_area.top()..graph_area.bottom() {\n                buf.get_mut(x, y)\n                    .set_symbol(symbols::line::VERTICAL)\n                    .set_style(self.y_axis.style);\n            }\n        }\n\n        if let Some(y) = layout.axis_x {\n            if let Some(x) = layout.axis_y {\n                buf.get_mut(x, y)\n                    .set_symbol(symbols::line::BOTTOM_LEFT)\n                    .set_style(self.x_axis.style);\n            }\n        }\n\n        for dataset in &self.datasets {\n            Canvas::default()\n                .background_color(self.style.bg.unwrap_or(Color::Reset))\n                .x_bounds(self.x_axis.bounds)\n                .y_bounds(self.y_axis.bounds)\n                .marker(dataset.marker)\n                .paint(|ctx| {\n                    ctx.draw(&Points {\n                        coords: dataset.data,\n                        color: dataset.style.fg.unwrap_or(Color::Reset),\n                    });\n                    if let GraphType::Line = dataset.graph_type {\n                        for data in dataset.data.windows(2) {\n                            ctx.draw(&Line {\n                                x1: data[0].0,\n                                y1: data[0].1,\n                                x2: data[1].0,\n                                y2: data[1].1,\n                                color: dataset.style.fg.unwrap_or(Color::Reset),\n                            })\n                        }\n                    }\n                })\n                .render(graph_area, buf);\n        }\n\n        if let Some(legend_area) = layout.legend_area {\n            buf.set_style(legend_area, original_style);\n            Block::default()\n                .borders(Borders::ALL)\n                .render(legend_area, buf);\n            for (i, dataset) in self.datasets.iter().enumerate() {\n                buf.set_string(\n                    legend_area.x + 1,\n                    legend_area.y + 1 + i as u16,\n                    &dataset.name,\n                    dataset.style,\n                );\n            }\n        }\n\n        if let Some((x, y)) = layout.title_x {\n            let title = self.x_axis.title.unwrap();\n            let width = graph_area.right().saturating_sub(x);\n            buf.set_style(\n                Rect {\n                    x,\n                    y,\n                    width,\n                    height: 1,\n                },\n                original_style,\n            );\n            buf.set_spans(x, y, &title, width);\n        }\n\n        if let Some((x, y)) = layout.title_y {\n            let title = self.y_axis.title.unwrap();\n            let width = graph_area.right().saturating_sub(x);\n            buf.set_style(\n                Rect {\n                    x,\n                    y,\n                    width,\n                    height: 1,\n                },\n                original_style,\n            );\n            buf.set_spans(x, y, &title, width);\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    struct LegendTestCase {\n        chart_area: Rect,\n        hidden_legend_constraints: (Constraint, Constraint),\n        legend_area: Option<Rect>,\n    }\n\n    #[test]\n    fn it_should_hide_the_legend() {\n        let data = [(0.0, 5.0), (1.0, 6.0), (3.0, 7.0)];\n        let cases = [\n            LegendTestCase {\n                chart_area: Rect::new(0, 0, 100, 100),\n                hidden_legend_constraints: (Constraint::Ratio(1, 4), Constraint::Ratio(1, 4)),\n                legend_area: Some(Rect::new(88, 0, 12, 12)),\n            },\n            LegendTestCase {\n                chart_area: Rect::new(0, 0, 100, 100),\n                hidden_legend_constraints: (Constraint::Ratio(1, 10), Constraint::Ratio(1, 4)),\n                legend_area: None,\n            },\n        ];\n        for case in &cases {\n            let datasets = (0..10)\n                .map(|i| {\n                    let name = format!(\"Dataset #{}\", i);\n                    Dataset::default().name(name).data(&data)\n                })\n                .collect::<Vec<_>>();\n            let chart = Chart::new(datasets)\n                .x_axis(Axis::default().title(\"X axis\"))\n                .y_axis(Axis::default().title(\"Y axis\"))\n                .hidden_legend_constraints(case.hidden_legend_constraints);\n            let layout = chart.layout(case.chart_area);\n            assert_eq!(layout.legend_area, case.legend_area);\n        }\n    }\n}\n"
  },
  {
    "path": "src/widgets/clear.rs",
    "content": "use crate::{buffer::Buffer, layout::Rect, widgets::Widget};\n\n/// A widget to clear/reset a certain area to allow overdrawing (e.g. for popups).\n///\n/// This widget **cannot be used to clear the terminal on the first render** as `tui` assumes the\n/// render area is empty. Use [`crate::Terminal::clear`] instead.\n///\n/// # Examples\n///\n/// ```\n/// # use tui::widgets::{Clear, Block, Borders};\n/// # use tui::layout::Rect;\n/// # use tui::Frame;\n/// # use tui::backend::Backend;\n/// fn draw_on_clear<B: Backend>(f: &mut Frame<B>, area: Rect) {\n///     let block = Block::default().title(\"Block\").borders(Borders::ALL);\n///     f.render_widget(Clear, area); // <- this will clear/reset the area first\n///     f.render_widget(block, area); // now render the block widget\n/// }\n/// ```\n///\n/// # Popup Example\n///\n/// For a more complete example how to utilize `Clear` to realize popups see\n/// the example `examples/popup.rs`\n#[derive(Debug, Clone)]\npub struct Clear;\n\nimpl Widget for Clear {\n    fn render(self, area: Rect, buf: &mut Buffer) {\n        for x in area.left()..area.right() {\n            for y in area.top()..area.bottom() {\n                buf.get_mut(x, y).reset();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/widgets/gauge.rs",
    "content": "use crate::{\n    buffer::Buffer,\n    layout::Rect,\n    style::{Color, Style},\n    symbols,\n    text::{Span, Spans},\n    widgets::{Block, Widget},\n};\n\n/// A widget to display a task progress.\n///\n/// # Examples:\n///\n/// ```\n/// # use tui::widgets::{Widget, Gauge, Block, Borders};\n/// # use tui::style::{Style, Color, Modifier};\n/// Gauge::default()\n///     .block(Block::default().borders(Borders::ALL).title(\"Progress\"))\n///     .gauge_style(Style::default().fg(Color::White).bg(Color::Black).add_modifier(Modifier::ITALIC))\n///     .percent(20);\n/// ```\n#[derive(Debug, Clone)]\npub struct Gauge<'a> {\n    block: Option<Block<'a>>,\n    ratio: f64,\n    label: Option<Span<'a>>,\n    use_unicode: bool,\n    style: Style,\n    gauge_style: Style,\n}\n\nimpl<'a> Default for Gauge<'a> {\n    fn default() -> Gauge<'a> {\n        Gauge {\n            block: None,\n            ratio: 0.0,\n            label: None,\n            use_unicode: false,\n            style: Style::default(),\n            gauge_style: Style::default(),\n        }\n    }\n}\n\nimpl<'a> Gauge<'a> {\n    pub fn block(mut self, block: Block<'a>) -> Gauge<'a> {\n        self.block = Some(block);\n        self\n    }\n\n    pub fn percent(mut self, percent: u16) -> Gauge<'a> {\n        assert!(\n            percent <= 100,\n            \"Percentage should be between 0 and 100 inclusively.\"\n        );\n        self.ratio = f64::from(percent) / 100.0;\n        self\n    }\n\n    /// Sets ratio ([0.0, 1.0]) directly.\n    pub fn ratio(mut self, ratio: f64) -> Gauge<'a> {\n        assert!(\n            (0.0..=1.0).contains(&ratio),\n            \"Ratio should be between 0 and 1 inclusively.\"\n        );\n        self.ratio = ratio;\n        self\n    }\n\n    pub fn label<T>(mut self, label: T) -> Gauge<'a>\n    where\n        T: Into<Span<'a>>,\n    {\n        self.label = Some(label.into());\n        self\n    }\n\n    pub fn style(mut self, style: Style) -> Gauge<'a> {\n        self.style = style;\n        self\n    }\n\n    pub fn gauge_style(mut self, style: Style) -> Gauge<'a> {\n        self.gauge_style = style;\n        self\n    }\n\n    pub fn use_unicode(mut self, unicode: bool) -> Gauge<'a> {\n        self.use_unicode = unicode;\n        self\n    }\n}\n\nimpl<'a> Widget for Gauge<'a> {\n    fn render(mut self, area: Rect, buf: &mut Buffer) {\n        buf.set_style(area, self.style);\n        let gauge_area = match self.block.take() {\n            Some(b) => {\n                let inner_area = b.inner(area);\n                b.render(area, buf);\n                inner_area\n            }\n            None => area,\n        };\n        buf.set_style(gauge_area, self.gauge_style);\n        if gauge_area.height < 1 {\n            return;\n        }\n\n        // compute label value and its position\n        // label is put at the center of the gauge_area\n        let label = {\n            let pct = f64::round(self.ratio * 100.0);\n            self.label\n                .unwrap_or_else(|| Span::from(format!(\"{}%\", pct)))\n        };\n        let clamped_label_width = gauge_area.width.min(label.width() as u16);\n        let label_col = gauge_area.left() + (gauge_area.width - clamped_label_width) / 2;\n        let label_row = gauge_area.top() + gauge_area.height / 2;\n\n        // the gauge will be filled proportionally to the ratio\n        let filled_width = f64::from(gauge_area.width) * self.ratio;\n        let end = if self.use_unicode {\n            gauge_area.left() + filled_width.floor() as u16\n        } else {\n            gauge_area.left() + filled_width.round() as u16\n        };\n        for y in gauge_area.top()..gauge_area.bottom() {\n            // render the filled area (left to end)\n            for x in gauge_area.left()..end {\n                // spaces are needed to apply the background styling\n                buf.get_mut(x, y)\n                    .set_symbol(\" \")\n                    .set_fg(self.gauge_style.bg.unwrap_or(Color::Reset))\n                    .set_bg(self.gauge_style.fg.unwrap_or(Color::Reset));\n            }\n            if self.use_unicode && self.ratio < 1.0 {\n                buf.get_mut(end, y)\n                    .set_symbol(get_unicode_block(filled_width % 1.0));\n            }\n        }\n        // set the span\n        buf.set_span(label_col, label_row, &label, clamped_label_width);\n    }\n}\n\nfn get_unicode_block<'a>(frac: f64) -> &'a str {\n    match (frac * 8.0).round() as u16 {\n        1 => symbols::block::ONE_EIGHTH,\n        2 => symbols::block::ONE_QUARTER,\n        3 => symbols::block::THREE_EIGHTHS,\n        4 => symbols::block::HALF,\n        5 => symbols::block::FIVE_EIGHTHS,\n        6 => symbols::block::THREE_QUARTERS,\n        7 => symbols::block::SEVEN_EIGHTHS,\n        8 => symbols::block::FULL,\n        _ => \" \",\n    }\n}\n\n/// A compact widget to display a task progress over a single line.\n///\n/// # Examples:\n///\n/// ```\n/// # use tui::widgets::{Widget, LineGauge, Block, Borders};\n/// # use tui::style::{Style, Color, Modifier};\n/// # use tui::symbols;\n/// LineGauge::default()\n///     .block(Block::default().borders(Borders::ALL).title(\"Progress\"))\n///     .gauge_style(Style::default().fg(Color::White).bg(Color::Black).add_modifier(Modifier::BOLD))\n///     .line_set(symbols::line::THICK)\n///     .ratio(0.4);\n/// ```\npub struct LineGauge<'a> {\n    block: Option<Block<'a>>,\n    ratio: f64,\n    label: Option<Spans<'a>>,\n    line_set: symbols::line::Set,\n    style: Style,\n    gauge_style: Style,\n}\n\nimpl<'a> Default for LineGauge<'a> {\n    fn default() -> Self {\n        Self {\n            block: None,\n            ratio: 0.0,\n            label: None,\n            style: Style::default(),\n            line_set: symbols::line::NORMAL,\n            gauge_style: Style::default(),\n        }\n    }\n}\n\nimpl<'a> LineGauge<'a> {\n    pub fn block(mut self, block: Block<'a>) -> Self {\n        self.block = Some(block);\n        self\n    }\n\n    pub fn ratio(mut self, ratio: f64) -> Self {\n        assert!(\n            (0.0..=1.0).contains(&ratio),\n            \"Ratio should be between 0 and 1 inclusively.\"\n        );\n        self.ratio = ratio;\n        self\n    }\n\n    pub fn line_set(mut self, set: symbols::line::Set) -> Self {\n        self.line_set = set;\n        self\n    }\n\n    pub fn label<T>(mut self, label: T) -> Self\n    where\n        T: Into<Spans<'a>>,\n    {\n        self.label = Some(label.into());\n        self\n    }\n\n    pub fn style(mut self, style: Style) -> Self {\n        self.style = style;\n        self\n    }\n\n    pub fn gauge_style(mut self, style: Style) -> Self {\n        self.gauge_style = style;\n        self\n    }\n}\n\nimpl<'a> Widget for LineGauge<'a> {\n    fn render(mut self, area: Rect, buf: &mut Buffer) {\n        buf.set_style(area, self.style);\n        let gauge_area = match self.block.take() {\n            Some(b) => {\n                let inner_area = b.inner(area);\n                b.render(area, buf);\n                inner_area\n            }\n            None => area,\n        };\n\n        if gauge_area.height < 1 {\n            return;\n        }\n\n        let ratio = self.ratio;\n        let label = self\n            .label\n            .unwrap_or_else(move || Spans::from(format!(\"{:.0}%\", ratio * 100.0)));\n        let (col, row) = buf.set_spans(\n            gauge_area.left(),\n            gauge_area.top(),\n            &label,\n            gauge_area.width,\n        );\n        let start = col + 1;\n        if start >= gauge_area.right() {\n            return;\n        }\n\n        let end = start\n            + (f64::from(gauge_area.right().saturating_sub(start)) * self.ratio).floor() as u16;\n        for col in start..end {\n            buf.get_mut(col, row)\n                .set_symbol(self.line_set.horizontal)\n                .set_style(Style {\n                    fg: self.gauge_style.fg,\n                    bg: None,\n                    add_modifier: self.gauge_style.add_modifier,\n                    sub_modifier: self.gauge_style.sub_modifier,\n                });\n        }\n        for col in end..gauge_area.right() {\n            buf.get_mut(col, row)\n                .set_symbol(self.line_set.horizontal)\n                .set_style(Style {\n                    fg: self.gauge_style.bg,\n                    bg: None,\n                    add_modifier: self.gauge_style.add_modifier,\n                    sub_modifier: self.gauge_style.sub_modifier,\n                });\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    #[should_panic]\n    fn gauge_invalid_percentage() {\n        Gauge::default().percent(110);\n    }\n\n    #[test]\n    #[should_panic]\n    fn gauge_invalid_ratio_upper_bound() {\n        Gauge::default().ratio(1.1);\n    }\n\n    #[test]\n    #[should_panic]\n    fn gauge_invalid_ratio_lower_bound() {\n        Gauge::default().ratio(-0.5);\n    }\n}\n"
  },
  {
    "path": "src/widgets/list.rs",
    "content": "use crate::{\n    buffer::Buffer,\n    layout::{Corner, Rect},\n    style::Style,\n    text::Text,\n    widgets::{Block, StatefulWidget, Widget},\n};\nuse unicode_width::UnicodeWidthStr;\n\n#[derive(Debug, Clone, Default)]\npub struct ListState {\n    offset: usize,\n    selected: Option<usize>,\n}\n\nimpl ListState {\n    pub fn selected(&self) -> Option<usize> {\n        self.selected\n    }\n\n    pub fn select(&mut self, index: Option<usize>) {\n        self.selected = index;\n        if index.is_none() {\n            self.offset = 0;\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct ListItem<'a> {\n    content: Text<'a>,\n    style: Style,\n}\n\nimpl<'a> ListItem<'a> {\n    pub fn new<T>(content: T) -> ListItem<'a>\n    where\n        T: Into<Text<'a>>,\n    {\n        ListItem {\n            content: content.into(),\n            style: Style::default(),\n        }\n    }\n\n    pub fn style(mut self, style: Style) -> ListItem<'a> {\n        self.style = style;\n        self\n    }\n\n    pub fn height(&self) -> usize {\n        self.content.height()\n    }\n}\n\n/// A widget to display several items among which one can be selected (optional)\n///\n/// # Examples\n///\n/// ```\n/// # use tui::widgets::{Block, Borders, List, ListItem};\n/// # use tui::style::{Style, Color, Modifier};\n/// let items = [ListItem::new(\"Item 1\"), ListItem::new(\"Item 2\"), ListItem::new(\"Item 3\")];\n/// List::new(items)\n///     .block(Block::default().title(\"List\").borders(Borders::ALL))\n///     .style(Style::default().fg(Color::White))\n///     .highlight_style(Style::default().add_modifier(Modifier::ITALIC))\n///     .highlight_symbol(\">>\");\n/// ```\n#[derive(Debug, Clone)]\npub struct List<'a> {\n    block: Option<Block<'a>>,\n    items: Vec<ListItem<'a>>,\n    /// Style used as a base style for the widget\n    style: Style,\n    start_corner: Corner,\n    /// Style used to render selected item\n    highlight_style: Style,\n    /// Symbol in front of the selected item (Shift all items to the right)\n    highlight_symbol: Option<&'a str>,\n    /// Whether to repeat the highlight symbol for each line of the selected item\n    repeat_highlight_symbol: bool,\n}\n\nimpl<'a> List<'a> {\n    pub fn new<T>(items: T) -> List<'a>\n    where\n        T: Into<Vec<ListItem<'a>>>,\n    {\n        List {\n            block: None,\n            style: Style::default(),\n            items: items.into(),\n            start_corner: Corner::TopLeft,\n            highlight_style: Style::default(),\n            highlight_symbol: None,\n            repeat_highlight_symbol: false,\n        }\n    }\n\n    pub fn block(mut self, block: Block<'a>) -> List<'a> {\n        self.block = Some(block);\n        self\n    }\n\n    pub fn style(mut self, style: Style) -> List<'a> {\n        self.style = style;\n        self\n    }\n\n    pub fn highlight_symbol(mut self, highlight_symbol: &'a str) -> List<'a> {\n        self.highlight_symbol = Some(highlight_symbol);\n        self\n    }\n\n    pub fn highlight_style(mut self, style: Style) -> List<'a> {\n        self.highlight_style = style;\n        self\n    }\n\n    pub fn repeat_highlight_symbol(mut self, repeat: bool) -> List<'a> {\n        self.repeat_highlight_symbol = repeat;\n        self\n    }\n\n    pub fn start_corner(mut self, corner: Corner) -> List<'a> {\n        self.start_corner = corner;\n        self\n    }\n\n    fn get_items_bounds(\n        &self,\n        selected: Option<usize>,\n        offset: usize,\n        max_height: usize,\n    ) -> (usize, usize) {\n        let offset = offset.min(self.items.len().saturating_sub(1));\n        let mut start = offset;\n        let mut end = offset;\n        let mut height = 0;\n        for item in self.items.iter().skip(offset) {\n            if height + item.height() > max_height {\n                break;\n            }\n            height += item.height();\n            end += 1;\n        }\n\n        let selected = selected.unwrap_or(0).min(self.items.len() - 1);\n        while selected >= end {\n            height = height.saturating_add(self.items[end].height());\n            end += 1;\n            while height > max_height {\n                height = height.saturating_sub(self.items[start].height());\n                start += 1;\n            }\n        }\n        while selected < start {\n            start -= 1;\n            height = height.saturating_add(self.items[start].height());\n            while height > max_height {\n                end -= 1;\n                height = height.saturating_sub(self.items[end].height());\n            }\n        }\n        (start, end)\n    }\n}\n\nimpl<'a> StatefulWidget for List<'a> {\n    type State = ListState;\n\n    fn render(mut self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {\n        buf.set_style(area, self.style);\n        let list_area = match self.block.take() {\n            Some(b) => {\n                let inner_area = b.inner(area);\n                b.render(area, buf);\n                inner_area\n            }\n            None => area,\n        };\n\n        if list_area.width < 1 || list_area.height < 1 {\n            return;\n        }\n\n        if self.items.is_empty() {\n            return;\n        }\n        let list_height = list_area.height as usize;\n\n        let (start, end) = self.get_items_bounds(state.selected, state.offset, list_height);\n        state.offset = start;\n\n        let highlight_symbol = self.highlight_symbol.unwrap_or(\"\");\n        let blank_symbol = \" \".repeat(highlight_symbol.width());\n\n        let mut current_height = 0;\n        let has_selection = state.selected.is_some();\n        for (i, item) in self\n            .items\n            .iter_mut()\n            .enumerate()\n            .skip(state.offset)\n            .take(end - start)\n        {\n            let (x, y) = match self.start_corner {\n                Corner::BottomLeft => {\n                    current_height += item.height() as u16;\n                    (list_area.left(), list_area.bottom() - current_height)\n                }\n                _ => {\n                    let pos = (list_area.left(), list_area.top() + current_height);\n                    current_height += item.height() as u16;\n                    pos\n                }\n            };\n            let area = Rect {\n                x,\n                y,\n                width: list_area.width,\n                height: item.height() as u16,\n            };\n            let item_style = self.style.patch(item.style);\n            buf.set_style(area, item_style);\n\n            let is_selected = state.selected.map(|s| s == i).unwrap_or(false);\n            for (j, line) in item.content.lines.iter().enumerate() {\n                // if the item is selected, we need to display the hightlight symbol:\n                // - either for the first line of the item only,\n                // - or for each line of the item if the appropriate option is set\n                let symbol = if is_selected && (j == 0 || self.repeat_highlight_symbol) {\n                    highlight_symbol\n                } else {\n                    &blank_symbol\n                };\n                let (elem_x, max_element_width) = if has_selection {\n                    let (elem_x, _) = buf.set_stringn(\n                        x,\n                        y + j as u16,\n                        symbol,\n                        list_area.width as usize,\n                        item_style,\n                    );\n                    (elem_x, (list_area.width - (elem_x - x)) as u16)\n                } else {\n                    (x, list_area.width)\n                };\n                buf.set_spans(elem_x, y + j as u16, line, max_element_width as u16);\n            }\n            if is_selected {\n                buf.set_style(area, self.highlight_style);\n            }\n        }\n    }\n}\n\nimpl<'a> Widget for List<'a> {\n    fn render(self, area: Rect, buf: &mut Buffer) {\n        let mut state = ListState::default();\n        StatefulWidget::render(self, area, buf, &mut state);\n    }\n}\n"
  },
  {
    "path": "src/widgets/mod.rs",
    "content": "//! `widgets` is a collection of types that implement [`Widget`] or [`StatefulWidget`] or both.\n//!\n//! All widgets are implemented using the builder pattern and are consumable objects. They are not\n//! meant to be stored but used as *commands* to draw common figures in the UI.\n//!\n//! The available widgets are:\n//! - [`Block`]\n//! - [`Tabs`]\n//! - [`List`]\n//! - [`Table`]\n//! - [`Paragraph`]\n//! - [`Chart`]\n//! - [`BarChart`]\n//! - [`Gauge`]\n//! - [`Sparkline`]\n//! - [`Clear`]\n\nmod barchart;\nmod block;\npub mod canvas;\nmod chart;\nmod clear;\nmod gauge;\nmod list;\nmod paragraph;\nmod reflow;\nmod sparkline;\nmod table;\nmod tabs;\n\npub use self::barchart::BarChart;\npub use self::block::{Block, BorderType};\npub use self::chart::{Axis, Chart, Dataset, GraphType};\npub use self::clear::Clear;\npub use self::gauge::{Gauge, LineGauge};\npub use self::list::{List, ListItem, ListState};\npub use self::paragraph::{Paragraph, Wrap};\npub use self::sparkline::Sparkline;\npub use self::table::{Cell, Row, Table, TableState};\npub use self::tabs::Tabs;\n\nuse crate::{buffer::Buffer, layout::Rect};\nuse bitflags::bitflags;\n\nbitflags! {\n    /// Bitflags that can be composed to set the visible borders essentially on the block widget.\n    pub struct Borders: u32 {\n        /// Show no border (default)\n        const NONE  = 0b0000_0001;\n        /// Show the top border\n        const TOP   = 0b0000_0010;\n        /// Show the right border\n        const RIGHT = 0b0000_0100;\n        /// Show the bottom border\n        const BOTTOM = 0b000_1000;\n        /// Show the left border\n        const LEFT = 0b0001_0000;\n        /// Show all borders\n        const ALL = Self::TOP.bits | Self::RIGHT.bits | Self::BOTTOM.bits | Self::LEFT.bits;\n    }\n}\n\n/// Base requirements for a Widget\npub trait Widget {\n    /// Draws the current state of the widget in the given buffer. That is the only method required\n    /// to implement a custom widget.\n    fn render(self, area: Rect, buf: &mut Buffer);\n}\n\n/// A `StatefulWidget` is a widget that can take advantage of some local state to remember things\n/// between two draw calls.\n///\n/// Most widgets can be drawn directly based on the input parameters. However, some features may\n/// require some kind of associated state to be implemented.\n///\n/// For example, the [`List`] widget can highlight the item currently selected. This can be\n/// translated in an offset, which is the number of elements to skip in order to have the selected\n/// item within the viewport currently allocated to this widget. The widget can therefore only\n/// provide the following behavior: whenever the selected item is out of the viewport scroll to a\n/// predefined position (making the selected item the last viewable item or the one in the middle\n/// for example). Nonetheless, if the widget has access to the last computed offset then it can\n/// implement a natural scrolling experience where the last offset is reused until the selected\n/// item is out of the viewport.\n///\n/// ## Examples\n///\n/// ```rust,no_run\n/// # use std::io;\n/// # use tui::Terminal;\n/// # use tui::backend::{Backend, TestBackend};\n/// # use tui::widgets::{Widget, List, ListItem, ListState};\n///\n/// // Let's say we have some events to display.\n/// struct Events {\n///     // `items` is the state managed by your application.\n///     items: Vec<String>,\n///     // `state` is the state that can be modified by the UI. It stores the index of the selected\n///     // item as well as the offset computed during the previous draw call (used to implement\n///     // natural scrolling).\n///     state: ListState\n/// }\n///\n/// impl Events {\n///     fn new(items: Vec<String>) -> Events {\n///         Events {\n///             items,\n///             state: ListState::default(),\n///         }\n///     }\n///\n///     pub fn set_items(&mut self, items: Vec<String>) {\n///         self.items = items;\n///         // We reset the state as the associated items have changed. This effectively reset\n///         // the selection as well as the stored offset.\n///         self.state = ListState::default();\n///     }\n///\n///     // Select the next item. This will not be reflected until the widget is drawn in the\n///     // `Terminal::draw` callback using `Frame::render_stateful_widget`.\n///     pub fn next(&mut self) {\n///         let i = match self.state.selected() {\n///             Some(i) => {\n///                 if i >= self.items.len() - 1 {\n///                     0\n///                 } else {\n///                     i + 1\n///                 }\n///             }\n///             None => 0,\n///         };\n///         self.state.select(Some(i));\n///     }\n///\n///     // Select the previous item. This will not be reflected until the widget is drawn in the\n///     // `Terminal::draw` callback using `Frame::render_stateful_widget`.\n///     pub fn previous(&mut self) {\n///         let i = match self.state.selected() {\n///             Some(i) => {\n///                 if i == 0 {\n///                     self.items.len() - 1\n///                 } else {\n///                     i - 1\n///                 }\n///             }\n///             None => 0,\n///         };\n///         self.state.select(Some(i));\n///     }\n///\n///     // Unselect the currently selected item if any. The implementation of `ListState` makes\n///     // sure that the stored offset is also reset.\n///     pub fn unselect(&mut self) {\n///         self.state.select(None);\n///     }\n/// }\n///\n/// # let backend = TestBackend::new(5, 5);\n/// # let mut terminal = Terminal::new(backend).unwrap();\n///\n/// let mut events = Events::new(vec![\n///     String::from(\"Item 1\"),\n///     String::from(\"Item 2\")\n/// ]);\n///\n/// loop {\n///     terminal.draw(|f| {\n///         // The items managed by the application are transformed to something\n///         // that is understood by tui.\n///         let items: Vec<ListItem>= events.items.iter().map(|i| ListItem::new(i.as_ref())).collect();\n///         // The `List` widget is then built with those items.\n///         let list = List::new(items);\n///         // Finally the widget is rendered using the associated state. `events.state` is\n///         // effectively the only thing that we will \"remember\" from this draw call.\n///         f.render_stateful_widget(list, f.size(), &mut events.state);\n///     });\n///\n///     // In response to some input events or an external http request or whatever:\n///     events.next();\n/// }\n/// ```\npub trait StatefulWidget {\n    type State;\n    fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State);\n}\n"
  },
  {
    "path": "src/widgets/paragraph.rs",
    "content": "use crate::{\n    buffer::Buffer,\n    layout::{Alignment, Rect},\n    style::Style,\n    text::{StyledGrapheme, Text},\n    widgets::{\n        reflow::{LineComposer, LineTruncator, WordWrapper},\n        Block, Widget,\n    },\n};\nuse std::iter;\nuse unicode_width::UnicodeWidthStr;\n\nfn get_line_offset(line_width: u16, text_area_width: u16, alignment: Alignment) -> u16 {\n    match alignment {\n        Alignment::Center => (text_area_width / 2).saturating_sub(line_width / 2),\n        Alignment::Right => text_area_width.saturating_sub(line_width),\n        Alignment::Left => 0,\n    }\n}\n\n/// A widget to display some text.\n///\n/// # Examples\n///\n/// ```\n/// # use tui::text::{Text, Spans, Span};\n/// # use tui::widgets::{Block, Borders, Paragraph, Wrap};\n/// # use tui::style::{Style, Color, Modifier};\n/// # use tui::layout::{Alignment};\n/// let text = vec![\n///     Spans::from(vec![\n///         Span::raw(\"First\"),\n///         Span::styled(\"line\",Style::default().add_modifier(Modifier::ITALIC)),\n///         Span::raw(\".\"),\n///     ]),\n///     Spans::from(Span::styled(\"Second line\", Style::default().fg(Color::Red))),\n/// ];\n/// Paragraph::new(text)\n///     .block(Block::default().title(\"Paragraph\").borders(Borders::ALL))\n///     .style(Style::default().fg(Color::White).bg(Color::Black))\n///     .alignment(Alignment::Center)\n///     .wrap(Wrap { trim: true });\n/// ```\n#[derive(Debug, Clone)]\npub struct Paragraph<'a> {\n    /// A block to wrap the widget in\n    block: Option<Block<'a>>,\n    /// Widget style\n    style: Style,\n    /// How to wrap the text\n    wrap: Option<Wrap>,\n    /// The text to display\n    text: Text<'a>,\n    /// Scroll\n    scroll: (u16, u16),\n    /// Alignment of the text\n    alignment: Alignment,\n}\n\n/// Describes how to wrap text across lines.\n///\n/// ## Examples\n///\n/// ```\n/// # use tui::widgets::{Paragraph, Wrap};\n/// # use tui::text::Text;\n/// let bullet_points = Text::from(r#\"Some indented points:\n///     - First thing goes here and is long so that it wraps\n///     - Here is another point that is long enough to wrap\"#);\n///\n/// // With leading spaces trimmed (window width of 30 chars):\n/// Paragraph::new(bullet_points.clone()).wrap(Wrap { trim: true });\n/// // Some indented points:\n/// // - First thing goes here and is\n/// // long so that it wraps\n/// // - Here is another point that\n/// // is long enough to wrap\n///\n/// // But without trimming, indentation is preserved:\n/// Paragraph::new(bullet_points).wrap(Wrap { trim: false });\n/// // Some indented points:\n/// //     - First thing goes here\n/// // and is long so that it wraps\n/// //     - Here is another point\n/// // that is long enough to wrap\n/// ```\n#[derive(Debug, Clone, Copy)]\npub struct Wrap {\n    /// Should leading whitespace be trimmed\n    pub trim: bool,\n}\n\nimpl<'a> Paragraph<'a> {\n    pub fn new<T>(text: T) -> Paragraph<'a>\n    where\n        T: Into<Text<'a>>,\n    {\n        Paragraph {\n            block: None,\n            style: Default::default(),\n            wrap: None,\n            text: text.into(),\n            scroll: (0, 0),\n            alignment: Alignment::Left,\n        }\n    }\n\n    pub fn block(mut self, block: Block<'a>) -> Paragraph<'a> {\n        self.block = Some(block);\n        self\n    }\n\n    pub fn style(mut self, style: Style) -> Paragraph<'a> {\n        self.style = style;\n        self\n    }\n\n    pub fn wrap(mut self, wrap: Wrap) -> Paragraph<'a> {\n        self.wrap = Some(wrap);\n        self\n    }\n\n    pub fn scroll(mut self, offset: (u16, u16)) -> Paragraph<'a> {\n        self.scroll = offset;\n        self\n    }\n\n    pub fn alignment(mut self, alignment: Alignment) -> Paragraph<'a> {\n        self.alignment = alignment;\n        self\n    }\n}\n\nimpl<'a> Widget for Paragraph<'a> {\n    fn render(mut self, area: Rect, buf: &mut Buffer) {\n        buf.set_style(area, self.style);\n        let text_area = match self.block.take() {\n            Some(b) => {\n                let inner_area = b.inner(area);\n                b.render(area, buf);\n                inner_area\n            }\n            None => area,\n        };\n\n        if text_area.height < 1 {\n            return;\n        }\n\n        let style = self.style;\n        let mut styled = self.text.lines.iter().flat_map(|spans| {\n            spans\n                .0\n                .iter()\n                .flat_map(|span| span.styled_graphemes(style))\n                // Required given the way composers work but might be refactored out if we change\n                // composers to operate on lines instead of a stream of graphemes.\n                .chain(iter::once(StyledGrapheme {\n                    symbol: \"\\n\",\n                    style: self.style,\n                }))\n        });\n\n        let mut line_composer: Box<dyn LineComposer> = if let Some(Wrap { trim }) = self.wrap {\n            Box::new(WordWrapper::new(&mut styled, text_area.width, trim))\n        } else {\n            let mut line_composer = Box::new(LineTruncator::new(&mut styled, text_area.width));\n            if let Alignment::Left = self.alignment {\n                line_composer.set_horizontal_offset(self.scroll.1);\n            }\n            line_composer\n        };\n        let mut y = 0;\n        while let Some((current_line, current_line_width)) = line_composer.next_line() {\n            if y >= self.scroll.0 {\n                let mut x = get_line_offset(current_line_width, text_area.width, self.alignment);\n                for StyledGrapheme { symbol, style } in current_line {\n                    buf.get_mut(text_area.left() + x, text_area.top() + y - self.scroll.0)\n                        .set_symbol(if symbol.is_empty() {\n                            // If the symbol is empty, the last char which rendered last time will\n                            // leave on the line. It's a quick fix.\n                            \" \"\n                        } else {\n                            symbol\n                        })\n                        .set_style(*style);\n                    x += symbol.width() as u16;\n                }\n            }\n            y += 1;\n            if y >= text_area.height + self.scroll.0 {\n                break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/widgets/reflow.rs",
    "content": "use crate::text::StyledGrapheme;\nuse unicode_segmentation::UnicodeSegmentation;\nuse unicode_width::UnicodeWidthStr;\n\nconst NBSP: &str = \"\\u{00a0}\";\n\n/// A state machine to pack styled symbols into lines.\n/// Cannot implement it as Iterator since it yields slices of the internal buffer (need streaming\n/// iterators for that).\npub trait LineComposer<'a> {\n    fn next_line(&mut self) -> Option<(&[StyledGrapheme<'a>], u16)>;\n}\n\n/// A state machine that wraps lines on word boundaries.\npub struct WordWrapper<'a, 'b> {\n    symbols: &'b mut dyn Iterator<Item = StyledGrapheme<'a>>,\n    max_line_width: u16,\n    current_line: Vec<StyledGrapheme<'a>>,\n    next_line: Vec<StyledGrapheme<'a>>,\n    /// Removes the leading whitespace from lines\n    trim: bool,\n}\n\nimpl<'a, 'b> WordWrapper<'a, 'b> {\n    pub fn new(\n        symbols: &'b mut dyn Iterator<Item = StyledGrapheme<'a>>,\n        max_line_width: u16,\n        trim: bool,\n    ) -> WordWrapper<'a, 'b> {\n        WordWrapper {\n            symbols,\n            max_line_width,\n            current_line: vec![],\n            next_line: vec![],\n            trim,\n        }\n    }\n}\n\nimpl<'a, 'b> LineComposer<'a> for WordWrapper<'a, 'b> {\n    fn next_line(&mut self) -> Option<(&[StyledGrapheme<'a>], u16)> {\n        if self.max_line_width == 0 {\n            return None;\n        }\n        std::mem::swap(&mut self.current_line, &mut self.next_line);\n        self.next_line.truncate(0);\n\n        let mut current_line_width = self\n            .current_line\n            .iter()\n            .map(|StyledGrapheme { symbol, .. }| symbol.width() as u16)\n            .sum();\n\n        let mut symbols_to_last_word_end: usize = 0;\n        let mut width_to_last_word_end: u16 = 0;\n        let mut prev_whitespace = false;\n        let mut symbols_exhausted = true;\n        for StyledGrapheme { symbol, style } in &mut self.symbols {\n            symbols_exhausted = false;\n            let symbol_whitespace = symbol.chars().all(&char::is_whitespace) && symbol != NBSP;\n\n            // Ignore characters wider that the total max width.\n            if symbol.width() as u16 > self.max_line_width\n                // Skip leading whitespace when trim is enabled.\n                || self.trim && symbol_whitespace && symbol != \"\\n\" && current_line_width == 0\n            {\n                continue;\n            }\n\n            // Break on newline and discard it.\n            if symbol == \"\\n\" {\n                if prev_whitespace {\n                    current_line_width = width_to_last_word_end;\n                    self.current_line.truncate(symbols_to_last_word_end);\n                }\n                break;\n            }\n\n            // Mark the previous symbol as word end.\n            if symbol_whitespace && !prev_whitespace {\n                symbols_to_last_word_end = self.current_line.len();\n                width_to_last_word_end = current_line_width;\n            }\n\n            self.current_line.push(StyledGrapheme { symbol, style });\n            current_line_width += symbol.width() as u16;\n\n            if current_line_width > self.max_line_width {\n                // If there was no word break in the text, wrap at the end of the line.\n                let (truncate_at, truncated_width) = if symbols_to_last_word_end != 0 {\n                    (symbols_to_last_word_end, width_to_last_word_end)\n                } else {\n                    (self.current_line.len() - 1, self.max_line_width)\n                };\n\n                // Push the remainder to the next line but strip leading whitespace:\n                {\n                    let remainder = &self.current_line[truncate_at..];\n                    if let Some(remainder_nonwhite) =\n                        remainder.iter().position(|StyledGrapheme { symbol, .. }| {\n                            !symbol.chars().all(&char::is_whitespace)\n                        })\n                    {\n                        self.next_line\n                            .extend_from_slice(&remainder[remainder_nonwhite..]);\n                    }\n                }\n                self.current_line.truncate(truncate_at);\n                current_line_width = truncated_width;\n                break;\n            }\n\n            prev_whitespace = symbol_whitespace;\n        }\n\n        // Even if the iterator is exhausted, pass the previous remainder.\n        if symbols_exhausted && self.current_line.is_empty() {\n            None\n        } else {\n            Some((&self.current_line[..], current_line_width))\n        }\n    }\n}\n\n/// A state machine that truncates overhanging lines.\npub struct LineTruncator<'a, 'b> {\n    symbols: &'b mut dyn Iterator<Item = StyledGrapheme<'a>>,\n    max_line_width: u16,\n    current_line: Vec<StyledGrapheme<'a>>,\n    /// Record the offet to skip render\n    horizontal_offset: u16,\n}\n\nimpl<'a, 'b> LineTruncator<'a, 'b> {\n    pub fn new(\n        symbols: &'b mut dyn Iterator<Item = StyledGrapheme<'a>>,\n        max_line_width: u16,\n    ) -> LineTruncator<'a, 'b> {\n        LineTruncator {\n            symbols,\n            max_line_width,\n            horizontal_offset: 0,\n            current_line: vec![],\n        }\n    }\n\n    pub fn set_horizontal_offset(&mut self, horizontal_offset: u16) {\n        self.horizontal_offset = horizontal_offset;\n    }\n}\n\nimpl<'a, 'b> LineComposer<'a> for LineTruncator<'a, 'b> {\n    fn next_line(&mut self) -> Option<(&[StyledGrapheme<'a>], u16)> {\n        if self.max_line_width == 0 {\n            return None;\n        }\n\n        self.current_line.truncate(0);\n        let mut current_line_width = 0;\n\n        let mut skip_rest = false;\n        let mut symbols_exhausted = true;\n        let mut horizontal_offset = self.horizontal_offset as usize;\n        for StyledGrapheme { symbol, style } in &mut self.symbols {\n            symbols_exhausted = false;\n\n            // Ignore characters wider that the total max width.\n            if symbol.width() as u16 > self.max_line_width {\n                continue;\n            }\n\n            // Break on newline and discard it.\n            if symbol == \"\\n\" {\n                break;\n            }\n\n            if current_line_width + symbol.width() as u16 > self.max_line_width {\n                // Exhaust the remainder of the line.\n                skip_rest = true;\n                break;\n            }\n\n            let symbol = if horizontal_offset == 0 {\n                symbol\n            } else {\n                let w = symbol.width();\n                if w > horizontal_offset {\n                    let t = trim_offset(symbol, horizontal_offset);\n                    horizontal_offset = 0;\n                    t\n                } else {\n                    horizontal_offset -= w;\n                    \"\"\n                }\n            };\n            current_line_width += symbol.width() as u16;\n            self.current_line.push(StyledGrapheme { symbol, style });\n        }\n\n        if skip_rest {\n            for StyledGrapheme { symbol, .. } in &mut self.symbols {\n                if symbol == \"\\n\" {\n                    break;\n                }\n            }\n        }\n\n        if symbols_exhausted && self.current_line.is_empty() {\n            None\n        } else {\n            Some((&self.current_line[..], current_line_width))\n        }\n    }\n}\n\n/// This function will return a str slice which start at specified offset.\n/// As src is a unicode str, start offset has to be calculated with each character.\nfn trim_offset(src: &str, mut offset: usize) -> &str {\n    let mut start = 0;\n    for c in UnicodeSegmentation::graphemes(src, true) {\n        let w = c.width();\n        if w <= offset {\n            offset -= w;\n            start += c.len();\n        } else {\n            break;\n        }\n    }\n    &src[start..]\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n    use unicode_segmentation::UnicodeSegmentation;\n\n    enum Composer {\n        WordWrapper { trim: bool },\n        LineTruncator,\n    }\n\n    fn run_composer(which: Composer, text: &str, text_area_width: u16) -> (Vec<String>, Vec<u16>) {\n        let style = Default::default();\n        let mut styled =\n            UnicodeSegmentation::graphemes(text, true).map(|g| StyledGrapheme { symbol: g, style });\n        let mut composer: Box<dyn LineComposer> = match which {\n            Composer::WordWrapper { trim } => {\n                Box::new(WordWrapper::new(&mut styled, text_area_width, trim))\n            }\n            Composer::LineTruncator => Box::new(LineTruncator::new(&mut styled, text_area_width)),\n        };\n        let mut lines = vec![];\n        let mut widths = vec![];\n        while let Some((styled, width)) = composer.next_line() {\n            let line = styled\n                .iter()\n                .map(|StyledGrapheme { symbol, .. }| *symbol)\n                .collect::<String>();\n            assert!(width <= text_area_width);\n            lines.push(line);\n            widths.push(width);\n        }\n        (lines, widths)\n    }\n\n    #[test]\n    fn line_composer_one_line() {\n        let width = 40;\n        for i in 1..width {\n            let text = \"a\".repeat(i);\n            let (word_wrapper, _) =\n                run_composer(Composer::WordWrapper { trim: true }, &text, width as u16);\n            let (line_truncator, _) = run_composer(Composer::LineTruncator, &text, width as u16);\n            let expected = vec![text];\n            assert_eq!(word_wrapper, expected);\n            assert_eq!(line_truncator, expected);\n        }\n    }\n\n    #[test]\n    fn line_composer_short_lines() {\n        let width = 20;\n        let text =\n            \"abcdefg\\nhijklmno\\npabcdefg\\nhijklmn\\nopabcdefghijk\\nlmnopabcd\\n\\n\\nefghijklmno\";\n        let (word_wrapper, _) = run_composer(Composer::WordWrapper { trim: true }, text, width);\n        let (line_truncator, _) = run_composer(Composer::LineTruncator, text, width);\n\n        let wrapped: Vec<&str> = text.split('\\n').collect();\n        assert_eq!(word_wrapper, wrapped);\n        assert_eq!(line_truncator, wrapped);\n    }\n\n    #[test]\n    fn line_composer_long_word() {\n        let width = 20;\n        let text = \"abcdefghijklmnopabcdefghijklmnopabcdefghijklmnopabcdefghijklmno\";\n        let (word_wrapper, _) =\n            run_composer(Composer::WordWrapper { trim: true }, text, width as u16);\n        let (line_truncator, _) = run_composer(Composer::LineTruncator, text, width as u16);\n\n        let wrapped = vec![\n            &text[..width],\n            &text[width..width * 2],\n            &text[width * 2..width * 3],\n            &text[width * 3..],\n        ];\n        assert_eq!(\n            word_wrapper, wrapped,\n            \"WordWrapper should detect the line cannot be broken on word boundary and \\\n             break it at line width limit.\"\n        );\n        assert_eq!(line_truncator, vec![&text[..width]]);\n    }\n\n    #[test]\n    fn line_composer_long_sentence() {\n        let width = 20;\n        let text =\n            \"abcd efghij klmnopabcd efgh ijklmnopabcdefg hijkl mnopab c d e f g h i j k l m n o\";\n        let text_multi_space =\n            \"abcd efghij    klmnopabcd efgh     ijklmnopabcdefg hijkl mnopab c d e f g h i j k l \\\n             m n o\";\n        let (word_wrapper_single_space, _) =\n            run_composer(Composer::WordWrapper { trim: true }, text, width as u16);\n        let (word_wrapper_multi_space, _) = run_composer(\n            Composer::WordWrapper { trim: true },\n            text_multi_space,\n            width as u16,\n        );\n        let (line_truncator, _) = run_composer(Composer::LineTruncator, text, width as u16);\n\n        let word_wrapped = vec![\n            \"abcd efghij\",\n            \"klmnopabcd efgh\",\n            \"ijklmnopabcdefg\",\n            \"hijkl mnopab c d e f\",\n            \"g h i j k l m n o\",\n        ];\n        assert_eq!(word_wrapper_single_space, word_wrapped);\n        assert_eq!(word_wrapper_multi_space, word_wrapped);\n\n        assert_eq!(line_truncator, vec![&text[..width]]);\n    }\n\n    #[test]\n    fn line_composer_zero_width() {\n        let width = 0;\n        let text = \"abcd efghij klmnopabcd efgh ijklmnopabcdefg hijkl mnopab \";\n        let (word_wrapper, _) = run_composer(Composer::WordWrapper { trim: true }, text, width);\n        let (line_truncator, _) = run_composer(Composer::LineTruncator, text, width);\n\n        let expected: Vec<&str> = Vec::new();\n        assert_eq!(word_wrapper, expected);\n        assert_eq!(line_truncator, expected);\n    }\n\n    #[test]\n    fn line_composer_max_line_width_of_1() {\n        let width = 1;\n        let text = \"abcd efghij klmnopabcd efgh ijklmnopabcdefg hijkl mnopab \";\n        let (word_wrapper, _) = run_composer(Composer::WordWrapper { trim: true }, text, width);\n        let (line_truncator, _) = run_composer(Composer::LineTruncator, text, width);\n\n        let expected: Vec<&str> = UnicodeSegmentation::graphemes(text, true)\n            .filter(|g| g.chars().any(|c| !c.is_whitespace()))\n            .collect();\n        assert_eq!(word_wrapper, expected);\n        assert_eq!(line_truncator, vec![\"a\"]);\n    }\n\n    #[test]\n    fn line_composer_max_line_width_of_1_double_width_characters() {\n        let width = 1;\n        let text = \"コンピュータ上で文字を扱う場合、典型的には文字\\naaaによる通信を行う場合にその\\\n                    両端点では、\";\n        let (word_wrapper, _) = run_composer(Composer::WordWrapper { trim: true }, text, width);\n        let (line_truncator, _) = run_composer(Composer::LineTruncator, text, width);\n        assert_eq!(word_wrapper, vec![\"\", \"a\", \"a\", \"a\"]);\n        assert_eq!(line_truncator, vec![\"\", \"a\"]);\n    }\n\n    /// Tests WordWrapper with words some of which exceed line length and some not.\n    #[test]\n    fn line_composer_word_wrapper_mixed_length() {\n        let width = 20;\n        let text = \"abcd efghij klmnopabcdefghijklmnopabcdefghijkl mnopab cdefghi j klmno\";\n        let (word_wrapper, _) = run_composer(Composer::WordWrapper { trim: true }, text, width);\n        assert_eq!(\n            word_wrapper,\n            vec![\n                \"abcd efghij\",\n                \"klmnopabcdefghijklmn\",\n                \"opabcdefghijkl\",\n                \"mnopab cdefghi j\",\n                \"klmno\",\n            ]\n        )\n    }\n\n    #[test]\n    fn line_composer_double_width_chars() {\n        let width = 20;\n        let text = \"コンピュータ上で文字を扱う場合、典型的には文字による通信を行う場合にその両端点\\\n                    では、\";\n        let (word_wrapper, word_wrapper_width) =\n            run_composer(Composer::WordWrapper { trim: true }, text, width);\n        let (line_truncator, _) = run_composer(Composer::LineTruncator, text, width);\n        assert_eq!(line_truncator, vec![\"コンピュータ上で文字\"]);\n        let wrapped = vec![\n            \"コンピュータ上で文字\",\n            \"を扱う場合、典型的に\",\n            \"は文字による通信を行\",\n            \"う場合にその両端点で\",\n            \"は、\",\n        ];\n        assert_eq!(word_wrapper, wrapped);\n        assert_eq!(word_wrapper_width, vec![width, width, width, width, 4]);\n    }\n\n    #[test]\n    fn line_composer_leading_whitespace_removal() {\n        let width = 20;\n        let text = \"AAAAAAAAAAAAAAAAAAAA    AAA\";\n        let (word_wrapper, _) = run_composer(Composer::WordWrapper { trim: true }, text, width);\n        let (line_truncator, _) = run_composer(Composer::LineTruncator, text, width);\n        assert_eq!(word_wrapper, vec![\"AAAAAAAAAAAAAAAAAAAA\", \"AAA\",]);\n        assert_eq!(line_truncator, vec![\"AAAAAAAAAAAAAAAAAAAA\"]);\n    }\n\n    /// Tests truncation of leading whitespace.\n    #[test]\n    fn line_composer_lots_of_spaces() {\n        let width = 20;\n        let text = \"                                                                     \";\n        let (word_wrapper, _) = run_composer(Composer::WordWrapper { trim: true }, text, width);\n        let (line_truncator, _) = run_composer(Composer::LineTruncator, text, width);\n        assert_eq!(word_wrapper, vec![\"\"]);\n        assert_eq!(line_truncator, vec![\"                    \"]);\n    }\n\n    /// Tests an input starting with a letter, folowed by spaces - some of the behaviour is\n    /// incidental.\n    #[test]\n    fn line_composer_char_plus_lots_of_spaces() {\n        let width = 20;\n        let text = \"a                                                                     \";\n        let (word_wrapper, _) = run_composer(Composer::WordWrapper { trim: true }, text, width);\n        let (line_truncator, _) = run_composer(Composer::LineTruncator, text, width);\n        // What's happening below is: the first line gets consumed, trailing spaces discarded,\n        // after 20 of which a word break occurs (probably shouldn't). The second line break\n        // discards all whitespace. The result should probably be vec![\"a\"] but it doesn't matter\n        // that much.\n        assert_eq!(word_wrapper, vec![\"a\", \"\"]);\n        assert_eq!(line_truncator, vec![\"a                   \"]);\n    }\n\n    #[test]\n    fn line_composer_word_wrapper_double_width_chars_mixed_with_spaces() {\n        let width = 20;\n        // Japanese seems not to use spaces but we should break on spaces anyway... We're using it\n        // to test double-width chars.\n        // You are more than welcome to add word boundary detection based of alterations of\n        // hiragana and katakana...\n        // This happens to also be a test case for mixed width because regular spaces are single width.\n        let text = \"コンピュ ータ上で文字を扱う場合、 典型的には文 字による 通信を行 う場合にその両端点では、\";\n        let (word_wrapper, word_wrapper_width) =\n            run_composer(Composer::WordWrapper { trim: true }, text, width);\n        assert_eq!(\n            word_wrapper,\n            vec![\n                \"コンピュ\",\n                \"ータ上で文字を扱う場\",\n                \"合、 典型的には文\",\n                \"字による 通信を行\",\n                \"う場合にその両端点で\",\n                \"は、\",\n            ]\n        );\n        // Odd-sized lines have a space in them.\n        assert_eq!(word_wrapper_width, vec![8, 20, 17, 17, 20, 4]);\n    }\n\n    /// Ensure words separated by nbsp are wrapped as if they were a single one.\n    #[test]\n    fn line_composer_word_wrapper_nbsp() {\n        let width = 20;\n        let text = \"AAAAAAAAAAAAAAA AAAA\\u{00a0}AAA\";\n        let (word_wrapper, _) = run_composer(Composer::WordWrapper { trim: true }, text, width);\n        assert_eq!(word_wrapper, vec![\"AAAAAAAAAAAAAAA\", \"AAAA\\u{00a0}AAA\",]);\n\n        // Ensure that if the character was a regular space, it would be wrapped differently.\n        let text_space = text.replace('\\u{00a0}', \" \");\n        let (word_wrapper_space, _) =\n            run_composer(Composer::WordWrapper { trim: true }, &text_space, width);\n        assert_eq!(word_wrapper_space, vec![\"AAAAAAAAAAAAAAA AAAA\", \"AAA\",]);\n    }\n\n    #[test]\n    fn line_composer_word_wrapper_preserve_indentation() {\n        let width = 20;\n        let text = \"AAAAAAAAAAAAAAAAAAAA    AAA\";\n        let (word_wrapper, _) = run_composer(Composer::WordWrapper { trim: false }, text, width);\n        assert_eq!(word_wrapper, vec![\"AAAAAAAAAAAAAAAAAAAA\", \"   AAA\",]);\n    }\n\n    #[test]\n    fn line_composer_word_wrapper_preserve_indentation_with_wrap() {\n        let width = 10;\n        let text = \"AAA AAA AAAAA AA AAAAAA\\n B\\n  C\\n   D\";\n        let (word_wrapper, _) = run_composer(Composer::WordWrapper { trim: false }, text, width);\n        assert_eq!(\n            word_wrapper,\n            vec![\"AAA AAA\", \"AAAAA AA\", \"AAAAAA\", \" B\", \"  C\", \"   D\"]\n        );\n    }\n\n    #[test]\n    fn line_composer_word_wrapper_preserve_indentation_lots_of_whitespace() {\n        let width = 10;\n        let text = \"               4 Indent\\n                 must wrap!\";\n        let (word_wrapper, _) = run_composer(Composer::WordWrapper { trim: false }, text, width);\n        assert_eq!(\n            word_wrapper,\n            vec![\n                \"          \",\n                \"    4\",\n                \"Indent\",\n                \"          \",\n                \"      must\",\n                \"wrap!\"\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "src/widgets/sparkline.rs",
    "content": "use crate::{\n    buffer::Buffer,\n    layout::Rect,\n    style::Style,\n    symbols,\n    widgets::{Block, Widget},\n};\nuse std::cmp::min;\n\n/// Widget to render a sparkline over one or more lines.\n///\n/// # Examples\n///\n/// ```\n/// # use tui::widgets::{Block, Borders, Sparkline};\n/// # use tui::style::{Style, Color};\n/// Sparkline::default()\n///     .block(Block::default().title(\"Sparkline\").borders(Borders::ALL))\n///     .data(&[0, 2, 3, 4, 1, 4, 10])\n///     .max(5)\n///     .style(Style::default().fg(Color::Red).bg(Color::White));\n/// ```\n#[derive(Debug, Clone)]\npub struct Sparkline<'a> {\n    /// A block to wrap the widget in\n    block: Option<Block<'a>>,\n    /// Widget style\n    style: Style,\n    /// A slice of the data to display\n    data: &'a [u64],\n    /// The maximum value to take to compute the maximum bar height (if nothing is specified, the\n    /// widget uses the max of the dataset)\n    max: Option<u64>,\n    /// A set of bar symbols used to represent the give data\n    bar_set: symbols::bar::Set,\n}\n\nimpl<'a> Default for Sparkline<'a> {\n    fn default() -> Sparkline<'a> {\n        Sparkline {\n            block: None,\n            style: Default::default(),\n            data: &[],\n            max: None,\n            bar_set: symbols::bar::NINE_LEVELS,\n        }\n    }\n}\n\nimpl<'a> Sparkline<'a> {\n    pub fn block(mut self, block: Block<'a>) -> Sparkline<'a> {\n        self.block = Some(block);\n        self\n    }\n\n    pub fn style(mut self, style: Style) -> Sparkline<'a> {\n        self.style = style;\n        self\n    }\n\n    pub fn data(mut self, data: &'a [u64]) -> Sparkline<'a> {\n        self.data = data;\n        self\n    }\n\n    pub fn max(mut self, max: u64) -> Sparkline<'a> {\n        self.max = Some(max);\n        self\n    }\n\n    pub fn bar_set(mut self, bar_set: symbols::bar::Set) -> Sparkline<'a> {\n        self.bar_set = bar_set;\n        self\n    }\n}\n\nimpl<'a> Widget for Sparkline<'a> {\n    fn render(mut self, area: Rect, buf: &mut Buffer) {\n        let spark_area = match self.block.take() {\n            Some(b) => {\n                let inner_area = b.inner(area);\n                b.render(area, buf);\n                inner_area\n            }\n            None => area,\n        };\n\n        if spark_area.height < 1 {\n            return;\n        }\n\n        let max = match self.max {\n            Some(v) => v,\n            None => *self.data.iter().max().unwrap_or(&1u64),\n        };\n        let max_index = min(spark_area.width as usize, self.data.len());\n        let mut data = self\n            .data\n            .iter()\n            .take(max_index)\n            .map(|e| {\n                if max != 0 {\n                    e * u64::from(spark_area.height) * 8 / max\n                } else {\n                    0\n                }\n            })\n            .collect::<Vec<u64>>();\n        for j in (0..spark_area.height).rev() {\n            for (i, d) in data.iter_mut().enumerate() {\n                let symbol = match *d {\n                    0 => self.bar_set.empty,\n                    1 => self.bar_set.one_eighth,\n                    2 => self.bar_set.one_quarter,\n                    3 => self.bar_set.three_eighths,\n                    4 => self.bar_set.half,\n                    5 => self.bar_set.five_eighths,\n                    6 => self.bar_set.three_quarters,\n                    7 => self.bar_set.seven_eighths,\n                    _ => self.bar_set.full,\n                };\n                buf.get_mut(spark_area.left() + i as u16, spark_area.top() + j)\n                    .set_symbol(symbol)\n                    .set_style(self.style);\n\n                if *d > 8 {\n                    *d -= 8;\n                } else {\n                    *d = 0;\n                }\n            }\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn it_does_not_panic_if_max_is_zero() {\n        let widget = Sparkline::default().data(&[0, 0, 0]);\n        let area = Rect::new(0, 0, 3, 1);\n        let mut buffer = Buffer::empty(area);\n        widget.render(area, &mut buffer);\n    }\n\n    #[test]\n    fn it_does_not_panic_if_max_is_set_to_zero() {\n        let widget = Sparkline::default().data(&[0, 1, 2]).max(0);\n        let area = Rect::new(0, 0, 3, 1);\n        let mut buffer = Buffer::empty(area);\n        widget.render(area, &mut buffer);\n    }\n}\n"
  },
  {
    "path": "src/widgets/table.rs",
    "content": "use crate::{\n    buffer::Buffer,\n    layout::{Constraint, Direction, Layout, Rect},\n    style::Style,\n    text::Text,\n    widgets::{Block, StatefulWidget, Widget},\n};\nuse unicode_width::UnicodeWidthStr;\n\n/// A [`Cell`] contains the [`Text`] to be displayed in a [`Row`] of a [`Table`].\n///\n/// It can be created from anything that can be converted to a [`Text`].\n/// ```rust\n/// # use tui::widgets::Cell;\n/// # use tui::style::{Style, Modifier};\n/// # use tui::text::{Span, Spans, Text};\n/// # use std::borrow::Cow;\n/// Cell::from(\"simple string\");\n///\n/// Cell::from(Span::from(\"span\"));\n///\n/// Cell::from(Spans::from(vec![\n///     Span::raw(\"a vec of \"),\n///     Span::styled(\"spans\", Style::default().add_modifier(Modifier::BOLD))\n/// ]));\n///\n/// Cell::from(Text::from(\"a text\"));\n///\n/// Cell::from(Text::from(Cow::Borrowed(\"hello\")));\n/// ```\n///\n/// You can apply a [`Style`] on the entire [`Cell`] using [`Cell::style`] or rely on the styling\n/// capabilities of [`Text`].\n#[derive(Debug, Clone, PartialEq, Eq, Default)]\npub struct Cell<'a> {\n    content: Text<'a>,\n    style: Style,\n}\n\nimpl<'a> Cell<'a> {\n    /// Set the `Style` of this cell.\n    pub fn style(mut self, style: Style) -> Self {\n        self.style = style;\n        self\n    }\n}\n\nimpl<'a, T> From<T> for Cell<'a>\nwhere\n    T: Into<Text<'a>>,\n{\n    fn from(content: T) -> Cell<'a> {\n        Cell {\n            content: content.into(),\n            style: Style::default(),\n        }\n    }\n}\n\n/// Holds data to be displayed in a [`Table`] widget.\n///\n/// A [`Row`] is a collection of cells. It can be created from simple strings:\n/// ```rust\n/// # use tui::widgets::Row;\n/// Row::new(vec![\"Cell1\", \"Cell2\", \"Cell3\"]);\n/// ```\n///\n/// But if you need a bit more control over individual cells, you can explicity create [`Cell`]s:\n/// ```rust\n/// # use tui::widgets::{Row, Cell};\n/// # use tui::style::{Style, Color};\n/// Row::new(vec![\n///     Cell::from(\"Cell1\"),\n///     Cell::from(\"Cell2\").style(Style::default().fg(Color::Yellow)),\n/// ]);\n/// ```\n///\n/// You can also construct a row from any type that can be converted into [`Text`]:\n/// ```rust\n/// # use std::borrow::Cow;\n/// # use tui::widgets::Row;\n/// Row::new(vec![\n///     Cow::Borrowed(\"hello\"),\n///     Cow::Owned(\"world\".to_uppercase()),\n/// ]);\n/// ```\n///\n/// By default, a row has a height of 1 but you can change this using [`Row::height`].\n#[derive(Debug, Clone, PartialEq, Eq, Default)]\npub struct Row<'a> {\n    cells: Vec<Cell<'a>>,\n    height: u16,\n    style: Style,\n    bottom_margin: u16,\n}\n\nimpl<'a> Row<'a> {\n    /// Creates a new [`Row`] from an iterator where items can be converted to a [`Cell`].\n    pub fn new<T>(cells: T) -> Self\n    where\n        T: IntoIterator,\n        T::Item: Into<Cell<'a>>,\n    {\n        Self {\n            height: 1,\n            cells: cells.into_iter().map(|c| c.into()).collect(),\n            style: Style::default(),\n            bottom_margin: 0,\n        }\n    }\n\n    /// Set the fixed height of the [`Row`]. Any [`Cell`] whose content has more lines than this\n    /// height will see its content truncated.\n    pub fn height(mut self, height: u16) -> Self {\n        self.height = height;\n        self\n    }\n\n    /// Set the [`Style`] of the entire row. This [`Style`] can be overriden by the [`Style`] of a\n    /// any individual [`Cell`] or event by their [`Text`] content.\n    pub fn style(mut self, style: Style) -> Self {\n        self.style = style;\n        self\n    }\n\n    /// Set the bottom margin. By default, the bottom margin is `0`.\n    pub fn bottom_margin(mut self, margin: u16) -> Self {\n        self.bottom_margin = margin;\n        self\n    }\n\n    /// Returns the total height of the row.\n    fn total_height(&self) -> u16 {\n        self.height.saturating_add(self.bottom_margin)\n    }\n}\n\n/// A widget to display data in formatted columns.\n///\n/// It is a collection of [`Row`]s, themselves composed of [`Cell`]s:\n/// ```rust\n/// # use tui::widgets::{Block, Borders, Table, Row, Cell};\n/// # use tui::layout::Constraint;\n/// # use tui::style::{Style, Color, Modifier};\n/// # use tui::text::{Text, Spans, Span};\n/// Table::new(vec![\n///     // Row can be created from simple strings.\n///     Row::new(vec![\"Row11\", \"Row12\", \"Row13\"]),\n///     // You can style the entire row.\n///     Row::new(vec![\"Row21\", \"Row22\", \"Row23\"]).style(Style::default().fg(Color::Blue)),\n///     // If you need more control over the styling you may need to create Cells directly\n///     Row::new(vec![\n///         Cell::from(\"Row31\"),\n///         Cell::from(\"Row32\").style(Style::default().fg(Color::Yellow)),\n///         Cell::from(Spans::from(vec![\n///             Span::raw(\"Row\"),\n///             Span::styled(\"33\", Style::default().fg(Color::Green))\n///         ])),\n///     ]),\n///     // If a Row need to display some content over multiple lines, you just have to change\n///     // its height.\n///     Row::new(vec![\n///         Cell::from(\"Row\\n41\"),\n///         Cell::from(\"Row\\n42\"),\n///         Cell::from(\"Row\\n43\"),\n///     ]).height(2),\n/// ])\n/// // You can set the style of the entire Table.\n/// .style(Style::default().fg(Color::White))\n/// // It has an optional header, which is simply a Row always visible at the top.\n/// .header(\n///     Row::new(vec![\"Col1\", \"Col2\", \"Col3\"])\n///         .style(Style::default().fg(Color::Yellow))\n///         // If you want some space between the header and the rest of the rows, you can always\n///         // specify some margin at the bottom.\n///         .bottom_margin(1)\n/// )\n/// // As any other widget, a Table can be wrapped in a Block.\n/// .block(Block::default().title(\"Table\"))\n/// // Columns widths are constrained in the same way as Layout...\n/// .widths(&[Constraint::Length(5), Constraint::Length(5), Constraint::Length(10)])\n/// // ...and they can be separated by a fixed spacing.\n/// .column_spacing(1)\n/// // If you wish to highlight a row in any specific way when it is selected...\n/// .highlight_style(Style::default().add_modifier(Modifier::BOLD))\n/// // ...and potentially show a symbol in front of the selection.\n/// .highlight_symbol(\">>\");\n/// ```\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct Table<'a> {\n    /// A block to wrap the widget in\n    block: Option<Block<'a>>,\n    /// Base style for the widget\n    style: Style,\n    /// Width constraints for each column\n    widths: &'a [Constraint],\n    /// Space between each column\n    column_spacing: u16,\n    /// Style used to render the selected row\n    highlight_style: Style,\n    /// Symbol in front of the selected rom\n    highlight_symbol: Option<&'a str>,\n    /// Optional header\n    header: Option<Row<'a>>,\n    /// Data to display in each row\n    rows: Vec<Row<'a>>,\n}\n\nimpl<'a> Table<'a> {\n    pub fn new<T>(rows: T) -> Self\n    where\n        T: IntoIterator<Item = Row<'a>>,\n    {\n        Self {\n            block: None,\n            style: Style::default(),\n            widths: &[],\n            column_spacing: 1,\n            highlight_style: Style::default(),\n            highlight_symbol: None,\n            header: None,\n            rows: rows.into_iter().collect(),\n        }\n    }\n\n    pub fn block(mut self, block: Block<'a>) -> Self {\n        self.block = Some(block);\n        self\n    }\n\n    pub fn header(mut self, header: Row<'a>) -> Self {\n        self.header = Some(header);\n        self\n    }\n\n    pub fn widths(mut self, widths: &'a [Constraint]) -> Self {\n        let between_0_and_100 = |&w| match w {\n            Constraint::Percentage(p) => p <= 100,\n            _ => true,\n        };\n        assert!(\n            widths.iter().all(between_0_and_100),\n            \"Percentages should be between 0 and 100 inclusively.\"\n        );\n        self.widths = widths;\n        self\n    }\n\n    pub fn style(mut self, style: Style) -> Self {\n        self.style = style;\n        self\n    }\n\n    pub fn highlight_symbol(mut self, highlight_symbol: &'a str) -> Self {\n        self.highlight_symbol = Some(highlight_symbol);\n        self\n    }\n\n    pub fn highlight_style(mut self, highlight_style: Style) -> Self {\n        self.highlight_style = highlight_style;\n        self\n    }\n\n    pub fn column_spacing(mut self, spacing: u16) -> Self {\n        self.column_spacing = spacing;\n        self\n    }\n\n    fn get_columns_widths(&self, max_width: u16, has_selection: bool) -> Vec<u16> {\n        let mut constraints = Vec::with_capacity(self.widths.len() * 2 + 1);\n        if has_selection {\n            let highlight_symbol_width =\n                self.highlight_symbol.map(|s| s.width() as u16).unwrap_or(0);\n            constraints.push(Constraint::Length(highlight_symbol_width));\n        }\n        for constraint in self.widths {\n            constraints.push(*constraint);\n            constraints.push(Constraint::Length(self.column_spacing));\n        }\n        if !self.widths.is_empty() {\n            constraints.pop();\n        }\n        let mut chunks = Layout::default()\n            .direction(Direction::Horizontal)\n            .constraints(constraints)\n            .expand_to_fill(false)\n            .split(Rect {\n                x: 0,\n                y: 0,\n                width: max_width,\n                height: 1,\n            });\n        if has_selection {\n            chunks.remove(0);\n        }\n        chunks.iter().step_by(2).map(|c| c.width).collect()\n    }\n\n    fn get_row_bounds(\n        &self,\n        selected: Option<usize>,\n        offset: usize,\n        max_height: u16,\n    ) -> (usize, usize) {\n        let offset = offset.min(self.rows.len().saturating_sub(1));\n        let mut start = offset;\n        let mut end = offset;\n        let mut height = 0;\n        for item in self.rows.iter().skip(offset) {\n            if height + item.height > max_height {\n                break;\n            }\n            height += item.total_height();\n            end += 1;\n        }\n\n        let selected = selected.unwrap_or(0).min(self.rows.len() - 1);\n        while selected >= end {\n            height = height.saturating_add(self.rows[end].total_height());\n            end += 1;\n            while height > max_height {\n                height = height.saturating_sub(self.rows[start].total_height());\n                start += 1;\n            }\n        }\n        while selected < start {\n            start -= 1;\n            height = height.saturating_add(self.rows[start].total_height());\n            while height > max_height {\n                end -= 1;\n                height = height.saturating_sub(self.rows[end].total_height());\n            }\n        }\n        (start, end)\n    }\n}\n\n#[derive(Debug, Clone, Default)]\npub struct TableState {\n    offset: usize,\n    selected: Option<usize>,\n}\n\nimpl TableState {\n    pub fn selected(&self) -> Option<usize> {\n        self.selected\n    }\n\n    pub fn select(&mut self, index: Option<usize>) {\n        self.selected = index;\n        if index.is_none() {\n            self.offset = 0;\n        }\n    }\n}\n\nimpl<'a> StatefulWidget for Table<'a> {\n    type State = TableState;\n\n    fn render(mut self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {\n        if area.area() == 0 {\n            return;\n        }\n        buf.set_style(area, self.style);\n        let table_area = match self.block.take() {\n            Some(b) => {\n                let inner_area = b.inner(area);\n                b.render(area, buf);\n                inner_area\n            }\n            None => area,\n        };\n\n        let has_selection = state.selected.is_some();\n        let columns_widths = self.get_columns_widths(table_area.width, has_selection);\n        let highlight_symbol = self.highlight_symbol.unwrap_or(\"\");\n        let blank_symbol = \" \".repeat(highlight_symbol.width());\n        let mut current_height = 0;\n        let mut rows_height = table_area.height;\n\n        // Draw header\n        if let Some(ref header) = self.header {\n            let max_header_height = table_area.height.min(header.total_height());\n            buf.set_style(\n                Rect {\n                    x: table_area.left(),\n                    y: table_area.top(),\n                    width: table_area.width,\n                    height: table_area.height.min(header.height),\n                },\n                header.style,\n            );\n            let mut col = table_area.left();\n            if has_selection {\n                col += (highlight_symbol.width() as u16).min(table_area.width);\n            }\n            for (width, cell) in columns_widths.iter().zip(header.cells.iter()) {\n                render_cell(\n                    buf,\n                    cell,\n                    Rect {\n                        x: col,\n                        y: table_area.top(),\n                        width: *width,\n                        height: max_header_height,\n                    },\n                );\n                col += *width + self.column_spacing;\n            }\n            current_height += max_header_height;\n            rows_height = rows_height.saturating_sub(max_header_height);\n        }\n\n        // Draw rows\n        if self.rows.is_empty() {\n            return;\n        }\n        let (start, end) = self.get_row_bounds(state.selected, state.offset, rows_height);\n        state.offset = start;\n        for (i, table_row) in self\n            .rows\n            .iter_mut()\n            .enumerate()\n            .skip(state.offset)\n            .take(end - start)\n        {\n            let (row, col) = (table_area.top() + current_height, table_area.left());\n            current_height += table_row.total_height();\n            let table_row_area = Rect {\n                x: col,\n                y: row,\n                width: table_area.width,\n                height: table_row.height,\n            };\n            buf.set_style(table_row_area, table_row.style);\n            let is_selected = state.selected.map(|s| s == i).unwrap_or(false);\n            let table_row_start_col = if has_selection {\n                let symbol = if is_selected {\n                    highlight_symbol\n                } else {\n                    &blank_symbol\n                };\n                let (col, _) =\n                    buf.set_stringn(col, row, symbol, table_area.width as usize, table_row.style);\n                col\n            } else {\n                col\n            };\n            let mut col = table_row_start_col;\n            for (width, cell) in columns_widths.iter().zip(table_row.cells.iter()) {\n                render_cell(\n                    buf,\n                    cell,\n                    Rect {\n                        x: col,\n                        y: row,\n                        width: *width,\n                        height: table_row.height,\n                    },\n                );\n                col += *width + self.column_spacing;\n            }\n            if is_selected {\n                buf.set_style(table_row_area, self.highlight_style);\n            }\n        }\n    }\n}\n\nfn render_cell(buf: &mut Buffer, cell: &Cell, area: Rect) {\n    buf.set_style(area, cell.style);\n    for (i, spans) in cell.content.lines.iter().enumerate() {\n        if i as u16 >= area.height {\n            break;\n        }\n        buf.set_spans(area.x, area.y + i as u16, spans, area.width);\n    }\n}\n\nimpl<'a> Widget for Table<'a> {\n    fn render(self, area: Rect, buf: &mut Buffer) {\n        let mut state = TableState::default();\n        StatefulWidget::render(self, area, buf, &mut state);\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    #[should_panic]\n    fn table_invalid_percentages() {\n        Table::new(vec![]).widths(&[Constraint::Percentage(110)]);\n    }\n}\n"
  },
  {
    "path": "src/widgets/tabs.rs",
    "content": "use crate::{\n    buffer::Buffer,\n    layout::Rect,\n    style::Style,\n    symbols,\n    text::{Span, Spans},\n    widgets::{Block, Widget},\n};\n\n/// A widget to display available tabs in a multiple panels context.\n///\n/// # Examples\n///\n/// ```\n/// # use tui::widgets::{Block, Borders, Tabs};\n/// # use tui::style::{Style, Color};\n/// # use tui::text::{Spans};\n/// # use tui::symbols::{DOT};\n/// let titles = [\"Tab1\", \"Tab2\", \"Tab3\", \"Tab4\"].iter().cloned().map(Spans::from).collect();\n/// Tabs::new(titles)\n///     .block(Block::default().title(\"Tabs\").borders(Borders::ALL))\n///     .style(Style::default().fg(Color::White))\n///     .highlight_style(Style::default().fg(Color::Yellow))\n///     .divider(DOT);\n/// ```\n#[derive(Debug, Clone)]\npub struct Tabs<'a> {\n    /// A block to wrap this widget in if necessary\n    block: Option<Block<'a>>,\n    /// One title for each tab\n    titles: Vec<Spans<'a>>,\n    /// The index of the selected tabs\n    selected: usize,\n    /// The style used to draw the text\n    style: Style,\n    /// Style to apply to the selected item\n    highlight_style: Style,\n    /// Tab divider\n    divider: Span<'a>,\n}\n\nimpl<'a> Tabs<'a> {\n    pub fn new(titles: Vec<Spans<'a>>) -> Tabs<'a> {\n        Tabs {\n            block: None,\n            titles,\n            selected: 0,\n            style: Default::default(),\n            highlight_style: Default::default(),\n            divider: Span::raw(symbols::line::VERTICAL),\n        }\n    }\n\n    pub fn block(mut self, block: Block<'a>) -> Tabs<'a> {\n        self.block = Some(block);\n        self\n    }\n\n    pub fn select(mut self, selected: usize) -> Tabs<'a> {\n        self.selected = selected;\n        self\n    }\n\n    pub fn style(mut self, style: Style) -> Tabs<'a> {\n        self.style = style;\n        self\n    }\n\n    pub fn highlight_style(mut self, style: Style) -> Tabs<'a> {\n        self.highlight_style = style;\n        self\n    }\n\n    pub fn divider<T>(mut self, divider: T) -> Tabs<'a>\n    where\n        T: Into<Span<'a>>,\n    {\n        self.divider = divider.into();\n        self\n    }\n}\n\nimpl<'a> Widget for Tabs<'a> {\n    fn render(mut self, area: Rect, buf: &mut Buffer) {\n        buf.set_style(area, self.style);\n        let tabs_area = match self.block.take() {\n            Some(b) => {\n                let inner_area = b.inner(area);\n                b.render(area, buf);\n                inner_area\n            }\n            None => area,\n        };\n\n        if tabs_area.height < 1 {\n            return;\n        }\n\n        let mut x = tabs_area.left();\n        let titles_length = self.titles.len();\n        for (i, title) in self.titles.into_iter().enumerate() {\n            let last_title = titles_length - 1 == i;\n            x = x.saturating_add(1);\n            let remaining_width = tabs_area.right().saturating_sub(x);\n            if remaining_width == 0 {\n                break;\n            }\n            let pos = buf.set_spans(x, tabs_area.top(), &title, remaining_width);\n            if i == self.selected {\n                buf.set_style(\n                    Rect {\n                        x,\n                        y: tabs_area.top(),\n                        width: pos.0.saturating_sub(x),\n                        height: 1,\n                    },\n                    self.highlight_style,\n                );\n            }\n            x = pos.0.saturating_add(1);\n            let remaining_width = tabs_area.right().saturating_sub(x);\n            if remaining_width == 0 || last_title {\n                break;\n            }\n            let pos = buf.set_span(x, tabs_area.top(), &self.divider, remaining_width);\n            x = pos.0;\n        }\n    }\n}\n"
  },
  {
    "path": "tests/backend_termion.rs",
    "content": "#[cfg(feature = \"termion\")]\n#[test]\nfn backend_termion_should_only_write_diffs() -> Result<(), Box<dyn std::error::Error>> {\n    use std::{fmt::Write, io::Cursor};\n\n    let mut bytes = Vec::new();\n    let mut stdout = Cursor::new(&mut bytes);\n    {\n        use tui::{\n            backend::TermionBackend, layout::Rect, widgets::Paragraph, Terminal, TerminalOptions,\n            Viewport,\n        };\n        let backend = TermionBackend::new(&mut stdout);\n        let area = Rect::new(0, 0, 3, 1);\n        let mut terminal = Terminal::with_options(\n            backend,\n            TerminalOptions {\n                viewport: Viewport::fixed(area),\n            },\n        )?;\n        terminal.draw(|f| {\n            f.render_widget(Paragraph::new(\"a\"), area);\n        })?;\n        terminal.draw(|f| {\n            f.render_widget(Paragraph::new(\"ab\"), area);\n        })?;\n        terminal.draw(|f| {\n            f.render_widget(Paragraph::new(\"abc\"), area);\n        })?;\n    }\n\n    let expected = {\n        use termion::{color, cursor, style};\n        let mut s = String::new();\n        // First draw\n        write!(s, \"{}\", cursor::Goto(1, 1))?;\n        s.push('a');\n        write!(s, \"{}\", color::Fg(color::Reset))?;\n        write!(s, \"{}\", color::Bg(color::Reset))?;\n        write!(s, \"{}\", style::Reset)?;\n        write!(s, \"{}\", cursor::Hide)?;\n        // Second draw\n        write!(s, \"{}\", cursor::Goto(2, 1))?;\n        s.push('b');\n        write!(s, \"{}\", color::Fg(color::Reset))?;\n        write!(s, \"{}\", color::Bg(color::Reset))?;\n        write!(s, \"{}\", style::Reset)?;\n        write!(s, \"{}\", cursor::Hide)?;\n        // Third draw\n        write!(s, \"{}\", cursor::Goto(3, 1))?;\n        s.push('c');\n        write!(s, \"{}\", color::Fg(color::Reset))?;\n        write!(s, \"{}\", color::Bg(color::Reset))?;\n        write!(s, \"{}\", style::Reset)?;\n        write!(s, \"{}\", cursor::Hide)?;\n        // Terminal drop\n        write!(s, \"{}\", cursor::Show)?;\n        s\n    };\n    assert_eq!(std::str::from_utf8(&bytes)?, expected);\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/terminal.rs",
    "content": "use std::error::Error;\nuse tui::{\n    backend::{Backend, TestBackend},\n    layout::Rect,\n    widgets::Paragraph,\n    Terminal,\n};\n\n#[test]\nfn terminal_buffer_size_should_be_limited() {\n    let backend = TestBackend::new(400, 400);\n    let terminal = Terminal::new(backend).unwrap();\n    let size = terminal.backend().size().unwrap();\n    assert_eq!(size.width, 255);\n    assert_eq!(size.height, 255);\n}\n\n#[test]\nfn terminal_draw_returns_the_completed_frame() -> Result<(), Box<dyn Error>> {\n    let backend = TestBackend::new(10, 10);\n    let mut terminal = Terminal::new(backend)?;\n    let frame = terminal.draw(|f| {\n        let paragrah = Paragraph::new(\"Test\");\n        f.render_widget(paragrah, f.size());\n    })?;\n    assert_eq!(frame.buffer.get(0, 0).symbol, \"T\");\n    assert_eq!(frame.area, Rect::new(0, 0, 10, 10));\n    terminal.backend_mut().resize(8, 8);\n    let frame = terminal.draw(|f| {\n        let paragrah = Paragraph::new(\"test\");\n        f.render_widget(paragrah, f.size());\n    })?;\n    assert_eq!(frame.buffer.get(0, 0).symbol, \"t\");\n    assert_eq!(frame.area, Rect::new(0, 0, 8, 8));\n    Ok(())\n}\n"
  },
  {
    "path": "tests/widgets_barchart.rs",
    "content": "use tui::backend::TestBackend;\nuse tui::buffer::Buffer;\nuse tui::widgets::{BarChart, Block, Borders};\nuse tui::Terminal;\n\n#[test]\nfn widgets_barchart_not_full_below_max_value() {\n    let test_case = |expected| {\n        let backend = TestBackend::new(30, 10);\n        let mut terminal = Terminal::new(backend).unwrap();\n\n        terminal\n            .draw(|f| {\n                let size = f.size();\n                let barchart = BarChart::default()\n                    .block(Block::default().borders(Borders::ALL))\n                    .data(&[(\"empty\", 0), (\"half\", 50), (\"almost\", 99), (\"full\", 100)])\n                    .max(100)\n                    .bar_width(7)\n                    .bar_gap(0);\n                f.render_widget(barchart, size);\n            })\n            .unwrap();\n        terminal.backend().assert_buffer(&expected);\n    };\n\n    // check that bars fill up correctly up to max value\n    test_case(Buffer::with_lines(vec![\n        \"┌────────────────────────────┐\",\n        \"│              ▇▇▇▇▇▇▇███████│\",\n        \"│              ██████████████│\",\n        \"│              ██████████████│\",\n        \"│       ▄▄▄▄▄▄▄██████████████│\",\n        \"│       █████████████████████│\",\n        \"│       █████████████████████│\",\n        \"│       ██50█████99█████100██│\",\n        \"│empty  half   almost full   │\",\n        \"└────────────────────────────┘\",\n    ]));\n}\n"
  },
  {
    "path": "tests/widgets_block.rs",
    "content": "use tui::{\n    backend::TestBackend,\n    buffer::Buffer,\n    layout::{Alignment, Rect},\n    style::{Color, Style},\n    text::Span,\n    widgets::{Block, Borders},\n    Terminal,\n};\n\n#[test]\nfn widgets_block_renders() {\n    let backend = TestBackend::new(10, 10);\n    let mut terminal = Terminal::new(backend).unwrap();\n    terminal\n        .draw(|f| {\n            let block = Block::default()\n                .title(Span::styled(\"Title\", Style::default().fg(Color::LightBlue)))\n                .borders(Borders::ALL);\n            f.render_widget(\n                block,\n                Rect {\n                    x: 0,\n                    y: 0,\n                    width: 8,\n                    height: 8,\n                },\n            );\n        })\n        .unwrap();\n    let mut expected = Buffer::with_lines(vec![\n        \"┌Title─┐  \",\n        \"│      │  \",\n        \"│      │  \",\n        \"│      │  \",\n        \"│      │  \",\n        \"│      │  \",\n        \"│      │  \",\n        \"└──────┘  \",\n        \"          \",\n        \"          \",\n    ]);\n    for x in 1..=5 {\n        expected.get_mut(x, 0).set_fg(Color::LightBlue);\n    }\n    terminal.backend().assert_buffer(&expected);\n}\n\n#[test]\nfn widgets_block_renders_on_small_areas() {\n    let test_case = |block, area: Rect, expected| {\n        let backend = TestBackend::new(area.width, area.height);\n        let mut terminal = Terminal::new(backend).unwrap();\n        terminal\n            .draw(|f| {\n                f.render_widget(block, area);\n            })\n            .unwrap();\n        terminal.backend().assert_buffer(&expected);\n    };\n\n    let one_cell_test_cases = [\n        (Borders::NONE, \"T\"),\n        (Borders::LEFT, \"│\"),\n        (Borders::TOP, \"T\"),\n        (Borders::RIGHT, \"│\"),\n        (Borders::BOTTOM, \"T\"),\n        (Borders::ALL, \"┌\"),\n    ];\n    for (borders, symbol) in one_cell_test_cases.iter().cloned() {\n        test_case(\n            Block::default().title(\"Test\").borders(borders),\n            Rect {\n                x: 0,\n                y: 0,\n                width: 0,\n                height: 0,\n            },\n            Buffer::empty(Rect {\n                x: 0,\n                y: 0,\n                width: 0,\n                height: 0,\n            }),\n        );\n        test_case(\n            Block::default().title(\"Test\").borders(borders),\n            Rect {\n                x: 0,\n                y: 0,\n                width: 1,\n                height: 0,\n            },\n            Buffer::empty(Rect {\n                x: 0,\n                y: 0,\n                width: 1,\n                height: 0,\n            }),\n        );\n        test_case(\n            Block::default().title(\"Test\").borders(borders),\n            Rect {\n                x: 0,\n                y: 0,\n                width: 0,\n                height: 1,\n            },\n            Buffer::empty(Rect {\n                x: 0,\n                y: 0,\n                width: 0,\n                height: 1,\n            }),\n        );\n        test_case(\n            Block::default().title(\"Test\").borders(borders),\n            Rect {\n                x: 0,\n                y: 0,\n                width: 1,\n                height: 1,\n            },\n            Buffer::with_lines(vec![symbol]),\n        );\n    }\n    test_case(\n        Block::default().title(\"Test\").borders(Borders::LEFT),\n        Rect {\n            x: 0,\n            y: 0,\n            width: 4,\n            height: 1,\n        },\n        Buffer::with_lines(vec![\"│Tes\"]),\n    );\n    test_case(\n        Block::default().title(\"Test\").borders(Borders::RIGHT),\n        Rect {\n            x: 0,\n            y: 0,\n            width: 4,\n            height: 1,\n        },\n        Buffer::with_lines(vec![\"Tes│\"]),\n    );\n    test_case(\n        Block::default().title(\"Test\").borders(Borders::RIGHT),\n        Rect {\n            x: 0,\n            y: 0,\n            width: 4,\n            height: 1,\n        },\n        Buffer::with_lines(vec![\"Tes│\"]),\n    );\n    test_case(\n        Block::default()\n            .title(\"Test\")\n            .borders(Borders::LEFT | Borders::RIGHT),\n        Rect {\n            x: 0,\n            y: 0,\n            width: 4,\n            height: 1,\n        },\n        Buffer::with_lines(vec![\"│Te│\"]),\n    );\n    test_case(\n        Block::default().title(\"Test\").borders(Borders::TOP),\n        Rect {\n            x: 0,\n            y: 0,\n            width: 4,\n            height: 1,\n        },\n        Buffer::with_lines(vec![\"Test\"]),\n    );\n    test_case(\n        Block::default().title(\"Test\").borders(Borders::TOP),\n        Rect {\n            x: 0,\n            y: 0,\n            width: 5,\n            height: 1,\n        },\n        Buffer::with_lines(vec![\"Test─\"]),\n    );\n    test_case(\n        Block::default()\n            .title(\"Test\")\n            .borders(Borders::LEFT | Borders::TOP),\n        Rect {\n            x: 0,\n            y: 0,\n            width: 5,\n            height: 1,\n        },\n        Buffer::with_lines(vec![\"┌Test\"]),\n    );\n    test_case(\n        Block::default()\n            .title(\"Test\")\n            .borders(Borders::LEFT | Borders::TOP),\n        Rect {\n            x: 0,\n            y: 0,\n            width: 6,\n            height: 1,\n        },\n        Buffer::with_lines(vec![\"┌Test─\"]),\n    );\n}\n\n#[test]\nfn widgets_block_title_alignment() {\n    let test_case = |alignment, borders, expected| {\n        let backend = TestBackend::new(15, 2);\n        let mut terminal = Terminal::new(backend).unwrap();\n\n        let block = Block::default()\n            .title(Span::styled(\"Title\", Style::default()))\n            .title_alignment(alignment)\n            .borders(borders);\n\n        let area = Rect {\n            x: 1,\n            y: 0,\n            width: 13,\n            height: 2,\n        };\n\n        terminal\n            .draw(|f| {\n                f.render_widget(block, area);\n            })\n            .unwrap();\n\n        terminal.backend().assert_buffer(&expected);\n    };\n\n    // title top-left with all borders\n    test_case(\n        Alignment::Left,\n        Borders::ALL,\n        Buffer::with_lines(vec![\" ┌Title──────┐ \", \" └───────────┘ \"]),\n    );\n\n    // title top-left without top border\n    test_case(\n        Alignment::Left,\n        Borders::LEFT | Borders::BOTTOM | Borders::RIGHT,\n        Buffer::with_lines(vec![\" │Title      │ \", \" └───────────┘ \"]),\n    );\n\n    // title top-left with no left border\n    test_case(\n        Alignment::Left,\n        Borders::TOP | Borders::RIGHT | Borders::BOTTOM,\n        Buffer::with_lines(vec![\" Title───────┐ \", \" ────────────┘ \"]),\n    );\n\n    // title top-left without right border\n    test_case(\n        Alignment::Left,\n        Borders::LEFT | Borders::TOP | Borders::BOTTOM,\n        Buffer::with_lines(vec![\" ┌Title─────── \", \" └──────────── \"]),\n    );\n\n    // title top-left without borders\n    test_case(\n        Alignment::Left,\n        Borders::NONE,\n        Buffer::with_lines(vec![\" Title         \", \"               \"]),\n    );\n\n    // title center with all borders\n    test_case(\n        Alignment::Center,\n        Borders::ALL,\n        Buffer::with_lines(vec![\" ┌───Title───┐ \", \" └───────────┘ \"]),\n    );\n\n    // title center without top border\n    test_case(\n        Alignment::Center,\n        Borders::LEFT | Borders::BOTTOM | Borders::RIGHT,\n        Buffer::with_lines(vec![\" │   Title   │ \", \" └───────────┘ \"]),\n    );\n\n    // title center with no left border\n    test_case(\n        Alignment::Center,\n        Borders::TOP | Borders::RIGHT | Borders::BOTTOM,\n        Buffer::with_lines(vec![\" ────Title───┐ \", \" ────────────┘ \"]),\n    );\n\n    // title center without right border\n    test_case(\n        Alignment::Center,\n        Borders::LEFT | Borders::TOP | Borders::BOTTOM,\n        Buffer::with_lines(vec![\" ┌───Title──── \", \" └──────────── \"]),\n    );\n\n    // title center without borders\n    test_case(\n        Alignment::Center,\n        Borders::NONE,\n        Buffer::with_lines(vec![\"     Title     \", \"               \"]),\n    );\n\n    // title top-right with all borders\n    test_case(\n        Alignment::Right,\n        Borders::ALL,\n        Buffer::with_lines(vec![\" ┌──────Title┐ \", \" └───────────┘ \"]),\n    );\n\n    // title top-right without top border\n    test_case(\n        Alignment::Right,\n        Borders::LEFT | Borders::BOTTOM | Borders::RIGHT,\n        Buffer::with_lines(vec![\" │      Title│ \", \" └───────────┘ \"]),\n    );\n\n    // title top-right with no left border\n    test_case(\n        Alignment::Right,\n        Borders::TOP | Borders::RIGHT | Borders::BOTTOM,\n        Buffer::with_lines(vec![\" ───────Title┐ \", \" ────────────┘ \"]),\n    );\n\n    // title top-right without right border\n    test_case(\n        Alignment::Right,\n        Borders::LEFT | Borders::TOP | Borders::BOTTOM,\n        Buffer::with_lines(vec![\" ┌───────Title \", \" └──────────── \"]),\n    );\n\n    // title top-right without borders\n    test_case(\n        Alignment::Right,\n        Borders::NONE,\n        Buffer::with_lines(vec![\"         Title \", \"               \"]),\n    );\n}\n"
  },
  {
    "path": "tests/widgets_canvas.rs",
    "content": "use tui::{\n    backend::TestBackend,\n    buffer::Buffer,\n    style::{Color, Style},\n    text::Span,\n    widgets::canvas::Canvas,\n    Terminal,\n};\n\n#[test]\nfn widgets_canvas_draw_labels() {\n    let backend = TestBackend::new(5, 5);\n    let mut terminal = Terminal::new(backend).unwrap();\n    terminal\n        .draw(|f| {\n            let label = String::from(\"test\");\n            let canvas = Canvas::default()\n                .background_color(Color::Yellow)\n                .x_bounds([0.0, 5.0])\n                .y_bounds([0.0, 5.0])\n                .paint(|ctx| {\n                    ctx.print(\n                        0.0,\n                        0.0,\n                        Span::styled(label.clone(), Style::default().fg(Color::Blue)),\n                    );\n                });\n            f.render_widget(canvas, f.size());\n        })\n        .unwrap();\n\n    let mut expected = Buffer::with_lines(vec![\"    \", \"    \", \"     \", \"     \", \"test \"]);\n    for row in 0..5 {\n        for col in 0..5 {\n            expected.get_mut(col, row).set_bg(Color::Yellow);\n        }\n    }\n    for col in 0..4 {\n        expected.get_mut(col, 4).set_fg(Color::Blue);\n    }\n    terminal.backend().assert_buffer(&expected)\n}\n"
  },
  {
    "path": "tests/widgets_chart.rs",
    "content": "use tui::layout::Alignment;\nuse tui::{\n    backend::TestBackend,\n    buffer::Buffer,\n    layout::Rect,\n    style::{Color, Style},\n    symbols,\n    text::Span,\n    widgets::{Axis, Block, Borders, Chart, Dataset, GraphType::Line},\n    Terminal,\n};\n\nfn create_labels<'a>(labels: &'a [&'a str]) -> Vec<Span<'a>> {\n    labels.iter().map(|l| Span::from(*l)).collect()\n}\n\nfn axis_test_case<S>(width: u16, height: u16, x_axis: Axis, y_axis: Axis, lines: Vec<S>)\nwhere\n    S: AsRef<str>,\n{\n    let backend = TestBackend::new(width, height);\n    let mut terminal = Terminal::new(backend).unwrap();\n    terminal\n        .draw(|f| {\n            let chart = Chart::new(vec![]).x_axis(x_axis).y_axis(y_axis);\n            f.render_widget(chart, f.size());\n        })\n        .unwrap();\n    let expected = Buffer::with_lines(lines);\n    terminal.backend().assert_buffer(&expected);\n}\n\n#[test]\nfn widgets_chart_can_render_on_small_areas() {\n    let test_case = |width, height| {\n        let backend = TestBackend::new(width, height);\n        let mut terminal = Terminal::new(backend).unwrap();\n        terminal\n            .draw(|f| {\n                let datasets = vec![Dataset::default()\n                    .marker(symbols::Marker::Braille)\n                    .style(Style::default().fg(Color::Magenta))\n                    .data(&[(0.0, 0.0)])];\n                let chart = Chart::new(datasets)\n                    .block(Block::default().title(\"Plot\").borders(Borders::ALL))\n                    .x_axis(\n                        Axis::default()\n                            .bounds([0.0, 0.0])\n                            .labels(create_labels(&[\"0.0\", \"1.0\"])),\n                    )\n                    .y_axis(\n                        Axis::default()\n                            .bounds([0.0, 0.0])\n                            .labels(create_labels(&[\"0.0\", \"1.0\"])),\n                    );\n                f.render_widget(chart, f.size());\n            })\n            .unwrap();\n    };\n    test_case(0, 0);\n    test_case(0, 1);\n    test_case(1, 0);\n    test_case(1, 1);\n    test_case(2, 2);\n}\n\n#[test]\nfn widgets_chart_handles_long_labels() {\n    let test_case = |x_labels, y_labels, x_alignment, lines| {\n        let mut x_axis = Axis::default().bounds([0.0, 1.0]);\n        if let Some((left_label, right_label)) = x_labels {\n            x_axis = x_axis\n                .labels(vec![Span::from(left_label), Span::from(right_label)])\n                .labels_alignment(x_alignment);\n        }\n\n        let mut y_axis = Axis::default().bounds([0.0, 1.0]);\n        if let Some((left_label, right_label)) = y_labels {\n            y_axis = y_axis.labels(vec![Span::from(left_label), Span::from(right_label)]);\n        }\n\n        axis_test_case(10, 5, x_axis, y_axis, lines);\n    };\n\n    test_case(\n        Some((\"AAAA\", \"B\")),\n        None,\n        Alignment::Left,\n        vec![\n            \"          \",\n            \"          \",\n            \"          \",\n            \"   ───────\",\n            \"AAA      B\",\n        ],\n    );\n    test_case(\n        Some((\"A\", \"BBBB\")),\n        None,\n        Alignment::Left,\n        vec![\n            \"          \",\n            \"          \",\n            \"          \",\n            \" ─────────\",\n            \"A     BBBB\",\n        ],\n    );\n    test_case(\n        Some((\"AAAAAAAAAAA\", \"B\")),\n        None,\n        Alignment::Left,\n        vec![\n            \"          \",\n            \"          \",\n            \"          \",\n            \"   ───────\",\n            \"AAA      B\",\n        ],\n    );\n    test_case(\n        Some((\"A\", \"B\")),\n        Some((\"CCCCCCC\", \"D\")),\n        Alignment::Left,\n        vec![\n            \"D  │      \",\n            \"   │      \",\n            \"CCC│      \",\n            \"   └──────\",\n            \"   A     B\",\n        ],\n    );\n    test_case(\n        Some((\"AAAAAAAAAA\", \"B\")),\n        Some((\"C\", \"D\")),\n        Alignment::Center,\n        vec![\n            \"D  │      \",\n            \"   │      \",\n            \"C  │      \",\n            \"   └──────\",\n            \"AAAAAAA  B\",\n        ],\n    );\n    test_case(\n        Some((\"AAAAAAA\", \"B\")),\n        Some((\"C\", \"D\")),\n        Alignment::Right,\n        vec![\n            \"D│        \",\n            \" │        \",\n            \"C│        \",\n            \" └────────\",\n            \" AAAAA   B\",\n        ],\n    );\n    test_case(\n        Some((\"AAAAAAA\", \"BBBBBBB\")),\n        Some((\"C\", \"D\")),\n        Alignment::Right,\n        vec![\n            \"D│        \",\n            \" │        \",\n            \"C│        \",\n            \" └────────\",\n            \" AAAAABBBB\",\n        ],\n    );\n}\n\n#[test]\nfn widgets_chart_handles_x_axis_labels_alignments() {\n    let test_case = |y_alignment, lines| {\n        let x_axis = Axis::default()\n            .labels(vec![Span::from(\"AAAA\"), Span::from(\"B\"), Span::from(\"C\")])\n            .labels_alignment(y_alignment);\n\n        let y_axis = Axis::default();\n\n        axis_test_case(10, 5, x_axis, y_axis, lines);\n    };\n\n    test_case(\n        Alignment::Left,\n        vec![\n            \"          \",\n            \"          \",\n            \"          \",\n            \"   ───────\",\n            \"AAA   B  C\",\n        ],\n    );\n    test_case(\n        Alignment::Center,\n        vec![\n            \"          \",\n            \"          \",\n            \"          \",\n            \"  ────────\",\n            \"AAAA B   C\",\n        ],\n    );\n    test_case(\n        Alignment::Right,\n        vec![\n            \"          \",\n            \"          \",\n            \"          \",\n            \"──────────\",\n            \"AAA  B   C\",\n        ],\n    );\n}\n\n#[test]\nfn widgets_chart_handles_y_axis_labels_alignments() {\n    let test_case = |y_alignment, lines| {\n        let x_axis = Axis::default().labels(create_labels(&[\"AAAAA\", \"B\"]));\n\n        let y_axis = Axis::default()\n            .labels(create_labels(&[\"C\", \"D\"]))\n            .labels_alignment(y_alignment);\n\n        axis_test_case(20, 5, x_axis, y_axis, lines);\n    };\n    test_case(\n        Alignment::Left,\n        vec![\n            \"D   │               \",\n            \"    │               \",\n            \"C   │               \",\n            \"    └───────────────\",\n            \"AAAAA              B\",\n        ],\n    );\n    test_case(\n        Alignment::Center,\n        vec![\n            \"  D │               \",\n            \"    │               \",\n            \"  C │               \",\n            \"    └───────────────\",\n            \"AAAAA              B\",\n        ],\n    );\n    test_case(\n        Alignment::Right,\n        vec![\n            \"   D│               \",\n            \"    │               \",\n            \"   C│               \",\n            \"    └───────────────\",\n            \"AAAAA              B\",\n        ],\n    );\n}\n\n#[test]\nfn widgets_chart_can_have_axis_with_zero_length_bounds() {\n    let backend = TestBackend::new(100, 100);\n    let mut terminal = Terminal::new(backend).unwrap();\n\n    terminal\n        .draw(|f| {\n            let datasets = vec![Dataset::default()\n                .marker(symbols::Marker::Braille)\n                .style(Style::default().fg(Color::Magenta))\n                .data(&[(0.0, 0.0)])];\n            let chart = Chart::new(datasets)\n                .block(Block::default().title(\"Plot\").borders(Borders::ALL))\n                .x_axis(\n                    Axis::default()\n                        .bounds([0.0, 0.0])\n                        .labels(create_labels(&[\"0.0\", \"1.0\"])),\n                )\n                .y_axis(\n                    Axis::default()\n                        .bounds([0.0, 0.0])\n                        .labels(create_labels(&[\"0.0\", \"1.0\"])),\n                );\n            f.render_widget(\n                chart,\n                Rect {\n                    x: 0,\n                    y: 0,\n                    width: 100,\n                    height: 100,\n                },\n            );\n        })\n        .unwrap();\n}\n\n#[test]\nfn widgets_chart_handles_overflows() {\n    let backend = TestBackend::new(80, 30);\n    let mut terminal = Terminal::new(backend).unwrap();\n\n    terminal\n        .draw(|f| {\n            let datasets = vec![Dataset::default()\n                .marker(symbols::Marker::Braille)\n                .style(Style::default().fg(Color::Magenta))\n                .data(&[\n                    (1_588_298_471.0, 1.0),\n                    (1_588_298_473.0, 0.0),\n                    (1_588_298_496.0, 1.0),\n                ])];\n            let chart = Chart::new(datasets)\n                .block(Block::default().title(\"Plot\").borders(Borders::ALL))\n                .x_axis(\n                    Axis::default()\n                        .bounds([1_588_298_471.0, 1_588_992_600.0])\n                        .labels(create_labels(&[\"1588298471.0\", \"1588992600.0\"])),\n                )\n                .y_axis(\n                    Axis::default()\n                        .bounds([0.0, 1.0])\n                        .labels(create_labels(&[\"0.0\", \"1.0\"])),\n                );\n            f.render_widget(\n                chart,\n                Rect {\n                    x: 0,\n                    y: 0,\n                    width: 80,\n                    height: 30,\n                },\n            );\n        })\n        .unwrap();\n}\n\n#[test]\nfn widgets_chart_can_have_empty_datasets() {\n    let backend = TestBackend::new(100, 100);\n    let mut terminal = Terminal::new(backend).unwrap();\n\n    terminal\n        .draw(|f| {\n            let datasets = vec![Dataset::default().data(&[]).graph_type(Line)];\n            let chart = Chart::new(datasets)\n                .block(\n                    Block::default()\n                        .title(\"Empty Dataset With Line\")\n                        .borders(Borders::ALL),\n                )\n                .x_axis(\n                    Axis::default()\n                        .bounds([0.0, 0.0])\n                        .labels(create_labels(&[\"0.0\", \"1.0\"])),\n                )\n                .y_axis(\n                    Axis::default()\n                        .bounds([0.0, 1.0])\n                        .labels(create_labels(&[\"0.0\", \"1.0\"])),\n                );\n            f.render_widget(\n                chart,\n                Rect {\n                    x: 0,\n                    y: 0,\n                    width: 100,\n                    height: 100,\n                },\n            );\n        })\n        .unwrap();\n}\n\n#[test]\nfn widgets_chart_can_have_a_legend() {\n    let backend = TestBackend::new(60, 30);\n    let mut terminal = Terminal::new(backend).unwrap();\n    terminal\n        .draw(|f| {\n            let datasets = vec![\n                Dataset::default()\n                    .name(\"Dataset 1\")\n                    .style(Style::default().fg(Color::Blue))\n                    .data(&[\n                        (0.0, 0.0),\n                        (10.0, 1.0),\n                        (20.0, 2.0),\n                        (30.0, 3.0),\n                        (40.0, 4.0),\n                        (50.0, 5.0),\n                        (60.0, 6.0),\n                        (70.0, 7.0),\n                        (80.0, 8.0),\n                        (90.0, 9.0),\n                        (100.0, 10.0),\n                    ])\n                    .graph_type(Line),\n                Dataset::default()\n                    .name(\"Dataset 2\")\n                    .style(Style::default().fg(Color::Green))\n                    .data(&[\n                        (0.0, 10.0),\n                        (10.0, 9.0),\n                        (20.0, 8.0),\n                        (30.0, 7.0),\n                        (40.0, 6.0),\n                        (50.0, 5.0),\n                        (60.0, 4.0),\n                        (70.0, 3.0),\n                        (80.0, 2.0),\n                        (90.0, 1.0),\n                        (100.0, 0.0),\n                    ])\n                    .graph_type(Line),\n            ];\n            let chart = Chart::new(datasets)\n                .style(Style::default().bg(Color::White))\n                .block(Block::default().title(\"Chart Test\").borders(Borders::ALL))\n                .x_axis(\n                    Axis::default()\n                        .bounds([0.0, 100.0])\n                        .title(Span::styled(\"X Axis\", Style::default().fg(Color::Yellow)))\n                        .labels(create_labels(&[\"0.0\", \"50.0\", \"100.0\"])),\n                )\n                .y_axis(\n                    Axis::default()\n                        .bounds([0.0, 10.0])\n                        .title(\"Y Axis\")\n                        .labels(create_labels(&[\"0.0\", \"5.0\", \"10.0\"])),\n                );\n            f.render_widget(\n                chart,\n                Rect {\n                    x: 0,\n                    y: 0,\n                    width: 60,\n                    height: 30,\n                },\n            );\n        })\n        .unwrap();\n    let mut expected = Buffer::with_lines(vec![\n        \"┌Chart Test────────────────────────────────────────────────┐\",\n        \"│10.0│Y Axis                                    ┌─────────┐│\",\n        \"│    │  ••                                      │Dataset 1││\",\n        \"│    │    ••                                    │Dataset 2││\",\n        \"│    │      ••                                  └─────────┘│\",\n        \"│    │        ••                                ••         │\",\n        \"│    │          ••                            ••           │\",\n        \"│    │            ••                        ••             │\",\n        \"│    │              ••                    ••               │\",\n        \"│    │                ••                ••                 │\",\n        \"│    │                  ••            ••                   │\",\n        \"│    │                    ••        ••                     │\",\n        \"│    │                      •••   ••                       │\",\n        \"│    │                         •••                         │\",\n        \"│5.0 │                        •• ••                        │\",\n        \"│    │                      ••     ••                      │\",\n        \"│    │                   •••         ••                    │\",\n        \"│    │                 ••              ••                  │\",\n        \"│    │               ••                  ••                │\",\n        \"│    │             ••                      ••              │\",\n        \"│    │           ••                          ••            │\",\n        \"│    │         ••                              ••          │\",\n        \"│    │       ••                                  ••        │\",\n        \"│    │     ••                                      •••     │\",\n        \"│    │   ••                                           ••   │\",\n        \"│    │ ••                                               •• │\",\n        \"│0.0 │•                                              X Axis│\",\n        \"│    └─────────────────────────────────────────────────────│\",\n        \"│  0.0                        50.0                    100.0│\",\n        \"└──────────────────────────────────────────────────────────┘\",\n    ]);\n\n    // Set expected backgound color\n    for row in 0..30 {\n        for col in 0..60 {\n            expected.get_mut(col, row).set_bg(Color::White);\n        }\n    }\n\n    // Set expected colors of the first dataset\n    let line1 = vec![\n        (48, 5),\n        (49, 5),\n        (46, 6),\n        (47, 6),\n        (44, 7),\n        (45, 7),\n        (42, 8),\n        (43, 8),\n        (40, 9),\n        (41, 9),\n        (38, 10),\n        (39, 10),\n        (36, 11),\n        (37, 11),\n        (34, 12),\n        (35, 12),\n        (33, 13),\n        (30, 14),\n        (31, 14),\n        (28, 15),\n        (29, 15),\n        (25, 16),\n        (26, 16),\n        (27, 16),\n        (23, 17),\n        (24, 17),\n        (21, 18),\n        (22, 18),\n        (19, 19),\n        (20, 19),\n        (17, 20),\n        (18, 20),\n        (15, 21),\n        (16, 21),\n        (13, 22),\n        (14, 22),\n        (11, 23),\n        (12, 23),\n        (9, 24),\n        (10, 24),\n        (7, 25),\n        (8, 25),\n        (6, 26),\n    ];\n    let legend1 = vec![\n        (49, 2),\n        (50, 2),\n        (51, 2),\n        (52, 2),\n        (53, 2),\n        (54, 2),\n        (55, 2),\n        (56, 2),\n        (57, 2),\n    ];\n    for (col, row) in line1 {\n        expected.get_mut(col, row).set_fg(Color::Blue);\n    }\n    for (col, row) in legend1 {\n        expected.get_mut(col, row).set_fg(Color::Blue);\n    }\n\n    // Set expected colors of the second dataset\n    let line2 = vec![\n        (8, 2),\n        (9, 2),\n        (10, 3),\n        (11, 3),\n        (12, 4),\n        (13, 4),\n        (14, 5),\n        (15, 5),\n        (16, 6),\n        (17, 6),\n        (18, 7),\n        (19, 7),\n        (20, 8),\n        (21, 8),\n        (22, 9),\n        (23, 9),\n        (24, 10),\n        (25, 10),\n        (26, 11),\n        (27, 11),\n        (28, 12),\n        (29, 12),\n        (30, 12),\n        (31, 13),\n        (32, 13),\n        (33, 14),\n        (34, 14),\n        (35, 15),\n        (36, 15),\n        (37, 16),\n        (38, 16),\n        (39, 17),\n        (40, 17),\n        (41, 18),\n        (42, 18),\n        (43, 19),\n        (44, 19),\n        (45, 20),\n        (46, 20),\n        (47, 21),\n        (48, 21),\n        (49, 22),\n        (50, 22),\n        (51, 23),\n        (52, 23),\n        (53, 23),\n        (54, 24),\n        (55, 24),\n        (56, 25),\n        (57, 25),\n    ];\n    let legend2 = vec![\n        (49, 3),\n        (50, 3),\n        (51, 3),\n        (52, 3),\n        (53, 3),\n        (54, 3),\n        (55, 3),\n        (56, 3),\n        (57, 3),\n    ];\n    for (col, row) in line2 {\n        expected.get_mut(col, row).set_fg(Color::Green);\n    }\n    for (col, row) in legend2 {\n        expected.get_mut(col, row).set_fg(Color::Green);\n    }\n\n    // Set expected colors of the x axis\n    let x_axis_title = vec![(53, 26), (54, 26), (55, 26), (56, 26), (57, 26), (58, 26)];\n    for (col, row) in x_axis_title {\n        expected.get_mut(col, row).set_fg(Color::Yellow);\n    }\n\n    terminal.backend().assert_buffer(&expected);\n}\n"
  },
  {
    "path": "tests/widgets_gauge.rs",
    "content": "use tui::{\n    backend::TestBackend,\n    buffer::Buffer,\n    layout::{Constraint, Direction, Layout, Rect},\n    style::{Color, Modifier, Style},\n    symbols,\n    text::Span,\n    widgets::{Block, Borders, Gauge, LineGauge},\n    Terminal,\n};\n\n#[test]\nfn widgets_gauge_renders() {\n    let backend = TestBackend::new(40, 10);\n    let mut terminal = Terminal::new(backend).unwrap();\n    terminal\n        .draw(|f| {\n            let chunks = Layout::default()\n                .direction(Direction::Vertical)\n                .margin(2)\n                .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())\n                .split(f.size());\n\n            let gauge = Gauge::default()\n                .block(Block::default().title(\"Percentage\").borders(Borders::ALL))\n                .gauge_style(Style::default().bg(Color::Blue).fg(Color::Red))\n                .use_unicode(true)\n                .percent(43);\n            f.render_widget(gauge, chunks[0]);\n            let gauge = Gauge::default()\n                .block(Block::default().title(\"Ratio\").borders(Borders::ALL))\n                .gauge_style(Style::default().bg(Color::Blue).fg(Color::Red))\n                .use_unicode(true)\n                .ratio(0.511_313_934_313_1);\n            f.render_widget(gauge, chunks[1]);\n        })\n        .unwrap();\n    let mut expected = Buffer::with_lines(vec![\n        \"                                        \",\n        \"                                        \",\n        \"  ┌Percentage────────────────────────┐  \",\n        \"  │              ▋43%                │  \",\n        \"  └──────────────────────────────────┘  \",\n        \"  ┌Ratio─────────────────────────────┐  \",\n        \"  │               51%                │  \",\n        \"  └──────────────────────────────────┘  \",\n        \"                                        \",\n        \"                                        \",\n    ]);\n\n    for i in 3..17 {\n        expected\n            .get_mut(i, 3)\n            .set_bg(Color::Red)\n            .set_fg(Color::Blue);\n    }\n    for i in 17..37 {\n        expected\n            .get_mut(i, 3)\n            .set_bg(Color::Blue)\n            .set_fg(Color::Red);\n    }\n\n    for i in 3..20 {\n        expected\n            .get_mut(i, 6)\n            .set_bg(Color::Red)\n            .set_fg(Color::Blue);\n    }\n    for i in 20..37 {\n        expected\n            .get_mut(i, 6)\n            .set_bg(Color::Blue)\n            .set_fg(Color::Red);\n    }\n\n    terminal.backend().assert_buffer(&expected);\n}\n\n#[test]\nfn widgets_gauge_renders_no_unicode() {\n    let backend = TestBackend::new(40, 10);\n    let mut terminal = Terminal::new(backend).unwrap();\n\n    terminal\n        .draw(|f| {\n            let chunks = Layout::default()\n                .direction(Direction::Vertical)\n                .margin(2)\n                .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())\n                .split(f.size());\n\n            let gauge = Gauge::default()\n                .block(Block::default().title(\"Percentage\").borders(Borders::ALL))\n                .percent(43)\n                .use_unicode(false);\n            f.render_widget(gauge, chunks[0]);\n            let gauge = Gauge::default()\n                .block(Block::default().title(\"Ratio\").borders(Borders::ALL))\n                .ratio(0.211_313_934_313_1)\n                .use_unicode(false);\n            f.render_widget(gauge, chunks[1]);\n        })\n        .unwrap();\n    let expected = Buffer::with_lines(vec![\n        \"                                        \",\n        \"                                        \",\n        \"  ┌Percentage────────────────────────┐  \",\n        \"  │               43%                │  \",\n        \"  └──────────────────────────────────┘  \",\n        \"  ┌Ratio─────────────────────────────┐  \",\n        \"  │               21%                │  \",\n        \"  └──────────────────────────────────┘  \",\n        \"                                        \",\n        \"                                        \",\n    ]);\n    terminal.backend().assert_buffer(&expected);\n}\n\n#[test]\nfn widgets_gauge_applies_styles() {\n    let backend = TestBackend::new(12, 5);\n    let mut terminal = Terminal::new(backend).unwrap();\n\n    terminal\n        .draw(|f| {\n            let gauge = Gauge::default()\n                .block(\n                    Block::default()\n                        .title(Span::styled(\"Test\", Style::default().fg(Color::Red)))\n                        .borders(Borders::ALL),\n                )\n                .gauge_style(Style::default().fg(Color::Blue).bg(Color::Red))\n                .percent(43)\n                .label(Span::styled(\n                    \"43%\",\n                    Style::default()\n                        .fg(Color::Green)\n                        .add_modifier(Modifier::BOLD),\n                ));\n            f.render_widget(gauge, f.size());\n        })\n        .unwrap();\n    let mut expected = Buffer::with_lines(vec![\n        \"┌Test──────┐\",\n        \"│          │\",\n        \"│   43%    │\",\n        \"│          │\",\n        \"└──────────┘\",\n    ]);\n    // title\n    expected.set_style(Rect::new(1, 0, 4, 1), Style::default().fg(Color::Red));\n    // gauge area\n    expected.set_style(\n        Rect::new(1, 1, 10, 3),\n        Style::default().fg(Color::Blue).bg(Color::Red),\n    );\n    // filled area\n    for y in 1..4 {\n        expected.set_style(\n            Rect::new(1, y, 4, 1),\n            // filled style is invert of gauge_style\n            Style::default().fg(Color::Red).bg(Color::Blue),\n        );\n    }\n    // label (foreground and modifier from label style)\n    expected.set_style(\n        Rect::new(4, 2, 1, 1),\n        Style::default()\n            .fg(Color::Green)\n            // \"4\" is in the filled area so background is gauge_style foreground\n            .bg(Color::Blue)\n            .add_modifier(Modifier::BOLD),\n    );\n    expected.set_style(\n        Rect::new(5, 2, 2, 1),\n        Style::default()\n            .fg(Color::Green)\n            // \"3%\" is not in the filled area so background is gauge_style background\n            .bg(Color::Red)\n            .add_modifier(Modifier::BOLD),\n    );\n    terminal.backend().assert_buffer(&expected);\n}\n\n#[test]\nfn widgets_gauge_supports_large_labels() {\n    let backend = TestBackend::new(10, 1);\n    let mut terminal = Terminal::new(backend).unwrap();\n\n    terminal\n        .draw(|f| {\n            let gauge = Gauge::default()\n                .percent(43)\n                .label(\"43333333333333333333333333333%\");\n            f.render_widget(gauge, f.size());\n        })\n        .unwrap();\n    let expected = Buffer::with_lines(vec![\"4333333333\"]);\n    terminal.backend().assert_buffer(&expected);\n}\n\n#[test]\nfn widgets_line_gauge_renders() {\n    let backend = TestBackend::new(20, 4);\n    let mut terminal = Terminal::new(backend).unwrap();\n    terminal\n        .draw(|f| {\n            let gauge = LineGauge::default()\n                .gauge_style(Style::default().fg(Color::Green).bg(Color::White))\n                .ratio(0.43);\n            f.render_widget(\n                gauge,\n                Rect {\n                    x: 0,\n                    y: 0,\n                    width: 20,\n                    height: 1,\n                },\n            );\n            let gauge = LineGauge::default()\n                .block(Block::default().title(\"Gauge 2\").borders(Borders::ALL))\n                .gauge_style(Style::default().fg(Color::Green))\n                .line_set(symbols::line::THICK)\n                .ratio(0.211_313_934_313_1);\n            f.render_widget(\n                gauge,\n                Rect {\n                    x: 0,\n                    y: 1,\n                    width: 20,\n                    height: 3,\n                },\n            );\n        })\n        .unwrap();\n    let mut expected = Buffer::with_lines(vec![\n        \"43% ────────────────\",\n        \"┌Gauge 2───────────┐\",\n        \"│21% ━━━━━━━━━━━━━━│\",\n        \"└──────────────────┘\",\n    ]);\n    for col in 4..10 {\n        expected.get_mut(col, 0).set_fg(Color::Green);\n    }\n    for col in 10..20 {\n        expected.get_mut(col, 0).set_fg(Color::White);\n    }\n    for col in 5..7 {\n        expected.get_mut(col, 2).set_fg(Color::Green);\n    }\n    terminal.backend().assert_buffer(&expected);\n}\n"
  },
  {
    "path": "tests/widgets_list.rs",
    "content": "use tui::{\n    backend::TestBackend,\n    buffer::Buffer,\n    layout::Rect,\n    style::{Color, Style},\n    symbols,\n    text::Spans,\n    widgets::{Block, Borders, List, ListItem, ListState},\n    Terminal,\n};\n\n#[test]\nfn widgets_list_should_highlight_the_selected_item() {\n    let backend = TestBackend::new(10, 3);\n    let mut terminal = Terminal::new(backend).unwrap();\n    let mut state = ListState::default();\n    state.select(Some(1));\n    terminal\n        .draw(|f| {\n            let size = f.size();\n            let items = vec![\n                ListItem::new(\"Item 1\"),\n                ListItem::new(\"Item 2\"),\n                ListItem::new(\"Item 3\"),\n            ];\n            let list = List::new(items)\n                .highlight_style(Style::default().bg(Color::Yellow))\n                .highlight_symbol(\">> \");\n            f.render_stateful_widget(list, size, &mut state);\n        })\n        .unwrap();\n    let mut expected = Buffer::with_lines(vec![\"   Item 1 \", \">> Item 2 \", \"   Item 3 \"]);\n    for x in 0..10 {\n        expected.get_mut(x, 1).set_bg(Color::Yellow);\n    }\n    terminal.backend().assert_buffer(&expected);\n}\n\n#[test]\nfn widgets_list_should_truncate_items() {\n    let backend = TestBackend::new(10, 2);\n    let mut terminal = Terminal::new(backend).unwrap();\n\n    struct TruncateTestCase<'a> {\n        selected: Option<usize>,\n        items: Vec<ListItem<'a>>,\n        expected: Buffer,\n    }\n\n    let cases = vec![\n        // An item is selected\n        TruncateTestCase {\n            selected: Some(0),\n            items: vec![\n                ListItem::new(\"A very long line\"),\n                ListItem::new(\"A very long line\"),\n            ],\n            expected: Buffer::with_lines(vec![\n                format!(\">> A ve{}  \", symbols::line::VERTICAL),\n                format!(\"   A ve{}  \", symbols::line::VERTICAL),\n            ]),\n        },\n        // No item is selected\n        TruncateTestCase {\n            selected: None,\n            items: vec![\n                ListItem::new(\"A very long line\"),\n                ListItem::new(\"A very long line\"),\n            ],\n            expected: Buffer::with_lines(vec![\n                format!(\"A very {}  \", symbols::line::VERTICAL),\n                format!(\"A very {}  \", symbols::line::VERTICAL),\n            ]),\n        },\n    ];\n    for case in cases {\n        let mut state = ListState::default();\n        state.select(case.selected);\n        terminal\n            .draw(|f| {\n                let list = List::new(case.items.clone())\n                    .block(Block::default().borders(Borders::RIGHT))\n                    .highlight_symbol(\">> \");\n                f.render_stateful_widget(list, Rect::new(0, 0, 8, 2), &mut state);\n            })\n            .unwrap();\n        terminal.backend().assert_buffer(&case.expected);\n    }\n}\n\n#[test]\nfn widgets_list_should_clamp_offset_if_items_are_removed() {\n    let backend = TestBackend::new(10, 4);\n    let mut terminal = Terminal::new(backend).unwrap();\n    let mut state = ListState::default();\n\n    // render with 6 items => offset will be at 2\n    state.select(Some(5));\n    terminal\n        .draw(|f| {\n            let size = f.size();\n            let items = vec![\n                ListItem::new(\"Item 0\"),\n                ListItem::new(\"Item 1\"),\n                ListItem::new(\"Item 2\"),\n                ListItem::new(\"Item 3\"),\n                ListItem::new(\"Item 4\"),\n                ListItem::new(\"Item 5\"),\n            ];\n            let list = List::new(items).highlight_symbol(\">> \");\n            f.render_stateful_widget(list, size, &mut state);\n        })\n        .unwrap();\n    let expected = Buffer::with_lines(vec![\"   Item 2 \", \"   Item 3 \", \"   Item 4 \", \">> Item 5 \"]);\n    terminal.backend().assert_buffer(&expected);\n\n    // render again with 1 items => check offset is clamped to 1\n    state.select(Some(1));\n    terminal\n        .draw(|f| {\n            let size = f.size();\n            let items = vec![ListItem::new(\"Item 3\")];\n            let list = List::new(items).highlight_symbol(\">> \");\n            f.render_stateful_widget(list, size, &mut state);\n        })\n        .unwrap();\n    let expected = Buffer::with_lines(vec![\"   Item 3 \", \"          \", \"          \", \"          \"]);\n    terminal.backend().assert_buffer(&expected);\n}\n\n#[test]\nfn widgets_list_should_display_multiline_items() {\n    let backend = TestBackend::new(10, 6);\n    let mut terminal = Terminal::new(backend).unwrap();\n    let mut state = ListState::default();\n    state.select(Some(1));\n    terminal\n        .draw(|f| {\n            let size = f.size();\n            let items = vec![\n                ListItem::new(vec![Spans::from(\"Item 1\"), Spans::from(\"Item 1a\")]),\n                ListItem::new(vec![Spans::from(\"Item 2\"), Spans::from(\"Item 2b\")]),\n                ListItem::new(vec![Spans::from(\"Item 3\"), Spans::from(\"Item 3c\")]),\n            ];\n            let list = List::new(items)\n                .highlight_style(Style::default().bg(Color::Yellow))\n                .highlight_symbol(\">> \");\n            f.render_stateful_widget(list, size, &mut state);\n        })\n        .unwrap();\n    let mut expected = Buffer::with_lines(vec![\n        \"   Item 1 \",\n        \"   Item 1a\",\n        \">> Item 2 \",\n        \"   Item 2b\",\n        \"   Item 3 \",\n        \"   Item 3c\",\n    ]);\n    for x in 0..10 {\n        expected.get_mut(x, 2).set_bg(Color::Yellow);\n        expected.get_mut(x, 3).set_bg(Color::Yellow);\n    }\n    terminal.backend().assert_buffer(&expected);\n}\n\n#[test]\nfn widgets_list_should_repeat_highlight_symbol() {\n    let backend = TestBackend::new(10, 6);\n    let mut terminal = Terminal::new(backend).unwrap();\n    let mut state = ListState::default();\n    state.select(Some(1));\n    terminal\n        .draw(|f| {\n            let size = f.size();\n            let items = vec![\n                ListItem::new(vec![Spans::from(\"Item 1\"), Spans::from(\"Item 1a\")]),\n                ListItem::new(vec![Spans::from(\"Item 2\"), Spans::from(\"Item 2b\")]),\n                ListItem::new(vec![Spans::from(\"Item 3\"), Spans::from(\"Item 3c\")]),\n            ];\n            let list = List::new(items)\n                .highlight_style(Style::default().bg(Color::Yellow))\n                .highlight_symbol(\">> \")\n                .repeat_highlight_symbol(true);\n            f.render_stateful_widget(list, size, &mut state);\n        })\n        .unwrap();\n    let mut expected = Buffer::with_lines(vec![\n        \"   Item 1 \",\n        \"   Item 1a\",\n        \">> Item 2 \",\n        \">> Item 2b\",\n        \"   Item 3 \",\n        \"   Item 3c\",\n    ]);\n    for x in 0..10 {\n        expected.get_mut(x, 2).set_bg(Color::Yellow);\n        expected.get_mut(x, 3).set_bg(Color::Yellow);\n    }\n    terminal.backend().assert_buffer(&expected);\n}\n"
  },
  {
    "path": "tests/widgets_paragraph.rs",
    "content": "use tui::{\n    backend::TestBackend,\n    buffer::Buffer,\n    layout::Alignment,\n    text::{Span, Spans, Text},\n    widgets::{Block, Borders, Paragraph, Wrap},\n    Terminal,\n};\n\nconst SAMPLE_STRING: &str = \"The library is based on the principle of immediate rendering with \\\n     intermediate buffers. This means that at each new frame you should build all widgets that are \\\n     supposed to be part of the UI. While providing a great flexibility for rich and \\\n     interactive UI, this may introduce overhead for highly dynamic content.\";\n\n#[test]\nfn widgets_paragraph_can_wrap_its_content() {\n    let test_case = |alignment, expected| {\n        let backend = TestBackend::new(20, 10);\n        let mut terminal = Terminal::new(backend).unwrap();\n\n        terminal\n            .draw(|f| {\n                let size = f.size();\n                let text = vec![Spans::from(SAMPLE_STRING)];\n                let paragraph = Paragraph::new(text)\n                    .block(Block::default().borders(Borders::ALL))\n                    .alignment(alignment)\n                    .wrap(Wrap { trim: true });\n                f.render_widget(paragraph, size);\n            })\n            .unwrap();\n        terminal.backend().assert_buffer(&expected);\n    };\n\n    test_case(\n        Alignment::Left,\n        Buffer::with_lines(vec![\n            \"┌──────────────────┐\",\n            \"│The library is    │\",\n            \"│based on the      │\",\n            \"│principle of      │\",\n            \"│immediate         │\",\n            \"│rendering with    │\",\n            \"│intermediate      │\",\n            \"│buffers. This     │\",\n            \"│means that at each│\",\n            \"└──────────────────┘\",\n        ]),\n    );\n    test_case(\n        Alignment::Right,\n        Buffer::with_lines(vec![\n            \"┌──────────────────┐\",\n            \"│    The library is│\",\n            \"│      based on the│\",\n            \"│      principle of│\",\n            \"│         immediate│\",\n            \"│    rendering with│\",\n            \"│      intermediate│\",\n            \"│     buffers. This│\",\n            \"│means that at each│\",\n            \"└──────────────────┘\",\n        ]),\n    );\n    test_case(\n        Alignment::Center,\n        Buffer::with_lines(vec![\n            \"┌──────────────────┐\",\n            \"│  The library is  │\",\n            \"│   based on the   │\",\n            \"│   principle of   │\",\n            \"│     immediate    │\",\n            \"│  rendering with  │\",\n            \"│   intermediate   │\",\n            \"│   buffers. This  │\",\n            \"│means that at each│\",\n            \"└──────────────────┘\",\n        ]),\n    );\n}\n\n#[test]\nfn widgets_paragraph_renders_double_width_graphemes() {\n    let backend = TestBackend::new(10, 10);\n    let mut terminal = Terminal::new(backend).unwrap();\n\n    let s = \"コンピュータ上で文字を扱う場合、典型的には文字による通信を行う場合にその両端点では、\";\n    terminal\n        .draw(|f| {\n            let size = f.size();\n            let text = vec![Spans::from(s)];\n            let paragraph = Paragraph::new(text)\n                .block(Block::default().borders(Borders::ALL))\n                .wrap(Wrap { trim: true });\n            f.render_widget(paragraph, size);\n        })\n        .unwrap();\n\n    let expected = Buffer::with_lines(vec![\n        \"┌────────┐\",\n        \"│コンピュ│\",\n        \"│ータ上で│\",\n        \"│文字を扱│\",\n        \"│う場合、│\",\n        \"│典型的に│\",\n        \"│は文字に│\",\n        \"│よる通信│\",\n        \"│を行う場│\",\n        \"└────────┘\",\n    ]);\n    terminal.backend().assert_buffer(&expected);\n}\n\n#[test]\nfn widgets_paragraph_renders_mixed_width_graphemes() {\n    let backend = TestBackend::new(10, 7);\n    let mut terminal = Terminal::new(backend).unwrap();\n\n    let s = \"aコンピュータ上で文字を扱う場合、\";\n    terminal\n        .draw(|f| {\n            let size = f.size();\n            let text = vec![Spans::from(s)];\n            let paragraph = Paragraph::new(text)\n                .block(Block::default().borders(Borders::ALL))\n                .wrap(Wrap { trim: true });\n            f.render_widget(paragraph, size);\n        })\n        .unwrap();\n\n    let expected = Buffer::with_lines(vec![\n        // The internal width is 8 so only 4 slots for double-width characters.\n        \"┌────────┐\",\n        \"│aコンピ │\", // Here we have 1 latin character so only 3 double-width ones can fit.\n        \"│ュータ上│\",\n        \"│で文字を│\",\n        \"│扱う場合│\",\n        \"│、      │\",\n        \"└────────┘\",\n    ]);\n    terminal.backend().assert_buffer(&expected);\n}\n\n#[test]\nfn widgets_paragraph_can_wrap_with_a_trailing_nbsp() {\n    let nbsp: &str = \"\\u{00a0}\";\n    let line = Spans::from(vec![Span::raw(\"NBSP\"), Span::raw(nbsp)]);\n    let backend = TestBackend::new(20, 3);\n    let mut terminal = Terminal::new(backend).unwrap();\n    let expected = Buffer::with_lines(vec![\n        \"┌──────────────────┐\",\n        \"│NBSP\\u{00a0}             │\",\n        \"└──────────────────┘\",\n    ]);\n    terminal\n        .draw(|f| {\n            let size = f.size();\n\n            let paragraph = Paragraph::new(line).block(Block::default().borders(Borders::ALL));\n            f.render_widget(paragraph, size);\n        })\n        .unwrap();\n    terminal.backend().assert_buffer(&expected);\n}\n#[test]\nfn widgets_paragraph_can_scroll_horizontally() {\n    let test_case = |alignment, scroll, expected| {\n        let backend = TestBackend::new(20, 10);\n        let mut terminal = Terminal::new(backend).unwrap();\n\n        terminal\n            .draw(|f| {\n                let size = f.size();\n                let text = Text::from(\n                    \"段落现在可以水平滚动了！\\nParagraph can scroll horizontally!\\nShort line\",\n                );\n                let paragraph = Paragraph::new(text)\n                    .block(Block::default().borders(Borders::ALL))\n                    .alignment(alignment)\n                    .scroll(scroll);\n                f.render_widget(paragraph, size);\n            })\n            .unwrap();\n        terminal.backend().assert_buffer(&expected);\n    };\n\n    test_case(\n        Alignment::Left,\n        (0, 7),\n        Buffer::with_lines(vec![\n            \"┌──────────────────┐\",\n            \"│在可以水平滚动了！│\",\n            \"│ph can scroll hori│\",\n            \"│ine               │\",\n            \"│                  │\",\n            \"│                  │\",\n            \"│                  │\",\n            \"│                  │\",\n            \"│                  │\",\n            \"└──────────────────┘\",\n        ]),\n    );\n    // only support Alignment::Left\n    test_case(\n        Alignment::Right,\n        (0, 7),\n        Buffer::with_lines(vec![\n            \"┌──────────────────┐\",\n            \"│段落现在可以水平滚│\",\n            \"│Paragraph can scro│\",\n            \"│        Short line│\",\n            \"│                  │\",\n            \"│                  │\",\n            \"│                  │\",\n            \"│                  │\",\n            \"│                  │\",\n            \"└──────────────────┘\",\n        ]),\n    );\n}\n"
  },
  {
    "path": "tests/widgets_table.rs",
    "content": "use tui::{\n    backend::TestBackend,\n    buffer::Buffer,\n    layout::Constraint,\n    style::{Color, Modifier, Style},\n    text::{Span, Spans},\n    widgets::{Block, Borders, Cell, Row, Table, TableState},\n    Terminal,\n};\n\n#[test]\nfn widgets_table_column_spacing_can_be_changed() {\n    let test_case = |column_spacing, expected| {\n        let backend = TestBackend::new(30, 10);\n        let mut terminal = Terminal::new(backend).unwrap();\n\n        terminal\n            .draw(|f| {\n                let size = f.size();\n                let table = Table::new(vec![\n                    Row::new(vec![\"Row11\", \"Row12\", \"Row13\"]),\n                    Row::new(vec![\"Row21\", \"Row22\", \"Row23\"]),\n                    Row::new(vec![\"Row31\", \"Row32\", \"Row33\"]),\n                    Row::new(vec![\"Row41\", \"Row42\", \"Row43\"]),\n                ])\n                .header(Row::new(vec![\"Head1\", \"Head2\", \"Head3\"]).bottom_margin(1))\n                .block(Block::default().borders(Borders::ALL))\n                .widths(&[\n                    Constraint::Length(5),\n                    Constraint::Length(5),\n                    Constraint::Length(5),\n                ])\n                .column_spacing(column_spacing);\n                f.render_widget(table, size);\n            })\n            .unwrap();\n        terminal.backend().assert_buffer(&expected);\n    };\n\n    // no space between columns\n    test_case(\n        0,\n        Buffer::with_lines(vec![\n            \"┌────────────────────────────┐\",\n            \"│Head1Head2Head3             │\",\n            \"│                            │\",\n            \"│Row11Row12Row13             │\",\n            \"│Row21Row22Row23             │\",\n            \"│Row31Row32Row33             │\",\n            \"│Row41Row42Row43             │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"└────────────────────────────┘\",\n        ]),\n    );\n\n    // one space between columns\n    test_case(\n        1,\n        Buffer::with_lines(vec![\n            \"┌────────────────────────────┐\",\n            \"│Head1 Head2 Head3           │\",\n            \"│                            │\",\n            \"│Row11 Row12 Row13           │\",\n            \"│Row21 Row22 Row23           │\",\n            \"│Row31 Row32 Row33           │\",\n            \"│Row41 Row42 Row43           │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"└────────────────────────────┘\",\n        ]),\n    );\n\n    // enough space to just not hide the third column\n    test_case(\n        6,\n        Buffer::with_lines(vec![\n            \"┌────────────────────────────┐\",\n            \"│Head1      Head2      Head3 │\",\n            \"│                            │\",\n            \"│Row11      Row12      Row13 │\",\n            \"│Row21      Row22      Row23 │\",\n            \"│Row31      Row32      Row33 │\",\n            \"│Row41      Row42      Row43 │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"└────────────────────────────┘\",\n        ]),\n    );\n\n    // enough space to hide part of the third column\n    test_case(\n        7,\n        Buffer::with_lines(vec![\n            \"┌────────────────────────────┐\",\n            \"│Head1       Head2       Head│\",\n            \"│                            │\",\n            \"│Row11       Row12       Row1│\",\n            \"│Row21       Row22       Row2│\",\n            \"│Row31       Row32       Row3│\",\n            \"│Row41       Row42       Row4│\",\n            \"│                            │\",\n            \"│                            │\",\n            \"└────────────────────────────┘\",\n        ]),\n    );\n}\n\n#[test]\nfn widgets_table_columns_widths_can_use_fixed_length_constraints() {\n    let test_case = |widths, expected| {\n        let backend = TestBackend::new(30, 10);\n        let mut terminal = Terminal::new(backend).unwrap();\n\n        terminal\n            .draw(|f| {\n                let size = f.size();\n                let table = Table::new(vec![\n                    Row::new(vec![\"Row11\", \"Row12\", \"Row13\"]),\n                    Row::new(vec![\"Row21\", \"Row22\", \"Row23\"]),\n                    Row::new(vec![\"Row31\", \"Row32\", \"Row33\"]),\n                    Row::new(vec![\"Row41\", \"Row42\", \"Row43\"]),\n                ])\n                .header(Row::new(vec![\"Head1\", \"Head2\", \"Head3\"]).bottom_margin(1))\n                .block(Block::default().borders(Borders::ALL))\n                .widths(widths);\n                f.render_widget(table, size);\n            })\n            .unwrap();\n        terminal.backend().assert_buffer(&expected);\n    };\n\n    // columns of zero width show nothing\n    test_case(\n        &[\n            Constraint::Length(0),\n            Constraint::Length(0),\n            Constraint::Length(0),\n        ],\n        Buffer::with_lines(vec![\n            \"┌────────────────────────────┐\",\n            \"│                            │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"└────────────────────────────┘\",\n        ]),\n    );\n\n    // columns of 1 width trim\n    test_case(\n        &[\n            Constraint::Length(1),\n            Constraint::Length(1),\n            Constraint::Length(1),\n        ],\n        Buffer::with_lines(vec![\n            \"┌────────────────────────────┐\",\n            \"│H H H                       │\",\n            \"│                            │\",\n            \"│R R R                       │\",\n            \"│R R R                       │\",\n            \"│R R R                       │\",\n            \"│R R R                       │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"└────────────────────────────┘\",\n        ]),\n    );\n\n    // columns of large width just before pushing a column off\n    test_case(\n        &[\n            Constraint::Length(8),\n            Constraint::Length(8),\n            Constraint::Length(8),\n        ],\n        Buffer::with_lines(vec![\n            \"┌────────────────────────────┐\",\n            \"│Head1    Head2    Head3     │\",\n            \"│                            │\",\n            \"│Row11    Row12    Row13     │\",\n            \"│Row21    Row22    Row23     │\",\n            \"│Row31    Row32    Row33     │\",\n            \"│Row41    Row42    Row43     │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"└────────────────────────────┘\",\n        ]),\n    );\n}\n\n#[test]\nfn widgets_table_columns_widths_can_use_percentage_constraints() {\n    let test_case = |widths, expected| {\n        let backend = TestBackend::new(30, 10);\n        let mut terminal = Terminal::new(backend).unwrap();\n\n        terminal\n            .draw(|f| {\n                let size = f.size();\n                let table = Table::new(vec![\n                    Row::new(vec![\"Row11\", \"Row12\", \"Row13\"]),\n                    Row::new(vec![\"Row21\", \"Row22\", \"Row23\"]),\n                    Row::new(vec![\"Row31\", \"Row32\", \"Row33\"]),\n                    Row::new(vec![\"Row41\", \"Row42\", \"Row43\"]),\n                ])\n                .header(Row::new(vec![\"Head1\", \"Head2\", \"Head3\"]).bottom_margin(1))\n                .block(Block::default().borders(Borders::ALL))\n                .widths(widths)\n                .column_spacing(0);\n                f.render_widget(table, size);\n            })\n            .unwrap();\n        terminal.backend().assert_buffer(&expected);\n    };\n\n    // columns of zero width show nothing\n    test_case(\n        &[\n            Constraint::Percentage(0),\n            Constraint::Percentage(0),\n            Constraint::Percentage(0),\n        ],\n        Buffer::with_lines(vec![\n            \"┌────────────────────────────┐\",\n            \"│                            │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"└────────────────────────────┘\",\n        ]),\n    );\n\n    // columns of not enough width trims the data\n    test_case(\n        &[\n            Constraint::Percentage(11),\n            Constraint::Percentage(11),\n            Constraint::Percentage(11),\n        ],\n        Buffer::with_lines(vec![\n            \"┌────────────────────────────┐\",\n            \"│HeaHeaHea                   │\",\n            \"│                            │\",\n            \"│RowRowRow                   │\",\n            \"│RowRowRow                   │\",\n            \"│RowRowRow                   │\",\n            \"│RowRowRow                   │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"└────────────────────────────┘\",\n        ]),\n    );\n\n    // columns of large width just before pushing a column off\n    test_case(\n        &[\n            Constraint::Percentage(33),\n            Constraint::Percentage(33),\n            Constraint::Percentage(33),\n        ],\n        Buffer::with_lines(vec![\n            \"┌────────────────────────────┐\",\n            \"│Head1    Head2    Head3     │\",\n            \"│                            │\",\n            \"│Row11    Row12    Row13     │\",\n            \"│Row21    Row22    Row23     │\",\n            \"│Row31    Row32    Row33     │\",\n            \"│Row41    Row42    Row43     │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"└────────────────────────────┘\",\n        ]),\n    );\n\n    // percentages summing to 100 should give equal widths\n    test_case(\n        &[Constraint::Percentage(50), Constraint::Percentage(50)],\n        Buffer::with_lines(vec![\n            \"┌────────────────────────────┐\",\n            \"│Head1         Head2         │\",\n            \"│                            │\",\n            \"│Row11         Row12         │\",\n            \"│Row21         Row22         │\",\n            \"│Row31         Row32         │\",\n            \"│Row41         Row42         │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"└────────────────────────────┘\",\n        ]),\n    );\n}\n\n#[test]\nfn widgets_table_columns_widths_can_use_mixed_constraints() {\n    let test_case = |widths, expected| {\n        let backend = TestBackend::new(30, 10);\n        let mut terminal = Terminal::new(backend).unwrap();\n\n        terminal\n            .draw(|f| {\n                let size = f.size();\n                let table = Table::new(vec![\n                    Row::new(vec![\"Row11\", \"Row12\", \"Row13\"]),\n                    Row::new(vec![\"Row21\", \"Row22\", \"Row23\"]),\n                    Row::new(vec![\"Row31\", \"Row32\", \"Row33\"]),\n                    Row::new(vec![\"Row41\", \"Row42\", \"Row43\"]),\n                ])\n                .header(Row::new(vec![\"Head1\", \"Head2\", \"Head3\"]).bottom_margin(1))\n                .block(Block::default().borders(Borders::ALL))\n                .widths(widths);\n                f.render_widget(table, size);\n            })\n            .unwrap();\n        terminal.backend().assert_buffer(&expected);\n    };\n\n    // columns of zero width show nothing\n    test_case(\n        &[\n            Constraint::Percentage(0),\n            Constraint::Length(0),\n            Constraint::Percentage(0),\n        ],\n        Buffer::with_lines(vec![\n            \"┌────────────────────────────┐\",\n            \"│                            │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"└────────────────────────────┘\",\n        ]),\n    );\n\n    // columns of not enough width trims the data\n    test_case(\n        &[\n            Constraint::Percentage(11),\n            Constraint::Length(20),\n            Constraint::Percentage(11),\n        ],\n        Buffer::with_lines(vec![\n            \"┌────────────────────────────┐\",\n            \"│Hea Head2                He │\",\n            \"│                            │\",\n            \"│Row Row12                Ro │\",\n            \"│Row Row22                Ro │\",\n            \"│Row Row32                Ro │\",\n            \"│Row Row42                Ro │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"└────────────────────────────┘\",\n        ]),\n    );\n\n    // columns of large width just before pushing a column off\n    test_case(\n        &[\n            Constraint::Percentage(33),\n            Constraint::Length(10),\n            Constraint::Percentage(33),\n        ],\n        Buffer::with_lines(vec![\n            \"┌────────────────────────────┐\",\n            \"│Head1     Head2      Head3  │\",\n            \"│                            │\",\n            \"│Row11     Row12      Row13  │\",\n            \"│Row21     Row22      Row23  │\",\n            \"│Row31     Row32      Row33  │\",\n            \"│Row41     Row42      Row43  │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"└────────────────────────────┘\",\n        ]),\n    );\n\n    // columns of large size (>100% total) hide the last column\n    test_case(\n        &[\n            Constraint::Percentage(60),\n            Constraint::Length(10),\n            Constraint::Percentage(60),\n        ],\n        Buffer::with_lines(vec![\n            \"┌────────────────────────────┐\",\n            \"│Head1            Head2      │\",\n            \"│                            │\",\n            \"│Row11            Row12      │\",\n            \"│Row21            Row22      │\",\n            \"│Row31            Row32      │\",\n            \"│Row41            Row42      │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"└────────────────────────────┘\",\n        ]),\n    );\n}\n\n#[test]\nfn widgets_table_columns_widths_can_use_ratio_constraints() {\n    let test_case = |widths, expected| {\n        let backend = TestBackend::new(30, 10);\n        let mut terminal = Terminal::new(backend).unwrap();\n\n        terminal\n            .draw(|f| {\n                let size = f.size();\n                let table = Table::new(vec![\n                    Row::new(vec![\"Row11\", \"Row12\", \"Row13\"]),\n                    Row::new(vec![\"Row21\", \"Row22\", \"Row23\"]),\n                    Row::new(vec![\"Row31\", \"Row32\", \"Row33\"]),\n                    Row::new(vec![\"Row41\", \"Row42\", \"Row43\"]),\n                ])\n                .header(Row::new(vec![\"Head1\", \"Head2\", \"Head3\"]).bottom_margin(1))\n                .block(Block::default().borders(Borders::ALL))\n                .widths(widths)\n                .column_spacing(0);\n                f.render_widget(table, size);\n            })\n            .unwrap();\n        terminal.backend().assert_buffer(&expected);\n    };\n\n    // columns of zero width show nothing\n    test_case(\n        &[\n            Constraint::Ratio(0, 1),\n            Constraint::Ratio(0, 1),\n            Constraint::Ratio(0, 1),\n        ],\n        Buffer::with_lines(vec![\n            \"┌────────────────────────────┐\",\n            \"│                            │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"└────────────────────────────┘\",\n        ]),\n    );\n\n    // columns of not enough width trims the data\n    test_case(\n        &[\n            Constraint::Ratio(1, 9),\n            Constraint::Ratio(1, 9),\n            Constraint::Ratio(1, 9),\n        ],\n        Buffer::with_lines(vec![\n            \"┌────────────────────────────┐\",\n            \"│HeaHeaHea                   │\",\n            \"│                            │\",\n            \"│RowRowRow                   │\",\n            \"│RowRowRow                   │\",\n            \"│RowRowRow                   │\",\n            \"│RowRowRow                   │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"└────────────────────────────┘\",\n        ]),\n    );\n\n    // columns of large width just before pushing a column off\n    test_case(\n        &[\n            Constraint::Ratio(1, 3),\n            Constraint::Ratio(1, 3),\n            Constraint::Ratio(1, 3),\n        ],\n        Buffer::with_lines(vec![\n            \"┌────────────────────────────┐\",\n            \"│Head1    Head2    Head3     │\",\n            \"│                            │\",\n            \"│Row11    Row12    Row13     │\",\n            \"│Row21    Row22    Row23     │\",\n            \"│Row31    Row32    Row33     │\",\n            \"│Row41    Row42    Row43     │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"└────────────────────────────┘\",\n        ]),\n    );\n\n    // percentages summing to 100 should give equal widths\n    test_case(\n        &[Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)],\n        Buffer::with_lines(vec![\n            \"┌────────────────────────────┐\",\n            \"│Head1         Head2         │\",\n            \"│                            │\",\n            \"│Row11         Row12         │\",\n            \"│Row21         Row22         │\",\n            \"│Row31         Row32         │\",\n            \"│Row41         Row42         │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"└────────────────────────────┘\",\n        ]),\n    );\n}\n\n#[test]\nfn widgets_table_can_have_rows_with_multi_lines() {\n    let test_case = |state: &mut TableState, expected: Buffer| {\n        let backend = TestBackend::new(30, 8);\n        let mut terminal = Terminal::new(backend).unwrap();\n        terminal\n            .draw(|f| {\n                let size = f.size();\n                let table = Table::new(vec![\n                    Row::new(vec![\"Row11\", \"Row12\", \"Row13\"]),\n                    Row::new(vec![\"Row21\", \"Row22\", \"Row23\"]).height(2),\n                    Row::new(vec![\"Row31\", \"Row32\", \"Row33\"]),\n                    Row::new(vec![\"Row41\", \"Row42\", \"Row43\"]).height(2),\n                ])\n                .header(Row::new(vec![\"Head1\", \"Head2\", \"Head3\"]).bottom_margin(1))\n                .block(Block::default().borders(Borders::ALL))\n                .highlight_symbol(\">> \")\n                .widths(&[\n                    Constraint::Length(5),\n                    Constraint::Length(5),\n                    Constraint::Length(5),\n                ])\n                .column_spacing(1);\n                f.render_stateful_widget(table, size, state);\n            })\n            .unwrap();\n        terminal.backend().assert_buffer(&expected);\n    };\n\n    let mut state = TableState::default();\n    // no selection\n    test_case(\n        &mut state,\n        Buffer::with_lines(vec![\n            \"┌────────────────────────────┐\",\n            \"│Head1 Head2 Head3           │\",\n            \"│                            │\",\n            \"│Row11 Row12 Row13           │\",\n            \"│Row21 Row22 Row23           │\",\n            \"│                            │\",\n            \"│Row31 Row32 Row33           │\",\n            \"└────────────────────────────┘\",\n        ]),\n    );\n\n    // select first\n    state.select(Some(0));\n    test_case(\n        &mut state,\n        Buffer::with_lines(vec![\n            \"┌────────────────────────────┐\",\n            \"│   Head1 Head2 Head3        │\",\n            \"│                            │\",\n            \"│>> Row11 Row12 Row13        │\",\n            \"│   Row21 Row22 Row23        │\",\n            \"│                            │\",\n            \"│   Row31 Row32 Row33        │\",\n            \"└────────────────────────────┘\",\n        ]),\n    );\n\n    // select second (we don't show partially the 4th row)\n    state.select(Some(1));\n    test_case(\n        &mut state,\n        Buffer::with_lines(vec![\n            \"┌────────────────────────────┐\",\n            \"│   Head1 Head2 Head3        │\",\n            \"│                            │\",\n            \"│   Row11 Row12 Row13        │\",\n            \"│>> Row21 Row22 Row23        │\",\n            \"│                            │\",\n            \"│   Row31 Row32 Row33        │\",\n            \"└────────────────────────────┘\",\n        ]),\n    );\n\n    // select 4th (we don't show partially the 1st row)\n    state.select(Some(3));\n    test_case(\n        &mut state,\n        Buffer::with_lines(vec![\n            \"┌────────────────────────────┐\",\n            \"│   Head1 Head2 Head3        │\",\n            \"│                            │\",\n            \"│   Row31 Row32 Row33        │\",\n            \"│>> Row41 Row42 Row43        │\",\n            \"│                            │\",\n            \"│                            │\",\n            \"└────────────────────────────┘\",\n        ]),\n    );\n}\n\n#[test]\nfn widgets_table_can_have_elements_styled_individually() {\n    let backend = TestBackend::new(30, 4);\n    let mut terminal = Terminal::new(backend).unwrap();\n    let mut state = TableState::default();\n    state.select(Some(0));\n    terminal\n        .draw(|f| {\n            let size = f.size();\n            let table = Table::new(vec![\n                Row::new(vec![\"Row11\", \"Row12\", \"Row13\"]).style(Style::default().fg(Color::Green)),\n                Row::new(vec![\n                    Cell::from(\"Row21\"),\n                    Cell::from(\"Row22\").style(Style::default().fg(Color::Yellow)),\n                    Cell::from(Spans::from(vec![\n                        Span::raw(\"Row\"),\n                        Span::styled(\"23\", Style::default().fg(Color::Blue)),\n                    ]))\n                    .style(Style::default().fg(Color::Red)),\n                ])\n                .style(Style::default().fg(Color::LightGreen)),\n            ])\n            .header(Row::new(vec![\"Head1\", \"Head2\", \"Head3\"]).bottom_margin(1))\n            .block(Block::default().borders(Borders::LEFT | Borders::RIGHT))\n            .highlight_symbol(\">> \")\n            .highlight_style(Style::default().add_modifier(Modifier::BOLD))\n            .widths(&[\n                Constraint::Length(6),\n                Constraint::Length(6),\n                Constraint::Length(6),\n            ])\n            .column_spacing(1);\n            f.render_stateful_widget(table, size, &mut state);\n        })\n        .unwrap();\n\n    let mut expected = Buffer::with_lines(vec![\n        \"│   Head1  Head2  Head3      │\",\n        \"│                            │\",\n        \"│>> Row11  Row12  Row13      │\",\n        \"│   Row21  Row22  Row23      │\",\n    ]);\n    // First row = row color + highlight style\n    for col in 1..=28 {\n        expected.get_mut(col, 2).set_style(\n            Style::default()\n                .fg(Color::Green)\n                .add_modifier(Modifier::BOLD),\n        );\n    }\n    // Second row:\n    // 1. row color\n    for col in 1..=28 {\n        expected\n            .get_mut(col, 3)\n            .set_style(Style::default().fg(Color::LightGreen));\n    }\n    // 2. cell color\n    for col in 11..=16 {\n        expected\n            .get_mut(col, 3)\n            .set_style(Style::default().fg(Color::Yellow));\n    }\n    for col in 18..=23 {\n        expected\n            .get_mut(col, 3)\n            .set_style(Style::default().fg(Color::Red));\n    }\n    // 3. text color\n    for col in 21..=22 {\n        expected\n            .get_mut(col, 3)\n            .set_style(Style::default().fg(Color::Blue));\n    }\n    terminal.backend().assert_buffer(&expected);\n}\n\n#[test]\nfn widgets_table_should_render_even_if_empty() {\n    let backend = TestBackend::new(30, 4);\n    let mut terminal = Terminal::new(backend).unwrap();\n    terminal\n        .draw(|f| {\n            let size = f.size();\n            let table = Table::new(vec![])\n                .header(Row::new(vec![\"Head1\", \"Head2\", \"Head3\"]))\n                .block(Block::default().borders(Borders::LEFT | Borders::RIGHT))\n                .widths(&[\n                    Constraint::Length(6),\n                    Constraint::Length(6),\n                    Constraint::Length(6),\n                ])\n                .column_spacing(1);\n            f.render_widget(table, size);\n        })\n        .unwrap();\n\n    let expected = Buffer::with_lines(vec![\n        \"│Head1  Head2  Head3         │\",\n        \"│                            │\",\n        \"│                            │\",\n        \"│                            │\",\n    ]);\n\n    terminal.backend().assert_buffer(&expected);\n}\n\n#[test]\nfn widgets_table_columns_dont_panic() {\n    let test_case = |state: &mut TableState, table: Table, width: u16| {\n        let backend = TestBackend::new(width, 8);\n        let mut terminal = Terminal::new(backend).unwrap();\n        terminal\n            .draw(|f| {\n                let size = f.size();\n                f.render_stateful_widget(table, size, state);\n            })\n            .unwrap();\n    };\n\n    // based on https://github.com/fdehau/tui-rs/issues/470#issuecomment-852562848\n    let table1_width = 98;\n    let table1 = Table::new(vec![Row::new(vec![\"r1\", \"r2\", \"r3\", \"r4\"])])\n        .header(Row::new(vec![\"h1\", \"h2\", \"h3\", \"h4\"]))\n        .block(Block::default().borders(Borders::ALL))\n        .highlight_symbol(\">> \")\n        .column_spacing(1)\n        .widths(&[\n            Constraint::Percentage(15),\n            Constraint::Percentage(15),\n            Constraint::Percentage(25),\n            Constraint::Percentage(45),\n        ]);\n\n    let mut state = TableState::default();\n\n    // select first, which would cause a panic before fix\n    state.select(Some(0));\n    test_case(&mut state, table1.clone(), table1_width);\n}\n\n#[test]\nfn widgets_table_should_clamp_offset_if_rows_are_removed() {\n    let backend = TestBackend::new(30, 8);\n    let mut terminal = Terminal::new(backend).unwrap();\n    let mut state = TableState::default();\n\n    // render with 6 items => offset will be at 2\n    state.select(Some(5));\n    terminal\n        .draw(|f| {\n            let size = f.size();\n            let table = Table::new(vec![\n                Row::new(vec![\"Row01\", \"Row02\", \"Row03\"]),\n                Row::new(vec![\"Row11\", \"Row12\", \"Row13\"]),\n                Row::new(vec![\"Row21\", \"Row22\", \"Row23\"]),\n                Row::new(vec![\"Row31\", \"Row32\", \"Row33\"]),\n                Row::new(vec![\"Row41\", \"Row42\", \"Row43\"]),\n                Row::new(vec![\"Row51\", \"Row52\", \"Row53\"]),\n            ])\n            .header(Row::new(vec![\"Head1\", \"Head2\", \"Head3\"]).bottom_margin(1))\n            .block(Block::default().borders(Borders::ALL))\n            .widths(&[\n                Constraint::Length(5),\n                Constraint::Length(5),\n                Constraint::Length(5),\n            ])\n            .column_spacing(1);\n            f.render_stateful_widget(table, size, &mut state);\n        })\n        .unwrap();\n    let expected = Buffer::with_lines(vec![\n        \"┌────────────────────────────┐\",\n        \"│Head1 Head2 Head3           │\",\n        \"│                            │\",\n        \"│Row21 Row22 Row23           │\",\n        \"│Row31 Row32 Row33           │\",\n        \"│Row41 Row42 Row43           │\",\n        \"│Row51 Row52 Row53           │\",\n        \"└────────────────────────────┘\",\n    ]);\n    terminal.backend().assert_buffer(&expected);\n\n    // render with 1 item => offset will be at 1\n    state.select(Some(1));\n    terminal\n        .draw(|f| {\n            let size = f.size();\n            let table = Table::new(vec![Row::new(vec![\"Row31\", \"Row32\", \"Row33\"])])\n                .header(Row::new(vec![\"Head1\", \"Head2\", \"Head3\"]).bottom_margin(1))\n                .block(Block::default().borders(Borders::ALL))\n                .widths(&[\n                    Constraint::Length(5),\n                    Constraint::Length(5),\n                    Constraint::Length(5),\n                ])\n                .column_spacing(1);\n            f.render_stateful_widget(table, size, &mut state);\n        })\n        .unwrap();\n    let expected = Buffer::with_lines(vec![\n        \"┌────────────────────────────┐\",\n        \"│Head1 Head2 Head3           │\",\n        \"│                            │\",\n        \"│Row31 Row32 Row33           │\",\n        \"│                            │\",\n        \"│                            │\",\n        \"│                            │\",\n        \"└────────────────────────────┘\",\n    ]);\n    terminal.backend().assert_buffer(&expected);\n}\n"
  },
  {
    "path": "tests/widgets_tabs.rs",
    "content": "use tui::{\n    backend::TestBackend, buffer::Buffer, layout::Rect, symbols, text::Spans, widgets::Tabs,\n    Terminal,\n};\n\n#[test]\nfn widgets_tabs_should_not_panic_on_narrow_areas() {\n    let backend = TestBackend::new(1, 1);\n    let mut terminal = Terminal::new(backend).unwrap();\n    terminal\n        .draw(|f| {\n            let tabs = Tabs::new([\"Tab1\", \"Tab2\"].iter().cloned().map(Spans::from).collect());\n            f.render_widget(\n                tabs,\n                Rect {\n                    x: 0,\n                    y: 0,\n                    width: 1,\n                    height: 1,\n                },\n            );\n        })\n        .unwrap();\n    let expected = Buffer::with_lines(vec![\" \"]);\n    terminal.backend().assert_buffer(&expected);\n}\n\n#[test]\nfn widgets_tabs_should_truncate_the_last_item() {\n    let backend = TestBackend::new(10, 1);\n    let mut terminal = Terminal::new(backend).unwrap();\n    terminal\n        .draw(|f| {\n            let tabs = Tabs::new([\"Tab1\", \"Tab2\"].iter().cloned().map(Spans::from).collect());\n            f.render_widget(\n                tabs,\n                Rect {\n                    x: 0,\n                    y: 0,\n                    width: 9,\n                    height: 1,\n                },\n            );\n        })\n        .unwrap();\n    let expected = Buffer::with_lines(vec![format!(\" Tab1 {} T \", symbols::line::VERTICAL)]);\n    terminal.backend().assert_buffer(&expected);\n}\n"
  }
]