From 97494e21d8a21aed1abd9f6e1db5fec6b0061821 Mon Sep 17 00:00:00 2001 From: tomarnepedersen Date: Sat, 15 Feb 2025 05:37:14 +0000 Subject: [PATCH] deploy: 460389b832f268aa200f7bdda40ee2f4f0b59799 --- .buildinfo | 4 + .nojekyll | 0 CHANGELOG.html | 468 +++++++++ LICENSE.html | 334 +++++++ README.html | 458 +++++++++ STYLEGUIDE.html | 797 +++++++++++++++ .../trafficgen.check_land_crossing.html | 378 ++++++++ _autosummary/trafficgen.encounter.html | 729 ++++++++++++++ .../trafficgen.marine_system_simulator.html | 462 +++++++++ .../trafficgen.plot_traffic_situation.html | 515 ++++++++++ _autosummary/trafficgen.read_files.html | 602 ++++++++++++ .../trafficgen.ship_traffic_generator.html | 377 ++++++++ _autosummary/trafficgen.utils.html | 673 +++++++++++++ ...icgen.write_traffic_situation_to_file.html | 411 ++++++++ _sources/CHANGELOG.md.txt | 2 + _sources/LICENSE.md.txt | 3 + _sources/README.md.txt | 2 + _sources/STYLEGUIDE.md.txt | 2 + .../trafficgen.check_land_crossing.rst.txt | 13 + .../_autosummary/trafficgen.encounter.rst.txt | 26 + ...trafficgen.marine_system_simulator.rst.txt | 15 + .../trafficgen.plot_traffic_situation.rst.txt | 19 + .../trafficgen.read_files.rst.txt | 25 + .../trafficgen.ship_traffic_generator.rst.txt | 13 + .../_autosummary/trafficgen.utils.rst.txt | 26 + ...en.write_traffic_situation_to_file.rst.txt | 15 + _sources/api.rst.txt | 7 + _sources/index.rst.txt | 26 + _sources/input_files.rst.txt | 228 +++++ _sources/trafficgen.rst.txt | 19 + _sources/usage.rst.txt | 58 ++ _static/DNV_logo_RGB.jpg | Bin 0 -> 202826 bytes _static/basic.css | 914 ++++++++++++++++++ _static/debug.css | 69 ++ _static/doctools.js | 149 +++ _static/documentation_options.js | 13 + _static/file.png | Bin 0 -> 286 bytes _static/language_data.js | 192 ++++ _static/minus.png | Bin 0 -> 90 bytes _static/my_package.svg | 1 + _static/plus.png | Bin 0 -> 90 bytes _static/pygments.css | 258 +++++ _static/scripts/furo-extensions.js | 0 _static/scripts/furo.js | 3 + _static/scripts/furo.js.LICENSE.txt | 7 + _static/scripts/furo.js.map | 1 + _static/searchtools.js | 632 ++++++++++++ _static/skeleton.css | 296 ++++++ _static/sphinx_highlight.js | 154 +++ _static/styles/furo-extensions.css | 2 + _static/styles/furo-extensions.css.map | 1 + _static/styles/furo.css | 2 + _static/styles/furo.css.map | 1 + api.html | 415 ++++++++ branch/main/.buildinfo | 4 + branch/main/CHANGELOG.html | 468 +++++++++ branch/main/LICENSE.html | 334 +++++++ branch/main/README.html | 458 +++++++++ branch/main/STYLEGUIDE.html | 797 +++++++++++++++ .../trafficgen.check_land_crossing.html | 378 ++++++++ .../_autosummary/trafficgen.encounter.html | 729 ++++++++++++++ .../trafficgen.marine_system_simulator.html | 462 +++++++++ .../trafficgen.plot_traffic_situation.html | 515 ++++++++++ .../_autosummary/trafficgen.read_files.html | 602 ++++++++++++ .../trafficgen.ship_traffic_generator.html | 377 ++++++++ .../main/_autosummary/trafficgen.utils.html | 673 +++++++++++++ ...icgen.write_traffic_situation_to_file.html | 411 ++++++++ branch/main/_sources/CHANGELOG.md.txt | 2 + branch/main/_sources/LICENSE.md.txt | 3 + branch/main/_sources/README.md.txt | 2 + branch/main/_sources/STYLEGUIDE.md.txt | 2 + .../trafficgen.check_land_crossing.rst.txt | 13 + .../_autosummary/trafficgen.encounter.rst.txt | 26 + ...trafficgen.marine_system_simulator.rst.txt | 15 + .../trafficgen.plot_traffic_situation.rst.txt | 19 + .../trafficgen.read_files.rst.txt | 25 + .../trafficgen.ship_traffic_generator.rst.txt | 13 + .../_autosummary/trafficgen.utils.rst.txt | 26 + ...en.write_traffic_situation_to_file.rst.txt | 15 + branch/main/_sources/api.rst.txt | 7 + branch/main/_sources/index.rst.txt | 26 + branch/main/_sources/input_files.rst.txt | 228 +++++ branch/main/_sources/trafficgen.rst.txt | 19 + branch/main/_sources/usage.rst.txt | 58 ++ branch/main/_static/DNV_logo_RGB.jpg | Bin 0 -> 202826 bytes branch/main/_static/basic.css | 914 ++++++++++++++++++ branch/main/_static/debug.css | 69 ++ branch/main/_static/doctools.js | 149 +++ branch/main/_static/documentation_options.js | 13 + branch/main/_static/file.png | Bin 0 -> 286 bytes branch/main/_static/language_data.js | 192 ++++ branch/main/_static/minus.png | Bin 0 -> 90 bytes branch/main/_static/my_package.svg | 1 + branch/main/_static/plus.png | Bin 0 -> 90 bytes branch/main/_static/pygments.css | 258 +++++ .../main/_static/scripts/furo-extensions.js | 0 branch/main/_static/scripts/furo.js | 3 + .../main/_static/scripts/furo.js.LICENSE.txt | 7 + branch/main/_static/scripts/furo.js.map | 1 + branch/main/_static/searchtools.js | 632 ++++++++++++ branch/main/_static/skeleton.css | 296 ++++++ branch/main/_static/sphinx_highlight.js | 154 +++ .../main/_static/styles/furo-extensions.css | 2 + .../_static/styles/furo-extensions.css.map | 1 + branch/main/_static/styles/furo.css | 2 + branch/main/_static/styles/furo.css.map | 1 + branch/main/api.html | 415 ++++++++ branch/main/genindex.html | 626 ++++++++++++ branch/main/index.html | 424 ++++++++ branch/main/input_files.html | 568 +++++++++++ branch/main/objects.inv | Bin 0 -> 1264 bytes branch/main/py-modindex.html | 372 +++++++ branch/main/search.html | 320 ++++++ branch/main/searchindex.js | 1 + branch/main/trafficgen.html | 377 ++++++++ branch/main/usage.html | 406 ++++++++ genindex.html | 626 ++++++++++++ index.html | 424 ++++++++ input_files.html | 568 +++++++++++ objects.inv | Bin 0 -> 1264 bytes py-modindex.html | 372 +++++++ search.html | 320 ++++++ searchindex.js | 1 + trafficgen.html | 377 ++++++++ usage.html | 406 ++++++++ 125 files changed, 25822 insertions(+) create mode 100644 .buildinfo create mode 100644 .nojekyll create mode 100644 CHANGELOG.html create mode 100644 LICENSE.html create mode 100644 README.html create mode 100644 STYLEGUIDE.html create mode 100644 _autosummary/trafficgen.check_land_crossing.html create mode 100644 _autosummary/trafficgen.encounter.html create mode 100644 _autosummary/trafficgen.marine_system_simulator.html create mode 100644 _autosummary/trafficgen.plot_traffic_situation.html create mode 100644 _autosummary/trafficgen.read_files.html create mode 100644 _autosummary/trafficgen.ship_traffic_generator.html create mode 100644 _autosummary/trafficgen.utils.html create mode 100644 _autosummary/trafficgen.write_traffic_situation_to_file.html create mode 100644 _sources/CHANGELOG.md.txt create mode 100644 _sources/LICENSE.md.txt create mode 100644 _sources/README.md.txt create mode 100644 _sources/STYLEGUIDE.md.txt create mode 100644 _sources/_autosummary/trafficgen.check_land_crossing.rst.txt create mode 100644 _sources/_autosummary/trafficgen.encounter.rst.txt create mode 100644 _sources/_autosummary/trafficgen.marine_system_simulator.rst.txt create mode 100644 _sources/_autosummary/trafficgen.plot_traffic_situation.rst.txt create mode 100644 _sources/_autosummary/trafficgen.read_files.rst.txt create mode 100644 _sources/_autosummary/trafficgen.ship_traffic_generator.rst.txt create mode 100644 _sources/_autosummary/trafficgen.utils.rst.txt create mode 100644 _sources/_autosummary/trafficgen.write_traffic_situation_to_file.rst.txt create mode 100644 _sources/api.rst.txt create mode 100644 _sources/index.rst.txt create mode 100644 _sources/input_files.rst.txt create mode 100644 _sources/trafficgen.rst.txt create mode 100644 _sources/usage.rst.txt create mode 100644 _static/DNV_logo_RGB.jpg create mode 100644 _static/basic.css create mode 100644 _static/debug.css create mode 100644 _static/doctools.js create mode 100644 _static/documentation_options.js create mode 100644 _static/file.png create mode 100644 _static/language_data.js create mode 100644 _static/minus.png create mode 100644 _static/my_package.svg create mode 100644 _static/plus.png create mode 100644 _static/pygments.css create mode 100644 _static/scripts/furo-extensions.js create mode 100644 _static/scripts/furo.js create mode 100644 _static/scripts/furo.js.LICENSE.txt create mode 100644 _static/scripts/furo.js.map create mode 100644 _static/searchtools.js create mode 100644 _static/skeleton.css create mode 100644 _static/sphinx_highlight.js create mode 100644 _static/styles/furo-extensions.css create mode 100644 _static/styles/furo-extensions.css.map create mode 100644 _static/styles/furo.css create mode 100644 _static/styles/furo.css.map create mode 100644 api.html create mode 100644 branch/main/.buildinfo create mode 100644 branch/main/CHANGELOG.html create mode 100644 branch/main/LICENSE.html create mode 100644 branch/main/README.html create mode 100644 branch/main/STYLEGUIDE.html create mode 100644 branch/main/_autosummary/trafficgen.check_land_crossing.html create mode 100644 branch/main/_autosummary/trafficgen.encounter.html create mode 100644 branch/main/_autosummary/trafficgen.marine_system_simulator.html create mode 100644 branch/main/_autosummary/trafficgen.plot_traffic_situation.html create mode 100644 branch/main/_autosummary/trafficgen.read_files.html create mode 100644 branch/main/_autosummary/trafficgen.ship_traffic_generator.html create mode 100644 branch/main/_autosummary/trafficgen.utils.html create mode 100644 branch/main/_autosummary/trafficgen.write_traffic_situation_to_file.html create mode 100644 branch/main/_sources/CHANGELOG.md.txt create mode 100644 branch/main/_sources/LICENSE.md.txt create mode 100644 branch/main/_sources/README.md.txt create mode 100644 branch/main/_sources/STYLEGUIDE.md.txt create mode 100644 branch/main/_sources/_autosummary/trafficgen.check_land_crossing.rst.txt create mode 100644 branch/main/_sources/_autosummary/trafficgen.encounter.rst.txt create mode 100644 branch/main/_sources/_autosummary/trafficgen.marine_system_simulator.rst.txt create mode 100644 branch/main/_sources/_autosummary/trafficgen.plot_traffic_situation.rst.txt create mode 100644 branch/main/_sources/_autosummary/trafficgen.read_files.rst.txt create mode 100644 branch/main/_sources/_autosummary/trafficgen.ship_traffic_generator.rst.txt create mode 100644 branch/main/_sources/_autosummary/trafficgen.utils.rst.txt create mode 100644 branch/main/_sources/_autosummary/trafficgen.write_traffic_situation_to_file.rst.txt create mode 100644 branch/main/_sources/api.rst.txt create mode 100644 branch/main/_sources/index.rst.txt create mode 100644 branch/main/_sources/input_files.rst.txt create mode 100644 branch/main/_sources/trafficgen.rst.txt create mode 100644 branch/main/_sources/usage.rst.txt create mode 100644 branch/main/_static/DNV_logo_RGB.jpg create mode 100644 branch/main/_static/basic.css create mode 100644 branch/main/_static/debug.css create mode 100644 branch/main/_static/doctools.js create mode 100644 branch/main/_static/documentation_options.js create mode 100644 branch/main/_static/file.png create mode 100644 branch/main/_static/language_data.js create mode 100644 branch/main/_static/minus.png create mode 100644 branch/main/_static/my_package.svg create mode 100644 branch/main/_static/plus.png create mode 100644 branch/main/_static/pygments.css create mode 100644 branch/main/_static/scripts/furo-extensions.js create mode 100644 branch/main/_static/scripts/furo.js create mode 100644 branch/main/_static/scripts/furo.js.LICENSE.txt create mode 100644 branch/main/_static/scripts/furo.js.map create mode 100644 branch/main/_static/searchtools.js create mode 100644 branch/main/_static/skeleton.css create mode 100644 branch/main/_static/sphinx_highlight.js create mode 100644 branch/main/_static/styles/furo-extensions.css create mode 100644 branch/main/_static/styles/furo-extensions.css.map create mode 100644 branch/main/_static/styles/furo.css create mode 100644 branch/main/_static/styles/furo.css.map create mode 100644 branch/main/api.html create mode 100644 branch/main/genindex.html create mode 100644 branch/main/index.html create mode 100644 branch/main/input_files.html create mode 100644 branch/main/objects.inv create mode 100644 branch/main/py-modindex.html create mode 100644 branch/main/search.html create mode 100644 branch/main/searchindex.js create mode 100644 branch/main/trafficgen.html create mode 100644 branch/main/usage.html create mode 100644 genindex.html create mode 100644 index.html create mode 100644 input_files.html create mode 100644 objects.inv create mode 100644 py-modindex.html create mode 100644 search.html create mode 100644 searchindex.js create mode 100644 trafficgen.html create mode 100644 usage.html diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 0000000..faf4d29 --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file records the configuration used when building these files. When it is not found, a full rebuild will be done. +config: b173307822a54cfbe21556b56523e84d +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/CHANGELOG.html b/CHANGELOG.html new file mode 100644 index 0000000..2da02e9 --- /dev/null +++ b/CHANGELOG.html @@ -0,0 +1,468 @@ + + + + + + + + + Changelog - trafficgen 0.7.1 + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+ +
+ +
+ +
+
+
+

Changelog

+

All notable changes to the trafficgen project will be documented in this file.
+The changelog format is based on Keep a Changelog.

+
+

[Unreleased]

+

-/-

+
+
+

[0.7.1] - 2025-01-30

+
+

Changed

+
    +
  • Made explicit that Python 3.13 is not yet supported in the pyproject.toml file

  • +
+
+
+
+

[0.7.0] - 2025-01-22

+
+

Changed

+
    +
  • The python package Maritime Schema is no longer open source, necessary types have been included here to remove the link

  • +
  • Project updated to use uv package installer

  • +
  • Documentation has been updated

  • +
  • Updating workflows

  • +
  • Removed maxSpeed from the output files generated using the tool

  • +
+
+
+
+

0.6.0 - 2024-11-11

+
+

Changed

+
    +
  • Updated to download-artifact@v4 (from download-artifact@v3)

  • +
+
+
+
+

0.5.0 - 2024-04-26

+
+

Changed

+
    +
  • removed specific names for target ships. Files generated with target ship 1, 2 etc.

  • +
  • changed tests. Still need to figure out why some tests “fail” using CLI.

  • +
+
+
+
+

0.4.0 - 2024-04-19

+
+

Changed

+
    +
  • possible to have several aypoints for own ship

  • +
  • fixing pyright error

  • +
  • beta (relative bearing between osn ship and target ship seen from own ship) +is not just a number, but could also be a range

  • +
  • situation length is used when checking if target ship is passing land

  • +
+
+
+
+

0.3.0 - 2024-04-10

+
+

Changed

+
    +
  • using types from maritime schema

  • +
  • lat/lon used instead of north/east

  • +
  • the generated output files are using “maritime” units: knots and degrees

  • +
+
+
+
+

0.2.0 - 2024-01-11

+
+

Changed

+
    +
  • add-basic-code-quality-settings-black-ruff-pyright,

  • +
  • first-small-round-of-code-improvement

  • +
  • add-domain-specific-data-types-for-ship-situation-etc-using-pydantic-models,

  • +
  • activate-remaining-pyright-rules,

  • +
  • add-github-workflows-to-build-package-and-to-build-and-publish-documentation

  • +
  • sorting output from os.listdir

  • +
  • github workflow for release

  • +
  • removed cyclic import

  • +
  • length of encounter may be specified by user

  • +
+
+
+
+

[0.1.0] - 2023-11-08

+
    +
  • First release on PyPI.

  • +
+ +
+
+ +
+
+ +
+ +
+
+ + + + + \ No newline at end of file diff --git a/LICENSE.html b/LICENSE.html new file mode 100644 index 0000000..c06f9c3 --- /dev/null +++ b/LICENSE.html @@ -0,0 +1,334 @@ + + + + + + + + + LICENSE - trafficgen 0.7.1 + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+ +
+ +
+ +
+
+
+

LICENSE

+

MIT License

+

Copyright (c) 2025 DNV open source

+

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

+

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.

+
+ +
+
+ +
+ +
+
+ + + + + \ No newline at end of file diff --git a/README.html b/README.html new file mode 100644 index 0000000..dfa6d47 --- /dev/null +++ b/README.html @@ -0,0 +1,458 @@ + + + + + + + + + Traffic Generator - trafficgen 0.7.1 + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+ +
+ +
+ +
+
+
+

Traffic Generator

+

The tool generates a structured set of encounters for verifying automatic collision and grounding avoidance systems. +Based on input parameters such as desired situation, relative speed, relative bearing etc, +the tool will generate a set of traffic situations. The traffic situations may be written to files and/or inspected using plots.

+

A paper is written describing the background for the tool and how it works [paper]

+
+

Installation

+

To install Ship Traffic Generator, run this command in your terminal:

+
pip install trafficgen
+
+
+

This is the preferred method to install Traffic Generator, as it will always install the most recent stable release.

+

You can check your installation by running:

+
uv run trafficgen --help
+
+
+

See documentation for usage of the Ship Traffic Generator.

+
+
+

Development Setup

+
+

Install UV

+

This project uses uv as package manager. +If you haven’t already, install uv, preferably using it’s “Standalone installer” method:
+..on Windows:

+
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
+
+
+

..on MacOS and Linux:

+
curl -LsSf https://astral.sh/uv/install.sh | sh
+
+
+

(see docs.astral.sh/uv for all / alternative installation methods.)

+

Once installed, you can update uv to its latest version, anytime, by running:

+
uv self update
+
+
+
+
+

Install Python

+

The traffic generator requires Python 3.11 or later.

+

If you don’t already have a compatible version installed on your machine, you way install Python through uv:

+
uv python install
+
+
+

This will install the latest stable version of Python into the uv Python directory, i.e. as a uv-managed version of Python.

+

Alternatively, and if you want a standalone version of Python on your machine, you can install Python either via winget:

+
winget install --id Python.Python
+
+
+

or you can download and install Python from the python.org website.

+
+
+

Clone the repository

+

Clone the traffig generator repository into your local development directory:

+
git clone https://github.com/dnv-opensource/ship-traffic-generator path/to/your/dir/ship-traffic-generator
+
+
+

Change into the project directory after cloning:

+
cd ship-traffic-generator
+
+
+
+
+

Install dependencies

+

Run uv sync to create a virtual environment and install all project dependencies into it:

+
uv sync
+
+
+
+

Note: Using --no-dev will omit installing development dependencies.

+
+
+

Note: uv will create a new virtual environment called .venv in the project root directory when running +uv sync the first time. Optionally, you can create your own virtual environment using e.g. uv venv, before running +uv sync.

+
+
+
+

(Optional) Activate the virtual environment

+

When using uv, there is in almost all cases no longer a need to manually activate the virtual environment.
+uv will find the .venv virtual environment in the working directory or any parent directory, and activate it on the fly whenever you run a command via uv inside your project folder structure:

+
uv run <command>
+
+
+

However, you still can manually activate the virtual environment if needed. +When developing in an IDE, for instance, this can in some cases be necessary depending on your IDE settings. +To manually activate the virtual environment, run one of the “known” legacy commands:
+..on Windows:

+
.venv\Scripts\activate.bat
+
+
+

..on Linux:

+
source .venv/bin/activate
+
+
+
+
+

Documentation

+

To generate documentation use:

+
uv run docs/make.bat html
+
+
+

The html documentation will then be available in docs/build/html/index.html

+
+
+
+ +
+
+ +
+ +
+
+ + + + + \ No newline at end of file diff --git a/STYLEGUIDE.html b/STYLEGUIDE.html new file mode 100644 index 0000000..64d4a2e --- /dev/null +++ b/STYLEGUIDE.html @@ -0,0 +1,797 @@ + + + + + + + + + Style Guide - trafficgen 0.7.1 + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+ +
+ +
+ +
+
+
+

Style Guide

+

All code shall be Ruff formatted.

+

References, details as well as examples of bad/good styles and their respective reasoning can be found below.

+
+

References

+ +
+
+

Code Layout

+
    +
  • Use 4 spaces instead of tabs

  • +
  • Maximum line length is 120 characters (not 79 as proposed in PEP-8)

  • +
  • 2 blank lines between classes and functions

  • +
  • 1 blank line within class, between class methods

  • +
  • Use blank lines for logic separation of functionality within functions/methods wherever it is justified

  • +
  • No whitespace adjacent to parentheses, brackets, or braces

  • +
+
    # Bad
+    spam( items[ 1 ], { key1 : arg1, key2 : arg2 }, )
+
+    # Good
+    spam(items[1], {key1: arg1, key2: arg2}, [])
+
+
+
    +
  • Surround operators with single whitespace on either side.

  • +
+
    # Bad
+    x<1
+
+    # Good
+    x == 1
+
+
+
    +
  • Never end your lines with a semicolon, and do not use a semicolon to put two statements on the same line

  • +
  • When branching, always start a new block on a new line

  • +
+
    # Bad
+    if flag: return None
+
+    # Good
+    if flag:
+        return None
+
+
+
    +
  • Similarly to branching, do not write methods on one line in any case:

  • +
+
    # Bad
+    def do_something(self): print("Something")
+
+    # Good
+    def do_something(self):
+        print("Something")
+
+
+
    +
  • Place a class’s __init__ function (the constructor) always at the beginning of the class

  • +
+
+
+

Line Breaks

+
    +
  • If function arguments do not fit into the specified line length, move them to a new line with indentation

  • +
+
    # Bad
+    def long_function_name(var_one, var_two, var_three,
+        var_four):
+        print(var_one)
+
+    # Bad
+    def long_function_name(var_one, var_two, var_three,
+            var_four):
+        print(var_one)
+
+    # Better (but not preferred)
+    def long_function_name(var_one,
+                           var_two,
+                           var_three,
+                           var_four):
+        print(var_one)
+
+    # Good (and preferred)
+    def long_function_name(
+        var_one,
+        var_two,
+        var_three,
+        var_four,
+    ):
+        print(var_one)
+
+
+
    +
  • Move concatenated logical conditions to new lines if the line does not fit the maximum line size. This will help you understand the condition by looking from top to bottom. Poor formatting makes it difficult to read and understand complex predicates.

  • +
+
    # Good
+    if (
+        this_is_one_thing
+        and that_is_another_thing
+        or that_is_third_thing
+        or that_is_yet_another_thing
+        and one_more_thing
+    ):
+        do_something()
+
+
+
    +
  • Where binary operations stretch multiple lines, break lines before the binary operators, not thereafter

  • +
+
    # Bad
+    GDP = (
+        private_consumption +
+        gross_investment +
+        government_investment +
+        government_spending +
+        (exports - imports)
+    )
+
+    # Good
+    GDP = (
+        private_consumption
+        + gross_investment
+        + government_investment
+        + government_spending
+        + (exports - imports)
+    )
+
+
+
    +
  • Chaining methods should be broken up on multiple lines for better readability

  • +
+
    (
+        df.write.format("jdbc")
+        .option("url", "jdbc:postgresql:dbserver")
+        .option("dbtable", "schema.tablename")
+        .option("user", "username")
+        .option("password", "password")
+        .save()
+    )
+
+
+
    +
  • Add a trailing comma to sequences of items when the closing container token ], ), or } does not appear on the same line as the final element

  • +
+
    # Bad
+    y = [
+        0,
+        1,
+        4,
+        6
+    ]
+    z = {
+        'a': 1,
+        'b': 2
+    }
+
+    # Good
+    x = [1, 2, 3]
+
+    # Good
+    y = [
+        0,
+        1,
+        4,
+        6,         <- note the trailing comma
+    ]
+    z = {
+        'a': 1,
+        'b': 2,    <- note the trailing comma
+    }
+
+
+
+
+

String Formatting

+
    +
  • When quoting string literals, use double-quoted strings. When the string itself contains single or double quote characters, however, use the respective other one to avoid backslashes in the string. It improves readability.

  • +
  • Use f-strings to format strings:

  • +
+
    # Bad
+    print("Hello, %s. You are %s years old. You are a %s." % (name, age, profession))
+
+    # Good
+    print(f"Hello, {name}. You are {age} years old. You are a {profession}.")
+
+
+
    +
  • Use multiline strings, not \ , since it gets much more readable.

  • +
+
    raise AttributeError(
+        "Here is a multiline error message with a very long first line "
+        "and a shorter second line."
+    )
+
+
+
+
+

Naming Conventions

+
    +
  • For module names: lowercase . +Long module names can have words separated by underscores (really_long_module_name.py), but this is not required. Try to use the convention of nearby files.

  • +
  • For class names: CamelCase

  • +
  • For methods, functions, variables and attributes: lowercase_with_underscores

  • +
  • For constants: UPPERCASE or UPPERCASE_WITH_UNDERSCORES +(Python does not differentiate between variables and constants. Using UPPERCASE for constants is just a convention, but helps a lot to quickly identify variables meant to serve as constants.)

  • +
  • Implementation-specific private methods and variables will use _single_underscore_prefix

  • +
  • Don’t include the type of a variable in its name. +E.g. use senders instead of sender_list

  • +
  • Names shall be clear about what a variable, class, or function contains or does. If you struggle to come up with a clear name, rethink your architecture: Often, the difficulty in finding a crisp name for something is a hint that separation of responsibilities can be improved. The solution then is less to agree on a name, but to start a round of refactoring: The name you’re seeking often comes naturally then with refactoring to an improved architecture with clear responsibilities. +(see SRP, Single-Responsibilty Principle by Robert C. Martin)

  • +
+
+
+

Named Arguments

+
    +
  • Use named arguments to improve readability and avoid mistakes introduced with future code maintenance

  • +
+
    # Bad
+    urlget("[http://google.com](http://google.com/)", 20)
+
+    # Good
+    urlget("[http://google.com](http://google.com/)", timeout=20)
+
+
+
    +
  • Never use mutable objects as default arguments in Python. If an attribute in a class or a named parameter in a function is of a mutable data type (e.g. a list or dict), never set its default value in the declaration of an object but always set it to None first, and then only later assign the default value in the class’s constructor, or the functions body, respectively. Sounds complicated? If you prefer the shortcut, the examples below are your friend. +If you are interested in the long story including the why‘s, read these discussions on Reddit and Twitter.

  • +
+
    # Bad
+    class Foo:
+        items = []
+
+    # Good
+    class Foo:
+        items = None
+        def __init__(self):
+            self.items = []
+
+
+    # Bad
+    class Foo:
+        def __init__(self, items=[]):
+            self.items = items
+
+    # Good
+    class Foo:
+        def __init__(self, items=None):
+            self.items = items or []
+
+
+    # Bad
+    def some_function(x, y, items=[]):
+        ...
+
+    # Good
+    def some_function(x, y, items=None):
+        items = items or []
+        ...
+
+
+
+
+

Commenting

+
    +
  • First of all, if the code needs comments to clarify its work, you should think about refactoring it. The best comment to code is the code itself.

  • +
  • Describe complex, possibly incomprehensible points and side effects in the comments

  • +
  • Separate # and the comment with one whitespace

  • +
+
    #bad comment
+    # good comment
+
+
+
    +
  • Use inline comments sparsely

  • +
  • Where used, inline comments shall have 2 whitespaces before the # and one whitespace thereafter

  • +
+
    x = y + z  # inline comment
+    str1 = str2 + str3  # another inline comment
+
+
+
    +
  • If a piece of code is poorly understood, mark the piece with a @TODO: tag and your name to support future refactoring:

  • +
+
    def get_ancestors_ids(self):
+        # @TODO: Do a cache reset while saving the category tree. CLAROS, YYYY-MM-DD
+        cache_name = f"{self._meta.model_name}_ancestors_{self.pk}"
+        cached_ids = cache.get(cache_name)
+        if cached_ids:
+            return cached_ids
+
+        ids = [c.pk for c in self.get_ancestors(include_self=True)]
+        cache.set(cache_name, ids, timeout=3600)
+
+        return ids
+
+
+
+
+

Type hints

+
    +
  • Use type hints in function signatures and module-scope variables. This is good documentation and can be used with linters for type checking and error checking. Use them whenever possible.

  • +
  • Use pyi files to type annotate third-party or extension modules.

  • +
+
+
+

Docstrings

+
    +
  • All Docstrings should be written in Numpy format. For a good tutorial on Docstrings, see Documenting Python Code: A Complete Guide

  • +
  • In a Docstring, summarize function/method behavior and document its arguments, return value(s), side effects, exceptions raised, and restrictions

  • +
  • Wrap Docstrings with triple double quotes (“””)

  • +
  • The description of the arguments must be indented

  • +
+
    def some_method(name, print=False):
+        """This function does something
+
+        Parameters
+        ----------
+        name : str
+            The name to use
+        print: bool, optional
+            A flag used to print the name to the console, by default False
+
+        Raises
+        ------
+        KeyError
+            If name is not found
+
+        Returns
+        -------
+        int
+            The return code
+        """
+        ...
+        return 0
+
+
+
+
+

Exceptions

+
    +
  • Raise specific exceptions and catch specific exceptions, such as KeyError, ValueError, etc.

  • +
  • Do not raise or catch just Exception, except in rare cases where this is unavoidable, such as a try/except block on the top-level loop of some long-running process. For a good tutorial on why this matters, see The Most Diabolical Python Antipattern.

  • +
  • Minimize the amount of code in a try/except block. The larger the body of the try, +the more likely that an exception will be raised by a line of code that you didn’t expect to raise an exception.

  • +
+
+
+

Imports

+
    +
  • Avoid creating circular imports by importing modules more specialized than the one you are editing

  • +
  • Relative imports are forbidden (PEP-8 only “highly discourages” them). Where absolutely needed, the from future import absolute_import syntax should be used (see PEP-328)

  • +
  • Never use wildcard imports (from <module> import *). Always be explicit about what you’re importing. Namespaces make code easier to read, so use them.

  • +
  • Break long imports using parentheses and indent by 4 spaces. Include the trailing comma after the last import and place the closing bracket on a separate line

  • +
+
    from my_pkg.utils import (
+        some_utility_method_1,
+        some_utility_method_2,
+        some_utility_method_3,
+        some_utility_method_4,
+        some_utility_method_5,
+    )
+
+
+
    +
  • Imports should be written in the following order, separated by a blank line:

    +
      +
    1. build-in modules

    2. +
    3. third-party modules

    4. +
    5. local application/library specific imports

    6. +
    +
  • +
+
    import logging
+    import os
+    import typing as T
+
+    import pandas as pd
+    import numpy as np
+
+    import my_package
+    import my_package.my_module
+    from my_package.my_module import my_function, MyClass
+
+
+
    +
  • Even if a Python file is intended to be used as executable / script file only, it shall still be importable as a module, and its import should not have any side effects. Its main functionality shall hence be in a main() function, so that the code can be imported as a module for testing or being reused in the future:

  • +
+
    def main():
+        ...
+
+    if __name__ == "__main__":
+        main()
+
+
+
+
+

Unit-tests

+
    +
  • Use pytest as the preferred testing framework.

  • +
  • The name of a test shall clearly express what is being tested.

  • +
  • Each test should preferably check only one specific aspect.

  • +
+
    # Bad
+    def test_smth():
+        result = f()
+        assert isinstance(result, list)
+        assert result[0] == 1
+        assert result[1] == 2
+        assert result[2] == 3
+        assert result[3] == 4
+
+    # Good
+    def test_smth_type():
+        result = f()
+        assert isinstance(result, list), "Result should be list"
+
+    def test_smth_values():
+        result = f()
+        assert set(result) == set(expected), f"Result should be {set(expected)}"
+
+
+
+
+

And finally: It is a bad idea to use

+
    +
  • global variables.

  • +
  • iterators where they can be replaced by vectorized operations.

  • +
  • lambda where it is not required.

  • +
  • map and lambda where it can be replaced by a simple list comprehension.

  • +
  • multiple nested maps and lambdas.

  • +
  • nested functions. They are hard to test and debug.

  • +
+
+
+ +
+
+ +
+ +
+
+ + + + + \ No newline at end of file diff --git a/_autosummary/trafficgen.check_land_crossing.html b/_autosummary/trafficgen.check_land_crossing.html new file mode 100644 index 0000000..4629541 --- /dev/null +++ b/_autosummary/trafficgen.check_land_crossing.html @@ -0,0 +1,378 @@ + + + + + + + + + trafficgen.check_land_crossing - trafficgen 0.7.1 + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+ +
+ +
+ +
+
+
+

trafficgen.check_land_crossing

+

Module with helper functions to determine if a generated path is crossing land.

+

Functions

+
+ + + + + + +

path_crosses_land(position_1, speed, cog, ...)

Find if path is crossing land.

+
+
+
+trafficgen.check_land_crossing.path_crosses_land(position_1: GeoPosition, speed: float, cog: float, lat_lon0: GeoPosition, time_interval: float = 300.0) bool
+

Find if path is crossing land.

+
+
Parameters:
+
    +
  • position_1 (GeoPosition) – Ship position, latitudinal [rad] and longitudinal [rad].

  • +
  • speed (float) – Ship speed [m/s].

  • +
  • cog (float) – Ship course over ground [rad].

  • +
  • lat_lon0 (GeoPosition) – Reference point, latitudinal [rad] and longitudinal [rad].

  • +
  • time_interval (float) – The time interval the vessel should travel without crossing land [sec]. Default is 300.0.

  • +
+
+
Returns:
+

is_on_land – True if parts of the path crosses land.

+
+
Return type:
+

bool

+
+
+
+ +
+ +
+
+ +
+ +
+
+ + + + + \ No newline at end of file diff --git a/_autosummary/trafficgen.encounter.html b/_autosummary/trafficgen.encounter.html new file mode 100644 index 0000000..e68c2a9 --- /dev/null +++ b/_autosummary/trafficgen.encounter.html @@ -0,0 +1,729 @@ + + + + + + + + + trafficgen.encounter - trafficgen 0.7.1 + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+ +
+ +
+ +
+
+
+

trafficgen.encounter

+

Functions to generate encounters.

+

The encounters consist of one own ship and one to many target ships. +The generated encounters may be of type head-on, overtaking give-way and stand-on and +crossing give-way and stand-on.

+

Functions

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

assign_beta(encounter_type, encounter_settings)

Assign random (uniform) relative bearing.

assign_beta_from_list(beta_limit)

Assign random (uniform) relative bearing.

assign_future_position_to_target_ship(...)

Randomly assign future position of target ship.

assign_sog_to_target_ship(encounter_type, ...)

Assign random (uniform) sog to target ship depending on type of encounter.

assign_vector_time(vector_time_range)

Assign random (uniform) vector time.

calculate_min_vector_length_target_ship(...)

Calculate minimum vector length (target ship sog x vector).

calculate_relative_bearing(...)

Calculate relative bearing between own ship and target ship.

calculate_ship_cog(pos_0, pos_1, lat_lon0)

Calculate ship cog between two waypoints.

check_encounter_evolvement(own_ship, ...)

Check encounter evolvement.

decide_target_ship(target_ships_static)

Randomly pick a target ship from a list of target ships.

define_own_ship(desired_traffic_situation, ...)

Define own ship based on information in desired traffic situation.

determine_colreg(alpha, beta, ...)

Determine the colreg type.

find_start_position_target_ship(...)

Find start position of target ship using desired beta and vector length.

generate_encounter(desired_encounter_type, ...)

Generate an encounter.

+
+
+
+trafficgen.encounter.assign_beta(encounter_type: EncounterType, encounter_settings: EncounterSettings) float
+

Assign random (uniform) relative bearing.

+
+
Parameters:
+
    +
  • encounter_type (EncounterType) – Type of encounter

  • +
  • encounter_settings (EncounterSettings) – Encounter settings

  • +
+
+
Returns:
+

relative_bearing – Relative bearing between own ship and target ship seen from own ship [rad]

+
+
Return type:
+

float

+
+
+
+ +
+
+trafficgen.encounter.assign_beta_from_list(beta_limit: list[float]) float
+

Assign random (uniform) relative bearing.

+

The beta between own ship and target ship depending is somewhere between +the limits given by beta_limit.

+
+
Parameters:
+

beta_limit (list[float]) – Limits for beta {min, max} [rad]

+
+
Returns:
+

relative_bearing – Relative bearing between own ship and target ship seen from own ship [rad]

+
+
Return type:
+

float

+
+
+
+ +
+
+trafficgen.encounter.assign_future_position_to_target_ship(own_ship_position_future: GeoPosition, lat_lon0: GeoPosition, max_meeting_distance: float) GeoPosition
+

Randomly assign future position of target ship.

+

If drawing a circle with radius max_meeting_distance around future position of own ship, +future position of target ship shall be somewhere inside this circle.

+
+
Parameters:
+
    +
  • own_ship_position_future (GeoPosition) – Own ship position at a given time in the future {lat, lon} [rad]

  • +
  • lat_lon0 (GeoPosition) – Reference point, latitudinal [rad] and longitudinal [rad]

  • +
  • max_meeting_distance (float) – Maximum distance between own ship and target ship at a given time in the future [m]

  • +
+
+
Returns:
+

future_position_target_ship – Future position of target ship {lat, lon} [rad]

+
+
Return type:
+

GeoPosition

+
+
+
+ +
+
+trafficgen.encounter.assign_sog_to_target_ship(encounter_type: EncounterType, own_ship_sog: float, min_target_ship_sog: float, relative_sog_setting: EncounterRelativeSpeed) float
+

Assign random (uniform) sog to target ship depending on type of encounter.

+
+
Parameters:
+
    +
  • encounter_type (EncounterType) – Type of encounter

  • +
  • own_ship_sog (float) – Own ship speed over ground [m/s]

  • +
  • min_target_ship_sog (float) – Minimum target ship speed over ground [m/s]

  • +
  • relative_sog_setting (EncounterRelativeSpeed) – Relative speed over ground setting dependent on encounter [-]

  • +
+
+
Returns:
+

target_ship_sog – Target ship speed over ground [m/s]

+
+
Return type:
+

float

+
+
+
+ +
+
+trafficgen.encounter.assign_vector_time(vector_time_range: list[float]) float
+

Assign random (uniform) vector time.

+
+
Parameters:
+

vector_time_range (list[float]) – Minimum and maximum value for vector time [min]

+
+
Returns:
+

vector_time – Vector time [min]

+
+
Return type:
+

float

+
+
+
+ +
+
+trafficgen.encounter.calculate_min_vector_length_target_ship(own_ship_position: GeoPosition, own_ship_cog: float, target_ship_position_future: GeoPosition, desired_beta: float, lat_lon0: GeoPosition) float
+

Calculate minimum vector length (target ship sog x vector).

+

This is done to ensure that ship sog is high enough to find proper situation.

+
+
Parameters:
+
    +
  • own_ship_position (GeoPosition) – Own ship initial position, latitudinal [rad] and longitudinal [rad]

  • +
  • own_ship_cog (float) – Own ship initial cog [rad]

  • +
  • target_ship_position_future (GeoPosition) – Target ship future position, latitudinal [rad] and longitudinal [rad]

  • +
  • desired_beta (float) – Desired relative bearing between own ship and target ship seen from own ship [rad]

  • +
  • lat_lon0 (GeoPosition) – Reference point, latitudinal [rad] and longitudinal [rad]

  • +
+
+
Returns:
+

min_vector_length – Minimum vector length (target ship sog x vector)

+
+
Return type:
+

float

+
+
+
+ +
+
+trafficgen.encounter.calculate_relative_bearing(position_own_ship: GeoPosition, heading_own_ship: float, position_target_ship: GeoPosition, heading_target_ship: float, lat_lon0: GeoPosition) tuple[float, float]
+

Calculate relative bearing between own ship and target ship.

+
+
Parameters:
+
    +
  • position_own_ship (GeoPosition) – Own ship position {lat, lon} [rad]

  • +
  • heading_own_ship (float) – Own ship heading [rad]

  • +
  • position_target_ship (GeoPosition) – Target ship position {lat, lon} [rad]

  • +
  • heading_target_ship (float) – Target ship heading [rad]

  • +
  • lat_lon0 (GeoPosition) – Reference point, latitudinal [rad] and longitudinal [rad]

  • +
+
+
Returns:
+

    +
  • beta (float) – Relative bearing between own ship and target ship seen from own ship [rad]

  • +
  • alpha (float) – Relative bearing between target ship and own ship seen from target ship [rad]

  • +
+

+
+
+
+ +
+
+trafficgen.encounter.calculate_ship_cog(pos_0: GeoPosition, pos_1: GeoPosition, lat_lon0: GeoPosition) float
+

Calculate ship cog between two waypoints.

+
+
Parameters:
+
    +
  • pos_0 (GeoPosition) – First waypoint {lat, lon} [rad]

  • +
  • pos_1 (GeoPosition) – Second waypoint {lat, lon} [rad]

  • +
  • lat_lon0 (GeoPosition) – Reference point, latitudinal [rad] and longitudinal [rad]

  • +
+
+
Returns:
+

cog – Ship coourse over ground [rad]

+
+
Return type:
+

float

+
+
+
+ +
+
+trafficgen.encounter.check_encounter_evolvement(own_ship: OwnShip, own_ship_cog: float, own_ship_position_future: GeoPosition, lat_lon0: GeoPosition, target_ship_sog: float, target_ship_cog: float, target_ship_position_future: GeoPosition, desired_encounter_type: EncounterType, encounter_settings: EncounterSettings) bool
+

Check encounter evolvement.

+

The generated encounter should be the same type of +encounter (head-on, crossing, give-way) also some time before the encounter is started.

+
+
Parameters:
+
    +
  • own_ship (OwnShip) – Own ship information such as initial position, sog and cog

  • +
  • own_ship_cog (float) – Own ship cog [rad]

  • +
  • own_ship_position_future (GeoPosition) – Own ship future position {lat, lon} [rad].

  • +
  • lat_lon0 (GeoPosition) – Reference point, latitudinal [rad] and longitudinal [rad]

  • +
  • target_ship_sog (float) – Target ship speed over ground [m/s]

  • +
  • target_ship_cog (float) – Target ship course over ground [rad]

  • +
  • target_ship_position_future (GeoPosition) – Target ship future position {lat, lon} [rad]

  • +
  • desired_encounter_type (EncounterType) – Desired type of encounter to be generated

  • +
  • encounter_settings (EncounterSettings) – Encounter settings

  • +
+
+
Returns:
+

encounterOK – Returns True if encounter ok, False if encounter not ok

+
+
Return type:
+

bool

+
+
+
+ +
+
+trafficgen.encounter.decide_target_ship(target_ships_static: list[ShipStatic]) ShipStatic
+

Randomly pick a target ship from a list of target ships.

+
+
Parameters:
+

target_ships (list[ShipStatic]) – List of target ships with static information

+
+
Returns:
+

target_ship – The target ship, info of type, size etc.

+
+
Return type:
+

ShipStatic

+
+
+
+ +
+
+trafficgen.encounter.define_own_ship(desired_traffic_situation: SituationInput, own_ship_static: ShipStatic, encounter_settings: EncounterSettings, lat_lon0: GeoPosition) OwnShip
+

Define own ship based on information in desired traffic situation.

+
+
Parameters:
+
    +
  • desired_traffic_situation (SituationInput) – Information about type of traffic situation to generate

  • +
  • own_ship_static (ShipStatic) – Static information of own ship.

  • +
  • encounter_settings (EncounterSettings) – Necessary setting for the encounter

  • +
  • lat_lon0 (GeoPosition) – Reference point, latitudinal [rad] and longitudinal [rad]

  • +
+
+
Returns:
+

own_ship – Own ship including static, initial and waypoints.

+
+
Return type:
+

OwnShip

+
+
+
+ +
+
+trafficgen.encounter.determine_colreg(alpha: float, beta: float, theta13_criteria: float, theta14_criteria: float, theta15_criteria: float, theta15: list[float]) EncounterType
+

Determine the colreg type.

+

Colreg type is based on alpha, relative bearing between target ship and own +ship seen from target ship, and beta, relative bearing between own ship and target ship +seen from own ship.

+
+
Parameters:
+
    +
  • alpha (float) – Relative bearing between target ship and own ship seen from target ship [rad]

  • +
  • beta (float) – Relative bearing between own ship and target ship seen from own ship [rad]

  • +
  • theta13_criteria (float) – Tolerance for “coming up with” relative bearing

  • +
  • theta14_criteria (float) – Tolerance for “reciprocal or nearly reciprocal cogs”, “when in any doubt… assume… [head-on]”

  • +
  • theta15_criteria (float) – Crossing aspect limit, used for classifying a crossing encounter

  • +
  • theta15 (list[float]) – 22.5 deg aft of the beam, used for classifying a crossing and an overtaking encounter [rad, rad]

  • +
+
+
Returns:
+

encounter_classification – Classification of the encounter

+
+
Return type:
+

EncounterType

+
+
+
+ +
+
+trafficgen.encounter.find_start_position_target_ship(own_ship_position: GeoPosition, lat_lon0: GeoPosition, own_ship_cog: float, target_ship_position_future: GeoPosition, target_ship_vector_length: float, desired_beta: float, desired_encounter_type: EncounterType, encounter_settings: EncounterSettings) tuple[GeoPosition, bool]
+

Find start position of target ship using desired beta and vector length.

+
+
Parameters:
+
    +
  • own_ship_position (GeoPosition) – Own ship position {lat, lon} [rad]

  • +
  • lat_lon0 (GeoPosition) – Reference point, latitudinal [rad] and longitudinal [rad]

  • +
  • own_ship_cog (float) – Own ship course over ground [rad]

  • +
  • target_ship_position_future (GeoPosition) – Target ship future position {lat, lon} [rad]

  • +
  • target_ship_vector_length (float) – vector length (target ship sog x vector)

  • +
  • desired_beta (float) – Desired bearing between own ship and target ship seen from own ship [rad]

  • +
  • desired_encounter_type (EncounterType) – Desired type of encounter to be generated

  • +
  • encounter_settings (EncounterSettings) – Encounter settings

  • +
+
+
Returns:
+

    +
  • start_position_target_ship (GeoPosition) – Initial position of target ship {lat, lon} [rad]

  • +
  • start_position_found (bool) – False if position not found, True if position found

  • +
+

+
+
+
+ +
+
+trafficgen.encounter.generate_encounter(desired_encounter_type: EncounterType, own_ship: OwnShip, target_ships_static: list[ShipStatic], encounter_number: int, beta_default: list[float] | float | None, relative_sog_default: float | None, vector_time_default: float | None, settings: EncounterSettings) tuple[TargetShip, bool]
+

Generate an encounter.

+
+
Parameters:
+
    +
  • desired_encounter_type (EncounterType) – Desired encounter to be generated.

  • +
  • own_ship (OwnShip) – Information about own ship that will encounter a target ship.

  • +
  • target_ships_static (list[ShipStatic]) – List of target ships including static information that may be used in an encounter.

  • +
  • encounter_number (Int) – Integer identifying the encounter.

  • +
  • beta_default (list[float] | float | None) – User defined beta. If not set, this is None [rad].

  • +
  • relative_sog_default (float | None) – User defined relative sog between own ship and target ship. If not set, this is None [m/s].

  • +
  • vector_time_default (float | None) – User defined vector time. If not set, this is None [min].

  • +
  • settings (EncounterSettings) – Encounter settings

  • +
+
+
Returns:
+

    +
  • target_ship (TargetShip) – target ship information, such as initial position, sog and cog

  • +
  • encounter_found (bool) – True=encounter found, False=encounter not found

  • +
+

+
+
+
+ +
+ +
+
+ +
+ +
+
+ + + + + \ No newline at end of file diff --git a/_autosummary/trafficgen.marine_system_simulator.html b/_autosummary/trafficgen.marine_system_simulator.html new file mode 100644 index 0000000..232b8e6 --- /dev/null +++ b/_autosummary/trafficgen.marine_system_simulator.html @@ -0,0 +1,462 @@ + + + + + + + + + trafficgen.marine_system_simulator - trafficgen 0.7.1 + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+ +
+ +
+ +
+
+
+

trafficgen.marine_system_simulator

+

The Marine Systems Simulator (MSS) is a Matlab and Simulink library for marine systems.

+

It includes models for ships, underwater vehicles, unmanned surface vehicles, and floating structures. +The library also contains guidance, navigation, and control (GNC) blocks for real-time simulation. +The algorithms are described in:

+

T. I. Fossen (2021). Handbook of Marine Craft Hydrodynamics and Motion Control. 2nd. Edition, +Wiley. ISBN-13: 978-1119575054

+

Parts of the library have been re-implemented in Python and are found below.

+

Functions

+
+ + + + + + + + + + + + +

flat2llh(x_n, y_n, lat_0, lon_0[, z_n, ...])

Compute lon lon (rad), lat lat (rad) and height h (m) for the NED coordinates (xn,yn,zn).

llh2flat(lat, lon, lat_0, lon_0[, height, ...])

Compute (north, east) for a flat Earth coordinate system from lon lon (rad) and lat lat (rad).

ssa(angle)

Return the "smallest signed angle" (SSA) or the smallest difference between two angles.

+
+
+
+trafficgen.marine_system_simulator.flat2llh(x_n: float, y_n: float, lat_0: float, lon_0: float, z_n: float = 0.0, height_ref: float = 0.0) tuple[float, float, float]
+

Compute lon lon (rad), lat lat (rad) and height h (m) for the NED coordinates (xn,yn,zn).

+

Method taken from the MSS (Marine System Simulator) toolbox which is a Matlab/Simulink +library for marine systems.

+

The method computes lon lon (rad), lat lat (rad) and height h (m) for the +NED coordinates (xn,yn,zn) using a flat Earth coordinate system defined by the WGS-84 +ellipsoid. The flat Earth coordinate origin is located at (lon_0, lat_0) with reference +height h_ref in meters above the surface of the ellipsoid. Both height and h_ref +are positive upwards, while zn is positive downwards (NED). +Author: Thor I. Fossen +Date: 20 July 2018 +Revisions: 2023-02-04 updates the formulas for lat and lon

+
+
Parameters:
+
    +
  • x_n (float) – Ship position, north [m]

  • +
  • y_n (float) – Ship position, east [m]

  • +
  • lat_0 (float) – Flat earth coordinate located at (lon_0, lat_0)

  • +
  • lon_0 (float) – Flat earth coordinate located at (lon_0, lat_0)

  • +
  • z_n (float) – Ship position, down [m], default is 0.0

  • +
  • h_ref (float) – Flat earth coordinate with reference h_ref in meters above the surface of the ellipsoid, default is 0.0

  • +
+
+
Returns:
+

    +
  • lat (float) – Ship position in lat [rad]

  • +
  • lon (float) – Ship position in lon [rad]

  • +
  • h (float) – Ship height in meters above the surface of the ellipsoid [m]

  • +
+

+
+
+
+ +
+
+trafficgen.marine_system_simulator.llh2flat(lat: float, lon: float, lat_0: float, lon_0: float, height: float = 0.0, height_ref: float = 0.0) tuple[float, float, float]
+

Compute (north, east) for a flat Earth coordinate system from lon lon (rad) and lat lat (rad).

+

Method taken from the MSS (Marine System Simulator) toolbox which is a Matlab/Simulink +library for marine systems.

+

The method computes (north, east) for a flat Earth coordinate system from lon +lon (rad) and lat lat (rad) of the WGS-84 elipsoid. The flat Earth coordinate +origin is located at (lon_0, lat_0). +Author: Thor I. Fossen +Date: 20 July 2018 +Revisions: 2023-02-04 updates the formulas for lat and lon

+
+
Parameters:
+
    +
  • lat (float) – Ship position in lat [rad]

  • +
  • lon (float) – Ship position in lon [rad]

  • +
  • lat_0 (float) – Flat earth coordinate located at (lon_0, lat_0)

  • +
  • lon_0 (float) – Flat earth coordinate located at (lon_0, lat_0)

  • +
  • h (float) – Ship height in meters above the surface of the ellipsoid, default is 0.0

  • +
  • h_ref (float) – Flat earth coordinate with reference h_ref in meters above the surface of the ellipsoid

  • +
+
+
Returns:
+

    +
  • x_n (float) – Ship position, north [m]

  • +
  • y_n (float) – Ship position, east [m]

  • +
  • z_n (float) – Ship position, down [m]

  • +
+

+
+
+
+ +
+
+trafficgen.marine_system_simulator.ssa(angle: float) float
+

Return the “smallest signed angle” (SSA) or the smallest difference between two angles.

+

Method taken from the MSS (Marine System Simulator) toolbox which is a Matlab/Simulink +library for marine systems.

+

Examples

+

angle = ssa(angle) maps an angle in rad to the interval [-pi pi)

+

Author: Thor I. Fossen +Date: 2018-09-21

+
+
Parameters:
+

angle (float) – Angle given in radius

+
+
Returns:
+

smallest_angle – “smallest signed angle” or the smallest difference between two angles

+
+
Return type:
+

float

+
+
+
+ +
+ +
+
+ +
+ +
+
+ + + + + \ No newline at end of file diff --git a/_autosummary/trafficgen.plot_traffic_situation.html b/_autosummary/trafficgen.plot_traffic_situation.html new file mode 100644 index 0000000..c8a9692 --- /dev/null +++ b/_autosummary/trafficgen.plot_traffic_situation.html @@ -0,0 +1,515 @@ + + + + + + + + + trafficgen.plot_traffic_situation - trafficgen 0.7.1 + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+ +
+ +
+ +
+
+
+

trafficgen.plot_traffic_situation

+

Functions to prepare and plot traffic situations.

+

Functions

+
+ + + + + + + + + + + + + + + + + + + + + + + + +

add_ship_to_map(ship, vector_time, lat_lon0, ...)

Add the ship to the map.

add_ship_to_plot(ship, vector_time, ...[, color])

Add the ship to the plot.

calculate_ship_outline(position, cog, lat_lon0)

Calculate the outline of the ship pointing in the direction of ship course.

calculate_vector_arrow(position, direction, ...)

Calculate the arrow with length vector pointing in the direction of ship course.

find_max_value_for_plot(ship, max_value, ...)

Find the maximum deviation from the Reference point in north and east direction.

plot_specific_traffic_situation(...)

Plot a specific situation in map.

plot_traffic_situations(traffic_situations, ...)

Plot the traffic situations in one more figures.

+
+
+
+trafficgen.plot_traffic_situation.add_ship_to_map(ship: Ship, vector_time: float, lat_lon0: GeoPosition, map_plot: Map | None, color: str = 'black') Map
+

Add the ship to the map.

+
+
Parameters:
+
    +
  • ship (Ship) – Ship information

  • +
  • vector_time (float) – Vector time [sec]

  • +
  • lat_lon0 (GeoPosition) – Reference point, latitudinal [rad] and longitudinal [rad]

  • +
  • map_plot (Map | None) – Instance of Map. If not set, instance is set to None

  • +
  • color (str) – Color of the ship. If not set, color is ‘black’

  • +
+
+
Returns:
+

map_plot – Updated instance of Map.

+
+
Return type:
+

Map

+
+
+
+ +
+
+trafficgen.plot_traffic_situation.add_ship_to_plot(ship: Ship, vector_time: float, lat_lon0: GeoPosition, axes: Axes | None, color: str = 'black') Axes
+

Add the ship to the plot.

+
+
Parameters:
+
    +
  • ship (Ship) – Ship information

  • +
  • vector_time (float) – Vector time [sec]

  • +
  • axes (Axes | None) – Instance of figure axis. If not set, instance is set to None

  • +
  • color (str) – Color of the ship. If not set, color is ‘black’

  • +
+
+
+
+ +
+
+trafficgen.plot_traffic_situation.calculate_ship_outline(position: GeoPosition, cog: float, lat_lon0: GeoPosition, ship_length: float = 100.0, ship_width: float = 15.0) list[tuple[float, float]]
+

Calculate the outline of the ship pointing in the direction of ship course.

+
+
Parameters:
+
    +
  • position (GeoPosition) – {lat}, {lon} position of the ship [rad]

  • +
  • cog (float) – Course over ground of the ship [rad]

  • +
  • lat_lon0 (GeoPosition) – Reference point, latitudinal [rad] and longitudinal [rad]

  • +
  • ship_length (float) – Ship length. If not given, ship length is set to 100

  • +
  • ship_width (float) – Ship width. If not given, ship width is set to 15

  • +
+
+
Returns:
+

ship_outline_points – Polygon points to draw the ship [deg]

+
+
Return type:
+

list[tuple[float, float]]

+
+
+
+ +
+
+trafficgen.plot_traffic_situation.calculate_vector_arrow(position: GeoPosition, direction: float, vector_length: float, lat_lon0: GeoPosition) list[tuple[float, float]]
+

Calculate the arrow with length vector pointing in the direction of ship course.

+
+
Parameters:
+
    +
  • position (GeoPosition) – {lat}, {lon} position of the ship [rad]

  • +
  • direction (float) – Direction the arrow is pointing [rad]

  • +
  • vector_length (float) – Length of vector [m]

  • +
  • lat_lon0 (GeoPosition) – Reference point, latitudinal [rad] and longitudinal [rad]

  • +
+
+
Returns:
+

arrow_points – Polygon points to draw the arrow [deg]

+
+
Return type:
+

list[tuple[float, float]]

+
+
+
+ +
+
+trafficgen.plot_traffic_situation.find_max_value_for_plot(ship: Ship, max_value: float, lat_lon0: GeoPosition) float
+

Find the maximum deviation from the Reference point in north and east direction.

+
+
Parameters:
+
    +
  • ship (Ship) – Ship information

  • +
  • max_value (float) – Maximum deviation in north, east direction [m]

  • +
  • lat_lon0 (GeoPosition) – Reference point, latitudinal [rad] and longitudinal [rad]

  • +
+
+
Returns:
+

* max_value

+
+
Return type:
+

updated maximum deviation in north, east direction [m]

+
+
+
+ +
+
+trafficgen.plot_traffic_situation.plot_specific_traffic_situation(traffic_situations: list[TrafficSituation], situation_number: int, encounter_settings: EncounterSettings) None
+

Plot a specific situation in map.

+
+
Parameters:
+
    +
  • traffic_situations (list[TrafficSituation]) – List of traffic situations that are generated

  • +
  • situation_number (int) – The specific situation to be plotted

  • +
  • encounter_settings (EncounterSettings) – Encounter settings

  • +
+
+
+
+ +
+
+trafficgen.plot_traffic_situation.plot_traffic_situations(traffic_situations: list[TrafficSituation], col: int, row: int, encounter_settings: EncounterSettings) None
+

Plot the traffic situations in one more figures.

+
+
Parameters:
+
    +
  • traffic_situations (list[TrafficSituation]) – List of traffic situations to be plotted

  • +
  • col (int) – Number of columns in each figure

  • +
  • row (int) – Number of rows in each figure

  • +
  • encounter_settings (EncounterSettings) – Encounter settings

  • +
+
+
+
+ +
+ +
+
+ +
+ +
+
+ + + + + \ No newline at end of file diff --git a/_autosummary/trafficgen.read_files.html b/_autosummary/trafficgen.read_files.html new file mode 100644 index 0000000..8423e5d --- /dev/null +++ b/_autosummary/trafficgen.read_files.html @@ -0,0 +1,602 @@ + + + + + + + + + trafficgen.read_files - trafficgen 0.7.1 + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+ +
+ +
+ +
+
+
+

trafficgen.read_files

+

Functions to read the files needed to build one or more traffic situations.

+

Functions

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

camel_to_snake(string)

Convert a camel case string to snake case.

convert_encounters(encounters)

Convert encounter data which is given in maritime units to SI units.

convert_keys_to_snake_case(data)

Convert keys in a nested dictionary from camel case to snake case.

convert_own_ship_initial_data(initial)

Convert own ship initial data which is given in maritime units to SI units.

convert_own_ship_waypoints(waypoints)

Convert own ship waypoint data which is given in maritime units to SI units.

convert_settings_data_from_maritime_to_si_units(...)

Convert situation data which is given in maritime units to SI units.

convert_ship_data_from_maritime_to_si_units(ship)

Convert ship static data which is given in maritime units to SI units.

convert_situation_data_from_maritime_to_si_units(...)

Convert situation data which is given in maritime units to SI units.

read_encounter_settings_file(settings_file)

Read encounter settings file.

read_generated_situation_files(situation_folder)

Read the generated traffic situation files.

read_own_ship_static_file(own_ship_static_file)

Read own ship static data from file.

read_situation_files(situation_folder)

Read traffic situation files.

read_target_ship_static_files(target_ship_folder)

Read target ship static data files.

+
+
+
+trafficgen.read_files.camel_to_snake(string: str) str
+

Convert a camel case string to snake case.

+
+ +
+
+trafficgen.read_files.convert_encounters(encounters: list[Encounter]) list[Encounter]
+

Convert encounter data which is given in maritime units to SI units.

+
+
Parameters:
+

encounters (list[Encounter]) – Encounter data to be converted

+
+
Returns:
+

encounters – Converted encounter data

+
+
Return type:
+

list[Encounter]

+
+
+
+ +
+
+trafficgen.read_files.convert_keys_to_snake_case(data: dict[str, Any]) dict[str, Any]
+

Convert keys in a nested dictionary from camel case to snake case.

+
+ +
+
+trafficgen.read_files.convert_own_ship_initial_data(initial: Initial) Initial
+

Convert own ship initial data which is given in maritime units to SI units.

+
+
Parameters:
+

initial (Initial) – Own ship initial data to be converted

+
+
Returns:
+

initial – Converted own ship initial data

+
+
Return type:
+

Initial

+
+
+
+ +
+
+trafficgen.read_files.convert_own_ship_waypoints(waypoints: list[Waypoint]) list[Waypoint]
+

Convert own ship waypoint data which is given in maritime units to SI units.

+
+
Parameters:
+

waypoints (list[Waypoint]) – Waypoint data to be converted

+
+
Returns:
+

waypoints – Converted waypoint data

+
+
Return type:
+

list[Waypoint]

+
+
+
+ +
+
+trafficgen.read_files.convert_settings_data_from_maritime_to_si_units(encounter_settings: EncounterSettings) EncounterSettings
+

Convert situation data which is given in maritime units to SI units.

+
+
Parameters:
+

encounter_settings (EncounterSettings) – Encounter settings data to be converted

+
+
Returns:
+

encounter_settings – Converted encounter settings data

+
+
Return type:
+

EncounterSettings

+
+
+
+ +
+
+trafficgen.read_files.convert_ship_data_from_maritime_to_si_units(ship: ShipStatic) ShipStatic
+

Convert ship static data which is given in maritime units to SI units.

+
+
Parameters:
+

ship (ShipStatic) – Ship data to be converted

+
+
Returns:
+

ship – Converted ship data

+
+
Return type:
+

ShipStatic

+
+
+
+ +
+
+trafficgen.read_files.convert_situation_data_from_maritime_to_si_units(situation: SituationInput) SituationInput
+

Convert situation data which is given in maritime units to SI units.

+
+
Parameters:
+

situation (SituationInput) – Situation data to be converted

+
+
Returns:
+

situation – Converted situation data

+
+
Return type:
+

SituationInput

+
+
+
+ +
+
+trafficgen.read_files.read_encounter_settings_file(settings_file: Path) EncounterSettings
+

Read encounter settings file.

+
+
Parameters:
+

settings_file (Path) – Path to the encounter setting file

+
+
Returns:
+

encounter_settings – Settings for the encounter

+
+
Return type:
+

EncounterSettings

+
+
+
+ +
+
+trafficgen.read_files.read_generated_situation_files(situation_folder: Path) list[TrafficSituation]
+

Read the generated traffic situation files. Used for testing the trafficgen algorithm.

+
+
Parameters:
+

situation_folder (Path) – Path to the folder where situation files are found

+
+
Returns:
+

situations – List of desired traffic situations

+
+
Return type:
+

list[TrafficSituation]

+
+
+
+ +
+
+trafficgen.read_files.read_own_ship_static_file(own_ship_static_file: Path) ShipStatic
+

Read own ship static data from file.

+
+
Parameters:
+

own_ship_file (Path) – Path to the own_ship_static_file file

+
+
Returns:
+

own_ship – Own_ship static information

+
+
Return type:
+

ShipStatic

+
+
+
+ +
+
+trafficgen.read_files.read_situation_files(situation_folder: Path) list[SituationInput]
+

Read traffic situation files.

+
+
Parameters:
+

situation_folder (Path) – Path to the folder where situation files are found

+
+
Returns:
+

situations – List of desired traffic situations

+
+
Return type:
+

list[SituationInput]

+
+
+
+ +
+
+trafficgen.read_files.read_target_ship_static_files(target_ship_folder: Path) list[ShipStatic]
+

Read target ship static data files.

+
+
Parameters:
+

target_ship_folder (Path) – Path to the folder where target ships are found

+
+
Returns:
+

target_ships_static – List of different target ships with static information

+
+
Return type:
+

list[ShipStatic]

+
+
+
+ +
+ +
+
+ +
+ +
+
+ + + + + \ No newline at end of file diff --git a/_autosummary/trafficgen.ship_traffic_generator.html b/_autosummary/trafficgen.ship_traffic_generator.html new file mode 100644 index 0000000..048c674 --- /dev/null +++ b/_autosummary/trafficgen.ship_traffic_generator.html @@ -0,0 +1,377 @@ + + + + + + + + + trafficgen.ship_traffic_generator - trafficgen 0.7.1 + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+ +
+ +
+ +
+
+
+

trafficgen.ship_traffic_generator

+

Functions to generate traffic situations.

+

Functions

+
+ + + + + + +

generate_traffic_situations(...)

Generate traffic situations based on the provided input files.

+
+
+
+trafficgen.ship_traffic_generator.generate_traffic_situations(situation_folder: Path, own_ship_file: Path, target_ship_folder: Path, settings_file: Path) list[TrafficSituation]
+

Generate traffic situations based on the provided input files.

+
+
Parameters:
+
    +
  • situation_folder (Path) – Path to the folder containing situation files.

  • +
  • own_ship_file (Path) – Path to the file containing own ship static data.

  • +
  • target_ship_folder (Path) – Path to the folder containing target ship static files.

  • +
  • settings_file (Path) – Path to the file containing encounter settings.

  • +
+
+
Returns:
+

A list of generated traffic situations.

+
+
Return type:
+

list[TrafficSituation]

+
+
+
+ +
+ +
+
+ +
+ +
+
+ + + + + \ No newline at end of file diff --git a/_autosummary/trafficgen.utils.html b/_autosummary/trafficgen.utils.html new file mode 100644 index 0000000..ae72d10 --- /dev/null +++ b/_autosummary/trafficgen.utils.html @@ -0,0 +1,673 @@ + + + + + + + + + trafficgen.utils - trafficgen 0.7.1 + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+ +
+ +
+ +
+
+
+

trafficgen.utils

+

Utility functions that are used by several other functions.

+

Functions

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

calculate_bearing_between_waypoints(...)

Calculate the bearing in rad between two waypoints.

calculate_destination_along_track(...)

Calculate the destination along the track between two waypoints when distance along the track is given.

calculate_distance(position_prev, position_next)

Calculate the distance in meter between two waypoints.

calculate_position_along_track_using_waypoints(...)

Calculate the position along the track using waypoints.

calculate_position_at_certain_time(position, ...)

Calculate the position of the ship at a given time.

convert_angle_0_to_2_pi_to_minus_pi_to_pi(...)

Angle conversion functions.

convert_angle_minus_pi_to_pi_to_0_to_2_pi(...)

Angle conversion functions.

deg_2_rad(angle_in_degrees)

Convert angle given in degrees to angle give in radians.

knot_2_m_pr_s(speed_in_knot)

Convert ship speed in knots to meters pr second.

m_2_nm(length_in_m)

Convert length given in meters to length given in nautical miles.

m_pr_s_2_knot(speed_in_m_pr_s)

Convert ship speed in knots to meters pr second.

min_2_s(time_in_min)

Convert time given in minutes to time given in seconds.

nm_2_m(length_in_nm)

Convert length given in nautical miles to length given in meters.

rad_2_deg(angle_in_radians)

Convert angle given in radians to angle give in degrees.

+
+
+
+trafficgen.utils.calculate_bearing_between_waypoints(position_prev: GeoPosition, position_next: GeoPosition) float
+

Calculate the bearing in rad between two waypoints.

+
+
Parameters:
+
    +
  • position_prev (GeoPosition) – Previous waypoint {lat, lon}[rad]

  • +
  • position_next (GeoPosition) – Next waypoint {lat, lon}[rad]

  • +
+
+
Returns:
+

bearing – Bearing between waypoints [rad]

+
+
Return type:
+

float

+
+
+
+ +
+
+trafficgen.utils.calculate_destination_along_track(position_prev: GeoPosition, distance: float, bearing: float) GeoPosition
+

Calculate the destination along the track between two waypoints when distance along the track is given.

+
+
Parameters:
+
    +
  • position_prev (GeoPosition) – Previous waypoint {lat, lon}[rad]

  • +
  • distance (float) – Distance to travel [m]

  • +
  • bearing (float) – Bearing from previous waypoint to next waypoint [rad]

  • +
+
+
Returns:
+

destination – Destination along the track {lat, lon}[rad]

+
+
Return type:
+

GeoPosition

+
+
+
+ +
+
+trafficgen.utils.calculate_distance(position_prev: GeoPosition, position_next: GeoPosition) float
+

Calculate the distance in meter between two waypoints.

+
+
Parameters:
+
    +
  • position_prev (GeoPosition) – Previous waypoint {lat, lon}[rad]

  • +
  • position_next (GeoPosition) – Next waypoint {lat, lon}[rad]

  • +
+
+
Returns:
+

distance – Distance between waypoints [m]

+
+
Return type:
+

float

+
+
+
+ +
+
+trafficgen.utils.calculate_position_along_track_using_waypoints(waypoints: list[Waypoint], inital_speed: float, vector_time: float) GeoPosition
+

Calculate the position along the track using waypoints.

+

The position along the track is calculated based on initial position +and delta time, and constant speed and course.

+
+
Parameters:
+
    +
  • waypoints (list[Waypoint]) – List of ship waypoints Initial ship position {lat, lon}[rad]

  • +
  • inital_speed (float) – Initial ship speed [m/s]

  • +
  • vector_time (float) – Delta time from now to the time new position is being calculated [sec]

  • +
+
+
Returns:
+

position – Estimated ship position in delta time seconds {lat, lon}[rad]

+
+
Return type:
+

GeoPosition

+
+
+
+ +
+
+trafficgen.utils.calculate_position_at_certain_time(position: GeoPosition, lat_lon0: GeoPosition, sog: float, cog: float, delta_time: float) GeoPosition
+

Calculate the position of the ship at a given time.

+

The calculated position is based on initial position and delta time, in addition to constant speed and course.

+
+
Parameters:
+
    +
  • position (GeoPosition) – Initial ship position {lat, lon} [rad]

  • +
  • lat_lon0 (GeoPosition) – Reference position {lat, lon} [rad]

  • +
  • sog (float) – Ship speed over ground[m/s]

  • +
  • cog (float) – Ship course over ground [rad]

  • +
  • delta_time (float) – Delta time from now to the time new position is being calculated [minutes]

  • +
+
+
Returns:
+

position – Estimated ship position in delta time minutes {lat, lon} [rad]

+
+
Return type:
+

GeoPosition

+
+
+
+ +
+
+trafficgen.utils.convert_angle_0_to_2_pi_to_minus_pi_to_pi(angle_2_pi: float) float
+

Angle conversion functions.

+

Convert an angle given in the region 0 to 2*pi degrees to an +angle given in the region -pi to pi degrees.

+
+
Parameters:
+

angle_2_pi (float) – Angle given in the region 0 to 2pi radians

+
+
Returns:
+

angle_pi – Angle given in the region -pi to pi radians

+
+
Return type:
+

float

+
+
+
+ +
+
+trafficgen.utils.convert_angle_minus_pi_to_pi_to_0_to_2_pi(angle_pi: float) float
+

Angle conversion functions.

+

Convert an angle given in the region -pi to pi degrees to an +angle given in the region 0 to 2pi radians.

+
+
Parameters:
+

angle_pi (float) – Angle given in the region -pi to pi radians

+
+
Returns:
+

angle_2_pi – Angle given in the region 0 to 2pi radians

+
+
Return type:
+

float

+
+
+
+ +
+
+trafficgen.utils.deg_2_rad(angle_in_degrees: float) float
+

Convert angle given in degrees to angle give in radians.

+
+
Parameters:
+

angle_in_degrees (float) – Angle given in degrees

+
+
Returns:
+

angle_in_radians – Angle given in radians

+
+
Return type:
+

float

+
+
+
+ +
+
+trafficgen.utils.knot_2_m_pr_s(speed_in_knot: float) float
+

Convert ship speed in knots to meters pr second.

+
+
Parameters:
+

speed_in_knot (float) – Ship speed given in knots

+
+
Returns:
+

speed_in_m_pr_s – Ship speed in meters pr second

+
+
Return type:
+

float

+
+
+
+ +
+
+trafficgen.utils.m_2_nm(length_in_m: float) float
+

Convert length given in meters to length given in nautical miles.

+
+
Parameters:
+

length_in_m (float) – Length given in meters

+
+
Returns:
+

length_in_nm – Length given in nautical miles

+
+
Return type:
+

float

+
+
+
+ +
+
+trafficgen.utils.m_pr_s_2_knot(speed_in_m_pr_s: float) float
+

Convert ship speed in knots to meters pr second.

+
+
Parameters:
+

speed_in_m_pr_s (float) – Ship speed given in meters pr second

+
+
Returns:
+

    +
  • speed_in_knot (float)

  • +
  • Ship speed in knots

  • +
+

+
+
+
+ +
+
+trafficgen.utils.min_2_s(time_in_min: float) float
+

Convert time given in minutes to time given in seconds.

+
+
Parameters:
+

time_in_min (float) – Time given in minutes

+
+
Returns:
+

time_in_s – Time in seconds

+
+
Return type:
+

float

+
+
+
+ +
+
+trafficgen.utils.nm_2_m(length_in_nm: float) float
+

Convert length given in nautical miles to length given in meters.

+
+
Parameters:
+

length_in_nm (float) – Length given in nautical miles

+
+
Returns:
+

length_in_m – Length given in meters

+
+
Return type:
+

float

+
+
+
+ +
+
+trafficgen.utils.rad_2_deg(angle_in_radians: float) float
+

Convert angle given in radians to angle give in degrees.

+
+
Parameters:
+

angle_in_degrees (float) – Angle given in degrees

+
+
Returns:
+

angle_in_radians – Angle given in radians

+
+
Return type:
+

float

+
+
+
+ +
+ +
+
+ +
+ +
+
+ + + + + \ No newline at end of file diff --git a/_autosummary/trafficgen.write_traffic_situation_to_file.html b/_autosummary/trafficgen.write_traffic_situation_to_file.html new file mode 100644 index 0000000..7b8551d --- /dev/null +++ b/_autosummary/trafficgen.write_traffic_situation_to_file.html @@ -0,0 +1,411 @@ + + + + + + + + + trafficgen.write_traffic_situation_to_file - trafficgen 0.7.1 + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+ +
+ +
+ +
+
+
+

trafficgen.write_traffic_situation_to_file

+

Functions to clean traffic situations data before writing it to a json file.

+

Functions

+
+ + + + + + + + + + + + +

convert_ship_data_from_si_units_to_maritime(ship)

Convert ship data which is given in SI units to maritime units.

convert_situation_data_from_si_units_to__maritime(...)

Convert situation data which is given in SI units to maritime units.

write_traffic_situations_to_json_file(...)

Write traffic situations to json file.

+
+
+
+trafficgen.write_traffic_situation_to_file.convert_ship_data_from_si_units_to_maritime(ship: T_ship) T_ship
+

Convert ship data which is given in SI units to maritime units.

+
+
Parameters:
+

ship (T_ship) – Ship data

+
+
Returns:
+

ship – Converted ship data

+
+
Return type:
+

T_ship

+
+
+
+ +
+
+trafficgen.write_traffic_situation_to_file.convert_situation_data_from_si_units_to__maritime(situation: TrafficSituation) TrafficSituation
+

Convert situation data which is given in SI units to maritime units.

+
+
Parameters:
+

situation (TrafficSituation) – Traffic situation data

+
+
Returns:
+

situation – Converted traffic situation data

+
+
Return type:
+

TrafficSituation

+
+
+
+ +
+
+trafficgen.write_traffic_situation_to_file.write_traffic_situations_to_json_file(situations: list[TrafficSituation], write_folder: Path) None
+

Write traffic situations to json file.

+
+
Parameters:
+
    +
  • traffic_situations (list[TrafficSituation]) – List of traffic situations to be written to file

  • +
  • write_folder (Path) – Path to the folder where the json files is to be written

  • +
+
+
+
+ +
+ +
+
+ +
+ +
+
+ + + + + \ No newline at end of file diff --git a/_sources/CHANGELOG.md.txt b/_sources/CHANGELOG.md.txt new file mode 100644 index 0000000..ff772da --- /dev/null +++ b/_sources/CHANGELOG.md.txt @@ -0,0 +1,2 @@ +```{include} ../../CHANGELOG.md +``` \ No newline at end of file diff --git a/_sources/LICENSE.md.txt b/_sources/LICENSE.md.txt new file mode 100644 index 0000000..947acdb --- /dev/null +++ b/_sources/LICENSE.md.txt @@ -0,0 +1,3 @@ +# LICENSE +```{include} ../../LICENSE +``` \ No newline at end of file diff --git a/_sources/README.md.txt b/_sources/README.md.txt new file mode 100644 index 0000000..060259b --- /dev/null +++ b/_sources/README.md.txt @@ -0,0 +1,2 @@ +```{include} ../../README.md +``` \ No newline at end of file diff --git a/_sources/STYLEGUIDE.md.txt b/_sources/STYLEGUIDE.md.txt new file mode 100644 index 0000000..8648352 --- /dev/null +++ b/_sources/STYLEGUIDE.md.txt @@ -0,0 +1,2 @@ +```{include} ../../STYLEGUIDE.md +``` \ No newline at end of file diff --git a/_sources/_autosummary/trafficgen.check_land_crossing.rst.txt b/_sources/_autosummary/trafficgen.check_land_crossing.rst.txt new file mode 100644 index 0000000..19b8c99 --- /dev/null +++ b/_sources/_autosummary/trafficgen.check_land_crossing.rst.txt @@ -0,0 +1,13 @@ +trafficgen.check\_land\_crossing +================================ + +.. automodule:: trafficgen.check_land_crossing + :members: + + + + .. rubric:: Functions + .. autosummary:: + + path_crosses_land + \ No newline at end of file diff --git a/_sources/_autosummary/trafficgen.encounter.rst.txt b/_sources/_autosummary/trafficgen.encounter.rst.txt new file mode 100644 index 0000000..7ab14ef --- /dev/null +++ b/_sources/_autosummary/trafficgen.encounter.rst.txt @@ -0,0 +1,26 @@ +trafficgen.encounter +==================== + +.. automodule:: trafficgen.encounter + :members: + + + + .. rubric:: Functions + .. autosummary:: + + assign_beta + assign_beta_from_list + assign_future_position_to_target_ship + assign_sog_to_target_ship + assign_vector_time + calculate_min_vector_length_target_ship + calculate_relative_bearing + calculate_ship_cog + check_encounter_evolvement + decide_target_ship + define_own_ship + determine_colreg + find_start_position_target_ship + generate_encounter + \ No newline at end of file diff --git a/_sources/_autosummary/trafficgen.marine_system_simulator.rst.txt b/_sources/_autosummary/trafficgen.marine_system_simulator.rst.txt new file mode 100644 index 0000000..2cc4f23 --- /dev/null +++ b/_sources/_autosummary/trafficgen.marine_system_simulator.rst.txt @@ -0,0 +1,15 @@ +trafficgen.marine\_system\_simulator +==================================== + +.. automodule:: trafficgen.marine_system_simulator + :members: + + + + .. rubric:: Functions + .. autosummary:: + + flat2llh + llh2flat + ssa + \ No newline at end of file diff --git a/_sources/_autosummary/trafficgen.plot_traffic_situation.rst.txt b/_sources/_autosummary/trafficgen.plot_traffic_situation.rst.txt new file mode 100644 index 0000000..c022e45 --- /dev/null +++ b/_sources/_autosummary/trafficgen.plot_traffic_situation.rst.txt @@ -0,0 +1,19 @@ +trafficgen.plot\_traffic\_situation +=================================== + +.. automodule:: trafficgen.plot_traffic_situation + :members: + + + + .. rubric:: Functions + .. autosummary:: + + add_ship_to_map + add_ship_to_plot + calculate_ship_outline + calculate_vector_arrow + find_max_value_for_plot + plot_specific_traffic_situation + plot_traffic_situations + \ No newline at end of file diff --git a/_sources/_autosummary/trafficgen.read_files.rst.txt b/_sources/_autosummary/trafficgen.read_files.rst.txt new file mode 100644 index 0000000..eb08b2c --- /dev/null +++ b/_sources/_autosummary/trafficgen.read_files.rst.txt @@ -0,0 +1,25 @@ +trafficgen.read\_files +====================== + +.. automodule:: trafficgen.read_files + :members: + + + + .. rubric:: Functions + .. autosummary:: + + camel_to_snake + convert_encounters + convert_keys_to_snake_case + convert_own_ship_initial_data + convert_own_ship_waypoints + convert_settings_data_from_maritime_to_si_units + convert_ship_data_from_maritime_to_si_units + convert_situation_data_from_maritime_to_si_units + read_encounter_settings_file + read_generated_situation_files + read_own_ship_static_file + read_situation_files + read_target_ship_static_files + \ No newline at end of file diff --git a/_sources/_autosummary/trafficgen.ship_traffic_generator.rst.txt b/_sources/_autosummary/trafficgen.ship_traffic_generator.rst.txt new file mode 100644 index 0000000..e59d482 --- /dev/null +++ b/_sources/_autosummary/trafficgen.ship_traffic_generator.rst.txt @@ -0,0 +1,13 @@ +trafficgen.ship\_traffic\_generator +=================================== + +.. automodule:: trafficgen.ship_traffic_generator + :members: + + + + .. rubric:: Functions + .. autosummary:: + + generate_traffic_situations + \ No newline at end of file diff --git a/_sources/_autosummary/trafficgen.utils.rst.txt b/_sources/_autosummary/trafficgen.utils.rst.txt new file mode 100644 index 0000000..ff2f0d3 --- /dev/null +++ b/_sources/_autosummary/trafficgen.utils.rst.txt @@ -0,0 +1,26 @@ +trafficgen.utils +================ + +.. automodule:: trafficgen.utils + :members: + + + + .. rubric:: Functions + .. autosummary:: + + calculate_bearing_between_waypoints + calculate_destination_along_track + calculate_distance + calculate_position_along_track_using_waypoints + calculate_position_at_certain_time + convert_angle_0_to_2_pi_to_minus_pi_to_pi + convert_angle_minus_pi_to_pi_to_0_to_2_pi + deg_2_rad + knot_2_m_pr_s + m_2_nm + m_pr_s_2_knot + min_2_s + nm_2_m + rad_2_deg + \ No newline at end of file diff --git a/_sources/_autosummary/trafficgen.write_traffic_situation_to_file.rst.txt b/_sources/_autosummary/trafficgen.write_traffic_situation_to_file.rst.txt new file mode 100644 index 0000000..54e7af0 --- /dev/null +++ b/_sources/_autosummary/trafficgen.write_traffic_situation_to_file.rst.txt @@ -0,0 +1,15 @@ +trafficgen.write\_traffic\_situation\_to\_file +============================================== + +.. automodule:: trafficgen.write_traffic_situation_to_file + :members: + + + + .. rubric:: Functions + .. autosummary:: + + convert_ship_data_from_si_units_to_maritime + convert_situation_data_from_si_units_to__maritime + write_traffic_situations_to_json_file + \ No newline at end of file diff --git a/_sources/api.rst.txt b/_sources/api.rst.txt new file mode 100644 index 0000000..dd4b477 --- /dev/null +++ b/_sources/api.rst.txt @@ -0,0 +1,7 @@ +API Reference +============= + +.. toctree:: + :maxdepth: 4 + + trafficgen diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt new file mode 100644 index 0000000..2590a13 --- /dev/null +++ b/_sources/index.rst.txt @@ -0,0 +1,26 @@ +.. my-package documentation master file, created by + sphinx-quickstart on Wed Jul 6 21:16:21 2022. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Ship Traffic Generator Documentation +==================================== + +.. toctree:: + :maxdepth: 4 + :caption: Contents: + + README + usage + input_files + api + CHANGELOG + STYLEGUIDE + LICENSE + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` diff --git a/_sources/input_files.rst.txt b/_sources/input_files.rst.txt new file mode 100644 index 0000000..3ec3995 --- /dev/null +++ b/_sources/input_files.rst.txt @@ -0,0 +1,228 @@ +=========== +Input files +=========== + +Situation files +~~~~~~~~~~~~~~~ +The situation files specify the traffic situations to be generated. The files are written in JSON format +and a predefined set of situation files with number of encounters in a situation ranging from 1 to 3 are located in the +`src/trafficgen/data/baseline_situations_input` directory. + +Below are some examples given on how to specify a situation: + +Example 1: Complete specified situation:: + + { + "title": "HO", + "description": "A head on situation with one target ship.", + "ownShip": { + "initial": { + "position": { + "lat": 58.763449, + "lon": 10.490654 + }, + "sog": 10.0, + "cog": 0.0, + "heading": 0.0, + "navStatus": "Under way using engine" + } + }, + "encounters": [ + { + "desiredEncounterType": "head-on", + "beta": 2.0, + "relativeSpeed": 1.2, + "vectorTime": 15.0 + } + ] + } + +The values are giben in maritime units. The `common_vector` is given in minutes. For radar plotting (plotting vessel positions and relative motions), +the `common_vector` and `vector_time` are used together with ship speed to display where the ship will be in e.g. 10 minutes +(Common vector is the common time vector used on a radar plot, e.g 10, 15, 20 minutes. The length of the arrow in the plot +will then be the speed times this time vector). +Speed and course of the own ship, which is the ship to be tested, are given in knots and degrees, respectively. +The own ship position is given in latitudinal and longitudinal (degree). +The reference point is the initial position of own ship. + +An encounter may be fully described as shown above, but the user may also deside to input less data, +as demonstrated in Example 2. Desired encounter type is mandatory, +while the `beta`, `relative_speed` and `vector_time` parameters are optional: + + * `desired_encounter_type` is either head-on, overtaking-give-way, overtaking-stand-on, crossing-give-way, and crossing-stand-on. + * `beta` is the relative bearing between the own ship and the target ship as seen from the own shop, given in degrees. + * `relative_speed` is relative speed between the own ship and the target ship as seen from the own ship, such that a relative speed of 1.2 means that the target ship's speed is 20% higher than the speed of the own ship. + +An encounter is built using a maximum meeting distance [nm], see the paper linked in the introduction for more info. +At some time in the future, given by the `vector_time`, the target ship will be located somewhere inside a circle +with a radius given by `max_meeting_distance` and a center point given by the own ship position. This is not necessarily the +closest point of approach. + +The `max_meeting_distance` parameter is common for all encounters and is specified in `src/trafficgen/settings/encounter_settings.json`. + +Example 2: Minimum specified situation:: + + { + "title": "HO", + "description": "A head on situation with one target ship.", + "ownShip": { + "initial": { + "position": { + "lat": 58.763449, + "lon": 10.490654 + }, + "sog": 10.0, + "cog": 0.0, + "heading": 0.0, + "navStatus": "Under way using engine" + } + }, + "encounters": [ + { + "desiredEncounterType": "head-on", + } + ] + } + + +You can also request the generation of several traffic situations of the same encounter type by specifying `num_situations`: + +Example 3: Generate multiple situations using `numSituations`:: + + { + "title": "HO", + "description": "A head on situation with one target ship.", + "numSituations": 5 + "ownShip": { + "initial": { + "position": { + "lat": 58.763449, + "lon": 10.490654 + }, + "sog": 10.0, + "cog": 0.0, + "heading": 0.0, + "navStatus": "Under way using engine" + } + }, + "encounters": [ + { + "desiredEncounterType": "head-on", + } + ] + } + +The next example show how it is possible to give a range for the relative bearing between own ship and target ship + +Example 4: Assign range for `beta`:: + + { + "title": "CR_GW", + "common_vector": 10.0, + "own_ship": { + "speed": 7.0, + "course": 0.0, + "position": { + "lat": 58.763449, + "lon": 10.490654 + } + }, + "encounter": [ + { + "desired_encounter_type": "crossing-give-way", + "beta": [45.0,120.0] + } + ] + } + +Own ship file +~~~~~~~~~~~~~~~ +The own ship file specify the own ship which is the ship to be controlled by the control system under test. +The file is written in JSON format and located in the `src/trafficgen/data/own_ship`:: + + { + "dimensions": { + "length": 122, + "width": 20, + "height": 8 + }, + "sogMax": 17, + "mmsi": 257847600, + "name": "BASTO VI", + "shipType": "Passenger" + } + +The values are given in maritime units. sogMax is the maximum speed over ground in knots, and the dimensions are given in meters. + +Target ship files +~~~~~~~~~~~~~~~~~ +The directory `src/trafficgen/data/target_ships` contains a set of target ships that can be used in the traffic generation. +The file is written in JSON format and is on the following structure:: + + { + "dimensions": { + "length": 122, + "width": 20, + "height": 8 + }, + "sogMax": 17, + "shipType": "Passenger" + } + +Encounter settings +~~~~~~~~~~~~~~~~~~ +The encounter setting file spesified parameters that are common from +all encounters. The file is written in JSON format and located in the `src/trafficgen/settings/encounter_settings.json`:: + + { + "classification": { + "theta13_criteria": 67.5, + "theta14_criteria": 5.0, + "theta15_criteria": 5.0, + "theta15": [ + 112.5, + 247.5 + ] + }, + "relative_speed": { + "overtaking_stand_on": [ + 1.5, + 2 + ], + "overtaking_give_way": [ + 0.25, + 0.75 + ], + "head_on": [ + 0.5, + 1.5 + ], + "crossing_give_way": [ + 0.5, + 1.5 + ], + "crossing_stand_on": [ + 0.5, + 1.5 + ] + }, + "vector_range": [ + 10.0, + 30.0 + ], + "situation_length": 30.0, + "max_meeting_distance": 0.0, + "common_vector": 5.0, + "evolve_time": 120.0, + "disable_land_check": true + } + +The values are given in maritime units. The `theta13_criteria`, `theta14_criteria` and `theta15_criteria` are the criteria for the classification of the encounters. +The `theta15` is the range for the relative bearing between own ship and target ship. +The `relative_speed` is the range for the relative speed between own ship and target ship. +The `vector_range` is the range for the vector time. +The `situation_length` is the length of the situation in minutes. +The `max_meeting_distance` is the maximum meeting distance in nautical miles. +The `common_vector` is the common time vector used on a radar plot. +The `evolve_time` is the time in minutes for the situation to evolve. +The `disable_land_check` is a boolean value that determines if the land check should be disabled or not. diff --git a/_sources/trafficgen.rst.txt b/_sources/trafficgen.rst.txt new file mode 100644 index 0000000..3426c91 --- /dev/null +++ b/_sources/trafficgen.rst.txt @@ -0,0 +1,19 @@ +trafficgen package +================== + +Modules +------- + +.. autosummary:: + :toctree: _autosummary + :template: custom-module.rst + :recursive: + + trafficgen.ship_traffic_generator + trafficgen.read_files + trafficgen.encounter + trafficgen.check_land_crossing + trafficgen.marine_system_simulator + trafficgen.plot_traffic_situation + trafficgen.write_traffic_situation_to_file + trafficgen.utils diff --git a/_sources/usage.rst.txt b/_sources/usage.rst.txt new file mode 100644 index 0000000..b9cb17a --- /dev/null +++ b/_sources/usage.rst.txt @@ -0,0 +1,58 @@ +===== +Usage +===== + +To use Traffic Generator in a project:: + + import trafficgen + +To use Traffic Generator as a command line tool for generating traffic situations, write:: + + trafficgen gen-situation + +The command line tool takes different input options:: + + -s, --situations PATH Folders with situations (default=./baseline_situations_input/) + -t, --targets PATH Folder with target configurations (default=./target_ships/) + -c, --settings PATH Path to settings file (default=./settings/encounter_settings.json) + --visualize Plot visualization + --col INTEGER Number of columns for plot, may be used with visualize (default=10) + --row INTEGER Number of rows for plot, may be used with visualize (default=6) + --visualize-situation INTEGER Plot individual traffic situation, specify INTEGER value + -o, --output PATH Output folder (default=None) + --help Show this message and exit. + +Example:: + + trafficgen gen-situation -s ./data/example_situations_input -o ./data/test_output_1 + +Situations +~~~~~~~~~~ +When generating situations without specifying where the desired situations (``--situation``) are found, the +default path, which is ``default=./baseline_situations_input/``, will be used. + +Baseline situations +~~~~~~~~~~~~~~~~~~~ +The baseline situations are a set of generic traffic situations covering head-on, overtaking stand-on/give-way +and crossing stand-on/give-way encounters. To cover the combination of encounters for 1, 2 and 3 target ships, +there are in total 55 baseline situations. The input files for generating these situations are found in +``./baseline_situations_input/`` + +Plotting +~~~~~~~~ +Plotting all generated traffic situations +----------------------------------------- +All the generated situations are displayed if using ``--visualize``. This will pop up one or more plot windows, +which show all the traffic situations. The number of colums and rows for the plots (per figure) can be specified by +using ``--col`` and ``--row``, respectively. + +Individual plots with map background +------------------------------------ +A specific encounter is visualized by using ``--visualize-situation INTEGER``, e.g.:: + + trafficgen gen-situation -s ./data/example_situations_input -o ./data/test_output_1 --visualize-situation 2 + +This will open a browser window/tab with an OpenStreetMap background and the traffic situation +radar plot as an overlay. +Note that the integer needs to be within the range of the number of generated situations, +for example 1 - 12 if you generated 12 situations. diff --git a/_static/DNV_logo_RGB.jpg b/_static/DNV_logo_RGB.jpg new file mode 100644 index 0000000000000000000000000000000000000000..136fe620f88821ed5b5455cc64326fae3a52a047 GIT binary patch literal 202826 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 aP!ymjKv96A07U_c0u%-Qw<)mS{eJ-a*w+F8 literal 0 HcmV?d00001 diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 0000000..7ebbd6d --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,914 @@ +/* + * Sphinx stylesheet -- basic theme. + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin-top: 10px; +} + +ul.search li { + padding: 5px 0; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/debug.css b/_static/debug.css new file mode 100644 index 0000000..74d4aec --- /dev/null +++ b/_static/debug.css @@ -0,0 +1,69 @@ +/* + This CSS file should be overridden by the theme authors. It's + meant for debugging and developing the skeleton that this theme provides. +*/ +body { + font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, + "Apple Color Emoji", "Segoe UI Emoji"; + background: lavender; +} +.sb-announcement { + background: rgb(131, 131, 131); +} +.sb-announcement__inner { + background: black; + color: white; +} +.sb-header { + background: lightskyblue; +} +.sb-header__inner { + background: royalblue; + color: white; +} +.sb-header-secondary { + background: lightcyan; +} +.sb-header-secondary__inner { + background: cornflowerblue; + color: white; +} +.sb-sidebar-primary { + background: lightgreen; +} +.sb-main { + background: blanchedalmond; +} +.sb-main__inner { + background: antiquewhite; +} +.sb-header-article { + background: lightsteelblue; +} +.sb-article-container { + background: snow; +} +.sb-article-main { + background: white; +} +.sb-footer-article { + background: lightpink; +} +.sb-sidebar-secondary { + background: lightgoldenrodyellow; +} +.sb-footer-content { + background: plum; +} +.sb-footer-content__inner { + background: palevioletred; +} +.sb-footer { + background: pink; +} +.sb-footer__inner { + background: salmon; +} +.sb-article { + background: white; +} diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 0000000..0398ebb --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,149 @@ +/* + * Base JavaScript utilities for all Sphinx HTML documentation. + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 0000000..74f3179 --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '0.7.1', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 0000000000000000000000000000000000000000..a858a410e4faa62ce324d814e4b816fff83a6fb3 GIT binary patch literal 286 zcmV+(0pb3MP)s`hMrGg#P~ix$^RISR_I47Y|r1 z_CyJOe}D1){SET-^Amu_i71Lt6eYfZjRyw@I6OQAIXXHDfiX^GbOlHe=Ae4>0m)d(f|Me07*qoM6N<$f}vM^LjV8( literal 0 HcmV?d00001 diff --git a/_static/language_data.js b/_static/language_data.js new file mode 100644 index 0000000..c7fe6c6 --- /dev/null +++ b/_static/language_data.js @@ -0,0 +1,192 @@ +/* + * This script contains the language-specific data used by searchtools.js, + * namely the list of stopwords, stemmer, scorer and splitter. + */ + +var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; + + +/* Non-minified version is copied as a separate JS file, if available */ + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/_static/minus.png b/_static/minus.png new file mode 100644 index 0000000000000000000000000000000000000000..d96755fdaf8bb2214971e0db9c1fd3077d7c419d GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^+#t*WBp7;*Yy1LIik>cxAr*|t7R?Mi>2?kWtu=nj kDsEF_5m^0CR;1wuP-*O&G^0G}KYk!hp00i_>zopr08q^qX#fBK literal 0 HcmV?d00001 diff --git a/_static/my_package.svg b/_static/my_package.svg new file mode 100644 index 0000000..1e02cbe --- /dev/null +++ b/_static/my_package.svg @@ -0,0 +1 @@ +mypackagelogo svg1224 x 1223 \ No newline at end of file diff --git a/_static/plus.png b/_static/plus.png new file mode 100644 index 0000000000000000000000000000000000000000..7107cec93a979b9a5f64843235a16651d563ce2d GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^+#t*WBp7;*Yy1LIik>cxAr*|t7R?Mi>2?kWtu>-2 m3q%Vub%g%s<8sJhVPMczOq}xhg9DJoz~JfX=d#Wzp$Pyb1r*Kz literal 0 HcmV?d00001 diff --git a/_static/pygments.css b/_static/pygments.css new file mode 100644 index 0000000..f71bfbf --- /dev/null +++ b/_static/pygments.css @@ -0,0 +1,258 @@ +.highlight pre { line-height: 125%; } +.highlight td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +.highlight span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +.highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f8f8f8; } +.highlight .c { color: #8F5902; font-style: italic } /* Comment */ +.highlight .err { color: #A40000; border: 1px solid #EF2929 } /* Error */ +.highlight .g { color: #000 } /* Generic */ +.highlight .k { color: #204A87; font-weight: bold } /* Keyword */ +.highlight .l { color: #000 } /* Literal */ +.highlight .n { color: #000 } /* Name */ +.highlight .o { color: #CE5C00; font-weight: bold } /* Operator */ +.highlight .x { color: #000 } /* Other */ +.highlight .p { color: #000; font-weight: bold } /* Punctuation */ +.highlight .ch { color: #8F5902; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #8F5902; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #8F5902; font-style: italic } /* Comment.Preproc */ +.highlight .cpf { color: #8F5902; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #8F5902; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #8F5902; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #A40000 } /* Generic.Deleted */ +.highlight .ge { color: #000; font-style: italic } /* Generic.Emph */ +.highlight .ges { color: #000; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.highlight .gr { color: #EF2929 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #000; font-style: italic } /* Generic.Output */ +.highlight .gp { color: #8F5902 } /* Generic.Prompt */ +.highlight .gs { color: #000; font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #A40000; font-weight: bold } /* Generic.Traceback */ +.highlight .kc { color: #204A87; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #204A87; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #204A87; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #204A87; font-weight: bold } /* Keyword.Pseudo */ +.highlight .kr { color: #204A87; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #204A87; font-weight: bold } /* Keyword.Type */ +.highlight .ld { color: #000 } /* Literal.Date */ +.highlight .m { color: #0000CF; font-weight: bold } /* Literal.Number */ +.highlight .s { color: #4E9A06 } /* Literal.String */ +.highlight .na { color: #C4A000 } /* Name.Attribute */ +.highlight .nb { color: #204A87 } /* Name.Builtin */ +.highlight .nc { color: #000 } /* Name.Class */ +.highlight .no { color: #000 } /* Name.Constant */ +.highlight .nd { color: #5C35CC; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #CE5C00 } /* Name.Entity */ +.highlight .ne { color: #C00; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #000 } /* Name.Function */ +.highlight .nl { color: #F57900 } /* Name.Label */ +.highlight .nn { color: #000 } /* Name.Namespace */ +.highlight .nx { color: #000 } /* Name.Other */ +.highlight .py { color: #000 } /* Name.Property */ +.highlight .nt { color: #204A87; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #000 } /* Name.Variable */ +.highlight .ow { color: #204A87; font-weight: bold } /* Operator.Word */ +.highlight .pm { color: #000; font-weight: bold } /* Punctuation.Marker */ +.highlight .w { color: #F8F8F8 } /* Text.Whitespace */ +.highlight .mb { color: #0000CF; font-weight: bold } /* Literal.Number.Bin */ +.highlight .mf { color: #0000CF; font-weight: bold } /* Literal.Number.Float */ +.highlight .mh { color: #0000CF; font-weight: bold } /* Literal.Number.Hex */ +.highlight .mi { color: #0000CF; font-weight: bold } /* Literal.Number.Integer */ +.highlight .mo { color: #0000CF; font-weight: bold } /* Literal.Number.Oct */ +.highlight .sa { color: #4E9A06 } /* Literal.String.Affix */ +.highlight .sb { color: #4E9A06 } /* Literal.String.Backtick */ +.highlight .sc { color: #4E9A06 } /* Literal.String.Char */ +.highlight .dl { color: #4E9A06 } /* Literal.String.Delimiter */ +.highlight .sd { color: #8F5902; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4E9A06 } /* Literal.String.Double */ +.highlight .se { color: #4E9A06 } /* Literal.String.Escape */ +.highlight .sh { color: #4E9A06 } /* Literal.String.Heredoc */ +.highlight .si { color: #4E9A06 } /* Literal.String.Interpol */ +.highlight .sx { color: #4E9A06 } /* Literal.String.Other */ +.highlight .sr { color: #4E9A06 } /* Literal.String.Regex */ +.highlight .s1 { color: #4E9A06 } /* Literal.String.Single */ +.highlight .ss { color: #4E9A06 } /* Literal.String.Symbol */ +.highlight .bp { color: #3465A4 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #000 } /* Name.Function.Magic */ +.highlight .vc { color: #000 } /* Name.Variable.Class */ +.highlight .vg { color: #000 } /* Name.Variable.Global */ +.highlight .vi { color: #000 } /* Name.Variable.Instance */ +.highlight .vm { color: #000 } /* Name.Variable.Magic */ +.highlight .il { color: #0000CF; font-weight: bold } /* Literal.Number.Integer.Long */ +@media not print { +body[data-theme="dark"] .highlight pre { line-height: 125%; } +body[data-theme="dark"] .highlight td.linenos .normal { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; } +body[data-theme="dark"] .highlight span.linenos { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; } +body[data-theme="dark"] .highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +body[data-theme="dark"] .highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +body[data-theme="dark"] .highlight .hll { background-color: #404040 } +body[data-theme="dark"] .highlight { background: #202020; color: #D0D0D0 } +body[data-theme="dark"] .highlight .c { color: #ABABAB; font-style: italic } /* Comment */ +body[data-theme="dark"] .highlight .err { color: #A61717; background-color: #E3D2D2 } /* Error */ +body[data-theme="dark"] .highlight .esc { color: #D0D0D0 } /* Escape */ +body[data-theme="dark"] .highlight .g { color: #D0D0D0 } /* Generic */ +body[data-theme="dark"] .highlight .k { color: #6EBF26; font-weight: bold } /* Keyword */ +body[data-theme="dark"] .highlight .l { color: #D0D0D0 } /* Literal */ +body[data-theme="dark"] .highlight .n { color: #D0D0D0 } /* Name */ +body[data-theme="dark"] .highlight .o { color: #D0D0D0 } /* Operator */ +body[data-theme="dark"] .highlight .x { color: #D0D0D0 } /* Other */ +body[data-theme="dark"] .highlight .p { color: #D0D0D0 } /* Punctuation */ +body[data-theme="dark"] .highlight .ch { color: #ABABAB; font-style: italic } /* Comment.Hashbang */ +body[data-theme="dark"] .highlight .cm { color: #ABABAB; font-style: italic } /* Comment.Multiline */ +body[data-theme="dark"] .highlight .cp { color: #FF3A3A; font-weight: bold } /* Comment.Preproc */ +body[data-theme="dark"] .highlight .cpf { color: #ABABAB; font-style: italic } /* Comment.PreprocFile */ +body[data-theme="dark"] .highlight .c1 { color: #ABABAB; font-style: italic } /* Comment.Single */ +body[data-theme="dark"] .highlight .cs { color: #E50808; font-weight: bold; background-color: #520000 } /* Comment.Special */ +body[data-theme="dark"] .highlight .gd { color: #FF3A3A } /* Generic.Deleted */ +body[data-theme="dark"] .highlight .ge { color: #D0D0D0; font-style: italic } /* Generic.Emph */ +body[data-theme="dark"] .highlight .ges { color: #D0D0D0; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +body[data-theme="dark"] .highlight .gr { color: #FF3A3A } /* Generic.Error */ +body[data-theme="dark"] .highlight .gh { color: #FFF; font-weight: bold } /* Generic.Heading */ +body[data-theme="dark"] .highlight .gi { color: #589819 } /* Generic.Inserted */ +body[data-theme="dark"] .highlight .go { color: #CCC } /* Generic.Output */ +body[data-theme="dark"] .highlight .gp { color: #AAA } /* Generic.Prompt */ +body[data-theme="dark"] .highlight .gs { color: #D0D0D0; font-weight: bold } /* Generic.Strong */ +body[data-theme="dark"] .highlight .gu { color: #FFF; text-decoration: underline } /* Generic.Subheading */ +body[data-theme="dark"] .highlight .gt { color: #FF3A3A } /* Generic.Traceback */ +body[data-theme="dark"] .highlight .kc { color: #6EBF26; font-weight: bold } /* Keyword.Constant */ +body[data-theme="dark"] .highlight .kd { color: #6EBF26; font-weight: bold } /* Keyword.Declaration */ +body[data-theme="dark"] .highlight .kn { color: #6EBF26; font-weight: bold } /* Keyword.Namespace */ +body[data-theme="dark"] .highlight .kp { color: #6EBF26 } /* Keyword.Pseudo */ +body[data-theme="dark"] .highlight .kr { color: #6EBF26; font-weight: bold } /* Keyword.Reserved */ +body[data-theme="dark"] .highlight .kt { color: #6EBF26; font-weight: bold } /* Keyword.Type */ +body[data-theme="dark"] .highlight .ld { color: #D0D0D0 } /* Literal.Date */ +body[data-theme="dark"] .highlight .m { color: #51B2FD } /* Literal.Number */ +body[data-theme="dark"] .highlight .s { color: #ED9D13 } /* Literal.String */ +body[data-theme="dark"] .highlight .na { color: #BBB } /* Name.Attribute */ +body[data-theme="dark"] .highlight .nb { color: #2FBCCD } /* Name.Builtin */ +body[data-theme="dark"] .highlight .nc { color: #71ADFF; text-decoration: underline } /* Name.Class */ +body[data-theme="dark"] .highlight .no { color: #40FFFF } /* Name.Constant */ +body[data-theme="dark"] .highlight .nd { color: #FFA500 } /* Name.Decorator */ +body[data-theme="dark"] .highlight .ni { color: #D0D0D0 } /* Name.Entity */ +body[data-theme="dark"] .highlight .ne { color: #BBB } /* Name.Exception */ +body[data-theme="dark"] .highlight .nf { color: #71ADFF } /* Name.Function */ +body[data-theme="dark"] .highlight .nl { color: #D0D0D0 } /* Name.Label */ +body[data-theme="dark"] .highlight .nn { color: #71ADFF; text-decoration: underline } /* Name.Namespace */ +body[data-theme="dark"] .highlight .nx { color: #D0D0D0 } /* Name.Other */ +body[data-theme="dark"] .highlight .py { color: #D0D0D0 } /* Name.Property */ +body[data-theme="dark"] .highlight .nt { color: #6EBF26; font-weight: bold } /* Name.Tag */ +body[data-theme="dark"] .highlight .nv { color: #40FFFF } /* Name.Variable */ +body[data-theme="dark"] .highlight .ow { color: #6EBF26; font-weight: bold } /* Operator.Word */ +body[data-theme="dark"] .highlight .pm { color: #D0D0D0 } /* Punctuation.Marker */ +body[data-theme="dark"] .highlight .w { color: #666 } /* Text.Whitespace */ +body[data-theme="dark"] .highlight .mb { color: #51B2FD } /* Literal.Number.Bin */ +body[data-theme="dark"] .highlight .mf { color: #51B2FD } /* Literal.Number.Float */ +body[data-theme="dark"] .highlight .mh { color: #51B2FD } /* Literal.Number.Hex */ +body[data-theme="dark"] .highlight .mi { color: #51B2FD } /* Literal.Number.Integer */ +body[data-theme="dark"] .highlight .mo { color: #51B2FD } /* Literal.Number.Oct */ +body[data-theme="dark"] .highlight .sa { color: #ED9D13 } /* Literal.String.Affix */ +body[data-theme="dark"] .highlight .sb { color: #ED9D13 } /* Literal.String.Backtick */ +body[data-theme="dark"] .highlight .sc { color: #ED9D13 } /* Literal.String.Char */ +body[data-theme="dark"] .highlight .dl { color: #ED9D13 } /* Literal.String.Delimiter */ +body[data-theme="dark"] .highlight .sd { color: #ED9D13 } /* Literal.String.Doc */ +body[data-theme="dark"] .highlight .s2 { color: #ED9D13 } /* Literal.String.Double */ +body[data-theme="dark"] .highlight .se { color: #ED9D13 } /* Literal.String.Escape */ +body[data-theme="dark"] .highlight .sh { color: #ED9D13 } /* Literal.String.Heredoc */ +body[data-theme="dark"] .highlight .si { color: #ED9D13 } /* Literal.String.Interpol */ +body[data-theme="dark"] .highlight .sx { color: #FFA500 } /* Literal.String.Other */ +body[data-theme="dark"] .highlight .sr { color: #ED9D13 } /* Literal.String.Regex */ +body[data-theme="dark"] .highlight .s1 { color: #ED9D13 } /* Literal.String.Single */ +body[data-theme="dark"] .highlight .ss { color: #ED9D13 } /* Literal.String.Symbol */ +body[data-theme="dark"] .highlight .bp { color: #2FBCCD } /* Name.Builtin.Pseudo */ +body[data-theme="dark"] .highlight .fm { color: #71ADFF } /* Name.Function.Magic */ +body[data-theme="dark"] .highlight .vc { color: #40FFFF } /* Name.Variable.Class */ +body[data-theme="dark"] .highlight .vg { color: #40FFFF } /* Name.Variable.Global */ +body[data-theme="dark"] .highlight .vi { color: #40FFFF } /* Name.Variable.Instance */ +body[data-theme="dark"] .highlight .vm { color: #40FFFF } /* Name.Variable.Magic */ +body[data-theme="dark"] .highlight .il { color: #51B2FD } /* Literal.Number.Integer.Long */ +@media (prefers-color-scheme: dark) { +body:not([data-theme="light"]) .highlight pre { line-height: 125%; } +body:not([data-theme="light"]) .highlight td.linenos .normal { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; } +body:not([data-theme="light"]) .highlight span.linenos { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; } +body:not([data-theme="light"]) .highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +body:not([data-theme="light"]) .highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +body:not([data-theme="light"]) .highlight .hll { background-color: #404040 } +body:not([data-theme="light"]) .highlight { background: #202020; color: #D0D0D0 } +body:not([data-theme="light"]) .highlight .c { color: #ABABAB; font-style: italic } /* Comment */ +body:not([data-theme="light"]) .highlight .err { color: #A61717; background-color: #E3D2D2 } /* Error */ +body:not([data-theme="light"]) .highlight .esc { color: #D0D0D0 } /* Escape */ +body:not([data-theme="light"]) .highlight .g { color: #D0D0D0 } /* Generic */ +body:not([data-theme="light"]) .highlight .k { color: #6EBF26; font-weight: bold } /* Keyword */ +body:not([data-theme="light"]) .highlight .l { color: #D0D0D0 } /* Literal */ +body:not([data-theme="light"]) .highlight .n { color: #D0D0D0 } /* Name */ +body:not([data-theme="light"]) .highlight .o { color: #D0D0D0 } /* Operator */ +body:not([data-theme="light"]) .highlight .x { color: #D0D0D0 } /* Other */ +body:not([data-theme="light"]) .highlight .p { color: #D0D0D0 } /* Punctuation */ +body:not([data-theme="light"]) .highlight .ch { color: #ABABAB; font-style: italic } /* Comment.Hashbang */ +body:not([data-theme="light"]) .highlight .cm { color: #ABABAB; font-style: italic } /* Comment.Multiline */ +body:not([data-theme="light"]) .highlight .cp { color: #FF3A3A; font-weight: bold } /* Comment.Preproc */ +body:not([data-theme="light"]) .highlight .cpf { color: #ABABAB; font-style: italic } /* Comment.PreprocFile */ +body:not([data-theme="light"]) .highlight .c1 { color: #ABABAB; font-style: italic } /* Comment.Single */ +body:not([data-theme="light"]) .highlight .cs { color: #E50808; font-weight: bold; background-color: #520000 } /* Comment.Special */ +body:not([data-theme="light"]) .highlight .gd { color: #FF3A3A } /* Generic.Deleted */ +body:not([data-theme="light"]) .highlight .ge { color: #D0D0D0; font-style: italic } /* Generic.Emph */ +body:not([data-theme="light"]) .highlight .ges { color: #D0D0D0; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +body:not([data-theme="light"]) .highlight .gr { color: #FF3A3A } /* Generic.Error */ +body:not([data-theme="light"]) .highlight .gh { color: #FFF; font-weight: bold } /* Generic.Heading */ +body:not([data-theme="light"]) .highlight .gi { color: #589819 } /* Generic.Inserted */ +body:not([data-theme="light"]) .highlight .go { color: #CCC } /* Generic.Output */ +body:not([data-theme="light"]) .highlight .gp { color: #AAA } /* Generic.Prompt */ +body:not([data-theme="light"]) .highlight .gs { color: #D0D0D0; font-weight: bold } /* Generic.Strong */ +body:not([data-theme="light"]) .highlight .gu { color: #FFF; text-decoration: underline } /* Generic.Subheading */ +body:not([data-theme="light"]) .highlight .gt { color: #FF3A3A } /* Generic.Traceback */ +body:not([data-theme="light"]) .highlight .kc { color: #6EBF26; font-weight: bold } /* Keyword.Constant */ +body:not([data-theme="light"]) .highlight .kd { color: #6EBF26; font-weight: bold } /* Keyword.Declaration */ +body:not([data-theme="light"]) .highlight .kn { color: #6EBF26; font-weight: bold } /* Keyword.Namespace */ +body:not([data-theme="light"]) .highlight .kp { color: #6EBF26 } /* Keyword.Pseudo */ +body:not([data-theme="light"]) .highlight .kr { color: #6EBF26; font-weight: bold } /* Keyword.Reserved */ +body:not([data-theme="light"]) .highlight .kt { color: #6EBF26; font-weight: bold } /* Keyword.Type */ +body:not([data-theme="light"]) .highlight .ld { color: #D0D0D0 } /* Literal.Date */ +body:not([data-theme="light"]) .highlight .m { color: #51B2FD } /* Literal.Number */ +body:not([data-theme="light"]) .highlight .s { color: #ED9D13 } /* Literal.String */ +body:not([data-theme="light"]) .highlight .na { color: #BBB } /* Name.Attribute */ +body:not([data-theme="light"]) .highlight .nb { color: #2FBCCD } /* Name.Builtin */ +body:not([data-theme="light"]) .highlight .nc { color: #71ADFF; text-decoration: underline } /* Name.Class */ +body:not([data-theme="light"]) .highlight .no { color: #40FFFF } /* Name.Constant */ +body:not([data-theme="light"]) .highlight .nd { color: #FFA500 } /* Name.Decorator */ +body:not([data-theme="light"]) .highlight .ni { color: #D0D0D0 } /* Name.Entity */ +body:not([data-theme="light"]) .highlight .ne { color: #BBB } /* Name.Exception */ +body:not([data-theme="light"]) .highlight .nf { color: #71ADFF } /* Name.Function */ +body:not([data-theme="light"]) .highlight .nl { color: #D0D0D0 } /* Name.Label */ +body:not([data-theme="light"]) .highlight .nn { color: #71ADFF; text-decoration: underline } /* Name.Namespace */ +body:not([data-theme="light"]) .highlight .nx { color: #D0D0D0 } /* Name.Other */ +body:not([data-theme="light"]) .highlight .py { color: #D0D0D0 } /* Name.Property */ +body:not([data-theme="light"]) .highlight .nt { color: #6EBF26; font-weight: bold } /* Name.Tag */ +body:not([data-theme="light"]) .highlight .nv { color: #40FFFF } /* Name.Variable */ +body:not([data-theme="light"]) .highlight .ow { color: #6EBF26; font-weight: bold } /* Operator.Word */ +body:not([data-theme="light"]) .highlight .pm { color: #D0D0D0 } /* Punctuation.Marker */ +body:not([data-theme="light"]) .highlight .w { color: #666 } /* Text.Whitespace */ +body:not([data-theme="light"]) .highlight .mb { color: #51B2FD } /* Literal.Number.Bin */ +body:not([data-theme="light"]) .highlight .mf { color: #51B2FD } /* Literal.Number.Float */ +body:not([data-theme="light"]) .highlight .mh { color: #51B2FD } /* Literal.Number.Hex */ +body:not([data-theme="light"]) .highlight .mi { color: #51B2FD } /* Literal.Number.Integer */ +body:not([data-theme="light"]) .highlight .mo { color: #51B2FD } /* Literal.Number.Oct */ +body:not([data-theme="light"]) .highlight .sa { color: #ED9D13 } /* Literal.String.Affix */ +body:not([data-theme="light"]) .highlight .sb { color: #ED9D13 } /* Literal.String.Backtick */ +body:not([data-theme="light"]) .highlight .sc { color: #ED9D13 } /* Literal.String.Char */ +body:not([data-theme="light"]) .highlight .dl { color: #ED9D13 } /* Literal.String.Delimiter */ +body:not([data-theme="light"]) .highlight .sd { color: #ED9D13 } /* Literal.String.Doc */ +body:not([data-theme="light"]) .highlight .s2 { color: #ED9D13 } /* Literal.String.Double */ +body:not([data-theme="light"]) .highlight .se { color: #ED9D13 } /* Literal.String.Escape */ +body:not([data-theme="light"]) .highlight .sh { color: #ED9D13 } /* Literal.String.Heredoc */ +body:not([data-theme="light"]) .highlight .si { color: #ED9D13 } /* Literal.String.Interpol */ +body:not([data-theme="light"]) .highlight .sx { color: #FFA500 } /* Literal.String.Other */ +body:not([data-theme="light"]) .highlight .sr { color: #ED9D13 } /* Literal.String.Regex */ +body:not([data-theme="light"]) .highlight .s1 { color: #ED9D13 } /* Literal.String.Single */ +body:not([data-theme="light"]) .highlight .ss { color: #ED9D13 } /* Literal.String.Symbol */ +body:not([data-theme="light"]) .highlight .bp { color: #2FBCCD } /* Name.Builtin.Pseudo */ +body:not([data-theme="light"]) .highlight .fm { color: #71ADFF } /* Name.Function.Magic */ +body:not([data-theme="light"]) .highlight .vc { color: #40FFFF } /* Name.Variable.Class */ +body:not([data-theme="light"]) .highlight .vg { color: #40FFFF } /* Name.Variable.Global */ +body:not([data-theme="light"]) .highlight .vi { color: #40FFFF } /* Name.Variable.Instance */ +body:not([data-theme="light"]) .highlight .vm { color: #40FFFF } /* Name.Variable.Magic */ +body:not([data-theme="light"]) .highlight .il { color: #51B2FD } /* Literal.Number.Integer.Long */ +} +} \ No newline at end of file diff --git a/_static/scripts/furo-extensions.js b/_static/scripts/furo-extensions.js new file mode 100644 index 0000000..e69de29 diff --git a/_static/scripts/furo.js b/_static/scripts/furo.js new file mode 100644 index 0000000..0abb2af --- /dev/null +++ b/_static/scripts/furo.js @@ -0,0 +1,3 @@ +/*! For license information please see furo.js.LICENSE.txt */ +(()=>{var t={856:function(t,e,n){var o,r;r=void 0!==n.g?n.g:"undefined"!=typeof window?window:this,o=function(){return function(t){"use strict";var e={navClass:"active",contentClass:"active",nested:!1,nestedClass:"active",offset:0,reflow:!1,events:!0},n=function(t,e,n){if(n.settings.events){var o=new CustomEvent(t,{bubbles:!0,cancelable:!0,detail:n});e.dispatchEvent(o)}},o=function(t){var e=0;if(t.offsetParent)for(;t;)e+=t.offsetTop,t=t.offsetParent;return e>=0?e:0},r=function(t){t&&t.sort((function(t,e){return o(t.content)=Math.max(document.body.scrollHeight,document.documentElement.scrollHeight,document.body.offsetHeight,document.documentElement.offsetHeight,document.body.clientHeight,document.documentElement.clientHeight)},l=function(t,e){var n=t[t.length-1];if(function(t,e){return!(!s()||!c(t.content,e,!0))}(n,e))return n;for(var o=t.length-1;o>=0;o--)if(c(t[o].content,e))return t[o]},a=function(t,e){if(e.nested&&t.parentNode){var n=t.parentNode.closest("li");n&&(n.classList.remove(e.nestedClass),a(n,e))}},i=function(t,e){if(t){var o=t.nav.closest("li");o&&(o.classList.remove(e.navClass),t.content.classList.remove(e.contentClass),a(o,e),n("gumshoeDeactivate",o,{link:t.nav,content:t.content,settings:e}))}},u=function(t,e){if(e.nested){var n=t.parentNode.closest("li");n&&(n.classList.add(e.nestedClass),u(n,e))}};return function(o,c){var s,a,d,f,m,v={setup:function(){s=document.querySelectorAll(o),a=[],Array.prototype.forEach.call(s,(function(t){var e=document.getElementById(decodeURIComponent(t.hash.substr(1)));e&&a.push({nav:t,content:e})})),r(a)},detect:function(){var t=l(a,m);t?d&&t.content===d.content||(i(d,m),function(t,e){if(t){var o=t.nav.closest("li");o&&(o.classList.add(e.navClass),t.content.classList.add(e.contentClass),u(o,e),n("gumshoeActivate",o,{link:t.nav,content:t.content,settings:e}))}}(t,m),d=t):d&&(i(d,m),d=null)}},h=function(e){f&&t.cancelAnimationFrame(f),f=t.requestAnimationFrame(v.detect)},g=function(e){f&&t.cancelAnimationFrame(f),f=t.requestAnimationFrame((function(){r(a),v.detect()}))};return v.destroy=function(){d&&i(d,m),t.removeEventListener("scroll",h,!1),m.reflow&&t.removeEventListener("resize",g,!1),a=null,s=null,d=null,f=null,m=null},m=function(){var t={};return Array.prototype.forEach.call(arguments,(function(e){for(var n in e){if(!e.hasOwnProperty(n))return;t[n]=e[n]}})),t}(e,c||{}),v.setup(),v.detect(),t.addEventListener("scroll",h,!1),m.reflow&&t.addEventListener("resize",g,!1),v}}(r)}.apply(e,[]),void 0===o||(t.exports=o)}},e={};function n(o){var r=e[o];if(void 0!==r)return r.exports;var c=e[o]={exports:{}};return t[o].call(c.exports,c,c.exports,n),c.exports}n.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return n.d(e,{a:e}),e},n.d=(t,e)=>{for(var o in e)n.o(e,o)&&!n.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:e[o]})},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),n.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),(()=>{"use strict";var t=n(856),e=n.n(t),o=null,r=null,c=document.documentElement.scrollTop;const s=64;function l(){const t=localStorage.getItem("theme")||"auto";var e;"light"!==(e=window.matchMedia("(prefers-color-scheme: dark)").matches?"auto"===t?"light":"light"==t?"dark":"auto":"auto"===t?"dark":"dark"==t?"light":"auto")&&"dark"!==e&&"auto"!==e&&(console.error(`Got invalid theme mode: ${e}. Resetting to auto.`),e="auto"),document.body.dataset.theme=e,localStorage.setItem("theme",e),console.log(`Changed to ${e} mode.`)}function a(){!function(){const t=document.getElementsByClassName("theme-toggle");Array.from(t).forEach((t=>{t.addEventListener("click",l)}))}(),function(){let t=0,e=!1;window.addEventListener("scroll",(function(n){t=window.scrollY,e||(window.requestAnimationFrame((function(){var n;(function(t){const e=Math.floor(r.getBoundingClientRect().top);console.log(`headerTop: ${e}`),0==e&&t!=e?r.classList.add("scrolled"):r.classList.remove("scrolled")})(n=t),function(t){tc&&document.documentElement.classList.remove("show-back-to-top"),c=t}(n),function(t){null!==o&&(0==t?o.scrollTo(0,0):Math.ceil(t)>=Math.floor(document.documentElement.scrollHeight-window.innerHeight)?o.scrollTo(0,o.scrollHeight):document.querySelector(".scroll-current"))}(n),e=!1})),e=!0)})),window.scroll()}(),null!==o&&new(e())(".toc-tree a",{reflow:!0,recursive:!0,navClass:"scroll-current",offset:()=>{let t=parseFloat(getComputedStyle(document.documentElement).fontSize);return r.getBoundingClientRect().height+2.5*t+1}})}document.addEventListener("DOMContentLoaded",(function(){document.body.parentNode.classList.remove("no-js"),r=document.querySelector("header"),o=document.querySelector(".toc-scroll"),a()}))})()})(); +//# sourceMappingURL=furo.js.map \ No newline at end of file diff --git a/_static/scripts/furo.js.LICENSE.txt b/_static/scripts/furo.js.LICENSE.txt new file mode 100644 index 0000000..1632189 --- /dev/null +++ b/_static/scripts/furo.js.LICENSE.txt @@ -0,0 +1,7 @@ +/*! + * gumshoejs v5.1.2 (patched by @pradyunsg) + * A simple, framework-agnostic scrollspy script. + * (c) 2019 Chris Ferdinandi + * MIT License + * http://github.com/cferdinandi/gumshoe + */ diff --git a/_static/scripts/furo.js.map b/_static/scripts/furo.js.map new file mode 100644 index 0000000..80ea12b --- /dev/null +++ b/_static/scripts/furo.js.map @@ -0,0 +1 @@ +{"version":3,"file":"scripts/furo.js","mappings":";iCAAA,MAQWA,SAWS,IAAX,EAAAC,EACH,EAAAA,EACkB,oBAAXC,OACLA,OACAC,KAbO,EAAF,WACP,OAaJ,SAAUD,GACR,aAMA,IAAIE,EAAW,CAEbC,SAAU,SACVC,aAAc,SAGdC,QAAQ,EACRC,YAAa,SAGbC,OAAQ,EACRC,QAAQ,EAGRC,QAAQ,GA6BNC,EAAY,SAAUC,EAAMC,EAAMC,GAEpC,GAAKA,EAAOC,SAASL,OAArB,CAGA,IAAIM,EAAQ,IAAIC,YAAYL,EAAM,CAChCM,SAAS,EACTC,YAAY,EACZL,OAAQA,IAIVD,EAAKO,cAAcJ,EAVgB,CAWrC,EAOIK,EAAe,SAAUR,GAC3B,IAAIS,EAAW,EACf,GAAIT,EAAKU,aACP,KAAOV,GACLS,GAAYT,EAAKW,UACjBX,EAAOA,EAAKU,aAGhB,OAAOD,GAAY,EAAIA,EAAW,CACpC,EAMIG,EAAe,SAAUC,GACvBA,GACFA,EAASC,MAAK,SAAUC,EAAOC,GAG7B,OAFcR,EAAaO,EAAME,SACnBT,EAAaQ,EAAMC,UACF,EACxB,CACT,GAEJ,EAwCIC,EAAW,SAAUlB,EAAME,EAAUiB,GACvC,IAAIC,EAASpB,EAAKqB,wBACd1B,EAnCU,SAAUO,GAExB,MAA+B,mBAApBA,EAASP,OACX2B,WAAWpB,EAASP,UAItB2B,WAAWpB,EAASP,OAC7B,CA2Be4B,CAAUrB,GACvB,OAAIiB,EAEAK,SAASJ,EAAOD,OAAQ,KACvB/B,EAAOqC,aAAeC,SAASC,gBAAgBC,cAG7CJ,SAASJ,EAAOS,IAAK,KAAOlC,CACrC,EAMImC,EAAa,WACf,OACEC,KAAKC,KAAK5C,EAAOqC,YAAcrC,EAAO6C,cAnCjCF,KAAKG,IACVR,SAASS,KAAKC,aACdV,SAASC,gBAAgBS,aACzBV,SAASS,KAAKE,aACdX,SAASC,gBAAgBU,aACzBX,SAASS,KAAKP,aACdF,SAASC,gBAAgBC,aAkC7B,EAmBIU,EAAY,SAAUzB,EAAUX,GAClC,IAAIqC,EAAO1B,EAASA,EAAS2B,OAAS,GACtC,GAbgB,SAAUC,EAAMvC,GAChC,SAAI4B,MAAgBZ,EAASuB,EAAKxB,QAASf,GAAU,GAEvD,CAUMwC,CAAYH,EAAMrC,GAAW,OAAOqC,EACxC,IAAK,IAAII,EAAI9B,EAAS2B,OAAS,EAAGG,GAAK,EAAGA,IACxC,GAAIzB,EAASL,EAAS8B,GAAG1B,QAASf,GAAW,OAAOW,EAAS8B,EAEjE,EAOIC,EAAmB,SAAUC,EAAK3C,GAEpC,GAAKA,EAAST,QAAWoD,EAAIC,WAA7B,CAGA,IAAIC,EAAKF,EAAIC,WAAWE,QAAQ,MAC3BD,IAGLA,EAAGE,UAAUC,OAAOhD,EAASR,aAG7BkD,EAAiBG,EAAI7C,GAV0B,CAWjD,EAOIiD,EAAa,SAAUC,EAAOlD,GAEhC,GAAKkD,EAAL,CAGA,IAAIL,EAAKK,EAAMP,IAAIG,QAAQ,MACtBD,IAGLA,EAAGE,UAAUC,OAAOhD,EAASX,UAC7B6D,EAAMnC,QAAQgC,UAAUC,OAAOhD,EAASV,cAGxCoD,EAAiBG,EAAI7C,GAGrBJ,EAAU,oBAAqBiD,EAAI,CACjCM,KAAMD,EAAMP,IACZ5B,QAASmC,EAAMnC,QACff,SAAUA,IAjBM,CAmBpB,EAOIoD,EAAiB,SAAUT,EAAK3C,GAElC,GAAKA,EAAST,OAAd,CAGA,IAAIsD,EAAKF,EAAIC,WAAWE,QAAQ,MAC3BD,IAGLA,EAAGE,UAAUM,IAAIrD,EAASR,aAG1B4D,EAAeP,EAAI7C,GAVS,CAW9B,EA6LA,OA1JkB,SAAUsD,EAAUC,GAKpC,IACIC,EAAU7C,EAAU8C,EAASC,EAAS1D,EADtC2D,EAAa,CAUjBA,MAAmB,WAEjBH,EAAWhC,SAASoC,iBAAiBN,GAGrC3C,EAAW,GAGXkD,MAAMC,UAAUC,QAAQC,KAAKR,GAAU,SAAUjB,GAE/C,IAAIxB,EAAUS,SAASyC,eACrBC,mBAAmB3B,EAAK4B,KAAKC,OAAO,KAEjCrD,GAGLJ,EAAS0D,KAAK,CACZ1B,IAAKJ,EACLxB,QAASA,GAEb,IAGAL,EAAaC,EACf,EAKAgD,OAAoB,WAElB,IAAIW,EAASlC,EAAUzB,EAAUX,GAG5BsE,EASDb,GAAWa,EAAOvD,UAAY0C,EAAQ1C,UAG1CkC,EAAWQ,EAASzD,GAzFT,SAAUkD,EAAOlD,GAE9B,GAAKkD,EAAL,CAGA,IAAIL,EAAKK,EAAMP,IAAIG,QAAQ,MACtBD,IAGLA,EAAGE,UAAUM,IAAIrD,EAASX,UAC1B6D,EAAMnC,QAAQgC,UAAUM,IAAIrD,EAASV,cAGrC8D,EAAeP,EAAI7C,GAGnBJ,EAAU,kBAAmBiD,EAAI,CAC/BM,KAAMD,EAAMP,IACZ5B,QAASmC,EAAMnC,QACff,SAAUA,IAjBM,CAmBpB,CAqEIuE,CAASD,EAAQtE,GAGjByD,EAAUa,GAfJb,IACFR,EAAWQ,EAASzD,GACpByD,EAAU,KAchB,GAMIe,EAAgB,SAAUvE,GAExByD,GACFxE,EAAOuF,qBAAqBf,GAI9BA,EAAUxE,EAAOwF,sBAAsBf,EAAWgB,OACpD,EAMIC,EAAgB,SAAU3E,GAExByD,GACFxE,EAAOuF,qBAAqBf,GAI9BA,EAAUxE,EAAOwF,uBAAsB,WACrChE,EAAaC,GACbgD,EAAWgB,QACb,GACF,EAkDA,OA7CAhB,EAAWkB,QAAU,WAEfpB,GACFR,EAAWQ,EAASzD,GAItBd,EAAO4F,oBAAoB,SAAUN,GAAe,GAChDxE,EAASN,QACXR,EAAO4F,oBAAoB,SAAUF,GAAe,GAItDjE,EAAW,KACX6C,EAAW,KACXC,EAAU,KACVC,EAAU,KACV1D,EAAW,IACb,EAOEA,EA3XS,WACX,IAAI+E,EAAS,CAAC,EAOd,OANAlB,MAAMC,UAAUC,QAAQC,KAAKgB,WAAW,SAAUC,GAChD,IAAK,IAAIC,KAAOD,EAAK,CACnB,IAAKA,EAAIE,eAAeD,GAAM,OAC9BH,EAAOG,GAAOD,EAAIC,EACpB,CACF,IACOH,CACT,CAkXeK,CAAOhG,EAAUmE,GAAW,CAAC,GAGxCI,EAAW0B,QAGX1B,EAAWgB,SAGXzF,EAAOoG,iBAAiB,SAAUd,GAAe,GAC7CxE,EAASN,QACXR,EAAOoG,iBAAiB,SAAUV,GAAe,GAS9CjB,CACT,CAOF,CArcW4B,CAAQvG,EAChB,UAFM,SAEN,uBCXDwG,EAA2B,CAAC,EAGhC,SAASC,EAAoBC,GAE5B,IAAIC,EAAeH,EAAyBE,GAC5C,QAAqBE,IAAjBD,EACH,OAAOA,EAAaE,QAGrB,IAAIC,EAASN,EAAyBE,GAAY,CAGjDG,QAAS,CAAC,GAOX,OAHAE,EAAoBL,GAAU1B,KAAK8B,EAAOD,QAASC,EAAQA,EAAOD,QAASJ,GAGpEK,EAAOD,OACf,CCrBAJ,EAAoBO,EAAKF,IACxB,IAAIG,EAASH,GAAUA,EAAOI,WAC7B,IAAOJ,EAAiB,QACxB,IAAM,EAEP,OADAL,EAAoBU,EAAEF,EAAQ,CAAEG,EAAGH,IAC5BA,CAAM,ECLdR,EAAoBU,EAAI,CAACN,EAASQ,KACjC,IAAI,IAAInB,KAAOmB,EACXZ,EAAoBa,EAAED,EAAYnB,KAASO,EAAoBa,EAAET,EAASX,IAC5EqB,OAAOC,eAAeX,EAASX,EAAK,CAAEuB,YAAY,EAAMC,IAAKL,EAAWnB,IAE1E,ECNDO,EAAoBxG,EAAI,WACvB,GAA0B,iBAAf0H,WAAyB,OAAOA,WAC3C,IACC,OAAOxH,MAAQ,IAAIyH,SAAS,cAAb,EAChB,CAAE,MAAOC,GACR,GAAsB,iBAAX3H,OAAqB,OAAOA,MACxC,CACA,CAPuB,GCAxBuG,EAAoBa,EAAI,CAACrB,EAAK6B,IAAUP,OAAOzC,UAAUqB,eAAenB,KAAKiB,EAAK6B,4CCK9EC,EAAY,KACZC,EAAS,KACTC,EAAgBzF,SAASC,gBAAgByF,UAC7C,MAAMC,EAAmB,GA8EzB,SAASC,IACP,MAAMC,EAAeC,aAAaC,QAAQ,UAAY,OAZxD,IAAkBC,EACH,WADGA,EAaItI,OAAOuI,WAAW,gCAAgCC,QAI/C,SAAjBL,EACO,QACgB,SAAhBA,EACA,OAEA,OAIU,SAAjBA,EACO,OACgB,QAAhBA,EACA,QAEA,SA9BoB,SAATG,GAA4B,SAATA,IACzCG,QAAQC,MAAM,2BAA2BJ,yBACzCA,EAAO,QAGThG,SAASS,KAAK4F,QAAQC,MAAQN,EAC9BF,aAAaS,QAAQ,QAASP,GAC9BG,QAAQK,IAAI,cAAcR,UA0B5B,CAkDA,SAASnC,KART,WAEE,MAAM4C,EAAUzG,SAAS0G,uBAAuB,gBAChDrE,MAAMsE,KAAKF,GAASlE,SAASqE,IAC3BA,EAAI9C,iBAAiB,QAAS8B,EAAe,GAEjD,CAGEiB,GA9CF,WAEE,IAAIC,EAA6B,EAC7BC,GAAU,EAEdrJ,OAAOoG,iBAAiB,UAAU,SAAUuB,GAC1CyB,EAA6BpJ,OAAOsJ,QAE/BD,IACHrJ,OAAOwF,uBAAsB,WAzDnC,IAAuB+D,GAxDvB,SAAgCA,GAC9B,MAAMC,EAAY7G,KAAK8G,MAAM3B,EAAO7F,wBAAwBQ,KAE5DgG,QAAQK,IAAI,cAAcU,KACT,GAAbA,GAAkBD,GAAaC,EACjC1B,EAAOjE,UAAUM,IAAI,YAErB2D,EAAOjE,UAAUC,OAAO,WAE5B,EAgDE4F,CADqBH,EA0DDH,GAvGtB,SAAmCG,GAC7BA,EAAYtB,EACd3F,SAASC,gBAAgBsB,UAAUC,OAAO,oBAEtCyF,EAAYxB,EACdzF,SAASC,gBAAgBsB,UAAUM,IAAI,oBAC9BoF,EAAYxB,GACrBzF,SAASC,gBAAgBsB,UAAUC,OAAO,oBAG9CiE,EAAgBwB,CAClB,CAoCEI,CAA0BJ,GAlC5B,SAA6BA,GACT,OAAd1B,IAKa,GAAb0B,EACF1B,EAAU+B,SAAS,EAAG,GAGtBjH,KAAKC,KAAK2G,IACV5G,KAAK8G,MAAMnH,SAASC,gBAAgBS,aAAehD,OAAOqC,aAE1DwF,EAAU+B,SAAS,EAAG/B,EAAU7E,cAGhBV,SAASuH,cAAc,mBAc3C,CAKEC,CAAoBP,GAwDdF,GAAU,CACZ,IAEAA,GAAU,EAEd,IACArJ,OAAO+J,QACT,CA6BEC,GA1BkB,OAAdnC,GAKJ,IAAI,IAAJ,CAAY,cAAe,CACzBrH,QAAQ,EACRyJ,WAAW,EACX9J,SAAU,iBACVI,OAAQ,KACN,IAAI2J,EAAMhI,WAAWiI,iBAAiB7H,SAASC,iBAAiB6H,UAChE,OAAOtC,EAAO7F,wBAAwBoI,OAAS,IAAMH,EAAM,CAAC,GAiBlE,CAcA5H,SAAS8D,iBAAiB,oBAT1B,WACE9D,SAASS,KAAKW,WAAWG,UAAUC,OAAO,SAE1CgE,EAASxF,SAASuH,cAAc,UAChChC,EAAYvF,SAASuH,cAAc,eAEnC1D,GACF","sources":["webpack:///./src/furo/assets/scripts/gumshoe-patched.js","webpack:///webpack/bootstrap","webpack:///webpack/runtime/compat get default export","webpack:///webpack/runtime/define property getters","webpack:///webpack/runtime/global","webpack:///webpack/runtime/hasOwnProperty shorthand","webpack:///./src/furo/assets/scripts/furo.js"],"sourcesContent":["/*!\n * gumshoejs v5.1.2 (patched by @pradyunsg)\n * A simple, framework-agnostic scrollspy script.\n * (c) 2019 Chris Ferdinandi\n * MIT License\n * http://github.com/cferdinandi/gumshoe\n */\n\n(function (root, factory) {\n if (typeof define === \"function\" && define.amd) {\n define([], function () {\n return factory(root);\n });\n } else if (typeof exports === \"object\") {\n module.exports = factory(root);\n } else {\n root.Gumshoe = factory(root);\n }\n})(\n typeof global !== \"undefined\"\n ? global\n : typeof window !== \"undefined\"\n ? window\n : this,\n function (window) {\n \"use strict\";\n\n //\n // Defaults\n //\n\n var defaults = {\n // Active classes\n navClass: \"active\",\n contentClass: \"active\",\n\n // Nested navigation\n nested: false,\n nestedClass: \"active\",\n\n // Offset & reflow\n offset: 0,\n reflow: false,\n\n // Event support\n events: true,\n };\n\n //\n // Methods\n //\n\n /**\n * Merge two or more objects together.\n * @param {Object} objects The objects to merge together\n * @returns {Object} Merged values of defaults and options\n */\n var extend = function () {\n var merged = {};\n Array.prototype.forEach.call(arguments, function (obj) {\n for (var key in obj) {\n if (!obj.hasOwnProperty(key)) return;\n merged[key] = obj[key];\n }\n });\n return merged;\n };\n\n /**\n * Emit a custom event\n * @param {String} type The event type\n * @param {Node} elem The element to attach the event to\n * @param {Object} detail Any details to pass along with the event\n */\n var emitEvent = function (type, elem, detail) {\n // Make sure events are enabled\n if (!detail.settings.events) return;\n\n // Create a new event\n var event = new CustomEvent(type, {\n bubbles: true,\n cancelable: true,\n detail: detail,\n });\n\n // Dispatch the event\n elem.dispatchEvent(event);\n };\n\n /**\n * Get an element's distance from the top of the Document.\n * @param {Node} elem The element\n * @return {Number} Distance from the top in pixels\n */\n var getOffsetTop = function (elem) {\n var location = 0;\n if (elem.offsetParent) {\n while (elem) {\n location += elem.offsetTop;\n elem = elem.offsetParent;\n }\n }\n return location >= 0 ? location : 0;\n };\n\n /**\n * Sort content from first to last in the DOM\n * @param {Array} contents The content areas\n */\n var sortContents = function (contents) {\n if (contents) {\n contents.sort(function (item1, item2) {\n var offset1 = getOffsetTop(item1.content);\n var offset2 = getOffsetTop(item2.content);\n if (offset1 < offset2) return -1;\n return 1;\n });\n }\n };\n\n /**\n * Get the offset to use for calculating position\n * @param {Object} settings The settings for this instantiation\n * @return {Float} The number of pixels to offset the calculations\n */\n var getOffset = function (settings) {\n // if the offset is a function run it\n if (typeof settings.offset === \"function\") {\n return parseFloat(settings.offset());\n }\n\n // Otherwise, return it as-is\n return parseFloat(settings.offset);\n };\n\n /**\n * Get the document element's height\n * @private\n * @returns {Number}\n */\n var getDocumentHeight = function () {\n return Math.max(\n document.body.scrollHeight,\n document.documentElement.scrollHeight,\n document.body.offsetHeight,\n document.documentElement.offsetHeight,\n document.body.clientHeight,\n document.documentElement.clientHeight,\n );\n };\n\n /**\n * Determine if an element is in view\n * @param {Node} elem The element\n * @param {Object} settings The settings for this instantiation\n * @param {Boolean} bottom If true, check if element is above bottom of viewport instead\n * @return {Boolean} Returns true if element is in the viewport\n */\n var isInView = function (elem, settings, bottom) {\n var bounds = elem.getBoundingClientRect();\n var offset = getOffset(settings);\n if (bottom) {\n return (\n parseInt(bounds.bottom, 10) <\n (window.innerHeight || document.documentElement.clientHeight)\n );\n }\n return parseInt(bounds.top, 10) <= offset;\n };\n\n /**\n * Check if at the bottom of the viewport\n * @return {Boolean} If true, page is at the bottom of the viewport\n */\n var isAtBottom = function () {\n if (\n Math.ceil(window.innerHeight + window.pageYOffset) >=\n getDocumentHeight()\n )\n return true;\n return false;\n };\n\n /**\n * Check if the last item should be used (even if not at the top of the page)\n * @param {Object} item The last item\n * @param {Object} settings The settings for this instantiation\n * @return {Boolean} If true, use the last item\n */\n var useLastItem = function (item, settings) {\n if (isAtBottom() && isInView(item.content, settings, true)) return true;\n return false;\n };\n\n /**\n * Get the active content\n * @param {Array} contents The content areas\n * @param {Object} settings The settings for this instantiation\n * @return {Object} The content area and matching navigation link\n */\n var getActive = function (contents, settings) {\n var last = contents[contents.length - 1];\n if (useLastItem(last, settings)) return last;\n for (var i = contents.length - 1; i >= 0; i--) {\n if (isInView(contents[i].content, settings)) return contents[i];\n }\n };\n\n /**\n * Deactivate parent navs in a nested navigation\n * @param {Node} nav The starting navigation element\n * @param {Object} settings The settings for this instantiation\n */\n var deactivateNested = function (nav, settings) {\n // If nesting isn't activated, bail\n if (!settings.nested || !nav.parentNode) return;\n\n // Get the parent navigation\n var li = nav.parentNode.closest(\"li\");\n if (!li) return;\n\n // Remove the active class\n li.classList.remove(settings.nestedClass);\n\n // Apply recursively to any parent navigation elements\n deactivateNested(li, settings);\n };\n\n /**\n * Deactivate a nav and content area\n * @param {Object} items The nav item and content to deactivate\n * @param {Object} settings The settings for this instantiation\n */\n var deactivate = function (items, settings) {\n // Make sure there are items to deactivate\n if (!items) return;\n\n // Get the parent list item\n var li = items.nav.closest(\"li\");\n if (!li) return;\n\n // Remove the active class from the nav and content\n li.classList.remove(settings.navClass);\n items.content.classList.remove(settings.contentClass);\n\n // Deactivate any parent navs in a nested navigation\n deactivateNested(li, settings);\n\n // Emit a custom event\n emitEvent(\"gumshoeDeactivate\", li, {\n link: items.nav,\n content: items.content,\n settings: settings,\n });\n };\n\n /**\n * Activate parent navs in a nested navigation\n * @param {Node} nav The starting navigation element\n * @param {Object} settings The settings for this instantiation\n */\n var activateNested = function (nav, settings) {\n // If nesting isn't activated, bail\n if (!settings.nested) return;\n\n // Get the parent navigation\n var li = nav.parentNode.closest(\"li\");\n if (!li) return;\n\n // Add the active class\n li.classList.add(settings.nestedClass);\n\n // Apply recursively to any parent navigation elements\n activateNested(li, settings);\n };\n\n /**\n * Activate a nav and content area\n * @param {Object} items The nav item and content to activate\n * @param {Object} settings The settings for this instantiation\n */\n var activate = function (items, settings) {\n // Make sure there are items to activate\n if (!items) return;\n\n // Get the parent list item\n var li = items.nav.closest(\"li\");\n if (!li) return;\n\n // Add the active class to the nav and content\n li.classList.add(settings.navClass);\n items.content.classList.add(settings.contentClass);\n\n // Activate any parent navs in a nested navigation\n activateNested(li, settings);\n\n // Emit a custom event\n emitEvent(\"gumshoeActivate\", li, {\n link: items.nav,\n content: items.content,\n settings: settings,\n });\n };\n\n /**\n * Create the Constructor object\n * @param {String} selector The selector to use for navigation items\n * @param {Object} options User options and settings\n */\n var Constructor = function (selector, options) {\n //\n // Variables\n //\n\n var publicAPIs = {};\n var navItems, contents, current, timeout, settings;\n\n //\n // Methods\n //\n\n /**\n * Set variables from DOM elements\n */\n publicAPIs.setup = function () {\n // Get all nav items\n navItems = document.querySelectorAll(selector);\n\n // Create contents array\n contents = [];\n\n // Loop through each item, get it's matching content, and push to the array\n Array.prototype.forEach.call(navItems, function (item) {\n // Get the content for the nav item\n var content = document.getElementById(\n decodeURIComponent(item.hash.substr(1)),\n );\n if (!content) return;\n\n // Push to the contents array\n contents.push({\n nav: item,\n content: content,\n });\n });\n\n // Sort contents by the order they appear in the DOM\n sortContents(contents);\n };\n\n /**\n * Detect which content is currently active\n */\n publicAPIs.detect = function () {\n // Get the active content\n var active = getActive(contents, settings);\n\n // if there's no active content, deactivate and bail\n if (!active) {\n if (current) {\n deactivate(current, settings);\n current = null;\n }\n return;\n }\n\n // If the active content is the one currently active, do nothing\n if (current && active.content === current.content) return;\n\n // Deactivate the current content and activate the new content\n deactivate(current, settings);\n activate(active, settings);\n\n // Update the currently active content\n current = active;\n };\n\n /**\n * Detect the active content on scroll\n * Debounced for performance\n */\n var scrollHandler = function (event) {\n // If there's a timer, cancel it\n if (timeout) {\n window.cancelAnimationFrame(timeout);\n }\n\n // Setup debounce callback\n timeout = window.requestAnimationFrame(publicAPIs.detect);\n };\n\n /**\n * Update content sorting on resize\n * Debounced for performance\n */\n var resizeHandler = function (event) {\n // If there's a timer, cancel it\n if (timeout) {\n window.cancelAnimationFrame(timeout);\n }\n\n // Setup debounce callback\n timeout = window.requestAnimationFrame(function () {\n sortContents(contents);\n publicAPIs.detect();\n });\n };\n\n /**\n * Destroy the current instantiation\n */\n publicAPIs.destroy = function () {\n // Undo DOM changes\n if (current) {\n deactivate(current, settings);\n }\n\n // Remove event listeners\n window.removeEventListener(\"scroll\", scrollHandler, false);\n if (settings.reflow) {\n window.removeEventListener(\"resize\", resizeHandler, false);\n }\n\n // Reset variables\n contents = null;\n navItems = null;\n current = null;\n timeout = null;\n settings = null;\n };\n\n /**\n * Initialize the current instantiation\n */\n var init = function () {\n // Merge user options into defaults\n settings = extend(defaults, options || {});\n\n // Setup variables based on the current DOM\n publicAPIs.setup();\n\n // Find the currently active content\n publicAPIs.detect();\n\n // Setup event listeners\n window.addEventListener(\"scroll\", scrollHandler, false);\n if (settings.reflow) {\n window.addEventListener(\"resize\", resizeHandler, false);\n }\n };\n\n //\n // Initialize and return the public APIs\n //\n\n init();\n return publicAPIs;\n };\n\n //\n // Return the Constructor\n //\n\n return Constructor;\n },\n);\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","import Gumshoe from \"./gumshoe-patched.js\";\n\n////////////////////////////////////////////////////////////////////////////////\n// Scroll Handling\n////////////////////////////////////////////////////////////////////////////////\nvar tocScroll = null;\nvar header = null;\nvar lastScrollTop = document.documentElement.scrollTop;\nconst GO_TO_TOP_OFFSET = 64;\n\nfunction scrollHandlerForHeader(positionY) {\n const headerTop = Math.floor(header.getBoundingClientRect().top);\n\n console.log(`headerTop: ${headerTop}`);\n if (headerTop == 0 && positionY != headerTop) {\n header.classList.add(\"scrolled\");\n } else {\n header.classList.remove(\"scrolled\");\n }\n}\n\nfunction scrollHandlerForBackToTop(positionY) {\n if (positionY < GO_TO_TOP_OFFSET) {\n document.documentElement.classList.remove(\"show-back-to-top\");\n } else {\n if (positionY < lastScrollTop) {\n document.documentElement.classList.add(\"show-back-to-top\");\n } else if (positionY > lastScrollTop) {\n document.documentElement.classList.remove(\"show-back-to-top\");\n }\n }\n lastScrollTop = positionY;\n}\n\nfunction scrollHandlerForTOC(positionY) {\n if (tocScroll === null) {\n return;\n }\n\n // top of page.\n if (positionY == 0) {\n tocScroll.scrollTo(0, 0);\n } else if (\n // bottom of page.\n Math.ceil(positionY) >=\n Math.floor(document.documentElement.scrollHeight - window.innerHeight)\n ) {\n tocScroll.scrollTo(0, tocScroll.scrollHeight);\n } else {\n // somewhere in the middle.\n const current = document.querySelector(\".scroll-current\");\n if (current == null) {\n return;\n }\n\n // https://github.com/pypa/pip/issues/9159 This breaks scroll behaviours.\n // // scroll the currently \"active\" heading in toc, into view.\n // const rect = current.getBoundingClientRect();\n // if (0 > rect.top) {\n // current.scrollIntoView(true); // the argument is \"alignTop\"\n // } else if (rect.bottom > window.innerHeight) {\n // current.scrollIntoView(false);\n // }\n }\n}\n\nfunction scrollHandler(positionY) {\n scrollHandlerForHeader(positionY);\n scrollHandlerForBackToTop(positionY);\n scrollHandlerForTOC(positionY);\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Theme Toggle\n////////////////////////////////////////////////////////////////////////////////\nfunction setTheme(mode) {\n if (mode !== \"light\" && mode !== \"dark\" && mode !== \"auto\") {\n console.error(`Got invalid theme mode: ${mode}. Resetting to auto.`);\n mode = \"auto\";\n }\n\n document.body.dataset.theme = mode;\n localStorage.setItem(\"theme\", mode);\n console.log(`Changed to ${mode} mode.`);\n}\n\nfunction cycleThemeOnce() {\n const currentTheme = localStorage.getItem(\"theme\") || \"auto\";\n const prefersDark = window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n\n if (prefersDark) {\n // Auto (dark) -> Light -> Dark\n if (currentTheme === \"auto\") {\n setTheme(\"light\");\n } else if (currentTheme == \"light\") {\n setTheme(\"dark\");\n } else {\n setTheme(\"auto\");\n }\n } else {\n // Auto (light) -> Dark -> Light\n if (currentTheme === \"auto\") {\n setTheme(\"dark\");\n } else if (currentTheme == \"dark\") {\n setTheme(\"light\");\n } else {\n setTheme(\"auto\");\n }\n }\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Setup\n////////////////////////////////////////////////////////////////////////////////\nfunction setupScrollHandler() {\n // Taken from https://developer.mozilla.org/en-US/docs/Web/API/Document/scroll_event\n let last_known_scroll_position = 0;\n let ticking = false;\n\n window.addEventListener(\"scroll\", function (e) {\n last_known_scroll_position = window.scrollY;\n\n if (!ticking) {\n window.requestAnimationFrame(function () {\n scrollHandler(last_known_scroll_position);\n ticking = false;\n });\n\n ticking = true;\n }\n });\n window.scroll();\n}\n\nfunction setupScrollSpy() {\n if (tocScroll === null) {\n return;\n }\n\n // Scrollspy -- highlight table on contents, based on scroll\n new Gumshoe(\".toc-tree a\", {\n reflow: true,\n recursive: true,\n navClass: \"scroll-current\",\n offset: () => {\n let rem = parseFloat(getComputedStyle(document.documentElement).fontSize);\n return header.getBoundingClientRect().height + 2.5 * rem + 1;\n },\n });\n}\n\nfunction setupTheme() {\n // Attach event handlers for toggling themes\n const buttons = document.getElementsByClassName(\"theme-toggle\");\n Array.from(buttons).forEach((btn) => {\n btn.addEventListener(\"click\", cycleThemeOnce);\n });\n}\n\nfunction setup() {\n setupTheme();\n setupScrollHandler();\n setupScrollSpy();\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Main entrypoint\n////////////////////////////////////////////////////////////////////////////////\nfunction main() {\n document.body.parentNode.classList.remove(\"no-js\");\n\n header = document.querySelector(\"header\");\n tocScroll = document.querySelector(\".toc-scroll\");\n\n setup();\n}\n\ndocument.addEventListener(\"DOMContentLoaded\", main);\n"],"names":["root","g","window","this","defaults","navClass","contentClass","nested","nestedClass","offset","reflow","events","emitEvent","type","elem","detail","settings","event","CustomEvent","bubbles","cancelable","dispatchEvent","getOffsetTop","location","offsetParent","offsetTop","sortContents","contents","sort","item1","item2","content","isInView","bottom","bounds","getBoundingClientRect","parseFloat","getOffset","parseInt","innerHeight","document","documentElement","clientHeight","top","isAtBottom","Math","ceil","pageYOffset","max","body","scrollHeight","offsetHeight","getActive","last","length","item","useLastItem","i","deactivateNested","nav","parentNode","li","closest","classList","remove","deactivate","items","link","activateNested","add","selector","options","navItems","current","timeout","publicAPIs","querySelectorAll","Array","prototype","forEach","call","getElementById","decodeURIComponent","hash","substr","push","active","activate","scrollHandler","cancelAnimationFrame","requestAnimationFrame","detect","resizeHandler","destroy","removeEventListener","merged","arguments","obj","key","hasOwnProperty","extend","setup","addEventListener","factory","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","exports","module","__webpack_modules__","n","getter","__esModule","d","a","definition","o","Object","defineProperty","enumerable","get","globalThis","Function","e","prop","tocScroll","header","lastScrollTop","scrollTop","GO_TO_TOP_OFFSET","cycleThemeOnce","currentTheme","localStorage","getItem","mode","matchMedia","matches","console","error","dataset","theme","setItem","log","buttons","getElementsByClassName","from","btn","setupTheme","last_known_scroll_position","ticking","scrollY","positionY","headerTop","floor","scrollHandlerForHeader","scrollHandlerForBackToTop","scrollTo","querySelector","scrollHandlerForTOC","scroll","setupScrollHandler","recursive","rem","getComputedStyle","fontSize","height"],"sourceRoot":""} \ No newline at end of file diff --git a/_static/searchtools.js b/_static/searchtools.js new file mode 100644 index 0000000..2c774d1 --- /dev/null +++ b/_static/searchtools.js @@ -0,0 +1,632 @@ +/* + * Sphinx JavaScript utilities for the full-text search. + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename, kind] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +// Global search result kind enum, used by themes to style search results. +class SearchResultKind { + static get index() { return "index"; } + static get object() { return "object"; } + static get text() { return "text"; } + static get title() { return "title"; } +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename, kind] = item; + + let listItem = document.createElement("li"); + // Add a class representing the item's type: + // can be used by a theme's CSS selector for styling + // See SearchResultKind for the class names. + listItem.classList.add(`kind-${kind}`); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms, anchor) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = Documentation.ngettext( + "Search finished, found one page matching the search query.", + "Search finished, found ${resultCount} pages matching the search query.", + resultCount, + ).replace('${resultCount}', resultCount); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; +// Helper function used by query() to order search results. +// Each input is an array of [docname, title, anchor, descr, score, filename, kind]. +// Order the results by score (in opposite order of appearance, since the +// `_displayNextItem` function uses pop() to retrieve items) and then alphabetically. +const _orderResultsByScoreThenName = (a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString, anchor) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + for (const removalQuery of [".headerlink", "script", "style"]) { + htmlElement.querySelectorAll(removalQuery).forEach((el) => { el.remove() }); + } + if (anchor) { + const anchorContent = htmlElement.querySelector(`[role="main"] ${anchor}`); + if (anchorContent) return anchorContent.textContent; + + console.warn( + `Anchored content block not found. Sphinx search tries to obtain it via DOM query '[role=main] ${anchor}'. Check your theme or template.` + ); + } + + // if anchor not specified or not found, fall back to main content + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent) return docContent.textContent; + + console.warn( + "Content block not found. Sphinx search tries to obtain it via DOM query '[role=main]'. Check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.setAttribute("role", "list"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + _parseQuery: (query) => { + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + return [query, searchTerms, excludedTerms, highlightTerms, objectTerms]; + }, + + /** + * execute search (requires search index to be loaded) + */ + _performSearch: (query, searchTerms, excludedTerms, highlightTerms, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // Collect multiple result groups to be sorted separately and then ordered. + // Each is an array of [docname, title, anchor, descr, score, filename, kind]. + const normalResults = []; + const nonMainIndexResults = []; + + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase().trim(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().trim().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + const score = Math.round(Scorer.title * queryLower.length / title.length); + const boost = titles[file] === title ? 1 : 0; // add a boost for document titles + normalResults.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score + boost, + filenames[file], + SearchResultKind.title, + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id, isMain] of foundEntries) { + const score = Math.round(100 * queryLower.length / entry.length); + const result = [ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + SearchResultKind.index, + ]; + if (isMain) { + normalResults.push(result); + } else { + nonMainIndexResults.push(result); + } + } + } + } + + // lookup as object + objectTerms.forEach((term) => + normalResults.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + normalResults.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) { + normalResults.forEach((item) => (item[4] = Scorer.score(item))); + nonMainIndexResults.forEach((item) => (item[4] = Scorer.score(item))); + } + + // Sort each group of results by score and then alphabetically by name. + normalResults.sort(_orderResultsByScoreThenName); + nonMainIndexResults.sort(_orderResultsByScoreThenName); + + // Combine the result groups in (reverse) order. + // Non-main index entries are typically arbitrary cross-references, + // so display them after other results. + let results = [...nonMainIndexResults, ...normalResults]; + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + return results.reverse(); + }, + + query: (query) => { + const [searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms] = Search._parseQuery(query); + const results = Search._performSearch(searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + SearchResultKind.object, + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + if (!terms.hasOwnProperty(word)) { + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + } + if (!titleTerms.hasOwnProperty(word)) { + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: titleTerms[term], score: Scorer.partialTitle }); + }); + } + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (!fileMap.has(file)) fileMap.set(file, [word]); + else if (fileMap.get(file).indexOf(word) === -1) fileMap.get(file).push(word); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + SearchResultKind.text, + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords, anchor) => { + const text = Search.htmlToText(htmlText, anchor); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/_static/skeleton.css b/_static/skeleton.css new file mode 100644 index 0000000..467c878 --- /dev/null +++ b/_static/skeleton.css @@ -0,0 +1,296 @@ +/* Some sane resets. */ +html { + height: 100%; +} + +body { + margin: 0; + min-height: 100%; +} + +/* All the flexbox magic! */ +body, +.sb-announcement, +.sb-content, +.sb-main, +.sb-container, +.sb-container__inner, +.sb-article-container, +.sb-footer-content, +.sb-header, +.sb-header-secondary, +.sb-footer { + display: flex; +} + +/* These order things vertically */ +body, +.sb-main, +.sb-article-container { + flex-direction: column; +} + +/* Put elements in the center */ +.sb-header, +.sb-header-secondary, +.sb-container, +.sb-content, +.sb-footer, +.sb-footer-content { + justify-content: center; +} +/* Put elements at the ends */ +.sb-article-container { + justify-content: space-between; +} + +/* These elements grow. */ +.sb-main, +.sb-content, +.sb-container, +article { + flex-grow: 1; +} + +/* Because padding making this wider is not fun */ +article { + box-sizing: border-box; +} + +/* The announcements element should never be wider than the page. */ +.sb-announcement { + max-width: 100%; +} + +.sb-sidebar-primary, +.sb-sidebar-secondary { + flex-shrink: 0; + width: 17rem; +} + +.sb-announcement__inner { + justify-content: center; + + box-sizing: border-box; + height: 3rem; + + overflow-x: auto; + white-space: nowrap; +} + +/* Sidebars, with checkbox-based toggle */ +.sb-sidebar-primary, +.sb-sidebar-secondary { + position: fixed; + height: 100%; + top: 0; +} + +.sb-sidebar-primary { + left: -17rem; + transition: left 250ms ease-in-out; +} +.sb-sidebar-secondary { + right: -17rem; + transition: right 250ms ease-in-out; +} + +.sb-sidebar-toggle { + display: none; +} +.sb-sidebar-overlay { + position: fixed; + top: 0; + width: 0; + height: 0; + + transition: width 0ms ease 250ms, height 0ms ease 250ms, opacity 250ms ease; + + opacity: 0; + background-color: rgba(0, 0, 0, 0.54); +} + +#sb-sidebar-toggle--primary:checked + ~ .sb-sidebar-overlay[for="sb-sidebar-toggle--primary"], +#sb-sidebar-toggle--secondary:checked + ~ .sb-sidebar-overlay[for="sb-sidebar-toggle--secondary"] { + width: 100%; + height: 100%; + opacity: 1; + transition: width 0ms ease, height 0ms ease, opacity 250ms ease; +} + +#sb-sidebar-toggle--primary:checked ~ .sb-container .sb-sidebar-primary { + left: 0; +} +#sb-sidebar-toggle--secondary:checked ~ .sb-container .sb-sidebar-secondary { + right: 0; +} + +/* Full-width mode */ +.drop-secondary-sidebar-for-full-width-content + .hide-when-secondary-sidebar-shown { + display: none !important; +} +.drop-secondary-sidebar-for-full-width-content .sb-sidebar-secondary { + display: none !important; +} + +/* Mobile views */ +.sb-page-width { + width: 100%; +} + +.sb-article-container, +.sb-footer-content__inner, +.drop-secondary-sidebar-for-full-width-content .sb-article, +.drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 100vw; +} + +.sb-article, +.match-content-width { + padding: 0 1rem; + box-sizing: border-box; +} + +@media (min-width: 32rem) { + .sb-article, + .match-content-width { + padding: 0 2rem; + } +} + +/* Tablet views */ +@media (min-width: 42rem) { + .sb-article-container { + width: auto; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 42rem; + } + .sb-article, + .match-content-width { + width: 42rem; + } +} +@media (min-width: 46rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 46rem; + } + .sb-article, + .match-content-width { + width: 46rem; + } +} +@media (min-width: 50rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 50rem; + } + .sb-article, + .match-content-width { + width: 50rem; + } +} + +/* Tablet views */ +@media (min-width: 59rem) { + .sb-sidebar-secondary { + position: static; + } + .hide-when-secondary-sidebar-shown { + display: none !important; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 59rem; + } + .sb-article, + .match-content-width { + width: 42rem; + } +} +@media (min-width: 63rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 63rem; + } + .sb-article, + .match-content-width { + width: 46rem; + } +} +@media (min-width: 67rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 67rem; + } + .sb-article, + .match-content-width { + width: 50rem; + } +} + +/* Desktop views */ +@media (min-width: 76rem) { + .sb-sidebar-primary { + position: static; + } + .hide-when-primary-sidebar-shown { + display: none !important; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 59rem; + } + .sb-article, + .match-content-width { + width: 42rem; + } +} + +/* Full desktop views */ +@media (min-width: 80rem) { + .sb-article, + .match-content-width { + width: 46rem; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 63rem; + } +} + +@media (min-width: 84rem) { + .sb-article, + .match-content-width { + width: 50rem; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 67rem; + } +} + +@media (min-width: 88rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 67rem; + } + .sb-page-width { + width: 88rem; + } +} diff --git a/_static/sphinx_highlight.js b/_static/sphinx_highlight.js new file mode 100644 index 0000000..8a96c69 --- /dev/null +++ b/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/_static/styles/furo-extensions.css b/_static/styles/furo-extensions.css new file mode 100644 index 0000000..8229587 --- /dev/null +++ b/_static/styles/furo-extensions.css @@ -0,0 +1,2 @@ +#furo-sidebar-ad-placement{padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)}#furo-sidebar-ad-placement .ethical-sidebar{background:var(--color-background-secondary);border:none;box-shadow:none}#furo-sidebar-ad-placement .ethical-sidebar:hover{background:var(--color-background-hover)}#furo-sidebar-ad-placement .ethical-sidebar a{color:var(--color-foreground-primary)}#furo-sidebar-ad-placement .ethical-callout a{color:var(--color-foreground-secondary)!important}#furo-readthedocs-versions{background:transparent;display:block;position:static;width:100%}#furo-readthedocs-versions .rst-versions{background:#1a1c1e}#furo-readthedocs-versions .rst-current-version{background:var(--color-sidebar-item-background);cursor:unset}#furo-readthedocs-versions .rst-current-version:hover{background:var(--color-sidebar-item-background)}#furo-readthedocs-versions .rst-current-version .fa-book{color:var(--color-foreground-primary)}#furo-readthedocs-versions>.rst-other-versions{padding:0}#furo-readthedocs-versions>.rst-other-versions small{opacity:1}#furo-readthedocs-versions .injected .rst-versions{position:unset}#furo-readthedocs-versions:focus-within,#furo-readthedocs-versions:hover{box-shadow:0 0 0 1px var(--color-sidebar-background-border)}#furo-readthedocs-versions:focus-within .rst-current-version,#furo-readthedocs-versions:hover .rst-current-version{background:#1a1c1e;font-size:inherit;height:auto;line-height:inherit;padding:12px;text-align:right}#furo-readthedocs-versions:focus-within .rst-current-version .fa-book,#furo-readthedocs-versions:hover .rst-current-version .fa-book{color:#fff;float:left}#furo-readthedocs-versions:focus-within .fa-caret-down,#furo-readthedocs-versions:hover .fa-caret-down{display:none}#furo-readthedocs-versions:focus-within .injected,#furo-readthedocs-versions:focus-within .rst-current-version,#furo-readthedocs-versions:focus-within .rst-other-versions,#furo-readthedocs-versions:hover .injected,#furo-readthedocs-versions:hover .rst-current-version,#furo-readthedocs-versions:hover .rst-other-versions{display:block}#furo-readthedocs-versions:focus-within>.rst-current-version,#furo-readthedocs-versions:hover>.rst-current-version{display:none}.highlight:hover button.copybtn{color:var(--color-code-foreground)}.highlight button.copybtn{align-items:center;background-color:var(--color-code-background);border:none;color:var(--color-background-item);cursor:pointer;height:1.25em;right:.5rem;top:.625rem;transition:color .3s,opacity .3s;width:1.25em}.highlight button.copybtn:hover{background-color:var(--color-code-background);color:var(--color-brand-content)}.highlight button.copybtn:after{background-color:transparent;color:var(--color-code-foreground);display:none}.highlight button.copybtn.success{color:#22863a;transition:color 0ms}.highlight button.copybtn.success:after{display:block}.highlight button.copybtn svg{padding:0}body{--sd-color-primary:var(--color-brand-primary);--sd-color-primary-highlight:var(--color-brand-content);--sd-color-primary-text:var(--color-background-primary);--sd-color-shadow:rgba(0,0,0,.05);--sd-color-card-border:var(--color-card-border);--sd-color-card-border-hover:var(--color-brand-content);--sd-color-card-background:var(--color-card-background);--sd-color-card-text:var(--color-foreground-primary);--sd-color-card-header:var(--color-card-marginals-background);--sd-color-card-footer:var(--color-card-marginals-background);--sd-color-tabs-label-active:var(--color-brand-content);--sd-color-tabs-label-hover:var(--color-foreground-muted);--sd-color-tabs-label-inactive:var(--color-foreground-muted);--sd-color-tabs-underline-active:var(--color-brand-content);--sd-color-tabs-underline-hover:var(--color-foreground-border);--sd-color-tabs-underline-inactive:var(--color-background-border);--sd-color-tabs-overline:var(--color-background-border);--sd-color-tabs-underline:var(--color-background-border)}.sd-tab-content{box-shadow:0 -2px var(--sd-color-tabs-overline),0 1px var(--sd-color-tabs-underline)}.sd-card{box-shadow:0 .1rem .25rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)}.sd-shadow-sm{box-shadow:0 .1rem .25rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)!important}.sd-shadow-md{box-shadow:0 .3rem .75rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)!important}.sd-shadow-lg{box-shadow:0 .6rem 1.5rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)!important}.sd-card-hover:hover{transform:none}.sd-cards-carousel{gap:.25rem;padding:.25rem}body{--tabs--label-text:var(--color-foreground-muted);--tabs--label-text--hover:var(--color-foreground-muted);--tabs--label-text--active:var(--color-brand-content);--tabs--label-text--active--hover:var(--color-brand-content);--tabs--label-background:transparent;--tabs--label-background--hover:transparent;--tabs--label-background--active:transparent;--tabs--label-background--active--hover:transparent;--tabs--padding-x:0.25em;--tabs--margin-x:1em;--tabs--border:var(--color-background-border);--tabs--label-border:transparent;--tabs--label-border--hover:var(--color-foreground-muted);--tabs--label-border--active:var(--color-brand-content);--tabs--label-border--active--hover:var(--color-brand-content)}[role=main] .container{max-width:none;padding-left:0;padding-right:0}.shadow.docutils{border:none;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 .0625rem rgba(0,0,0,.1)!important}.sphinx-bs .card{background-color:var(--color-background-secondary);color:var(--color-foreground)} +/*# sourceMappingURL=furo-extensions.css.map*/ \ No newline at end of file diff --git a/_static/styles/furo-extensions.css.map b/_static/styles/furo-extensions.css.map new file mode 100644 index 0000000..c26eac7 --- /dev/null +++ b/_static/styles/furo-extensions.css.map @@ -0,0 +1 @@ +{"version":3,"file":"styles/furo-extensions.css","mappings":"AAGA,2BACE,oFACA,4CAKE,6CAHA,YACA,eAEA,CACA,kDACE,yCAEF,8CACE,sCAEJ,8CACE,kDAEJ,2BAGE,uBACA,cAHA,gBACA,UAEA,CAGA,yCACE,mBAEF,gDAEE,gDADA,YACA,CACA,sDACE,gDACF,yDACE,sCAEJ,+CACE,UACA,qDACE,UAGF,mDACE,eAEJ,yEAEE,4DAEA,mHASE,mBAPA,kBAEA,YADA,oBAGA,aADA,gBAIA,CAEA,qIAEE,WADA,UACA,CAEJ,uGACE,aAEF,iUAGE,cAEF,mHACE,aC1EJ,gCACE,mCAEF,0BAEE,mBAUA,8CACA,YAFA,mCAKA,eAZA,cAIA,YADA,YAYA,iCAdA,YAcA,CAEA,gCAEE,8CADA,gCACA,CAEF,gCAGE,6BADA,mCADA,YAEA,CAEF,kCAEE,cADA,oBACA,CACA,wCACE,cAEJ,8BACE,UCzCN,KAEE,6CAA8C,CAC9C,uDAAwD,CACxD,uDAAwD,CAGxD,iCAAsC,CAGtC,+CAAgD,CAChD,uDAAwD,CACxD,uDAAwD,CACxD,oDAAqD,CACrD,6DAA8D,CAC9D,6DAA8D,CAG9D,uDAAwD,CACxD,yDAA0D,CAC1D,4DAA6D,CAC7D,2DAA4D,CAC5D,8DAA+D,CAC/D,iEAAkE,CAClE,uDAAwD,CACxD,wDAAyD,CAG3D,gBACE,qFAGF,SACE,6EAEF,cACE,uFAEF,cACE,uFAEF,cACE,uFAGF,qBACE,eAEF,mBACE,WACA,eChDF,KACE,gDAAiD,CACjD,uDAAwD,CACxD,qDAAsD,CACtD,4DAA6D,CAC7D,oCAAqC,CACrC,2CAA4C,CAC5C,4CAA6C,CAC7C,mDAAoD,CACpD,wBAAyB,CACzB,oBAAqB,CACrB,6CAA8C,CAC9C,gCAAiC,CACjC,yDAA0D,CAC1D,uDAAwD,CACxD,8DAA+D,CCbjE,uBACE,eACA,eACA,gBAGF,iBACE,YACA,+EAGF,iBACE,mDACA","sources":["webpack:///./src/furo/assets/styles/extensions/_readthedocs.sass","webpack:///./src/furo/assets/styles/extensions/_copybutton.sass","webpack:///./src/furo/assets/styles/extensions/_sphinx-design.sass","webpack:///./src/furo/assets/styles/extensions/_sphinx-inline-tabs.sass","webpack:///./src/furo/assets/styles/extensions/_sphinx-panels.sass"],"sourcesContent":["// This file contains the styles used for tweaking how ReadTheDoc's embedded\n// contents would show up inside the theme.\n\n#furo-sidebar-ad-placement\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n .ethical-sidebar\n // Remove the border and box-shadow.\n border: none\n box-shadow: none\n // Manage the background colors.\n background: var(--color-background-secondary)\n &:hover\n background: var(--color-background-hover)\n // Ensure the text is legible.\n a\n color: var(--color-foreground-primary)\n\n .ethical-callout a\n color: var(--color-foreground-secondary) !important\n\n#furo-readthedocs-versions\n position: static\n width: 100%\n background: transparent\n display: block\n\n // Make the background color fit with the theme's aesthetic.\n .rst-versions\n background: rgb(26, 28, 30)\n\n .rst-current-version\n cursor: unset\n background: var(--color-sidebar-item-background)\n &:hover\n background: var(--color-sidebar-item-background)\n .fa-book\n color: var(--color-foreground-primary)\n\n > .rst-other-versions\n padding: 0\n small\n opacity: 1\n\n .injected\n .rst-versions\n position: unset\n\n &:hover,\n &:focus-within\n box-shadow: 0 0 0 1px var(--color-sidebar-background-border)\n\n .rst-current-version\n // Undo the tweaks done in RTD's CSS\n font-size: inherit\n line-height: inherit\n height: auto\n text-align: right\n padding: 12px\n\n // Match the rest of the body\n background: #1a1c1e\n\n .fa-book\n float: left\n color: white\n\n .fa-caret-down\n display: none\n\n .rst-current-version,\n .rst-other-versions,\n .injected\n display: block\n\n > .rst-current-version\n display: none\n",".highlight\n &:hover button.copybtn\n color: var(--color-code-foreground)\n\n button.copybtn\n // Align things correctly\n align-items: center\n\n height: 1.25em\n width: 1.25em\n\n top: 0.625rem // $code-spacing-vertical\n right: 0.5rem\n\n // Make it look better\n color: var(--color-background-item)\n background-color: var(--color-code-background)\n border: none\n\n // Change to cursor to make it obvious that you can click on it\n cursor: pointer\n\n // Transition smoothly, for aesthetics\n transition: color 300ms, opacity 300ms\n\n &:hover\n color: var(--color-brand-content)\n background-color: var(--color-code-background)\n\n &::after\n display: none\n color: var(--color-code-foreground)\n background-color: transparent\n\n &.success\n transition: color 0ms\n color: #22863a\n &::after\n display: block\n\n svg\n padding: 0\n","body\n // Colors\n --sd-color-primary: var(--color-brand-primary)\n --sd-color-primary-highlight: var(--color-brand-content)\n --sd-color-primary-text: var(--color-background-primary)\n\n // Shadows\n --sd-color-shadow: rgba(0, 0, 0, 0.05)\n\n // Cards\n --sd-color-card-border: var(--color-card-border)\n --sd-color-card-border-hover: var(--color-brand-content)\n --sd-color-card-background: var(--color-card-background)\n --sd-color-card-text: var(--color-foreground-primary)\n --sd-color-card-header: var(--color-card-marginals-background)\n --sd-color-card-footer: var(--color-card-marginals-background)\n\n // Tabs\n --sd-color-tabs-label-active: var(--color-brand-content)\n --sd-color-tabs-label-hover: var(--color-foreground-muted)\n --sd-color-tabs-label-inactive: var(--color-foreground-muted)\n --sd-color-tabs-underline-active: var(--color-brand-content)\n --sd-color-tabs-underline-hover: var(--color-foreground-border)\n --sd-color-tabs-underline-inactive: var(--color-background-border)\n --sd-color-tabs-overline: var(--color-background-border)\n --sd-color-tabs-underline: var(--color-background-border)\n\n// Tabs\n.sd-tab-content\n box-shadow: 0 -2px var(--sd-color-tabs-overline), 0 1px var(--sd-color-tabs-underline)\n\n// Shadows\n.sd-card // Have a shadow by default\n box-shadow: 0 0.1rem 0.25rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1)\n\n.sd-shadow-sm\n box-shadow: 0 0.1rem 0.25rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n.sd-shadow-md\n box-shadow: 0 0.3rem 0.75rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n.sd-shadow-lg\n box-shadow: 0 0.6rem 1.5rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n// Cards\n.sd-card-hover:hover // Don't change scale on hover\n transform: none\n\n.sd-cards-carousel // Have a bit of gap in the carousel by default\n gap: 0.25rem\n padding: 0.25rem\n","// This file contains styles to tweak sphinx-inline-tabs to work well with Furo.\n\nbody\n --tabs--label-text: var(--color-foreground-muted)\n --tabs--label-text--hover: var(--color-foreground-muted)\n --tabs--label-text--active: var(--color-brand-content)\n --tabs--label-text--active--hover: var(--color-brand-content)\n --tabs--label-background: transparent\n --tabs--label-background--hover: transparent\n --tabs--label-background--active: transparent\n --tabs--label-background--active--hover: transparent\n --tabs--padding-x: 0.25em\n --tabs--margin-x: 1em\n --tabs--border: var(--color-background-border)\n --tabs--label-border: transparent\n --tabs--label-border--hover: var(--color-foreground-muted)\n --tabs--label-border--active: var(--color-brand-content)\n --tabs--label-border--active--hover: var(--color-brand-content)\n","// This file contains styles to tweak sphinx-panels to work well with Furo.\n\n// sphinx-panels includes Bootstrap 4, which uses .container which can conflict\n// with docutils' `.. container::` directive.\n[role=\"main\"] .container\n max-width: initial\n padding-left: initial\n padding-right: initial\n\n// Make the panels look nicer!\n.shadow.docutils\n border: none\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n// Make panel colors respond to dark mode\n.sphinx-bs .card\n background-color: var(--color-background-secondary)\n color: var(--color-foreground)\n"],"names":[],"sourceRoot":""} \ No newline at end of file diff --git a/_static/styles/furo.css b/_static/styles/furo.css new file mode 100644 index 0000000..05a56b1 --- /dev/null +++ b/_static/styles/furo.css @@ -0,0 +1,2 @@ +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}[hidden],template{display:none}@media print{.content-icon-container,.headerlink,.mobile-header,.related-pages{display:none!important}.highlight{border:.1pt solid var(--color-foreground-border)}a,blockquote,dl,ol,p,pre,table,ul{page-break-inside:avoid}caption,figure,h1,h2,h3,h4,h5,h6,img{page-break-after:avoid;page-break-inside:avoid}dl,ol,ul{page-break-before:avoid}}.visually-hidden{height:1px!important;margin:-1px!important;overflow:hidden!important;padding:0!important;position:absolute!important;width:1px!important;clip:rect(0,0,0,0)!important;background:var(--color-background-primary);border:0!important;color:var(--color-foreground-primary);white-space:nowrap!important}:-moz-focusring{outline:auto}body{--font-stack:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;--font-stack--monospace:"SFMono-Regular",Menlo,Consolas,Monaco,Liberation Mono,Lucida Console,monospace;--font-stack--headings:var(--font-stack);--font-size--normal:100%;--font-size--small:87.5%;--font-size--small--2:81.25%;--font-size--small--3:75%;--font-size--small--4:62.5%;--sidebar-caption-font-size:var(--font-size--small--2);--sidebar-item-font-size:var(--font-size--small);--sidebar-search-input-font-size:var(--font-size--small);--toc-font-size:var(--font-size--small--3);--toc-font-size--mobile:var(--font-size--normal);--toc-title-font-size:var(--font-size--small--4);--admonition-font-size:0.8125rem;--admonition-title-font-size:0.8125rem;--code-font-size:var(--font-size--small--2);--api-font-size:var(--font-size--small);--header-height:calc(var(--sidebar-item-line-height) + var(--sidebar-item-spacing-vertical)*4);--header-padding:0.5rem;--sidebar-tree-space-above:1.5rem;--sidebar-caption-space-above:1rem;--sidebar-item-line-height:1rem;--sidebar-item-spacing-vertical:0.5rem;--sidebar-item-spacing-horizontal:1rem;--sidebar-item-height:calc(var(--sidebar-item-line-height) + var(--sidebar-item-spacing-vertical)*2);--sidebar-expander-width:var(--sidebar-item-height);--sidebar-search-space-above:0.5rem;--sidebar-search-input-spacing-vertical:0.5rem;--sidebar-search-input-spacing-horizontal:0.5rem;--sidebar-search-input-height:1rem;--sidebar-search-icon-size:var(--sidebar-search-input-height);--toc-title-padding:0.25rem 0;--toc-spacing-vertical:1.5rem;--toc-spacing-horizontal:1.5rem;--toc-item-spacing-vertical:0.4rem;--toc-item-spacing-horizontal:1rem;--icon-search:url('data:image/svg+xml;charset=utf-8,');--icon-pencil:url('data:image/svg+xml;charset=utf-8,');--icon-abstract:url('data:image/svg+xml;charset=utf-8,');--icon-info:url('data:image/svg+xml;charset=utf-8,');--icon-flame:url('data:image/svg+xml;charset=utf-8,');--icon-question:url('data:image/svg+xml;charset=utf-8,');--icon-warning:url('data:image/svg+xml;charset=utf-8,');--icon-failure:url('data:image/svg+xml;charset=utf-8,');--icon-spark:url('data:image/svg+xml;charset=utf-8,');--color-admonition-title--caution:#ff9100;--color-admonition-title-background--caution:rgba(255,145,0,.2);--color-admonition-title--warning:#ff9100;--color-admonition-title-background--warning:rgba(255,145,0,.2);--color-admonition-title--danger:#ff5252;--color-admonition-title-background--danger:rgba(255,82,82,.2);--color-admonition-title--attention:#ff5252;--color-admonition-title-background--attention:rgba(255,82,82,.2);--color-admonition-title--error:#ff5252;--color-admonition-title-background--error:rgba(255,82,82,.2);--color-admonition-title--hint:#00c852;--color-admonition-title-background--hint:rgba(0,200,82,.2);--color-admonition-title--tip:#00c852;--color-admonition-title-background--tip:rgba(0,200,82,.2);--color-admonition-title--important:#00bfa5;--color-admonition-title-background--important:rgba(0,191,165,.2);--color-admonition-title--note:#00b0ff;--color-admonition-title-background--note:rgba(0,176,255,.2);--color-admonition-title--seealso:#448aff;--color-admonition-title-background--seealso:rgba(68,138,255,.2);--color-admonition-title--admonition-todo:grey;--color-admonition-title-background--admonition-todo:hsla(0,0%,50%,.2);--color-admonition-title:#651fff;--color-admonition-title-background:rgba(101,31,255,.2);--icon-admonition-default:var(--icon-abstract);--color-topic-title:#14b8a6;--color-topic-title-background:rgba(20,184,166,.2);--icon-topic-default:var(--icon-pencil);--color-problematic:#b30000;--color-foreground-primary:#000;--color-foreground-secondary:#5a5c63;--color-foreground-muted:#6b6f76;--color-foreground-border:#878787;--color-background-primary:#fff;--color-background-secondary:#f8f9fb;--color-background-hover:#efeff4;--color-background-hover--transparent:#efeff400;--color-background-border:#eeebee;--color-background-item:#ccc;--color-announcement-background:#000000dd;--color-announcement-text:#eeebee;--color-brand-primary:#0a4bff;--color-brand-content:#2757dd;--color-brand-visited:#872ee0;--color-api-background:var(--color-background-hover--transparent);--color-api-background-hover:var(--color-background-hover);--color-api-overall:var(--color-foreground-secondary);--color-api-name:var(--color-problematic);--color-api-pre-name:var(--color-problematic);--color-api-paren:var(--color-foreground-secondary);--color-api-keyword:var(--color-foreground-primary);--color-api-added:#21632c;--color-api-added-border:#38a84d;--color-api-changed:#046172;--color-api-changed-border:#06a1bc;--color-api-deprecated:#605706;--color-api-deprecated-border:#f0d90f;--color-api-removed:#b30000;--color-api-removed-border:#ff5c5c;--color-highlight-on-target:#ffc;--color-inline-code-background:var(--color-background-secondary);--color-highlighted-background:#def;--color-highlighted-text:var(--color-foreground-primary);--color-guilabel-background:#ddeeff80;--color-guilabel-border:#bedaf580;--color-guilabel-text:var(--color-foreground-primary);--color-admonition-background:transparent;--color-table-header-background:var(--color-background-secondary);--color-table-border:var(--color-background-border);--color-card-border:var(--color-background-secondary);--color-card-background:transparent;--color-card-marginals-background:var(--color-background-secondary);--color-header-background:var(--color-background-primary);--color-header-border:var(--color-background-border);--color-header-text:var(--color-foreground-primary);--color-sidebar-background:var(--color-background-secondary);--color-sidebar-background-border:var(--color-background-border);--color-sidebar-brand-text:var(--color-foreground-primary);--color-sidebar-caption-text:var(--color-foreground-muted);--color-sidebar-link-text:var(--color-foreground-secondary);--color-sidebar-link-text--top-level:var(--color-brand-primary);--color-sidebar-item-background:var(--color-sidebar-background);--color-sidebar-item-background--current:var( --color-sidebar-item-background );--color-sidebar-item-background--hover:linear-gradient(90deg,var(--color-background-hover--transparent) 0%,var(--color-background-hover) var(--sidebar-item-spacing-horizontal),var(--color-background-hover) 100%);--color-sidebar-item-expander-background:transparent;--color-sidebar-item-expander-background--hover:var( --color-background-hover );--color-sidebar-search-text:var(--color-foreground-primary);--color-sidebar-search-background:var(--color-background-secondary);--color-sidebar-search-background--focus:var(--color-background-primary);--color-sidebar-search-border:var(--color-background-border);--color-sidebar-search-icon:var(--color-foreground-muted);--color-toc-background:var(--color-background-primary);--color-toc-title-text:var(--color-foreground-muted);--color-toc-item-text:var(--color-foreground-secondary);--color-toc-item-text--hover:var(--color-foreground-primary);--color-toc-item-text--active:var(--color-brand-primary);--color-content-foreground:var(--color-foreground-primary);--color-content-background:transparent;--color-link:var(--color-brand-content);--color-link-underline:var(--color-background-border);--color-link--hover:var(--color-brand-content);--color-link-underline--hover:var(--color-foreground-border);--color-link--visited:var(--color-brand-visited);--color-link-underline--visited:var(--color-background-border);--color-link--visited--hover:var(--color-brand-visited);--color-link-underline--visited--hover:var(--color-foreground-border)}.only-light{display:block!important}html body .only-dark{display:none!important}@media not print{body[data-theme=dark]{--color-problematic:#ee5151;--color-foreground-primary:#cfd0d0;--color-foreground-secondary:#9ca0a5;--color-foreground-muted:#81868d;--color-foreground-border:#666;--color-background-primary:#131416;--color-background-secondary:#1a1c1e;--color-background-hover:#1e2124;--color-background-hover--transparent:#1e212400;--color-background-border:#303335;--color-background-item:#444;--color-announcement-background:#000000dd;--color-announcement-text:#eeebee;--color-brand-primary:#3d94ff;--color-brand-content:#5ca5ff;--color-brand-visited:#b27aeb;--color-highlighted-background:#083563;--color-guilabel-background:#08356380;--color-guilabel-border:#13395f80;--color-api-keyword:var(--color-foreground-secondary);--color-highlight-on-target:#330;--color-api-added:#3db854;--color-api-added-border:#267334;--color-api-changed:#09b0ce;--color-api-changed-border:#056d80;--color-api-deprecated:#b1a10b;--color-api-deprecated-border:#6e6407;--color-api-removed:#ff7575;--color-api-removed-border:#b03b3b;--color-admonition-background:#18181a;--color-card-border:var(--color-background-secondary);--color-card-background:#18181a;--color-card-marginals-background:var(--color-background-hover)}html body[data-theme=dark] .only-light{display:none!important}body[data-theme=dark] .only-dark{display:block!important}@media(prefers-color-scheme:dark){body:not([data-theme=light]){--color-problematic:#ee5151;--color-foreground-primary:#cfd0d0;--color-foreground-secondary:#9ca0a5;--color-foreground-muted:#81868d;--color-foreground-border:#666;--color-background-primary:#131416;--color-background-secondary:#1a1c1e;--color-background-hover:#1e2124;--color-background-hover--transparent:#1e212400;--color-background-border:#303335;--color-background-item:#444;--color-announcement-background:#000000dd;--color-announcement-text:#eeebee;--color-brand-primary:#3d94ff;--color-brand-content:#5ca5ff;--color-brand-visited:#b27aeb;--color-highlighted-background:#083563;--color-guilabel-background:#08356380;--color-guilabel-border:#13395f80;--color-api-keyword:var(--color-foreground-secondary);--color-highlight-on-target:#330;--color-api-added:#3db854;--color-api-added-border:#267334;--color-api-changed:#09b0ce;--color-api-changed-border:#056d80;--color-api-deprecated:#b1a10b;--color-api-deprecated-border:#6e6407;--color-api-removed:#ff7575;--color-api-removed-border:#b03b3b;--color-admonition-background:#18181a;--color-card-border:var(--color-background-secondary);--color-card-background:#18181a;--color-card-marginals-background:var(--color-background-hover)}html body:not([data-theme=light]) .only-light{display:none!important}body:not([data-theme=light]) .only-dark{display:block!important}}}body[data-theme=auto] .theme-toggle svg.theme-icon-when-auto-light{display:block}@media(prefers-color-scheme:dark){body[data-theme=auto] .theme-toggle svg.theme-icon-when-auto-dark{display:block}body[data-theme=auto] .theme-toggle svg.theme-icon-when-auto-light{display:none}}body[data-theme=dark] .theme-toggle svg.theme-icon-when-dark,body[data-theme=light] .theme-toggle svg.theme-icon-when-light{display:block}body{font-family:var(--font-stack)}code,kbd,pre,samp{font-family:var(--font-stack--monospace)}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}article{line-height:1.5}h1,h2,h3,h4,h5,h6{border-radius:.5rem;font-family:var(--font-stack--headings);font-weight:700;line-height:1.25;margin:.5rem -.5rem;padding-left:.5rem;padding-right:.5rem}h1+p,h2+p,h3+p,h4+p,h5+p,h6+p{margin-top:0}h1{font-size:2.5em;margin-bottom:1rem}h1,h2{margin-top:1.75rem}h2{font-size:2em}h3{font-size:1.5em}h4{font-size:1.25em}h5{font-size:1.125em}h6{font-size:1em}small{font-size:80%;opacity:75%}p{margin-bottom:.75rem;margin-top:.5rem}hr.docutils{background-color:var(--color-background-border);border:0;height:1px;margin:2rem 0;padding:0}.centered{text-align:center}a{color:var(--color-link);text-decoration:underline;text-decoration-color:var(--color-link-underline)}a:visited{color:var(--color-link--visited);text-decoration-color:var(--color-link-underline--visited)}a:visited:hover{color:var(--color-link--visited--hover);text-decoration-color:var(--color-link-underline--visited--hover)}a:hover{color:var(--color-link--hover);text-decoration-color:var(--color-link-underline--hover)}a.muted-link{color:inherit}a.muted-link:hover{color:var(--color-link--hover);text-decoration-color:var(--color-link-underline--hover)}a.muted-link:hover:visited{color:var(--color-link--visited--hover);text-decoration-color:var(--color-link-underline--visited--hover)}html{overflow-x:hidden;overflow-y:scroll;scroll-behavior:smooth}.sidebar-scroll,.toc-scroll,article[role=main] *{scrollbar-color:var(--color-foreground-border) transparent;scrollbar-width:thin}.sidebar-scroll::-webkit-scrollbar,.toc-scroll::-webkit-scrollbar,article[role=main] ::-webkit-scrollbar{height:.25rem;width:.25rem}.sidebar-scroll::-webkit-scrollbar-thumb,.toc-scroll::-webkit-scrollbar-thumb,article[role=main] ::-webkit-scrollbar-thumb{background-color:var(--color-foreground-border);border-radius:.125rem}body,html{height:100%}.skip-to-content,body,html{background:var(--color-background-primary);color:var(--color-foreground-primary)}.skip-to-content{border-radius:1rem;left:.25rem;padding:1rem;position:fixed;top:.25rem;transform:translateY(-200%);transition:transform .3s ease-in-out;z-index:40}.skip-to-content:focus-within{transform:translateY(0)}article{background:var(--color-content-background);color:var(--color-content-foreground);overflow-wrap:break-word}.page{display:flex;min-height:100%}.mobile-header{background-color:var(--color-header-background);border-bottom:1px solid var(--color-header-border);color:var(--color-header-text);display:none;height:var(--header-height);width:100%;z-index:10}.mobile-header.scrolled{border-bottom:none;box-shadow:0 0 .2rem rgba(0,0,0,.1),0 .2rem .4rem rgba(0,0,0,.2)}.mobile-header .header-center a{color:var(--color-header-text);text-decoration:none}.main{display:flex;flex:1}.sidebar-drawer{background:var(--color-sidebar-background);border-right:1px solid var(--color-sidebar-background-border);box-sizing:border-box;display:flex;justify-content:flex-end;min-width:15em;width:calc(50% - 26em)}.sidebar-container,.toc-drawer{box-sizing:border-box;width:15em}.toc-drawer{background:var(--color-toc-background);padding-right:1rem}.sidebar-sticky,.toc-sticky{display:flex;flex-direction:column;height:min(100%,100vh);height:100vh;position:sticky;top:0}.sidebar-scroll,.toc-scroll{flex-grow:1;flex-shrink:1;overflow:auto;scroll-behavior:smooth}.content{display:flex;flex-direction:column;justify-content:space-between;padding:0 3em;width:46em}.icon{display:inline-block;height:1rem;width:1rem}.icon svg{height:100%;width:100%}.announcement{align-items:center;background-color:var(--color-announcement-background);color:var(--color-announcement-text);display:flex;height:var(--header-height);overflow-x:auto}.announcement+.page{min-height:calc(100% - var(--header-height))}.announcement-content{box-sizing:border-box;min-width:100%;padding:.5rem;text-align:center;white-space:nowrap}.announcement-content a{color:var(--color-announcement-text);text-decoration-color:var(--color-announcement-text)}.announcement-content a:hover{color:var(--color-announcement-text);text-decoration-color:var(--color-link--hover)}.no-js .theme-toggle-container{display:none}.theme-toggle-container{display:flex}.theme-toggle{background:transparent;border:none;cursor:pointer;display:flex;padding:0}.theme-toggle svg{color:var(--color-foreground-primary);display:none;height:1.25rem;width:1.25rem}.theme-toggle-header{align-items:center;display:flex;justify-content:center}.nav-overlay-icon,.toc-overlay-icon{cursor:pointer;display:none}.nav-overlay-icon .icon,.toc-overlay-icon .icon{color:var(--color-foreground-secondary);height:1.5rem;width:1.5rem}.nav-overlay-icon,.toc-header-icon{align-items:center;justify-content:center}.toc-content-icon{height:1.5rem;width:1.5rem}.content-icon-container{display:flex;float:right;gap:.5rem;margin-bottom:1rem;margin-left:1rem;margin-top:1.5rem}.content-icon-container .edit-this-page svg,.content-icon-container .view-this-page svg{color:inherit;height:1.25rem;width:1.25rem}.sidebar-toggle{display:none;position:absolute}.sidebar-toggle[name=__toc]{left:20px}.sidebar-toggle:checked{left:40px}.overlay{background-color:rgba(0,0,0,.54);height:0;opacity:0;position:fixed;top:0;transition:width 0ms,height 0ms,opacity .25s ease-out;width:0}.sidebar-overlay{z-index:20}.toc-overlay{z-index:40}.sidebar-drawer{transition:left .25s ease-in-out;z-index:30}.toc-drawer{transition:right .25s ease-in-out;z-index:50}#__navigation:checked~.sidebar-overlay{height:100%;opacity:1;width:100%}#__navigation:checked~.page .sidebar-drawer{left:0;top:0}#__toc:checked~.toc-overlay{height:100%;opacity:1;width:100%}#__toc:checked~.page .toc-drawer{right:0;top:0}.back-to-top{background:var(--color-background-primary);border-radius:1rem;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 1px 0 hsla(220,9%,46%,.502);display:none;font-size:.8125rem;left:0;margin-left:50%;padding:.5rem .75rem .5rem .5rem;position:fixed;text-decoration:none;top:1rem;transform:translateX(-50%);z-index:10}.back-to-top svg{height:1rem;width:1rem;fill:currentColor;display:inline-block}.back-to-top span{margin-left:.25rem}.show-back-to-top .back-to-top{align-items:center;display:flex}@media(min-width:97em){html{font-size:110%}}@media(max-width:82em){.toc-content-icon{display:flex}.toc-drawer{border-left:1px solid var(--color-background-muted);height:100vh;position:fixed;right:-15em;top:0}.toc-tree{border-left:none;font-size:var(--toc-font-size--mobile)}.sidebar-drawer{width:calc(50% - 18.5em)}}@media(max-width:67em){.content{margin-left:auto;margin-right:auto;padding:0 1em}}@media(max-width:63em){.nav-overlay-icon{display:flex}.sidebar-drawer{height:100vh;left:-15em;position:fixed;top:0;width:15em}.theme-toggle-header,.toc-header-icon{display:flex}.theme-toggle-content,.toc-content-icon{display:none}.mobile-header{align-items:center;display:flex;justify-content:space-between;position:sticky;top:0}.mobile-header .header-left,.mobile-header .header-right{display:flex;height:var(--header-height);padding:0 var(--header-padding)}.mobile-header .header-left label,.mobile-header .header-right label{height:100%;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:100%}.nav-overlay-icon .icon,.theme-toggle svg{height:1.5rem;width:1.5rem}:target{scroll-margin-top:calc(var(--header-height) + 2.5rem)}.back-to-top{top:calc(var(--header-height) + .5rem)}.page{flex-direction:column;justify-content:center}}@media(max-width:48em){.content{overflow-x:auto;width:100%}}@media(max-width:46em){article[role=main] aside.sidebar{float:none;margin:1rem 0;width:100%}}.admonition,.topic{background:var(--color-admonition-background);border-radius:.2rem;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 .0625rem rgba(0,0,0,.1);font-size:var(--admonition-font-size);margin:1rem auto;overflow:hidden;padding:0 .5rem .5rem;page-break-inside:avoid}.admonition>:nth-child(2),.topic>:nth-child(2){margin-top:0}.admonition>:last-child,.topic>:last-child{margin-bottom:0}.admonition p.admonition-title,p.topic-title{font-size:var(--admonition-title-font-size);font-weight:500;line-height:1.3;margin:0 -.5rem .5rem;padding:.4rem .5rem .4rem 2rem;position:relative}.admonition p.admonition-title:before,p.topic-title:before{content:"";height:1rem;left:.5rem;position:absolute;width:1rem}p.admonition-title{background-color:var(--color-admonition-title-background)}p.admonition-title:before{background-color:var(--color-admonition-title);-webkit-mask-image:var(--icon-admonition-default);mask-image:var(--icon-admonition-default);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}p.topic-title{background-color:var(--color-topic-title-background)}p.topic-title:before{background-color:var(--color-topic-title);-webkit-mask-image:var(--icon-topic-default);mask-image:var(--icon-topic-default);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}.admonition{border-left:.2rem solid var(--color-admonition-title)}.admonition.caution{border-left-color:var(--color-admonition-title--caution)}.admonition.caution>.admonition-title{background-color:var(--color-admonition-title-background--caution)}.admonition.caution>.admonition-title:before{background-color:var(--color-admonition-title--caution);-webkit-mask-image:var(--icon-spark);mask-image:var(--icon-spark)}.admonition.warning{border-left-color:var(--color-admonition-title--warning)}.admonition.warning>.admonition-title{background-color:var(--color-admonition-title-background--warning)}.admonition.warning>.admonition-title:before{background-color:var(--color-admonition-title--warning);-webkit-mask-image:var(--icon-warning);mask-image:var(--icon-warning)}.admonition.danger{border-left-color:var(--color-admonition-title--danger)}.admonition.danger>.admonition-title{background-color:var(--color-admonition-title-background--danger)}.admonition.danger>.admonition-title:before{background-color:var(--color-admonition-title--danger);-webkit-mask-image:var(--icon-spark);mask-image:var(--icon-spark)}.admonition.attention{border-left-color:var(--color-admonition-title--attention)}.admonition.attention>.admonition-title{background-color:var(--color-admonition-title-background--attention)}.admonition.attention>.admonition-title:before{background-color:var(--color-admonition-title--attention);-webkit-mask-image:var(--icon-warning);mask-image:var(--icon-warning)}.admonition.error{border-left-color:var(--color-admonition-title--error)}.admonition.error>.admonition-title{background-color:var(--color-admonition-title-background--error)}.admonition.error>.admonition-title:before{background-color:var(--color-admonition-title--error);-webkit-mask-image:var(--icon-failure);mask-image:var(--icon-failure)}.admonition.hint{border-left-color:var(--color-admonition-title--hint)}.admonition.hint>.admonition-title{background-color:var(--color-admonition-title-background--hint)}.admonition.hint>.admonition-title:before{background-color:var(--color-admonition-title--hint);-webkit-mask-image:var(--icon-question);mask-image:var(--icon-question)}.admonition.tip{border-left-color:var(--color-admonition-title--tip)}.admonition.tip>.admonition-title{background-color:var(--color-admonition-title-background--tip)}.admonition.tip>.admonition-title:before{background-color:var(--color-admonition-title--tip);-webkit-mask-image:var(--icon-info);mask-image:var(--icon-info)}.admonition.important{border-left-color:var(--color-admonition-title--important)}.admonition.important>.admonition-title{background-color:var(--color-admonition-title-background--important)}.admonition.important>.admonition-title:before{background-color:var(--color-admonition-title--important);-webkit-mask-image:var(--icon-flame);mask-image:var(--icon-flame)}.admonition.note{border-left-color:var(--color-admonition-title--note)}.admonition.note>.admonition-title{background-color:var(--color-admonition-title-background--note)}.admonition.note>.admonition-title:before{background-color:var(--color-admonition-title--note);-webkit-mask-image:var(--icon-pencil);mask-image:var(--icon-pencil)}.admonition.seealso{border-left-color:var(--color-admonition-title--seealso)}.admonition.seealso>.admonition-title{background-color:var(--color-admonition-title-background--seealso)}.admonition.seealso>.admonition-title:before{background-color:var(--color-admonition-title--seealso);-webkit-mask-image:var(--icon-info);mask-image:var(--icon-info)}.admonition.admonition-todo{border-left-color:var(--color-admonition-title--admonition-todo)}.admonition.admonition-todo>.admonition-title{background-color:var(--color-admonition-title-background--admonition-todo)}.admonition.admonition-todo>.admonition-title:before{background-color:var(--color-admonition-title--admonition-todo);-webkit-mask-image:var(--icon-pencil);mask-image:var(--icon-pencil)}.admonition-todo>.admonition-title{text-transform:uppercase}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd{margin-left:2rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd>:first-child{margin-top:.125rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list,dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd>:last-child{margin-bottom:.75rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list>dt{font-size:var(--font-size--small);text-transform:uppercase}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd:empty{margin-bottom:.5rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd>ul{margin-left:-1.2rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd>ul>li>p:nth-child(2){margin-top:0}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd>ul>li>p+p:last-child:empty{margin-bottom:0;margin-top:0}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt{color:var(--color-api-overall)}.sig:not(.sig-inline){background:var(--color-api-background);border-radius:.25rem;font-family:var(--font-stack--monospace);font-size:var(--api-font-size);font-weight:700;margin-left:-.25rem;margin-right:-.25rem;padding:.25rem .5rem .25rem 3em;text-indent:-2.5em;transition:background .1s ease-out}.sig:not(.sig-inline):hover{background:var(--color-api-background-hover)}.sig:not(.sig-inline) a.reference .viewcode-link{font-weight:400;width:4.25rem}em.property{font-style:normal}em.property:first-child{color:var(--color-api-keyword)}.sig-name{color:var(--color-api-name)}.sig-prename{color:var(--color-api-pre-name);font-weight:400}.sig-paren{color:var(--color-api-paren)}.sig-param{font-style:normal}div.deprecated,div.versionadded,div.versionchanged,div.versionremoved{border-left:.1875rem solid;border-radius:.125rem;padding-left:.75rem}div.deprecated p,div.versionadded p,div.versionchanged p,div.versionremoved p{margin-bottom:.125rem;margin-top:.125rem}div.versionadded{border-color:var(--color-api-added-border)}div.versionadded .versionmodified{color:var(--color-api-added)}div.versionchanged{border-color:var(--color-api-changed-border)}div.versionchanged .versionmodified{color:var(--color-api-changed)}div.deprecated{border-color:var(--color-api-deprecated-border)}div.deprecated .versionmodified{color:var(--color-api-deprecated)}div.versionremoved{border-color:var(--color-api-removed-border)}div.versionremoved .versionmodified{color:var(--color-api-removed)}.viewcode-back,.viewcode-link{float:right;text-align:right}.line-block{margin-bottom:.75rem;margin-top:.5rem}.line-block .line-block{margin-bottom:0;margin-top:0;padding-left:1rem}.code-block-caption,article p.caption,table>caption{font-size:var(--font-size--small);text-align:center}.toctree-wrapper.compound .caption,.toctree-wrapper.compound :not(.caption)>.caption-text{font-size:var(--font-size--small);margin-bottom:0;text-align:initial;text-transform:uppercase}.toctree-wrapper.compound>ul{margin-bottom:0;margin-top:0}.sig-inline,code.literal{background:var(--color-inline-code-background);border-radius:.2em;font-size:var(--font-size--small--2);padding:.1em .2em}pre.literal-block .sig-inline,pre.literal-block code.literal{font-size:inherit;padding:0}p .sig-inline,p code.literal{border:1px solid var(--color-background-border)}.sig-inline{font-family:var(--font-stack--monospace)}div[class*=" highlight-"],div[class^=highlight-]{display:flex;margin:1em 0}div[class*=" highlight-"] .table-wrapper,div[class^=highlight-] .table-wrapper,pre{margin:0;padding:0}pre{overflow:auto}article[role=main] .highlight pre{line-height:1.5}.highlight pre,pre.literal-block{font-size:var(--code-font-size);padding:.625rem .875rem}pre.literal-block{background-color:var(--color-code-background);border-radius:.2rem;color:var(--color-code-foreground);margin-bottom:1rem;margin-top:1rem}.highlight{border-radius:.2rem;width:100%}.highlight .gp,.highlight span.linenos{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.highlight .hll{display:block;margin-left:-.875rem;margin-right:-.875rem;padding-left:.875rem;padding-right:.875rem}.code-block-caption{background-color:var(--color-code-background);border-bottom:1px solid;border-radius:.25rem;border-bottom-left-radius:0;border-bottom-right-radius:0;border-color:var(--color-background-border);color:var(--color-code-foreground);display:flex;font-weight:300;padding:.625rem .875rem}.code-block-caption+div[class]{margin-top:0}.code-block-caption+div[class] pre{border-top-left-radius:0;border-top-right-radius:0}.highlighttable{display:block;width:100%}.highlighttable tbody{display:block}.highlighttable tr{display:flex}.highlighttable td.linenos{background-color:var(--color-code-background);border-bottom-left-radius:.2rem;border-top-left-radius:.2rem;color:var(--color-code-foreground);padding:.625rem 0 .625rem .875rem}.highlighttable .linenodiv{box-shadow:-.0625rem 0 var(--color-foreground-border) inset;font-size:var(--code-font-size);padding-right:.875rem}.highlighttable td.code{display:block;flex:1;overflow:hidden;padding:0}.highlighttable td.code .highlight{border-bottom-left-radius:0;border-top-left-radius:0}.highlight span.linenos{box-shadow:-.0625rem 0 var(--color-foreground-border) inset;display:inline-block;margin-right:.875rem;padding-left:0;padding-right:.875rem}.footnote-reference{font-size:var(--font-size--small--4);vertical-align:super}dl.footnote.brackets{color:var(--color-foreground-secondary);display:grid;font-size:var(--font-size--small);grid-template-columns:max-content auto}dl.footnote.brackets dt{margin:0}dl.footnote.brackets dt>.fn-backref{margin-left:.25rem}dl.footnote.brackets dt:after{content:":"}dl.footnote.brackets dt .brackets:before{content:"["}dl.footnote.brackets dt .brackets:after{content:"]"}dl.footnote.brackets dd{margin:0;padding:0 1rem}aside.footnote{color:var(--color-foreground-secondary);font-size:var(--font-size--small)}aside.footnote>span,div.citation>span{float:left;font-weight:500;padding-right:.25rem}aside.footnote>:not(span),div.citation>p{margin-left:2rem}img{box-sizing:border-box;height:auto;max-width:100%}article .figure,article figure{border-radius:.2rem;margin:0}article .figure :last-child,article figure :last-child{margin-bottom:0}article .align-left{clear:left;float:left;margin:0 1rem 1rem}article .align-right{clear:right;float:right;margin:0 1rem 1rem}article .align-center,article .align-default{display:block;margin-left:auto;margin-right:auto;text-align:center}article table.align-default{display:table;text-align:initial}.domainindex-jumpbox,.genindex-jumpbox{border-bottom:1px solid var(--color-background-border);border-top:1px solid var(--color-background-border);padding:.25rem}.domainindex-section h2,.genindex-section h2{margin-bottom:.5rem;margin-top:.75rem}.domainindex-section ul,.genindex-section ul{margin-bottom:0;margin-top:0}ol,ul{margin-bottom:1rem;margin-top:1rem;padding-left:1.2rem}ol li>p:first-child,ul li>p:first-child{margin-bottom:.25rem;margin-top:.25rem}ol li>p:last-child,ul li>p:last-child{margin-top:.25rem}ol li>ol,ol li>ul,ul li>ol,ul li>ul{margin-bottom:.5rem;margin-top:.5rem}ol.arabic{list-style:decimal}ol.loweralpha{list-style:lower-alpha}ol.upperalpha{list-style:upper-alpha}ol.lowerroman{list-style:lower-roman}ol.upperroman{list-style:upper-roman}.simple li>ol,.simple li>ul,.toctree-wrapper li>ol,.toctree-wrapper li>ul{margin-bottom:0;margin-top:0}.field-list dt,.option-list dt,dl.footnote dt,dl.glossary dt,dl.simple dt,dl:not([class]) dt{font-weight:500;margin-top:.25rem}.field-list dt+dt,.option-list dt+dt,dl.footnote dt+dt,dl.glossary dt+dt,dl.simple dt+dt,dl:not([class]) dt+dt{margin-top:0}.field-list dt .classifier:before,.option-list dt .classifier:before,dl.footnote dt .classifier:before,dl.glossary dt .classifier:before,dl.simple dt .classifier:before,dl:not([class]) dt .classifier:before{content:":";margin-left:.2rem;margin-right:.2rem}.field-list dd ul,.field-list dd>p:first-child,.option-list dd ul,.option-list dd>p:first-child,dl.footnote dd ul,dl.footnote dd>p:first-child,dl.glossary dd ul,dl.glossary dd>p:first-child,dl.simple dd ul,dl.simple dd>p:first-child,dl:not([class]) dd ul,dl:not([class]) dd>p:first-child{margin-top:.125rem}.field-list dd ul,.option-list dd ul,dl.footnote dd ul,dl.glossary dd ul,dl.simple dd ul,dl:not([class]) dd ul{margin-bottom:.125rem}.math-wrapper{overflow-x:auto;width:100%}div.math{position:relative;text-align:center}div.math .headerlink,div.math:focus .headerlink{display:none}div.math:hover .headerlink{display:inline-block}div.math span.eqno{position:absolute;right:.5rem;top:50%;transform:translateY(-50%);z-index:1}abbr[title]{cursor:help}.problematic{color:var(--color-problematic)}kbd:not(.compound){background-color:var(--color-background-secondary);border:1px solid var(--color-foreground-border);border-radius:.2rem;box-shadow:0 .0625rem 0 rgba(0,0,0,.2),inset 0 0 0 .125rem var(--color-background-primary);color:var(--color-foreground-primary);display:inline-block;font-size:var(--font-size--small--3);margin:0 .2rem;padding:0 .2rem;vertical-align:text-bottom}blockquote{background:var(--color-background-secondary);border-left:4px solid var(--color-background-border);margin-left:0;margin-right:0;padding:.5rem 1rem}blockquote .attribution{font-weight:600;text-align:right}blockquote.highlights,blockquote.pull-quote{font-size:1.25em}blockquote.epigraph,blockquote.pull-quote{border-left-width:0;border-radius:.5rem}blockquote.highlights{background:transparent;border-left-width:0}p .reference img{vertical-align:middle}p.rubric{font-size:1.125em;font-weight:700;line-height:1.25}dd p.rubric{font-size:var(--font-size--small);font-weight:inherit;line-height:inherit;text-transform:uppercase}article .sidebar{background-color:var(--color-background-secondary);border:1px solid var(--color-background-border);border-radius:.2rem;clear:right;float:right;margin-left:1rem;margin-right:0;width:30%}article .sidebar>*{padding-left:1rem;padding-right:1rem}article .sidebar>ol,article .sidebar>ul{padding-left:2.2rem}article .sidebar .sidebar-title{border-bottom:1px solid var(--color-background-border);font-weight:500;margin:0;padding:.5rem 1rem}[role=main] .table-wrapper.container{margin-bottom:.5rem;margin-top:1rem;overflow-x:auto;padding:.2rem .2rem .75rem;width:100%}table.docutils{border-collapse:collapse;border-radius:.2rem;border-spacing:0;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 .0625rem rgba(0,0,0,.1)}table.docutils th{background:var(--color-table-header-background)}table.docutils td,table.docutils th{border-bottom:1px solid var(--color-table-border);border-left:1px solid var(--color-table-border);border-right:1px solid var(--color-table-border);padding:0 .25rem}table.docutils td p,table.docutils th p{margin:.25rem}table.docutils td:first-child,table.docutils th:first-child{border-left:none}table.docutils td:last-child,table.docutils th:last-child{border-right:none}table.docutils td.text-left,table.docutils th.text-left{text-align:left}table.docutils td.text-right,table.docutils th.text-right{text-align:right}table.docutils td.text-center,table.docutils th.text-center{text-align:center}:target{scroll-margin-top:2.5rem}@media(max-width:67em){:target{scroll-margin-top:calc(2.5rem + var(--header-height))}section>span:target{scroll-margin-top:calc(2.8rem + var(--header-height))}}.headerlink{font-weight:100;-webkit-user-select:none;-moz-user-select:none;user-select:none}.code-block-caption>.headerlink,dl dt>.headerlink,figcaption p>.headerlink,h1>.headerlink,h2>.headerlink,h3>.headerlink,h4>.headerlink,h5>.headerlink,h6>.headerlink,p.caption>.headerlink,table>caption>.headerlink{margin-left:.5rem;visibility:hidden}.code-block-caption:hover>.headerlink,dl dt:hover>.headerlink,figcaption p:hover>.headerlink,h1:hover>.headerlink,h2:hover>.headerlink,h3:hover>.headerlink,h4:hover>.headerlink,h5:hover>.headerlink,h6:hover>.headerlink,p.caption:hover>.headerlink,table>caption:hover>.headerlink{visibility:visible}.code-block-caption>.toc-backref,dl dt>.toc-backref,figcaption p>.toc-backref,h1>.toc-backref,h2>.toc-backref,h3>.toc-backref,h4>.toc-backref,h5>.toc-backref,h6>.toc-backref,p.caption>.toc-backref,table>caption>.toc-backref{color:inherit;text-decoration-line:none}figure:hover>figcaption>p>.headerlink,table:hover>caption>.headerlink{visibility:visible}:target>h1:first-of-type,:target>h2:first-of-type,:target>h3:first-of-type,:target>h4:first-of-type,:target>h5:first-of-type,:target>h6:first-of-type,span:target~h1:first-of-type,span:target~h2:first-of-type,span:target~h3:first-of-type,span:target~h4:first-of-type,span:target~h5:first-of-type,span:target~h6:first-of-type{background-color:var(--color-highlight-on-target)}:target>h1:first-of-type code.literal,:target>h2:first-of-type code.literal,:target>h3:first-of-type code.literal,:target>h4:first-of-type code.literal,:target>h5:first-of-type code.literal,:target>h6:first-of-type code.literal,span:target~h1:first-of-type code.literal,span:target~h2:first-of-type code.literal,span:target~h3:first-of-type code.literal,span:target~h4:first-of-type code.literal,span:target~h5:first-of-type code.literal,span:target~h6:first-of-type code.literal{background-color:transparent}.literal-block-wrapper:target .code-block-caption,.this-will-duplicate-information-and-it-is-still-useful-here li :target,figure:target,table:target>caption{background-color:var(--color-highlight-on-target)}dt:target{background-color:var(--color-highlight-on-target)!important}.footnote-reference:target,.footnote>dt:target+dd{background-color:var(--color-highlight-on-target)}.guilabel{background-color:var(--color-guilabel-background);border:1px solid var(--color-guilabel-border);border-radius:.5em;color:var(--color-guilabel-text);font-size:.9em;padding:0 .3em}footer{display:flex;flex-direction:column;font-size:var(--font-size--small);margin-top:2rem}.bottom-of-page{align-items:center;border-top:1px solid var(--color-background-border);color:var(--color-foreground-secondary);display:flex;justify-content:space-between;line-height:1.5;margin-top:1rem;padding-bottom:1rem;padding-top:1rem}@media(max-width:46em){.bottom-of-page{flex-direction:column-reverse;gap:.25rem;text-align:center}}.bottom-of-page .left-details{font-size:var(--font-size--small)}.bottom-of-page .right-details{display:flex;flex-direction:column;gap:.25rem;text-align:right}.bottom-of-page .icons{display:flex;font-size:1rem;gap:.25rem;justify-content:flex-end}.bottom-of-page .icons a{text-decoration:none}.bottom-of-page .icons img,.bottom-of-page .icons svg{font-size:1.125rem;height:1em;width:1em}.related-pages a{align-items:center;display:flex;text-decoration:none}.related-pages a:hover .page-info .title{color:var(--color-link);text-decoration:underline;text-decoration-color:var(--color-link-underline)}.related-pages a svg.furo-related-icon,.related-pages a svg.furo-related-icon>use{color:var(--color-foreground-border);flex-shrink:0;height:.75rem;margin:0 .5rem;width:.75rem}.related-pages a.next-page{clear:right;float:right;max-width:50%;text-align:right}.related-pages a.prev-page{clear:left;float:left;max-width:50%}.related-pages a.prev-page svg{transform:rotate(180deg)}.page-info{display:flex;flex-direction:column;overflow-wrap:anywhere}.next-page .page-info{align-items:flex-end}.page-info .context{align-items:center;color:var(--color-foreground-muted);display:flex;font-size:var(--font-size--small);padding-bottom:.1rem;text-decoration:none}ul.search{list-style:none;padding-left:0}ul.search li{border-bottom:1px solid var(--color-background-border);padding:1rem 0}[role=main] .highlighted{background-color:var(--color-highlighted-background);color:var(--color-highlighted-text)}.sidebar-brand{display:flex;flex-direction:column;flex-shrink:0;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal);text-decoration:none}.sidebar-brand-text{color:var(--color-sidebar-brand-text);font-size:1.5rem;overflow-wrap:break-word}.sidebar-brand-text,.sidebar-logo-container{margin:var(--sidebar-item-spacing-vertical) 0}.sidebar-logo{display:block;margin:0 auto;max-width:100%}.sidebar-search-container{align-items:center;background:var(--color-sidebar-search-background);display:flex;margin-top:var(--sidebar-search-space-above);position:relative}.sidebar-search-container:focus-within,.sidebar-search-container:hover{background:var(--color-sidebar-search-background--focus)}.sidebar-search-container:before{background-color:var(--color-sidebar-search-icon);content:"";height:var(--sidebar-search-icon-size);left:var(--sidebar-item-spacing-horizontal);-webkit-mask-image:var(--icon-search);mask-image:var(--icon-search);position:absolute;width:var(--sidebar-search-icon-size)}.sidebar-search{background:transparent;border:none;border-bottom:1px solid var(--color-sidebar-search-border);border-top:1px solid var(--color-sidebar-search-border);box-sizing:border-box;color:var(--color-sidebar-search-foreground);padding:var(--sidebar-search-input-spacing-vertical) var(--sidebar-search-input-spacing-horizontal) var(--sidebar-search-input-spacing-vertical) calc(var(--sidebar-item-spacing-horizontal) + var(--sidebar-search-input-spacing-horizontal) + var(--sidebar-search-icon-size));width:100%;z-index:10}.sidebar-search:focus{outline:none}.sidebar-search::-moz-placeholder{font-size:var(--sidebar-search-input-font-size)}.sidebar-search::placeholder{font-size:var(--sidebar-search-input-font-size)}#searchbox .highlight-link{margin:0;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal) 0;text-align:center}#searchbox .highlight-link a{color:var(--color-sidebar-search-icon);font-size:var(--font-size--small--2)}.sidebar-tree{font-size:var(--sidebar-item-font-size);margin-bottom:var(--sidebar-item-spacing-vertical);margin-top:var(--sidebar-tree-space-above)}.sidebar-tree ul{display:flex;flex-direction:column;list-style:none;margin-bottom:0;margin-top:0;padding:0}.sidebar-tree li{margin:0;position:relative}.sidebar-tree li>ul{margin-left:var(--sidebar-item-spacing-horizontal)}.sidebar-tree .icon,.sidebar-tree .reference{color:var(--color-sidebar-link-text)}.sidebar-tree .reference{box-sizing:border-box;display:inline-block;height:100%;line-height:var(--sidebar-item-line-height);overflow-wrap:anywhere;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal);text-decoration:none;width:100%}.sidebar-tree .reference:hover{background:var(--color-sidebar-item-background--hover);color:var(--color-sidebar-link-text)}.sidebar-tree .reference.external:after{color:var(--color-sidebar-link-text);content:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23607D8B' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' viewBox='0 0 24 24'%3E%3Cpath stroke='none' d='M0 0h24v24H0z'/%3E%3Cpath d='M11 7H6a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2v-5M10 14 20 4M15 4h5v5'/%3E%3C/svg%3E");margin:0 .25rem;vertical-align:middle}.sidebar-tree .current-page>.reference{font-weight:700}.sidebar-tree label{align-items:center;cursor:pointer;display:flex;height:var(--sidebar-item-height);justify-content:center;position:absolute;right:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:var(--sidebar-expander-width)}.sidebar-tree .caption,.sidebar-tree :not(.caption)>.caption-text{color:var(--color-sidebar-caption-text);font-size:var(--sidebar-caption-font-size);font-weight:700;margin:var(--sidebar-caption-space-above) 0 0 0;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal);text-transform:uppercase}.sidebar-tree li.has-children>.reference{padding-right:var(--sidebar-expander-width)}.sidebar-tree .toctree-l1>.reference,.sidebar-tree .toctree-l1>label .icon{color:var(--color-sidebar-link-text--top-level)}.sidebar-tree label{background:var(--color-sidebar-item-expander-background)}.sidebar-tree label:hover{background:var(--color-sidebar-item-expander-background--hover)}.sidebar-tree .current>.reference{background:var(--color-sidebar-item-background--current)}.sidebar-tree .current>.reference:hover{background:var(--color-sidebar-item-background--hover)}.toctree-checkbox{display:none;position:absolute}.toctree-checkbox~ul{display:none}.toctree-checkbox~label .icon svg{transform:rotate(90deg)}.toctree-checkbox:checked~ul{display:block}.toctree-checkbox:checked~label .icon svg{transform:rotate(-90deg)}.toc-title-container{padding:var(--toc-title-padding);padding-top:var(--toc-spacing-vertical)}.toc-title{color:var(--color-toc-title-text);font-size:var(--toc-title-font-size);padding-left:var(--toc-spacing-horizontal);text-transform:uppercase}.no-toc{display:none}.toc-tree-container{padding-bottom:var(--toc-spacing-vertical)}.toc-tree{border-left:1px solid var(--color-background-border);font-size:var(--toc-font-size);line-height:1.3;padding-left:calc(var(--toc-spacing-horizontal) - var(--toc-item-spacing-horizontal))}.toc-tree>ul>li:first-child{padding-top:0}.toc-tree>ul>li:first-child>ul{padding-left:0}.toc-tree>ul>li:first-child>a{display:none}.toc-tree ul{list-style-type:none;margin-bottom:0;margin-top:0;padding-left:var(--toc-item-spacing-horizontal)}.toc-tree li{padding-top:var(--toc-item-spacing-vertical)}.toc-tree li.scroll-current>.reference{color:var(--color-toc-item-text--active);font-weight:700}.toc-tree a.reference{color:var(--color-toc-item-text);overflow-wrap:anywhere;text-decoration:none}.toc-scroll{max-height:100vh;overflow-y:scroll}.contents:not(.this-will-duplicate-information-and-it-is-still-useful-here){background:rgba(255,0,0,.25);color:var(--color-problematic)}.contents:not(.this-will-duplicate-information-and-it-is-still-useful-here):before{content:"ERROR: Adding a table of contents in Furo-based documentation is unnecessary, and does not work well with existing styling. Add a 'this-will-duplicate-information-and-it-is-still-useful-here' class, if you want an escape hatch."}.text-align\:left>p{text-align:left}.text-align\:center>p{text-align:center}.text-align\:right>p{text-align:right} +/*# sourceMappingURL=furo.css.map*/ \ No newline at end of file diff --git a/_static/styles/furo.css.map b/_static/styles/furo.css.map new file mode 100644 index 0000000..3ecc371 --- /dev/null +++ b/_static/styles/furo.css.map @@ -0,0 +1 @@ +{"version":3,"file":"styles/furo.css","mappings":"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sCAIA,aADF,WACE,CAKF,SACE,CAHJ,kBAEE,CAJE,gBAEJ,CAHI,iBAMA,yFAKA,aACA,eACA,cElbJ,iBAEE,aADA,iBACA,6BAEA,kCAEA,SACA,UAIA,gCACA,CALA,SAEA,SAEA,CAJA,0EAEA,CAFA,OAKA,CAGA,mDACE,iBAGF,gCACE,CADF,UACE,aAEJ,iCAEE,CAFF,UAEE,wCAEA,WACA,WADA,UACA,CACA,4CAGA,MACA,CADA,KACA,wCACA,UAGA,CAJA,UAIA,6DAUA,0CACE,CAFF,mBAEE,wEACA,CAVA,YACA,CAMF,mBAJE,OAOA,gBAJJ,gCACE,CANE,cACA,CAHA,oBACA,CAGA,QAGJ,CAII,0BACA,CADA,UACA,wCAEJ,kBACE,0DACA,gCACE,kBACA,CADA,YACA,oEACA,2CAMF,mDAII,CALN,YACE,CANE,cAKJ,CACE,iBAII,kEACA,yCACE,kDACA,yDACE,+CACA,uBANN,CAMM,+BANN,uCACE,qDACA,4BAEE,mBADA,0CACA,CADA,qBACA,0DACE,wCACA,sGALJ,oCACA,sBACE,kBAFF,UAEE,2CACA,wFACE,cACA,kEANN,uBACE,iDACA,CADA,UACA,0DACE,wDAEE,iEACA,qEANN,sCACE,CAGE,iBAHF,gBAGE,qBACE,CAJJ,uBACA,gDACE,wDACA,6DAHF,2CACA,CADA,gBACA,eACE,CAGE,sBANN,8BACE,CAII,iBAFF,4DACA,WACE,YADF,uCACE,6EACA,2BANN,8CACE,kDACA,0CACE,8BACA,yFACE,sBACA,sFALJ,mEACA,sBACE,kEACA,6EACE,uCACA,kEALJ,qGAEE,kEACA,6EACE,uCACA,kEALJ,8CACA,uDACE,sEACA,2EACE,sCACA,iEALJ,mGACA,qCACE,oDACA,0DACE,6GACA,gDAGR,yDCrEA,sEACE,CACA,6GACE,gEACF,iGAIF,wFACE,qDAGA,mGAEE,2CAEF,4FACE,gCACF,wGACE,8DAEE,6FAIA,iJAKN,6GACE,gDAKF,yDACA,qCAGA,6BACA,kBACA,qDAKA,oCAEA,+DAGA,2CAGE,oDAIA,oEAEE,qBAGJ,wDAEE,uCAEF,kE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","sources":["webpack:///./node_modules/normalize.css/normalize.css","webpack:///./src/furo/assets/styles/base/_print.sass","webpack:///./src/furo/assets/styles/base/_screen-readers.sass","webpack:///./src/furo/assets/styles/base/_theme.sass","webpack:///./src/furo/assets/styles/variables/_fonts.scss","webpack:///./src/furo/assets/styles/variables/_spacing.scss","webpack:///./src/furo/assets/styles/variables/_icons.scss","webpack:///./src/furo/assets/styles/variables/_admonitions.scss","webpack:///./src/furo/assets/styles/variables/_colors.scss","webpack:///./src/furo/assets/styles/base/_typography.sass","webpack:///./src/furo/assets/styles/_scaffold.sass","webpack:///./src/furo/assets/styles/variables/_layout.scss","webpack:///./src/furo/assets/styles/content/_admonitions.sass","webpack:///./src/furo/assets/styles/content/_api.sass","webpack:///./src/furo/assets/styles/content/_blocks.sass","webpack:///./src/furo/assets/styles/content/_captions.sass","webpack:///./src/furo/assets/styles/content/_code.sass","webpack:///./src/furo/assets/styles/content/_footnotes.sass","webpack:///./src/furo/assets/styles/content/_images.sass","webpack:///./src/furo/assets/styles/content/_indexes.sass","webpack:///./src/furo/assets/styles/content/_lists.sass","webpack:///./src/furo/assets/styles/content/_math.sass","webpack:///./src/furo/assets/styles/content/_misc.sass","webpack:///./src/furo/assets/styles/content/_rubrics.sass","webpack:///./src/furo/assets/styles/content/_sidebar.sass","webpack:///./src/furo/assets/styles/content/_tables.sass","webpack:///./src/furo/assets/styles/content/_target.sass","webpack:///./src/furo/assets/styles/content/_gui-labels.sass","webpack:///./src/furo/assets/styles/components/_footer.sass","webpack:///./src/furo/assets/styles/components/_sidebar.sass","webpack:///./src/furo/assets/styles/components/_table_of_contents.sass","webpack:///./src/furo/assets/styles/_shame.sass"],"sourcesContent":["/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */\n\n/* Document\n ========================================================================== */\n\n/**\n * 1. Correct the line height in all browsers.\n * 2. Prevent adjustments of font size after orientation changes in iOS.\n */\n\nhtml {\n line-height: 1.15; /* 1 */\n -webkit-text-size-adjust: 100%; /* 2 */\n}\n\n/* Sections\n ========================================================================== */\n\n/**\n * Remove the margin in all browsers.\n */\n\nbody {\n margin: 0;\n}\n\n/**\n * Render the `main` element consistently in IE.\n */\n\nmain {\n display: block;\n}\n\n/**\n * Correct the font size and margin on `h1` elements within `section` and\n * `article` contexts in Chrome, Firefox, and Safari.\n */\n\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\n\n/* Grouping content\n ========================================================================== */\n\n/**\n * 1. Add the correct box sizing in Firefox.\n * 2. Show the overflow in Edge and IE.\n */\n\nhr {\n box-sizing: content-box; /* 1 */\n height: 0; /* 1 */\n overflow: visible; /* 2 */\n}\n\n/**\n * 1. Correct the inheritance and scaling of font size in all browsers.\n * 2. Correct the odd `em` font sizing in all browsers.\n */\n\npre {\n font-family: monospace, monospace; /* 1 */\n font-size: 1em; /* 2 */\n}\n\n/* Text-level semantics\n ========================================================================== */\n\n/**\n * Remove the gray background on active links in IE 10.\n */\n\na {\n background-color: transparent;\n}\n\n/**\n * 1. Remove the bottom border in Chrome 57-\n * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.\n */\n\nabbr[title] {\n border-bottom: none; /* 1 */\n text-decoration: underline; /* 2 */\n text-decoration: underline dotted; /* 2 */\n}\n\n/**\n * Add the correct font weight in Chrome, Edge, and Safari.\n */\n\nb,\nstrong {\n font-weight: bolder;\n}\n\n/**\n * 1. Correct the inheritance and scaling of font size in all browsers.\n * 2. Correct the odd `em` font sizing in all browsers.\n */\n\ncode,\nkbd,\nsamp {\n font-family: monospace, monospace; /* 1 */\n font-size: 1em; /* 2 */\n}\n\n/**\n * Add the correct font size in all browsers.\n */\n\nsmall {\n font-size: 80%;\n}\n\n/**\n * Prevent `sub` and `sup` elements from affecting the line height in\n * all browsers.\n */\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -0.25em;\n}\n\nsup {\n top: -0.5em;\n}\n\n/* Embedded content\n ========================================================================== */\n\n/**\n * Remove the border on images inside links in IE 10.\n */\n\nimg {\n border-style: none;\n}\n\n/* Forms\n ========================================================================== */\n\n/**\n * 1. Change the font styles in all browsers.\n * 2. Remove the margin in Firefox and Safari.\n */\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n font-family: inherit; /* 1 */\n font-size: 100%; /* 1 */\n line-height: 1.15; /* 1 */\n margin: 0; /* 2 */\n}\n\n/**\n * Show the overflow in IE.\n * 1. Show the overflow in Edge.\n */\n\nbutton,\ninput { /* 1 */\n overflow: visible;\n}\n\n/**\n * Remove the inheritance of text transform in Edge, Firefox, and IE.\n * 1. Remove the inheritance of text transform in Firefox.\n */\n\nbutton,\nselect { /* 1 */\n text-transform: none;\n}\n\n/**\n * Correct the inability to style clickable types in iOS and Safari.\n */\n\nbutton,\n[type=\"button\"],\n[type=\"reset\"],\n[type=\"submit\"] {\n -webkit-appearance: button;\n}\n\n/**\n * Remove the inner border and padding in Firefox.\n */\n\nbutton::-moz-focus-inner,\n[type=\"button\"]::-moz-focus-inner,\n[type=\"reset\"]::-moz-focus-inner,\n[type=\"submit\"]::-moz-focus-inner {\n border-style: none;\n padding: 0;\n}\n\n/**\n * Restore the focus styles unset by the previous rule.\n */\n\nbutton:-moz-focusring,\n[type=\"button\"]:-moz-focusring,\n[type=\"reset\"]:-moz-focusring,\n[type=\"submit\"]:-moz-focusring {\n outline: 1px dotted ButtonText;\n}\n\n/**\n * Correct the padding in Firefox.\n */\n\nfieldset {\n padding: 0.35em 0.75em 0.625em;\n}\n\n/**\n * 1. Correct the text wrapping in Edge and IE.\n * 2. Correct the color inheritance from `fieldset` elements in IE.\n * 3. Remove the padding so developers are not caught out when they zero out\n * `fieldset` elements in all browsers.\n */\n\nlegend {\n box-sizing: border-box; /* 1 */\n color: inherit; /* 2 */\n display: table; /* 1 */\n max-width: 100%; /* 1 */\n padding: 0; /* 3 */\n white-space: normal; /* 1 */\n}\n\n/**\n * Add the correct vertical alignment in Chrome, Firefox, and Opera.\n */\n\nprogress {\n vertical-align: baseline;\n}\n\n/**\n * Remove the default vertical scrollbar in IE 10+.\n */\n\ntextarea {\n overflow: auto;\n}\n\n/**\n * 1. Add the correct box sizing in IE 10.\n * 2. Remove the padding in IE 10.\n */\n\n[type=\"checkbox\"],\n[type=\"radio\"] {\n box-sizing: border-box; /* 1 */\n padding: 0; /* 2 */\n}\n\n/**\n * Correct the cursor style of increment and decrement buttons in Chrome.\n */\n\n[type=\"number\"]::-webkit-inner-spin-button,\n[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n/**\n * 1. Correct the odd appearance in Chrome and Safari.\n * 2. Correct the outline style in Safari.\n */\n\n[type=\"search\"] {\n -webkit-appearance: textfield; /* 1 */\n outline-offset: -2px; /* 2 */\n}\n\n/**\n * Remove the inner padding in Chrome and Safari on macOS.\n */\n\n[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n/**\n * 1. Correct the inability to style clickable types in iOS and Safari.\n * 2. Change font properties to `inherit` in Safari.\n */\n\n::-webkit-file-upload-button {\n -webkit-appearance: button; /* 1 */\n font: inherit; /* 2 */\n}\n\n/* Interactive\n ========================================================================== */\n\n/*\n * Add the correct display in Edge, IE 10+, and Firefox.\n */\n\ndetails {\n display: block;\n}\n\n/*\n * Add the correct display in all browsers.\n */\n\nsummary {\n display: list-item;\n}\n\n/* Misc\n ========================================================================== */\n\n/**\n * Add the correct display in IE 10+.\n */\n\ntemplate {\n display: none;\n}\n\n/**\n * Add the correct display in IE 10.\n */\n\n[hidden] {\n display: none;\n}\n","// This file contains styles for managing print media.\n\n////////////////////////////////////////////////////////////////////////////////\n// Hide elements not relevant to print media.\n////////////////////////////////////////////////////////////////////////////////\n@media print\n // Hide icon container.\n .content-icon-container\n display: none !important\n\n // Hide showing header links if hovering over when printing.\n .headerlink\n display: none !important\n\n // Hide mobile header.\n .mobile-header\n display: none !important\n\n // Hide navigation links.\n .related-pages\n display: none !important\n\n////////////////////////////////////////////////////////////////////////////////\n// Tweaks related to decolorization.\n////////////////////////////////////////////////////////////////////////////////\n@media print\n // Apply a border around code which no longer have a color background.\n .highlight\n border: 0.1pt solid var(--color-foreground-border)\n\n////////////////////////////////////////////////////////////////////////////////\n// Avoid page break in some relevant cases.\n////////////////////////////////////////////////////////////////////////////////\n@media print\n ul, ol, dl, a, table, pre, blockquote, p\n page-break-inside: avoid\n\n h1, h2, h3, h4, h5, h6, img, figure, caption\n page-break-inside: avoid\n page-break-after: avoid\n\n ul, ol, dl\n page-break-before: avoid\n",".visually-hidden\n position: absolute !important\n width: 1px !important\n height: 1px !important\n padding: 0 !important\n margin: -1px !important\n overflow: hidden !important\n clip: rect(0,0,0,0) !important\n white-space: nowrap !important\n border: 0 !important\n color: var(--color-foreground-primary)\n background: var(--color-background-primary)\n\n:-moz-focusring\n outline: auto\n","// This file serves as the \"skeleton\" of the theming logic.\n//\n// This contains the bulk of the logic for handling dark mode, color scheme\n// toggling and the handling of color-scheme-specific hiding of elements.\n\nbody\n @include fonts\n @include spacing\n @include icons\n @include admonitions\n @include default-admonition(#651fff, \"abstract\")\n @include default-topic(#14B8A6, \"pencil\")\n\n @include colors\n\n.only-light\n display: block !important\nhtml body .only-dark\n display: none !important\n\n// Ignore dark-mode hints if print media.\n@media not print\n // Enable dark-mode, if requested.\n body[data-theme=\"dark\"]\n @include colors-dark\n\n html & .only-light\n display: none !important\n .only-dark\n display: block !important\n\n // Enable dark mode, unless explicitly told to avoid.\n @media (prefers-color-scheme: dark)\n body:not([data-theme=\"light\"])\n @include colors-dark\n\n html & .only-light\n display: none !important\n .only-dark\n display: block !important\n\n//\n// Theme toggle presentation\n//\nbody[data-theme=\"auto\"]\n .theme-toggle svg.theme-icon-when-auto-light\n display: block\n\n @media (prefers-color-scheme: dark)\n .theme-toggle svg.theme-icon-when-auto-dark\n display: block\n .theme-toggle svg.theme-icon-when-auto-light\n display: none\n\nbody[data-theme=\"dark\"]\n .theme-toggle svg.theme-icon-when-dark\n display: block\n\nbody[data-theme=\"light\"]\n .theme-toggle svg.theme-icon-when-light\n display: block\n","// Fonts used by this theme.\n//\n// There are basically two things here -- using the system font stack and\n// defining sizes for various elements in %ages. We could have also used `em`\n// but %age is easier to reason about for me.\n\n@mixin fonts {\n // These are adapted from https://systemfontstack.com/\n --font-stack: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,\n sans-serif, Apple Color Emoji, Segoe UI Emoji;\n --font-stack--monospace: \"SFMono-Regular\", Menlo, Consolas, Monaco,\n Liberation Mono, Lucida Console, monospace;\n --font-stack--headings: var(--font-stack);\n\n --font-size--normal: 100%;\n --font-size--small: 87.5%;\n --font-size--small--2: 81.25%;\n --font-size--small--3: 75%;\n --font-size--small--4: 62.5%;\n\n // Sidebar\n --sidebar-caption-font-size: var(--font-size--small--2);\n --sidebar-item-font-size: var(--font-size--small);\n --sidebar-search-input-font-size: var(--font-size--small);\n\n // Table of Contents\n --toc-font-size: var(--font-size--small--3);\n --toc-font-size--mobile: var(--font-size--normal);\n --toc-title-font-size: var(--font-size--small--4);\n\n // Admonitions\n //\n // These aren't defined in terms of %ages, since nesting these is permitted.\n --admonition-font-size: 0.8125rem;\n --admonition-title-font-size: 0.8125rem;\n\n // Code\n --code-font-size: var(--font-size--small--2);\n\n // API\n --api-font-size: var(--font-size--small);\n}\n","// Spacing for various elements on the page\n//\n// If the user wants to tweak things in a certain way, they are permitted to.\n// They also have to deal with the consequences though!\n\n@mixin spacing {\n // Header!\n --header-height: calc(\n var(--sidebar-item-line-height) + 4 * #{var(--sidebar-item-spacing-vertical)}\n );\n --header-padding: 0.5rem;\n\n // Sidebar\n --sidebar-tree-space-above: 1.5rem;\n --sidebar-caption-space-above: 1rem;\n\n --sidebar-item-line-height: 1rem;\n --sidebar-item-spacing-vertical: 0.5rem;\n --sidebar-item-spacing-horizontal: 1rem;\n --sidebar-item-height: calc(\n var(--sidebar-item-line-height) + 2 *#{var(--sidebar-item-spacing-vertical)}\n );\n\n --sidebar-expander-width: var(--sidebar-item-height); // be square\n\n --sidebar-search-space-above: 0.5rem;\n --sidebar-search-input-spacing-vertical: 0.5rem;\n --sidebar-search-input-spacing-horizontal: 0.5rem;\n --sidebar-search-input-height: 1rem;\n --sidebar-search-icon-size: var(--sidebar-search-input-height);\n\n // Table of Contents\n --toc-title-padding: 0.25rem 0;\n --toc-spacing-vertical: 1.5rem;\n --toc-spacing-horizontal: 1.5rem;\n --toc-item-spacing-vertical: 0.4rem;\n --toc-item-spacing-horizontal: 1rem;\n}\n","// Expose theme icons as CSS variables.\n\n$icons: (\n // Adapted from tabler-icons\n // url: https://tablericons.com/\n \"search\":\n url('data:image/svg+xml;charset=utf-8,'),\n // Factored out from mkdocs-material on 24-Aug-2020.\n // url: https://squidfunk.github.io/mkdocs-material/reference/admonitions/\n \"pencil\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"abstract\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"info\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"flame\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"question\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"warning\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"failure\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"spark\":\n url('data:image/svg+xml;charset=utf-8,')\n);\n\n@mixin icons {\n @each $name, $glyph in $icons {\n --icon-#{$name}: #{$glyph};\n }\n}\n","// Admonitions\n\n// Structure of these is:\n// admonition-class: color \"icon-name\";\n//\n// The colors are translated into CSS variables below. The icons are\n// used directly in the main declarations to set the `mask-image` in\n// the title.\n\n// prettier-ignore\n$admonitions: (\n // Each of these has an reST directives for it.\n \"caution\": #ff9100 \"spark\",\n \"warning\": #ff9100 \"warning\",\n \"danger\": #ff5252 \"spark\",\n \"attention\": #ff5252 \"warning\",\n \"error\": #ff5252 \"failure\",\n \"hint\": #00c852 \"question\",\n \"tip\": #00c852 \"info\",\n \"important\": #00bfa5 \"flame\",\n \"note\": #00b0ff \"pencil\",\n \"seealso\": #448aff \"info\",\n \"admonition-todo\": #808080 \"pencil\"\n);\n\n@mixin default-admonition($color, $icon-name) {\n --color-admonition-title: #{$color};\n --color-admonition-title-background: #{rgba($color, 0.2)};\n\n --icon-admonition-default: var(--icon-#{$icon-name});\n}\n\n@mixin default-topic($color, $icon-name) {\n --color-topic-title: #{$color};\n --color-topic-title-background: #{rgba($color, 0.2)};\n\n --icon-topic-default: var(--icon-#{$icon-name});\n}\n\n@mixin admonitions {\n @each $name, $values in $admonitions {\n --color-admonition-title--#{$name}: #{nth($values, 1)};\n --color-admonition-title-background--#{$name}: #{rgba(\n nth($values, 1),\n 0.2\n )};\n }\n}\n","// Colors used throughout this theme.\n//\n// The aim is to give the user more control. Thus, instead of hard-coding colors\n// in various parts of the stylesheet, the approach taken is to define all\n// colors as CSS variables and reusing them in all the places.\n//\n// `colors-dark` depends on `colors` being included at a lower specificity.\n\n@mixin colors {\n --color-problematic: #b30000;\n\n // Base Colors\n --color-foreground-primary: black; // for main text and headings\n --color-foreground-secondary: #5a5c63; // for secondary text\n --color-foreground-muted: #6b6f76; // for muted text\n --color-foreground-border: #878787; // for content borders\n\n --color-background-primary: white; // for content\n --color-background-secondary: #f8f9fb; // for navigation + ToC\n --color-background-hover: #efeff4ff; // for navigation-item hover\n --color-background-hover--transparent: #efeff400;\n --color-background-border: #eeebee; // for UI borders\n --color-background-item: #ccc; // for \"background\" items (eg: copybutton)\n\n // Announcements\n --color-announcement-background: #000000dd;\n --color-announcement-text: #eeebee;\n\n // Brand colors\n --color-brand-primary: #0a4bff;\n --color-brand-content: #2757dd;\n --color-brand-visited: #872ee0;\n\n // API documentation\n --color-api-background: var(--color-background-hover--transparent);\n --color-api-background-hover: var(--color-background-hover);\n --color-api-overall: var(--color-foreground-secondary);\n --color-api-name: var(--color-problematic);\n --color-api-pre-name: var(--color-problematic);\n --color-api-paren: var(--color-foreground-secondary);\n --color-api-keyword: var(--color-foreground-primary);\n\n --color-api-added: #21632c;\n --color-api-added-border: #38a84d;\n --color-api-changed: #046172;\n --color-api-changed-border: #06a1bc;\n --color-api-deprecated: #605706;\n --color-api-deprecated-border: #f0d90f;\n --color-api-removed: #b30000;\n --color-api-removed-border: #ff5c5c;\n\n --color-highlight-on-target: #ffffcc;\n\n // Inline code background\n --color-inline-code-background: var(--color-background-secondary);\n\n // Highlighted text (search)\n --color-highlighted-background: #ddeeff;\n --color-highlighted-text: var(--color-foreground-primary);\n\n // GUI Labels\n --color-guilabel-background: #ddeeff80;\n --color-guilabel-border: #bedaf580;\n --color-guilabel-text: var(--color-foreground-primary);\n\n // Admonitions!\n --color-admonition-background: transparent;\n\n //////////////////////////////////////////////////////////////////////////////\n // Everything below this should be one of:\n // - var(...)\n // - *-gradient(...)\n // - special literal values (eg: transparent, none)\n //////////////////////////////////////////////////////////////////////////////\n\n // Tables\n --color-table-header-background: var(--color-background-secondary);\n --color-table-border: var(--color-background-border);\n\n // Cards\n --color-card-border: var(--color-background-secondary);\n --color-card-background: transparent;\n --color-card-marginals-background: var(--color-background-secondary);\n\n // Header\n --color-header-background: var(--color-background-primary);\n --color-header-border: var(--color-background-border);\n --color-header-text: var(--color-foreground-primary);\n\n // Sidebar (left)\n --color-sidebar-background: var(--color-background-secondary);\n --color-sidebar-background-border: var(--color-background-border);\n\n --color-sidebar-brand-text: var(--color-foreground-primary);\n --color-sidebar-caption-text: var(--color-foreground-muted);\n --color-sidebar-link-text: var(--color-foreground-secondary);\n --color-sidebar-link-text--top-level: var(--color-brand-primary);\n\n --color-sidebar-item-background: var(--color-sidebar-background);\n --color-sidebar-item-background--current: var(\n --color-sidebar-item-background\n );\n --color-sidebar-item-background--hover: linear-gradient(\n 90deg,\n var(--color-background-hover--transparent) 0%,\n var(--color-background-hover) var(--sidebar-item-spacing-horizontal),\n var(--color-background-hover) 100%\n );\n\n --color-sidebar-item-expander-background: transparent;\n --color-sidebar-item-expander-background--hover: var(\n --color-background-hover\n );\n\n --color-sidebar-search-text: var(--color-foreground-primary);\n --color-sidebar-search-background: var(--color-background-secondary);\n --color-sidebar-search-background--focus: var(--color-background-primary);\n --color-sidebar-search-border: var(--color-background-border);\n --color-sidebar-search-icon: var(--color-foreground-muted);\n\n // Table of Contents (right)\n --color-toc-background: var(--color-background-primary);\n --color-toc-title-text: var(--color-foreground-muted);\n --color-toc-item-text: var(--color-foreground-secondary);\n --color-toc-item-text--hover: var(--color-foreground-primary);\n --color-toc-item-text--active: var(--color-brand-primary);\n\n // Actual page contents\n --color-content-foreground: var(--color-foreground-primary);\n --color-content-background: transparent;\n\n // Links\n --color-link: var(--color-brand-content);\n --color-link-underline: var(--color-background-border);\n --color-link--hover: var(--color-brand-content);\n --color-link-underline--hover: var(--color-foreground-border);\n\n --color-link--visited: var(--color-brand-visited);\n --color-link-underline--visited: var(--color-background-border);\n --color-link--visited--hover: var(--color-brand-visited);\n --color-link-underline--visited--hover: var(--color-foreground-border);\n}\n\n@mixin colors-dark {\n --color-problematic: #ee5151;\n\n // Base Colors\n --color-foreground-primary: #cfd0d0; // for main text and headings\n --color-foreground-secondary: #9ca0a5; // for secondary text\n --color-foreground-muted: #81868d; // for muted text\n --color-foreground-border: #666666; // for content borders\n\n --color-background-primary: #131416; // for content\n --color-background-secondary: #1a1c1e; // for navigation + ToC\n --color-background-hover: #1e2124ff; // for navigation-item hover\n --color-background-hover--transparent: #1e212400;\n --color-background-border: #303335; // for UI borders\n --color-background-item: #444; // for \"background\" items (eg: copybutton)\n\n // Announcements\n --color-announcement-background: #000000dd;\n --color-announcement-text: #eeebee;\n\n // Brand colors\n --color-brand-primary: #3d94ff;\n --color-brand-content: #5ca5ff;\n --color-brand-visited: #b27aeb;\n\n // Highlighted text (search)\n --color-highlighted-background: #083563;\n\n // GUI Labels\n --color-guilabel-background: #08356380;\n --color-guilabel-border: #13395f80;\n\n // API documentation\n --color-api-keyword: var(--color-foreground-secondary);\n --color-highlight-on-target: #333300;\n\n --color-api-added: #3db854;\n --color-api-added-border: #267334;\n --color-api-changed: #09b0ce;\n --color-api-changed-border: #056d80;\n --color-api-deprecated: #b1a10b;\n --color-api-deprecated-border: #6e6407;\n --color-api-removed: #ff7575;\n --color-api-removed-border: #b03b3b;\n\n // Admonitions\n --color-admonition-background: #18181a;\n\n // Cards\n --color-card-border: var(--color-background-secondary);\n --color-card-background: #18181a;\n --color-card-marginals-background: var(--color-background-hover);\n}\n","// This file contains the styling for making the content throughout the page,\n// including fonts, paragraphs, headings and spacing among these elements.\n\nbody\n font-family: var(--font-stack)\npre,\ncode,\nkbd,\nsamp\n font-family: var(--font-stack--monospace)\n\n// Make fonts look slightly nicer.\nbody\n -webkit-font-smoothing: antialiased\n -moz-osx-font-smoothing: grayscale\n\n// Line height from Bootstrap 4.1\narticle\n line-height: 1.5\n\n//\n// Headings\n//\nh1,\nh2,\nh3,\nh4,\nh5,\nh6\n line-height: 1.25\n font-family: var(--font-stack--headings)\n font-weight: bold\n\n border-radius: 0.5rem\n margin-top: 0.5rem\n margin-bottom: 0.5rem\n margin-left: -0.5rem\n margin-right: -0.5rem\n padding-left: 0.5rem\n padding-right: 0.5rem\n\n + p\n margin-top: 0\n\nh1\n font-size: 2.5em\n margin-top: 1.75rem\n margin-bottom: 1rem\nh2\n font-size: 2em\n margin-top: 1.75rem\nh3\n font-size: 1.5em\nh4\n font-size: 1.25em\nh5\n font-size: 1.125em\nh6\n font-size: 1em\n\nsmall\n opacity: 75%\n font-size: 80%\n\n// Paragraph\np\n margin-top: 0.5rem\n margin-bottom: 0.75rem\n\n// Horizontal rules\nhr.docutils\n height: 1px\n padding: 0\n margin: 2rem 0\n background-color: var(--color-background-border)\n border: 0\n\n.centered\n text-align: center\n\n// Links\na\n text-decoration: underline\n\n color: var(--color-link)\n text-decoration-color: var(--color-link-underline)\n\n &:visited\n color: var(--color-link--visited)\n text-decoration-color: var(--color-link-underline--visited)\n &:hover\n color: var(--color-link--visited--hover)\n text-decoration-color: var(--color-link-underline--visited--hover)\n\n &:hover\n color: var(--color-link--hover)\n text-decoration-color: var(--color-link-underline--hover)\n &.muted-link\n color: inherit\n &:hover\n color: var(--color-link--hover)\n text-decoration-color: var(--color-link-underline--hover)\n &:visited\n color: var(--color-link--visited--hover)\n text-decoration-color: var(--color-link-underline--visited--hover)\n","// This file contains the styles for the overall layouting of the documentation\n// skeleton, including the responsive changes as well as sidebar toggles.\n//\n// This is implemented as a mobile-last design, which isn't ideal, but it is\n// reasonably good-enough and I got pretty tired by the time I'd finished this\n// to move the rules around to fix this. Shouldn't take more than 3-4 hours,\n// if you know what you're doing tho.\n\n// HACK: Not all browsers account for the scrollbar width in media queries.\n// This results in horizontal scrollbars in the breakpoint where we go\n// from displaying everything to hiding the ToC. We accomodate for this by\n// adding a bit of padding to the TOC drawer, disabling the horizontal\n// scrollbar and allowing the scrollbars to cover the padding.\n// https://www.456bereastreet.com/archive/201301/media_query_width_and_vertical_scrollbars/\n\n// HACK: Always having the scrollbar visible, prevents certain browsers from\n// causing the content to stutter horizontally between taller-than-viewport and\n// not-taller-than-viewport pages.\n\nhtml\n overflow-x: hidden\n overflow-y: scroll\n scroll-behavior: smooth\n\n.sidebar-scroll, .toc-scroll, article[role=main] *\n // Override Firefox scrollbar style\n scrollbar-width: thin\n scrollbar-color: var(--color-foreground-border) transparent\n\n // Override Chrome scrollbar styles\n &::-webkit-scrollbar\n width: 0.25rem\n height: 0.25rem\n &::-webkit-scrollbar-thumb\n background-color: var(--color-foreground-border)\n border-radius: 0.125rem\n\n//\n// Overalls\n//\nhtml,\nbody\n height: 100%\n color: var(--color-foreground-primary)\n background: var(--color-background-primary)\n\n.skip-to-content\n position: fixed\n padding: 1rem\n border-radius: 1rem\n left: 0.25rem\n top: 0.25rem\n z-index: 40\n background: var(--color-background-primary)\n color: var(--color-foreground-primary)\n\n transform: translateY(-200%)\n transition: transform 300ms ease-in-out\n\n &:focus-within\n transform: translateY(0%)\n\narticle\n color: var(--color-content-foreground)\n background: var(--color-content-background)\n overflow-wrap: break-word\n\n.page\n display: flex\n // fill the viewport for pages with little content.\n min-height: 100%\n\n.mobile-header\n width: 100%\n height: var(--header-height)\n background-color: var(--color-header-background)\n color: var(--color-header-text)\n border-bottom: 1px solid var(--color-header-border)\n\n // Looks like sub-script/super-script have this, and we need this to\n // be \"on top\" of those.\n z-index: 10\n\n // We don't show the header on large screens.\n display: none\n\n // Add shadow when scrolled\n &.scrolled\n border-bottom: none\n box-shadow: 0 0 0.2rem rgba(0, 0, 0, 0.1), 0 0.2rem 0.4rem rgba(0, 0, 0, 0.2)\n\n .header-center\n a\n color: var(--color-header-text)\n text-decoration: none\n\n.main\n display: flex\n flex: 1\n\n// Sidebar (left) also covers the entire left portion of screen.\n.sidebar-drawer\n box-sizing: border-box\n\n border-right: 1px solid var(--color-sidebar-background-border)\n background: var(--color-sidebar-background)\n\n display: flex\n justify-content: flex-end\n // These next two lines took me two days to figure out.\n width: calc((100% - #{$full-width}) / 2 + #{$sidebar-width})\n min-width: $sidebar-width\n\n// Scroll-along sidebars\n.sidebar-container,\n.toc-drawer\n box-sizing: border-box\n width: $sidebar-width\n\n.toc-drawer\n background: var(--color-toc-background)\n // See HACK described on top of this document\n padding-right: 1rem\n\n.sidebar-sticky,\n.toc-sticky\n position: sticky\n top: 0\n height: min(100%, 100vh)\n height: 100vh\n\n display: flex\n flex-direction: column\n\n.sidebar-scroll,\n.toc-scroll\n flex-grow: 1\n flex-shrink: 1\n\n overflow: auto\n scroll-behavior: smooth\n\n// Central items.\n.content\n padding: 0 $content-padding\n width: $content-width\n\n display: flex\n flex-direction: column\n justify-content: space-between\n\n.icon\n display: inline-block\n height: 1rem\n width: 1rem\n svg\n width: 100%\n height: 100%\n\n//\n// Accommodate announcement banner\n//\n.announcement\n background-color: var(--color-announcement-background)\n color: var(--color-announcement-text)\n\n height: var(--header-height)\n display: flex\n align-items: center\n overflow-x: auto\n & + .page\n min-height: calc(100% - var(--header-height))\n\n.announcement-content\n box-sizing: border-box\n padding: 0.5rem\n min-width: 100%\n white-space: nowrap\n text-align: center\n\n a\n color: var(--color-announcement-text)\n text-decoration-color: var(--color-announcement-text)\n\n &:hover\n color: var(--color-announcement-text)\n text-decoration-color: var(--color-link--hover)\n\n////////////////////////////////////////////////////////////////////////////////\n// Toggles for theme\n////////////////////////////////////////////////////////////////////////////////\n.no-js .theme-toggle-container // don't show theme toggle if there's no JS\n display: none\n\n.theme-toggle-container\n display: flex\n\n.theme-toggle\n display: flex\n cursor: pointer\n border: none\n padding: 0\n background: transparent\n\n.theme-toggle svg\n height: 1.25rem\n width: 1.25rem\n color: var(--color-foreground-primary)\n display: none\n\n.theme-toggle-header\n display: flex\n align-items: center\n justify-content: center\n\n////////////////////////////////////////////////////////////////////////////////\n// Toggles for elements\n////////////////////////////////////////////////////////////////////////////////\n.toc-overlay-icon, .nav-overlay-icon\n display: none\n cursor: pointer\n\n .icon\n color: var(--color-foreground-secondary)\n height: 1.5rem\n width: 1.5rem\n\n.toc-header-icon, .nav-overlay-icon\n // for when we set display: flex\n justify-content: center\n align-items: center\n\n.toc-content-icon\n height: 1.5rem\n width: 1.5rem\n\n.content-icon-container\n float: right\n display: flex\n margin-top: 1.5rem\n margin-left: 1rem\n margin-bottom: 1rem\n gap: 0.5rem\n\n .edit-this-page, .view-this-page\n svg\n color: inherit\n height: 1.25rem\n width: 1.25rem\n\n.sidebar-toggle\n position: absolute\n display: none\n// \n.sidebar-toggle[name=\"__toc\"]\n left: 20px\n.sidebar-toggle:checked\n left: 40px\n// \n\n.overlay\n position: fixed\n top: 0\n width: 0\n height: 0\n\n transition: width 0ms, height 0ms, opacity 250ms ease-out\n\n opacity: 0\n background-color: rgba(0, 0, 0, 0.54)\n.sidebar-overlay\n z-index: 20\n.toc-overlay\n z-index: 40\n\n// Keep things on top and smooth.\n.sidebar-drawer\n z-index: 30\n transition: left 250ms ease-in-out\n.toc-drawer\n z-index: 50\n transition: right 250ms ease-in-out\n\n// Show the Sidebar\n#__navigation:checked\n & ~ .sidebar-overlay\n width: 100%\n height: 100%\n opacity: 1\n & ~ .page\n .sidebar-drawer\n top: 0\n left: 0\n // Show the toc sidebar\n#__toc:checked\n & ~ .toc-overlay\n width: 100%\n height: 100%\n opacity: 1\n & ~ .page\n .toc-drawer\n top: 0\n right: 0\n\n////////////////////////////////////////////////////////////////////////////////\n// Back to top\n////////////////////////////////////////////////////////////////////////////////\n.back-to-top\n text-decoration: none\n\n display: none\n position: fixed\n left: 0\n top: 1rem\n padding: 0.5rem\n padding-right: 0.75rem\n border-radius: 1rem\n font-size: 0.8125rem\n\n background: var(--color-background-primary)\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), #6b728080 0px 0px 1px 0px\n\n z-index: 10\n\n margin-left: 50%\n transform: translateX(-50%)\n svg\n height: 1rem\n width: 1rem\n fill: currentColor\n display: inline-block\n\n span\n margin-left: 0.25rem\n\n .show-back-to-top &\n display: flex\n align-items: center\n\n////////////////////////////////////////////////////////////////////////////////\n// Responsive layouting\n////////////////////////////////////////////////////////////////////////////////\n// Make things a bit bigger on bigger screens.\n@media (min-width: $full-width + $sidebar-width)\n html\n font-size: 110%\n\n@media (max-width: $full-width)\n // Collapse \"toc\" into the icon.\n .toc-content-icon\n display: flex\n .toc-drawer\n position: fixed\n height: 100vh\n top: 0\n right: -$sidebar-width\n border-left: 1px solid var(--color-background-muted)\n .toc-tree\n border-left: none\n font-size: var(--toc-font-size--mobile)\n\n // Accomodate for a changed content width.\n .sidebar-drawer\n width: calc((100% - #{$full-width - $sidebar-width}) / 2 + #{$sidebar-width})\n\n@media (max-width: $content-padded-width + $sidebar-width)\n // Center the page\n .content\n margin-left: auto\n margin-right: auto\n padding: 0 $content-padding--small\n\n@media (max-width: $content-padded-width--small + $sidebar-width)\n // Collapse \"navigation\".\n .nav-overlay-icon\n display: flex\n .sidebar-drawer\n position: fixed\n height: 100vh\n width: $sidebar-width\n\n top: 0\n left: -$sidebar-width\n\n // Swap which icon is visible.\n .toc-header-icon, .theme-toggle-header\n display: flex\n .toc-content-icon, .theme-toggle-content\n display: none\n\n // Show the header.\n .mobile-header\n position: sticky\n top: 0\n display: flex\n justify-content: space-between\n align-items: center\n\n .header-left,\n .header-right\n display: flex\n height: var(--header-height)\n padding: 0 var(--header-padding)\n label\n height: 100%\n width: 100%\n user-select: none\n\n .nav-overlay-icon .icon,\n .theme-toggle svg\n height: 1.5rem\n width: 1.5rem\n\n // Add a scroll margin for the content\n :target\n scroll-margin-top: calc(var(--header-height) + 2.5rem)\n\n // Show back-to-top below the header\n .back-to-top\n top: calc(var(--header-height) + 0.5rem)\n\n // Accommodate for the header.\n .page\n flex-direction: column\n justify-content: center\n\n@media (max-width: $content-width + 2* $content-padding--small)\n // Content should respect window limits.\n .content\n width: 100%\n overflow-x: auto\n\n@media (max-width: $content-width)\n article[role=main] aside.sidebar\n float: none\n width: 100%\n margin: 1rem 0\n","// Overall Layout Variables\n//\n// Because CSS variables can't be used in media queries. The fact that this\n// makes the layout non-user-configurable is a good thing.\n$content-padding: 3em;\n$content-padding--small: 1em;\n$content-width: 46em;\n$sidebar-width: 15em;\n$content-padded-width: $content-width + 2 * $content-padding;\n$content-padded-width--small: $content-width + 2 * $content-padding--small;\n$full-width: $content-padded-width + 2 * $sidebar-width;\n","//\n// The design here is strongly inspired by mkdocs-material.\n.admonition, .topic\n margin: 1rem auto\n padding: 0 0.5rem 0.5rem 0.5rem\n\n background: var(--color-admonition-background)\n\n border-radius: 0.2rem\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0 0.0625rem rgba(0, 0, 0, 0.1)\n\n font-size: var(--admonition-font-size)\n\n overflow: hidden\n page-break-inside: avoid\n\n // First element should have no margin, since the title has it.\n > :nth-child(2)\n margin-top: 0\n\n // Last item should have no margin, since we'll control that w/ padding\n > :last-child\n margin-bottom: 0\n\n.admonition p.admonition-title,\np.topic-title\n position: relative\n margin: 0 -0.5rem 0.5rem\n padding-left: 2rem\n padding-right: .5rem\n padding-top: .4rem\n padding-bottom: .4rem\n\n font-weight: 500\n font-size: var(--admonition-title-font-size)\n line-height: 1.3\n\n // Our fancy icon\n &::before\n content: \"\"\n position: absolute\n left: 0.5rem\n width: 1rem\n height: 1rem\n\n// Default styles\np.admonition-title\n background-color: var(--color-admonition-title-background)\n &::before\n background-color: var(--color-admonition-title)\n mask-image: var(--icon-admonition-default)\n mask-repeat: no-repeat\n\np.topic-title\n background-color: var(--color-topic-title-background)\n &::before\n background-color: var(--color-topic-title)\n mask-image: var(--icon-topic-default)\n mask-repeat: no-repeat\n\n//\n// Variants\n//\n.admonition\n border-left: 0.2rem solid var(--color-admonition-title)\n\n @each $type, $value in $admonitions\n &.#{$type}\n border-left-color: var(--color-admonition-title--#{$type})\n > .admonition-title\n background-color: var(--color-admonition-title-background--#{$type})\n &::before\n background-color: var(--color-admonition-title--#{$type})\n mask-image: var(--icon-#{nth($value, 2)})\n\n.admonition-todo > .admonition-title\n text-transform: uppercase\n","// This file stylizes the API documentation (stuff generated by autodoc). It's\n// deeply nested due to how autodoc structures the HTML without enough classes\n// to select the relevant items.\n\n// API docs!\ndl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)\n // Tweak the spacing of all the things!\n dd\n margin-left: 2rem\n > :first-child\n margin-top: 0.125rem\n > :last-child\n margin-bottom: 0.75rem\n\n // This is used for the arguments\n .field-list\n margin-bottom: 0.75rem\n\n // \"Headings\" (like \"Parameters\" and \"Return\")\n > dt\n text-transform: uppercase\n font-size: var(--font-size--small)\n\n dd:empty\n margin-bottom: 0.5rem\n dd > ul\n margin-left: -1.2rem\n > li\n > p:nth-child(2)\n margin-top: 0\n // When the last-empty-paragraph follows a paragraph, it doesn't need\n // to augument the existing spacing.\n > p + p:last-child:empty\n margin-top: 0\n margin-bottom: 0\n\n // Colorize the elements\n > dt\n color: var(--color-api-overall)\n\n.sig:not(.sig-inline)\n font-weight: bold\n\n font-size: var(--api-font-size)\n font-family: var(--font-stack--monospace)\n\n margin-left: -0.25rem\n margin-right: -0.25rem\n padding-top: 0.25rem\n padding-bottom: 0.25rem\n padding-right: 0.5rem\n\n // These are intentionally em, to properly match the font size.\n padding-left: 3em\n text-indent: -2.5em\n\n border-radius: 0.25rem\n\n background: var(--color-api-background)\n transition: background 100ms ease-out\n\n &:hover\n background: var(--color-api-background-hover)\n\n // adjust the size of the [source] link on the right.\n a.reference\n .viewcode-link\n font-weight: normal\n width: 4.25rem\n\nem.property\n font-style: normal\n &:first-child\n color: var(--color-api-keyword)\n.sig-name\n color: var(--color-api-name)\n.sig-prename\n font-weight: normal\n color: var(--color-api-pre-name)\n.sig-paren\n color: var(--color-api-paren)\n.sig-param\n font-style: normal\n\ndiv.versionadded,\ndiv.versionchanged,\ndiv.deprecated,\ndiv.versionremoved\n border-left: 0.1875rem solid\n border-radius: 0.125rem\n\n padding-left: 0.75rem\n\n p\n margin-top: 0.125rem\n margin-bottom: 0.125rem\n\ndiv.versionadded\n border-color: var(--color-api-added-border)\n .versionmodified\n color: var(--color-api-added)\n\ndiv.versionchanged\n border-color: var(--color-api-changed-border)\n .versionmodified\n color: var(--color-api-changed)\n\ndiv.deprecated\n border-color: var(--color-api-deprecated-border)\n .versionmodified\n color: var(--color-api-deprecated)\n\ndiv.versionremoved\n border-color: var(--color-api-removed-border)\n .versionmodified\n color: var(--color-api-removed)\n\n// Align the [docs] and [source] to the right.\n.viewcode-link, .viewcode-back\n float: right\n text-align: right\n",".line-block\n margin-top: 0.5rem\n margin-bottom: 0.75rem\n .line-block\n margin-top: 0rem\n margin-bottom: 0rem\n padding-left: 1rem\n","// Captions\narticle p.caption,\ntable > caption,\n.code-block-caption\n font-size: var(--font-size--small)\n text-align: center\n\n// Caption above a TOCTree\n.toctree-wrapper.compound\n .caption, :not(.caption) > .caption-text\n font-size: var(--font-size--small)\n text-transform: uppercase\n\n text-align: initial\n margin-bottom: 0\n\n > ul\n margin-top: 0\n margin-bottom: 0\n","// Inline code\ncode.literal, .sig-inline\n background: var(--color-inline-code-background)\n border-radius: 0.2em\n // Make the font smaller, and use padding to recover.\n font-size: var(--font-size--small--2)\n padding: 0.1em 0.2em\n\n pre.literal-block &\n font-size: inherit\n padding: 0\n\n p &\n border: 1px solid var(--color-background-border)\n\n.sig-inline\n font-family: var(--font-stack--monospace)\n\n// Code and Literal Blocks\n$code-spacing-vertical: 0.625rem\n$code-spacing-horizontal: 0.875rem\n\n// Wraps every literal block + line numbers.\ndiv[class*=\" highlight-\"],\ndiv[class^=\"highlight-\"]\n margin: 1em 0\n display: flex\n\n .table-wrapper\n margin: 0\n padding: 0\n\npre\n margin: 0\n padding: 0\n overflow: auto\n\n // Needed to have more specificity than pygments' \"pre\" selector. :(\n article[role=\"main\"] .highlight &\n line-height: 1.5\n\n &.literal-block,\n .highlight &\n font-size: var(--code-font-size)\n padding: $code-spacing-vertical $code-spacing-horizontal\n\n // Make it look like all the other blocks.\n &.literal-block\n margin-top: 1rem\n margin-bottom: 1rem\n\n border-radius: 0.2rem\n background-color: var(--color-code-background)\n color: var(--color-code-foreground)\n\n// All code is always contained in this.\n.highlight\n width: 100%\n border-radius: 0.2rem\n\n // Make line numbers and prompts un-selectable.\n .gp, span.linenos\n user-select: none\n pointer-events: none\n\n // Expand the line-highlighting.\n .hll\n display: block\n margin-left: -$code-spacing-horizontal\n margin-right: -$code-spacing-horizontal\n padding-left: $code-spacing-horizontal\n padding-right: $code-spacing-horizontal\n\n/* Make code block captions be nicely integrated */\n.code-block-caption\n display: flex\n padding: $code-spacing-vertical $code-spacing-horizontal\n\n border-radius: 0.25rem\n border-bottom-left-radius: 0\n border-bottom-right-radius: 0\n font-weight: 300\n border-bottom: 1px solid\n\n background-color: var(--color-code-background)\n color: var(--color-code-foreground)\n border-color: var(--color-background-border)\n\n + div[class]\n margin-top: 0\n pre\n border-top-left-radius: 0\n border-top-right-radius: 0\n\n// When `html_codeblock_linenos_style` is table.\n.highlighttable\n width: 100%\n display: block\n tbody\n display: block\n\n tr\n display: flex\n\n // Line numbers\n td.linenos\n background-color: var(--color-code-background)\n color: var(--color-code-foreground)\n padding: $code-spacing-vertical $code-spacing-horizontal\n padding-right: 0\n border-top-left-radius: 0.2rem\n border-bottom-left-radius: 0.2rem\n\n .linenodiv\n padding-right: $code-spacing-horizontal\n font-size: var(--code-font-size)\n box-shadow: -0.0625rem 0 var(--color-foreground-border) inset\n\n // Actual code\n td.code\n padding: 0\n display: block\n flex: 1\n overflow: hidden\n\n .highlight\n border-top-left-radius: 0\n border-bottom-left-radius: 0\n\n// When `html_codeblock_linenos_style` is inline.\n.highlight\n span.linenos\n display: inline-block\n padding-left: 0\n padding-right: $code-spacing-horizontal\n margin-right: $code-spacing-horizontal\n box-shadow: -0.0625rem 0 var(--color-foreground-border) inset\n","// Inline Footnote Reference\n.footnote-reference\n font-size: var(--font-size--small--4)\n vertical-align: super\n\n// Definition list, listing the content of each note.\n// docutils <= 0.17\ndl.footnote.brackets\n font-size: var(--font-size--small)\n color: var(--color-foreground-secondary)\n\n display: grid\n grid-template-columns: max-content auto\n dt\n margin: 0\n > .fn-backref\n margin-left: 0.25rem\n\n &:after\n content: \":\"\n\n .brackets\n &:before\n content: \"[\"\n &:after\n content: \"]\"\n\n dd\n margin: 0\n padding: 0 1rem\n\n// docutils >= 0.18\naside.footnote\n font-size: var(--font-size--small)\n color: var(--color-foreground-secondary)\n\naside.footnote > span,\ndiv.citation > span\n float: left\n font-weight: 500\n padding-right: 0.25rem\n\naside.footnote > *:not(span),\ndiv.citation > p\n margin-left: 2rem\n","//\n// Figures\n//\nimg\n box-sizing: border-box\n max-width: 100%\n height: auto\n\narticle\n figure, .figure\n border-radius: 0.2rem\n\n margin: 0\n :last-child\n margin-bottom: 0\n\n .align-left\n float: left\n clear: left\n margin: 0 1rem 1rem\n\n .align-right\n float: right\n clear: right\n margin: 0 1rem 1rem\n\n .align-default,\n .align-center\n display: block\n text-align: center\n margin-left: auto\n margin-right: auto\n\n // WELL, table needs to be stylised like a table.\n table.align-default\n display: table\n text-align: initial\n",".genindex-jumpbox, .domainindex-jumpbox\n border-top: 1px solid var(--color-background-border)\n border-bottom: 1px solid var(--color-background-border)\n padding: 0.25rem\n\n.genindex-section, .domainindex-section\n h2\n margin-top: 0.75rem\n margin-bottom: 0.5rem\n ul\n margin-top: 0\n margin-bottom: 0\n","ul,\nol\n padding-left: 1.2rem\n\n // Space lists out like paragraphs\n margin-top: 1rem\n margin-bottom: 1rem\n // reduce margins within li.\n li\n > p:first-child\n margin-top: 0.25rem\n margin-bottom: 0.25rem\n\n > p:last-child\n margin-top: 0.25rem\n\n > ul,\n > ol\n margin-top: 0.5rem\n margin-bottom: 0.5rem\n\nol\n &.arabic\n list-style: decimal\n &.loweralpha\n list-style: lower-alpha\n &.upperalpha\n list-style: upper-alpha\n &.lowerroman\n list-style: lower-roman\n &.upperroman\n list-style: upper-roman\n\n// Don't space lists out when they're \"simple\" or in a `.. toctree::`\n.simple,\n.toctree-wrapper\n li\n > ul,\n > ol\n margin-top: 0\n margin-bottom: 0\n\n// Definition Lists\n.field-list,\n.option-list,\ndl:not([class]),\ndl.simple,\ndl.footnote,\ndl.glossary\n dt\n font-weight: 500\n margin-top: 0.25rem\n + dt\n margin-top: 0\n\n .classifier::before\n content: \":\"\n margin-left: 0.2rem\n margin-right: 0.2rem\n\n dd\n > p:first-child,\n ul\n margin-top: 0.125rem\n\n ul\n margin-bottom: 0.125rem\n",".math-wrapper\n width: 100%\n overflow-x: auto\n\ndiv.math\n position: relative\n text-align: center\n\n .headerlink,\n &:focus .headerlink\n display: none\n\n &:hover .headerlink\n display: inline-block\n\n span.eqno\n position: absolute\n right: 0.5rem\n top: 50%\n transform: translate(0, -50%)\n z-index: 1\n","// Abbreviations\nabbr[title]\n cursor: help\n\n// \"Problematic\" content, as identified by Sphinx\n.problematic\n color: var(--color-problematic)\n\n// Keyboard / Mouse \"instructions\"\nkbd:not(.compound)\n margin: 0 0.2rem\n padding: 0 0.2rem\n border-radius: 0.2rem\n border: 1px solid var(--color-foreground-border)\n color: var(--color-foreground-primary)\n vertical-align: text-bottom\n\n font-size: var(--font-size--small--3)\n display: inline-block\n\n box-shadow: 0 0.0625rem 0 rgba(0, 0, 0, 0.2), inset 0 0 0 0.125rem var(--color-background-primary)\n\n background-color: var(--color-background-secondary)\n\n// Blockquote\nblockquote\n border-left: 4px solid var(--color-background-border)\n background: var(--color-background-secondary)\n\n margin-left: 0\n margin-right: 0\n padding: 0.5rem 1rem\n\n .attribution\n font-weight: 600\n text-align: right\n\n &.pull-quote,\n &.highlights\n font-size: 1.25em\n\n &.epigraph,\n &.pull-quote\n border-left-width: 0\n border-radius: 0.5rem\n\n &.highlights\n border-left-width: 0\n background: transparent\n\n// Center align embedded-in-text images\np .reference img\n vertical-align: middle\n","p.rubric\n line-height: 1.25\n font-weight: bold\n font-size: 1.125em\n\n // For Numpy-style documentation that's got rubrics within it.\n // https://github.com/pradyunsg/furo/discussions/505\n dd &\n line-height: inherit\n font-weight: inherit\n\n font-size: var(--font-size--small)\n text-transform: uppercase\n","article .sidebar\n float: right\n clear: right\n width: 30%\n\n margin-left: 1rem\n margin-right: 0\n\n border-radius: 0.2rem\n background-color: var(--color-background-secondary)\n border: var(--color-background-border) 1px solid\n\n > *\n padding-left: 1rem\n padding-right: 1rem\n\n > ul, > ol // lists need additional padding, because bullets.\n padding-left: 2.2rem\n\n .sidebar-title\n margin: 0\n padding: 0.5rem 1rem\n border-bottom: var(--color-background-border) 1px solid\n\n font-weight: 500\n\n// TODO: subtitle\n// TODO: dedicated variables?\n","[role=main] .table-wrapper.container\n width: 100%\n overflow-x: auto\n margin-top: 1rem\n margin-bottom: 0.5rem\n padding: 0.2rem 0.2rem 0.75rem\n\ntable.docutils\n border-radius: 0.2rem\n border-spacing: 0\n border-collapse: collapse\n\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0 0.0625rem rgba(0, 0, 0, 0.1)\n\n th\n background: var(--color-table-header-background)\n\n td,\n th\n // Space things out properly\n padding: 0 0.25rem\n\n // Get the borders looking just-right.\n border-left: 1px solid var(--color-table-border)\n border-right: 1px solid var(--color-table-border)\n border-bottom: 1px solid var(--color-table-border)\n\n p\n margin: 0.25rem\n\n &:first-child\n border-left: none\n &:last-child\n border-right: none\n\n // MyST-parser tables set these classes for control of column alignment\n &.text-left\n text-align: left\n &.text-right\n text-align: right\n &.text-center\n text-align: center\n",":target\n scroll-margin-top: 2.5rem\n\n@media (max-width: $full-width - $sidebar-width)\n :target\n scroll-margin-top: calc(2.5rem + var(--header-height))\n\n // When a heading is selected\n section > span:target\n scroll-margin-top: calc(2.8rem + var(--header-height))\n\n// Permalinks\n.headerlink\n font-weight: 100\n user-select: none\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\ndl dt,\np.caption,\nfigcaption p,\ntable > caption,\n.code-block-caption\n > .headerlink\n margin-left: 0.5rem\n visibility: hidden\n &:hover > .headerlink\n visibility: visible\n\n // Don't change to link-like, if someone adds the contents directive.\n > .toc-backref\n color: inherit\n text-decoration-line: none\n\n// Figure and table captions are special.\nfigure:hover > figcaption > p > .headerlink,\ntable:hover > caption > .headerlink\n visibility: visible\n\n:target >, // Regular section[id] style anchors\nspan:target ~ // Non-regular span[id] style \"extra\" anchors\n h1,\n h2,\n h3,\n h4,\n h5,\n h6\n &:nth-of-type(1)\n background-color: var(--color-highlight-on-target)\n // .headerlink\n // visibility: visible\n code.literal\n background-color: transparent\n\ntable:target > caption,\nfigure:target\n background-color: var(--color-highlight-on-target)\n\n// Inline page contents\n.this-will-duplicate-information-and-it-is-still-useful-here li :target\n background-color: var(--color-highlight-on-target)\n\n// Code block permalinks\n.literal-block-wrapper:target .code-block-caption\n background-color: var(--color-highlight-on-target)\n\n// When a definition list item is selected\n//\n// There isn't really an alternative to !important here, due to the\n// high-specificity of API documentation's selector.\ndt:target\n background-color: var(--color-highlight-on-target) !important\n\n// When a footnote reference is selected\n.footnote > dt:target + dd,\n.footnote-reference:target\n background-color: var(--color-highlight-on-target)\n",".guilabel\n background-color: var(--color-guilabel-background)\n border: 1px solid var(--color-guilabel-border)\n color: var(--color-guilabel-text)\n\n padding: 0 0.3em\n border-radius: 0.5em\n font-size: 0.9em\n","// This file contains the styles used for stylizing the footer that's shown\n// below the content.\n\nfooter\n font-size: var(--font-size--small)\n display: flex\n flex-direction: column\n\n margin-top: 2rem\n\n// Bottom of page information\n.bottom-of-page\n display: flex\n align-items: center\n justify-content: space-between\n\n margin-top: 1rem\n padding-top: 1rem\n padding-bottom: 1rem\n\n color: var(--color-foreground-secondary)\n border-top: 1px solid var(--color-background-border)\n\n line-height: 1.5\n\n @media (max-width: $content-width)\n text-align: center\n flex-direction: column-reverse\n gap: 0.25rem\n\n .left-details\n font-size: var(--font-size--small)\n\n .right-details\n display: flex\n flex-direction: column\n gap: 0.25rem\n text-align: right\n\n .icons\n display: flex\n justify-content: flex-end\n gap: 0.25rem\n font-size: 1rem\n\n a\n text-decoration: none\n\n svg,\n img\n font-size: 1.125rem\n height: 1em\n width: 1em\n\n// Next/Prev page information\n.related-pages\n a\n display: flex\n align-items: center\n\n text-decoration: none\n &:hover .page-info .title\n text-decoration: underline\n color: var(--color-link)\n text-decoration-color: var(--color-link-underline)\n\n svg.furo-related-icon,\n svg.furo-related-icon > use\n flex-shrink: 0\n\n color: var(--color-foreground-border)\n\n width: 0.75rem\n height: 0.75rem\n margin: 0 0.5rem\n\n &.next-page\n max-width: 50%\n\n float: right\n clear: right\n text-align: right\n\n &.prev-page\n max-width: 50%\n\n float: left\n clear: left\n\n svg\n transform: rotate(180deg)\n\n.page-info\n display: flex\n flex-direction: column\n overflow-wrap: anywhere\n\n .next-page &\n align-items: flex-end\n\n .context\n display: flex\n align-items: center\n\n padding-bottom: 0.1rem\n\n color: var(--color-foreground-muted)\n font-size: var(--font-size--small)\n text-decoration: none\n","// This file contains the styles for the contents of the left sidebar, which\n// contains the navigation tree, logo, search etc.\n\n////////////////////////////////////////////////////////////////////////////////\n// Brand on top of the scrollable tree.\n////////////////////////////////////////////////////////////////////////////////\n.sidebar-brand\n display: flex\n flex-direction: column\n flex-shrink: 0\n\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n text-decoration: none\n\n.sidebar-brand-text\n color: var(--color-sidebar-brand-text)\n overflow-wrap: break-word\n margin: var(--sidebar-item-spacing-vertical) 0\n font-size: 1.5rem\n\n.sidebar-logo-container\n margin: var(--sidebar-item-spacing-vertical) 0\n\n.sidebar-logo\n margin: 0 auto\n display: block\n max-width: 100%\n\n////////////////////////////////////////////////////////////////////////////////\n// Search\n////////////////////////////////////////////////////////////////////////////////\n.sidebar-search-container\n display: flex\n align-items: center\n margin-top: var(--sidebar-search-space-above)\n\n position: relative\n\n background: var(--color-sidebar-search-background)\n &:hover,\n &:focus-within\n background: var(--color-sidebar-search-background--focus)\n\n &::before\n content: \"\"\n position: absolute\n left: var(--sidebar-item-spacing-horizontal)\n width: var(--sidebar-search-icon-size)\n height: var(--sidebar-search-icon-size)\n\n background-color: var(--color-sidebar-search-icon)\n mask-image: var(--icon-search)\n\n.sidebar-search\n box-sizing: border-box\n\n border: none\n border-top: 1px solid var(--color-sidebar-search-border)\n border-bottom: 1px solid var(--color-sidebar-search-border)\n\n padding-top: var(--sidebar-search-input-spacing-vertical)\n padding-bottom: var(--sidebar-search-input-spacing-vertical)\n padding-right: var(--sidebar-search-input-spacing-horizontal)\n padding-left: calc(var(--sidebar-item-spacing-horizontal) + var(--sidebar-search-input-spacing-horizontal) + var(--sidebar-search-icon-size))\n\n width: 100%\n\n color: var(--color-sidebar-search-foreground)\n background: transparent\n z-index: 10\n\n &:focus\n outline: none\n\n &::placeholder\n font-size: var(--sidebar-search-input-font-size)\n\n//\n// Hide Search Matches link\n//\n#searchbox .highlight-link\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal) 0\n margin: 0\n text-align: center\n\n a\n color: var(--color-sidebar-search-icon)\n font-size: var(--font-size--small--2)\n\n////////////////////////////////////////////////////////////////////////////////\n// Structure/Skeleton of the navigation tree (left)\n////////////////////////////////////////////////////////////////////////////////\n.sidebar-tree\n font-size: var(--sidebar-item-font-size)\n margin-top: var(--sidebar-tree-space-above)\n margin-bottom: var(--sidebar-item-spacing-vertical)\n\n ul\n padding: 0\n margin-top: 0\n margin-bottom: 0\n\n display: flex\n flex-direction: column\n\n list-style: none\n\n li\n position: relative\n margin: 0\n\n > ul\n margin-left: var(--sidebar-item-spacing-horizontal)\n\n .icon\n color: var(--color-sidebar-link-text)\n\n .reference\n box-sizing: border-box\n color: var(--color-sidebar-link-text)\n\n // Fill the parent.\n display: inline-block\n line-height: var(--sidebar-item-line-height)\n text-decoration: none\n\n // Don't allow long words to cause wrapping.\n overflow-wrap: anywhere\n\n height: 100%\n width: 100%\n\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n\n &:hover\n color: var(--color-sidebar-link-text)\n background: var(--color-sidebar-item-background--hover)\n\n // Add a nice little \"external-link\" arrow here.\n &.external::after\n content: url('data:image/svg+xml,')\n margin: 0 0.25rem\n vertical-align: middle\n color: var(--color-sidebar-link-text)\n\n // Make the current page reference bold.\n .current-page > .reference\n font-weight: bold\n\n label\n position: absolute\n top: 0\n right: 0\n height: var(--sidebar-item-height)\n width: var(--sidebar-expander-width)\n\n cursor: pointer\n user-select: none\n\n display: flex\n justify-content: center\n align-items: center\n\n .caption, :not(.caption) > .caption-text\n font-size: var(--sidebar-caption-font-size)\n color: var(--color-sidebar-caption-text)\n\n font-weight: bold\n text-transform: uppercase\n\n margin: var(--sidebar-caption-space-above) 0 0 0\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n\n // If it has children, add a bit more padding to wrap the content to avoid\n // overlapping with the