diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 00000000..c0052ad6 --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: ec3314133302e9b89521ac1202d98768 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/_images/external_port.png b/_images/external_port.png new file mode 100644 index 00000000..3dff654f Binary files /dev/null and b/_images/external_port.png differ diff --git a/_images/invalid_connection.png b/_images/invalid_connection.png new file mode 100644 index 00000000..c157c312 Binary files /dev/null and b/_images/invalid_connection.png differ diff --git a/_images/ipconnect.png b/_images/ipconnect.png new file mode 100644 index 00000000..8fc97e15 Binary files /dev/null and b/_images/ipconnect.png differ diff --git a/_images/node_parameters.png b/_images/node_parameters.png new file mode 100644 index 00000000..f951c484 Binary files /dev/null and b/_images/node_parameters.png differ diff --git a/_images/pwm.png b/_images/pwm.png new file mode 100644 index 00000000..5b7f8d27 Binary files /dev/null and b/_images/pwm.png differ diff --git a/_images/pwm_design.png b/_images/pwm_design.png new file mode 100644 index 00000000..1a93c795 Binary files /dev/null and b/_images/pwm_design.png differ diff --git a/_images/wrapper.png b/_images/wrapper.png new file mode 100644 index 00000000..f9c5c11d Binary files /dev/null and b/_images/wrapper.png differ diff --git a/_sources/cli.md.txt b/_sources/cli.md.txt new file mode 100644 index 00000000..148a6ceb --- /dev/null +++ b/_sources/cli.md.txt @@ -0,0 +1,76 @@ +# Command-line Interface + +## Building design + +To run Topwrap, use: + +``` +python -m topwrap build --design project.yml +``` + +Where `project.yml` should be your file with description of the top module. + +You can specify a directory to be scanned for additional sources: + +``` +python -m topwrap build --sources src --design project.yml +``` + +To implement the design for a specific FPGA chip, provide the part name: + +``` +python -m topwrap build --sources src --design project.yml --part 'xc7z020clg400-3' +``` + +(connect-topwrap-to-pm)= + +## Connect Topwrap to Pipeline Manager + +If you want to use Pipeline Manager as a UI for creating block design, you need to: + +1. Build and run Pipeline Manager server application. + +``` +python -m topwrap kpm_build_server +python -m topwrap kpm_run_server +``` + +2. Run Topwrap's client application, that will connect to a running Pipeline Manager server app. + +``` +python -m topwrap kpm_client [-h ip_addr] [-p port] [-d FILE] FILES +``` + +Topwrap will then try to connect to the server running on `ip_addr:port` and send a specification generated from `FILES`, which should be IP core description yamls. + +If `-h` or `-p` options are not specified, ip address `127.0.0.1` and port `9000` will be chosen by default. + +If `-d` option is specified, kpm will start with specified design file loaded. + +(generating-ip-yamls)= + +## Generating IP core description YAMLs + +You can also use Topwrap to generate ip core description yamls from HDL sources, +that can be later used in your `project.yml`: + +``` +python -m topwrap parse HDL_FILES +``` + +In HDL source files, ports that belong to the same interface (e.g. wishbone or AXI), +have often a common prefix, which corresponds to the interface name. If such naming +convention is followed in the HDL sources, Topwrap can also divide ports into user-specified +interfaces, or automatically deduce interfaces names when generating yaml file: + +``` +python -m topwrap parse --iface wishbone --iface s_axi HDL_FILES + +python -m topwrap parse --iface-deduce HDL_FILES +``` + +To get help, use: + +``` +python -m topwrap [build|kpm_client|parse] --help +``` diff --git a/_sources/description_files.md.txt b/_sources/description_files.md.txt new file mode 100644 index 00000000..a97566f1 --- /dev/null +++ b/_sources/description_files.md.txt @@ -0,0 +1,256 @@ +(description-files)= + +# Description files + +(design-description)= + +## Design Description + +To create a complete, fully synthesizable design, a proper design file is needed. +It's used to specify interconnects, IP cores, set their parameters' values, describe hierarchies for the project, +connect the IPs and hierarchies, and pick external ports (those which will be connected to physical I/O). + +You can see example design files in `examples` directory. The structure is as below: + +```yaml +ips: + # specify relations between IPs names in the design yaml + # and IP cores description yamls and modules + {ip_instance_name}: + file: {path_to_yaml_file_of_the_ip} + module: {name_of_the_HDL_module} + ... + +design: + name: {design_name} # optional name of the toplevel + hierarchies: + # see "Hierarchies" page for a detailed description of the format + ... + parameters: # specify IPs parameter values to be overridden + {ip_instance_name}: + {param_name} : {param_value} + ... + + ports: + # specify incoming ports connections of an IP named `ip1_name` + {ip1_name}: + {port1_name} : [{ip2_name}, {port2_name}] + ... + # specify incoming ports connections of a hierarchy named `hier_name` + {hier_name}: + {port1_name} : [{ip_name}, {port2_name}] + ... + # specify external ports connections + {ip_instance_name}: + {port_name} : ext_port_name + ... + + interfaces: + # specify incoming interfaces connections of `ip1_name` IP + {ip1_name}: + {iface1_name} : [{ip2_name}, {iface2_name}] + ... + # specify incoming interfaces connections of `hier_name` hierarchy + {hier_name}: + {iface1_name} : [{ip_name}, {iface2_name}] + ... + # specify external interfaces connections + {ip_instance_name}: + {iface_name} : ext_iface_name + ... + + interconnects: + # see "Interconnect generation" page for a detailed description of the format + ... + +external: # specify names of external ports and interfaces of the top module + ports: + out: + - {ext_port_name} + inout: + - [{ip_name/hierarchy_name, port_name}] + interfaces: + in: + - {ext_iface_name} + # note that `inout:` is invalid in the interfaces section +``` + +`inout` ports are handled differently than `in` and `out` ports. When any IP has an inout port or when a hierarchy has an inout port specified in its `external.ports.inout` section, it must be included in `external.ports.inout` section of the parent design by specifying the name of the IP/hierarchy and port name that contains it. Name of the external port will be identical to the one in the IP core. In case of duplicate names a suffix `$n` is added (where `n` is a natural number) to the name of the second and subsequent duplicate names. `inout` ports cannot be connected to each other. + +The design description yaml format allows creating hierarchical designs. In order to create a hierarchy, it suffices to add its name as a key in the `design` section and describe the hierarchy design "recursively" by using the same keys and values (`ports`, `parameters` etc.) as in the top-level design (see above). Hierarchies can be nested recursively, which means that you can create a hierarchy inside another one. + +Note that IPs and hierarchies names cannot be duplicated on the same hierarchy level. For example, the `design` section cannot contain two identical keys, but it's correct to have `ip_name` key in this section and `ip_name` in the `design` section of some hierarchy. + +(ip-description)= + +## IP description files + +Every IP wrapped by Topwrap needs a description file in YAML format. + +The ports of an IP should be placed in global `signals` node, followed by the direction of `in`, `out` or `inout`. +Here's an example description of ports of Clock Crossing IP: + +```yaml +# file: clock_crossing.yaml +signals: + in: + - clkA + - A + - clkB + out: + - B +``` + +The previous example is enough to make use of any IP. However, in order to benefit from connecting whole interfaces at once, ports must belong to a named interface like in this example: + +```yaml +#file: axis_width_converter.yaml +interfaces: + s_axis: + type: AXIStream + mode: slave + signals: + in: + TDATA: [s_axis_tdata, 63, 0] + TKEEP: [s_axis_tkeep, 7, 0] + TVALID: s_axis_tvalid + TLAST: s_axis_tlast + TID: [s_axis_tid, 7, 0] + TDEST: [s_axis_tdest, 7, 0] + TUSER: s_axis_tuser + out: + TREADY: s_axis_tready + + m_axis: + type: AXIStream + mode: master + signals: + in: + TREADY: m_axis_tready + out: + TDATA: [m_axis_tdata, 31, 0] + TKEEP: [m_axis_tkeep, 3, 0] + TVALID: m_axis_tvalid + TLAST: m_axis_tlast + TID: [m_axis_tid, 7, 0] + TDEST: [m_axis_tdest, 7, 0] + TUSER: m_axis_tuser +signals: # These ports don't belong to any interface + in: + - clk + - rst +``` + +Names `s_axis` and `m_axis` will be used to group the selected ports. +Each signal in an interface has a name which must match with the signal it's supposed to be connected to, for example `TDATA: port_name` will be connected to `TDATA: other_port_name`. + +Note that you don't have to write IP core description yamls by hand. You can use Topwrap's `parse` command (see {ref}`Generating IP core description YAMLs `) in order to generate yamls from HDL source files and then adjust the yaml to your needs. + +### Port widths + +The width of every port defaults to `1`. +You can specify the width using this notation: + +```yaml +interfaces: + s_axis: + type: AXIStream + mode: slave + signals: + in: + TDATA: [s_axis_tdata, 63, 0] # 64 bits + ... + TVALID: s_axis_tvalid # defaults to 1 bit + +signals: + in: + - [gpio_io_i, 31, 0] # 32 bits +``` + +### Parameterization + +Port widths don't have to be hardcoded - you can use parameters to describe an IP core in a generic way. +Values specified in IP core yamls can be overridden in a design description file (see {ref}`Design Description `). + +```yaml +parameters: + DATA_WIDTH: 8 + KEEP_WIDTH: (DATA_WIDTH+7)/8 + ID_WIDTH: 8 + DEST_WIDTH: 8 + USER_WIDTH: 1 + +interfaces: + s_axis: + type: AXI4Stream + mode: slave + signals: + in: + TDATA: [s_axis_tdata, DATA_WIDTH-1, 0] + TKEEP: [s_axis_tkeep, KEEP_WIDTH-1, 0] + ... + TID: [s_axis_tid, ID_WIDTH-1, 0] + TDEST: [s_axis_tdest, DEST_WIDTH-1, 0] + TUSER: [s_axis_tuser, USER_WIDTH-1, 0] +``` + +Parameters values can be integers or math expressions, which are evaluated using `numexpr.evaluate()`. + +(port-slicing)= + +### Port slicing + +You can also slice a port, to use some bits of the port as a signal that belongs to an interface. +The example below means: + +`Port m_axi_bid of the IP core is 36 bits wide. Use bits 23..12 as the BID signal of AXI master named m_axi_1` + +```yaml +m_axi_1: + type: AXI + mode: master + signals: + in: + BID: [m_axi_bid, 35, 0, 23, 12] +``` + +(interface-description-files)= + +## Interface Description files + +Topwrap can use predefined interfaces described in YAML files that come packaged with the tool. +Currently supported interfaces are AXI4, AXI3, AXI Stream, AXI Lite and Wishbone. + +You can see an example file below: + +```yaml +name: AXI4Stream +port_prefix: AXIS +signals: + # convention assumes the AXI Stream transmitter (master) perspective + required: + out: + TVALID: tvalid + TDATA: tdata + TLAST: tlast + in: + TREADY: tready + optional: + out: + TID: tid + TDEST: tdest + TKEEP: tkeep + TSTRB: tstrb + TUSER: tuser + TWAKEUP: twakeup +``` + +The name of an interface has to be unique. +We also specify a prefix which will be used as a shortened identifier. +Signals are either required or optional. +Their direction is described from the the perspective of master (i.e. directionality of signals in the slave is flipped) - note that clock and reset are not included as these are usually inputs in both master and slave so they're not supported in interface specification. +These distinctions are used when an option to check if all mandatory signals are present is enabled and when parsing an IP core with `topwrap parse` (not all required signals must necessarily be present but it's taken into account). +Every signal is a key-value pair, where the key is a generic signal name (usually from interface specification) and value is a regex that is used to pair the generic name with a concrete signal name in the RTL source when using `topwrap parse`. +This pairing is performed on signal names that are transformed to lowercase and have a common prefix of an interface they belong to removed. +If a regexp occurs in such transformed signal name anywhere, that name is paired with the generic name. +Since this occurs on names that have all characters in lowercase, regex must be written in lowercase as well. diff --git a/_sources/developers_guide/config.md.txt b/_sources/developers_guide/config.md.txt new file mode 100644 index 00000000..1bc31145 --- /dev/null +++ b/_sources/developers_guide/config.md.txt @@ -0,0 +1,19 @@ +# Config + +A {class}`~topwrap.config.Config` object stores configuration values. +A global `topwrap.config.config` object is used throughout the codebase to access topwrap's configuration. +This is created by {class}`~topwrap.config.ConfigManager` that reads config files defined in {attr}`topwrap.config.ConfigManager.DEFAULT_SEARCH_PATHS`, with files most local to the project taking precedence. + +```{eval-rst} +.. autoclass:: topwrap.config.Config + :members: + + .. automethod:: __init__ +``` + +```{eval-rst} +.. autoclass:: topwrap.config.ConfigManager + :members: + + .. automethod:: __init__ +``` diff --git a/_sources/developers_guide/elaboratable_wrapper.md.txt b/_sources/developers_guide/elaboratable_wrapper.md.txt new file mode 100644 index 00000000..68b7605b --- /dev/null +++ b/_sources/developers_guide/elaboratable_wrapper.md.txt @@ -0,0 +1,12 @@ +# ElaboratableWrapper class + +{class}`~topwrap.elaboratable_wrapper.ElaboratableWrapper` encapsulates an Amaranth's Elaboratable and exposes an interface compatible with other wrappers which allows making connections with them. +Supplied elaboratable must contain a `signature` property and a conforming interface as specified by [Amaranth docs](https://amaranth-lang.org/rfcs/0002-interfaces.html). +Ports' directionality, their names and widths are inferred from it. + +```{eval-rst} +.. autoclass:: topwrap.elaboratable_wrapper.ElaboratableWrapper + :members: + + .. automethod:: __init__ +``` diff --git a/_sources/developers_guide/examples.md.txt b/_sources/developers_guide/examples.md.txt new file mode 100644 index 00000000..b85ef58a --- /dev/null +++ b/_sources/developers_guide/examples.md.txt @@ -0,0 +1,17 @@ +# Examples + +:::{note} +Basic usage of examples is explained in the {ref}`getting-started` section. +::: + +Examples provided with this project should cover from very simple designs to complex fully synthesizable cores. +They should be sorted by increasing complexity and number of used features, e.g: +- 101: minimal base design +- 102: introduce user to parameters +- 103: introduce user to slicing +- 104: introduce user to interfaces +- 105: etc. + +Developers are encouraged to create/add new examples in the same spirit. +Simple examples are used to teach how to use this tool and demonstrate its features. +Real-world use cases are also welcome to prove that the implementation is mature enough to handle practical designs. diff --git a/_sources/developers_guide/fusesocbuilder.md.txt b/_sources/developers_guide/fusesocbuilder.md.txt new file mode 100644 index 00000000..464c0c16 --- /dev/null +++ b/_sources/developers_guide/fusesocbuilder.md.txt @@ -0,0 +1,34 @@ +# FuseSocBuilder + +Topwrap has support for generating FuseSoC's core files with {class}`~topwrap.fuse_helper.FuseSocBuilder`. +Such core file contains information about source files and synthesis tools. +Generation is based on a jinja template that defaults to `topwrap/templates/core.yaml.j2` but can be overridden. + +Here's an example of how to generate a simple project: + +```python +from topwrap.fuse_helper import FuseSocBuilder +fuse = FuseSocBuilder() + +# add source of the IPs used in the project +fuse.add_source('DMATop.v', 'verilogSource') + +# add source of the top file +fuse.add_source('top.v', 'verilogSource') + +# specify the names of the Core file and the directory where sources are stored +# generate the project +fuse.build('build/top.core', 'sources') +``` + +:::{warning} +Default template in `topwrap/templates/core.yaml.j2` does not make use of resources added with {meth}`~topwrap.fuse_helper.FuseSocBuilder.add_dependency` or {meth}`~topwrap.fuse_helper.FuseSocBuilder.add_external_ip`, i.e. they won't be present in the generated core file. +::: + + +```{eval-rst} +.. autoclass:: topwrap.fuse_helper.FuseSocBuilder + :members: + + .. automethod:: __init__ +``` diff --git a/_sources/developers_guide/future_enhancements.md.txt b/_sources/developers_guide/future_enhancements.md.txt new file mode 100644 index 00000000..1063013a --- /dev/null +++ b/_sources/developers_guide/future_enhancements.md.txt @@ -0,0 +1,59 @@ +(future-enhancements)= + +# Future enhancements + +(hierarchical-block-designs)= +## Support for hierarchical block design in Pipeline Manager + +Currently topwrap supports creating hierarchical designs only by manually writing the hierarchy in the design description YAML. +Supporting such feature in the Pipeline Manager via its subgraphs would be a huge improvement in terms of organizing complex designs. + +(bus-management)= +## Bus management + +Another goal we'd like to achieve is to enable users to create full-featured designs with processors by providing proper support for bus management. +This should include features such as: + +* ability to specify the address of a peripheral device on the bus +* support for the most popular buses or the ones that we use (AXI, wishbone, Tile-link) + +This will require writing or creating bus arbiters (round-robin, crossbar) and providing a mechanism for connecting master(s) and slave(s) together. +As a result, the user should be able to create complex SoC with Topwrap. + +Currently only experimental support for Wishbone with a round-robin arbiter {ref}`is available `. + +(improve-recreating-design)= +## Improve the process of recreating a design from a YAML file + +One of the main features that are supported by Topwrap and Pipeline Manager is exporting and importing user-created design to or from a design description YAML. However, during these conversions, information about the positions of user-added nodes is not preserved. This is cumbersome in the case of complicated designs since the imported nodes cannot be placed in the optimal positions. + +Therefore, one of our objectives is to provide a convenient way of creating and restoring user-created designs in Pipeline Manager, so that the user doesn't have to worry about node positions when importing a design to Pipeline Manager. + +(systemverilog-parsing)= +## Support for parsing SystemVerilog sources + +Information about IP cores is stored in {ref}`IP core description YAMLs `. These files can be generated automatically from HDL source files - currently Verilog and VHDL are supported. Our goal is to provide the possibility of generating such YAMLs from SystemVerilog too. + +(pm-hdl-parsing)= +## Provide a way to parse HDL sources from the Pipeline Manager level + +Another issue related to HDL parsing is that the user has to manually parse HDL sources to obtain the IP core description YAMLs. Then the files need to be provided as command-line parameters when launching the Topwrap Pipeline Manager client application. Therefore, we aim to provide a way of parsing HDL files and including them in the editor directly from the Pipeline Manager level. + +(toplevel-vhdl)= +## Ability to produce top-level wrappers in VHDL + +Topwrap now uses Amaranth to generate top-level design in Verilog. We would also like to add the ability to produce such designs in VHDL. + +(core-library)= +## Library of open-source cores + +Currently user has to supply all of the cores used in the design manually or semi-manually (e.g. through FuseSoC). +A repository of open-source cores that could be easily reused in topwrap would improve convenience and allow quickly putting together a design from premade hardware blocks. + +(tools-integration)= +## Integrating with other tools + +Topwrap can build the design but testing and synthesis rely on the user - they have to automate this process themselves (e.g. with makefiles). +Ideally the user should be able to write scripts that integrate tools for synthesis, simulation and co-simulation (e.g. with Renode) with topwrap. +Some would come pre-packaged with topwrap (e.g. simulation with verilator, synthesis with vivado). +It should also be possible to invoke these from the Pipeline Manager GUI by using its ability to add custom buttons and integrated terminal. diff --git a/_sources/developers_guide/interface.md.txt b/_sources/developers_guide/interface.md.txt new file mode 100644 index 00000000..03ef37bf --- /dev/null +++ b/_sources/developers_guide/interface.md.txt @@ -0,0 +1,18 @@ +# Interface definition + +Topwrap uses interface definition files for its parsing functionality. +These are used to match a given set of signals that appear in the HDL source with signals in the interface definition. + +{class}`~topwrap.interface.InterfaceDefinition` is defined as a {class}`marshmallow_dataclass.dataclass` - this enables loading YAML structure into Python objects and performs validation (that the YAML has the correct format) and typechecking (that the loaded values are of correct types). + + +```{eval-rst} +.. autoclass:: topwrap.interface.InterfaceDefinition + :members: + + .. automethod:: __init__ +``` + +```{eval-rst} +.. autofunction:: topwrap.interface.get_interface_by_name +``` diff --git a/_sources/developers_guide/ipconnect.md.txt b/_sources/developers_guide/ipconnect.md.txt new file mode 100644 index 00000000..8785b67d --- /dev/null +++ b/_sources/developers_guide/ipconnect.md.txt @@ -0,0 +1,39 @@ +# IPConnect class + +{class}`~topwrap.ipconnect.IPConnect` provides means of connecting ports and interfaces of objects that are subclasses of {class}`~topwrap.wrapper.Wrapper`. +Since {class}`~topwrap.ipconnect.IPConnect` is a subclass of {class}`~topwrap.wrapper.Wrapper` itself, this means that it also has IO - ports and interfaces, and that multiple {class}`~topwrap.ipconnect.IPConnect`s can have their ports and interfaces connected to each other (or other objects that subclass {class}`~topwrap.wrapper.Wrapper`). + +```{image} ../img/ipconnect.png +``` + +Instances of {class}`~topwrap.wrapper.Wrapper` objects can be added to an {class}`~topwrap.ipconnect.IPConnect` using {meth}`~topwrap.ipconnect.IPConnect.add_component` method: + +```python +# create a wrapper for an IP +dma = IPWrapper('DMATop.yaml', ip_name='DMATop', instance_name='DMATop0') +ipc = IPConnect() +ipc.add_component("dma", dma) +``` + +Connections between cores can then be made with {meth}`~topwrap.ipconnect.IPConnect.connect_ports` and {meth}`~topwrap.ipconnect.IPConnect.connect_interfaces` based on names of the components and names of ports/interfaces: + +```python +ipc.connect_ports("comp1_port_name", "comp1_name", "comp2_port_name", "comp2_name") +ipc.connect_interfaces("comp1_interface_name", "comp1_name", "comp2_interface_name", "comp2_name") +``` + +Setting ports or interfaces of a module added to {class}`~topwrap.ipconnect.IPConnect` as external with {meth}`~topwrap.ipconnect.IPConnect._set_port` and {meth}`~topwrap.ipconnect.IPConnect._set_interface` and allows these ports/interfaces to be connected to other {class}`~topwrap.wrapper.Wrapper` instances. +```python +ipc._set_port("comp1_name", "comp1_port_name", "external_port_name") +ipc._set_interface("comp1_name", "comp1_interface_name", "external_interface_name") +``` + +This is done automatically in {meth}`~topwrap.ipconnect.IPConnect.make_connections` method when the design is built based on the data from the YAML design description. + +```{eval-rst} +.. autoclass:: topwrap.ipconnect.IPConnect + :members: + :private-members: + + .. automethod:: __init__ +``` diff --git a/_sources/developers_guide/ipwrapper.md.txt b/_sources/developers_guide/ipwrapper.md.txt new file mode 100644 index 00000000..a5ddebcc --- /dev/null +++ b/_sources/developers_guide/ipwrapper.md.txt @@ -0,0 +1,19 @@ +# IPWrapper class + +{class}`~topwrap.ipwrapper.IPWrapper` provides an abstraction over a raw HDL source file. +Instances of this class can be created from a loaded YAML IP-core description. + +Under the hood it will create Amaranth's `Instance` object during elaboration, referencing a particular HDL module and it will appear as a module instantiation in the generated toplevel. +Ports and interfaces (lists of ports) can be retrieved via standard methods of {class}`~topwrap.wrapper.Wrapper`. +These are instances of {class}`~topwrap.amaranth_helpers.WrapperPort`s. + + +```{image} ../img/wrapper.png +``` + +```{eval-rst} +.. autoclass:: topwrap.ipwrapper.IPWrapper + :members: + + .. automethod:: __init__ +``` diff --git a/_sources/developers_guide/parsing.md.txt b/_sources/developers_guide/parsing.md.txt new file mode 100644 index 00000000..3614ea39 --- /dev/null +++ b/_sources/developers_guide/parsing.md.txt @@ -0,0 +1,67 @@ +# Deducing interfaces + +This section describes how inferring interfaces works when using `topwrap parse` with `--iface-deduce`, `--iface` or `--use-yosys` options. + +The problem can be described as follows: given a set of signals, infer what interfaces are present in this set and assign signals to appropriate interfaces. +Interface names and types (AXI4, AXI Stream, Wishbone, etc.) are, in the general case, not given in advance. +Algorithm implemented in topwrap works roughly as follows: + +1. Split the given signal set into disjoint subsets of signals based on common prefixes in their names +2. For a given subset, try to pair each signal name (as it appears in the RTL) with the name of an interface signal (as it is defined in the specification of a particular interface). +This pairing is called "a matching". +Matching with signals from all defined interfaces is tried. +3. For a given subset and matched interface, infer the interface direction (master/slave) based on the direction of some signal in this set. +4. Compute score for each matching, e.g. if signal names contain `cyc`, `stb` and `ack` (and possibly more) it's likely that this set is a Wishbone interface. +Among all interfaces, interface that has the highest matching score is selected. + +## Step 1. - splitting ports into subsets + +First, all ports of a module are grouped into disjoint subsets. Execution of this step differs based on the options supplied to `topwrap parse`: +- with `--iface` the user supplies topwrap with interface names - ports with names starting with a given interface name will be put in the same subset. +- with `--use-yosys` grouping is done by parsing the RTL source with `yosys`, where ports have attributes in the form of `(* interface="interface_name" *)`. +Ports with the same `interface_name` will be put in the same subset. +- with `--iface-deduce` grouping is done by computing longest common prefixes among all ports. +This is done with the help of a [trie](https://en.wikipedia.org/wiki/Trie) and only allows prefixes that would split the port name on an underscore (e.g. in `under_score` valid prefixes are an empty string, `under` and `under_score`) or a camel-case word boundary (e.g. in `wordBoundary` valid prefixes are an empty string, `word` and `wordBoundary`). +As with user-supplied prefixes, ports with names starting with a given prefix will be put in the same subset. + +## Step 2. - matching ports with interface signal names + +Given a subset of ports from a previous step, this step tries to match a regexp from an interface definition YAML for a given interface signal to one of the port names and returns a collection of pairs: RTL port + interface port. +For example, when matching against AXI4, a port named `axi_a_arvalid` should match to an interface port named `ARVALID` in the interface definition YAML. + +This operation is performed for all defined interfaces per a given subset of ports so the overall result of this step is a collection of matchings. +For most interfaces these matching will be poor - e.g. `axi_a_arvalid` or other AXI4 signals won't match to most Wishbone interface signals, but an interface that a human would usually assign to a given set of signals will have the most signals matched. + +## Step 3. - inferring interface direction + +This step picks a representative RTL signal from a single signal matching from the previous step and checks its direction against direction of the corresponding interface signal in interface definition YAML - if it's the same then it's a master interface (since the convention in interface description files is to describe signals from the master's perspective), otherwise it's a slave. + +## Step 4. - computing interface matching score + +This step computes a score for each matching returned by step 2. +This score is based on the number of matched/unmatched optional/required signals in each matching. + +Not matching some signals in a given group (from step 1.) is heavily penalized to encourage selecting interface that "fits" a given group best. +For example, AXI Lite is a subset of AXI4, so a set of signals that should be assigned AXI4 interface could very well fit the description of AXI Lite, but this mechanism discourages selecting such matching in favor of selecting the other. + +Not matching some signals of a given interface (from interface description YAML) is also penalized. +Inverting the previous example, a set of signals that should be assigned AXI Lite interface could very well fit the description of AXI4, but because it's missing a few AXI4 signals so selecting this matching is discouraged in favor of selecting the other. + +### Good scoring function + +A well-behaving scoring function should satisfy some properties to ensure that the best "fitting" interface is selected. +To describe these we introduce the following terminology: +* `>`/`>=`/`==` should be read as "must have a greater/greater or equal/equal score than". +* Partial matching means matching where some rtl signals haven't been matched to interface signals, full matching means matching where all have been matched. + +Current implementation when used with default config values satisfies these properties: + +1. full matching with N+1 signals matched (same type) == full matching with N signals matched (same type) +2. full matching with N signals matched (same type) > partial matching with N signals matched (same type) +3. partial matching with N+1 signals matched (same type) > partial matching with N signals matched (same type) +4. full matching with N+1 required, M+1 optional signals >= full matching with N+1 optional, M optional signals >= full matching with N required, M+1 optional signals >= full matching with N required, M optional signals + +Properties 2-4 generally ensure that interfaces with more signals matched are favored more over those with less signals matched. +Property 1. follows from the current implementation and is not needed in all implementations. + +Full details can be found in the implementation itself. diff --git a/_sources/developers_guide/setup.md.txt b/_sources/developers_guide/setup.md.txt new file mode 100644 index 00000000..2c76d8bf --- /dev/null +++ b/_sources/developers_guide/setup.md.txt @@ -0,0 +1,12 @@ +# Setup + +It is required for developers to keep code style and recommended to frequently run tests. +In order to setup the developer's environment install optional dependency groups `topwrap-parse`, `tests` and `lint` specified in `pyproject.toml` which include `nox` and `pre-commit`: + +```bash +python -m venv venv +source venv/bin/activate +pip install -e ".[topwrap-parse,tests,lint]" +``` + +The `-e` option is for installing in editable mode - meaning changes in the code under development will be immediately visible when using the package. diff --git a/_sources/developers_guide/style.md.txt b/_sources/developers_guide/style.md.txt new file mode 100644 index 00000000..a8f55990 --- /dev/null +++ b/_sources/developers_guide/style.md.txt @@ -0,0 +1,70 @@ +# Code style + +Automatic formatting and linting of the code can be performed with either `nox` or `pre-commit`. + +## Lint with nox + +After successful setup, `nox` sessions can be executed to perform lint checks: + +```bash +nox -s lint +``` + +This runs `isort`, `black`, `flake8` and `codespell` and fixes almost all formatting and linting problems automatically, but a small minority has to be fixed by hand (e.g. unused imports). + +:::{note} +To reuse current virtual environment and avoid long installation time use `-R` option: + +```bash +nox -R -s lint +``` +::: + +:::{note} +pre-commit can also be run from nox: + +```bash +nox -s pre_commit +``` +::: +## Lint with pre-commit + +Alternatively, you can use pre-commit to perform the same job. +`Pre-commit` hooks need to be installed: + +```bash +pre-commit install +``` + +Now, each use of `git commit` in the shell will trigger actions defined in the `.pre-commit-config.yaml` file. +Pre-commit can be easily disabled with a similar command: + +```bash +pre-commit uninstall +``` + +If you wish to run `pre-commit` asynchronously, then use: + +```bash +pre-commit run --all-files +``` + +:::{note} +`pre-commit` by default also runs `nox` with `isort`,`flake8`, `black` and `codespell` sessions +::: + +## Tools + +Tools used in project for maintaining code style: +* `Nox` is a tool, which simplifies management of Python testing. +[Visit nox website](https://nox.thea.codes/en/stable/) +* `Pre-commit` is a framework for managing and maintaining multi-language pre-commit hooks. +[Visit pre-commit website](https://pre-commit.com/) +* `Black` is a code formatter. +[Visit black website](https://black.readthedocs.io/en/stable/) +* `Flake8` is a tool capable of linting, styling fixes and complexity analysis. +[Visit flake8 website](https://flake8.pycqa.org/en/latest/) +* `Isort` is a Python utility to sort imports alphabetically. +[Visit isort website](https://pycqa.github.io/isort/) +* `Codespell` is a Python tool to fix common spelling mistakes in text files +[Visit codespell repository](https://github.com/codespell-project/codespell) diff --git a/_sources/developers_guide/tests.md.txt b/_sources/developers_guide/tests.md.txt new file mode 100644 index 00000000..3a9a9131 --- /dev/null +++ b/_sources/developers_guide/tests.md.txt @@ -0,0 +1,74 @@ +# Tests + +Topwrap functionality is validated with tests, leveraging the `pytest` library. + + +## Test execution + +Tests are located in the `tests` directory. +All tests can be run with `nox` by specifying the `tests` session: + +```bash +nox -s tests +``` + +This only runs tests on python interpreter versions that are available locally. +There is also a session `tests_in_env` that will automatically install all required python versions, provided you have [pyenv](https://github.com/pyenv/pyenv) installed: + +```bash +nox -s tests_in_env +``` + +:::{note} +To reuse existing virtual environment and avoid long installation time use `-R` option: + +```bash +nox -R -s tests_in_env +``` +::: + +To force a specific Python version and avoid running tests for all listed versions, use `-p VERSION` option: + +```bash +nox -p 3.10 -s tests_in_env +``` + +Tests can also be launched without `nox` by executing: +```bash +python -m pytest +``` + +:::{warning} +When running tests by invoking `pytest` directly, tests are ran only on the locally selected python interpreter. +As CI runs them on all supported Python versions it's recommended to run tests with `nox` on all versions before pushing. +::: + +Ignoring particular test can be done with `--ignore=test_path`, e.g: +```bash +python -m pytest --ignore=tests/tests_build/test_interconnect.py +``` + +Sometimes it's useful to see what's being printed by the test for debugging purposes. +Pytest captures all output from the test and displays it when all tests finish. +To see the output immediately, pass `-s` option to pytest: +```bash +python -m pytest -s +``` + +## Test coverage + +Test coverage is automatically generated when running tests with `nox`. +When invoking `pytest` directly it can be generated with `--cov=topwrap` option. +This will generate a summary of coverage displayed in CLI. + +```bash +python -m pytest --cov=topwrap +``` + +Additionally, the summary can be generated in HTML with `--cov=topwrap --cov-report html`, where lines that were not covered by tests can be browsed: + +```bash +python -m pytest --cov=topwrap --cov-report html +``` + +Generated report is available at `htmlcov/index.html` diff --git a/_sources/developers_guide/wrapper.md.txt b/_sources/developers_guide/wrapper.md.txt new file mode 100644 index 00000000..7bd6beea --- /dev/null +++ b/_sources/developers_guide/wrapper.md.txt @@ -0,0 +1,11 @@ +# Wrapper + +{class}`~topwrap.wrapper.Wrapper` is an abstraction over entities that have ports - examples include IP cores written in Verilog/VHDL, cores written in Amaranth and hierarchical collections for these that expose some external ports. +Subclasses of this class have to supply implementation of property {meth}`~topwrap.wrapper.Wrapper.get_ports` that has to return a list of all ports of the entity. + +```{eval-rst} +.. autoclass:: topwrap.wrapper.Wrapper + :members: + + .. automethod:: __init__ +``` diff --git a/_sources/developers_guide/wrapper_port.md.txt b/_sources/developers_guide/wrapper_port.md.txt new file mode 100644 index 00000000..fd59289b --- /dev/null +++ b/_sources/developers_guide/wrapper_port.md.txt @@ -0,0 +1,28 @@ +# Wrapper Port + +Class {class}`~topwrap.amaranth_helpers.WrapperPort` is an extension to Amaranth's {class}`Signal`. +It wraps a port, adding a new name and optionally slicing the signal. +It adds these attributes: + +```python +WrapperPort.internal_name # name of the port in internal source to be wrapped +WrapperPort.direction # DIR_FANIN, DIR_FANOUT or DIR_NONE +WrapperPort.interface_name # name of the group of ports (interface) +WrapperPort.bounds # range of bits that belong to the port + # and range which is sliced from the port +``` + +See {ref}`Port slicing ` to know more about `bounds`. + +This is used in {class}`~topwrap.ipwrapper.IPWrapper` class implementation and there should be no need to use {class}`~topwrap.amaranth_helpers.WrapperPort` individually. + +:::{warning} +{class}`~topwrap.amaranth_helpers.WrapperPort` is scheduled to be replaced in favor of plain Amaranth's {class}`Signal` so it should not be used in any new functionality. +::: + +```{eval-rst} +.. autoclass:: topwrap.amaranth_helpers.WrapperPort + :members: + + .. automethod:: __init__ +``` diff --git a/_sources/fusesoc.md.txt b/_sources/fusesoc.md.txt new file mode 100644 index 00000000..023c4f20 --- /dev/null +++ b/_sources/fusesoc.md.txt @@ -0,0 +1,16 @@ +# FuseSoC + +Topwrap uses FuseSoC to automate project generation and build process. +When `topwrap build` is invoked it generates a FuseSoC core file along with the top-level wrapper. + +A template for the core file is bundled with Topwrap (`templates/core.yaml.j2`). +You may need to edit the file to change the backend tool, set additional `Hooks` and change the FPGA part name or other parameters. +By default, {class}`topwrap.fuse_helper.FuseSocBuilder` searches for the template file in the directory you work in, so you should first copy the template into the project's location. + +After generating the core file you can run FuseSoC to generate bitstream and program FPGA: + +```bash +fusesoc --cores-root build run project_1 +``` + +This requires having the suitable backend tool in your `PATH` (Vivado, for example). diff --git a/_sources/getting_started.md.txt b/_sources/getting_started.md.txt new file mode 100644 index 00000000..3fd590e5 --- /dev/null +++ b/_sources/getting_started.md.txt @@ -0,0 +1,223 @@ +(getting-started)= + +# Getting started + +## Installation + +1. Install required system packages: + + Debian: + ```bash + apt install -y git g++ make python3 python3-pip antlr4 libantlr4-runtime-dev yosys npm + ``` + + Arch: + ```bash + pacman -Syu git gcc make python3 python-pip antlr4 antlr4-runtime yosys npm + ``` + + Fedora: + ```bash + dnf install git g++ make python3 python3-pip python3-devel antlr4 antlr4-cpp-runtime-devel yosys npm + ``` + +2. Install the Topwrap package (It is highly recommended to run this step in a Python virtual environment, e.g. [venv](https://docs.python.org/3/library/venv.html)): + + ```bash + pip install . + ``` + +:::{note} +To use `topwrap parse` command you also need to install optional dependencies: +```bash +pip install ".[topwrap-parse]" +``` +On Arch-based distributions a symlink to antlr4 runtime library needs to created and an environment variable set: +```bash +ln -s /usr/share/java/antlr-complete.jar antlr4-complete.jar +ANTLR_COMPLETE_PATH=`pwd` pip install ".[topwrap-parse]" +``` +On Fedora-based distributions symlinks need to be made inside `/usr/share/java` directory itself: +```bash +sudo ln -s /usr/share/java/stringtemplate4/ST4.jar /usr/share/java/stringtemplate4.jar +sudo ln -s /usr/share/java/antlr4/antlr4.jar /usr/share/java/antlr4.jar +sudo ln -s /usr/share/java/antlr4/antlr4-runtime.jar /usr/share/java/antlr4-runtime.jar +sudo ln -s /usr/share/java/treelayout/org.abego.treelayout.core.jar /usr/share/java/treelayout.jar +pip install ".[topwrap-parse]" +``` +::: + +(example-usage)= + +## Example usage + +This section demonstrates the basic usage of Topwrap to generate IP wrappers and a top module. + +1. Create {ref}`IP core description ` file for every IP Core you want to use or let {ref}`topwrap parse ` handle this for you. This file describes the ports, parameters and interfaces of an IP core. + +As an example, Verilog module such as: + +```verilog +module ibuf ( + input wire clk, + input wire rst, + input wire a, + output reg z +); + // ... +endmodule +``` + +Needs this corresponding description: + +```yaml +signals: + in: + - clk + - rst + - a + out: + - z +``` + +2. Create a {ref}`design description ` file where you can specify all instances of IP cores and connections between them (`project.yaml` in this example) + +- Create instances of IP cores: + +```yaml +ips: + vexriscv_instance: + file: ipcores/gen_VexRiscv.yaml + module: VexRiscv + wb_ram_data_instance: + file: ipcores/gen_mem.yaml + module: mem + wb_ram_instr_instance: + file: ipcores/gen_mem.yaml + module: mem + +``` + +`file` and `module` are mandatory fields providing the IP description file and the name of the HDL module as it appears in the source. + +- (Optional) Set parameters for IP core instances: + +```yaml +parameters: + wb_ram_data_instance: + depth: 0x1000 + memfile: "top_sram.init" + wb_ram_instr_instance: + depth: 0xA000 + memfile: "bios.init" +``` + +- Connect desired ports of the IP cores: + +```yaml +ports: + wb_ram_data_instance: + clk: [some_other_ip, clk_out] + rst: [reset_core, reset0] + wb_ram_instr_instance: + clk: [some_other_ip, clk_out] + rst: [reset_core, reset0] + vexriscv_instance: + softwareInterrupt: [some_other_ip, sw_interrupt] + ... +``` + +Connections only need to be written once, i.e. if A connects to B, then only a connection A: B has to be specified (B: A is redundant). + +- Connect desired interfaces of the IP cores: + +```yaml +interfaces: + vexriscv_instance: + iBusWishbone: [wb_ram_instr_instance, mem_bus] + dBusWishbone: [wb_ram_data_instance, mem_bus] +``` + +- Specify external ports or interfaces of the top module and connect them with chosen IP cores' ports or interfaces: + +```yaml +ports: + vexriscv_instance: + timerInterrupt: ext_timer_interrupt + +... + +external: + ports: + out: + - ext_timer_interrupt + interfaces: + ... +``` + +3. Create a Core file template for FuseSoC, or use a default one bundled with Topwrap. + +You may want to modify the file to add dependencies, source files, or change the target board. +The file should be named `core.yaml.j2`. You can find an example template in `examples/hdmi` directory of the project. +If you don't create any template a default template bundled with Topwrap will be used (stored in `templates` directory). + +4. Place any additional source files in a directory (`sources` in this example). + +5. Run Topwrap: + + ``` + python -m topwrap build --design project.yaml --sources sources + ``` + +### Example PWM design + +There's an example setup in `examples/pwm`. + +In order to generate the top module, run: + +``` +make generate +``` + +In order to generate bitstream, add Vivado to your path and run: + +``` +make +``` + +The FPGA design utilizes an AXI-mapped PWM IP Core. +You can access its registers starting from address `0x4000000` (that's the base address of `AXI_GP0` on ZYNQ). +Each IP Core used in the project is declared in `ips` section in `project.yml` file. +`ports` section allows to connect individual ports of IP Cores, and `interfaces` is used analogously for connecting whole interfaces. +Finally, you can specify which ports will be used as external I/O in `external` section. + +To connect the I/O signals to specific FPGA pins, you need proper mappings in a constraints file. See `zynq.xdc` used in the setup and modify it accordingly. + +```{image} img/pwm.png +``` + +### Example HDMI design + +There's an example setup stored in `examples/hdmi`. + +You can generate bitstream for desired target: + +> - Snickerdoodle Black: +> +> ``` +> make snickerdoodle +> ``` +> +> - Zynq Video Board: +> +> ``` +> make zvb +> ``` + +If you wish to generate HDL sources without running Vivado, you can use: + +``` +make generate +``` + +You can find more information in README of the example setup. diff --git a/_sources/hierarchies.md.txt b/_sources/hierarchies.md.txt new file mode 100644 index 00000000..980cef99 --- /dev/null +++ b/_sources/hierarchies.md.txt @@ -0,0 +1,44 @@ +# Hierarchies + +Hierarchies allow for creating designs with subgraphs in them. +Subgraphs can contain multiple IP-cores and other subgraphs. +This allows creating nested designs in topwrap. + +## Format + +All information about hierarchies is specified in [design description](description_files.md). +`hierarchies` key must be a direct descendant of the `design` key. +Format is as follows: + +```yaml +hierarchies: + {hierarchy_name_1}: + ips: # ips that are used on this hierarchy level + {ip_name}: + ... + + design: + parameters: + ... + ports: # ports connections internal to this hierarchy + # note that also you have to connect port to it's external port equivalent (if exists) + {ip1_name}: + {port1_name} : [{ip2_name}, {port2_name}] + {port2_name} : {port2_external_equivalent} # connection to external port equivalent. Note that it has to be to the parent port + ... + hierarchies: + {nested_hierarchy_name}: + # structure here will be the same as for {hierarchy_name_1} + ... + external: + # external ports and/or interfaces of this hierarchy; these can be + # referenced in the upper-level `ports`, `interfaces` or `external` section + ports: + in: + - {port2_external_equivalent} + ... + {hierarchy_name_2}: + ... +``` + +More complex hierarchy example can be found in [examples/hierarchy](https://github.com/antmicro/topwrap/tree/main/examples/hierarchy). diff --git a/_sources/index.md.txt b/_sources/index.md.txt new file mode 100644 index 00000000..34144f88 --- /dev/null +++ b/_sources/index.md.txt @@ -0,0 +1,34 @@ +# Welcome to Topwrap! + +```{toctree} +:caption: Documentation +:maxdepth: 2 +introduction +getting_started +description_files +interconnect_gen +cli +user_repositories +hierarchies +pipeline_manager +fusesoc +``` + +```{toctree} +:caption: Developer's Guide +:maxdepth: 2 +developers_guide/setup +developers_guide/style +developers_guide/tests +developers_guide/wrapper +developers_guide/ipwrapper +developers_guide/ipconnect +developers_guide/elaboratable_wrapper +developers_guide/wrapper_port +developers_guide/fusesocbuilder +developers_guide/interface +developers_guide/config +developers_guide/parsing +developers_guide/examples +developers_guide/future_enhancements +``` diff --git a/_sources/interconnect_gen.md.txt b/_sources/interconnect_gen.md.txt new file mode 100644 index 00000000..a26be4a4 --- /dev/null +++ b/_sources/interconnect_gen.md.txt @@ -0,0 +1,68 @@ +(interconnect-generation)= +# Interconnect generation + +Generating interconnects is an experimental feature of topwrap. +With a specification of which interfaces are masters or slaves and their address ranges, topwrap is able to automatically generate an interconnect conforming to this description. Currently supported interconnect types are: +- Wishbone round-robin + +## Format + +The format for describing interconnects is specified below. `interconnects` key must be a direct descendant of the `design` key in the design description. + +```yaml +interconnects: + {interconnect1_name}: + # specify clock and reset to drive the interconnect with + clock: [{ip_name, clk_port_name}] + reset: [{ip_name, rst_port_name}] + # alternatively you can specify a connection to an external interface: + # clock: ext_clk_port_name + # reset: ext_rst_port_name + + # specify interconnect type + type: {interconnect_type} + + # specify interconnect parameters - interconnect-type-dependent (see "Interconnect params" section): + params: + {param_name1}: param_value1 + ... + + # specify masters and their interfaces connected to the bus + masters: + {master1_name}: + - {master1_iface1_name} + ... + ... + + # specify slaves, their interfaces connected to the bus and their bus parameters + slaves: + {slave1_name}: + {slave1_interface1_name}: + # requests in address range [address, address+size) will be routed to this interface + address: {start_address} + size: {range_size} + ... + ... +``` + +## Interconnect params + +Different interconnect types may provide different configuration options. +This section lists parameter names for available interconnects for use in the `params` section of interconnect specification. + +### Wishbone round-robin + +Corresponds to `type: wishbone_roundrobin` + +- `addr_width` - bit width of the address line (addresses access `data_width`-sized chunks) +- `data_width` - bit width of the data line +- `granularity` - access granularity - smallest unit of data transfer that the interconnect is capable of transferring. Must be one of: 8, 16, 32, 64 +- `features` - optional, list of optional wishbone signals, can contain: `err`, `rty`, `stall`, `lock`, `cti`, `bte` + +## Limitations + +Known limitations currently are: +- only word-sized addressing is supported (in other words - consecutive addresses access word-sized chunks of data) +- crossing clock domains is not supported +- down-converting (initiating multiple transactions on a narrow bus per one transaction on a wider bus) is not supported +- up-converting is not supported diff --git a/_sources/introduction.md.txt b/_sources/introduction.md.txt new file mode 100644 index 00000000..8439715c --- /dev/null +++ b/_sources/introduction.md.txt @@ -0,0 +1,13 @@ +# Introduction + +ASIC and FPGA designs consist of distinct blocks of logic bound together by a top-level design. +To take advantage of this modularity and enable reuse of blocks across designs and so facilitate the shift towards automation in logic design, it is necessary to derive a generic way to aggregate the blocks in various configurations and make the top-level design easy to parse and process automatically. + +Topwrap is an open source command line toolkit for connecting individual HDL modules into full designs of varying complexity. +The toolkit is designed to take advantage of the ever-growing availability of open source digital logic designs and offers a user-friendly graphical interface which lets you mix-and-match GUI-driven design with CLI-based adjustments and present designs in a diagram form thanks to the integration with Antmicro’s [Pipeline Manager](https://github.com/antmicro/kenning-pipeline-manager). + +Topwrap's most notable features are: +* Parsing HDL design files with automatic recognition of common interfaces +* Simple YAML-based description for command-line use +* Capability to create a custom libraries for reuse across projects +* User-friendly GUI powered by [Kenning Pipeline Manager](https://github.com/antmicro/kenning-pipeline-manager). diff --git a/_sources/pipeline_manager.md.txt b/_sources/pipeline_manager.md.txt new file mode 100644 index 00000000..156ee7c7 --- /dev/null +++ b/_sources/pipeline_manager.md.txt @@ -0,0 +1,98 @@ +(kenning-pipeline-manager)= + +# Kenning Pipeline Manager + +Topwrap can make use of [Kenning Pipeline Manager](https://github.com/antmicro/kenning-pipeline-manager) to visualize the process of creating block design. + +## Run Topwrap with Pipeline Manager + +1. Build and run Pipeline Manager server + + In order to start creating block design in Pipeline Manager, you need to first build and run a server application - here is a brief instruction on how to achieve this (the process of building and installation of Pipeline Manager is described in detail in its [documentation](https://antmicro.github.io/kenning-pipeline-manager/project-readme.html#building-and-running)): + + ``` + python -m topwrap kpm_build_server + python -m topwrap kpm_run_server + ``` + + After executing the above-mentioned commands, the Pipeline Manager server is waiting for an external application (i.e. Topwrap) to connect on `127.0.0.1:9000` and you can connect to the web GUI frontend in your browser on `http://127.0.0.1:5000`. + +2. Establish connection with Topwrap + + Once the Pipeline Manager server is running, you can now launch Topwrap's client application in order to connect to the server. You need to specify: + * IP address (`127.0.0.1` is default) + * listening port (`9000` is default) + * yamls describing IP cores, that will be used in the block design + * design to load initially (`None` by default) + + An example command, that runs Topwrap's client, may look like this: + ``` + python -m topwrap kpm_client -h 127.0.0.1 -p 9000 \ + topwrap/ips/axi/axi_axil_adapter.yaml \ + examples/pwm/ipcores/{litex_pwm.yml,ps7.yaml} -d examples/pwm/project.yml + ``` + +3. Create block design in Pipeline Manager + + Upon successful connection to a Pipeline Manager server, Topwrap will generate and send to the server a specification describing the structure of previously selected IP cores. After that, you are free to create a custom block design by means of: + * adding IP core instances to the block design. Each Pipeline Manager's node has `delete` and `rename` options, which make it possible to remove the selected node and change its name respectively. This means that you can create multiple instances of the same IP core. + * adjusting IP cores' parameters values. Each node may have input boxes in which you can enter parameters' values (default parameter values are added while adding an IP core to the block design): + ```{image} img/node_parameters.png + ``` + * connecting IP cores' ports and interfaces. Only connections between ports or interfaces of matching types are allowed. This is automatically checked by Pipeline Manager, as the types of nodes' ports and interfaces are contained in the loaded specification, so Pipeline Manager will prevent you from connecting non-matching interfaces (e.g. *AXI4* with *AXI4Lite* or a port with an interface). A green line will be displayed if a connection is possible to create, or a red line elsewhere: + ```{image} img/invalid_connection.png + ``` + * specifying external ports or interfaces in the top module. This can be done by adding `External Input`, `External Output` or `External Inout` metanodes and creating connections between them and chosen ports or interfaces. Note that you should adjust the name of the external port or interface in a textbox inside selected metanode. In the example below, output port `pwm` of `litex_pwm_top` IP core will be made external in the generated top module and the external port name will be set to `ext_pwm`: + ```{image} img/external_port.png + ``` + Note, that you don't always have to create a new block design by hand - you can use a {ref}`design import ` feature to load an existing block design from a description in Topwrap's yaml format. + + An example block design in Pipeline Manager for the PWM project may look like this: + + ```{image} img/pwm_design.png + ``` + +## Pipeline Manager features + +While creating a custom block design, you can make use of the following Pipeline Manager's features: +* export (save) design to a file +* import (load) design from a file +* validate design +* build design + +(export-design)= + +### Export design to yaml description file + +Created block design can be saved to a {ref}`design description file ` in yaml format, using Pipeline Manager's `Save file` option. +Target location on the filesystem can then be browsed in a filesystem dialog window. + +(import-design)= + +### Import design from yaml description file + +Topwrap also supports conversion in the opposite way - block design in Pipeline Manager can be generated from a yaml design description file using `Load file` feature. + +(validate-design)= + +### Design validation + +Pipeline Manager is capable of performing some basic checks at runtime such as interface type checking while creating a connection. However you can also run more complex tests by using Pipeline Manager's `Validate` option. Topwrap will then respond with a validity confirmation or error messages. The rules you need to follow in order to keep your block design valid are: +* multiple IP cores with the same name are not allowed (except from external metanodes). +* parameters values can be integers of different bases (e.g. `0x28`, `40` or `0b101000`) or arithmetic expressions, that are later evaluated using [numexpr.evaluate()](https://numexpr.readthedocs.io/en/latest/api.html#numexpr.evaluate) function (e.g. `(AXI_DATA_WIDTH+1)/4` is a valid parameter value assuming that a parameter named `AXI_DATA_WIDTH` exists in the same IP core). You can also write a parameter value in a Verilog format (e.g. `8'b00011111` or `8'h1F`) - in such case it will be interpreted as a fixed-width bit vector. +* a single port or interface cannot be external and connected to another IP core at the same time. +* connections between two external metanodes are not allowed. +* all the created external output or inout ports must have unique names. Only multiple input ports of IP cores can be driven be the same external signal. + +Topwrap can also generate warnings if: +* some ports or interfaces remain unconnected. +* multiple ports are connected to an `External Input` metanode with an empty `External Name` property. +* `inout` ports of two modules are connected together (all `inout` ports are required to be directly connected to `External Inout` metanodes) + +If a block design validation returns a warning, it means that the block design can be successfully built, but it is recommended to follow the suggestion and resolve a particular issue. + +(build-design)= + +### Building design + +Once the design has been created and tested for validity, you can build design using `Run` button. If the design does not contain any errors, this will result in creating a top module in a directory where `topwrap kpm_client` was ran, similarly when using Topwrap's `topwrap build` command. diff --git a/_sources/user_repositories.md.txt b/_sources/user_repositories.md.txt new file mode 100644 index 00000000..f6a289a6 --- /dev/null +++ b/_sources/user_repositories.md.txt @@ -0,0 +1,45 @@ +# User repositories +Repositories allow for easy loading packages with IP-cores. + +You can add repositories to be loaded each time topwrap is ran by specifying them in configuration file. + +It has to be located in one of the following locations: +``` +topwrap.yaml +~/.config/topwrap/topwrap.yaml +~/.config/topwrap/config.yaml +``` + +Example contents of user config: +``` +force_interface_compliance: true +repositories: + - name: name of repo + path: ~/path_to_repo/repo +``` + +Topwrap provides internal API for constructing repositories in python code which can be [found here](https://github.com/antmicro/topwrap/blob/main/topwrap/repo/user_repo.py#L144) + +Structure of repository has to be as follows: +``` +path_to_repository/ +|───cores +| |───someCore1 +| | |───srcs +| | | | file1.v +| | | design.yaml +| | +| |───someCore1 +| |───srcs +| | | file1.v +| | design.yaml +| +|───interfaces(Optional) +| interface1.yaml +| interface2.yaml +``` +Repository has two main catalogs: `cores` and `interfaces`. Inside `cores` each core has it's own catalog with it's design file and `srcs` where are stored verilog/VHDL files. + +There is optional interfaces catalog where can be stored interfaces for cores. + +Example User Repo can be found in [examples/user_repository](https://github.com/antmicro/topwrap/tree/main/examples/user_repository). diff --git a/_static/fonts/0053ba6958e79f26751eabb555bd73d0.woff2 b/_static/fonts/0053ba6958e79f26751eabb555bd73d0.woff2 new file mode 100644 index 00000000..ab301009 Binary files /dev/null and b/_static/fonts/0053ba6958e79f26751eabb555bd73d0.woff2 differ diff --git a/_static/fonts/029e176ad602329b4434892101db9cf3.woff2 b/_static/fonts/029e176ad602329b4434892101db9cf3.woff2 new file mode 100644 index 00000000..09e03c95 Binary files /dev/null and b/_static/fonts/029e176ad602329b4434892101db9cf3.woff2 differ diff --git a/_static/fonts/07ff82964967feebb9c96288e0e0df05.woff2 b/_static/fonts/07ff82964967feebb9c96288e0e0df05.woff2 new file mode 100644 index 00000000..d338178b Binary files /dev/null and b/_static/fonts/07ff82964967feebb9c96288e0e0df05.woff2 differ diff --git a/_static/fonts/0948409a22b5979aa7e1ec20da9e61f1.woff2 b/_static/fonts/0948409a22b5979aa7e1ec20da9e61f1.woff2 new file mode 100644 index 00000000..6b0b4afe Binary files /dev/null and b/_static/fonts/0948409a22b5979aa7e1ec20da9e61f1.woff2 differ diff --git a/_static/fonts/0a0ad0eae50e549ecd713b9ad417f1a1.woff2 b/_static/fonts/0a0ad0eae50e549ecd713b9ad417f1a1.woff2 new file mode 100644 index 00000000..f477fda0 Binary files /dev/null and b/_static/fonts/0a0ad0eae50e549ecd713b9ad417f1a1.woff2 differ diff --git a/_static/fonts/0b68e8634c96265eb32a0c769416b5b0.woff2 b/_static/fonts/0b68e8634c96265eb32a0c769416b5b0.woff2 new file mode 100644 index 00000000..9a378af0 Binary files /dev/null and b/_static/fonts/0b68e8634c96265eb32a0c769416b5b0.woff2 differ diff --git a/_static/fonts/0d1b73eee266eabb2cff35dfa4ce25a3.woff2 b/_static/fonts/0d1b73eee266eabb2cff35dfa4ce25a3.woff2 new file mode 100644 index 00000000..48a8c10f Binary files /dev/null and b/_static/fonts/0d1b73eee266eabb2cff35dfa4ce25a3.woff2 differ diff --git a/_static/fonts/0e1f73c6737cdf273efb4b79504e4c0a.woff2 b/_static/fonts/0e1f73c6737cdf273efb4b79504e4c0a.woff2 new file mode 100644 index 00000000..6aa28456 Binary files /dev/null and b/_static/fonts/0e1f73c6737cdf273efb4b79504e4c0a.woff2 differ diff --git a/_static/fonts/0e326670106c8eb6a11a8c30734ecfc8.ttf b/_static/fonts/0e326670106c8eb6a11a8c30734ecfc8.ttf new file mode 100644 index 00000000..fbb56251 Binary files /dev/null and b/_static/fonts/0e326670106c8eb6a11a8c30734ecfc8.ttf differ diff --git a/_static/fonts/0ec3cc19652785204ea2e322330f0f1b.woff2 b/_static/fonts/0ec3cc19652785204ea2e322330f0f1b.woff2 new file mode 100644 index 00000000..5b0171c1 Binary files /dev/null and b/_static/fonts/0ec3cc19652785204ea2e322330f0f1b.woff2 differ diff --git a/_static/fonts/0f303f31706d39866cced9dcc17b61fb.woff2 b/_static/fonts/0f303f31706d39866cced9dcc17b61fb.woff2 new file mode 100644 index 00000000..71c9bb7d Binary files /dev/null and b/_static/fonts/0f303f31706d39866cced9dcc17b61fb.woff2 differ diff --git a/_static/fonts/101522bafe9c61c68698ecc784607772.woff2 b/_static/fonts/101522bafe9c61c68698ecc784607772.woff2 new file mode 100644 index 00000000..186d9986 Binary files /dev/null and b/_static/fonts/101522bafe9c61c68698ecc784607772.woff2 differ diff --git a/_static/fonts/10b31f4cad9ea78d43449886bfbb88ac.woff2 b/_static/fonts/10b31f4cad9ea78d43449886bfbb88ac.woff2 new file mode 100644 index 00000000..02a27ead Binary files /dev/null and b/_static/fonts/10b31f4cad9ea78d43449886bfbb88ac.woff2 differ diff --git a/_static/fonts/1181a8e619707033241139715eca64c6.woff2 b/_static/fonts/1181a8e619707033241139715eca64c6.woff2 new file mode 100644 index 00000000..59ed385e Binary files /dev/null and b/_static/fonts/1181a8e619707033241139715eca64c6.woff2 differ diff --git a/_static/fonts/122802d03aed4bf8cd6a03997a97aca4.woff2 b/_static/fonts/122802d03aed4bf8cd6a03997a97aca4.woff2 new file mode 100644 index 00000000..40b9fda9 Binary files /dev/null and b/_static/fonts/122802d03aed4bf8cd6a03997a97aca4.woff2 differ diff --git a/_static/fonts/1383417807f7965daaf94e7c497dcddb.woff2 b/_static/fonts/1383417807f7965daaf94e7c497dcddb.woff2 new file mode 100644 index 00000000..d953103e Binary files /dev/null and b/_static/fonts/1383417807f7965daaf94e7c497dcddb.woff2 differ diff --git a/_static/fonts/144860ed1e48e186f08997e6388a9c3f.woff2 b/_static/fonts/144860ed1e48e186f08997e6388a9c3f.woff2 new file mode 100644 index 00000000..508baefb Binary files /dev/null and b/_static/fonts/144860ed1e48e186f08997e6388a9c3f.woff2 differ diff --git a/_static/fonts/1488146d8b2e9859d6c90e6c2b48f7ef.woff2 b/_static/fonts/1488146d8b2e9859d6c90e6c2b48f7ef.woff2 new file mode 100644 index 00000000..bdad3dfb Binary files /dev/null and b/_static/fonts/1488146d8b2e9859d6c90e6c2b48f7ef.woff2 differ diff --git a/_static/fonts/1512b579343c6b61c7523cdd838d8328.ttf b/_static/fonts/1512b579343c6b61c7523cdd838d8328.ttf new file mode 100644 index 00000000..1a6895d1 Binary files /dev/null and b/_static/fonts/1512b579343c6b61c7523cdd838d8328.ttf differ diff --git a/_static/fonts/1c9cc76fd52238330f0aabac35acd2ca.woff2 b/_static/fonts/1c9cc76fd52238330f0aabac35acd2ca.woff2 new file mode 100644 index 00000000..cb9bfa71 Binary files /dev/null and b/_static/fonts/1c9cc76fd52238330f0aabac35acd2ca.woff2 differ diff --git a/_static/fonts/1f1481679a64a39f3427547aa1b13f0f.woff2 b/_static/fonts/1f1481679a64a39f3427547aa1b13f0f.woff2 new file mode 100644 index 00000000..6d458ad0 Binary files /dev/null and b/_static/fonts/1f1481679a64a39f3427547aa1b13f0f.woff2 differ diff --git a/_static/fonts/2096d27efc16cbdd79183bf295c8ebde.ttf b/_static/fonts/2096d27efc16cbdd79183bf295c8ebde.ttf new file mode 100644 index 00000000..2cf147e1 Binary files /dev/null and b/_static/fonts/2096d27efc16cbdd79183bf295c8ebde.ttf differ diff --git a/_static/fonts/20dc200cc43ab904876fb0c1697ebe39.woff2 b/_static/fonts/20dc200cc43ab904876fb0c1697ebe39.woff2 new file mode 100644 index 00000000..87711c04 Binary files /dev/null and b/_static/fonts/20dc200cc43ab904876fb0c1697ebe39.woff2 differ diff --git a/_static/fonts/214adfc289a2f2af8b0008c59ed0c7f2.woff2 b/_static/fonts/214adfc289a2f2af8b0008c59ed0c7f2.woff2 new file mode 100644 index 00000000..bc7e1b2c Binary files /dev/null and b/_static/fonts/214adfc289a2f2af8b0008c59ed0c7f2.woff2 differ diff --git a/_static/fonts/21953b998bab09c1f60c599caee56378.woff2 b/_static/fonts/21953b998bab09c1f60c599caee56378.woff2 new file mode 100644 index 00000000..d4ec1890 Binary files /dev/null and b/_static/fonts/21953b998bab09c1f60c599caee56378.woff2 differ diff --git a/_static/fonts/22aadc77cafa07b2db9ed560d0320616.woff2 b/_static/fonts/22aadc77cafa07b2db9ed560d0320616.woff2 new file mode 100644 index 00000000..2950a77c Binary files /dev/null and b/_static/fonts/22aadc77cafa07b2db9ed560d0320616.woff2 differ diff --git a/_static/fonts/2325b97b584755067ea4f7f56ee05430.woff2 b/_static/fonts/2325b97b584755067ea4f7f56ee05430.woff2 new file mode 100644 index 00000000..51c88fde Binary files /dev/null and b/_static/fonts/2325b97b584755067ea4f7f56ee05430.woff2 differ diff --git a/_static/fonts/2550c2e2d8495c3ed2d4d52f824374f1.woff2 b/_static/fonts/2550c2e2d8495c3ed2d4d52f824374f1.woff2 new file mode 100644 index 00000000..81848e2c Binary files /dev/null and b/_static/fonts/2550c2e2d8495c3ed2d4d52f824374f1.woff2 differ diff --git a/_static/fonts/255cf41e0317d95e3992683a76ef28a8.woff2 b/_static/fonts/255cf41e0317d95e3992683a76ef28a8.woff2 new file mode 100644 index 00000000..7e931875 Binary files /dev/null and b/_static/fonts/255cf41e0317d95e3992683a76ef28a8.woff2 differ diff --git a/_static/fonts/25c52b9af13f0d1b10719f5289e8c803.woff2 b/_static/fonts/25c52b9af13f0d1b10719f5289e8c803.woff2 new file mode 100644 index 00000000..544eddca Binary files /dev/null and b/_static/fonts/25c52b9af13f0d1b10719f5289e8c803.woff2 differ diff --git a/_static/fonts/2781e9e7c3f369b8fc7965e679b17b60.woff2 b/_static/fonts/2781e9e7c3f369b8fc7965e679b17b60.woff2 new file mode 100644 index 00000000..cf61b889 Binary files /dev/null and b/_static/fonts/2781e9e7c3f369b8fc7965e679b17b60.woff2 differ diff --git a/_static/fonts/28e6b81b1bc1964707edd4179e4268f5.ttf b/_static/fonts/28e6b81b1bc1964707edd4179e4268f5.ttf new file mode 100644 index 00000000..d7455040 Binary files /dev/null and b/_static/fonts/28e6b81b1bc1964707edd4179e4268f5.ttf differ diff --git a/_static/fonts/2a8c422bef4a7099e99dbf0e61ed5e49.woff2 b/_static/fonts/2a8c422bef4a7099e99dbf0e61ed5e49.woff2 new file mode 100644 index 00000000..c8091bc9 Binary files /dev/null and b/_static/fonts/2a8c422bef4a7099e99dbf0e61ed5e49.woff2 differ diff --git a/_static/fonts/2aadfad5aee7ceeaf4eb0924efabe5b4.ttf b/_static/fonts/2aadfad5aee7ceeaf4eb0924efabe5b4.ttf new file mode 100644 index 00000000..64fca947 Binary files /dev/null and b/_static/fonts/2aadfad5aee7ceeaf4eb0924efabe5b4.ttf differ diff --git a/_static/fonts/2c0f74be498d2da814c0a84dd6833f70.woff2 b/_static/fonts/2c0f74be498d2da814c0a84dd6833f70.woff2 new file mode 100644 index 00000000..8c63b51b Binary files /dev/null and b/_static/fonts/2c0f74be498d2da814c0a84dd6833f70.woff2 differ diff --git a/_static/fonts/2e10480d4154762bc7c8fbb40877e104.woff2 b/_static/fonts/2e10480d4154762bc7c8fbb40877e104.woff2 new file mode 100644 index 00000000..1f579aa4 Binary files /dev/null and b/_static/fonts/2e10480d4154762bc7c8fbb40877e104.woff2 differ diff --git a/_static/fonts/2ea7a97b7c976b121112a088eb398561.woff2 b/_static/fonts/2ea7a97b7c976b121112a088eb398561.woff2 new file mode 100644 index 00000000..e0d3c435 Binary files /dev/null and b/_static/fonts/2ea7a97b7c976b121112a088eb398561.woff2 differ diff --git a/_static/fonts/2f5c32f094829c0278bce28fe2bbe074.ttf b/_static/fonts/2f5c32f094829c0278bce28fe2bbe074.ttf new file mode 100644 index 00000000..ea5c8fe0 Binary files /dev/null and b/_static/fonts/2f5c32f094829c0278bce28fe2bbe074.ttf differ diff --git a/_static/fonts/2f7c3c315334a99574ee4ceb21af654d.woff2 b/_static/fonts/2f7c3c315334a99574ee4ceb21af654d.woff2 new file mode 100644 index 00000000..4b7a373a Binary files /dev/null and b/_static/fonts/2f7c3c315334a99574ee4ceb21af654d.woff2 differ diff --git a/_static/fonts/302b0425bf5ea66f37a822a61d723adc.ttf b/_static/fonts/302b0425bf5ea66f37a822a61d723adc.ttf new file mode 100644 index 00000000..d25425d8 Binary files /dev/null and b/_static/fonts/302b0425bf5ea66f37a822a61d723adc.ttf differ diff --git a/_static/fonts/3177dacffeac1eb4102852811ae4a2c7.woff2 b/_static/fonts/3177dacffeac1eb4102852811ae4a2c7.woff2 new file mode 100644 index 00000000..c5776a5e Binary files /dev/null and b/_static/fonts/3177dacffeac1eb4102852811ae4a2c7.woff2 differ diff --git a/_static/fonts/3254c528e2ab56454a9f22191035c5fe.ttf b/_static/fonts/3254c528e2ab56454a9f22191035c5fe.ttf new file mode 100644 index 00000000..9c48d222 Binary files /dev/null and b/_static/fonts/3254c528e2ab56454a9f22191035c5fe.ttf differ diff --git a/_static/fonts/32c8a74ac0816253d69a7cc68a60986d.woff2 b/_static/fonts/32c8a74ac0816253d69a7cc68a60986d.woff2 new file mode 100644 index 00000000..53d081f3 Binary files /dev/null and b/_static/fonts/32c8a74ac0816253d69a7cc68a60986d.woff2 differ diff --git a/_static/fonts/33c5d27ca0eaeb12ebe728ae2fc7106d.woff2 b/_static/fonts/33c5d27ca0eaeb12ebe728ae2fc7106d.woff2 new file mode 100644 index 00000000..45eae25c Binary files /dev/null and b/_static/fonts/33c5d27ca0eaeb12ebe728ae2fc7106d.woff2 differ diff --git a/_static/fonts/36e39c6463ae1c71c71e69c05e593e1b.woff2 b/_static/fonts/36e39c6463ae1c71c71e69c05e593e1b.woff2 new file mode 100644 index 00000000..f3c5f6ac Binary files /dev/null and b/_static/fonts/36e39c6463ae1c71c71e69c05e593e1b.woff2 differ diff --git a/_static/fonts/3728fbdd191d75bad5b83a838dfe2fc1.woff2 b/_static/fonts/3728fbdd191d75bad5b83a838dfe2fc1.woff2 new file mode 100644 index 00000000..cb5834ff Binary files /dev/null and b/_static/fonts/3728fbdd191d75bad5b83a838dfe2fc1.woff2 differ diff --git a/_static/fonts/38f3ee1f96b758f95672c632d8759594.ttf b/_static/fonts/38f3ee1f96b758f95672c632d8759594.ttf new file mode 100644 index 00000000..7c38f724 Binary files /dev/null and b/_static/fonts/38f3ee1f96b758f95672c632d8759594.ttf differ diff --git a/_static/fonts/392ff374142585f7b886ee1fe66e686e.woff2 b/_static/fonts/392ff374142585f7b886ee1fe66e686e.woff2 new file mode 100644 index 00000000..b1dc168f Binary files /dev/null and b/_static/fonts/392ff374142585f7b886ee1fe66e686e.woff2 differ diff --git a/_static/fonts/3a38c967413f7bce36d3baefc321aade.woff2 b/_static/fonts/3a38c967413f7bce36d3baefc321aade.woff2 new file mode 100644 index 00000000..53b8d0dc Binary files /dev/null and b/_static/fonts/3a38c967413f7bce36d3baefc321aade.woff2 differ diff --git a/_static/fonts/3c23eb02de6b34e30f18cfb7167abd81.woff2 b/_static/fonts/3c23eb02de6b34e30f18cfb7167abd81.woff2 new file mode 100644 index 00000000..8a8de615 Binary files /dev/null and b/_static/fonts/3c23eb02de6b34e30f18cfb7167abd81.woff2 differ diff --git a/_static/fonts/3c505383d37d2078648e37868bbd1fad.woff2 b/_static/fonts/3c505383d37d2078648e37868bbd1fad.woff2 new file mode 100644 index 00000000..63995528 Binary files /dev/null and b/_static/fonts/3c505383d37d2078648e37868bbd1fad.woff2 differ diff --git a/_static/fonts/3cf78ad3bcd1324e10a4acdc34bfc4a1.woff2 b/_static/fonts/3cf78ad3bcd1324e10a4acdc34bfc4a1.woff2 new file mode 100644 index 00000000..59cab0f1 Binary files /dev/null and b/_static/fonts/3cf78ad3bcd1324e10a4acdc34bfc4a1.woff2 differ diff --git a/_static/fonts/3f1918538864f9681d47a4538d48289c.woff2 b/_static/fonts/3f1918538864f9681d47a4538d48289c.woff2 new file mode 100644 index 00000000..99b1da1b Binary files /dev/null and b/_static/fonts/3f1918538864f9681d47a4538d48289c.woff2 differ diff --git a/_static/fonts/4039566f251699c4b421ed1a38a59b24.woff2 b/_static/fonts/4039566f251699c4b421ed1a38a59b24.woff2 new file mode 100644 index 00000000..45f222cc Binary files /dev/null and b/_static/fonts/4039566f251699c4b421ed1a38a59b24.woff2 differ diff --git a/_static/fonts/4207cbc8cb7bc2cbd0bcce565298cbbc.woff2 b/_static/fonts/4207cbc8cb7bc2cbd0bcce565298cbbc.woff2 new file mode 100644 index 00000000..8ab91719 Binary files /dev/null and b/_static/fonts/4207cbc8cb7bc2cbd0bcce565298cbbc.woff2 differ diff --git a/_static/fonts/43358c04243de546caddd0898dbf0757.woff2 b/_static/fonts/43358c04243de546caddd0898dbf0757.woff2 new file mode 100644 index 00000000..1f384187 Binary files /dev/null and b/_static/fonts/43358c04243de546caddd0898dbf0757.woff2 differ diff --git a/_static/fonts/435e4b7f9f250d9d9243d4754799fc96.woff2 b/_static/fonts/435e4b7f9f250d9d9243d4754799fc96.woff2 new file mode 100644 index 00000000..0f6e60b8 Binary files /dev/null and b/_static/fonts/435e4b7f9f250d9d9243d4754799fc96.woff2 differ diff --git a/_static/fonts/437939342255944b82a49f916404c5fc.woff2 b/_static/fonts/437939342255944b82a49f916404c5fc.woff2 new file mode 100644 index 00000000..0bb27069 Binary files /dev/null and b/_static/fonts/437939342255944b82a49f916404c5fc.woff2 differ diff --git a/_static/fonts/455c2c1af0a2bf20047a1864d7d7c174.woff2 b/_static/fonts/455c2c1af0a2bf20047a1864d7d7c174.woff2 new file mode 100644 index 00000000..b289f002 Binary files /dev/null and b/_static/fonts/455c2c1af0a2bf20047a1864d7d7c174.woff2 differ diff --git a/_static/fonts/47aa3bfad6cb9e2d63abdd58f4e6ce4f.woff2 b/_static/fonts/47aa3bfad6cb9e2d63abdd58f4e6ce4f.woff2 new file mode 100644 index 00000000..9d7fb7f8 Binary files /dev/null and b/_static/fonts/47aa3bfad6cb9e2d63abdd58f4e6ce4f.woff2 differ diff --git a/_static/fonts/495d38d4b9741e8aa4204002414069e2.woff2 b/_static/fonts/495d38d4b9741e8aa4204002414069e2.woff2 new file mode 100644 index 00000000..47da3629 Binary files /dev/null and b/_static/fonts/495d38d4b9741e8aa4204002414069e2.woff2 differ diff --git a/_static/fonts/4c815fdc869f885520f7c8eae6730edf.woff2 b/_static/fonts/4c815fdc869f885520f7c8eae6730edf.woff2 new file mode 100644 index 00000000..997a45c6 Binary files /dev/null and b/_static/fonts/4c815fdc869f885520f7c8eae6730edf.woff2 differ diff --git a/_static/fonts/4ec57f2a80b91090971b83970230ca09.woff2 b/_static/fonts/4ec57f2a80b91090971b83970230ca09.woff2 new file mode 100644 index 00000000..3c450111 Binary files /dev/null and b/_static/fonts/4ec57f2a80b91090971b83970230ca09.woff2 differ diff --git a/_static/fonts/4f17f22fc6bff4f3333ccf7ed7126e6d.woff2 b/_static/fonts/4f17f22fc6bff4f3333ccf7ed7126e6d.woff2 new file mode 100644 index 00000000..fb22fec2 Binary files /dev/null and b/_static/fonts/4f17f22fc6bff4f3333ccf7ed7126e6d.woff2 differ diff --git a/_static/fonts/4f93c2808e3b69e525c118074e5de31f.woff2 b/_static/fonts/4f93c2808e3b69e525c118074e5de31f.woff2 new file mode 100644 index 00000000..de10a3cf Binary files /dev/null and b/_static/fonts/4f93c2808e3b69e525c118074e5de31f.woff2 differ diff --git a/_static/fonts/50aacf068f685be0dd903a91d5bab7d8.woff2 b/_static/fonts/50aacf068f685be0dd903a91d5bab7d8.woff2 new file mode 100644 index 00000000..2e71425c Binary files /dev/null and b/_static/fonts/50aacf068f685be0dd903a91d5bab7d8.woff2 differ diff --git a/_static/fonts/51f3f41805329fb8341beb56ded833ea.woff2 b/_static/fonts/51f3f41805329fb8341beb56ded833ea.woff2 new file mode 100644 index 00000000..c0099878 Binary files /dev/null and b/_static/fonts/51f3f41805329fb8341beb56ded833ea.woff2 differ diff --git a/_static/fonts/52f28cb4d065b4adfa78df4f9559c639.woff2 b/_static/fonts/52f28cb4d065b4adfa78df4f9559c639.woff2 new file mode 100644 index 00000000..a0f44185 Binary files /dev/null and b/_static/fonts/52f28cb4d065b4adfa78df4f9559c639.woff2 differ diff --git a/_static/fonts/555ceea3a65ffbbecf8b7e6d04966c7f.woff2 b/_static/fonts/555ceea3a65ffbbecf8b7e6d04966c7f.woff2 new file mode 100644 index 00000000..3df1d8a0 Binary files /dev/null and b/_static/fonts/555ceea3a65ffbbecf8b7e6d04966c7f.woff2 differ diff --git a/_static/fonts/5989ef3a21d7f252337ab3326f78bde7.woff2 b/_static/fonts/5989ef3a21d7f252337ab3326f78bde7.woff2 new file mode 100644 index 00000000..100e81a6 Binary files /dev/null and b/_static/fonts/5989ef3a21d7f252337ab3326f78bde7.woff2 differ diff --git a/_static/fonts/5b6377da4c959db6d4b22738a27f1bee.woff2 b/_static/fonts/5b6377da4c959db6d4b22738a27f1bee.woff2 new file mode 100644 index 00000000..a0d68e2b Binary files /dev/null and b/_static/fonts/5b6377da4c959db6d4b22738a27f1bee.woff2 differ diff --git a/_static/fonts/5ce47d5195e59af38114d0b70217baf2.woff2 b/_static/fonts/5ce47d5195e59af38114d0b70217baf2.woff2 new file mode 100644 index 00000000..f496f9e2 Binary files /dev/null and b/_static/fonts/5ce47d5195e59af38114d0b70217baf2.woff2 differ diff --git a/_static/fonts/5d7ff31ac7bf945e8d61878f8a941239.woff2 b/_static/fonts/5d7ff31ac7bf945e8d61878f8a941239.woff2 new file mode 100644 index 00000000..dd5a4a2e Binary files /dev/null and b/_static/fonts/5d7ff31ac7bf945e8d61878f8a941239.woff2 differ diff --git a/_static/fonts/5dc0e4b14e903ba7f45c581df7402b3f.woff2 b/_static/fonts/5dc0e4b14e903ba7f45c581df7402b3f.woff2 new file mode 100644 index 00000000..c2862d73 Binary files /dev/null and b/_static/fonts/5dc0e4b14e903ba7f45c581df7402b3f.woff2 differ diff --git a/_static/fonts/60eb682678bbea5e8ad71f66f2f65536.woff2 b/_static/fonts/60eb682678bbea5e8ad71f66f2f65536.woff2 new file mode 100644 index 00000000..6a258ac6 Binary files /dev/null and b/_static/fonts/60eb682678bbea5e8ad71f66f2f65536.woff2 differ diff --git a/_static/fonts/63111d307c01b52ffccf7b0319cb7917.woff2 b/_static/fonts/63111d307c01b52ffccf7b0319cb7917.woff2 new file mode 100644 index 00000000..fecc1855 Binary files /dev/null and b/_static/fonts/63111d307c01b52ffccf7b0319cb7917.woff2 differ diff --git a/_static/fonts/638764dc2513deb09c55fc025f6dd36c.woff2 b/_static/fonts/638764dc2513deb09c55fc025f6dd36c.woff2 new file mode 100644 index 00000000..122ac2c7 Binary files /dev/null and b/_static/fonts/638764dc2513deb09c55fc025f6dd36c.woff2 differ diff --git a/_static/fonts/63f4b74ebf127dbeb033126ea988f54e.woff2 b/_static/fonts/63f4b74ebf127dbeb033126ea988f54e.woff2 new file mode 100644 index 00000000..00a4a4be Binary files /dev/null and b/_static/fonts/63f4b74ebf127dbeb033126ea988f54e.woff2 differ diff --git a/_static/fonts/64a6b4e954cf84685cbf8de77eb47344.woff2 b/_static/fonts/64a6b4e954cf84685cbf8de77eb47344.woff2 new file mode 100644 index 00000000..edfc6cd0 Binary files /dev/null and b/_static/fonts/64a6b4e954cf84685cbf8de77eb47344.woff2 differ diff --git a/_static/fonts/661d4b208656c006e7aab58acf778485.woff2 b/_static/fonts/661d4b208656c006e7aab58acf778485.woff2 new file mode 100644 index 00000000..ae1933f3 Binary files /dev/null and b/_static/fonts/661d4b208656c006e7aab58acf778485.woff2 differ diff --git a/_static/fonts/6725a7e91680edd1cdc9ed5c26ac05fd.woff2 b/_static/fonts/6725a7e91680edd1cdc9ed5c26ac05fd.woff2 new file mode 100644 index 00000000..ece005fc Binary files /dev/null and b/_static/fonts/6725a7e91680edd1cdc9ed5c26ac05fd.woff2 differ diff --git a/_static/fonts/6a84eeee6a25e7c9a8a03191007a6720.woff2 b/_static/fonts/6a84eeee6a25e7c9a8a03191007a6720.woff2 new file mode 100644 index 00000000..1bb7737c Binary files /dev/null and b/_static/fonts/6a84eeee6a25e7c9a8a03191007a6720.woff2 differ diff --git a/_static/fonts/6ac1ee292434fac2313c42b0dfb7897c.ttf b/_static/fonts/6ac1ee292434fac2313c42b0dfb7897c.ttf new file mode 100644 index 00000000..3e69acbe Binary files /dev/null and b/_static/fonts/6ac1ee292434fac2313c42b0dfb7897c.ttf differ diff --git a/_static/fonts/6ad3f6bbe6220cc476a0d3c731d3fb04.ttf b/_static/fonts/6ad3f6bbe6220cc476a0d3c731d3fb04.ttf new file mode 100644 index 00000000..563f4493 Binary files /dev/null and b/_static/fonts/6ad3f6bbe6220cc476a0d3c731d3fb04.ttf differ diff --git a/_static/fonts/6be97ca17228a69c406231d89c003194.woff2 b/_static/fonts/6be97ca17228a69c406231d89c003194.woff2 new file mode 100644 index 00000000..a56a6ede Binary files /dev/null and b/_static/fonts/6be97ca17228a69c406231d89c003194.woff2 differ diff --git a/_static/fonts/6de03a64aa8100032abc6e836b3ed803.ttf b/_static/fonts/6de03a64aa8100032abc6e836b3ed803.ttf new file mode 100644 index 00000000..604934aa Binary files /dev/null and b/_static/fonts/6de03a64aa8100032abc6e836b3ed803.ttf differ diff --git a/_static/fonts/6deb20301c65a96db17c433ad0cf8158.woff2 b/_static/fonts/6deb20301c65a96db17c433ad0cf8158.woff2 new file mode 100644 index 00000000..cbe564b0 Binary files /dev/null and b/_static/fonts/6deb20301c65a96db17c433ad0cf8158.woff2 differ diff --git a/_static/fonts/6f8d857c5a8545e67de6b60aa0fe5c33.woff2 b/_static/fonts/6f8d857c5a8545e67de6b60aa0fe5c33.woff2 new file mode 100644 index 00000000..92fe38dd Binary files /dev/null and b/_static/fonts/6f8d857c5a8545e67de6b60aa0fe5c33.woff2 differ diff --git a/_static/fonts/713780d8b30bda5583052ea847cdcb4f.woff2 b/_static/fonts/713780d8b30bda5583052ea847cdcb4f.woff2 new file mode 100644 index 00000000..0933dfe8 Binary files /dev/null and b/_static/fonts/713780d8b30bda5583052ea847cdcb4f.woff2 differ diff --git a/_static/fonts/71e06579279fba7436d58a1c49288909.ttf b/_static/fonts/71e06579279fba7436d58a1c49288909.ttf new file mode 100644 index 00000000..454e5d05 Binary files /dev/null and b/_static/fonts/71e06579279fba7436d58a1c49288909.ttf differ diff --git a/_static/fonts/765bd4a97597a4d7781193793477a6cd.ttf b/_static/fonts/765bd4a97597a4d7781193793477a6cd.ttf new file mode 100644 index 00000000..10f8720c Binary files /dev/null and b/_static/fonts/765bd4a97597a4d7781193793477a6cd.ttf differ diff --git a/_static/fonts/76945c7494c20515bb45d1dedab8f706.woff2 b/_static/fonts/76945c7494c20515bb45d1dedab8f706.woff2 new file mode 100644 index 00000000..943c5a0a Binary files /dev/null and b/_static/fonts/76945c7494c20515bb45d1dedab8f706.woff2 differ diff --git a/_static/fonts/76da333ab59c6d625cabfb0768f82b4a.woff2 b/_static/fonts/76da333ab59c6d625cabfb0768f82b4a.woff2 new file mode 100644 index 00000000..9eda94a2 Binary files /dev/null and b/_static/fonts/76da333ab59c6d625cabfb0768f82b4a.woff2 differ diff --git a/_static/fonts/770518db51bed1e082feecc532cfcbf8.woff2 b/_static/fonts/770518db51bed1e082feecc532cfcbf8.woff2 new file mode 100644 index 00000000..c0f0f73b Binary files /dev/null and b/_static/fonts/770518db51bed1e082feecc532cfcbf8.woff2 differ diff --git a/_static/fonts/77b24796a3d4ab521f66765651875338.woff2 b/_static/fonts/77b24796a3d4ab521f66765651875338.woff2 new file mode 100644 index 00000000..6284d2e3 Binary files /dev/null and b/_static/fonts/77b24796a3d4ab521f66765651875338.woff2 differ diff --git a/_static/fonts/77ff81100e5a1db3d925f713660700ad.woff2 b/_static/fonts/77ff81100e5a1db3d925f713660700ad.woff2 new file mode 100644 index 00000000..dd0851d5 Binary files /dev/null and b/_static/fonts/77ff81100e5a1db3d925f713660700ad.woff2 differ diff --git a/_static/fonts/78a9265759e7b861a1639a36f4c01d04.woff2 b/_static/fonts/78a9265759e7b861a1639a36f4c01d04.woff2 new file mode 100644 index 00000000..be81ddf5 Binary files /dev/null and b/_static/fonts/78a9265759e7b861a1639a36f4c01d04.woff2 differ diff --git a/_static/fonts/7af61b2367eba2b1852e837c46a75696.woff2 b/_static/fonts/7af61b2367eba2b1852e837c46a75696.woff2 new file mode 100644 index 00000000..e0d41239 Binary files /dev/null and b/_static/fonts/7af61b2367eba2b1852e837c46a75696.woff2 differ diff --git a/_static/fonts/7b63598dcc2a26583b82594bd0e36d5b.woff2 b/_static/fonts/7b63598dcc2a26583b82594bd0e36d5b.woff2 new file mode 100644 index 00000000..ff1f96d3 Binary files /dev/null and b/_static/fonts/7b63598dcc2a26583b82594bd0e36d5b.woff2 differ diff --git a/_static/fonts/7b8c2179b6b778308d2ff39bdb82e926.woff2 b/_static/fonts/7b8c2179b6b778308d2ff39bdb82e926.woff2 new file mode 100644 index 00000000..66efc250 Binary files /dev/null and b/_static/fonts/7b8c2179b6b778308d2ff39bdb82e926.woff2 differ diff --git a/_static/fonts/7e262106f82cc52663e403f5b73795bb.woff2 b/_static/fonts/7e262106f82cc52663e403f5b73795bb.woff2 new file mode 100644 index 00000000..067cb322 Binary files /dev/null and b/_static/fonts/7e262106f82cc52663e403f5b73795bb.woff2 differ diff --git a/_static/fonts/7f1c829b0c90fd664a03bb714a74f7d3.woff2 b/_static/fonts/7f1c829b0c90fd664a03bb714a74f7d3.woff2 new file mode 100644 index 00000000..68f094cd Binary files /dev/null and b/_static/fonts/7f1c829b0c90fd664a03bb714a74f7d3.woff2 differ diff --git a/_static/fonts/7fa86b886bee5d6ab420a8e89b9f3052.ttf b/_static/fonts/7fa86b886bee5d6ab420a8e89b9f3052.ttf new file mode 100644 index 00000000..13a7f42e Binary files /dev/null and b/_static/fonts/7fa86b886bee5d6ab420a8e89b9f3052.ttf differ diff --git a/_static/fonts/8007dfe835cfb201b8caaa9651098588.woff2 b/_static/fonts/8007dfe835cfb201b8caaa9651098588.woff2 new file mode 100644 index 00000000..11c7018c Binary files /dev/null and b/_static/fonts/8007dfe835cfb201b8caaa9651098588.woff2 differ diff --git a/_static/fonts/83614c36460a4a9734968789cb535de7.woff2 b/_static/fonts/83614c36460a4a9734968789cb535de7.woff2 new file mode 100644 index 00000000..e836b518 Binary files /dev/null and b/_static/fonts/83614c36460a4a9734968789cb535de7.woff2 differ diff --git a/_static/fonts/84e959dd07f302392f0ffd86f87db888.ttf b/_static/fonts/84e959dd07f302392f0ffd86f87db888.ttf new file mode 100644 index 00000000..99c5795f Binary files /dev/null and b/_static/fonts/84e959dd07f302392f0ffd86f87db888.ttf differ diff --git a/_static/fonts/85a41b80c5fdc14e3dc48636a30d87dd.woff2 b/_static/fonts/85a41b80c5fdc14e3dc48636a30d87dd.woff2 new file mode 100644 index 00000000..8a81a2ff Binary files /dev/null and b/_static/fonts/85a41b80c5fdc14e3dc48636a30d87dd.woff2 differ diff --git a/_static/fonts/870e5928dd14fcfe0ce9386107666774.woff2 b/_static/fonts/870e5928dd14fcfe0ce9386107666774.woff2 new file mode 100644 index 00000000..ef9a2bdd Binary files /dev/null and b/_static/fonts/870e5928dd14fcfe0ce9386107666774.woff2 differ diff --git a/_static/fonts/8898c4b754d5d96c1a5e1b1d54100554.woff2 b/_static/fonts/8898c4b754d5d96c1a5e1b1d54100554.woff2 new file mode 100644 index 00000000..6b05020c Binary files /dev/null and b/_static/fonts/8898c4b754d5d96c1a5e1b1d54100554.woff2 differ diff --git a/_static/fonts/89b4f174a5a728d2d8c85b87990c9ab4.ttf b/_static/fonts/89b4f174a5a728d2d8c85b87990c9ab4.ttf new file mode 100644 index 00000000..57a6dc38 Binary files /dev/null and b/_static/fonts/89b4f174a5a728d2d8c85b87990c9ab4.ttf differ diff --git a/_static/fonts/8a8dca39f24b52e89e6fd6dcd8b6dd32.woff2 b/_static/fonts/8a8dca39f24b52e89e6fd6dcd8b6dd32.woff2 new file mode 100644 index 00000000..9756ba7c Binary files /dev/null and b/_static/fonts/8a8dca39f24b52e89e6fd6dcd8b6dd32.woff2 differ diff --git a/_static/fonts/8aa562790559d61dd5178a88a296d70f.ttf b/_static/fonts/8aa562790559d61dd5178a88a296d70f.ttf new file mode 100644 index 00000000..68ff2a47 Binary files /dev/null and b/_static/fonts/8aa562790559d61dd5178a88a296d70f.ttf differ diff --git a/_static/fonts/8c3798e37724f71bc0c63c44a5307413.woff2 b/_static/fonts/8c3798e37724f71bc0c63c44a5307413.woff2 new file mode 100644 index 00000000..72fc0214 Binary files /dev/null and b/_static/fonts/8c3798e37724f71bc0c63c44a5307413.woff2 differ diff --git a/_static/fonts/8c49ed8b472d38d3985ec9bbbccea601.ttf b/_static/fonts/8c49ed8b472d38d3985ec9bbbccea601.ttf new file mode 100644 index 00000000..9c039d63 Binary files /dev/null and b/_static/fonts/8c49ed8b472d38d3985ec9bbbccea601.ttf differ diff --git a/_static/fonts/8e48cf20cf9f9e5feb7197c79028132b.woff2 b/_static/fonts/8e48cf20cf9f9e5feb7197c79028132b.woff2 new file mode 100644 index 00000000..f8d7a0d4 Binary files /dev/null and b/_static/fonts/8e48cf20cf9f9e5feb7197c79028132b.woff2 differ diff --git a/_static/fonts/9095d663e4d450059bcc2260bb75cd62.woff2 b/_static/fonts/9095d663e4d450059bcc2260bb75cd62.woff2 new file mode 100644 index 00000000..472bf5a5 Binary files /dev/null and b/_static/fonts/9095d663e4d450059bcc2260bb75cd62.woff2 differ diff --git a/_static/fonts/90ebb29b5cffa197b184773983ba7e91.woff2 b/_static/fonts/90ebb29b5cffa197b184773983ba7e91.woff2 new file mode 100644 index 00000000..5fd10290 Binary files /dev/null and b/_static/fonts/90ebb29b5cffa197b184773983ba7e91.woff2 differ diff --git a/_static/fonts/93b6c99d936df38895a0d95e3ffea2fd.woff2 b/_static/fonts/93b6c99d936df38895a0d95e3ffea2fd.woff2 new file mode 100644 index 00000000..cb00b8b5 Binary files /dev/null and b/_static/fonts/93b6c99d936df38895a0d95e3ffea2fd.woff2 differ diff --git a/_static/fonts/9582ced8a675bf267cc7ac392a86413e.woff2 b/_static/fonts/9582ced8a675bf267cc7ac392a86413e.woff2 new file mode 100644 index 00000000..ef920e5a Binary files /dev/null and b/_static/fonts/9582ced8a675bf267cc7ac392a86413e.woff2 differ diff --git a/_static/fonts/99be4d68845d66c27c7f7d3a48687b66.woff2 b/_static/fonts/99be4d68845d66c27c7f7d3a48687b66.woff2 new file mode 100644 index 00000000..3f7f93ab Binary files /dev/null and b/_static/fonts/99be4d68845d66c27c7f7d3a48687b66.woff2 differ diff --git a/_static/fonts/99cf36e763be9cce7b4c59b91841af58.woff2 b/_static/fonts/99cf36e763be9cce7b4c59b91841af58.woff2 new file mode 100644 index 00000000..663ec4c2 Binary files /dev/null and b/_static/fonts/99cf36e763be9cce7b4c59b91841af58.woff2 differ diff --git a/_static/fonts/9a9bf2d91ebbb1b96eab8eb0b0514bcc.woff2 b/_static/fonts/9a9bf2d91ebbb1b96eab8eb0b0514bcc.woff2 new file mode 100644 index 00000000..d0c5aa5e Binary files /dev/null and b/_static/fonts/9a9bf2d91ebbb1b96eab8eb0b0514bcc.woff2 differ diff --git a/_static/fonts/9bcbc88b33b2efc2aee821b831499f1c.woff2 b/_static/fonts/9bcbc88b33b2efc2aee821b831499f1c.woff2 new file mode 100644 index 00000000..3f060b34 Binary files /dev/null and b/_static/fonts/9bcbc88b33b2efc2aee821b831499f1c.woff2 differ diff --git a/_static/fonts/9c9be791a58af8a04c611ca1d13f51c6.woff2 b/_static/fonts/9c9be791a58af8a04c611ca1d13f51c6.woff2 new file mode 100644 index 00000000..2f2cacd3 Binary files /dev/null and b/_static/fonts/9c9be791a58af8a04c611ca1d13f51c6.woff2 differ diff --git a/_static/fonts/9fdb12ceee3a402d3a54afe354552459.woff2 b/_static/fonts/9fdb12ceee3a402d3a54afe354552459.woff2 new file mode 100644 index 00000000..1d173f2a Binary files /dev/null and b/_static/fonts/9fdb12ceee3a402d3a54afe354552459.woff2 differ diff --git a/_static/fonts/a6933e678530b263486fa7b185a449ca.woff2 b/_static/fonts/a6933e678530b263486fa7b185a449ca.woff2 new file mode 100644 index 00000000..dd587a2b Binary files /dev/null and b/_static/fonts/a6933e678530b263486fa7b185a449ca.woff2 differ diff --git a/_static/fonts/a6caf7b9888eb0c382948c1ca5e8bebb.woff2 b/_static/fonts/a6caf7b9888eb0c382948c1ca5e8bebb.woff2 new file mode 100644 index 00000000..9213da01 Binary files /dev/null and b/_static/fonts/a6caf7b9888eb0c382948c1ca5e8bebb.woff2 differ diff --git a/_static/fonts/a70ff2592da5e3453943f727633aff54.woff2 b/_static/fonts/a70ff2592da5e3453943f727633aff54.woff2 new file mode 100644 index 00000000..c932cd45 Binary files /dev/null and b/_static/fonts/a70ff2592da5e3453943f727633aff54.woff2 differ diff --git a/_static/fonts/aa28d99c7db60ad23f96a5c317615c42.woff2 b/_static/fonts/aa28d99c7db60ad23f96a5c317615c42.woff2 new file mode 100644 index 00000000..cce41ce7 Binary files /dev/null and b/_static/fonts/aa28d99c7db60ad23f96a5c317615c42.woff2 differ diff --git a/_static/fonts/aab05142e0e2dadf7df633e061e612ad.woff2 b/_static/fonts/aab05142e0e2dadf7df633e061e612ad.woff2 new file mode 100644 index 00000000..c8ab3b2d Binary files /dev/null and b/_static/fonts/aab05142e0e2dadf7df633e061e612ad.woff2 differ diff --git a/_static/fonts/ab03beb9091fa15ce4e783199e076bc6.woff2 b/_static/fonts/ab03beb9091fa15ce4e783199e076bc6.woff2 new file mode 100644 index 00000000..477887e3 Binary files /dev/null and b/_static/fonts/ab03beb9091fa15ce4e783199e076bc6.woff2 differ diff --git a/_static/fonts/ac848474638236e67a64bc654fb18de0.ttf b/_static/fonts/ac848474638236e67a64bc654fb18de0.ttf new file mode 100644 index 00000000..aa6a46dd Binary files /dev/null and b/_static/fonts/ac848474638236e67a64bc654fb18de0.ttf differ diff --git a/_static/fonts/acaac043ca238f0e56e61864456777fa.woff2 b/_static/fonts/acaac043ca238f0e56e61864456777fa.woff2 new file mode 100644 index 00000000..c88b8aea Binary files /dev/null and b/_static/fonts/acaac043ca238f0e56e61864456777fa.woff2 differ diff --git a/_static/fonts/aeed0e51b0bac7c89e5c7e6cf086d7e0.woff2 b/_static/fonts/aeed0e51b0bac7c89e5c7e6cf086d7e0.woff2 new file mode 100644 index 00000000..8571683e Binary files /dev/null and b/_static/fonts/aeed0e51b0bac7c89e5c7e6cf086d7e0.woff2 differ diff --git a/_static/fonts/b019538234514166ec7665359d097403.woff2 b/_static/fonts/b019538234514166ec7665359d097403.woff2 new file mode 100644 index 00000000..29342a8d Binary files /dev/null and b/_static/fonts/b019538234514166ec7665359d097403.woff2 differ diff --git a/_static/fonts/b076e86301cbee8c5c9aef51863a9c0a.woff2 b/_static/fonts/b076e86301cbee8c5c9aef51863a9c0a.woff2 new file mode 100644 index 00000000..91231c9c Binary files /dev/null and b/_static/fonts/b076e86301cbee8c5c9aef51863a9c0a.woff2 differ diff --git a/_static/fonts/b19ac4e57f2a56639eebd1c35319e5a7.woff2 b/_static/fonts/b19ac4e57f2a56639eebd1c35319e5a7.woff2 new file mode 100644 index 00000000..4ccadd18 Binary files /dev/null and b/_static/fonts/b19ac4e57f2a56639eebd1c35319e5a7.woff2 differ diff --git a/_static/fonts/b4d3c40a77fd9e35a881a79077957055.woff2 b/_static/fonts/b4d3c40a77fd9e35a881a79077957055.woff2 new file mode 100644 index 00000000..38d4c74d Binary files /dev/null and b/_static/fonts/b4d3c40a77fd9e35a881a79077957055.woff2 differ diff --git a/_static/fonts/b4e42731e8d667ae87c3450c345754ae.woff2 b/_static/fonts/b4e42731e8d667ae87c3450c345754ae.woff2 new file mode 100644 index 00000000..ee64c936 Binary files /dev/null and b/_static/fonts/b4e42731e8d667ae87c3450c345754ae.woff2 differ diff --git a/_static/fonts/b57a5ada789f195d5d42f4073a6cf313.woff2 b/_static/fonts/b57a5ada789f195d5d42f4073a6cf313.woff2 new file mode 100644 index 00000000..18c3f128 Binary files /dev/null and b/_static/fonts/b57a5ada789f195d5d42f4073a6cf313.woff2 differ diff --git a/_static/fonts/b5b4146d87e5d22d0a4e0d04f3ee5626.woff2 b/_static/fonts/b5b4146d87e5d22d0a4e0d04f3ee5626.woff2 new file mode 100644 index 00000000..a4699c78 Binary files /dev/null and b/_static/fonts/b5b4146d87e5d22d0a4e0d04f3ee5626.woff2 differ diff --git a/_static/fonts/b7ef2cd1159a8cbfd271ff2abe07f237.woff2 b/_static/fonts/b7ef2cd1159a8cbfd271ff2abe07f237.woff2 new file mode 100644 index 00000000..22ddee9c Binary files /dev/null and b/_static/fonts/b7ef2cd1159a8cbfd271ff2abe07f237.woff2 differ diff --git a/_static/fonts/b93199bb6f964f190f4da04ecdbaf5a4.woff2 b/_static/fonts/b93199bb6f964f190f4da04ecdbaf5a4.woff2 new file mode 100644 index 00000000..fa67bec9 Binary files /dev/null and b/_static/fonts/b93199bb6f964f190f4da04ecdbaf5a4.woff2 differ diff --git a/_static/fonts/bb8007225d94a099cddbade7ea904667.woff2 b/_static/fonts/bb8007225d94a099cddbade7ea904667.woff2 new file mode 100644 index 00000000..22c57b01 Binary files /dev/null and b/_static/fonts/bb8007225d94a099cddbade7ea904667.woff2 differ diff --git a/_static/fonts/bc67bba106323289ea3eda0826de1912.ttf b/_static/fonts/bc67bba106323289ea3eda0826de1912.ttf new file mode 100644 index 00000000..ce5a5252 Binary files /dev/null and b/_static/fonts/bc67bba106323289ea3eda0826de1912.ttf differ diff --git a/_static/fonts/bcd47c2f3649cfcaa86a08fb741255d6.woff2 b/_static/fonts/bcd47c2f3649cfcaa86a08fb741255d6.woff2 new file mode 100644 index 00000000..20eb7ec2 Binary files /dev/null and b/_static/fonts/bcd47c2f3649cfcaa86a08fb741255d6.woff2 differ diff --git a/_static/fonts/bd0efe13f0d9d591b337ddc7f289f494.woff2 b/_static/fonts/bd0efe13f0d9d591b337ddc7f289f494.woff2 new file mode 100644 index 00000000..2900346b Binary files /dev/null and b/_static/fonts/bd0efe13f0d9d591b337ddc7f289f494.woff2 differ diff --git a/_static/fonts/bd51fb0ca67e64c809ffcf7e1370f969.woff2 b/_static/fonts/bd51fb0ca67e64c809ffcf7e1370f969.woff2 new file mode 100644 index 00000000..0f11176a Binary files /dev/null and b/_static/fonts/bd51fb0ca67e64c809ffcf7e1370f969.woff2 differ diff --git a/_static/fonts/bdbb6b52604c2451fdcba9cdfd44f4e1.woff2 b/_static/fonts/bdbb6b52604c2451fdcba9cdfd44f4e1.woff2 new file mode 100644 index 00000000..6363b1c7 Binary files /dev/null and b/_static/fonts/bdbb6b52604c2451fdcba9cdfd44f4e1.woff2 differ diff --git a/_static/fonts/bf2ad3287f13eb7076cccb516ec2986f.ttf b/_static/fonts/bf2ad3287f13eb7076cccb516ec2986f.ttf new file mode 100644 index 00000000..99e1e894 Binary files /dev/null and b/_static/fonts/bf2ad3287f13eb7076cccb516ec2986f.ttf differ diff --git a/_static/fonts/bfd1a0c9c783e84595589f33e1828a57.woff2 b/_static/fonts/bfd1a0c9c783e84595589f33e1828a57.woff2 new file mode 100644 index 00000000..27773c96 Binary files /dev/null and b/_static/fonts/bfd1a0c9c783e84595589f33e1828a57.woff2 differ diff --git a/_static/fonts/c13b34dd5b6a35b309944b61c91b2ace.woff2 b/_static/fonts/c13b34dd5b6a35b309944b61c91b2ace.woff2 new file mode 100644 index 00000000..b2ffb560 Binary files /dev/null and b/_static/fonts/c13b34dd5b6a35b309944b61c91b2ace.woff2 differ diff --git a/_static/fonts/c22066c14662d6c80415ae04c5dd9d51.woff2 b/_static/fonts/c22066c14662d6c80415ae04c5dd9d51.woff2 new file mode 100644 index 00000000..7148fac7 Binary files /dev/null and b/_static/fonts/c22066c14662d6c80415ae04c5dd9d51.woff2 differ diff --git a/_static/fonts/c28a41f656599f6694528b5463c6a445.woff2 b/_static/fonts/c28a41f656599f6694528b5463c6a445.woff2 new file mode 100644 index 00000000..fcadc912 Binary files /dev/null and b/_static/fonts/c28a41f656599f6694528b5463c6a445.woff2 differ diff --git a/_static/fonts/c6dc61b627bbc5af9130518297bd4f17.ttf b/_static/fonts/c6dc61b627bbc5af9130518297bd4f17.ttf new file mode 100644 index 00000000..7a8b630b Binary files /dev/null and b/_static/fonts/c6dc61b627bbc5af9130518297bd4f17.ttf differ diff --git a/_static/fonts/c8a9fd4eab4e83382cc66fde70911b41.woff2 b/_static/fonts/c8a9fd4eab4e83382cc66fde70911b41.woff2 new file mode 100644 index 00000000..d2f30b58 Binary files /dev/null and b/_static/fonts/c8a9fd4eab4e83382cc66fde70911b41.woff2 differ diff --git a/_static/fonts/ca7eea0cf248d6e8442c01074765bd33.woff2 b/_static/fonts/ca7eea0cf248d6e8442c01074765bd33.woff2 new file mode 100644 index 00000000..24a1bfd3 Binary files /dev/null and b/_static/fonts/ca7eea0cf248d6e8442c01074765bd33.woff2 differ diff --git a/_static/fonts/cadfb311297a9362b07fab73934b432a.ttf b/_static/fonts/cadfb311297a9362b07fab73934b432a.ttf new file mode 100644 index 00000000..4242da4d Binary files /dev/null and b/_static/fonts/cadfb311297a9362b07fab73934b432a.ttf differ diff --git a/_static/fonts/cbfd26d5bcf084ee407a0b2b7599e84b.woff2 b/_static/fonts/cbfd26d5bcf084ee407a0b2b7599e84b.woff2 new file mode 100644 index 00000000..65687e73 Binary files /dev/null and b/_static/fonts/cbfd26d5bcf084ee407a0b2b7599e84b.woff2 differ diff --git a/_static/fonts/ccdebed88064e470c15f37c432922e57.woff2 b/_static/fonts/ccdebed88064e470c15f37c432922e57.woff2 new file mode 100644 index 00000000..6abf54d0 Binary files /dev/null and b/_static/fonts/ccdebed88064e470c15f37c432922e57.woff2 differ diff --git a/_static/fonts/cce2217cc8323fe49789adefb3596291.woff2 b/_static/fonts/cce2217cc8323fe49789adefb3596291.woff2 new file mode 100644 index 00000000..b8dff97b Binary files /dev/null and b/_static/fonts/cce2217cc8323fe49789adefb3596291.woff2 differ diff --git a/_static/fonts/cd3d1f17e048e2116f438bd7157baccf.woff2 b/_static/fonts/cd3d1f17e048e2116f438bd7157baccf.woff2 new file mode 100644 index 00000000..93cd525d Binary files /dev/null and b/_static/fonts/cd3d1f17e048e2116f438bd7157baccf.woff2 differ diff --git a/_static/fonts/d07f561ba87d93460742b060727d9e0d.woff2 b/_static/fonts/d07f561ba87d93460742b060727d9e0d.woff2 new file mode 100644 index 00000000..bfa05a0f Binary files /dev/null and b/_static/fonts/d07f561ba87d93460742b060727d9e0d.woff2 differ diff --git a/_static/fonts/d368cf5bed7856dbafa2af36b51acb9c.woff2 b/_static/fonts/d368cf5bed7856dbafa2af36b51acb9c.woff2 new file mode 100644 index 00000000..72ce0e98 Binary files /dev/null and b/_static/fonts/d368cf5bed7856dbafa2af36b51acb9c.woff2 differ diff --git a/_static/fonts/d422317033deb87342a5e56c7be67458.ttf b/_static/fonts/d422317033deb87342a5e56c7be67458.ttf new file mode 100644 index 00000000..6a9fc931 Binary files /dev/null and b/_static/fonts/d422317033deb87342a5e56c7be67458.ttf differ diff --git a/_static/fonts/d6f9cdf1a40893111566fcdee3bbe5a9.woff2 b/_static/fonts/d6f9cdf1a40893111566fcdee3bbe5a9.woff2 new file mode 100644 index 00000000..b9cee29d Binary files /dev/null and b/_static/fonts/d6f9cdf1a40893111566fcdee3bbe5a9.woff2 differ diff --git a/_static/fonts/d98f35e926c11f3d5c0c8e3205d43907.ttf b/_static/fonts/d98f35e926c11f3d5c0c8e3205d43907.ttf new file mode 100644 index 00000000..11a1e9fe Binary files /dev/null and b/_static/fonts/d98f35e926c11f3d5c0c8e3205d43907.ttf differ diff --git a/_static/fonts/d9e6a498dac7e9e91f6e0b4f8930eba0.woff2 b/_static/fonts/d9e6a498dac7e9e91f6e0b4f8930eba0.woff2 new file mode 100644 index 00000000..0b792b0b Binary files /dev/null and b/_static/fonts/d9e6a498dac7e9e91f6e0b4f8930eba0.woff2 differ diff --git a/_static/fonts/da6cd48e6dad1888fccc91735e7522f7.woff2 b/_static/fonts/da6cd48e6dad1888fccc91735e7522f7.woff2 new file mode 100644 index 00000000..fe8fcec7 Binary files /dev/null and b/_static/fonts/da6cd48e6dad1888fccc91735e7522f7.woff2 differ diff --git a/_static/fonts/daf12b5f1889502004bba85ad71f9fa4.woff2 b/_static/fonts/daf12b5f1889502004bba85ad71f9fa4.woff2 new file mode 100644 index 00000000..3d0f604e Binary files /dev/null and b/_static/fonts/daf12b5f1889502004bba85ad71f9fa4.woff2 differ diff --git a/_static/fonts/daf51ab540602b2d0b87646621637bac.woff2 b/_static/fonts/daf51ab540602b2d0b87646621637bac.woff2 new file mode 100644 index 00000000..fc71d944 Binary files /dev/null and b/_static/fonts/daf51ab540602b2d0b87646621637bac.woff2 differ diff --git a/_static/fonts/db0424fb67fb52e7e538490240cc7fb9.woff2 b/_static/fonts/db0424fb67fb52e7e538490240cc7fb9.woff2 new file mode 100644 index 00000000..e1b7a79f Binary files /dev/null and b/_static/fonts/db0424fb67fb52e7e538490240cc7fb9.woff2 differ diff --git a/_static/fonts/dc25cbf4baaf778bd8ae78fbc0e79479.woff2 b/_static/fonts/dc25cbf4baaf778bd8ae78fbc0e79479.woff2 new file mode 100644 index 00000000..75d29cff Binary files /dev/null and b/_static/fonts/dc25cbf4baaf778bd8ae78fbc0e79479.woff2 differ diff --git a/_static/fonts/dd719f1662079ce6a61260f9af972379.woff2 b/_static/fonts/dd719f1662079ce6a61260f9af972379.woff2 new file mode 100644 index 00000000..44819272 Binary files /dev/null and b/_static/fonts/dd719f1662079ce6a61260f9af972379.woff2 differ diff --git a/_static/fonts/de018865c95896bb57265fc97c48ebd7.woff2 b/_static/fonts/de018865c95896bb57265fc97c48ebd7.woff2 new file mode 100644 index 00000000..a181dfe7 Binary files /dev/null and b/_static/fonts/de018865c95896bb57265fc97c48ebd7.woff2 differ diff --git a/_static/fonts/e33716333704ab19fdf9989e072ad49a.woff2 b/_static/fonts/e33716333704ab19fdf9989e072ad49a.woff2 new file mode 100644 index 00000000..b2391b92 Binary files /dev/null and b/_static/fonts/e33716333704ab19fdf9989e072ad49a.woff2 differ diff --git a/_static/fonts/e56cc9fb5272752b78f144b4be43175d.woff2 b/_static/fonts/e56cc9fb5272752b78f144b4be43175d.woff2 new file mode 100644 index 00000000..9997e98d Binary files /dev/null and b/_static/fonts/e56cc9fb5272752b78f144b4be43175d.woff2 differ diff --git a/_static/fonts/e704ef18719c08839bc99a32437ef0f8.woff2 b/_static/fonts/e704ef18719c08839bc99a32437ef0f8.woff2 new file mode 100644 index 00000000..bfcc76fa Binary files /dev/null and b/_static/fonts/e704ef18719c08839bc99a32437ef0f8.woff2 differ diff --git a/_static/fonts/e99627cd27de169d23ece4573006af2a.woff2 b/_static/fonts/e99627cd27de169d23ece4573006af2a.woff2 new file mode 100644 index 00000000..677de8b5 Binary files /dev/null and b/_static/fonts/e99627cd27de169d23ece4573006af2a.woff2 differ diff --git a/_static/fonts/ef8f0236a7e8b46bc9d642ecf4ab0cb7.woff2 b/_static/fonts/ef8f0236a7e8b46bc9d642ecf4ab0cb7.woff2 new file mode 100644 index 00000000..064e94b7 Binary files /dev/null and b/_static/fonts/ef8f0236a7e8b46bc9d642ecf4ab0cb7.woff2 differ diff --git a/_static/fonts/f154d62b4879af7a22895af7a4ef03f0.woff2 b/_static/fonts/f154d62b4879af7a22895af7a4ef03f0.woff2 new file mode 100644 index 00000000..074504d6 Binary files /dev/null and b/_static/fonts/f154d62b4879af7a22895af7a4ef03f0.woff2 differ diff --git a/_static/fonts/f17ee050ada0453f3bd07bc466c2dde2.woff2 b/_static/fonts/f17ee050ada0453f3bd07bc466c2dde2.woff2 new file mode 100644 index 00000000..0bfb07d7 Binary files /dev/null and b/_static/fonts/f17ee050ada0453f3bd07bc466c2dde2.woff2 differ diff --git a/_static/fonts/f265cee675c0e5b2d6ab263d0edcc754.woff2 b/_static/fonts/f265cee675c0e5b2d6ab263d0edcc754.woff2 new file mode 100644 index 00000000..f041fde3 Binary files /dev/null and b/_static/fonts/f265cee675c0e5b2d6ab263d0edcc754.woff2 differ diff --git a/_static/fonts/f2f69e8cd15fdd15a4244c95ec8a8514.woff2 b/_static/fonts/f2f69e8cd15fdd15a4244c95ec8a8514.woff2 new file mode 100644 index 00000000..5b19d60d Binary files /dev/null and b/_static/fonts/f2f69e8cd15fdd15a4244c95ec8a8514.woff2 differ diff --git a/_static/fonts/f534242dea2255c25b9d05c2371986e3.woff2 b/_static/fonts/f534242dea2255c25b9d05c2371986e3.woff2 new file mode 100644 index 00000000..23fcdf30 Binary files /dev/null and b/_static/fonts/f534242dea2255c25b9d05c2371986e3.woff2 differ diff --git a/_static/fonts/f53f3b5a15d717b6d21d7885285e90ed.woff2 b/_static/fonts/f53f3b5a15d717b6d21d7885285e90ed.woff2 new file mode 100644 index 00000000..2bfc2cee Binary files /dev/null and b/_static/fonts/f53f3b5a15d717b6d21d7885285e90ed.woff2 differ diff --git a/_static/fonts/f55dac651a40fce74a5cf5728d9f8ffc.woff2 b/_static/fonts/f55dac651a40fce74a5cf5728d9f8ffc.woff2 new file mode 100644 index 00000000..481279c0 Binary files /dev/null and b/_static/fonts/f55dac651a40fce74a5cf5728d9f8ffc.woff2 differ diff --git a/_static/fonts/f5aebdfea35d1e7656ef4acc5db1f243.woff2 b/_static/fonts/f5aebdfea35d1e7656ef4acc5db1f243.woff2 new file mode 100644 index 00000000..771fbecc Binary files /dev/null and b/_static/fonts/f5aebdfea35d1e7656ef4acc5db1f243.woff2 differ diff --git a/_static/fonts/f5f971e9640a9eb86ef553a7e7e999c7.woff2 b/_static/fonts/f5f971e9640a9eb86ef553a7e7e999c7.woff2 new file mode 100644 index 00000000..d87fe266 Binary files /dev/null and b/_static/fonts/f5f971e9640a9eb86ef553a7e7e999c7.woff2 differ diff --git a/_static/fonts/f6734f8177112c0839b961f96d813fcb.woff2 b/_static/fonts/f6734f8177112c0839b961f96d813fcb.woff2 new file mode 100644 index 00000000..020729ef Binary files /dev/null and b/_static/fonts/f6734f8177112c0839b961f96d813fcb.woff2 differ diff --git a/_static/fonts/f75911313e1c7802c23345ab57e754d8.woff2 b/_static/fonts/f75911313e1c7802c23345ab57e754d8.woff2 new file mode 100644 index 00000000..60681387 Binary files /dev/null and b/_static/fonts/f75911313e1c7802c23345ab57e754d8.woff2 differ diff --git a/_static/fonts/fb17f56622e45dd4ecee00bb5c63cd2b.woff2 b/_static/fonts/fb17f56622e45dd4ecee00bb5c63cd2b.woff2 new file mode 100644 index 00000000..4487ab7b Binary files /dev/null and b/_static/fonts/fb17f56622e45dd4ecee00bb5c63cd2b.woff2 differ diff --git a/_static/fonts/fb1aaa90783b8cb9375265abeb91b153.woff2 b/_static/fonts/fb1aaa90783b8cb9375265abeb91b153.woff2 new file mode 100644 index 00000000..1351aad4 Binary files /dev/null and b/_static/fonts/fb1aaa90783b8cb9375265abeb91b153.woff2 differ diff --git a/_static/fonts/fc66f942651a9fe1a598770d3d896529.woff2 b/_static/fonts/fc66f942651a9fe1a598770d3d896529.woff2 new file mode 100644 index 00000000..94ab5fb0 Binary files /dev/null and b/_static/fonts/fc66f942651a9fe1a598770d3d896529.woff2 differ diff --git a/_static/language_data.js b/_static/language_data.js new file mode 100644 index 00000000..367b8ed8 --- /dev/null +++ b/_static/language_data.js @@ -0,0 +1,199 @@ +/* + * language_data.js + * ~~~~~~~~~~~~~~~~ + * + * This script contains the language-specific data used by searchtools.js, + * namely the list of stopwords, stemmer, scorer and splitter. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +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/sphinx_immaterial_theme.1b5b7a2d5891aec19.min.js b/_static/sphinx_immaterial_theme.1b5b7a2d5891aec19.min.js new file mode 100644 index 00000000..ec77f5d0 --- /dev/null +++ b/_static/sphinx_immaterial_theme.1b5b7a2d5891aec19.min.js @@ -0,0 +1,27 @@ +"use strict";(()=>{var aa=Object.create;var wr=Object.defineProperty;var sa=Object.getOwnPropertyDescriptor;var ca=Object.getOwnPropertyNames,Rt=Object.getOwnPropertySymbols,fa=Object.getPrototypeOf,Er=Object.prototype.hasOwnProperty,dn=Object.prototype.propertyIsEnumerable;var mn=(e,t,r)=>t in e?wr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,V=(e,t)=>{for(var r in t||(t={}))Er.call(t,r)&&mn(e,r,t[r]);if(Rt)for(var r of Rt(t))dn.call(t,r)&&mn(e,r,t[r]);return e};var hn=(e,t)=>{var r={};for(var n in e)Er.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(e!=null&&Rt)for(var n of Rt(e))t.indexOf(n)<0&&dn.call(e,n)&&(r[n]=e[n]);return r};var vt=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var la=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of ca(t))!Er.call(e,o)&&o!==r&&wr(e,o,{get:()=>t[o],enumerable:!(n=sa(t,o))||n.enumerable});return e};var Je=(e,t,r)=>(r=e!=null?aa(fa(e)):{},la(t||!e||!e.__esModule?wr(r,"default",{value:e,enumerable:!0}):r,e));var ze=(e,t,r)=>new Promise((n,o)=>{var i=s=>{try{c(r.next(s))}catch(f){o(f)}},a=s=>{try{c(r.throw(s))}catch(f){o(f)}},c=s=>s.done?n(s.value):Promise.resolve(s.value).then(i,a);c((r=r.apply(e,t)).next())});var vn=vt((Sr,bn)=>{(function(e,t){typeof Sr=="object"&&typeof bn!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(Sr,function(){"use strict";function e(r){var n=!0,o=!1,i=null,a={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function c(y){return!!(y&&y!==document&&y.nodeName!=="HTML"&&y.nodeName!=="BODY"&&"classList"in y&&"contains"in y.classList)}function s(y){var Te=y.type,Le=y.tagName;return!!(Le==="INPUT"&&a[Te]&&!y.readOnly||Le==="TEXTAREA"&&!y.readOnly||y.isContentEditable)}function f(y){y.classList.contains("focus-visible")||(y.classList.add("focus-visible"),y.setAttribute("data-focus-visible-added",""))}function u(y){!y.hasAttribute("data-focus-visible-added")||(y.classList.remove("focus-visible"),y.removeAttribute("data-focus-visible-added"))}function l(y){y.metaKey||y.altKey||y.ctrlKey||(c(r.activeElement)&&f(r.activeElement),n=!0)}function p(y){n=!1}function m(y){!c(y.target)||(n||s(y.target))&&f(y.target)}function h(y){!c(y.target)||(y.target.classList.contains("focus-visible")||y.target.hasAttribute("data-focus-visible-added"))&&(o=!0,window.clearTimeout(i),i=window.setTimeout(function(){o=!1},100),u(y.target))}function b(y){document.visibilityState==="hidden"&&(o&&(n=!0),w())}function w(){document.addEventListener("mousemove",$),document.addEventListener("mousedown",$),document.addEventListener("mouseup",$),document.addEventListener("pointermove",$),document.addEventListener("pointerdown",$),document.addEventListener("pointerup",$),document.addEventListener("touchmove",$),document.addEventListener("touchstart",$),document.addEventListener("touchend",$)}function q(){document.removeEventListener("mousemove",$),document.removeEventListener("mousedown",$),document.removeEventListener("mouseup",$),document.removeEventListener("pointermove",$),document.removeEventListener("pointerdown",$),document.removeEventListener("pointerup",$),document.removeEventListener("touchmove",$),document.removeEventListener("touchstart",$),document.removeEventListener("touchend",$)}function $(y){y.target.nodeName&&y.target.nodeName.toLowerCase()==="html"||(n=!1,q())}document.addEventListener("keydown",l,!0),document.addEventListener("mousedown",p,!0),document.addEventListener("pointerdown",p,!0),document.addEventListener("touchstart",p,!0),document.addEventListener("visibilitychange",b,!0),w(),r.addEventListener("focus",m,!0),r.addEventListener("blur",h,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var gn=vt(Or=>{(function(e){var t=function(){try{return!!Symbol.iterator}catch(f){return!1}},r=t(),n=function(f){var u={next:function(){var l=f.shift();return{done:l===void 0,value:l}}};return r&&(u[Symbol.iterator]=function(){return u}),u},o=function(f){return encodeURIComponent(f).replace(/%20/g,"+")},i=function(f){return decodeURIComponent(String(f).replace(/\+/g," "))},a=function(){var f=function(l){Object.defineProperty(this,"_entries",{writable:!0,value:{}});var p=typeof l;if(p!=="undefined")if(p==="string")l!==""&&this._fromString(l);else if(l instanceof f){var m=this;l.forEach(function(q,$){m.append($,q)})}else if(l!==null&&p==="object")if(Object.prototype.toString.call(l)==="[object Array]")for(var h=0;hm[0]?1:0}),f._entries&&(f._entries={});for(var l=0;l1?i(m[1]):"")}})})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Or);(function(e){var t=function(){try{var o=new e.URL("b","http://a");return o.pathname="c d",o.href==="http://a/c%20d"&&o.searchParams}catch(i){return!1}},r=function(){var o=e.URL,i=function(s,f){typeof s!="string"&&(s=String(s)),f&&typeof f!="string"&&(f=String(f));var u=document,l;if(f&&(e.location===void 0||f!==e.location.href)){f=f.toLowerCase(),u=document.implementation.createHTMLDocument(""),l=u.createElement("base"),l.href=f,u.head.appendChild(l);try{if(l.href.indexOf(f)!==0)throw new Error(l.href)}catch(y){throw new Error("URL unable to set base "+f+" due to "+y)}}var p=u.createElement("a");p.href=s,l&&(u.body.appendChild(p),p.href=p.href);var m=u.createElement("input");if(m.type="url",m.value=s,p.protocol===":"||!/:/.test(p.href)||!m.checkValidity()&&!f)throw new TypeError("Invalid URL");Object.defineProperty(this,"_anchorElement",{value:p});var h=new e.URLSearchParams(this.search),b=!0,w=!0,q=this;["append","delete","set"].forEach(function(y){var Te=h[y];h[y]=function(){Te.apply(h,arguments),b&&(w=!1,q.search=h.toString(),w=!0)}}),Object.defineProperty(this,"searchParams",{value:h,enumerable:!0});var $=void 0;Object.defineProperty(this,"_updateSearchParams",{enumerable:!1,configurable:!1,writable:!1,value:function(){this.search!==$&&($=this.search,w&&(b=!1,this.searchParams._fromString(this.search),b=!0))}})},a=i.prototype,c=function(s){Object.defineProperty(a,s,{get:function(){return this._anchorElement[s]},set:function(f){this._anchorElement[s]=f},enumerable:!0})};["hash","host","hostname","port","protocol"].forEach(function(s){c(s)}),Object.defineProperty(a,"search",{get:function(){return this._anchorElement.search},set:function(s){this._anchorElement.search=s,this._updateSearchParams()},enumerable:!0}),Object.defineProperties(a,{toString:{get:function(){var s=this;return function(){return s.href}}},href:{get:function(){return this._anchorElement.href.replace(/\?$/,"")},set:function(s){this._anchorElement.href=s,this._updateSearchParams()},enumerable:!0},pathname:{get:function(){return this._anchorElement.pathname.replace(/(^\/?)/,"/")},set:function(s){this._anchorElement.pathname=s},enumerable:!0},origin:{get:function(){var s={"http:":80,"https:":443,"ftp:":21}[this._anchorElement.protocol],f=this._anchorElement.port!=s&&this._anchorElement.port!=="";return this._anchorElement.protocol+"//"+this._anchorElement.hostname+(f?":"+this._anchorElement.port:"")},enumerable:!0},password:{get:function(){return""},set:function(s){},enumerable:!0},username:{get:function(){return""},set:function(s){},enumerable:!0}}),i.createObjectURL=function(s){return o.createObjectURL.apply(o,arguments)},i.revokeObjectURL=function(s){return o.revokeObjectURL.apply(o,arguments)},e.URL=i};if(t()||r(),e.location!==void 0&&!("origin"in e.location)){var n=function(){return e.location.protocol+"//"+e.location.hostname+(e.location.port?":"+e.location.port:"")};try{Object.defineProperty(e.location,"origin",{get:n,enumerable:!0})}catch(o){setInterval(function(){e.location.origin=n()},100)}}})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Or)});var Un=vt((tc,Pt)=>{/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */var yn,xn,wn,En,Sn,On,_n,Tn,Ln,Ht,_r,Mn,An,Cn,it,Rn,Hn,kn,Pn,$n,In,jn,Fn,kt;(function(e){var t=typeof global=="object"?global:typeof self=="object"?self:typeof this=="object"?this:{};typeof define=="function"&&define.amd?define("tslib",["exports"],function(n){e(r(t,r(n)))}):typeof Pt=="object"&&typeof Pt.exports=="object"?e(r(t,r(Pt.exports))):e(r(t));function r(n,o){return n!==t&&(typeof Object.create=="function"?Object.defineProperty(n,"__esModule",{value:!0}):n.__esModule=!0),function(i,a){return n[i]=o?o(i,a):a}}})(function(e){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(n,o){n.__proto__=o}||function(n,o){for(var i in o)Object.prototype.hasOwnProperty.call(o,i)&&(n[i]=o[i])};yn=function(n,o){if(typeof o!="function"&&o!==null)throw new TypeError("Class extends value "+String(o)+" is not a constructor or null");t(n,o);function i(){this.constructor=n}n.prototype=o===null?Object.create(o):(i.prototype=o.prototype,new i)},xn=Object.assign||function(n){for(var o,i=1,a=arguments.length;i=0;u--)(f=n[u])&&(s=(c<3?f(s):c>3?f(o,i,s):f(o,i))||s);return c>3&&s&&Object.defineProperty(o,i,s),s},Sn=function(n,o){return function(i,a){o(i,a,n)}},On=function(n,o){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(n,o)},_n=function(n,o,i,a){function c(s){return s instanceof i?s:new i(function(f){f(s)})}return new(i||(i=Promise))(function(s,f){function u(m){try{p(a.next(m))}catch(h){f(h)}}function l(m){try{p(a.throw(m))}catch(h){f(h)}}function p(m){m.done?s(m.value):c(m.value).then(u,l)}p((a=a.apply(n,o||[])).next())})},Tn=function(n,o){var i={label:0,sent:function(){if(s[0]&1)throw s[1];return s[1]},trys:[],ops:[]},a,c,s,f;return f={next:u(0),throw:u(1),return:u(2)},typeof Symbol=="function"&&(f[Symbol.iterator]=function(){return this}),f;function u(p){return function(m){return l([p,m])}}function l(p){if(a)throw new TypeError("Generator is already executing.");for(;i;)try{if(a=1,c&&(s=p[0]&2?c.return:p[0]?c.throw||((s=c.return)&&s.call(c),0):c.next)&&!(s=s.call(c,p[1])).done)return s;switch(c=0,s&&(p=[p[0]&2,s.value]),p[0]){case 0:case 1:s=p;break;case 4:return i.label++,{value:p[1],done:!1};case 5:i.label++,c=p[1],p=[0];continue;case 7:p=i.ops.pop(),i.trys.pop();continue;default:if(s=i.trys,!(s=s.length>0&&s[s.length-1])&&(p[0]===6||p[0]===2)){i=0;continue}if(p[0]===3&&(!s||p[1]>s[0]&&p[1]=n.length&&(n=void 0),{value:n&&n[a++],done:!n}}};throw new TypeError(o?"Object is not iterable.":"Symbol.iterator is not defined.")},_r=function(n,o){var i=typeof Symbol=="function"&&n[Symbol.iterator];if(!i)return n;var a=i.call(n),c,s=[],f;try{for(;(o===void 0||o-- >0)&&!(c=a.next()).done;)s.push(c.value)}catch(u){f={error:u}}finally{try{c&&!c.done&&(i=a.return)&&i.call(a)}finally{if(f)throw f.error}}return s},Mn=function(){for(var n=[],o=0;o1||u(b,w)})})}function u(b,w){try{l(a[b](w))}catch(q){h(s[0][3],q)}}function l(b){b.value instanceof it?Promise.resolve(b.value.v).then(p,m):h(s[0][2],b)}function p(b){u("next",b)}function m(b){u("throw",b)}function h(b,w){b(w),s.shift(),s.length&&u(s[0][0],s[0][1])}},Hn=function(n){var o,i;return o={},a("next"),a("throw",function(c){throw c}),a("return"),o[Symbol.iterator]=function(){return this},o;function a(c,s){o[c]=n[c]?function(f){return(i=!i)?{value:it(n[c](f)),done:c==="return"}:s?s(f):f}:s}},kn=function(n){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var o=n[Symbol.asyncIterator],i;return o?o.call(n):(n=typeof Ht=="function"?Ht(n):n[Symbol.iterator](),i={},a("next"),a("throw"),a("return"),i[Symbol.asyncIterator]=function(){return this},i);function a(s){i[s]=n[s]&&function(f){return new Promise(function(u,l){f=n[s](f),c(u,l,f.done,f.value)})}}function c(s,f,u,l){Promise.resolve(l).then(function(p){s({value:p,done:u})},f)}},Pn=function(n,o){return Object.defineProperty?Object.defineProperty(n,"raw",{value:o}):n.raw=o,n};var r=Object.create?function(n,o){Object.defineProperty(n,"default",{enumerable:!0,value:o})}:function(n,o){n.default=o};$n=function(n){if(n&&n.__esModule)return n;var o={};if(n!=null)for(var i in n)i!=="default"&&Object.prototype.hasOwnProperty.call(n,i)&&kt(o,n,i);return r(o,n),o},In=function(n){return n&&n.__esModule?n:{default:n}},jn=function(n,o){if(!o.has(n))throw new TypeError("attempted to get private field on non-instance");return o.get(n)},Fn=function(n,o,i){if(!o.has(n))throw new TypeError("attempted to set private field on non-instance");return o.set(n,i),i},e("__extends",yn),e("__assign",xn),e("__rest",wn),e("__decorate",En),e("__param",Sn),e("__metadata",On),e("__awaiter",_n),e("__generator",Tn),e("__exportStar",Ln),e("__createBinding",kt),e("__values",Ht),e("__read",_r),e("__spread",Mn),e("__spreadArrays",An),e("__spreadArray",Cn),e("__await",it),e("__asyncGenerator",Rn),e("__asyncDelegator",Hn),e("__asyncValues",kn),e("__makeTemplateObject",Pn),e("__importStar",$n),e("__importDefault",In),e("__classPrivateFieldGet",jn),e("__classPrivateFieldSet",Fn)})});var Qr=vt((Lt,Jr)=>{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof Lt=="object"&&typeof Jr=="object"?Jr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Lt=="object"?Lt.ClipboardJS=r():t.ClipboardJS=r()})(Lt,function(){return function(){var e={686:function(n,o,i){"use strict";i.d(o,{default:function(){return ia}});var a=i(279),c=i.n(a),s=i(370),f=i.n(s),u=i(817),l=i.n(u);function p(F){try{return document.execCommand(F)}catch(S){return!1}}var m=function(S){var E=l()(S);return p("cut"),E},h=m;function b(F){var S=document.documentElement.getAttribute("dir")==="rtl",E=document.createElement("textarea");E.style.fontSize="12pt",E.style.border="0",E.style.padding="0",E.style.margin="0",E.style.position="absolute",E.style[S?"right":"left"]="-9999px";var H=window.pageYOffset||document.documentElement.scrollTop;return E.style.top="".concat(H,"px"),E.setAttribute("readonly",""),E.value=F,E}var w=function(S,E){var H=b(S);E.container.appendChild(H);var j=l()(H);return p("copy"),H.remove(),j},q=function(S){var E=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},H="";return typeof S=="string"?H=w(S,E):S instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(S==null?void 0:S.type)?H=w(S.value,E):(H=l()(S),p("copy")),H},$=q;function y(F){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?y=function(E){return typeof E}:y=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},y(F)}var Te=function(){var S=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},E=S.action,H=E===void 0?"copy":E,j=S.container,K=S.target,Me=S.text;if(H!=="copy"&&H!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(K!==void 0)if(K&&y(K)==="object"&&K.nodeType===1){if(H==="copy"&&K.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(H==="cut"&&(K.hasAttribute("readonly")||K.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Me)return $(Me,{container:j});if(K)return H==="cut"?h(K):$(K,{container:j})},Le=Te;function we(F){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?we=function(E){return typeof E}:we=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},we(F)}function Mt(F,S){if(!(F instanceof S))throw new TypeError("Cannot call a class as a function")}function ot(F,S){for(var E=0;E0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof j.action=="function"?j.action:this.defaultAction,this.target=typeof j.target=="function"?j.target:this.defaultTarget,this.text=typeof j.text=="function"?j.text:this.defaultText,this.container=we(j.container)==="object"?j.container:document.body}},{key:"listenClick",value:function(j){var K=this;this.listener=f()(j,"click",function(Me){return K.onClick(Me)})}},{key:"onClick",value:function(j){var K=j.delegateTarget||j.currentTarget,Me=this.action(K)||"copy",Ct=Le({action:Me,container:this.container,target:this.target(K),text:this.text(K)});this.emit(Ct?"success":"error",{action:Me,text:Ct,trigger:K,clearSelection:function(){K&&K.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(j){return xr("action",j)}},{key:"defaultTarget",value:function(j){var K=xr("target",j);if(K)return document.querySelector(K)}},{key:"defaultText",value:function(j){return xr("text",j)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(j){var K=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return $(j,K)}},{key:"cut",value:function(j){return h(j)}},{key:"isSupported",value:function(){var j=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],K=typeof j=="string"?[j]:j,Me=!!document.queryCommandSupported;return K.forEach(function(Ct){Me=Me&&!!document.queryCommandSupported(Ct)}),Me}}]),E}(c()),ia=oa},828:function(n){var o=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function a(c,s){for(;c&&c.nodeType!==o;){if(typeof c.matches=="function"&&c.matches(s))return c;c=c.parentNode}}n.exports=a},438:function(n,o,i){var a=i(828);function c(u,l,p,m,h){var b=f.apply(this,arguments);return u.addEventListener(p,b,h),{destroy:function(){u.removeEventListener(p,b,h)}}}function s(u,l,p,m,h){return typeof u.addEventListener=="function"?c.apply(null,arguments):typeof p=="function"?c.bind(null,document).apply(null,arguments):(typeof u=="string"&&(u=document.querySelectorAll(u)),Array.prototype.map.call(u,function(b){return c(b,l,p,m,h)}))}function f(u,l,p,m){return function(h){h.delegateTarget=a(h.target,l),h.delegateTarget&&m.call(u,h)}}n.exports=s},879:function(n,o){o.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},o.nodeList=function(i){var a=Object.prototype.toString.call(i);return i!==void 0&&(a==="[object NodeList]"||a==="[object HTMLCollection]")&&"length"in i&&(i.length===0||o.node(i[0]))},o.string=function(i){return typeof i=="string"||i instanceof String},o.fn=function(i){var a=Object.prototype.toString.call(i);return a==="[object Function]"}},370:function(n,o,i){var a=i(879),c=i(438);function s(p,m,h){if(!p&&!m&&!h)throw new Error("Missing required arguments");if(!a.string(m))throw new TypeError("Second argument must be a String");if(!a.fn(h))throw new TypeError("Third argument must be a Function");if(a.node(p))return f(p,m,h);if(a.nodeList(p))return u(p,m,h);if(a.string(p))return l(p,m,h);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function f(p,m,h){return p.addEventListener(m,h),{destroy:function(){p.removeEventListener(m,h)}}}function u(p,m,h){return Array.prototype.forEach.call(p,function(b){b.addEventListener(m,h)}),{destroy:function(){Array.prototype.forEach.call(p,function(b){b.removeEventListener(m,h)})}}}function l(p,m,h){return c(document.body,p,m,h)}n.exports=s},817:function(n){function o(i){var a;if(i.nodeName==="SELECT")i.focus(),a=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var c=i.hasAttribute("readonly");c||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),c||i.removeAttribute("readonly"),a=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var s=window.getSelection(),f=document.createRange();f.selectNodeContents(i),s.removeAllRanges(),s.addRange(f),a=s.toString()}return a}n.exports=o},279:function(n){function o(){}o.prototype={on:function(i,a,c){var s=this.e||(this.e={});return(s[i]||(s[i]=[])).push({fn:a,ctx:c}),this},once:function(i,a,c){var s=this;function f(){s.off(i,f),a.apply(c,arguments)}return f._=a,this.on(i,f,c)},emit:function(i){var a=[].slice.call(arguments,1),c=((this.e||(this.e={}))[i]||[]).slice(),s=0,f=c.length;for(s;s{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var Ls=/["'&<>]/;Ti.exports=Ms;function Ms(e){var t=""+e,r=Ls.exec(t);if(!r)return t;var n,o="",i=0,a=0;for(i=r.index;i0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var n=this,o=this,i=o.hasError,a=o.isStopped,c=o.observers;return i||a?Tr:(this.currentObservers=null,c.push(r),new $e(function(){n.currentObservers=null,Ve(c,r)}))},t.prototype._checkFinalizedStatuses=function(r){var n=this,o=n.hasError,i=n.thrownError,a=n.isStopped;o?r.error(i):a&&r.complete()},t.prototype.asObservable=function(){var r=new U;return r.source=this,r},t.create=function(r,n){return new Xn(r,n)},t}(U);var Xn=function(e){re(t,e);function t(r,n){var o=e.call(this)||this;return o.destination=r,o.source=n,o}return t.prototype.next=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,r)},t.prototype.error=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,r)},t.prototype.complete=function(){var r,n;(n=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||n===void 0||n.call(r)},t.prototype._subscribe=function(r){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(r))!==null&&o!==void 0?o:Tr},t}(L);var yt={now:function(){return(yt.delegate||Date).now()},delegate:void 0};var xt=function(e){re(t,e);function t(r,n,o){r===void 0&&(r=1/0),n===void 0&&(n=1/0),o===void 0&&(o=yt);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=n,i._timestampProvider=o,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=n===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,n),i}return t.prototype.next=function(r){var n=this,o=n.isStopped,i=n._buffer,a=n._infiniteTimeWindow,c=n._timestampProvider,s=n._windowTime;o||(i.push(r),!a&&i.push(c.now()+s)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var n=this._innerSubscribe(r),o=this,i=o._infiniteTimeWindow,a=o._buffer,c=a.slice(),s=0;s0?e.prototype.requestAsyncId.call(this,r,n,o):(r.actions.push(this),r._scheduled||(r._scheduled=ft.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,n,o){var i;if(o===void 0&&(o=0),o!=null?o>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,n,o);var a=r.actions;n!=null&&((i=a[a.length-1])===null||i===void 0?void 0:i.id)!==n&&(ft.cancelAnimationFrame(n),r._scheduled=void 0)},t}(Dt);var to=function(e){re(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var n=this._scheduled;this._scheduled=void 0;var o=this.actions,i;r=r||o.shift();do if(i=r.execute(r.state,r.delay))break;while((r=o[0])&&r.id===n&&o.shift());if(this._active=!1,i){for(;(r=o[0])&&r.id===n&&o.shift();)r.unsubscribe();throw i}},t}(Wt);var fe=new to(eo);var k=new U(function(e){return e.complete()});function zt(e){return e&&T(e.schedule)}function kr(e){return e[e.length-1]}function qe(e){return T(kr(e))?e.pop():void 0}function Ee(e){return zt(kr(e))?e.pop():void 0}function qt(e,t){return typeof kr(e)=="number"?e.pop():t}var lt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Kt(e){return T(e==null?void 0:e.then)}function Bt(e){return T(e[ct])}function Yt(e){return Symbol.asyncIterator&&T(e==null?void 0:e[Symbol.asyncIterator])}function Gt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function ya(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Jt=ya();function Qt(e){return T(e==null?void 0:e[Jt])}function Xt(e){return Dn(this,arguments,function(){var r,n,o,i;return $t(this,function(a){switch(a.label){case 0:r=e.getReader(),a.label=1;case 1:a.trys.push([1,,9,10]),a.label=2;case 2:return[4,It(r.read())];case 3:return n=a.sent(),o=n.value,i=n.done,i?[4,It(void 0)]:[3,5];case 4:return[2,a.sent()];case 5:return[4,It(o)];case 6:return[4,a.sent()];case 7:return a.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function Zt(e){return T(e==null?void 0:e.getReader)}function N(e){if(e instanceof U)return e;if(e!=null){if(Bt(e))return xa(e);if(lt(e))return wa(e);if(Kt(e))return Ea(e);if(Yt(e))return ro(e);if(Qt(e))return Sa(e);if(Zt(e))return Oa(e)}throw Gt(e)}function xa(e){return new U(function(t){var r=e[ct]();if(T(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function wa(e){return new U(function(t){for(var r=0;r=2,!0))}function pe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new L}:t,n=e.resetOnError,o=n===void 0?!0:n,i=e.resetOnComplete,a=i===void 0?!0:i,c=e.resetOnRefCountZero,s=c===void 0?!0:c;return function(f){var u,l,p,m=0,h=!1,b=!1,w=function(){l==null||l.unsubscribe(),l=void 0},q=function(){w(),u=p=void 0,h=b=!1},$=function(){var y=u;q(),y==null||y.unsubscribe()};return g(function(y,Te){m++,!b&&!h&&w();var Le=p=p!=null?p:r();Te.add(function(){m--,m===0&&!b&&!h&&(l=Dr($,s))}),Le.subscribe(Te),!u&&m>0&&(u=new Xe({next:function(we){return Le.next(we)},error:function(we){b=!0,w(),l=Dr(q,o,we),Le.error(we)},complete:function(){h=!0,w(),l=Dr(q,a),Le.complete()}}),N(y).subscribe(u))})(f)}}function Dr(e,t){for(var r=[],n=2;ne.next(document)),e}function D(e,t=document){return Array.from(t.querySelectorAll(e))}function B(e,t=document){let r=ie(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function ie(e,t=document){return t.querySelector(e)||void 0}function Fe(){return document.activeElement instanceof HTMLElement&&document.activeElement||void 0}function nr(e){return P(x(document.body,"focusin"),x(document.body,"focusout")).pipe(He(1),d(()=>{let t=Fe();return typeof t!="undefined"?e.contains(t):!1}),z(e===Fe()),Q())}function Be(e){return{x:e.offsetLeft,y:e.offsetTop}}function Oo(e){return P(x(window,"load"),x(window,"resize")).pipe(Re(0,fe),d(()=>Be(e)),z(Be(e)))}function or(e){return{x:e.scrollLeft,y:e.scrollTop}}function _t(e){return P(x(e,"scroll"),x(window,"resize")).pipe(Re(0,fe),d(()=>or(e)),z(or(e)))}var To=function(){if(typeof Map!="undefined")return Map;function e(t,r){var n=-1;return t.some(function(o,i){return o[0]===r?(n=i,!0):!1}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(r){var n=e(this.__entries__,r),o=this.__entries__[n];return o&&o[1]},t.prototype.set=function(r,n){var o=e(this.__entries__,r);~o?this.__entries__[o][1]=n:this.__entries__.push([r,n])},t.prototype.delete=function(r){var n=this.__entries__,o=e(n,r);~o&&n.splice(o,1)},t.prototype.has=function(r){return!!~e(this.__entries__,r)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(r,n){n===void 0&&(n=null);for(var o=0,i=this.__entries__;o0},e.prototype.connect_=function(){!Br||this.connected_||(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),Ka?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){!Br||!this.connected_||(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(t){var r=t.propertyName,n=r===void 0?"":r,o=qa.some(function(i){return!!~n.indexOf(i)});o&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),Lo=function(e,t){for(var r=0,n=Object.keys(t);r0},e}(),Ao=typeof WeakMap!="undefined"?new WeakMap:new To,Co=function(){function e(t){if(!(this instanceof e))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var r=Ba.getInstance(),n=new ns(t,r,this);Ao.set(this,n)}return e}();["observe","unobserve","disconnect"].forEach(function(e){Co.prototype[e]=function(){var t;return(t=Ao.get(this))[e].apply(t,arguments)}});var os=function(){return typeof ir.ResizeObserver!="undefined"?ir.ResizeObserver:Co}(),Ro=os;var Ho=new L,is=I(()=>C(new Ro(e=>{for(let t of e)Ho.next(t)}))).pipe(_(e=>P(je,C(e)).pipe(R(()=>e.disconnect()))),X(1));function Se(e){return{width:e.offsetWidth,height:e.offsetHeight}}function de(e){return is.pipe(M(t=>t.observe(e)),_(t=>Ho.pipe(A(({target:r})=>r===e),R(()=>t.unobserve(e)),d(()=>Se(e)))),z(Se(e)))}function Tt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function ko(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}var Po=new L,as=I(()=>C(new IntersectionObserver(e=>{for(let t of e)Po.next(t)},{threshold:0}))).pipe(_(e=>P(je,C(e)).pipe(R(()=>e.disconnect()))),X(1));function cr(e){return as.pipe(M(t=>t.observe(e)),_(t=>Po.pipe(A(({target:r})=>r===e),R(()=>t.unobserve(e)),d(({isIntersecting:r})=>r))))}var fr={drawer:B("[data-md-toggle=drawer]"),search:B("[data-md-toggle=search]")};function $o(e){return fr[e].checked}function Ye(e,t){fr[e].checked!==t&&fr[e].click()}function ht(e){let t=fr[e];return x(t,"change").pipe(d(()=>t.checked),z(t.checked))}function ss(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Io(){return x(window,"keydown").pipe(A(e=>!(e.metaKey||e.ctrlKey)),d(e=>({mode:$o("search")?"search":"global",type:e.key,claim(){e.preventDefault(),e.stopPropagation()}})),A(({mode:e,type:t})=>{if(e==="global"){let r=Fe();if(typeof r!="undefined")return!ss(r,t)}return!0}),pe())}function Oe(){return new URL(location.href)}function lr(e){location.href=e.href}function jo(){return new L}function Fo(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)Fo(e,r)}function O(e,t,...r){let n=document.createElement(e);if(t)for(let o of Object.keys(t))typeof t[o]!="undefined"&&(typeof t[o]!="boolean"?n.setAttribute(o,t[o]):n.setAttribute(o,""));for(let o of r)Fo(n,o);return n}function Uo(e,t){let r=t;if(e.length>r){for(;e[r]!==" "&&--r>0;);return`${e.substring(0,r)}...`}return e}function ur(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function Vo(){return location.hash.substring(1)}function No(e){let t=O("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function cs(){return x(window,"hashchange").pipe(d(Vo),z(Vo()),A(e=>e.length>0),X(1))}function Do(){return cs().pipe(d(e=>ie(`[id="${e}"]`)),A(e=>typeof e!="undefined"))}function Yr(e){let t=matchMedia(e);return tr(r=>t.addListener(()=>r(t.matches))).pipe(z(t.matches))}function Wo(){let e=matchMedia("print");return P(x(window,"beforeprint").pipe(d(()=>!0)),x(window,"afterprint").pipe(d(()=>!1))).pipe(z(e.matches))}function Gr(e,t){return e.pipe(_(r=>r?t():k))}function pr(e,t={credentials:"same-origin"}){return be(fetch(`${e}`,t)).pipe(le(()=>k),_(r=>r.status!==200?Et(()=>new Error(r.statusText)):C(r)))}function Ge(e,t){return pr(e,t).pipe(_(r=>r.json()),X(1))}function zo(e,t){let r=new DOMParser;return pr(e,t).pipe(_(n=>n.text()),d(n=>r.parseFromString(n,"text/xml")),X(1))}function qo(e){let t=O("script",{src:e});return I(()=>(document.head.appendChild(t),P(x(t,"load"),x(t,"error").pipe(_(()=>Et(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(d(()=>{}),R(()=>document.head.removeChild(t)),ve(1))))}function Ko(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function Bo(){return P(x(window,"scroll",{passive:!0}),x(window,"resize",{passive:!0})).pipe(d(Ko),z(Ko()))}function Yo(){return{width:innerWidth,height:innerHeight}}function Go(){return x(window,"resize",{passive:!0}).pipe(d(Yo),z(Yo()))}function Jo(){return G([Bo(),Go()]).pipe(d(([e,t])=>({offset:e,size:t})),X(1))}function mr(e,{viewport$:t,header$:r}){let n=t.pipe(J("size")),o=G([n,r]).pipe(d(()=>Be(e)));return G([r,t,o]).pipe(d(([{height:i},{offset:a,size:c},{x:s,y:f}])=>({offset:{x:a.x-s,y:a.y-f+i},size:c})))}var fs=B("#__config"),bt=JSON.parse(fs.textContent);bt.base=`${new URL(bt.base,Oe())}`;function ce(){return bt}function Z(e){return bt.features.includes(e)}function ae(e,t){return typeof t!="undefined"?bt.translations[e].replace("#",t.toString()):bt.translations[e]}function _e(e,t=document){return B(`[data-md-component=${e}]`,t)}function ee(e,t=document){return D(`[data-md-component=${e}]`,t)}function ls(e){let t=B(".md-typeset > :first-child",e);return x(t,"click",{once:!0}).pipe(d(()=>B(".md-typeset",e)),d(r=>({hash:__md_hash(r.innerHTML)})))}function Qo(e){return!Z("announce.dismiss")||!e.childElementCount?k:I(()=>{let t=new L;return t.pipe(z({hash:__md_get("__announce")})).subscribe(({hash:r})=>{var n;r&&r===((n=__md_get("__announce"))!=null?n:r)&&(e.hidden=!0,__md_set("__announce",r))}),ls(e).pipe(M(r=>t.next(r)),R(()=>t.complete()),d(r=>V({ref:e},r)))})}function us(e,{target$:t}){return t.pipe(d(r=>({hidden:r!==e})))}function Xo(e,t){let r=new L;return r.subscribe(({hidden:n})=>{e.hidden=n}),us(e,t).pipe(M(n=>r.next(n)),R(()=>r.complete()),d(n=>V({ref:e},n)))}var fi=Je(Qr());function Xr(e){return O("div",{class:"md-tooltip",id:e},O("div",{class:"md-tooltip__inner md-typeset"}))}function Zo(e,t){if(t=t?`${t}_annotation_${e}`:void 0,t){let r=t?`#${t}`:void 0;return O("aside",{class:"md-annotation",tabIndex:0},Xr(t),O("a",{href:r,class:"md-annotation__index",tabIndex:-1},O("span",{"data-md-annotation-id":e})))}else return O("aside",{class:"md-annotation",tabIndex:0},Xr(t),O("span",{class:"md-annotation__index",tabIndex:-1},O("span",{"data-md-annotation-id":e})))}function ei(e){return O("button",{class:"md-clipboard md-icon",title:ae("clipboard.copy"),"data-clipboard-target":`#${e} > code`})}function Zr(e,t){let r=t&2,n=t&1,o=Object.keys(e.terms).filter(c=>!e.terms[c]).reduce((c,s)=>[...c,O("del",null,s)," "],[]).slice(0,-1),i=new URL(e.location);Z("search.highlight")&&i.searchParams.set("h",Object.entries(e.terms).filter(([,c])=>c).reduce((c,[s])=>`${c} ${s}`.trim(),""));let{tags:a}=ce();return O("a",{href:`${i}`,class:"md-search-result__link",tabIndex:-1},O("article",{class:["md-search-result__article",...r?["md-search-result__article--document"]:[]].join(" "),"data-md-score":e.score.toFixed(2)},r>0&&O("div",{class:"md-search-result__icon md-icon"}),O("h1",{class:"md-search-result__title"},e.title),n>0&&e.text.length>0&&O("p",{class:"md-search-result__teaser"},Uo(e.text,320)),e.tags&&O("div",{class:"md-typeset"},e.tags.map(c=>{let s=c.replace(/<[^>]+>/g,""),f=a?s in a?`md-tag-icon md-tag-icon--${a[s]}`:"md-tag-icon":"";return O("span",{class:`md-tag ${f}`},c)})),n>0&&o.length>0&&O("p",{class:"md-search-result__terms"},ae("search.result.term.missing"),": ",...o)))}function ti(e){let t=e[0].score,r=[...e],n=r.findIndex(f=>!f.location.includes("#")),[o]=r.splice(n===-1?0:n,1),i=r.findIndex(f=>f.scoreZr(f,1)),...c.length?[O("details",{class:"md-search-result__more"},O("summary",{tabIndex:-1},c.length>0&&c.length===1?ae("search.result.more.one"):ae("search.result.more.other",c.length)),...c.map(f=>Zr(f,1)))]:[]];return O("li",{class:"md-search-result__item"},s)}function ri(e){return O("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>O("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?ur(r):r)))}function en(e){let t=`tabbed-control tabbed-control--${e}`;return O("div",{class:t,hidden:!0},O("button",{class:"tabbed-button",tabIndex:-1}))}function ni(e){return O("div",{class:"md-typeset__scrollwrap"},O("div",{class:"md-typeset__table"},e))}function ps(e){let t=ce(),r=new URL(`${e.version}/`,new URL("../",t.base));return O("li",{class:"md-version__item"},O("a",{href:`${r}`,class:"md-version__link"},e.title))}function oi(e,t){return O("div",{class:"md-version"},O("button",{class:"md-version__current","aria-label":ae("select.version.title")},t.title),O("ul",{class:"md-version__list"},e.map(ps)))}function ms(e,t){let r=I(()=>G([Oo(e),_t(t)])).pipe(d(([{x:n,y:o},i])=>{let{width:a,height:c}=Se(e);return{x:n-i.x+a/2,y:o-i.y+c/2}}));return nr(e).pipe(_(n=>r.pipe(d(o=>({active:n,offset:o})),ve(+!n||1/0))))}function ii(e,t,{target$:r}){let[n,o]=Array.from(e.children);return I(()=>{let i=new L,a=i.pipe(ue(1));return i.subscribe({next({offset:c}){e.style.setProperty("--md-tooltip-x",`${c.x}px`),e.style.setProperty("--md-tooltip-y",`${c.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),cr(e).pipe(te(a)).subscribe(c=>{e.toggleAttribute("data-md-visible",c)}),P(i.pipe(A(({active:c})=>c)),i.pipe(He(250),A(({active:c})=>!c))).subscribe({next({active:c}){c?e.prepend(n):n.remove()},complete(){e.prepend(n)}}),i.pipe(Re(16,fe)).subscribe(({active:c})=>{n.classList.toggle("md-tooltip--active",c)}),i.pipe(Kr(125,fe),A(()=>!!e.offsetParent),d(()=>e.offsetParent.getBoundingClientRect()),d(({x:c})=>c)).subscribe({next(c){c?e.style.setProperty("--md-tooltip-0",`${-c}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}}),x(o,"click").pipe(te(a),A(c=>!(c.metaKey||c.ctrlKey))).subscribe(c=>c.preventDefault()),x(o,"mousedown").pipe(te(a),me(i)).subscribe(([c,{active:s}])=>{var f;if(c.button!==0||c.metaKey||c.ctrlKey)c.preventDefault();else if(s){c.preventDefault();let u=e.parentElement.closest(".md-annotation");u instanceof HTMLElement?u.focus():(f=Fe())==null||f.blur()}}),r.pipe(te(a),A(c=>c===n),ke(125)).subscribe(()=>e.focus()),ms(e,t).pipe(M(c=>i.next(c)),R(()=>i.complete()),d(c=>V({ref:e},c)))})}function ds(e){let t=[];for(let r of D(".c, .c1, .cm",e)){let n=[],o=document.createNodeIterator(r,NodeFilter.SHOW_TEXT);for(let i=o.nextNode();i;i=o.nextNode())n.push(i);for(let i of n){let a;for(;a=/(\(\d+\))(!)?/.exec(i.textContent);){let[,c,s]=a;if(typeof s=="undefined"){let f=i.splitText(a.index);i=f.splitText(c.length),t.push(f)}else{i.textContent=c,t.push(i);break}}}}return t}function ai(e,t){t.append(...Array.from(e.childNodes))}function si(e,t,{target$:r,print$:n}){let o=t.closest("[id]"),i=o==null?void 0:o.id,a=new Map;for(let c of ds(t)){let[,s]=c.textContent.match(/\((\d+)\)/);ie(`li:nth-child(${s})`,e)&&(a.set(s,Zo(s,i)),c.replaceWith(a.get(s)))}return a.size===0?k:I(()=>{let c=new L,s=[];for(let[f,u]of a)s.push([B(".md-typeset",u),B(`li:nth-child(${f})`,e)]);return n.pipe(te(c.pipe(ue(1)))).subscribe(f=>{e.hidden=!f;for(let[u,l]of s)f?ai(u,l):ai(l,u)}),P(...[...a].map(([,f])=>ii(f,t,{target$:r}))).pipe(R(()=>c.complete()),pe())})}var hs=0;function li(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return li(t)}}function ci(e){return de(e).pipe(d(({width:t})=>({scrollable:Tt(e).width>t})),J("scrollable"))}function ui(e,t){let{matches:r}=matchMedia("(hover)"),n=I(()=>{let o=new L;if(o.subscribe(({scrollable:a})=>{a&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")}),fi.default.isSupported()){let a=e.closest("pre");a.id=`__code_${++hs}`,a.insertBefore(ei(a.id),e)}let i=e.closest(".highlight");if(i instanceof HTMLElement){let a=li(i);if(typeof a!="undefined"&&(i.classList.contains("annotate")||Z("content.code.annotate"))){let c=si(a,e,t);return ci(e).pipe(M(s=>o.next(s)),R(()=>o.complete()),d(s=>V({ref:e},s)),tt(de(i).pipe(d(({width:s,height:f})=>s&&f),Q(),_(s=>s?c:k))))}}return ci(e).pipe(M(a=>o.next(a)),R(()=>o.complete()),d(a=>V({ref:e},a)))});return Z("content.lazy")?cr(e).pipe(A(o=>o),ve(1),_(()=>n)):n}var pi=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:transparent}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel rect,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel rect{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color)}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}defs #flowchart-circleEnd,defs #flowchart-circleStart,defs #flowchart-crossEnd,defs #flowchart-crossStart,defs #flowchart-pointEnd,defs #flowchart-pointStart{stroke:none}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs #classDiagram-compositionEnd,defs #classDiagram-compositionStart,defs #classDiagram-dependencyEnd,defs #classDiagram-dependencyStart,defs #classDiagram-extensionEnd,defs #classDiagram-extensionStart{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs #classDiagram-aggregationEnd,defs #classDiagram-aggregationStart{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}.entityBox{fill:var(--md-mermaid-label-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityLabel{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.relationshipLabelBox{fill:var(--md-mermaid-label-bg-color);fill-opacity:1;background-color:var(--md-mermaid-label-bg-color);opacity:1}.relationshipLabel{fill:var(--md-mermaid-label-fg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs #ONE_OR_MORE_END *,defs #ONE_OR_MORE_START *,defs #ONLY_ONE_END *,defs #ONLY_ONE_START *,defs #ZERO_OR_MORE_END *,defs #ZERO_OR_MORE_START *,defs #ZERO_OR_ONE_END *,defs #ZERO_OR_ONE_START *{stroke:var(--md-mermaid-edge-color)!important}.actor,defs #ZERO_OR_MORE_END circle,defs #ZERO_OR_MORE_START circle{fill:var(--md-mermaid-label-bg-color)}.actor{stroke:var(--md-mermaid-node-fg-color)}text.actor>tspan{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-default-fg-color--lighter)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-edge-color)}.loopText>tspan,.messageText,.noteText>tspan{font-family:var(--md-mermaid-font-family)!important}#arrowhead path,.loopText>tspan,.messageText,.noteText>tspan{fill:var(--md-mermaid-edge-color);stroke:none}.loopLine{stroke:var(--md-mermaid-node-fg-color)}.labelBox,.loopLine{fill:var(--md-mermaid-node-bg-color)}.labelBox{stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-node-fg-color);font-family:var(--md-mermaid-font-family)}";var tn,vs=0,gs=ce();function ys(){return typeof mermaid=="undefined"||mermaid instanceof Element?qo(`${gs.base}_static/mermaid/mermaid.min.js`):C(void 0)}function mi(e){return e.classList.remove("mermaid"),tn||(tn=ys().pipe(M(()=>mermaid.initialize({startOnLoad:!1,themeCSS:pi,sequence:{actorFontSize:"16px",messageFontSize:"16px",noteFontSize:"16px"}})),d(()=>{}),X(1))),tn.subscribe(()=>{e.classList.add("mermaid");let t=`__mermaid_${vs++}`,r=O("div",{class:"mermaid"});mermaid.mermaidAPI.render(t,e.textContent,n=>{let o=r.attachShadow({mode:"closed"});o.innerHTML=n,e.replaceWith(r)})}),tn.pipe(d(()=>({ref:e})))}function xs(e,{target$:t,print$:r}){let n=!0;return P(t.pipe(d(o=>o.closest("details:not([open])")),A(o=>e===o),d(()=>({action:"open",reveal:!0}))),r.pipe(A(o=>o||!n),M(()=>n=e.open),d(o=>({action:o?"open":"close"}))))}function di(e,t){return I(()=>{let r=new L;return r.subscribe(({action:n,reveal:o})=>{e.toggleAttribute("open",n==="open"),o&&e.scrollIntoView()}),xs(e,t).pipe(M(n=>r.next(n)),R(()=>r.complete()),d(n=>V({ref:e},n)))})}var hi=O("table");function bi(e){return e.replaceWith(hi),hi.replaceWith(ni(e)),C({ref:e})}function ws(e){let t=D(":scope > input",e),r=t.find(n=>n.checked)||t[0];return P(...t.map(n=>x(n,"change").pipe(d(()=>B(`label[for="${n.id}"]`))))).pipe(z(B(`label[for="${r.id}"]`)),d(n=>({active:n})))}function vi(e,{viewport$:t}){let r=en("prev");e.append(r);let n=en("next");e.append(n);let o=B(".tabbed-labels",e);return I(()=>{let i=new L,a=i.pipe(ue(1));return G([i,de(e)]).pipe(Re(1,fe),te(a)).subscribe({next([{active:c},s]){let f=Be(c),{width:u}=Se(c);e.style.setProperty("--md-indicator-x",`${f.x}px`),e.style.setProperty("--md-indicator-width",`${u}px`);let l=or(o);(f.xl.x+s.width)&&o.scrollTo({left:Math.max(0,f.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),G([_t(o),de(o)]).pipe(te(a)).subscribe(([c,s])=>{let f=Tt(o);r.hidden=c.x<16,n.hidden=c.x>f.width-s.width-16}),P(x(r,"click").pipe(d(()=>-1)),x(n,"click").pipe(d(()=>1))).pipe(te(a)).subscribe(c=>{let{width:s}=Se(o);o.scrollBy({left:s*c,behavior:"smooth"})}),Z("content.tabs.link")&&i.pipe(Pe(1),me(t)).subscribe(([{active:c},{offset:s}])=>{let f=c.innerText.trim();if(c.hasAttribute("data-md-switching"))c.removeAttribute("data-md-switching");else{let u=e.offsetTop-s.y;for(let p of D("[data-tabs]"))for(let m of D(":scope > input",p)){let h=B(`label[for="${m.id}"]`);if(h!==c&&h.innerText.trim()===f){h.setAttribute("data-md-switching",""),m.click();break}}window.scrollTo({top:e.offsetTop-u});let l=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([f,...l])])}}),ws(e).pipe(M(c=>i.next(c)),R(()=>i.complete()),d(c=>V({ref:e},c)))}).pipe(Ze(se))}function gi(e,{viewport$:t,target$:r,print$:n}){return P(...D("pre:not(.mermaid) > code",e).map(o=>ui(o,{target$:r,print$:n})),...D("pre.mermaid",e).map(o=>mi(o)),...D("table:not([class])",e).map(o=>bi(o)),...D("details",e).map(o=>di(o,{target$:r,print$:n})),...D("[data-tabs]",e).map(o=>vi(o,{viewport$:t})))}function Es(e,{alert$:t}){return t.pipe(_(r=>P(C(!0),C(!1).pipe(ke(2e3))).pipe(d(n=>({message:r,active:n})))))}function yi(e,t){let r=B(".md-typeset",e);return I(()=>{let n=new L;return n.subscribe(({message:o,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=o}),Es(e,t).pipe(M(o=>n.next(o)),R(()=>n.complete()),d(o=>V({ref:e},o)))})}function Ss({viewport$:e}){if(!Z("header.autohide"))return C(!1);let t=e.pipe(d(({offset:{y:o}})=>o),Ne(2,1),d(([o,i])=>[oMath.abs(i-o.y)>100),d(([,[o]])=>o),Q()),n=ht("search");return G([e,n]).pipe(d(([{offset:o},i])=>o.y>400&&!i),Q(),_(o=>o?r:C(!1)),z(!1))}function xi(e,t){return I(()=>G([de(e),Ss(t)])).pipe(d(([{height:r},n])=>({height:r,hidden:n})),Q((r,n)=>r.height===n.height&&r.hidden===n.hidden),X(1))}function wi(e,{header$:t,main$:r}){return I(()=>{let n=new L,o=n.pipe(ue(1));return n.pipe(J("active"),St(t)).subscribe(([{active:i},{hidden:a}])=>{e.classList.toggle("md-header--shadow",i&&!a),e.hidden=a}),r.subscribe(n),t.pipe(te(o),d(i=>V({ref:e},i)))})}function Os(e,{viewport$:t,header$:r}){return mr(e,{viewport$:t,header$:r}).pipe(d(({offset:{y:n}})=>{let{height:o}=Se(e);return{active:n>=o}}),J("active"))}function Ei(e,t){return I(()=>{let r=new L;r.subscribe(({active:o})=>{e.classList.toggle("md-header__title--active",o)});let n=ie("article h1, .objdesc > dt .descname");return typeof n=="undefined"?k:Os(n,t).pipe(M(o=>r.next(o)),R(()=>r.complete()),d(o=>V({ref:e},o)))})}function Si(e,{viewport$:t,header$:r}){let n=r.pipe(d(({height:i})=>i),Q()),o=n.pipe(_(()=>de(e).pipe(d(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),J("bottom"))));return G([n,o,t]).pipe(d(([i,{top:a,bottom:c},{offset:{y:s},size:{height:f}}])=>(f=Math.max(0,f-Math.max(0,a-s,i)-Math.max(0,f+s-c)),{offset:a-i,height:f,active:a-i<=s})),Q((i,a)=>i.offset===a.offset&&i.height===a.height&&i.active===a.active))}function _s(e){let t=__md_get("__palette")||{index:e.findIndex(r=>matchMedia(r.getAttribute("data-md-color-media")).matches)};return C(...e).pipe(oe(r=>x(r,"change").pipe(d(()=>r))),z(e[Math.max(0,t.index)]),d(r=>({index:e.indexOf(r),color:{scheme:r.getAttribute("data-md-color-scheme"),primary:r.getAttribute("data-md-color-primary"),accent:r.getAttribute("data-md-color-accent")}})),X(1))}function Oi(e){return I(()=>{let t=new L;t.subscribe(n=>{document.body.setAttribute("data-md-color-switching","");for(let[o,i]of Object.entries(n.color))document.body.setAttribute(`data-md-color-${o}`,i);for(let o=0;o{document.body.removeAttribute("data-md-color-switching")});let r=D("input",e);return _s(r).pipe(M(n=>t.next(n)),R(()=>t.complete()),d(n=>V({ref:e},n)))})}function Ts(e){let t=a=>a.trim(),{searchParams:r}=Oe(),n;if(r.has("q")){Ye("search",!0);let a=r.get("q");n=C(a)}else n=C();ht("search").pipe(A(a=>!a),ve(1)).subscribe(()=>{let a=new URL(location.href);a.searchParams.delete("q"),history.replaceState({},"",`${a}`)}),n.subscribe(a=>{a&&(e.value=a,e.focus())});let o=nr(e),i=P(x(e,"keyup"),x(e,"focus").pipe(ke(1)),n).pipe(d(()=>t(e.value)),z(""),Q());return G([i,o]).pipe(d(([a,c])=>({value:a,focus:c})),X(1))}function _i(e){let t=new L,r=t.pipe(ue(1));return t.pipe(J("focus")).subscribe(({focus:n})=>{n?(Ye("search",n),e.placeholder=""):e.placeholder=ae("search.placeholder")}),x(e.form,"reset").pipe(te(r)).subscribe(()=>e.focus()),Ts(e).pipe(M(n=>t.next(n)),R(()=>t.complete()),d(n=>V({ref:e},n)),pe())}var on=Je(rn());var As=ce();function nn(e){return`${As.base}${e}`}var dr;function Li(e){return new Promise((t,r)=>{let n=document.createElement("script"),o=nn(e);n.src=o,n.addEventListener("load",()=>t()),n.addEventListener("error",()=>{console.error(`Failed to load search data: ${o}`),r()}),document.body.appendChild(n)})}function Cs(){return dr!==void 0||(dr=Promise.all([Li("_static/language_data.js"),Li("searchindex.js")]).then(()=>{})),dr}var Ue={objNameMatch:11,objPartialMatch:6,objPrio:{0:15,1:5,2:-5},objPrioDefault:0,title:15,partialTitle:7,term:5,partialTerm:2},an;window.Search={setIndex:e=>{an=e}};var Rs=!1;function Hs(e,t){let{docurls:r,objects:n,objnames:o,titles:i}=an,a=[];function c(s,f,u,l,p,m,h){var q;let b=(s?`${s}.`:"")+m,w=b.toLowerCase();if(w.indexOf(e)>-1){let $=0,y=w.split(".");w===e||y[y.length-1]===e?$+=Ue.objNameMatch:y[y.length-1].indexOf(e)>-1&&($+=Ue.objPartialMatch);let Te=o[u][2],Le=i[f];if(t.length>0){let we=`${s} ${m} ${Te} ${Le} ${h!=null?h:""}`.toLowerCase(),Mt=!0;for(let ot=0;ot2){let m=sn(u);if(!o[u])for(let h in o)h.match(m)&&p.push({files:o[h],score:Ue.partialTerm});if(!i[u])for(let h in i)h.match(m)&&p.push({files:i[h],score:Ue.partialTitle})}if(p.every(m=>m.files===void 0))break;p.forEach(m=>{let h=m.files;if(h!==void 0){Array.isArray(h)||(h=[h]),l.push(...h);for(let b=0;bm.length>2).length;if(!(a[u].length!==e.length&&a[u].length!==p)){for(let m=0;mc[f][h]));s.push({docurl:r[f],title:n[f],anchor:"",objectLabel:null,synopsis:null,score:m})}}}return s}function $s(e){let t=new DOMParser().parseFromString(e,"text/html");t.querySelectorAll(".headerlink").forEach(s=>{var f;(f=s.parentNode)==null||f.removeChild(s)});let r=t.querySelector("[role=main]");if(r===null)return console.warn("Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template."),[];let n=r.querySelectorAll("h1, h2, h3, h4, h5, h6"),o,i=[],a=t.createRange(),c=(s,f)=>{var m;s!==void 0?a.setStartAfter(s):a.setStartBefore(r),f!==void 0?a.setEndBefore(f):a.setEndAfter(r);let u=a.toString().trim(),l=(m=s==null?void 0:s.textContent)==null?void 0:m.trim();if(!l&&!u)return;let p=s!==void 0?`#${s.id}`:"";i.push({title:l!=null?l:"",anchor:p,text:u})};return n.forEach(s=>{if(!s.id)return;let u=o;o=s,c(u,s)}),c(o,void 0),i}function Is(e,t){let r=$s(e),n=t.map(i=>new RegExp(sn(i),"im")),o=[];for(let i=0;ii.score!==a.score?a.score-i.score:i.sectionIndex-a.sectionIndex),o.length!==0)return o.map(i=>{let c=r[i.sectionIndex],s=Math.max(i.snippetIndex-240/2,0);return{snippet:(s>0?"\u2026":"")+c.text.substr(s,240).trim()+(s+240${(0,on.default)(e.objectLabel)}`,text:r(e.synopsis)}];let a=nn(e.docurl),c;if(window.location.protocol!=="file:")try{let l=yield(yield fetch(a)).text();c=Is(l,t)}catch(u){console.warn("Failed to retrieve search result document: ",u)}c===void 0&&(c=[{score:-1,title:"",anchor:"",snippet:"",terms:i}]);let s=[];c[0].score!==-1&&s.push({location:n,score:e.score,terms:i,title:r(o),text:""});let f;for(let u of c)f===void 0&&(f=u.score),s.push({location:n+u.anchor,score:u.score===f?e.score:0,terms:u.terms,title:r(u.title||o),text:r(u.snippet)});return s})}function Fs(e){return new DOMParser().parseFromString(e,"text/html").body.textContent||""}function Mi(e){return ze(this,null,function*(){yield Cs();let t=new Stemmer,r=[],n=[],o=[],i=[];for(let u of ks(e)){let l=u.toLowerCase();if(l.length===0||(i.push(l),stopwords.indexOf(l)!==-1))continue;let p=t.stemWord(l);p.length<3&&l.length>=3&&(p=l);let m;p[0]==="-"?(m=n,p=p.substr(1)):(m=r,o.push(l)),m.indexOf(p)===-1&&m.push(p)}let a=[];for(let u=0;u{let p=u.score,m=l.score;if(p!==m)return m-p;let h=u.title.toLowerCase(),b=l.title.toLowerCase();return h>b?1:h`${u}`,f=u=>(0,on.default)(u).replace(c,s).replace(/<\/mark>(\s+)]*>/gim,"$1");return{count:a.length,get:u=>js(a[u],o,f)}})}function Ai(e,{query$:t}){let r=B(":scope > :first-child",e),n=B(":scope > :last-child",e),o,i,a=e.parentElement,c=16,s=()=>a.scrollTop+a.clientHeight+c>a.scrollHeight,f=()=>{i!==void 0&&s()&&(i(),i=void 0)};a.addEventListener("scroll",f,{passive:!0}),window.addEventListener("resize",f,{passive:!0});let u=l=>ze(this,null,function*(){o=l;let p=4,m=p;for(let h=0;h{i=()=>w(void 0)})),m+=p),o!==l)return;let b=yield l.get(h);if(o!==l)return;n.appendChild(ti(b))}});return t.pipe(J("value"),Fr(()=>$r(250)),mt(l=>ze(this,null,function*(){if(!!l.value)return Mi(l.value)})),Ce(fe)).subscribe(l=>{if(n.innerHTML="",l){switch(l.count){case 0:r.textContent=ae("search.result.none");break;case 1:r.textContent=ae("search.result.one");break;default:r.textContent=ae("search.result.other",ur(l.count))}u(l)}else r.textContent=ae("search.result.placeholder")}),C()}function Us(e,{query$:t}){return t.pipe(d(({value:r})=>{let n=Oe();return n.hash="",n.searchParams.delete("h"),n.searchParams.set("q",r),{url:n}}))}function Ci(e,t){let r=new L;return r.subscribe(({url:n})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${n}`}),x(e,"click").subscribe(n=>n.preventDefault()),Us(e,t).pipe(M(n=>r.next(n)),R(()=>r.complete()),d(n=>V({ref:e},n)))}function Ri(e,{keyboard$:t}){let r=_e("search-query");return t.pipe(A(({mode:n})=>n==="search")).subscribe(n=>{switch(n.type){case"ArrowRight":e.innerText.length&&r.selectionStart===r.value.length&&(r.value=e.innerText);break}}),C()}function Hi(e,{keyboard$:t}){try{let r=_e("search-query",e),n=_e("search-result",e);t.pipe(A(({mode:a})=>a==="search")).subscribe(a=>{let c=Fe();switch(a.type){case"Enter":if(c===r){let s=new Map;for(let f of D(":first-child [href]",n)){let u=f.firstElementChild;s.set(f,parseFloat(u.getAttribute("data-md-score")))}if(s.size){let[[f]]=[...s].sort(([,u],[,l])=>l-u);f.click()}a.claim()}break;case"Escape":case"Tab":Ye("search",!1),r.blur();break;case"ArrowUp":case"ArrowDown":if(typeof c=="undefined")r.focus();else{let s=[r,...D(":not(details) > [href], summary, details[open] [href]",n)],f=Math.max(0,(Math.max(0,s.indexOf(c))+s.length+(a.type==="ArrowUp"?-1:1))%s.length);s[f].focus()}a.claim();break;default:r!==Fe()&&r.focus()}}),t.pipe(A(({mode:a})=>a==="global")).subscribe(a=>{switch(a.type){case"f":case"s":case"/":r.focus(),r.select(),a.claim();break}});let o=_i(r),i=Ai(n,{query$:o});return P(o,i).pipe(tt(...ee("search-share",e).map(a=>Ci(a,{query$:o})),...ee("search-suggest",e).map(a=>Ri(a,{keyboard$:t}))))}catch(r){return e.hidden=!0,je}}var cn=Je(Qr());function Vs(e){e.setAttribute("data-md-copying","");let t=e.innerText;return e.removeAttribute("data-md-copying"),t}function ki({alert$:e}){cn.default.isSupported()&&new U(t=>{new cn.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||Vs(B(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(M(t=>{t.trigger.focus()}),d(()=>ae("clipboard.copied"))).subscribe(e)}function Ns(e){if(e.length<2)return[""];let[t,r]=[...e].sort((o,i)=>o.length-i.length).map(o=>o.replace(/[^/]+$/,"")),n=0;if(t===r)n=t.length;else for(;t.charCodeAt(n)===r.charCodeAt(n);)n++;return e.map(o=>o.replace(t.slice(0,n),""))}function hr(e){let t=__md_get("__sitemap",sessionStorage,e);if(t)return C(t);{let r=ce();return zo(new URL("sitemap.xml",e||r.base)).pipe(d(n=>Ns(D("loc",n).map(o=>o.textContent))),le(()=>k),De([]),M(n=>__md_set("__sitemap",n,sessionStorage,e)))}}function Pi({document$:e,location$:t,viewport$:r}){let n=ce();if(location.protocol==="file:")return;"scrollRestoration"in history&&(history.scrollRestoration="manual",x(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}));let o=ie("link[rel=icon]");typeof o!="undefined"&&(o.href=o.href);let i=hr().pipe(d(l=>l.map(p=>`${new URL(p,n.base)}`)),_(l=>x(document.body,"click").pipe(A(p=>!p.metaKey&&!p.ctrlKey),_(p=>{if(p.target instanceof Element){let m=p.target.closest("a");if(m&&!m.target){let h=new URL(m.href);if(h.search="",h.hash="",h.pathname!==location.pathname&&l.includes(h.toString()))return p.preventDefault(),C({url:new URL(m.href)})}}return je}))),pe()),a=x(window,"popstate").pipe(A(l=>l.state!==null),d(l=>({url:new URL(location.href),offset:l.state})),pe());P(i,a).pipe(Q((l,p)=>l.url.href===p.url.href),d(({url:l})=>l)).subscribe(t);let c=t.pipe(J("pathname"),_(l=>pr(l.href).pipe(le(()=>(lr(l),je)))),pe());i.pipe(rr(c)).subscribe(({url:l})=>{history.pushState({},"",`${l}`)});let s=new DOMParser;c.pipe(_(l=>l.text()),d(l=>s.parseFromString(l,"text/html"))).subscribe(e);let f=new Set,u=new Set;for(let l of D("script",document))l.src?f.add(new URL(l.src,document.baseURI).toString()):u.add(l.outerHTML);e.pipe(Pe(1),mt(l=>ze(this,null,function*(){var p;for(let m of["title","link[rel=canonical]","meta[name=author]","meta[name=description]","[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...Z("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let h=ie(m),b=ie(m,l);typeof h!="undefined"&&typeof b!="undefined"&&h.replaceWith(b)}((p=window.MathJax)==null?void 0:p.typesetPromise)!==void 0&&(yield window.MathJax.typesetPromise());for(let m of D("script",l))if(m.src){let h=new URL(m.src,document.baseURI).toString();if(!f.has(h)){let b=document.createElement("script");for(let q of m.getAttributeNames())b.setAttribute(q,m.getAttribute(q));let w;b.src=h,b.async||(w=new Promise(q=>b.addEventListener("load",()=>q()))),document.body.appendChild(b),f.add(h),w!==void 0&&(yield w)}}else{let h=m.outerHTML;if(!u.has(h)){let b=document.createElement("script");for(let w of m.getAttributeNames())b.setAttribute(w,m.getAttribute(w));b.textContent=m.textContent,document.body.appendChild(b),u.add(h)}}}))).subscribe(),e.pipe(Pe(1),d(()=>_e("container")),_(l=>D("script",l)),mt(l=>{let p=O("script");if(l.src){for(let m of l.getAttributeNames())p.setAttribute(m,l.getAttribute(m));return l.replaceWith(p),new U(m=>{p.onload=()=>m.complete()})}else return p.textContent=l.textContent,l.replaceWith(p),k})).subscribe(),P(i,a).pipe(rr(e)).subscribe(({url:l,offset:p})=>{l.hash&&!p?No(l.hash):window.scrollTo(0,(p==null?void 0:p.y)||0)}),r.pipe(Wr(i),He(250),J("offset")).subscribe(({offset:l})=>{history.replaceState(l,"")}),P(i,a).pipe(Ne(2,1),A(([l,p])=>l.url.pathname===p.url.pathname),d(([,l])=>l)).subscribe(({offset:l})=>{window.scrollTo(0,(l==null?void 0:l.y)||0)})}var $i=Je(rn());function Ii(e,t){let r=new RegExp(e.separator,"img"),n=(o,i,a)=>`${i}${a}`;return o=>{o=o.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator})(${o.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return a=>(t?(0,$i.default)(a):a).replace(i,n).replace(/<\/mark>(\s+)]*>/img,"$1")}}function ji({document$:e}){var a;let t=ce(),r=t.version.staticVersions?C(t.version.staticVersions):Ge(new URL((a=t.version.versionPath)!=null?a:"../versions.json",t.base)),n=new URL("..",t.base),o=c=>new URL(c,n).toString().replace(/\/*$/,""),i=r.pipe(d(c=>{let s=t.base.toString().replace(/\/*$/,"");return c.find(({version:f,aliases:u})=>o(f)===s||u.find(l=>o(l)===s))||c[0]}));r.pipe(d(c=>new Map(c.map(s=>[`${new URL(`../${s.version}/`,t.base)}`,s]))),_(c=>x(document.body,"click").pipe(A(s=>!s.metaKey&&!s.ctrlKey),me(i),_(([s,f])=>{if(s.target instanceof Element){let u=s.target.closest("a");if(u&&!u.target&&c.has(u.href)){let l=u.href;return!s.target.closest(".md-version")&&c.get(l)===f?k:(s.preventDefault(),C(l))}}return k}),_(s=>{let{version:f}=c.get(s);return hr(new URL(s)).pipe(d(u=>{let p=Oe().href.replace(t.base,"");return u.includes(p.split("#")[0])?new URL(`../${f}/${p}`,t.base):new URL(s)}))})))).subscribe(c=>lr(c)),G([r,i]).subscribe(([c,s])=>{B(".md-header__topic").appendChild(oi(c,s))}),e.pipe(_(()=>i)).subscribe(c=>{var f;let s=__md_get("__outdated",sessionStorage);if(s===null){let u=((f=t.version)==null?void 0:f.default)||"latest";s=!c.aliases.includes(u),__md_set("__outdated",s,sessionStorage)}if(s)for(let u of ee("outdated"))u.hidden=!1})}function Fi(e,{location$:t}){let r={lang:[],separator:"\\s+"};return G([t.pipe(z(Oe()),A(n=>!!n.searchParams.get("h")))]).pipe(d(([n])=>Ii(r,!0)(n.searchParams.get("h"))),d(n=>{var a;let o=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let c=i.nextNode();c;c=i.nextNode())if((a=c.parentElement)!=null&&a.offsetHeight){let s=c.textContent,f=n(s);f.length>s.length&&o.set(c,f)}for(let[c,s]of o){let{childNodes:f}=O("span",null,s);c.replaceWith(...Array.from(f))}return{ref:e,nodes:o}}))}function Ds(e,{viewport$:t,main$:r}){let n=e.parentElement,o=n.offsetTop-n.parentElement.offsetTop;return G([r,t]).pipe(d(([{offset:i,height:a},{offset:{y:c}}])=>(a=a+Math.min(o,Math.max(0,c-i))-o,{height:a,locked:c>=i+o})),Q((i,a)=>i.height===a.height&&i.locked===a.locked))}function fn(e,n){var o=n,{header$:t}=o,r=hn(o,["header$"]);let i=B(".md-sidebar__scrollwrap",e),{y:a}=Be(i);return I(()=>{let c=new L;return c.pipe(Re(0,fe),me(t)).subscribe({next([{height:s},{height:f}]){i.style.height=`${s-2*a}px`,e.style.top=`${f}px`},complete(){i.style.height="",e.style.top=""}}),c.pipe(Ce(fe),ve(1)).subscribe(()=>{for(let s of D(".md-nav__link--active[href]",e)){let f=ko(s);if(typeof f!="undefined"){let u=s.offsetTop-f.offsetTop,{height:l}=Se(f);f.scrollTo({top:u-l/2})}}}),Ds(e,r).pipe(M(s=>c.next(s)),R(()=>c.complete()),d(s=>V({ref:e},s)))})}function Ui(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return Ir(Ge(`${r}/releases/latest`).pipe(le(()=>k),d(n=>({version:n.tag_name})),De({})),Ge(r).pipe(le(()=>k),d(n=>({stars:n.stargazers_count,forks:n.forks_count})),De({}))).pipe(d(([n,o])=>V(V({},n),o)))}else{let r=`https://api.github.com/users/${e}`;return Ge(r).pipe(d(n=>({repositories:n.public_repos})),De({}))}}function Vi(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return Ge(r).pipe(le(()=>k),d(({star_count:n,forks_count:o})=>({stars:n,forks:o})),De({}))}function Ni(e){let[t]=e.match(/(git(?:hub|lab))/i)||[];switch(t.toLowerCase()){case"github":let[,r,n]=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);return Ui(r,n);case"gitlab":let[,o,i]=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i);return Vi(o,i);default:return k}}var Ws;function zs(e){return Ws||(Ws=I(()=>{let t=__md_get("__source",sessionStorage);if(t)return C(t);if(ee("consent").length){let n=__md_get("__consent");if(!(n&&n.github))return k}return Ni(e.href).pipe(M(n=>__md_set("__source",n,sessionStorage)))}).pipe(le(()=>k),A(t=>Object.keys(t).length>0),d(t=>({facts:t})),X(1)))}function Di(e){let t=B(":scope > :last-child",e);return I(()=>{let r=new L;return r.subscribe(({facts:n})=>{t.appendChild(ri(n)),t.classList.add("md-source__repository--active")}),zs(e).pipe(M(n=>r.next(n)),R(()=>r.complete()),d(n=>V({ref:e},n)))})}function qs(e,{viewport$:t,header$:r}){return de(document.body).pipe(_(()=>mr(e,{header$:r,viewport$:t})),d(({offset:{y:n}})=>({hidden:n>=10})),J("hidden"))}function Wi(e,t){return I(()=>{let r=new L;return r.subscribe({next({hidden:n}){e.hidden=n},complete(){e.hidden=!1}}),(Z("navigation.tabs.sticky")?C({hidden:!1}):qs(e,t)).pipe(M(n=>r.next(n)),R(()=>r.complete()),d(n=>V({ref:e},n)))})}function Ks(e,{viewport$:t,header$:r,excludedLinks:n}){let o=new Map,i=D("a[href]",e);for(let s of i){if(n!=null&&n.has(s))continue;let f=s.getAttribute("href"),u;if(f.startsWith("#")){let l=decodeURIComponent(s.hash.substring(1));u=ie(`[id="${l}"]`)}else u=ie(`a.pseudo-toc-entry[href=${CSS.escape(f)}]`);if(typeof u!="undefined"){let l=s.closest(".md-nav__link");l!==null&&o.set(l,u)}}let a=r.pipe(J("height"),d(({height:s})=>{let f=_e("main"),u=B(":scope > :first-child",f);return s+.8*(u.offsetTop-f.offsetTop)}),pe());return de(document.body).pipe(J("height"),_(s=>I(()=>{let f=[];return C([...o].reduce((u,[l,p])=>{for(;f.length&&o.get(f[f.length-1]).tagName>=p.tagName;)f.pop();let m=p.offsetTop;for(;!m&&p.parentElement;)p=p.parentElement,m=p.offsetTop;return u.set([...f=[...f,l]].reverse(),m)},new Map))}).pipe(d(f=>new Map([...f].sort(([,u],[,l])=>u-l))),St(a),_(([f,u])=>t.pipe(Nr(([l,p],{offset:{y:m},size:h})=>{let b=m+h.height>=Math.floor(s.height);for(;p.length;){let[,w]=p[0];if(w-u=m&&!b)p=[l.pop(),...p];else break}return[l,p]},[[],[...f]]),Q((l,p)=>l[0]===p[0]&&l[1]===p[1])))))).pipe(d(([s,f])=>({prev:s.map(([u])=>u),next:f.map(([u])=>u)})),z({prev:[],next:[]}),Ne(2,1),d(([s,f])=>s.prev.length{let i=new L,a=o?"md-nav__link--active":"md-nav__link--in-viewport";if(i.subscribe(({prev:s,next:f})=>{for(let[u]of f)u.classList.remove("md-nav__link--passed"),u.classList.remove(a);for(let[u,[l]]of s.entries())l.classList.add("md-nav__link--passed"),l.classList.toggle(a,u===s.length-1)}),Z("toc.follow")&&(o||!Z("toc.integrate"))){let s=!o||Z("toc.integrate");i.pipe(He(1)).subscribe(({prev:f})=>{var m;let u;if(f.length===0&&s&&(u=(m=e.querySelector("a[href='#']"))!=null?m:e),s=!1,f.length!==0&&(u=f[f.length-1][0]),u===void 0||!u.offsetHeight)return;let l=u.parentElement,p=5;for(;l!==null&&l.scrollHeight-p<=l.clientHeight;)l=l.parentElement;if(l!==null&&l!==document.body&&l!==document.documentElement){let h=u.getBoundingClientRect(),b=l.getBoundingClientRect();l.scrollTo({top:l.scrollTop+(h.y-b.height/2-b.y)})}})}o&&Z("navigation.tracking")&&t.pipe(te(i.pipe(ue(1))),J("offset"),He(250),Pe(1),te(n.pipe(Pe(1))),Ot({delay:250}),me(i)).subscribe(([,{prev:s}])=>{let f=Oe(),u=s[s.length-1];if(u&&u.length){let[l]=u,{hash:p}=new URL(l.href);f.hash!==p&&(f.hash=p,history.replaceState({},"",`${f}`))}else f.hash="",history.replaceState({},"",`${f}`)}),Z("toc.sticky")&&de(document.body).pipe(J("width"),He(0)).subscribe(()=>{let s=new Map,f="--md-nav__header-height";for(let u of D(".md-nav__link",e)){let l=u.nextElementSibling;if(!(l instanceof HTMLElement)||l.tagName!=="NAV")continue;let p="",m=NaN,h=l.parentElement.closest("nav");if(h!==null){let b=s.get(h);b!==void 0&&(p=`${b.height} + `,m=b.zindex-1)}isNaN(m)&&(m=100),p+=`${u.offsetHeight}px + 0.625em`,u.classList.add("md-nav__sticky"),u.style.setProperty("--md-nav__sticky-zindex",m.toString()),l.style.setProperty(f,`calc(${p})`),s.set(l,{height:p,zindex:m})}});let c=o?void 0:new Set(D("[data-md-component='toc'] a[href]",e));return Ks(e,{viewport$:t,header$:r,excludedLinks:c}).pipe(M(s=>i.next(s)),R(()=>i.complete()),d(s=>V({ref:e},s)))})}function Bs(e,{viewport$:t,main$:r,target$:n}){let o=t.pipe(d(({offset:{y:a}})=>a),Ne(2,1),d(([a,c])=>a>c&&c>0),Q()),i=r.pipe(d(({active:a})=>a));return G([i,o]).pipe(d(([a,c])=>!(a&&c)),Q(),te(n.pipe(Pe(1))),Vr(!0),Ot({delay:250}),d(a=>({hidden:a})))}function zi(e,{viewport$:t,header$:r,main$:n,target$:o}){let i=new L,a=i.pipe(ue(1));return i.subscribe({next({hidden:c}){e.hidden=c,c?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(te(a),J("height")).subscribe(({height:c})=>{e.style.top=`${c+16}px`}),Bs(e,{viewport$:t,main$:n,target$:o}).pipe(M(c=>i.next(c)),R(()=>i.complete()),d(c=>V({ref:e},c)))}function qi({document$:e,tablet$:t}){e.pipe(_(()=>D(".md-toggle--indeterminate, [data-md-state=indeterminate]")),M(r=>{r.indeterminate=!0,r.checked=!1}),oe(r=>x(r,"change").pipe(zr(()=>r.classList.contains("md-toggle--indeterminate")),d(()=>r))),me(t)).subscribe(([r,n])=>{r.classList.remove("md-toggle--indeterminate"),n&&(r.checked=!1)})}function Ys(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function Ki({document$:e}){e.pipe(_(()=>D("[data-md-scrollfix]")),M(t=>t.removeAttribute("data-md-scrollfix")),A(Ys),oe(t=>x(t,"touchstart").pipe(d(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function Bi({viewport$:e,tablet$:t}){G([ht("search"),t]).pipe(d(([r,n])=>r&&!n),_(r=>C(r).pipe(ke(r?400:100))),me(e)).subscribe(([r,{offset:{y:n}}])=>{if(r)document.body.setAttribute("data-md-scrolllock",""),document.body.style.top=`-${n}px`;else{let o=-1*parseInt(document.body.style.top,10);document.body.removeAttribute("data-md-scrolllock"),document.body.style.top="",o&&window.scrollTo(0,o)}})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let n=e[r];typeof n!="object"?n=document.createTextNode(n):n.parentNode&&n.parentNode.removeChild(n),r?t.insertBefore(this.previousSibling,n):t.replaceChild(n,this)}}}));document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var nt=So(),vr=jo(),rt=Do(),un=Io(),ge=Jo(),gr=Yr("(min-width: 960px)"),Gi=Yr("(min-width: 1220px)"),Ji=Wo(),Gs=ce(),pn=new L;ki({alert$:pn});Z("navigation.instant")&&Pi({document$:nt,location$:vr,viewport$:ge});var Yi;((Yi=Gs.version)==null?void 0:Yi.provider)==="mike"&&ji({document$:nt});P(vr,rt).pipe(ke(125)).subscribe(()=>{Ye("drawer",!1),Ye("search",!1)});un.pipe(A(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=ie("[href][rel=prev]");typeof t!="undefined"&&t.click();break;case"n":case".":let r=ie("[href][rel=next]");typeof r!="undefined"&&r.click();break}});qi({document$:nt,tablet$:gr});Ki({document$:nt});Bi({viewport$:ge,tablet$:gr});var We=xi(_e("header"),{viewport$:ge}),br=nt.pipe(d(()=>_e("main")),_(e=>Si(e,{viewport$:ge,header$:We})),X(1)),Js=P(...ee("consent").map(e=>Xo(e,{target$:rt})),...ee("dialog").map(e=>yi(e,{alert$:pn})),...ee("header").map(e=>wi(e,{viewport$:ge,header$:We,main$:br})),...ee("palette").map(e=>Oi(e)),...ee("search").map(e=>Hi(e,{keyboard$:un})),...ee("source").map(e=>Di(e))),Qs=I(()=>P(...ee("announce").map(e=>Qo(e)),...ee("content").map(e=>gi(e,{viewport$:ge,target$:rt,print$:Ji})),...ee("content").map(e=>Z("search.highlight")?Fi(e,{location$:vr}):k),...ee("header-title").map(e=>Ei(e,{viewport$:ge,header$:We})),...ee("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?Gr(Gi,()=>fn(e,{viewport$:ge,header$:We,main$:br})):Gr(gr,()=>fn(e,{viewport$:ge,header$:We,main$:br}))),...ee("tabs").map(e=>Wi(e,{viewport$:ge,header$:We})),...ee("toc").map(e=>ln(e,{viewport$:ge,header$:We,target$:rt,localToc:!0})),...ee("sidebar").filter(e=>e.getAttribute("data-md-type")==="navigation").map(e=>ln(e,{viewport$:ge,header$:We,target$:rt,localToc:!1})),...ee("top").map(e=>zi(e,{viewport$:ge,header$:We,main$:br,target$:rt})))),Qi=nt.pipe(_(()=>Qs),tt(Js),X(1));Qi.subscribe();window.document$=nt;window.location$=vr;window.target$=rt;window.keyboard$=un;window.viewport$=ge;window.tablet$=gr;window.screen$=Gi;window.print$=Ji;window.alert$=pn;window.component$=Qi;})(); diff --git a/_static/sphinx_immaterial_theme.af531f03affe68837.min.css b/_static/sphinx_immaterial_theme.af531f03affe68837.min.css new file mode 100644 index 00000000..abac0976 --- /dev/null +++ b/_static/sphinx_immaterial_theme.af531f03affe68837.min.css @@ -0,0 +1,4 @@ +@charset "UTF-8";html{-webkit-text-size-adjust:none;-moz-text-size-adjust:none;text-size-adjust:none;box-sizing:border-box}*,:after,:before{box-sizing:inherit}@media (prefers-reduced-motion){*,:after,:before{transition:none!important}}body{margin:0}a,button,input,label{-webkit-tap-highlight-color:transparent}a{color:inherit;text-decoration:none}hr{border:0;box-sizing:content-box;display:block;height:.05rem;overflow:visible;padding:0}small{font-size:80%}sub,sup{line-height:1em}img{border-style:none}table{border-collapse:separate;border-spacing:0}td,th{font-weight:400;vertical-align:top}button{background:transparent;border:0;font-family:inherit;font-size:inherit;margin:0;padding:0}input{border:0;outline:none}:root,[data-md-color-scheme=default]{--md-default-fg-color:rgba(0,0,0,.87);--md-default-fg-color--light:rgba(0,0,0,.54);--md-default-fg-color--lighter:rgba(0,0,0,.32);--md-default-fg-color--lightest:rgba(0,0,0,.07);--md-default-bg-color:#fff;--md-default-bg-color--light:hsla(0,0%,100%,.7);--md-default-bg-color--lighter:hsla(0,0%,100%,.3);--md-default-bg-color--lightest:hsla(0,0%,100%,.12);--md-primary-fg-color:#4051b5;--md-primary-fg-color--light:#5d6cc0;--md-primary-fg-color--dark:#303fa1;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7);--md-accent-fg-color:#526cfe;--md-accent-fg-color--transparent:rgba(82,108,254,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7);--md-code-fg-color:#36464e;--md-code-bg-color:#f5f5f5;--md-code-hl-color:rgba(255,255,0,.5);--md-code-hl-number-color:#d52a2a;--md-code-hl-special-color:#db1457;--md-code-hl-function-color:#a846b9;--md-code-hl-constant-color:#6e59d9;--md-code-hl-keyword-color:#3f6ec6;--md-code-hl-string-color:#1c7d4d;--md-code-hl-name-color:var(--md-code-fg-color);--md-code-hl-operator-color:var(--md-default-fg-color--light);--md-code-hl-punctuation-color:var(--md-default-fg-color--light);--md-code-hl-comment-color:var(--md-default-fg-color--light);--md-code-hl-generic-color:var(--md-default-fg-color--light);--md-code-hl-variable-color:var(--md-default-fg-color--light);--md-typeset-color:var(--md-default-fg-color);--md-typeset-a-color:var(--md-primary-fg-color);--md-typeset-mark-color:rgba(255,255,0,.5);--md-typeset-del-color:rgba(245,80,61,.15);--md-typeset-ins-color:rgba(11,213,112,.15);--md-typeset-kbd-color:#fafafa;--md-typeset-kbd-accent-color:#fff;--md-typeset-kbd-border-color:#b8b8b8;--md-typeset-table-color:rgba(0,0,0,.12);--md-admonition-fg-color:var(--md-default-fg-color);--md-admonition-bg-color:var(--md-default-bg-color);--md-footer-fg-color:#fff;--md-footer-fg-color--light:hsla(0,0%,100%,.7);--md-footer-fg-color--lighter:hsla(0,0%,100%,.3);--md-footer-bg-color:rgba(0,0,0,.87);--md-footer-bg-color--dark:rgba(0,0,0,.32);--md-shadow-z1:0 0.2rem 0.5rem rgba(0,0,0,.05),0 0 0.05rem rgba(0,0,0,.1);--md-shadow-z2:0 0.2rem 0.5rem rgba(0,0,0,.1),0 0 0.05rem rgba(0,0,0,.25);--md-shadow-z3:0 0.2rem 0.5rem rgba(0,0,0,.2),0 0 0.05rem rgba(0,0,0,.35)}.md-icon svg{fill:currentcolor;display:block;height:1.2rem;width:1.2rem}.si-icon-inline:before{background-color:var(--md-default-fg-color);content:"";display:inline-flex;height:1.125em;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;vertical-align:text-top;width:1.125em}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;--md-text-font-family:var(--md-text-font,_),-apple-system,BlinkMacSystemFont,Helvetica,Arial,sans-serif;--md-code-font-family:var(--md-code-font,_),SFMono-Regular,Consolas,Menlo,monospace}body,input{font-feature-settings:"kern","liga";font-family:var(--md-text-font-family)}body,code,input,kbd,pre{color:var(--md-typeset-color)}code,kbd,pre{font-feature-settings:"kern";font-family:var(--md-code-font-family)}:root{--md-typeset-table-sort-icon:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--asc:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--desc:url('data:image/svg+xml;charset=utf-8,')}.md-typeset{-webkit-print-color-adjust:exact;color-adjust:exact;font-size:.8rem;line-height:1.6}@media print{.md-typeset{font-size:.68rem}}.md-typeset blockquote,.md-typeset dl,.md-typeset figure,.md-typeset ol,.md-typeset pre,.md-typeset ul{margin-bottom:1em;margin-top:1em}.md-typeset h1{color:var(--md-default-fg-color--light);font-size:2em;line-height:1.3;margin:0 0 1.25em}.md-typeset h1,.md-typeset h2{font-weight:300;letter-spacing:-.01em}.md-typeset h2{font-size:1.5625em;line-height:1.4;margin:1.6em 0 .64em}.md-typeset h3{font-size:1.25em;font-weight:400;letter-spacing:-.01em;line-height:1.5;margin:1.6em 0 .8em}.md-typeset h2+h3{margin-top:.8em}.md-typeset h4{font-weight:700;letter-spacing:-.01em;margin:1em 0}.md-typeset h5,.md-typeset h6{color:var(--md-default-fg-color--light);font-size:.8em;font-weight:700;letter-spacing:-.01em;margin:1.25em 0}.md-typeset h5{text-transform:uppercase}.md-typeset hr{border-bottom:.05rem solid var(--md-default-fg-color--lightest);display:flow-root;margin:1.5em 0}.md-typeset a{color:var(--md-typeset-a-color);word-break:break-word}.md-typeset a,.md-typeset a:before{transition:color 125ms}.md-typeset a:focus,.md-typeset a:hover{color:var(--md-accent-fg-color)}.md-typeset a:focus code,.md-typeset a:hover code{background-color:var(--md-accent-fg-color--transparent)}.md-typeset a code{color:currentcolor;transition:background-color 125ms}.md-typeset a.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset code,.md-typeset kbd,.md-typeset pre{color:var(--md-code-fg-color);direction:ltr;font-variant-ligatures:none}@media print{.md-typeset code,.md-typeset kbd,.md-typeset pre{white-space:pre-wrap}}.md-typeset code{background-color:var(--md-code-bg-color);border-radius:.1rem;-webkit-box-decoration-break:clone;box-decoration-break:clone;font-size:.85em;padding:0 .2941176471em;word-break:break-word}.md-typeset code:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-typeset pre{display:flow-root;line-height:1.4;position:relative}.md-typeset pre>code{-webkit-box-decoration-break:slice;box-decoration-break:slice;box-shadow:none;display:block;margin:0;outline-color:var(--md-accent-fg-color);overflow:auto;padding:.7720588235em 1.1764705882em;scrollbar-color:var(--md-default-fg-color--lighter) transparent;scrollbar-width:thin;touch-action:auto;word-break:normal}.md-typeset pre>code:hover{scrollbar-color:var(--md-accent-fg-color) transparent}.md-typeset pre>code::-webkit-scrollbar{height:.2rem;width:.2rem}.md-typeset pre>code::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-typeset pre>code::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}.md-typeset .code-block-caption+.notranslate .highlighttable,.md-typeset .code-block-caption+.notranslate pre{margin-top:0}.md-typeset kbd{background-color:var(--md-typeset-kbd-color);border-radius:.1rem;box-shadow:0 .1rem 0 .05rem var(--md-typeset-kbd-border-color),0 .1rem 0 var(--md-typeset-kbd-border-color),0 -.1rem .2rem var(--md-typeset-kbd-accent-color) inset;color:var(--md-default-fg-color);display:inline-block;font-size:.75em;padding:0 .6666666667em;vertical-align:text-top;word-break:break-word}.md-typeset mark{background-color:var(--md-typeset-mark-color);-webkit-box-decoration-break:clone;box-decoration-break:clone;color:inherit;word-break:break-word}.md-typeset abbr{border-bottom:.05rem dotted var(--md-default-fg-color--light);cursor:help;text-decoration:none}@media (hover:none){.md-typeset abbr{position:relative}.md-typeset abbr[title]:-webkit-any(:focus,:hover):after{background-color:var(--md-default-fg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z3);color:var(--md-default-bg-color);content:attr(title);display:inline-block;font-size:.7rem;margin-top:2em;max-width:80%;min-width:max-content;padding:.2rem .3rem;position:absolute;width:auto}.md-typeset abbr[title]:-moz-any(:focus,:hover):after{background-color:var(--md-default-fg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z3);color:var(--md-default-bg-color);content:attr(title);display:inline-block;font-size:.7rem;margin-top:2em;max-width:80%;min-width:-moz-max-content;min-width:max-content;padding:.2rem .3rem;position:absolute;width:auto}[dir=ltr] .md-typeset abbr[title]:-webkit-any(:focus,:hover):after{left:0}[dir=ltr] .md-typeset abbr[title]:-moz-any(:focus,:hover):after{left:0}[dir=ltr] .md-typeset abbr[title]:is(:focus,:hover):after{left:0}[dir=rtl] .md-typeset abbr[title]:-webkit-any(:focus,:hover):after{right:0}[dir=rtl] .md-typeset abbr[title]:-moz-any(:focus,:hover):after{right:0}[dir=rtl] .md-typeset abbr[title]:is(:focus,:hover):after{right:0}.md-typeset abbr[title]:is(:focus,:hover):after{background-color:var(--md-default-fg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z3);color:var(--md-default-bg-color);content:attr(title);display:inline-block;font-size:.7rem;margin-top:2em;max-width:80%;min-width:-moz-max-content;min-width:max-content;padding:.2rem .3rem;position:absolute;width:auto}}.md-typeset small{opacity:.75}[dir=ltr] .md-typeset sub,[dir=ltr] .md-typeset sup{margin-left:.078125em}[dir=rtl] .md-typeset sub,[dir=rtl] .md-typeset sup{margin-right:.078125em}[dir=ltr] .md-typeset blockquote{padding-left:.6rem}[dir=rtl] .md-typeset blockquote{padding-right:.6rem}[dir=ltr] .md-typeset blockquote{border-left:.2rem solid var(--md-default-fg-color--lighter)}[dir=rtl] .md-typeset blockquote{border-right:.2rem solid var(--md-default-fg-color--lighter)}.md-typeset blockquote{color:var(--md-default-fg-color--light);margin-left:0;margin-right:0}.md-typeset ul{list-style-type:disc}[dir=ltr] .md-typeset ol,[dir=ltr] .md-typeset ul{margin-left:.625em}[dir=rtl] .md-typeset ol,[dir=rtl] .md-typeset ul{margin-right:.625em}.md-typeset ol,.md-typeset ul{padding:0}.md-typeset ol:not([hidden]),.md-typeset ul:not([hidden]){display:flow-root}.md-typeset ol ol,.md-typeset ul ol{list-style-type:lower-alpha}.md-typeset ol ol ol,.md-typeset ul ol ol{list-style-type:lower-roman}[dir=ltr] .md-typeset ol li,[dir=ltr] .md-typeset ul li{margin-left:1.25em}[dir=rtl] .md-typeset ol li,[dir=rtl] .md-typeset ul li{margin-right:1.25em}.md-typeset ol li,.md-typeset ul li{margin-bottom:.5em}.md-typeset ol li blockquote,.md-typeset ol li p,.md-typeset ul li blockquote,.md-typeset ul li p{margin:.5em 0}.md-typeset ol li:last-child,.md-typeset ul li:last-child{margin-bottom:0}.md-typeset ol li :-webkit-any(ul,ol),.md-typeset ul li :-webkit-any(ul,ol){margin-bottom:.5em;margin-top:.5em}.md-typeset ol li :-moz-any(ul,ol),.md-typeset ul li :-moz-any(ul,ol){margin-bottom:.5em;margin-top:.5em}[dir=ltr] .md-typeset ol li :-webkit-any(ul,ol),[dir=ltr] .md-typeset ul li :-webkit-any(ul,ol){margin-left:.625em}[dir=ltr] .md-typeset ol li :-moz-any(ul,ol),[dir=ltr] .md-typeset ul li :-moz-any(ul,ol){margin-left:.625em}[dir=ltr] .md-typeset ol li :is(ul,ol),[dir=ltr] .md-typeset ul li :is(ul,ol){margin-left:.625em}[dir=rtl] .md-typeset ol li :-webkit-any(ul,ol),[dir=rtl] .md-typeset ul li :-webkit-any(ul,ol){margin-right:.625em}[dir=rtl] .md-typeset ol li :-moz-any(ul,ol),[dir=rtl] .md-typeset ul li :-moz-any(ul,ol){margin-right:.625em}[dir=rtl] .md-typeset ol li :is(ul,ol),[dir=rtl] .md-typeset ul li :is(ul,ol){margin-right:.625em}.md-typeset ol li :is(ul,ol),.md-typeset ul li :is(ul,ol){margin-bottom:.5em;margin-top:.5em}[dir=ltr] .md-typeset dd{margin-left:1.875em}[dir=rtl] .md-typeset dd{margin-right:1.875em}.md-typeset dd{margin-bottom:1.5em;margin-top:1em}.md-typeset img,.md-typeset svg,.md-typeset video{height:auto;max-width:100%}.md-typeset img[align=left]{margin:1em 1em 1em 0}.md-typeset img[align=right]{margin:1em 0 1em 1em}.md-typeset img[align]:only-child{margin-top:0}.md-typeset img[src$="#gh-dark-mode-only"],.md-typeset img[src$="#only-dark"]{display:none}.md-typeset figure{display:flow-root;margin:1em auto;max-width:100%;text-align:center;width:-moz-fit-content;width:fit-content}.md-typeset figure img{display:block}.md-typeset figcaption{font-style:italic;margin:1em auto;max-width:24rem}.md-typeset iframe{max-width:100%}.md-typeset table.data:not(.plain){background-color:var(--md-default-bg-color);border:.05rem solid var(--md-typeset-table-color);border-radius:.1rem;display:block;font-size:.64rem;max-width:100%;overflow:auto;touch-action:auto;width:-moz-max-content;width:max-content}@media print{.md-typeset table.data:not(.plain){display:table}}.md-typeset table.data:not(.plain)+*{margin-top:1.5em}.md-typeset table.data:not(.plain) :-webkit-any(th,td)>:first-child{margin-top:0}.md-typeset table.data:not(.plain) :-moz-any(th,td)>:first-child{margin-top:0}.md-typeset table.data:not(.plain) :is(th,td)>:first-child{margin-top:0}.md-typeset table.data:not(.plain) :-webkit-any(th,td)>:last-child{margin-bottom:0}.md-typeset table.data:not(.plain) :-moz-any(th,td)>:last-child{margin-bottom:0}.md-typeset table.data:not(.plain) :is(th,td)>:last-child{margin-bottom:0}.md-typeset table.data:not(.plain) :-webkit-any(th,td):not([align],.align-center,.align-left,.align-right){text-align:left}.md-typeset table.data:not(.plain) :-moz-any(th,td):not([align],.align-center,.align-left,.align-right){text-align:left}.md-typeset table.data:not(.plain) :is(th,td):not([align],.align-center,.align-left,.align-right){text-align:left}[dir=rtl] .md-typeset table.data:not(.plain) :-webkit-any(th,td):not([align],.align-center,.align-left,.align-right){text-align:right}[dir=rtl] .md-typeset table.data:not(.plain) :-moz-any(th,td):not([align],.align-center,.align-left,.align-right){text-align:right}[dir=rtl] .md-typeset table.data:not(.plain) :is(th,td):not([align],.align-center,.align-left,.align-right){text-align:right}.md-typeset table.data:not(.plain) th{font-weight:700;min-width:5rem;padding:.9375em 1.25em;vertical-align:top}.md-typeset table.data:not(.plain) td{border-top:.05rem solid var(--md-typeset-table-color);padding:.9375em 1.25em;vertical-align:top}.md-typeset table.data:not(.plain) tbody tr{transition:background-color 125ms}.md-typeset table.data:not(.plain) tbody tr:hover{background-color:rgba(0,0,0,.035);box-shadow:0 .05rem 0 var(--md-default-bg-color) inset}.md-typeset table.data:not(.plain) a{word-break:normal}.md-typeset table th[role=columnheader]{cursor:pointer}[dir=ltr] .md-typeset table th[role=columnheader]:after{margin-left:.5em}[dir=rtl] .md-typeset table th[role=columnheader]:after{margin-right:.5em}.md-typeset table th[role=columnheader]:after{content:"";display:inline-block;height:1.2em;-webkit-mask-image:var(--md-typeset-table-sort-icon);mask-image:var(--md-typeset-table-sort-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset table th[role=columnheader]:hover:after{background-color:var(--md-default-fg-color--lighter)}.md-typeset table th[role=columnheader][aria-sort=ascending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--asc);mask-image:var(--md-typeset-table-sort-icon--asc)}.md-typeset table th[role=columnheader][aria-sort=descending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--desc);mask-image:var(--md-typeset-table-sort-icon--desc)}.md-typeset__scrollwrap{margin:1em -.8rem;overflow-x:auto;touch-action:auto}.md-typeset__table{display:inline-block;margin-bottom:.5em;padding:0 .8rem}@media print{.md-typeset__table{display:block}}html .md-typeset__table table{display:table;margin:0;overflow:hidden;width:100%}@media screen and (max-width:44.9375em){.md-content__inner>pre{margin:1em -.8rem}.md-content__inner>pre code{border-radius:0}}.md-banner{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color);overflow:auto}@media print{.md-banner{display:none}}.md-banner--warning{background:var(--md-typeset-mark-color);color:var(--md-default-fg-color)}.md-banner__inner{font-size:.7rem;margin:.6rem auto;padding:0 .8rem}[dir=ltr] .md-banner__button{float:right}[dir=rtl] .md-banner__button{float:left}.md-banner__button{color:inherit;cursor:pointer;transition:opacity .25s}.md-banner__button:hover{opacity:.7}html{font-size:125%;height:100%;overflow-x:hidden}@media screen and (min-width:100em){html{font-size:137.5%}}@media screen and (min-width:125em){html{font-size:150%}}body{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;font-size:.5rem;min-height:100%;position:relative;width:100%}@media print{body{display:block}}@media screen and (max-width:59.9375em){body[data-md-scrolllock]{position:fixed}}.md-grid{margin-left:auto;margin-right:auto;max-width:61rem}.md-container{display:flex;flex-direction:column;flex-grow:1}@media print{.md-container{display:block}}.md-main{flex-grow:1}.md-main__inner{display:flex;height:100%;margin-top:1.5rem}.md-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.md-toggle{display:none}.md-option{height:0;opacity:0;position:absolute;width:0}.md-option:checked+label:not([hidden]){display:block}.md-option.focus-visible+label{outline-color:var(--md-accent-fg-color);outline-style:auto}.md-skip{background-color:var(--md-default-fg-color);border-radius:.1rem;color:var(--md-default-bg-color);font-size:.64rem;margin:.5rem;opacity:0;outline-color:var(--md-accent-fg-color);padding:.3rem .5rem;position:fixed;transform:translateY(.4rem);z-index:-1}.md-skip:focus{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 175ms 75ms;z-index:10}@page{margin:25mm}:root{--md-clipboard-icon:url('data:image/svg+xml;charset=utf-8,')}.md-clipboard{border-radius:.1rem;color:var(--md-default-fg-color--lightest);cursor:pointer;height:1.5em;outline-color:var(--md-accent-fg-color);outline-offset:.1rem;position:absolute;right:.5em;top:.5em;transition:color .25s;width:1.5em;z-index:1}@media print{.md-clipboard{display:none}}.md-clipboard:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}:hover>.md-clipboard{color:var(--md-default-fg-color--light)}.md-clipboard:-webkit-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-clipboard:-moz-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-clipboard:is(:focus,:hover){color:var(--md-accent-fg-color)}.md-clipboard:after{background-color:currentcolor;content:"";display:block;height:1.125em;margin:0 auto;-webkit-mask-image:var(--md-clipboard-icon);mask-image:var(--md-clipboard-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:1.125em}.md-clipboard--inline{cursor:pointer}.md-clipboard--inline code{transition:color .25s,background-color .25s}.md-clipboard--inline:-webkit-any(:focus,:hover) code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-clipboard--inline:-moz-any(:focus,:hover) code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-clipboard--inline:is(:focus,:hover) code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}@keyframes consent{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}@keyframes overlay{0%{opacity:0}to{opacity:1}}.md-consent__overlay{animation:overlay .25s both;-webkit-backdrop-filter:blur(.1rem);backdrop-filter:blur(.1rem);background-color:rgba(0,0,0,.54);height:100%;opacity:1;position:fixed;top:0;width:100%;z-index:5}.md-consent__inner{animation:consent .5s cubic-bezier(.1,.7,.1,1) both;background-color:var(--md-default-bg-color);border:0;border-radius:.1rem;bottom:0;box-shadow:0 0 .2rem rgba(0,0,0,.1),0 .2rem .4rem rgba(0,0,0,.2);max-height:100%;overflow:auto;padding:0;position:fixed;width:100%;z-index:5}.md-consent__form{padding:.8rem}.md-consent__settings{display:none;margin:1em 0}input:checked+.md-consent__settings{display:block}.md-consent__controls{margin-bottom:.8rem}.md-typeset .md-consent__controls .md-button{display:inline}@media screen and (max-width:44.9375em){.md-typeset .md-consent__controls .md-button{display:block;margin-top:.4rem;text-align:center;width:100%}}.md-consent label{cursor:pointer}.md-content{flex-grow:1;min-width:0}.md-content__inner{margin:0 .8rem 1.2rem;padding-top:.6rem}@media screen and (min-width:76.25em){[dir=ltr] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}[dir=ltr] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner,[dir=rtl] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-right:1.2rem}[dir=rtl] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}}.md-content__inner:before{content:"";display:block;height:.4rem}.md-content__inner>:last-child{margin-bottom:0}[dir=ltr] .md-content__button{float:right}[dir=rtl] .md-content__button{float:left}[dir=ltr] .md-content__button{margin-left:.4rem}[dir=rtl] .md-content__button{margin-right:.4rem}.md-content__button{margin:.4rem 0;padding:0}@media print{.md-content__button{display:none}}.md-typeset .md-content__button{color:var(--md-default-fg-color--lighter)}.md-content__button svg{display:inline;vertical-align:top}[dir=rtl] .md-content__button svg{transform:scaleX(-1)}[dir=ltr] .md-dialog{right:.8rem}[dir=rtl] .md-dialog{left:.8rem}.md-dialog{background-color:var(--md-default-fg-color);border-radius:.1rem;bottom:.8rem;box-shadow:var(--md-shadow-z3);min-width:11.1rem;opacity:0;padding:.4rem .6rem;pointer-events:none;position:fixed;transform:translateY(100%);transition:transform 0ms .4s,opacity .4s;z-index:4}@media print{.md-dialog{display:none}}.md-dialog--active{opacity:1;pointer-events:auto;transform:translateY(0);transition:transform .4s cubic-bezier(.075,.85,.175,1),opacity .4s}.md-dialog__inner{color:var(--md-default-bg-color);font-size:.7rem}.md-feedback{margin:2em 0 1em;text-align:center}.md-feedback fieldset{border:none;margin:0;padding:0}.md-feedback__title{font-weight:700;margin:1em auto}.md-feedback__inner{position:relative}.md-feedback__list{align-content:baseline;display:flex;flex-wrap:wrap;justify-content:center;position:relative}.md-feedback__list:hover .md-icon:not(:disabled){color:var(--md-default-fg-color--lighter)}:disabled .md-feedback__list{min-height:1.8rem}.md-feedback__icon{color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;margin:0 .1rem;transition:color 125ms}.md-feedback__icon:not(:disabled).md-icon:hover{color:var(--md-accent-fg-color)}.md-feedback__icon:disabled{color:var(--md-default-fg-color--lightest);pointer-events:none}.md-feedback__note{opacity:0;position:relative;transform:translateY(.4rem);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-feedback__note>*{margin:0 auto;max-width:16rem}:disabled .md-feedback__note{opacity:1;transform:translateY(0)}.md-footer{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color)}@media print{.md-footer{display:none}}.md-footer__inner{justify-content:space-between;overflow:auto;padding:.2rem}.md-footer__inner:not([hidden]){display:flex}.md-footer__link{display:flex;flex-grow:0.01;outline-color:var(--md-accent-fg-color);overflow:hidden;padding-bottom:.4rem;padding-top:1.4rem;transition:opacity .25s}.md-footer__link:-webkit-any(:focus,:hover){opacity:.7}.md-footer__link:-moz-any(:focus,:hover){opacity:.7}.md-footer__link:is(:focus,:hover){opacity:.7}[dir=rtl] .md-footer__link svg{transform:scaleX(-1)}@media screen and (max-width:44.9375em){.md-footer__link--prev .md-footer__title{display:none}}[dir=ltr] .md-footer__link--next{margin-left:auto}[dir=rtl] .md-footer__link--next{margin-right:auto}.md-footer__link--next{text-align:right}[dir=rtl] .md-footer__link--next{text-align:left}.md-footer__title{flex-grow:1;font-size:.9rem;line-height:2.4rem;max-width:calc(100% - 2.4rem);padding:0 1rem;position:relative;white-space:nowrap}.md-footer__button{margin:.2rem;padding:.4rem}.md-footer__direction{font-size:.64rem;left:0;margin-top:-1rem;opacity:.7;padding:0 1rem;position:absolute;right:0}.md-footer-meta{background-color:var(--md-footer-bg-color--dark)}.md-footer-meta__inner{display:flex;flex-wrap:wrap;justify-content:space-between;padding:.2rem}html .md-footer-meta.md-typeset a{color:var(--md-footer-fg-color--light)}html .md-footer-meta.md-typeset a:-webkit-any(:focus,:hover){color:var(--md-footer-fg-color)}html .md-footer-meta.md-typeset a:-moz-any(:focus,:hover){color:var(--md-footer-fg-color)}html .md-footer-meta.md-typeset a:is(:focus,:hover){color:var(--md-footer-fg-color)}.md-copyright{color:var(--md-footer-fg-color--lighter);font-size:.64rem;margin:auto .6rem;padding:.4rem 0;width:100%}@media screen and (min-width:45em){.md-copyright{width:auto}}.md-copyright__highlight{color:var(--md-footer-fg-color--light)}.md-social{margin:0 .4rem;padding:.2rem 0 .6rem}@media screen and (min-width:45em){.md-social{padding:.6rem 0}}.md-social__link{display:inline-block;height:1.6rem;text-align:center;width:1.6rem}.md-social__link:before{line-height:1.9}.md-social__link svg{fill:currentcolor;max-height:.8rem;vertical-align:-25%}.md-typeset .md-button{border:.1rem solid;border-radius:.1rem;color:var(--md-primary-fg-color);cursor:pointer;display:inline-block;font-weight:700;padding:.625em 2em;transition:color 125ms,background-color 125ms,border-color 125ms}.md-typeset .md-button--primary{background-color:var(--md-primary-fg-color);border-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color)}.md-typeset .md-button:-webkit-any(:focus,:hover){background-color:var(--md-accent-fg-color);border-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-typeset .md-button:-moz-any(:focus,:hover){background-color:var(--md-accent-fg-color);border-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-typeset .md-button:is(:focus,:hover){background-color:var(--md-accent-fg-color);border-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[dir=ltr] .md-typeset .md-input{border-top-left-radius:.1rem}[dir=ltr] .md-typeset .md-input,[dir=rtl] .md-typeset .md-input{border-top-right-radius:.1rem}[dir=rtl] .md-typeset .md-input{border-top-left-radius:.1rem}.md-typeset .md-input{border-bottom:.1rem solid var(--md-default-fg-color--lighter);box-shadow:var(--md-shadow-z1);font-size:.8rem;height:1.8rem;padding:0 .6rem;transition:border .25s,box-shadow .25s}.md-typeset .md-input:-webkit-any(:focus,:hover){border-bottom-color:var(--md-accent-fg-color);box-shadow:var(--md-shadow-z2)}.md-typeset .md-input:-moz-any(:focus,:hover){border-bottom-color:var(--md-accent-fg-color);box-shadow:var(--md-shadow-z2)}.md-typeset .md-input:is(:focus,:hover){border-bottom-color:var(--md-accent-fg-color);box-shadow:var(--md-shadow-z2)}.md-typeset .md-input--stretch{width:100%}.md-header{background-color:var(--md-primary-fg-color);box-shadow:0 0 .2rem transparent,0 .2rem .4rem transparent;color:var(--md-primary-bg-color);display:block;left:0;position:sticky;right:0;top:0;z-index:4}@media print{.md-header{display:none}}.md-header[hidden]{transform:translateY(-100%);transition:transform .25s cubic-bezier(.8,0,.6,1),box-shadow .25s}.md-header--shadow{box-shadow:0 0 .2rem rgba(0,0,0,.1),0 .2rem .4rem rgba(0,0,0,.2);transition:transform .25s cubic-bezier(.1,.7,.1,1),box-shadow .25s}.md-header__inner{align-items:center;display:flex;padding:0 .2rem}.md-header__button{color:currentcolor;cursor:pointer;margin:.2rem;outline-color:var(--md-accent-fg-color);padding:.4rem;position:relative;transition:opacity .25s;vertical-align:middle;z-index:1}.md-header__button:hover{opacity:.7}.md-header__button:not([hidden]){display:inline-block}.md-header__button:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-header__button.md-logo{margin:.2rem;padding:.4rem}@media screen and (max-width:76.1875em){.md-header__button.md-logo{display:none}}.md-header__button.md-logo :-webkit-any(img,svg){fill:currentcolor;display:block;height:1.2rem;width:auto}.md-header__button.md-logo :-moz-any(img,svg){fill:currentcolor;display:block;height:1.2rem;width:auto}.md-header__button.md-logo :is(img,svg){fill:currentcolor;display:block;height:1.2rem;width:auto}@media screen and (min-width:60em){.md-header__button[for=__search]{display:none}}.no-js .md-header__button[for=__search]{display:none}[dir=rtl] .md-header__button[for=__search] svg{transform:scaleX(-1)}@media screen and (min-width:76.25em){.md-header__button[for=__drawer]{display:none}}.md-header__topic{display:flex;max-width:100%;position:absolute;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;white-space:nowrap}.md-header__topic+.md-header__topic{opacity:0;pointer-events:none;transform:translateX(1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__topic+.md-header__topic{transform:translateX(-1.25rem)}.md-header__topic:first-child{font-weight:700}[dir=ltr] .md-header__title{margin-right:.4rem}[dir=rtl] .md-header__title{margin-left:.4rem}[dir=ltr] .md-header__title{margin-left:1rem}[dir=rtl] .md-header__title{margin-right:1rem}.md-header__title{flex-grow:1;font-size:.9rem;height:2.4rem;line-height:2.4rem}.md-header__title--active .md-header__topic{opacity:0;pointer-events:none;transform:translateX(-1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__title--active .md-header__topic{transform:translateX(1.25rem)}.md-header__title--active .md-header__topic+.md-header__topic{opacity:1;pointer-events:auto;transform:translateX(0);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;z-index:0}.md-header__title>.md-header__ellipsis{height:100%;position:relative;width:100%}.md-header__option{display:flex;flex-shrink:0;max-width:100%;transition:max-width 0ms .25s,opacity .25s .25s;white-space:nowrap}[data-md-toggle=search]:checked~.md-header .md-header__option{max-width:0;opacity:0;transition:max-width 0ms,opacity 0ms}.md-header__source{display:none}@media screen and (min-width:60em){[dir=ltr] .md-header__source{margin-left:1rem}[dir=rtl] .md-header__source{margin-right:1rem}.md-header__source{display:block;max-width:11.7rem;width:11.7rem}}@media screen and (min-width:76.25em){[dir=ltr] .md-header__source{margin-left:1.4rem}[dir=rtl] .md-header__source{margin-right:1.4rem}}.md-hero{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);font-size:1rem;overflow:hidden;transition:background .25s}.md-hero__inner{margin-top:1rem;padding:.8rem .8rem .4rem;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .25s;transition-delay:.1s}@media screen and (max-width:76.1875em){.md-hero__inner{margin-bottom:1.2rem;margin-top:2.4rem}}[data-md-state=hidden] .md-hero__inner{opacity:0;pointer-events:none;transform:translateY(.625rem);transition:transform 0ms .4s,opacity .1s 0ms}.md-hero--expand .md-hero__inner{margin-bottom:1.2rem}:root{--md-nav-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-nav-icon--next:url('data:image/svg+xml;charset=utf-8,');--md-toc-icon:url('data:image/svg+xml;charset=utf-8,')}.md-nav{font-size:.7rem;line-height:1.3}.md-nav__title{align-items:center;display:flex;font-weight:700;overflow:hidden;padding:0 .6rem;text-overflow:ellipsis}.md-nav__title .md-nav__button{display:none}.md-nav__title .md-nav__button img{height:100%;width:auto}.md-nav__title .md-nav__button.md-logo :-webkit-any(img,svg){fill:currentcolor;display:block;height:2.4rem;max-width:100%;object-fit:contain;width:auto}.md-nav__title .md-nav__button.md-logo :-moz-any(img,svg){fill:currentcolor;display:block;height:2.4rem;max-width:100%;object-fit:contain;width:auto}.md-nav__title .md-nav__button.md-logo :is(img,svg){fill:currentcolor;display:block;height:2.4rem;max-width:100%;-o-object-fit:contain;object-fit:contain;width:auto}.md-nav__list{list-style:none;margin:0;padding:0}.md-nav__item{padding:0 .6rem}[dir=ltr] .md-nav__item .md-nav__item{padding-right:0}[dir=rtl] .md-nav__item .md-nav__item{padding-left:0}.md-nav__link{align-items:center;cursor:pointer;display:flex;margin-top:.625em;scroll-snap-align:start;transition:color 125ms}.md-nav__link.md-nav__sticky{box-shadow:0 -.625em var(--md-default-bg-color),0 .625em var(--md-default-bg-color)}.md-nav__link--passed{color:var(--md-default-fg-color--light)}.md-nav__item .md-nav__link--active{color:var(--md-typeset-a-color)}.md-nav__link--in-viewport{position:relative}.md-nav__link--in-viewport:before{background-color:var(--md-primary-fg-color);bottom:0;content:"";height:100%;position:absolute;right:calc(100% + .3rem);top:0;width:.05rem}.md-nav__item .md-nav__link--index [href]{width:100%}.md-nav__link:-webkit-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-nav__link:-moz-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-nav__link:is(:focus,:hover){color:var(--md-accent-fg-color)}.md-nav__link.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-nav--primary .md-nav__link[for=__toc]{display:none}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{background-color:currentcolor;display:block;height:100%;-webkit-mask-image:var(--md-toc-icon);mask-image:var(--md-toc-icon);width:100%}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:none}.md-nav__link>*{cursor:pointer;display:flex}.md-nav__sticky{background-color:var(--md-default-bg-color);position:sticky;top:var(--md-nav__header-height,0);z-index:var(--md-nav__sticky-zindex)}.md-nav .md-ellipsis{display:block;flex-grow:1;white-space:normal}.md-nav__icon{flex-shrink:0}.md-nav__source{display:none}@media screen and (max-width:76.1875em){.md-nav--primary,.md-nav--primary .md-nav{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;height:100%;left:0;position:absolute;right:0;top:0;z-index:1}.md-nav--primary .md-nav__sticky{background-color:transparent;box-shadow:none;position:static;z-index:auto}.md-nav--primary :-webkit-any(.md-nav__title,.md-nav__item){font-size:.8rem;line-height:1.5}.md-nav--primary :-moz-any(.md-nav__title,.md-nav__item){font-size:.8rem;line-height:1.5}.md-nav--primary :is(.md-nav__title,.md-nav__item){font-size:.8rem;line-height:1.5}.md-nav--primary .md-nav__title{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light);cursor:pointer;line-height:2.4rem;min-height:5.6rem;padding:3rem .8rem .2rem;position:relative;white-space:nowrap}[dir=ltr] .md-nav--primary .md-nav__title .md-nav__icon{left:.4rem}[dir=rtl] .md-nav--primary .md-nav__title .md-nav__icon{right:.4rem}.md-nav--primary .md-nav__title .md-nav__icon{display:block;height:1.2rem;margin:.2rem;position:absolute;top:.4rem;width:1.2rem}.md-nav--primary .md-nav__title .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--prev);mask-image:var(--md-nav-icon--prev);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}.md-nav--primary .md-nav__title~.md-nav__list{background-color:var(--md-default-bg-color);box-shadow:0 .05rem 0 var(--md-default-fg-color--lightest) inset;overflow-y:auto;scroll-snap-type:y mandatory;touch-action:pan-y}.md-nav--primary .md-nav__title~.md-nav__list>:first-child{border-top:0}.md-nav--primary .md-nav__title[for=__drawer]{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);font-weight:700}.md-nav--primary .md-nav__title .md-logo{display:block;left:.2rem;margin:.2rem;padding:.4rem;position:absolute;right:.2rem;top:.2rem}.md-nav--primary .md-nav__list{flex:1}.md-nav--primary .md-nav__item{border-top:.05rem solid var(--md-default-fg-color--lightest);padding:0}.md-nav--primary .md-nav__item--active>.md-nav__link{color:var(--md-typeset-a-color)}.md-nav--primary .md-nav__item--active>.md-nav__link:-webkit-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-nav--primary .md-nav__item--active>.md-nav__link:-moz-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-nav--primary .md-nav__item--active>.md-nav__link:is(:focus,:hover){color:var(--md-accent-fg-color)}.md-nav--primary .md-nav__link{margin-top:0;padding:.6rem .8rem}[dir=ltr] .md-nav--primary .md-nav__link .md-nav__icon{margin-right:-.2rem}[dir=rtl] .md-nav--primary .md-nav__link .md-nav__icon{margin-left:-.2rem}.md-nav--primary .md-nav__link .md-nav__icon{font-size:1.2rem;height:1.2rem;width:1.2rem}.md-nav--primary .md-nav__link .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-nav--primary .md-nav__icon:after{transform:scale(-1)}.md-nav--primary .md-nav--secondary .md-nav{background-color:transparent;position:static}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-left:1.4rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-right:1.4rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-left:2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-right:2rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-left:2.6rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-right:2.6rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-left:3.2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-right:3.2rem}.md-nav--secondary{background-color:transparent}.md-nav__toggle~.md-nav{display:flex;opacity:0;transform:translateX(100%);transition:transform .25s cubic-bezier(.8,0,.6,1),opacity 125ms 50ms}[dir=rtl] .md-nav__toggle~.md-nav{transform:translateX(-100%)}.md-nav__toggle:checked~.md-nav{opacity:1;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 125ms 125ms}.md-nav__toggle:checked~.md-nav>.md-nav__list{-webkit-backface-visibility:hidden;backface-visibility:hidden}.md-nav .md-nav__title .md-ellipsis{white-space:nowrap}.md-nav .md-nav__title .md-ellipsis wbr{display:none}}@media screen and (max-width:59.9375em){.md-nav__current-nested{display:none}.md-nav--primary .md-nav__link[for=__toc]{display:flex}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--primary .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:flex}.md-nav__source{background-color:var(--md-primary-fg-color--dark);color:var(--md-primary-bg-color);display:block;padding:0 .2rem}}@media screen and (min-width:60em) and (max-width:76.1875em){.md-nav--integrated .md-nav__link[for=__toc]{display:flex}.md-nav--integrated .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--integrated .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--integrated .md-nav__link[for=__toc]~.md-nav{display:flex}}@media screen and (min-width:60em){.md-nav__current-toc{display:none}.md-nav--secondary .md-nav__title{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);position:sticky;top:0;z-index:1}.md-nav--secondary .md-nav__title[for=__toc]{scroll-snap-align:start}.md-nav--secondary .md-nav__title .md-nav__icon{display:none}}@media screen and (min-width:76.25em){.md-nav{transition:max-height .25s cubic-bezier(.86,0,.07,1)}.md-nav--primary .md-nav__title{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);position:sticky;top:0;z-index:1}.md-nav--primary .md-nav__title[for=__drawer]{scroll-snap-align:start}.md-nav--primary .md-nav__title .md-nav__icon,.md-nav__toggle~.md-nav{display:none}.md-nav__toggle:-webkit-any(:checked,:indeterminate)~.md-nav{display:block}.md-nav__toggle:-moz-any(:checked,:indeterminate)~.md-nav{display:block}.md-nav__toggle:is(:checked,:indeterminate)~.md-nav{display:block}.md-nav__item--nested>.md-nav>.md-nav__title{display:none}.md-nav__item--section{display:block;margin:1.25em 0}.md-nav__item--section:last-child{margin-bottom:0}.md-nav__item--section>.md-nav__link{font-weight:700;pointer-events:none}.md-nav__item--section>.md-nav__link--index [href]{pointer-events:auto}.md-nav__item--section>.md-nav__link .md-nav__icon{display:none}.md-nav__item--section>.md-nav{display:block}.md-nav__item--section>.md-nav>.md-nav__list>.md-nav__item{padding:0}.md-nav__icon{border-radius:100%;height:.9rem;transition:background-color .25s,transform .25s;width:.9rem}[dir=rtl] .md-nav__icon{transform:rotate(180deg)}.md-nav__icon:hover{background-color:var(--md-accent-fg-color--transparent)}.md-nav__icon:after{background-color:currentcolor;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:-.1rem;width:100%}.md-nav__item--nested .md-nav__toggle:checked~.md-nav__link .md-nav__icon,.md-nav__item--nested .md-nav__toggle:indeterminate~.md-nav__link .md-nav__icon{transform:rotate(90deg)}.md-nav--lifted>.md-nav__list>.md-nav__item,.md-nav--lifted>.md-nav__list>.md-nav__item--nested,.md-nav--lifted>.md-nav__title{display:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active{display:block;padding:0}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);font-weight:700;margin-top:0;padding:0 .6rem;position:sticky;top:0;z-index:var(--md-nav__sticky-zindex,1)}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link:not(.md-nav__link--index){pointer-events:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link .md-nav__icon{display:none}.md-nav--lifted .md-nav[data-md-level="1"]{display:block}[dir=ltr] .md-nav--lifted .md-nav[data-md-level="1"]>.md-nav__list>.md-nav__item{padding-right:.6rem}[dir=rtl] .md-nav--lifted .md-nav[data-md-level="1"]>.md-nav__list>.md-nav__item{padding-left:.6rem}.md-nav--integrated>.md-nav__list>.md-nav__item--active:not(.md-nav__item--nested){padding:0 .6rem}.md-nav--integrated>.md-nav__list>.md-nav__item--active:not(.md-nav__item--nested)>.md-nav__link{padding:0}[dir=ltr] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-left:.05rem solid var(--md-primary-fg-color)}[dir=rtl] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-right:.05rem solid var(--md-primary-fg-color)}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{display:block;margin-bottom:1.25em}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__title{display:none}}:root{--md-search-result-icon:url('data:image/svg+xml;charset=utf-8,')}.md-search{position:relative}@media screen and (min-width:60em){.md-search{padding:.2rem 0}}.no-js .md-search{display:none}.md-search__overlay{opacity:0;z-index:1}@media screen and (max-width:59.9375em){[dir=ltr] .md-search__overlay{left:-2.2rem}[dir=rtl] .md-search__overlay{right:-2.2rem}.md-search__overlay{background-color:var(--md-default-bg-color);border-radius:1rem;height:2rem;overflow:hidden;pointer-events:none;position:absolute;top:-1rem;transform-origin:center;transition:transform .3s .1s,opacity .2s .2s;width:2rem}[data-md-toggle=search]:checked~.md-header .md-search__overlay{opacity:1;transition:transform .4s,opacity .1s}}@media screen and (min-width:60em){[dir=ltr] .md-search__overlay{left:0}[dir=rtl] .md-search__overlay{right:0}.md-search__overlay{background-color:rgba(0,0,0,.54);cursor:pointer;height:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0}[data-md-toggle=search]:checked~.md-header .md-search__overlay{height:200vh;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@media screen and (max-width:29.9375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(45)}}@media screen and (min-width:30em) and (max-width:44.9375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(60)}}@media screen and (min-width:45em) and (max-width:59.9375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(75)}}.md-search__inner{-webkit-backface-visibility:hidden;backface-visibility:hidden}@media screen and (max-width:59.9375em){[dir=ltr] .md-search__inner{left:0}[dir=rtl] .md-search__inner{right:0}.md-search__inner{height:0;opacity:0;overflow:hidden;position:fixed;top:0;transform:translateX(5%);transition:width 0ms .3s,height 0ms .3s,transform .15s cubic-bezier(.4,0,.2,1) .15s,opacity .15s .15s;width:0;z-index:2}[dir=rtl] .md-search__inner{transform:translateX(-5%)}[data-md-toggle=search]:checked~.md-header .md-search__inner{height:100%;opacity:1;transform:translateX(0);transition:width 0ms 0ms,height 0ms 0ms,transform .15s cubic-bezier(.1,.7,.1,1) .15s,opacity .15s .15s;width:100%}}@media screen and (min-width:60em){[dir=ltr] .md-search__inner{float:right}[dir=rtl] .md-search__inner{float:left}.md-search__inner{padding:.1rem 0;position:relative;transition:width .25s cubic-bezier(.1,.7,.1,1);width:11.7rem}}@media screen and (min-width:60em) and (max-width:76.1875em){[data-md-toggle=search]:checked~.md-header .md-search__inner{width:23.4rem}}@media screen and (min-width:76.25em){[data-md-toggle=search]:checked~.md-header .md-search__inner{width:34.4rem}}.md-search__form{background-color:var(--md-default-bg-color);box-shadow:0 0 .6rem transparent;height:2.4rem;position:relative;transition:color .25s,background-color .25s;z-index:2}@media screen and (min-width:60em){.md-search__form{background-color:rgba(0,0,0,.26);border-radius:.1rem;height:1.8rem}.md-search__form:hover{background-color:hsla(0,0%,100%,.12)}}[data-md-toggle=search]:checked~.md-header .md-search__form{background-color:var(--md-default-bg-color);border-radius:.1rem .1rem 0 0;box-shadow:0 0 .6rem rgba(0,0,0,.07);color:var(--md-default-fg-color)}[dir=ltr] .md-search__input{padding-left:3.6rem;padding-right:2.2rem}[dir=rtl] .md-search__input{padding-left:2.2rem;padding-right:3.6rem}.md-search__input{background:transparent;font-size:.9rem;height:100%;position:relative;text-overflow:ellipsis;width:100%;z-index:2}.md-search__input::-moz-placeholder{-moz-transition:color .25s;transition:color .25s}.md-search__input::placeholder{transition:color .25s}.md-search__input::-moz-placeholder{color:var(--md-default-fg-color--light)}.md-search__input::placeholder,.md-search__input~.md-search__icon{color:var(--md-default-fg-color--light)}.md-search__input::-ms-clear{display:none}@media screen and (max-width:59.9375em){.md-search__input{font-size:.9rem;height:2.4rem;width:100%}}@media screen and (min-width:60em){[dir=ltr] .md-search__input{padding-left:2.2rem}[dir=rtl] .md-search__input{padding-right:2.2rem}.md-search__input{color:inherit;font-size:.8rem}.md-search__input::-moz-placeholder{color:var(--md-primary-bg-color--light)}.md-search__input::placeholder{color:var(--md-primary-bg-color--light)}.md-search__input+.md-search__icon{color:var(--md-primary-bg-color)}[data-md-toggle=search]:checked~.md-header .md-search__input{text-overflow:clip}[data-md-toggle=search]:checked~.md-header .md-search__input::-moz-placeholder{color:var(--md-default-fg-color--light)}[data-md-toggle=search]:checked~.md-header .md-search__input+.md-search__icon,[data-md-toggle=search]:checked~.md-header .md-search__input::placeholder{color:var(--md-default-fg-color--light)}}.md-search__icon{cursor:pointer;display:inline-block;height:1.2rem;transition:color .25s,opacity .25s;width:1.2rem}.md-search__icon:hover{opacity:.7}[dir=ltr] .md-search__icon[for=__search]{left:.5rem}[dir=rtl] .md-search__icon[for=__search]{right:.5rem}.md-search__icon[for=__search]{position:absolute;top:.3rem;z-index:2}[dir=rtl] .md-search__icon[for=__search] svg{transform:scaleX(-1)}@media screen and (max-width:59.9375em){[dir=ltr] .md-search__icon[for=__search]{left:.8rem}[dir=rtl] .md-search__icon[for=__search]{right:.8rem}.md-search__icon[for=__search]{top:.6rem}.md-search__icon[for=__search] svg:first-child{display:none}}@media screen and (min-width:60em){.md-search__icon[for=__search]{pointer-events:none}.md-search__icon[for=__search] svg:last-child{display:none}}[dir=ltr] .md-search__options{right:.5rem}[dir=rtl] .md-search__options{left:.5rem}.md-search__options{pointer-events:none;position:absolute;top:.3rem;z-index:2}@media screen and (max-width:59.9375em){[dir=ltr] .md-search__options{right:.8rem}[dir=rtl] .md-search__options{left:.8rem}.md-search__options{top:.6rem}}[dir=ltr] .md-search__options>*{margin-left:.2rem}[dir=rtl] .md-search__options>*{margin-right:.2rem}.md-search__options>*{color:var(--md-default-fg-color--light);opacity:0;transform:scale(.75);transition:transform .15s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-search__options>:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__options>*{opacity:1;pointer-events:auto;transform:scale(1)}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__options>:hover{opacity:.7}[dir=ltr] .md-search__suggest{padding-left:3.6rem;padding-right:2.2rem}[dir=rtl] .md-search__suggest{padding-left:2.2rem;padding-right:3.6rem}.md-search__suggest{align-items:center;color:var(--md-default-fg-color--lighter);display:flex;font-size:.9rem;height:100%;opacity:0;position:absolute;top:0;transition:opacity 50ms;white-space:nowrap;width:100%}@media screen and (min-width:60em){[dir=ltr] .md-search__suggest{padding-left:2.2rem}[dir=rtl] .md-search__suggest{padding-right:2.2rem}.md-search__suggest{font-size:.8rem}}[data-md-toggle=search]:checked~.md-header .md-search__suggest{opacity:1;transition:opacity .3s .1s}[dir=ltr] .md-search__output{border-bottom-left-radius:.1rem}[dir=ltr] .md-search__output,[dir=rtl] .md-search__output{border-bottom-right-radius:.1rem}[dir=rtl] .md-search__output{border-bottom-left-radius:.1rem}.md-search__output{overflow:hidden;position:absolute;width:100%;z-index:1}@media screen and (max-width:59.9375em){.md-search__output{bottom:0;top:2.4rem}}@media screen and (min-width:60em){.md-search__output{opacity:0;top:1.9rem;transition:opacity .4s}[data-md-toggle=search]:checked~.md-header .md-search__output{box-shadow:var(--md-shadow-z3);opacity:1}}.md-search__scrollwrap{-webkit-backface-visibility:hidden;backface-visibility:hidden;background-color:var(--md-default-bg-color);height:100%;overflow-y:auto;touch-action:pan-y}@media (-webkit-max-device-pixel-ratio:1),(max-resolution:1dppx){.md-search__scrollwrap{transform:translateZ(0)}}@media screen and (min-width:60em) and (max-width:76.1875em){.md-search__scrollwrap{width:23.4rem}}@media screen and (min-width:76.25em){.md-search__scrollwrap{width:34.4rem}}@media screen and (min-width:60em){.md-search__scrollwrap{max-height:0;scrollbar-color:var(--md-default-fg-color--lighter) transparent;scrollbar-width:thin}[data-md-toggle=search]:checked~.md-header .md-search__scrollwrap{max-height:75vh}.md-search__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) transparent}.md-search__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-search__scrollwrap::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}}.md-search-result{color:var(--md-default-fg-color);word-break:break-word}.md-search-result__meta{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light);font-size:.64rem;line-height:1.8rem;padding:0 .8rem;scroll-snap-align:start}@media screen and (min-width:60em){[dir=ltr] .md-search-result__meta{padding-left:2.2rem}[dir=rtl] .md-search-result__meta{padding-right:2.2rem}}.md-search-result__list{list-style:none;margin:0;padding:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.md-search-result__item{box-shadow:0 -.05rem var(--md-default-fg-color--lightest)}.md-search-result__item:first-child{box-shadow:none}.md-search-result__link{display:block;outline:none;scroll-snap-align:start;transition:background-color .25s}.md-search-result__link:-webkit-any(:focus,:hover){background-color:var(--md-accent-fg-color--transparent)}.md-search-result__link:-moz-any(:focus,:hover){background-color:var(--md-accent-fg-color--transparent)}.md-search-result__link:is(:focus,:hover){background-color:var(--md-accent-fg-color--transparent)}.md-search-result__link:last-child p:last-child{margin-bottom:.6rem}.md-search-result__more summary{color:var(--md-typeset-a-color);cursor:pointer;display:block;font-size:.64rem;outline:none;padding:.75em .8rem;scroll-snap-align:start;transition:color .25s,background-color .25s}@media screen and (min-width:60em){[dir=ltr] .md-search-result__more summary{padding-left:2.2rem}[dir=rtl] .md-search-result__more summary{padding-right:2.2rem}}.md-search-result__more summary:-webkit-any(:focus,:hover){background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-search-result__more summary:-moz-any(:focus,:hover){background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-search-result__more summary:is(:focus,:hover){background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-search-result__more summary::marker{display:none}.md-search-result__more summary::-webkit-details-marker{display:none}.md-search-result__more summary~*>*{opacity:.65}.md-search-result__article{overflow:hidden;padding:0 .8rem;position:relative}@media screen and (min-width:60em){[dir=ltr] .md-search-result__article{padding-left:2.2rem}[dir=rtl] .md-search-result__article{padding-right:2.2rem}}.md-search-result__article--document .md-search-result__title{font-size:.8rem;font-weight:400;line-height:1.4;margin:.55rem 0}[dir=ltr] .md-search-result__icon{left:0}[dir=rtl] .md-search-result__icon{right:0}.md-search-result__icon{color:var(--md-default-fg-color--light);height:1.2rem;margin:.5rem;position:absolute;width:1.2rem}@media screen and (max-width:59.9375em){.md-search-result__icon{display:none}}.md-search-result__icon:after{background-color:currentcolor;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-search-result-icon);mask-image:var(--md-search-result-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-search-result__icon:after{transform:scaleX(-1)}.md-search-result__title{font-size:.64rem;font-weight:700;line-height:1.6;margin:.5em 0}.md-search-result__teaser{-webkit-box-orient:vertical;-webkit-line-clamp:2;color:var(--md-default-fg-color--light);display:-webkit-box;font-size:.64rem;line-height:1.6;margin:.5em 0;max-height:2rem;overflow:hidden;text-overflow:ellipsis}@media screen and (max-width:44.9375em){.md-search-result__teaser{-webkit-line-clamp:3;max-height:3rem}}@media screen and (min-width:60em) and (max-width:76.1875em){.md-search-result__teaser{-webkit-line-clamp:3;max-height:3rem}}.md-search-result__teaser mark{background-color:transparent;text-decoration:underline}.md-search-result__terms{font-size:.64rem;font-style:italic;margin:.5em 0}.md-search-result mark{background-color:transparent;color:var(--md-accent-fg-color)}.md-select{position:relative;z-index:1}.md-select__inner{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);left:50%;margin-top:.2rem;max-height:0;opacity:0;position:absolute;top:calc(100% - .2rem);transform:translate3d(-50%,.3rem,0);transition:transform .25s 375ms,opacity .25s .25s,max-height 0ms .5s}.md-select:-webkit-any(:focus-within,:hover) .md-select__inner{max-height:10rem;opacity:1;transform:translate3d(-50%,0,0);-webkit-transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms;transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms}.md-select:-moz-any(:focus-within,:hover) .md-select__inner{max-height:10rem;opacity:1;transform:translate3d(-50%,0,0);-moz-transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms;transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms}.md-select:is(:focus-within,:hover) .md-select__inner{max-height:10rem;opacity:1;transform:translate3d(-50%,0,0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms}.md-select__inner:after{border-bottom:.2rem solid transparent;border-bottom-color:var(--md-default-bg-color);border-left:.2rem solid transparent;border-right:.2rem solid transparent;border-top:0;content:"";height:0;left:50%;margin-left:-.2rem;margin-top:-.2rem;position:absolute;top:0;width:0}.md-select__list{border-radius:.1rem;font-size:.8rem;list-style-type:none;margin:0;max-height:inherit;overflow:auto;padding:0}.md-select__item{line-height:1.8rem}[dir=ltr] .md-select__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-select__link{padding-left:1.2rem;padding-right:.6rem}.md-select__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:background-color .25s,color .25s;width:100%}.md-select__link:-webkit-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-select__link:-moz-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-select__link:is(:focus,:hover){color:var(--md-accent-fg-color)}.md-select__link:focus{background-color:var(--md-default-fg-color--lightest)}.md-sidebar{align-self:flex-start;flex-shrink:0;padding:1.2rem 0;position:sticky;top:2.4rem;width:12.1rem}@media print{.md-sidebar{display:none}}@media screen and (max-width:76.1875em){[dir=ltr] .md-sidebar--primary{left:-12.1rem}[dir=rtl] .md-sidebar--primary{right:-12.1rem}.md-sidebar--primary{background-color:var(--md-default-bg-color);display:block;height:100%;position:fixed;top:0;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),box-shadow .25s;width:12.1rem;z-index:5}[data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{box-shadow:var(--md-shadow-z3);transform:translateX(12.1rem)}[dir=rtl] [data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{transform:translateX(-12.1rem)}.md-sidebar--primary .md-sidebar__scrollwrap{bottom:0;left:0;margin:0;overflow:hidden;position:absolute;right:0;scroll-snap-type:none;top:0}}@media screen and (min-width:76.25em){.md-sidebar{height:0}.no-js .md-sidebar{height:auto}.md-header--lifted~.md-container .md-sidebar{top:4.8rem}}.md-sidebar--secondary{display:none;order:2}@media screen and (min-width:60em){.md-sidebar--secondary{height:0}.no-js .md-sidebar--secondary{height:auto}.md-sidebar--secondary:not([hidden]){display:block}.md-sidebar--secondary .md-sidebar__scrollwrap{touch-action:pan-y}}.md-sidebar__scrollwrap{scrollbar-gutter:stable;-webkit-backface-visibility:hidden;backface-visibility:hidden;margin:0 .2rem;overflow-y:auto;scrollbar-color:var(--md-default-fg-color--lighter) transparent;scrollbar-width:thin}.md-sidebar__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) transparent}.md-sidebar__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-sidebar__scrollwrap::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}@supports selector(::-webkit-scrollbar){.md-sidebar__scrollwrap{scrollbar-gutter:auto}[dir=ltr] .md-sidebar__inner{padding-right:calc(100% - 11.5rem)}[dir=rtl] .md-sidebar__inner{padding-left:calc(100% - 11.5rem)}}@media screen and (max-width:76.1875em){.md-overlay{background-color:rgba(0,0,0,.54);height:0;opacity:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0;z-index:5}[data-md-toggle=drawer]:checked~.md-overlay{height:100%;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@keyframes facts{0%{height:0}to{height:.65rem}}@keyframes fact{0%{opacity:0;transform:translateY(100%)}50%{opacity:0}to{opacity:1;transform:translateY(0)}}:root{--md-source-forks-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-repositories-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-stars-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-source{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:block;font-size:.65rem;line-height:1.2;outline-color:var(--md-accent-fg-color);transition:opacity .25s;white-space:nowrap}.md-source:hover{opacity:.7}.md-source__icon{display:inline-block;height:2.4rem;vertical-align:middle;width:2rem}[dir=ltr] .md-source__icon svg{margin-left:.6rem}[dir=rtl] .md-source__icon svg{margin-right:.6rem}.md-source__icon svg{margin-top:.6rem}[dir=ltr] .md-source__icon+.md-source__repository{margin-left:-2rem}[dir=rtl] .md-source__icon+.md-source__repository{margin-right:-2rem}[dir=ltr] .md-source__icon+.md-source__repository{padding-left:2rem}[dir=rtl] .md-source__icon+.md-source__repository{padding-right:2rem}[dir=ltr] .md-source__repository{margin-left:.6rem}[dir=rtl] .md-source__repository{margin-right:.6rem}.md-source__repository{display:inline-block;max-width:calc(100% - 1.2rem);overflow:hidden;text-overflow:ellipsis;vertical-align:middle}.md-source__facts{display:flex;font-size:.55rem;gap:.4rem;list-style-type:none;margin:.1rem 0 0;opacity:.75;overflow:hidden;padding:0;width:100%}.md-source__repository--active .md-source__facts{animation:facts .25s ease-in}.md-source__fact{overflow:hidden;text-overflow:ellipsis}.md-source__repository--active .md-source__fact{animation:fact .4s ease-out}[dir=ltr] .md-source__fact:before{margin-right:.1rem}[dir=rtl] .md-source__fact:before{margin-left:.1rem}.md-source__fact:before{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-top;width:.6rem}.md-source__fact:nth-child(1n+2){flex-shrink:0}.md-source__fact--version:before{-webkit-mask-image:var(--md-source-version-icon);mask-image:var(--md-source-version-icon)}.md-source__fact--stars:before{-webkit-mask-image:var(--md-source-stars-icon);mask-image:var(--md-source-stars-icon)}.md-source__fact--forks:before{-webkit-mask-image:var(--md-source-forks-icon);mask-image:var(--md-source-forks-icon)}.md-source__fact--repositories:before{-webkit-mask-image:var(--md-source-repositories-icon);mask-image:var(--md-source-repositories-icon)}.md-tabs{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);display:block;line-height:1.3;overflow:auto;width:100%;z-index:3}@media print{.md-tabs{display:none}}@media screen and (max-width:76.1875em){.md-tabs{display:none}}.md-tabs[hidden]{pointer-events:none}[dir=ltr] .md-tabs__list{margin-left:.2rem}[dir=rtl] .md-tabs__list{margin-right:.2rem}.md-tabs__list{contain:content;list-style:none;margin:0;padding:0;white-space:nowrap}.md-tabs__item{display:inline-block;height:2.4rem;padding-left:.6rem;padding-right:.6rem}.md-tabs__link{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:block;font-size:.7rem;margin-top:.8rem;opacity:.7;outline-color:var(--md-accent-fg-color);outline-offset:.2rem;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .25s}.md-tabs__link--active,.md-tabs__link:-webkit-any(:focus,:hover){color:inherit;opacity:1}.md-tabs__link--active,.md-tabs__link:-moz-any(:focus,:hover){color:inherit;opacity:1}.md-tabs__link--active,.md-tabs__link:is(:focus,:hover){color:inherit;opacity:1}.md-tabs__item:nth-child(2) .md-tabs__link{transition-delay:20ms}.md-tabs__item:nth-child(3) .md-tabs__link{transition-delay:40ms}.md-tabs__item:nth-child(4) .md-tabs__link{transition-delay:60ms}.md-tabs__item:nth-child(5) .md-tabs__link{transition-delay:80ms}.md-tabs__item:nth-child(6) .md-tabs__link{transition-delay:.1s}.md-tabs__item:nth-child(7) .md-tabs__link{transition-delay:.12s}.md-tabs__item:nth-child(8) .md-tabs__link{transition-delay:.14s}.md-tabs__item:nth-child(9) .md-tabs__link{transition-delay:.16s}.md-tabs__item:nth-child(10) .md-tabs__link{transition-delay:.18s}.md-tabs__item:nth-child(11) .md-tabs__link{transition-delay:.2s}.md-tabs__item:nth-child(12) .md-tabs__link{transition-delay:.22s}.md-tabs__item:nth-child(13) .md-tabs__link{transition-delay:.24s}.md-tabs__item:nth-child(14) .md-tabs__link{transition-delay:.26s}.md-tabs__item:nth-child(15) .md-tabs__link{transition-delay:.28s}.md-tabs__item:nth-child(16) .md-tabs__link{transition-delay:.3s}.md-tabs[hidden] .md-tabs__link{opacity:0;transform:translateY(50%);transition:transform 0ms .1s,opacity .1s}:root{--md-tag-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .md-tags{margin-bottom:.75em;margin-top:-.125em}[dir=ltr] .md-typeset .md-tag{margin-right:.5em}[dir=rtl] .md-typeset .md-tag{margin-left:.5em}.md-typeset .md-tag{background:var(--md-default-fg-color--lightest);border-radius:2.4rem;display:inline-block;font-size:.64rem;font-weight:700;letter-spacing:normal;line-height:1.6;margin-bottom:.5em;padding:.3125em .9375em;vertical-align:middle}.md-typeset .md-tag[href]{-webkit-tap-highlight-color:transparent;color:inherit;outline:none;transition:color 125ms,background-color 125ms}.md-typeset .md-tag[href]:focus,.md-typeset .md-tag[href]:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[id]>.md-typeset .md-tag{vertical-align:text-top}.md-typeset .md-tag-icon:before{background-color:var(--md-default-fg-color--lighter);content:"";display:inline-block;height:1.2em;margin-right:.4em;-webkit-mask-image:var(--md-tag-icon);mask-image:var(--md-tag-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset .md-tag-icon:-webkit-any(a:focus,a:hover):before{background-color:var(--md-accent-bg-color)}.md-typeset .md-tag-icon:-moz-any(a:focus,a:hover):before{background-color:var(--md-accent-bg-color)}.md-typeset .md-tag-icon:is(a:focus,a:hover):before{background-color:var(--md-accent-bg-color)}@keyframes pulse{0%{box-shadow:0 0 0 0 var(--md-default-fg-color--lightest);transform:scale(.95)}75%{box-shadow:0 0 0 .625em transparent;transform:scale(1)}to{box-shadow:0 0 0 0 transparent;transform:scale(.95)}}:root{--md-tooltip-width:20rem}.md-tooltip{-webkit-backface-visibility:hidden;backface-visibility:hidden;background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);font-family:var(--md-text-font-family);left:clamp(var(--md-tooltip-0,0rem) + .8rem,var(--md-tooltip-x),100vw + var(--md-tooltip-0,0rem) + .8rem - var(--md-tooltip-width) - 2 * .8rem);max-width:calc(100vw - 1.6rem);opacity:0;position:absolute;top:var(--md-tooltip-y);transform:translateY(-.4rem);transition:transform 0ms .25s,opacity .25s,z-index .25s;width:var(--md-tooltip-width);z-index:0}.md-tooltip--active{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,z-index 0ms;z-index:2}:-webkit-any(.focus-visible>.md-tooltip,.md-tooltip:target){outline:var(--md-accent-fg-color) auto}:-moz-any(.focus-visible>.md-tooltip,.md-tooltip:target){outline:var(--md-accent-fg-color) auto}:is(.focus-visible>.md-tooltip,.md-tooltip:target){outline:var(--md-accent-fg-color) auto}.md-tooltip__inner{font-size:.64rem;padding:.8rem}.md-tooltip__inner.md-typeset>:first-child{margin-top:0}.md-tooltip__inner.md-typeset>:last-child{margin-bottom:0}.md-annotation{font-weight:400;outline:none;white-space:normal}[dir=rtl] .md-annotation{direction:rtl}.md-annotation:not([hidden]){display:inline-block;line-height:1.325}.md-annotation__index{cursor:pointer;font-family:var(--md-code-font-family);font-size:.85em;margin:0 1ch;outline:none;position:relative;-webkit-user-select:none;-moz-user-select:none;user-select:none;z-index:0}.md-annotation .md-annotation__index{color:#fff;transition:z-index .25s}.md-annotation .md-annotation__index:-webkit-any(:focus,:hover){color:#fff}.md-annotation .md-annotation__index:-moz-any(:focus,:hover){color:#fff}.md-annotation .md-annotation__index:is(:focus,:hover){color:#fff}.md-annotation__index:after{background-color:var(--md-default-fg-color--lighter);border-radius:2ch;content:"";height:2.2ch;left:-.125em;margin:0 -.4ch;padding:0 .4ch;position:absolute;top:0;transition:color .25s,background-color .25s;width:calc(100% + 1.2ch);width:max(2.2ch,100% + 1.2ch);z-index:-1}@media not all and (prefers-reduced-motion){[data-md-visible]>.md-annotation__index:after{animation:pulse 2s infinite}}.md-tooltip--active+.md-annotation__index:after{animation:none;transition:color .25s,background-color .25s}code .md-annotation__index{font-family:var(--md-code-font-family);font-size:inherit}:-webkit-any(.md-tooltip--active+.md-annotation__index,:hover>.md-annotation__index){color:var(--md-accent-bg-color)}:-moz-any(.md-tooltip--active+.md-annotation__index,:hover>.md-annotation__index){color:var(--md-accent-bg-color)}:is(.md-tooltip--active+.md-annotation__index,:hover>.md-annotation__index){color:var(--md-accent-bg-color)}:-webkit-any(.md-tooltip--active+.md-annotation__index,:hover>.md-annotation__index):after{background-color:var(--md-accent-fg-color)}:-moz-any(.md-tooltip--active+.md-annotation__index,:hover>.md-annotation__index):after{background-color:var(--md-accent-fg-color)}:is(.md-tooltip--active+.md-annotation__index,:hover>.md-annotation__index):after{background-color:var(--md-accent-fg-color)}.md-tooltip--active+.md-annotation__index{animation:none;transition:none;z-index:2}.md-annotation__index [data-md-annotation-id]{display:inline-block;line-height:90%}.md-annotation__index [data-md-annotation-id]:before{content:attr(data-md-annotation-id);display:inline-block;padding-bottom:.1em;transform:scale(1.15);transition:transform .4s cubic-bezier(.1,.7,.1,1);vertical-align:.065em}@media not print{.md-annotation__index [data-md-annotation-id]:before{content:"+"}:focus-within>.md-annotation__index [data-md-annotation-id]:before{transform:scale(1.25) rotate(45deg)}}[dir=ltr] .md-top{margin-left:50%}[dir=rtl] .md-top{margin-right:50%}.md-top{background-color:var(--md-default-bg-color);border-radius:1.6rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color--light);display:block;font-size:.7rem;outline:none;padding:.4rem .8rem;position:fixed;top:3.2rem;transform:translate(-50%);transition:color 125ms,background-color 125ms,transform 125ms cubic-bezier(.4,0,.2,1),opacity 125ms;z-index:2}@media print{.md-top{display:none}}[dir=rtl] .md-top{transform:translate(50%)}.md-top[hidden]{opacity:0;pointer-events:none;transform:translate(-50%,.2rem);transition-duration:0ms}[dir=rtl] .md-top[hidden]{transform:translate(50%,.2rem)}.md-top:-webkit-any(:focus,:hover){background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-top:-moz-any(:focus,:hover){background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-top:is(:focus,:hover){background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-top svg{display:inline-block;vertical-align:-.5em}@keyframes hoverfix{0%{pointer-events:none}}:root{--md-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-version{flex-shrink:0;font-size:.8rem;height:2.4rem}[dir=ltr] .md-version__current{margin-left:1.4rem;margin-right:.4rem}[dir=rtl] .md-version__current{margin-left:.4rem;margin-right:1.4rem}.md-version__current{color:inherit;cursor:pointer;outline:none;position:relative;top:.05rem}[dir=ltr] .md-version__current:after{margin-left:.4rem}[dir=rtl] .md-version__current:after{margin-right:.4rem}.md-version__current:after{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-image:var(--md-version-icon);mask-image:var(--md-version-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.4rem}.md-version__list{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);list-style-type:none;margin:.2rem .8rem;max-height:0;opacity:0;overflow:auto;padding:0;position:absolute;scroll-snap-type:y mandatory;top:.15rem;transition:max-height 0ms .5s,opacity .25s .25s;z-index:3}.md-version:-webkit-any(:focus-within,:hover) .md-version__list{max-height:10rem;opacity:1;-webkit-transition:max-height 0ms,opacity .25s;transition:max-height 0ms,opacity .25s}.md-version:-moz-any(:focus-within,:hover) .md-version__list{max-height:10rem;opacity:1;-moz-transition:max-height 0ms,opacity .25s;transition:max-height 0ms,opacity .25s}.md-version:is(:focus-within,:hover) .md-version__list{max-height:10rem;opacity:1;transition:max-height 0ms,opacity .25s}@media (pointer:coarse){.md-version:hover .md-version__list{animation:hoverfix .25s forwards}.md-version:focus-within .md-version__list{animation:none}}.md-version__item{line-height:1.8rem}[dir=ltr] .md-version__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-version__link{padding-left:1.2rem;padding-right:.6rem}.md-version__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:color .25s,background-color .25s;white-space:nowrap;width:100%}.md-version__link:-webkit-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-version__link:-moz-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-version__link:is(:focus,:hover){color:var(--md-accent-fg-color)}.md-version__link:focus{background-color:var(--md-default-fg-color--lightest)}:root{--md-admonition-icon--note:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--abstract:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--info:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--tip:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--success:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--question:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--warning:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--failure:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--danger:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--bug:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--example:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--quote:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .admonition,.md-typeset details{background-color:var(--md-admonition-bg-color);border:.05rem solid #448aff;border-radius:.2rem;box-shadow:var(--md-shadow-z1);color:var(--md-admonition-fg-color);display:flow-root;font-size:.64rem;margin:1.5625em 0;padding:0 .6rem;page-break-inside:avoid}@media print{.md-typeset .admonition,.md-typeset details{box-shadow:none}}.md-typeset .admonition>*,.md-typeset details>*{box-sizing:border-box}.md-typeset .admonition :-webkit-any(.admonition,details),.md-typeset details :-webkit-any(.admonition,details){margin-bottom:1em;margin-top:1em}.md-typeset .admonition :-moz-any(.admonition,details),.md-typeset details :-moz-any(.admonition,details){margin-bottom:1em;margin-top:1em}.md-typeset .admonition :is(.admonition,details),.md-typeset details :is(.admonition,details){margin-bottom:1em;margin-top:1em}.md-typeset .admonition .md-typeset__scrollwrap,.md-typeset details .md-typeset__scrollwrap{margin:1em -.6rem}.md-typeset .admonition .md-typeset__table,.md-typeset details .md-typeset__table{padding:0 .6rem}.md-typeset .admonition>.tabbed-set:only-child,.md-typeset details>.tabbed-set:only-child{margin-top:0}html .md-typeset .admonition>:last-child,html .md-typeset details>:last-child{margin-bottom:.6rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{padding-left:2rem;padding-right:.6rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{padding-left:.6rem;padding-right:2rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{border-left-width:.2rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-right-width:.2rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{border-top-left-radius:.1rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary,[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-top-right-radius:.1rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-top-left-radius:.1rem}.md-typeset .admonition-title,.md-typeset summary{background-color:rgba(68,138,255,.1);border:none;font-weight:700;margin:0 -.6rem;padding-bottom:.4rem;padding-top:.4rem;position:relative}html .md-typeset .admonition-title:last-child,html .md-typeset summary:last-child{margin-bottom:0}[dir=ltr] .md-typeset .admonition-title:before,[dir=ltr] .md-typeset summary:before{left:.6rem}[dir=rtl] .md-typeset .admonition-title:before,[dir=rtl] .md-typeset summary:before{right:.6rem}.md-typeset .admonition-title:before,.md-typeset summary:before{background-color:#448aff;content:"";height:1rem;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;width:1rem}.md-typeset .admonition-title code,.md-typeset summary code{box-shadow:0 0 0 .05rem var(--md-default-fg-color--lightest)}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.note){border-color:#448aff}.md-typeset :-moz-any(.admonition,details):-moz-any(.note){border-color:#448aff}.md-typeset :is(.admonition,details):is(.note){border-color:#448aff}.md-typeset :-webkit-any(.note)>:-webkit-any(.admonition-title,summary){background-color:rgba(68,138,255,.1)}.md-typeset :-moz-any(.note)>:-moz-any(.admonition-title,summary){background-color:rgba(68,138,255,.1)}.md-typeset :is(.note)>:is(.admonition-title,summary){background-color:rgba(68,138,255,.1)}.md-typeset :-webkit-any(.note)>:-webkit-any(.admonition-title,summary):before{background-color:#448aff;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note)}.md-typeset :-moz-any(.note)>:-moz-any(.admonition-title,summary):before{background-color:#448aff;mask-image:var(--md-admonition-icon--note)}.md-typeset :is(.note)>:is(.admonition-title,summary):before{background-color:#448aff;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note)}.md-typeset :-webkit-any(.note)>:-webkit-any(.admonition-title,summary):after{color:#448aff}.md-typeset :-moz-any(.note)>:-moz-any(.admonition-title,summary):after{color:#448aff}.md-typeset :is(.note)>:is(.admonition-title,summary):after{color:#448aff}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.abstract,.summary,.tldr){border-color:#00b0ff}.md-typeset :-moz-any(.admonition,details):-moz-any(.abstract,.summary,.tldr){border-color:#00b0ff}.md-typeset :is(.admonition,details):is(.abstract,.summary,.tldr){border-color:#00b0ff}.md-typeset :-webkit-any(.abstract,.summary,.tldr)>:-webkit-any(.admonition-title,summary){background-color:rgba(0,176,255,.1)}.md-typeset :-moz-any(.abstract,.summary,.tldr)>:-moz-any(.admonition-title,summary){background-color:rgba(0,176,255,.1)}.md-typeset :is(.abstract,.summary,.tldr)>:is(.admonition-title,summary){background-color:rgba(0,176,255,.1)}.md-typeset :-webkit-any(.abstract,.summary,.tldr)>:-webkit-any(.admonition-title,summary):before{background-color:#00b0ff;-webkit-mask-image:var(--md-admonition-icon--abstract);mask-image:var(--md-admonition-icon--abstract)}.md-typeset :-moz-any(.abstract,.summary,.tldr)>:-moz-any(.admonition-title,summary):before{background-color:#00b0ff;mask-image:var(--md-admonition-icon--abstract)}.md-typeset :is(.abstract,.summary,.tldr)>:is(.admonition-title,summary):before{background-color:#00b0ff;-webkit-mask-image:var(--md-admonition-icon--abstract);mask-image:var(--md-admonition-icon--abstract)}.md-typeset :-webkit-any(.abstract,.summary,.tldr)>:-webkit-any(.admonition-title,summary):after{color:#00b0ff}.md-typeset :-moz-any(.abstract,.summary,.tldr)>:-moz-any(.admonition-title,summary):after{color:#00b0ff}.md-typeset :is(.abstract,.summary,.tldr)>:is(.admonition-title,summary):after{color:#00b0ff}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.info,.todo){border-color:#00b8d4}.md-typeset :-moz-any(.admonition,details):-moz-any(.info,.todo){border-color:#00b8d4}.md-typeset :is(.admonition,details):is(.info,.todo){border-color:#00b8d4}.md-typeset :-webkit-any(.info,.todo)>:-webkit-any(.admonition-title,summary){background-color:rgba(0,184,212,.1)}.md-typeset :-moz-any(.info,.todo)>:-moz-any(.admonition-title,summary){background-color:rgba(0,184,212,.1)}.md-typeset :is(.info,.todo)>:is(.admonition-title,summary){background-color:rgba(0,184,212,.1)}.md-typeset :-webkit-any(.info,.todo)>:-webkit-any(.admonition-title,summary):before{background-color:#00b8d4;-webkit-mask-image:var(--md-admonition-icon--info);mask-image:var(--md-admonition-icon--info)}.md-typeset :-moz-any(.info,.todo)>:-moz-any(.admonition-title,summary):before{background-color:#00b8d4;mask-image:var(--md-admonition-icon--info)}.md-typeset :is(.info,.todo)>:is(.admonition-title,summary):before{background-color:#00b8d4;-webkit-mask-image:var(--md-admonition-icon--info);mask-image:var(--md-admonition-icon--info)}.md-typeset :-webkit-any(.info,.todo)>:-webkit-any(.admonition-title,summary):after{color:#00b8d4}.md-typeset :-moz-any(.info,.todo)>:-moz-any(.admonition-title,summary):after{color:#00b8d4}.md-typeset :is(.info,.todo)>:is(.admonition-title,summary):after{color:#00b8d4}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.tip,.hint,.important){border-color:#00bfa5}.md-typeset :-moz-any(.admonition,details):-moz-any(.tip,.hint,.important){border-color:#00bfa5}.md-typeset :is(.admonition,details):is(.tip,.hint,.important){border-color:#00bfa5}.md-typeset :-webkit-any(.tip,.hint,.important)>:-webkit-any(.admonition-title,summary){background-color:rgba(0,191,165,.1)}.md-typeset :-moz-any(.tip,.hint,.important)>:-moz-any(.admonition-title,summary){background-color:rgba(0,191,165,.1)}.md-typeset :is(.tip,.hint,.important)>:is(.admonition-title,summary){background-color:rgba(0,191,165,.1)}.md-typeset :-webkit-any(.tip,.hint,.important)>:-webkit-any(.admonition-title,summary):before{background-color:#00bfa5;-webkit-mask-image:var(--md-admonition-icon--tip);mask-image:var(--md-admonition-icon--tip)}.md-typeset :-moz-any(.tip,.hint,.important)>:-moz-any(.admonition-title,summary):before{background-color:#00bfa5;mask-image:var(--md-admonition-icon--tip)}.md-typeset :is(.tip,.hint,.important)>:is(.admonition-title,summary):before{background-color:#00bfa5;-webkit-mask-image:var(--md-admonition-icon--tip);mask-image:var(--md-admonition-icon--tip)}.md-typeset :-webkit-any(.tip,.hint,.important)>:-webkit-any(.admonition-title,summary):after{color:#00bfa5}.md-typeset :-moz-any(.tip,.hint,.important)>:-moz-any(.admonition-title,summary):after{color:#00bfa5}.md-typeset :is(.tip,.hint,.important)>:is(.admonition-title,summary):after{color:#00bfa5}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.success,.check,.done){border-color:#00c853}.md-typeset :-moz-any(.admonition,details):-moz-any(.success,.check,.done){border-color:#00c853}.md-typeset :is(.admonition,details):is(.success,.check,.done){border-color:#00c853}.md-typeset :-webkit-any(.success,.check,.done)>:-webkit-any(.admonition-title,summary){background-color:rgba(0,200,83,.1)}.md-typeset :-moz-any(.success,.check,.done)>:-moz-any(.admonition-title,summary){background-color:rgba(0,200,83,.1)}.md-typeset :is(.success,.check,.done)>:is(.admonition-title,summary){background-color:rgba(0,200,83,.1)}.md-typeset :-webkit-any(.success,.check,.done)>:-webkit-any(.admonition-title,summary):before{background-color:#00c853;-webkit-mask-image:var(--md-admonition-icon--success);mask-image:var(--md-admonition-icon--success)}.md-typeset :-moz-any(.success,.check,.done)>:-moz-any(.admonition-title,summary):before{background-color:#00c853;mask-image:var(--md-admonition-icon--success)}.md-typeset :is(.success,.check,.done)>:is(.admonition-title,summary):before{background-color:#00c853;-webkit-mask-image:var(--md-admonition-icon--success);mask-image:var(--md-admonition-icon--success)}.md-typeset :-webkit-any(.success,.check,.done)>:-webkit-any(.admonition-title,summary):after{color:#00c853}.md-typeset :-moz-any(.success,.check,.done)>:-moz-any(.admonition-title,summary):after{color:#00c853}.md-typeset :is(.success,.check,.done)>:is(.admonition-title,summary):after{color:#00c853}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.question,.help,.faq){border-color:#64dd17}.md-typeset :-moz-any(.admonition,details):-moz-any(.question,.help,.faq){border-color:#64dd17}.md-typeset :is(.admonition,details):is(.question,.help,.faq){border-color:#64dd17}.md-typeset :-webkit-any(.question,.help,.faq)>:-webkit-any(.admonition-title,summary){background-color:rgba(100,221,23,.1)}.md-typeset :-moz-any(.question,.help,.faq)>:-moz-any(.admonition-title,summary){background-color:rgba(100,221,23,.1)}.md-typeset :is(.question,.help,.faq)>:is(.admonition-title,summary){background-color:rgba(100,221,23,.1)}.md-typeset :-webkit-any(.question,.help,.faq)>:-webkit-any(.admonition-title,summary):before{background-color:#64dd17;-webkit-mask-image:var(--md-admonition-icon--question);mask-image:var(--md-admonition-icon--question)}.md-typeset :-moz-any(.question,.help,.faq)>:-moz-any(.admonition-title,summary):before{background-color:#64dd17;mask-image:var(--md-admonition-icon--question)}.md-typeset :is(.question,.help,.faq)>:is(.admonition-title,summary):before{background-color:#64dd17;-webkit-mask-image:var(--md-admonition-icon--question);mask-image:var(--md-admonition-icon--question)}.md-typeset :-webkit-any(.question,.help,.faq)>:-webkit-any(.admonition-title,summary):after{color:#64dd17}.md-typeset :-moz-any(.question,.help,.faq)>:-moz-any(.admonition-title,summary):after{color:#64dd17}.md-typeset :is(.question,.help,.faq)>:is(.admonition-title,summary):after{color:#64dd17}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.warning,.caution,.attention){border-color:#ff9100}.md-typeset :-moz-any(.admonition,details):-moz-any(.warning,.caution,.attention){border-color:#ff9100}.md-typeset :is(.admonition,details):is(.warning,.caution,.attention){border-color:#ff9100}.md-typeset :-webkit-any(.warning,.caution,.attention)>:-webkit-any(.admonition-title,summary){background-color:rgba(255,145,0,.1)}.md-typeset :-moz-any(.warning,.caution,.attention)>:-moz-any(.admonition-title,summary){background-color:rgba(255,145,0,.1)}.md-typeset :is(.warning,.caution,.attention)>:is(.admonition-title,summary){background-color:rgba(255,145,0,.1)}.md-typeset :-webkit-any(.warning,.caution,.attention)>:-webkit-any(.admonition-title,summary):before{background-color:#ff9100;-webkit-mask-image:var(--md-admonition-icon--warning);mask-image:var(--md-admonition-icon--warning)}.md-typeset :-moz-any(.warning,.caution,.attention)>:-moz-any(.admonition-title,summary):before{background-color:#ff9100;mask-image:var(--md-admonition-icon--warning)}.md-typeset :is(.warning,.caution,.attention)>:is(.admonition-title,summary):before{background-color:#ff9100;-webkit-mask-image:var(--md-admonition-icon--warning);mask-image:var(--md-admonition-icon--warning)}.md-typeset :-webkit-any(.warning,.caution,.attention)>:-webkit-any(.admonition-title,summary):after{color:#ff9100}.md-typeset :-moz-any(.warning,.caution,.attention)>:-moz-any(.admonition-title,summary):after{color:#ff9100}.md-typeset :is(.warning,.caution,.attention)>:is(.admonition-title,summary):after{color:#ff9100}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.failure,.fail,.missing){border-color:#ff5252}.md-typeset :-moz-any(.admonition,details):-moz-any(.failure,.fail,.missing){border-color:#ff5252}.md-typeset :is(.admonition,details):is(.failure,.fail,.missing){border-color:#ff5252}.md-typeset :-webkit-any(.failure,.fail,.missing)>:-webkit-any(.admonition-title,summary){background-color:rgba(255,82,82,.1)}.md-typeset :-moz-any(.failure,.fail,.missing)>:-moz-any(.admonition-title,summary){background-color:rgba(255,82,82,.1)}.md-typeset :is(.failure,.fail,.missing)>:is(.admonition-title,summary){background-color:rgba(255,82,82,.1)}.md-typeset :-webkit-any(.failure,.fail,.missing)>:-webkit-any(.admonition-title,summary):before{background-color:#ff5252;-webkit-mask-image:var(--md-admonition-icon--failure);mask-image:var(--md-admonition-icon--failure)}.md-typeset :-moz-any(.failure,.fail,.missing)>:-moz-any(.admonition-title,summary):before{background-color:#ff5252;mask-image:var(--md-admonition-icon--failure)}.md-typeset :is(.failure,.fail,.missing)>:is(.admonition-title,summary):before{background-color:#ff5252;-webkit-mask-image:var(--md-admonition-icon--failure);mask-image:var(--md-admonition-icon--failure)}.md-typeset :-webkit-any(.failure,.fail,.missing)>:-webkit-any(.admonition-title,summary):after{color:#ff5252}.md-typeset :-moz-any(.failure,.fail,.missing)>:-moz-any(.admonition-title,summary):after{color:#ff5252}.md-typeset :is(.failure,.fail,.missing)>:is(.admonition-title,summary):after{color:#ff5252}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.danger,.error){border-color:#ff1744}.md-typeset :-moz-any(.admonition,details):-moz-any(.danger,.error){border-color:#ff1744}.md-typeset :is(.admonition,details):is(.danger,.error){border-color:#ff1744}.md-typeset :-webkit-any(.danger,.error)>:-webkit-any(.admonition-title,summary){background-color:rgba(255,23,68,.1)}.md-typeset :-moz-any(.danger,.error)>:-moz-any(.admonition-title,summary){background-color:rgba(255,23,68,.1)}.md-typeset :is(.danger,.error)>:is(.admonition-title,summary){background-color:rgba(255,23,68,.1)}.md-typeset :-webkit-any(.danger,.error)>:-webkit-any(.admonition-title,summary):before{background-color:#ff1744;-webkit-mask-image:var(--md-admonition-icon--danger);mask-image:var(--md-admonition-icon--danger)}.md-typeset :-moz-any(.danger,.error)>:-moz-any(.admonition-title,summary):before{background-color:#ff1744;mask-image:var(--md-admonition-icon--danger)}.md-typeset :is(.danger,.error)>:is(.admonition-title,summary):before{background-color:#ff1744;-webkit-mask-image:var(--md-admonition-icon--danger);mask-image:var(--md-admonition-icon--danger)}.md-typeset :-webkit-any(.danger,.error)>:-webkit-any(.admonition-title,summary):after{color:#ff1744}.md-typeset :-moz-any(.danger,.error)>:-moz-any(.admonition-title,summary):after{color:#ff1744}.md-typeset :is(.danger,.error)>:is(.admonition-title,summary):after{color:#ff1744}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.bug){border-color:#f50057}.md-typeset :-moz-any(.admonition,details):-moz-any(.bug){border-color:#f50057}.md-typeset :is(.admonition,details):is(.bug){border-color:#f50057}.md-typeset :-webkit-any(.bug)>:-webkit-any(.admonition-title,summary){background-color:rgba(245,0,87,.1)}.md-typeset :-moz-any(.bug)>:-moz-any(.admonition-title,summary){background-color:rgba(245,0,87,.1)}.md-typeset :is(.bug)>:is(.admonition-title,summary){background-color:rgba(245,0,87,.1)}.md-typeset :-webkit-any(.bug)>:-webkit-any(.admonition-title,summary):before{background-color:#f50057;-webkit-mask-image:var(--md-admonition-icon--bug);mask-image:var(--md-admonition-icon--bug)}.md-typeset :-moz-any(.bug)>:-moz-any(.admonition-title,summary):before{background-color:#f50057;mask-image:var(--md-admonition-icon--bug)}.md-typeset :is(.bug)>:is(.admonition-title,summary):before{background-color:#f50057;-webkit-mask-image:var(--md-admonition-icon--bug);mask-image:var(--md-admonition-icon--bug)}.md-typeset :-webkit-any(.bug)>:-webkit-any(.admonition-title,summary):after{color:#f50057}.md-typeset :-moz-any(.bug)>:-moz-any(.admonition-title,summary):after{color:#f50057}.md-typeset :is(.bug)>:is(.admonition-title,summary):after{color:#f50057}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.example){border-color:#7c4dff}.md-typeset :-moz-any(.admonition,details):-moz-any(.example){border-color:#7c4dff}.md-typeset :is(.admonition,details):is(.example){border-color:#7c4dff}.md-typeset :-webkit-any(.example)>:-webkit-any(.admonition-title,summary){background-color:rgba(124,77,255,.1)}.md-typeset :-moz-any(.example)>:-moz-any(.admonition-title,summary){background-color:rgba(124,77,255,.1)}.md-typeset :is(.example)>:is(.admonition-title,summary){background-color:rgba(124,77,255,.1)}.md-typeset :-webkit-any(.example)>:-webkit-any(.admonition-title,summary):before{background-color:#7c4dff;-webkit-mask-image:var(--md-admonition-icon--example);mask-image:var(--md-admonition-icon--example)}.md-typeset :-moz-any(.example)>:-moz-any(.admonition-title,summary):before{background-color:#7c4dff;mask-image:var(--md-admonition-icon--example)}.md-typeset :is(.example)>:is(.admonition-title,summary):before{background-color:#7c4dff;-webkit-mask-image:var(--md-admonition-icon--example);mask-image:var(--md-admonition-icon--example)}.md-typeset :-webkit-any(.example)>:-webkit-any(.admonition-title,summary):after{color:#7c4dff}.md-typeset :-moz-any(.example)>:-moz-any(.admonition-title,summary):after{color:#7c4dff}.md-typeset :is(.example)>:is(.admonition-title,summary):after{color:#7c4dff}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.quote,.cite){border-color:#9e9e9e}.md-typeset :-moz-any(.admonition,details):-moz-any(.quote,.cite){border-color:#9e9e9e}.md-typeset :is(.admonition,details):is(.quote,.cite){border-color:#9e9e9e}.md-typeset :-webkit-any(.quote,.cite)>:-webkit-any(.admonition-title,summary){background-color:hsla(0,0%,62%,.1)}.md-typeset :-moz-any(.quote,.cite)>:-moz-any(.admonition-title,summary){background-color:hsla(0,0%,62%,.1)}.md-typeset :is(.quote,.cite)>:is(.admonition-title,summary){background-color:hsla(0,0%,62%,.1)}.md-typeset :-webkit-any(.quote,.cite)>:-webkit-any(.admonition-title,summary):before{background-color:#9e9e9e;-webkit-mask-image:var(--md-admonition-icon--quote);mask-image:var(--md-admonition-icon--quote)}.md-typeset :-moz-any(.quote,.cite)>:-moz-any(.admonition-title,summary):before{background-color:#9e9e9e;mask-image:var(--md-admonition-icon--quote)}.md-typeset :is(.quote,.cite)>:is(.admonition-title,summary):before{background-color:#9e9e9e;-webkit-mask-image:var(--md-admonition-icon--quote);mask-image:var(--md-admonition-icon--quote)}.md-typeset :-webkit-any(.quote,.cite)>:-webkit-any(.admonition-title,summary):after{color:#9e9e9e}.md-typeset :-moz-any(.quote,.cite)>:-moz-any(.admonition-title,summary):after{color:#9e9e9e}.md-typeset :is(.quote,.cite)>:is(.admonition-title,summary):after{color:#9e9e9e}:root{--md-footnotes-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .footnote{color:var(--md-default-fg-color--light);font-size:.64rem}[dir=ltr] .md-typeset .footnote>ol{margin-left:0}[dir=rtl] .md-typeset .footnote>ol{margin-right:0}.md-typeset .footnote>ol>li{transition:color 125ms}.md-typeset .footnote>ol>li:target{color:var(--md-default-fg-color)}.md-typeset .footnote>ol>li:focus-within .footnote-backref{opacity:1;transform:translateX(0);transition:none}.md-typeset .footnote>ol>li:-webkit-any(:hover,:target) .footnote-backref{opacity:1;transform:translateX(0)}.md-typeset .footnote>ol>li:-moz-any(:hover,:target) .footnote-backref{opacity:1;transform:translateX(0)}.md-typeset .footnote>ol>li:is(:hover,:target) .footnote-backref{opacity:1;transform:translateX(0)}.md-typeset .footnote>ol>li>:first-child{margin-top:0}.md-typeset .footnote-ref{font-size:.75em;font-weight:700}html .md-typeset .footnote-ref{outline-offset:.1rem}.md-typeset [id^="fnref:"]:target>.footnote-ref{outline:auto}.md-typeset .footnote-backref{color:var(--md-typeset-a-color);display:inline-block;font-size:0;opacity:0;transform:translateX(.25rem);transition:color .25s,transform .25s .25s,opacity 125ms .25s;vertical-align:text-bottom}@media print{.md-typeset .footnote-backref{color:var(--md-typeset-a-color);opacity:1;transform:translateX(0)}}[dir=rtl] .md-typeset .footnote-backref{transform:translateX(-.25rem)}.md-typeset .footnote-backref:hover{color:var(--md-accent-fg-color)}.md-typeset .footnote-backref:before{background-color:currentcolor;content:"";display:inline-block;height:.8rem;-webkit-mask-image:var(--md-footnotes-icon);mask-image:var(--md-footnotes-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.8rem}[dir=rtl] .md-typeset .footnote-backref:before svg{transform:scaleX(-1)}[dir=ltr] .md-typeset .headerlink{margin-left:.5rem}[dir=rtl] .md-typeset .headerlink{margin-right:.5rem}.md-typeset .headerlink{color:var(--md-default-fg-color--lighter);display:inline-block;opacity:0;transition:color .25s,opacity 125ms}@media print{.md-typeset .headerlink{display:none}}.md-typeset .headerlink:focus,.md-typeset :-webkit-any(:hover,:target)>.headerlink{opacity:1;-webkit-transition:color .25s,opacity 125ms;transition:color .25s,opacity 125ms}.md-typeset .headerlink:focus,.md-typeset :-moz-any(:hover,:target)>.headerlink{opacity:1;-moz-transition:color .25s,opacity 125ms;transition:color .25s,opacity 125ms}.md-typeset .headerlink:focus,.md-typeset :is(:hover,:target)>.headerlink{opacity:1;transition:color .25s,opacity 125ms}.md-typeset .headerlink:-webkit-any(:focus,:hover),.md-typeset :target>.headerlink{color:var(--md-accent-fg-color)}.md-typeset .headerlink:-moz-any(:focus,:hover),.md-typeset :target>.headerlink{color:var(--md-accent-fg-color)}.md-typeset .headerlink:is(:focus,:hover),.md-typeset :target>.headerlink{color:var(--md-accent-fg-color)}.md-typeset :target{--md-scroll-margin:3.6rem;--md-scroll-offset:0rem;scroll-margin-top:calc(var(--md-scroll-margin) - var(--md-scroll-offset))}@media screen and (min-width:76.25em){.md-header--lifted~.md-container .md-typeset :target{--md-scroll-margin:6rem}}.md-typeset :-webkit-any(h1,h2,h3):target{--md-scroll-offset:0.2rem}.md-typeset :-moz-any(h1,h2,h3):target{--md-scroll-offset:0.2rem}.md-typeset :is(h1,h2,h3):target{--md-scroll-offset:0.2rem}.md-typeset h4:target{--md-scroll-offset:0.15rem}.md-typeset div.arithmatex{overflow:auto}@media screen and (max-width:44.9375em){.md-typeset div.arithmatex{margin:0 -.8rem}}.md-typeset div.arithmatex>*{margin-left:auto!important;margin-right:auto!important;padding:0 .8rem;touch-action:auto;width:-moz-min-content;width:min-content}.md-typeset div.arithmatex>* mjx-container{margin:0!important}.md-typeset :-webkit-any(del,ins,.comment).critic{-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset :-moz-any(del,ins,.comment).critic{box-decoration-break:clone}.md-typeset :is(del,ins,.comment).critic{-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset del.critic{background-color:var(--md-typeset-del-color)}.md-typeset ins.critic{background-color:var(--md-typeset-ins-color)}.md-typeset .critic.comment{color:var(--md-code-hl-comment-color)}.md-typeset .critic.comment:before{content:"/* "}.md-typeset .critic.comment:after{content:" */"}.md-typeset .critic.block{box-shadow:none;display:block;margin:1em 0;overflow:auto;padding-left:.8rem;padding-right:.8rem}.md-typeset .critic.block>:first-child{margin-top:.5em}.md-typeset .critic.block>:last-child{margin-bottom:.5em}:root{--md-details-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset details{display:flow-root;overflow:visible;padding-top:0}.md-typeset details[open]>summary:after{transform:rotate(90deg)}.md-typeset details:not([open]){box-shadow:none;padding-bottom:0}.md-typeset details:not([open])>summary{border-radius:.1rem}[dir=ltr] .md-typeset summary{padding-right:1.8rem}[dir=rtl] .md-typeset summary{padding-left:1.8rem}[dir=ltr] .md-typeset summary{border-top-left-radius:.1rem}[dir=ltr] .md-typeset summary,[dir=rtl] .md-typeset summary{border-top-right-radius:.1rem}[dir=rtl] .md-typeset summary{border-top-left-radius:.1rem}.md-typeset summary{cursor:pointer;display:block;min-height:1rem}.md-typeset summary.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset summary:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[dir=ltr] .md-typeset summary:after{right:.4rem}[dir=rtl] .md-typeset summary:after{left:.4rem}.md-typeset summary:after{background-color:currentcolor;content:"";height:1rem;-webkit-mask-image:var(--md-details-icon);mask-image:var(--md-details-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;transform:rotate(0deg);transition:transform .25s;width:1rem}[dir=rtl] .md-typeset summary:after{transform:rotate(180deg)}.md-typeset summary::marker{display:none}.md-typeset summary::-webkit-details-marker{display:none}.md-typeset :-webkit-any(.emojione,.twemoji,.gemoji){display:inline-flex;height:1.125em;vertical-align:text-top}.md-typeset :-moz-any(.emojione,.twemoji,.gemoji){display:inline-flex;height:1.125em;vertical-align:text-top}.md-typeset :is(.emojione,.twemoji,.gemoji){display:inline-flex;height:1.125em;vertical-align:text-top}.md-typeset :-webkit-any(.emojione,.twemoji,.gemoji) svg{fill:currentcolor;max-height:100%;width:1.125em}.md-typeset :-moz-any(.emojione,.twemoji,.gemoji) svg{fill:currentcolor;max-height:100%;width:1.125em}.md-typeset :is(.emojione,.twemoji,.gemoji) svg{fill:currentcolor;max-height:100%;width:1.125em}.highlight :-webkit-any(.o,.ow){color:var(--md-code-hl-operator-color)}.highlight :-moz-any(.o,.ow){color:var(--md-code-hl-operator-color)}.highlight :is(.o,.ow){color:var(--md-code-hl-operator-color)}.highlight .p{color:var(--md-code-hl-punctuation-color)}.highlight :-webkit-any(.cpf,.l,.s,.sb,.sc,.s2,.si,.s1,.ss){color:var(--md-code-hl-string-color)}.highlight :-moz-any(.cpf,.l,.s,.sb,.sc,.s2,.si,.s1,.ss){color:var(--md-code-hl-string-color)}.highlight :is(.cpf,.l,.s,.sb,.sc,.s2,.si,.s1,.ss){color:var(--md-code-hl-string-color)}.highlight :-webkit-any(.cp,.se,.sh,.sr,.sx){color:var(--md-code-hl-special-color)}.highlight :-moz-any(.cp,.se,.sh,.sr,.sx){color:var(--md-code-hl-special-color)}.highlight :is(.cp,.se,.sh,.sr,.sx){color:var(--md-code-hl-special-color)}.highlight :-webkit-any(.m,.mb,.mf,.mh,.mi,.il,.mo){color:var(--md-code-hl-number-color)}.highlight :-moz-any(.m,.mb,.mf,.mh,.mi,.il,.mo){color:var(--md-code-hl-number-color)}.highlight :is(.m,.mb,.mf,.mh,.mi,.il,.mo){color:var(--md-code-hl-number-color)}.highlight :-webkit-any(.k,.kd,.kn,.kp,.kr,.kt){color:var(--md-code-hl-keyword-color)}.highlight :-moz-any(.k,.kd,.kn,.kp,.kr,.kt){color:var(--md-code-hl-keyword-color)}.highlight :is(.k,.kd,.kn,.kp,.kr,.kt){color:var(--md-code-hl-keyword-color)}.highlight :-webkit-any(.n){color:var(--md-code-hl-name-color)}.highlight :-moz-any(.n){color:var(--md-code-hl-name-color)}.highlight :is(.n){color:var(--md-code-hl-name-color)}.highlight :-webkit-any(.kc,.no,.nb,.bp){color:var(--md-code-hl-constant-color)}.highlight :-moz-any(.kc,.no,.nb,.bp){color:var(--md-code-hl-constant-color)}.highlight :is(.kc,.no,.nb,.bp){color:var(--md-code-hl-constant-color)}.highlight :-webkit-any(.nc,.ne,.nf,.nn){color:var(--md-code-hl-function-color)}.highlight :-moz-any(.nc,.ne,.nf,.nn){color:var(--md-code-hl-function-color)}.highlight :is(.nc,.ne,.nf,.nn){color:var(--md-code-hl-function-color)}.highlight :-webkit-any(.nd,.ni,.nl,.nt){color:var(--md-code-hl-keyword-color)}.highlight :-moz-any(.nd,.ni,.nl,.nt){color:var(--md-code-hl-keyword-color)}.highlight :is(.nd,.ni,.nl,.nt){color:var(--md-code-hl-keyword-color)}.highlight :-webkit-any(.c,.cm,.c1,.ch,.cs,.sd){color:var(--md-code-hl-comment-color)}.highlight :-moz-any(.c,.cm,.c1,.ch,.cs,.sd){color:var(--md-code-hl-comment-color)}.highlight :is(.c,.cm,.c1,.ch,.cs,.sd){color:var(--md-code-hl-comment-color)}.highlight :-webkit-any(.na,.nv,.vc,.vg,.vi){color:var(--md-code-hl-variable-color)}.highlight :-moz-any(.na,.nv,.vc,.vg,.vi){color:var(--md-code-hl-variable-color)}.highlight :is(.na,.nv,.vc,.vg,.vi){color:var(--md-code-hl-variable-color)}.highlight :-webkit-any(.ge,.gr,.gh,.go,.gp,.gs,.gu,.gt){color:var(--md-code-hl-generic-color)}.highlight :-moz-any(.ge,.gr,.gh,.go,.gp,.gs,.gu,.gt){color:var(--md-code-hl-generic-color)}.highlight :is(.ge,.gr,.gh,.go,.gp,.gs,.gu,.gt){color:var(--md-code-hl-generic-color)}.highlight :-webkit-any(.gd,.gi){border-radius:.1rem;margin:0 -.125em;padding:0 .125em}.highlight :-moz-any(.gd,.gi){border-radius:.1rem;margin:0 -.125em;padding:0 .125em}.highlight :is(.gd,.gi){border-radius:.1rem;margin:0 -.125em;padding:0 .125em}.highlight .gd{background-color:var(--md-typeset-del-color)}.highlight .gi{background-color:var(--md-typeset-ins-color)}.highlight .hll{background-color:var(--md-code-hl-color);display:block;margin:0 -1.1764705882em;padding:0 1.1764705882em}.highlight span.filename{background-color:var(--md-code-bg-color);border-bottom:.05rem solid var(--md-default-fg-color--lightest);border-top-left-radius:.1rem;border-top-right-radius:.1rem;display:flow-root;font-size:.85em;font-weight:700;margin-top:1em;padding:.6617647059em 1.1764705882em;position:relative}.highlight span.filename+pre{margin-top:0}.highlight span.filename+pre>code{border-top-left-radius:0;border-top-right-radius:0}.highlight [data-linenos]:before{background-color:var(--md-code-bg-color);box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset;color:var(--md-default-fg-color--light);content:attr(data-linenos);float:left;left:-1.1764705882em;margin-left:-1.1764705882em;margin-right:1.1764705882em;padding-left:1.1764705882em;position:sticky;-webkit-user-select:none;-moz-user-select:none;user-select:none;z-index:3}.highlight code a[id]{position:absolute;visibility:hidden}.highlight code[data-md-copying] .hll{display:contents}.highlight code[data-md-copying] .md-annotation{display:none}.highlighttable{display:flow-root}.highlighttable :-webkit-any(tbody,td){display:block;padding:0}.highlighttable :-moz-any(tbody,td){display:block;padding:0}.highlighttable :is(tbody,td){display:block;padding:0}.highlighttable tr{display:flex}.highlighttable pre{margin:0}.highlighttable th.filename{flex-grow:1;padding:0;text-align:left}.highlighttable th.filename span.filename{margin-top:0}.highlighttable .linenos{background-color:var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-top-left-radius:.1rem;font-size:.85em;padding:.7720588235em 0 .7720588235em 1.1764705882em;-webkit-user-select:none;-moz-user-select:none;user-select:none}.highlighttable .linenodiv{box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset;padding-right:.5882352941em}.highlighttable .linenodiv pre{color:var(--md-default-fg-color--light);text-align:right}.highlighttable .code{flex:1;min-width:0}.linenodiv a{color:inherit}.md-typeset .highlighttable{direction:ltr;margin:1em 0}.md-typeset .highlighttable>tbody>tr>.code>div>pre>code{border-bottom-left-radius:0;border-top-left-radius:0}.md-typeset :-webkit-any(.highlight,.highlighttable,.literal-block-wrapper,div[class^=highlight-],.results-prefix)+.result{border:.05rem solid var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-bottom-right-radius:.1rem;border-top-width:.1rem;margin-top:-1.125em;overflow:visible;padding:0 1em}.md-typeset :-moz-any(.highlight,.highlighttable,.literal-block-wrapper,div[class^=highlight-],.results-prefix)+.result{border:.05rem solid var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-bottom-right-radius:.1rem;border-top-width:.1rem;margin-top:-1.125em;overflow:visible;padding:0 1em}.md-typeset :is(.highlight,.highlighttable,.literal-block-wrapper,div[class^=highlight-],.results-prefix)+.result{border:.05rem solid var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-bottom-right-radius:.1rem;border-top-width:.1rem;margin-top:-1.125em;overflow:visible;padding:0 1em}.md-typeset :-webkit-any(.highlight,.highlighttable,.literal-block-wrapper,div[class^=highlight-],.results-prefix)+.result:after{clear:both;content:"";display:block}.md-typeset :-moz-any(.highlight,.highlighttable,.literal-block-wrapper,div[class^=highlight-],.results-prefix)+.result:after{clear:both;content:"";display:block}.md-typeset :is(.highlight,.highlighttable,.literal-block-wrapper,div[class^=highlight-],.results-prefix)+.result:after{clear:both;content:"";display:block}.md-typeset .results .results-prefix+.result{margin-top:0}.md-typeset .results .results-prefix{background-color:var(--md-code-bg-color);font-size:.85em;font-weight:700;margin-top:-1em;padding:.6617647059em 1.1764705882em}@media screen and (max-width:44.9375em){.md-content__inner>.highlight{margin:1em -.8rem}.md-content__inner>.highlight>.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.code>div>pre>code,.md-content__inner>.highlight>.highlighttable>tbody>tr>.filename span.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.linenos,.md-content__inner>.highlight>pre>code{border-radius:0}.md-content__inner>.highlight+.result{border-left-width:0;border-radius:0;border-right-width:0;margin-left:-.8rem;margin-right:-.8rem}}.md-typeset .keys kbd:-webkit-any(:before,:after){-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;color:inherit;margin:0;position:relative}.md-typeset .keys kbd:-moz-any(:before,:after){-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;color:inherit;margin:0;position:relative}.md-typeset .keys kbd:is(:before,:after){-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;color:inherit;margin:0;position:relative}.md-typeset .keys span{color:var(--md-default-fg-color--light);padding:0 .2em}.md-typeset .keys .key-alt:before,.md-typeset .keys .key-left-alt:before,.md-typeset .keys .key-right-alt:before{content:"⎇";padding-right:.4em}.md-typeset .keys .key-command:before,.md-typeset .keys .key-left-command:before,.md-typeset .keys .key-right-command:before{content:"⌘";padding-right:.4em}.md-typeset .keys .key-control:before,.md-typeset .keys .key-left-control:before,.md-typeset .keys .key-right-control:before{content:"⌃";padding-right:.4em}.md-typeset .keys .key-left-meta:before,.md-typeset .keys .key-meta:before,.md-typeset .keys .key-right-meta:before{content:"◆";padding-right:.4em}.md-typeset .keys .key-left-option:before,.md-typeset .keys .key-option:before,.md-typeset .keys .key-right-option:before{content:"⌥";padding-right:.4em}.md-typeset .keys .key-left-shift:before,.md-typeset .keys .key-right-shift:before,.md-typeset .keys .key-shift:before{content:"⇧";padding-right:.4em}.md-typeset .keys .key-left-super:before,.md-typeset .keys .key-right-super:before,.md-typeset .keys .key-super:before{content:"❖";padding-right:.4em}.md-typeset .keys .key-left-windows:before,.md-typeset .keys .key-right-windows:before,.md-typeset .keys .key-windows:before{content:"⊞";padding-right:.4em}.md-typeset .keys .key-arrow-down:before{content:"↓";padding-right:.4em}.md-typeset .keys .key-arrow-left:before{content:"←";padding-right:.4em}.md-typeset .keys .key-arrow-right:before{content:"→";padding-right:.4em}.md-typeset .keys .key-arrow-up:before{content:"↑";padding-right:.4em}.md-typeset .keys .key-backspace:before{content:"⌫";padding-right:.4em}.md-typeset .keys .key-backtab:before{content:"⇤";padding-right:.4em}.md-typeset .keys .key-caps-lock:before{content:"⇪";padding-right:.4em}.md-typeset .keys .key-clear:before{content:"⌧";padding-right:.4em}.md-typeset .keys .key-context-menu:before{content:"☰";padding-right:.4em}.md-typeset .keys .key-delete:before{content:"⌦";padding-right:.4em}.md-typeset .keys .key-eject:before{content:"⏏";padding-right:.4em}.md-typeset .keys .key-end:before{content:"⤓";padding-right:.4em}.md-typeset .keys .key-escape:before{content:"⎋";padding-right:.4em}.md-typeset .keys .key-home:before{content:"⤒";padding-right:.4em}.md-typeset .keys .key-insert:before{content:"⎀";padding-right:.4em}.md-typeset .keys .key-page-down:before{content:"⇟";padding-right:.4em}.md-typeset .keys .key-page-up:before{content:"⇞";padding-right:.4em}.md-typeset .keys .key-print-screen:before{content:"⎙";padding-right:.4em}.md-typeset .keys .key-tab:after{content:"⇥";padding-left:.4em}.md-typeset .keys .key-num-enter:after{content:"⌤";padding-left:.4em}.md-typeset .keys .key-enter:after{content:"⏎";padding-left:.4em}:root{--md-tabbed-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-tabbed-icon--next:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .tabbed-set{border-radius:.1rem;display:flex;flex-flow:column wrap;margin:1em 0;position:relative}.md-typeset .tabbed-set>input{height:0;opacity:0;position:absolute;width:0}.md-typeset .tabbed-set>input:target{--md-scroll-offset:0.625em}.md-typeset .tabbed-labels{-ms-overflow-style:none;box-shadow:0 -.05rem var(--md-default-fg-color--lightest) inset;display:flex;max-width:100%;overflow:auto;scrollbar-width:none}@media print{.md-typeset .tabbed-labels{display:contents}}@media screen{.js .md-typeset .tabbed-labels{position:relative}.js .md-typeset .tabbed-labels:before{background:var(--md-accent-fg-color);bottom:0;content:"";display:block;height:2px;left:0;position:absolute;transform:translateX(var(--md-indicator-x));transition:width 225ms,transform .25s;transition-timing-function:cubic-bezier(.4,0,.2,1);width:var(--md-indicator-width)}}.md-typeset .tabbed-labels::-webkit-scrollbar{display:none}.md-typeset .tabbed-labels>label{border-bottom:.1rem solid transparent;border-radius:.1rem .1rem 0 0;color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;font-size:.64rem;font-weight:700;padding:.78125em 1.25em .625em;scroll-margin-inline-start:1rem;transition:background-color .25s,color .25s;white-space:nowrap;width:auto}@media print{.md-typeset .tabbed-labels>label:first-child{order:1}.md-typeset .tabbed-labels>label:nth-child(2){order:2}.md-typeset .tabbed-labels>label:nth-child(3){order:3}.md-typeset .tabbed-labels>label:nth-child(4){order:4}.md-typeset .tabbed-labels>label:nth-child(5){order:5}.md-typeset .tabbed-labels>label:nth-child(6){order:6}.md-typeset .tabbed-labels>label:nth-child(7){order:7}.md-typeset .tabbed-labels>label:nth-child(8){order:8}.md-typeset .tabbed-labels>label:nth-child(9){order:9}.md-typeset .tabbed-labels>label:nth-child(10){order:10}.md-typeset .tabbed-labels>label:nth-child(11){order:11}.md-typeset .tabbed-labels>label:nth-child(12){order:12}.md-typeset .tabbed-labels>label:nth-child(13){order:13}.md-typeset .tabbed-labels>label:nth-child(14){order:14}.md-typeset .tabbed-labels>label:nth-child(15){order:15}.md-typeset .tabbed-labels>label:nth-child(16){order:16}.md-typeset .tabbed-labels>label:nth-child(17){order:17}.md-typeset .tabbed-labels>label:nth-child(18){order:18}.md-typeset .tabbed-labels>label:nth-child(19){order:19}.md-typeset .tabbed-labels>label:nth-child(20){order:20}}.md-typeset .tabbed-labels>label:hover{color:var(--md-accent-fg-color)}.md-typeset .tabbed-content{width:100%}@media print{.md-typeset .tabbed-content{display:contents}}.md-typeset .tabbed-block{display:none}@media print{.md-typeset .tabbed-block{display:block}.md-typeset .tabbed-block:first-child{order:1}.md-typeset .tabbed-block:nth-child(2){order:2}.md-typeset .tabbed-block:nth-child(3){order:3}.md-typeset .tabbed-block:nth-child(4){order:4}.md-typeset .tabbed-block:nth-child(5){order:5}.md-typeset .tabbed-block:nth-child(6){order:6}.md-typeset .tabbed-block:nth-child(7){order:7}.md-typeset .tabbed-block:nth-child(8){order:8}.md-typeset .tabbed-block:nth-child(9){order:9}.md-typeset .tabbed-block:nth-child(10){order:10}.md-typeset .tabbed-block:nth-child(11){order:11}.md-typeset .tabbed-block:nth-child(12){order:12}.md-typeset .tabbed-block:nth-child(13){order:13}.md-typeset .tabbed-block:nth-child(14){order:14}.md-typeset .tabbed-block:nth-child(15){order:15}.md-typeset .tabbed-block:nth-child(16){order:16}.md-typeset .tabbed-block:nth-child(17){order:17}.md-typeset .tabbed-block:nth-child(18){order:18}.md-typeset .tabbed-block:nth-child(19){order:19}.md-typeset .tabbed-block:nth-child(20){order:20}}.md-typeset .tabbed-block>.highlight:first-child>pre,.md-typeset .tabbed-block>pre:first-child{margin:0}.md-typeset .tabbed-block>.highlight:first-child>pre>code,.md-typeset .tabbed-block>pre:first-child>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child>.filename{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable{margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.filename span.filename,.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.linenos{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.code>div>pre>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child+.result{margin-top:-.125em}.md-typeset .tabbed-block>.tabbed-set{margin:0}.md-typeset .tabbed-button{align-self:center;border-radius:100%;color:var(--md-default-fg-color--light);cursor:pointer;display:block;height:.9rem;margin-top:.1rem;pointer-events:auto;transition:background-color .25s;width:.9rem}.md-typeset .tabbed-button:hover{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-typeset .tabbed-button:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-tabbed-icon--prev);mask-image:var(--md-tabbed-icon--prev);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color .25s,transform .25s;width:100%}.md-typeset .tabbed-control{background:linear-gradient(to right,var(--md-default-bg-color) 60%,transparent);display:flex;height:1.9rem;justify-content:start;pointer-events:none;position:absolute;transition:opacity 125ms;width:1.2rem}[dir=rtl] .md-typeset .tabbed-control{transform:rotate(180deg)}.md-typeset .tabbed-control[hidden]{opacity:0}.md-typeset .tabbed-control--next{background:linear-gradient(to left,var(--md-default-bg-color) 60%,transparent);justify-content:end;right:0}.md-typeset .tabbed-control--next .tabbed-button:after{-webkit-mask-image:var(--md-tabbed-icon--next);mask-image:var(--md-tabbed-icon--next)}@media screen and (max-width:44.9375em){[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels{padding-right:.8rem}.md-content__inner>.tabbed-set .tabbed-labels{margin:0 -.8rem;max-width:100vw;scroll-padding-inline-start:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-left:.8rem}.md-content__inner>.tabbed-set .tabbed-labels:after{content:""}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-left:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-right:-.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-right:.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{width:2rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-right:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-left:-.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-left:.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{width:2rem}}@media screen{.md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){color:var(--md-accent-fg-color)}.md-typeset .no-js .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .no-js .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .no-js .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .no-js .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .no-js .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .no-js .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .no-js .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .no-js .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .no-js .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .no-js .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .no-js .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .no-js .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .no-js .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .no-js .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .no-js .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .no-js .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .no-js .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .no-js .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .no-js .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .no-js .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),.no-js .md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.no-js .md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.no-js .md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.no-js .md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.no-js .md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.no-js .md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.no-js .md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.no-js .md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.no-js .md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.no-js .md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.no-js .md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.no-js .md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.no-js .md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.no-js .md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.no-js .md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.no-js .md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.no-js .md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.no-js .md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.no-js .md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.no-js .md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){border-color:var(--md-accent-fg-color)}}.md-typeset .tabbed-set>input:first-child.focus-visible~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10).focus-visible~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11).focus-visible~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12).focus-visible~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13).focus-visible~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14).focus-visible~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15).focus-visible~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16).focus-visible~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17).focus-visible~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18).focus-visible~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19).focus-visible~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2).focus-visible~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20).focus-visible~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3).focus-visible~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4).focus-visible~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5).focus-visible~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6).focus-visible~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7).focus-visible~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8).focus-visible~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9).focus-visible~.tabbed-labels>:nth-child(9){background-color:var(--md-accent-fg-color--transparent)}.md-typeset .tabbed-set>input:first-child:checked~.tabbed-content>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-content>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-content>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-content>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-content>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-content>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-content>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-content>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-content>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-content>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-content>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-content>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-content>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-content>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-content>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-content>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-content>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-content>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-content>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-content>:nth-child(9){display:block}:root{--md-tasklist-icon:url('data:image/svg+xml;charset=utf-8,');--md-tasklist-icon--checked:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .task-list-item{list-style-type:none;position:relative}[dir=ltr] .md-typeset .task-list-item [type=checkbox]{left:-2em}[dir=rtl] .md-typeset .task-list-item [type=checkbox]{right:-2em}.md-typeset .task-list-item [type=checkbox]{position:absolute;top:.45em}.md-typeset .task-list-control [type=checkbox]{opacity:0;z-index:-1}[dir=ltr] .md-typeset .task-list-indicator:before{left:-1.5em}[dir=rtl] .md-typeset .task-list-indicator:before{right:-1.5em}.md-typeset .task-list-indicator:before{background-color:var(--md-default-fg-color--lightest);content:"";height:1.25em;-webkit-mask-image:var(--md-tasklist-icon);mask-image:var(--md-tasklist-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.15em;width:1.25em}.md-typeset [type=checkbox]:checked+.task-list-indicator:before{background-color:#00e676;-webkit-mask-image:var(--md-tasklist-icon--checked);mask-image:var(--md-tasklist-icon--checked)}.rst-versions{font-family:var(--md-text-font-family)}.rst-versions.rst-badge{bottom:inherit!important;font-size:.85rem;height:auto;top:50px}:root>*{--md-mermaid-font-family:var(--md-text-font-family),sans-serif;--md-mermaid-edge-color:var(--md-code-fg-color);--md-mermaid-node-bg-color:var(--md-accent-fg-color--transparent);--md-mermaid-node-fg-color:var(--md-accent-fg-color);--md-mermaid-label-bg-color:var(--md-default-bg-color);--md-mermaid-label-fg-color:var(--md-code-fg-color)}.mermaid{line-height:normal;margin:1em 0}:root>*{--md-graphviz-edge-color:var(--md-default-fg-color);--md-graphviz-node-bg-color:var(--md-accent-fg-color--transparent);--md-graphviz-node-fg-color:var(--md-accent-fg-color);--md-graphviz-label-bg-color:var(--md-default-bg-color);--md-graphviz-label-fg-color:var(--md-code-fg-color);--md-graphviz-a-hover-color:var(--md-primary-fg-color)}.graphviz{margin:1em 0}.graphviz a:hover>text{fill:var(--md-graphviz-hover-color)!important}@media screen and (min-width:45em){[dir=ltr] .md-typeset .inline{float:left}[dir=rtl] .md-typeset .inline{float:right}[dir=ltr] .md-typeset .inline{margin-right:.8rem}[dir=rtl] .md-typeset .inline{margin-left:.8rem}.md-typeset .inline{margin-bottom:.8rem;margin-top:0;width:11.7rem}[dir=ltr] .md-typeset .inline.end{float:right}[dir=rtl] .md-typeset .inline.end{float:left}[dir=ltr] .md-typeset .inline.end{margin-left:.8rem;margin-right:0}[dir=rtl] .md-typeset .inline.end{margin-left:0;margin-right:.8rem}}.md-typeset .align-left{text-align:left}.md-typeset .align-right{text-align:right}.md-typeset .align-center{clear:both;text-align:center}.md-typeset .align-top{vertical-align:top}.md-typeset .align-middle{vertical-align:middle}.md-typeset .align-bottom{vertical-align:bottom}.md-typeset .figure.align-left,.md-typeset figure.align-left,.md-typeset img.align-left,.md-typeset object.align-left,.md-typeset table.align-left{margin-right:auto}.md-typeset .figure.align-center,.md-typeset figure.align-center,.md-typeset img.align-center,.md-typeset object.align-center,.md-typeset table.align-center{margin-left:auto;margin-right:auto}.md-typeset .figure.align-right,.md-typeset figure.align-right,.md-typeset img.align-right,.md-typeset object.align-right,.md-typeset table.align-right{margin-left:auto}.md-typeset .figure.align-center,.md-typeset .figure.align-right,.md-typeset figure.align-center,.md-typeset figure.align-right,.md-typeset img.align-center,.md-typeset img.align-right,.md-typeset object.align-center,.md-typeset object.align-right{display:block}.md-typeset .figure.align-left,.md-typeset .figure.align-right,.md-typeset figure.align-left,.md-typeset figure.align-right,.md-typeset table.align-center,.md-typeset table.align-left,.md-typeset table.align-right{text-align:inherit}.md-typeset .rubric{font-weight:700}.md-typeset .viewcode-block .viewcode-back{float:right}.md-typeset .versionmodified{font-style:italic}.md-typeset div.line-block{display:block}.md-typeset div.line-block div.line-block{margin-left:1.5em}.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt{background:var(--md-code-bg-color);font-family:var(--md-code-font-family)}.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt{background:var(--md-code-bg-color);font-family:var(--md-code-font-family)}.md-typeset :is(dl.objdesc,dl.api-field)>dt{background:var(--md-code-bg-color);font-family:var(--md-code-font-family)}.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt code{border-radius:0;padding:0}.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt code{border-radius:0;padding:0}.md-typeset :is(dl.objdesc,dl.api-field)>dt code{border-radius:0;padding:0}.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt .sig-name:not(.sig-name-nonprimary){color:var(--md-code-hl-name-color);font-weight:700;padding:0}.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt .sig-name:not(.sig-name-nonprimary){color:var(--md-code-hl-name-color);font-weight:700;padding:0}.md-typeset :is(dl.objdesc,dl.api-field)>dt .sig-name:not(.sig-name-nonprimary){color:var(--md-code-hl-name-color);font-weight:700;padding:0}.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt .sig-param{font-style:normal}.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt .sig-param{font-style:normal}.md-typeset :is(dl.objdesc,dl.api-field)>dt .sig-param{font-style:normal}.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt .sig-param .n:not(.desctype){color:var(--md-default-fg-color--light)}.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt .sig-param .n:not(.desctype){color:var(--md-default-fg-color--light)}.md-typeset :is(dl.objdesc,dl.api-field)>dt .sig-param .n:not(.desctype){color:var(--md-default-fg-color--light)}.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt .sig-param a.reference .n:not(.desctype):hover{color:var(--md-accent-fg-color)}.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt .sig-param a.reference .n:not(.desctype):hover{color:var(--md-accent-fg-color)}.md-typeset :is(dl.objdesc,dl.api-field)>dt .sig-param a.reference .n:not(.desctype):hover{color:var(--md-accent-fg-color)}.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt.sig-wrap .sig-param-decl:before{content:"\a ";white-space:pre}.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt.sig-wrap .sig-param-decl:before{content:"\a ";white-space:pre}.md-typeset :is(dl.objdesc,dl.api-field)>dt.sig-wrap .sig-param-decl:before{content:"\a ";white-space:pre}.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt.sig-wrap .sig-paren~.sig-paren:before{content:"\a";white-space:pre}.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt.sig-wrap .sig-paren~.sig-paren:before{content:"\a";white-space:pre}.md-typeset :is(dl.objdesc,dl.api-field)>dt.sig-wrap .sig-paren~.sig-paren:before{content:"\a";white-space:pre}.md-typeset dl.objdesc>dd>dl.field-list>dt>.colon{display:none}.md-typeset .sig-inline a.reference.sig-name,.md-typeset .sig-inline a.reference:not(.desctype)>.n,.md-typeset .sig-inline a.reference>.sig-name,.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt a.reference.sig-name,.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt a.reference:not(.desctype)>.n,.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt a.reference>.sig-name{color:var(--md-typeset-a-color)}.md-typeset .sig-inline a.reference.sig-name,.md-typeset .sig-inline a.reference:not(.desctype)>.n,.md-typeset .sig-inline a.reference>.sig-name,.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt a.reference.sig-name,.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt a.reference:not(.desctype)>.n,.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt a.reference>.sig-name{color:var(--md-typeset-a-color)}.md-typeset .sig-inline a.reference.sig-name,.md-typeset .sig-inline a.reference:not(.desctype)>.n,.md-typeset .sig-inline a.reference>.sig-name,.md-typeset :is(dl.objdesc,dl.api-field)>dt a.reference.sig-name,.md-typeset :is(dl.objdesc,dl.api-field)>dt a.reference:not(.desctype)>.n,.md-typeset :is(dl.objdesc,dl.api-field)>dt a.reference>.sig-name{color:var(--md-typeset-a-color)}.md-typeset .sig-inline a.reference.sig-name:hover,.md-typeset .sig-inline a.reference:not(.desctype)>.n:hover,.md-typeset .sig-inline a.reference>.sig-name:hover,.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt a.reference.sig-name:hover,.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt a.reference:not(.desctype)>.n:hover,.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt a.reference>.sig-name:hover{color:var(--md-accent-fg-color)}.md-typeset .sig-inline a.reference.sig-name:hover,.md-typeset .sig-inline a.reference:not(.desctype)>.n:hover,.md-typeset .sig-inline a.reference>.sig-name:hover,.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt a.reference.sig-name:hover,.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt a.reference:not(.desctype)>.n:hover,.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt a.reference>.sig-name:hover{color:var(--md-accent-fg-color)}.md-typeset .sig-inline a.reference.sig-name:hover,.md-typeset .sig-inline a.reference:not(.desctype)>.n:hover,.md-typeset .sig-inline a.reference>.sig-name:hover,.md-typeset :is(dl.objdesc,dl.api-field)>dt a.reference.sig-name:hover,.md-typeset :is(dl.objdesc,dl.api-field)>dt a.reference:not(.desctype)>.n:hover,.md-typeset :is(dl.objdesc,dl.api-field)>dt a.reference>.sig-name:hover{color:var(--md-accent-fg-color)}.md-typeset .sig-inline .desctype,.md-typeset .sig-inline .desctype>a.reference,.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt .desctype,.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt .desctype>a.reference{color:var(--md-code-hl-special-color)}.md-typeset .sig-inline .desctype,.md-typeset .sig-inline .desctype>a.reference,.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt .desctype,.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt .desctype>a.reference{color:var(--md-code-hl-special-color)}.md-typeset .sig-inline .desctype,.md-typeset .sig-inline .desctype>a.reference,.md-typeset :is(dl.objdesc,dl.api-field)>dt .desctype,.md-typeset :is(dl.objdesc,dl.api-field)>dt .desctype>a.reference{color:var(--md-code-hl-special-color)}.md-typeset .sig-inline .desctype .n,.md-typeset .sig-inline .desctype>a.reference .n,.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt .desctype .n,.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt .desctype>a.reference .n{color:inherit}.md-typeset .sig-inline .desctype .n,.md-typeset .sig-inline .desctype>a.reference .n,.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt .desctype .n,.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt .desctype>a.reference .n{color:inherit}.md-typeset .sig-inline .desctype .n,.md-typeset .sig-inline .desctype>a.reference .n,.md-typeset :is(dl.objdesc,dl.api-field)>dt .desctype .n,.md-typeset :is(dl.objdesc,dl.api-field)>dt .desctype>a.reference .n{color:inherit}.md-typeset .sig-inline .desctype:-webkit-any(a.reference):hover,.md-typeset .sig-inline .desctype>a.reference:hover,.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt .desctype:-webkit-any(a.reference):hover,.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt .desctype>a.reference:hover{color:var(--md-accent-fg-color)}.md-typeset .sig-inline .desctype:-moz-any(a.reference):hover,.md-typeset .sig-inline .desctype>a.reference:hover,.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt .desctype:-moz-any(a.reference):hover,.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt .desctype>a.reference:hover{color:var(--md-accent-fg-color)}.md-typeset .sig-inline .desctype:is(a.reference):hover,.md-typeset .sig-inline .desctype>a.reference:hover,.md-typeset :is(dl.objdesc,dl.api-field)>dt .desctype:is(a.reference):hover,.md-typeset :is(dl.objdesc,dl.api-field)>dt .desctype>a.reference:hover{color:var(--md-accent-fg-color)}.md-typeset dl.objdesc>dt{background:var(--md-code-bg-color);font-family:var(--md-code-font-family);padding-left:.5em;padding-right:.5em;padding-top:.5em}.md-typeset dl.objdesc>dt,.md-typeset dl.objdesc>dt code{font-size:.75rem}.md-typeset dl.objdesc>dt .property{color:var(--md-code-hl-keyword-color);font-style:normal;font-weight:700}.md-typeset dl.objdesc>dt .sig-prename{color:var(--md-code-hl-name-color);padding:0}.md-typeset dl.objdesc>dt .viewcode-back,.md-typeset dl.objdesc>dt .viewcode-link{float:right;text-align:right}.md-typeset dl.objdesc>dt.api-include-path,.md-typeset dl.objdesc>dt.api-include-path code{font-size:.65rem}.md-typeset dl.objdesc>dt:first-child{padding-top:.5em}.md-typeset dl.objdesc>dt:last-of-type{padding-bottom:.5em}.md-typeset dl.objdesc>dd dl.field-list>dt{font-size:1em;font-weight:700;margin-bottom:1em}.md-typeset dl.objdesc>dd dd.noindent{margin-left:0}.md-typeset dl.api-field>dt{display:table}.md-typeset dl.api-field>dt a.headerlink{left:.5em;margin-left:0;position:relative;width:0}.md-typeset dl.api-field>dt,.md-typeset dl.api-field>dt code{font-size:.65rem}.md-typeset dl.api-field>dt.api-parameter-kind{float:right;font-family:var(--md-text-font-family)}.md-typeset dl.api-field>dt.api-parameter-kind:before{content:"["}.md-typeset dl.api-field>dt.api-parameter-kind:after{content:"]"}.md-typeset dl.objdesc.summary>dd,.md-typeset dl.objdesc.summary>dd>p:first-child{margin-top:0}.md-typeset .sig-inline:-webkit-any(.c-texpr,.cpp-texpr){background-color:unset;font-family:unset}.md-typeset .sig-inline:-moz-any(.c-texpr,.cpp-texpr){background-color:unset;font-family:unset}.md-typeset .sig-inline:is(.c-texpr,.cpp-texpr){background-color:unset;font-family:unset}.md-nav__link{white-space:nowrap}:root>*{--objinfo-icon-fg-alias:#e65100;--objinfo-icon-fg-default:#424242;--objinfo-icon-fg-data:#1565c0;--objinfo-icon-fg-procedure:#6a1b9a;--objinfo-icon-fg-sub-data:#2e7d32;--objinfo-icon-bg-default:var(--md-default-bg-color)}@media screen{[data-md-color-scheme=slate]{--objinfo-icon-fg-alias:#ffb74d;--objinfo-icon-fg-default:#e0e0e0;--objinfo-icon-fg-data:#64b5f6;--objinfo-icon-fg-procedure:#ce93d8;--objinfo-icon-fg-sub-data:#81c784}}.objinfo-icon{background-color:var(--objinfo-icon-bg-default);border:1px solid var(--objinfo-icon-fg-default);border-radius:2px;color:var(--objinfo-icon-fg-default);display:inline-table;flex-shrink:0;font-family:var(--md-text-font-family);font-weight:500;height:16px;line-height:16px;margin-right:8px;text-align:center;vertical-align:middle;width:16px}.objinfo-icon__alias{background-color:var(--objinfo-icon-fg-alias);border:1px solid var(--objinfo-icon-fg-alias);color:var(--objinfo-icon-bg-default)}.objinfo-icon__procedure{background-color:var(--objinfo-icon-fg-procedure);border:1px solid var(--objinfo-icon-fg-procedure);color:var(--objinfo-icon-bg-default)}.objinfo-icon__data{background-color:var(--objinfo-icon-fg-data);border:1px solid var(--objinfo-icon-fg-data);color:var(--objinfo-icon-bg-default)}.objinfo-icon__sub-data{background-color:var(--objinfo-icon-fg-sub-data);border:1px solid var(--objinfo-icon-fg-sub-data);color:var(--objinfo-icon-bg-default)}.search-result-objlabel{border:1px solid var(--md-default-fg-color--light);border-radius:2px;float:right;padding:2px}table.longtable.docutils.data.align-default tbody>tr>td>p>a.reference.internal>code.xref.py.py-obj.docutils.literal.notranslate>span.pre{word-break:normal} +@media screen{[data-md-color-scheme=slate]{--md-hue:232;--md-default-fg-color:hsla(var(--md-hue),75%,95%,1);--md-default-fg-color--light:hsla(var(--md-hue),75%,90%,0.62);--md-default-fg-color--lighter:hsla(var(--md-hue),75%,90%,0.32);--md-default-fg-color--lightest:hsla(var(--md-hue),75%,90%,0.12);--md-default-bg-color:hsla(var(--md-hue),15%,21%,1);--md-default-bg-color--light:hsla(var(--md-hue),15%,21%,0.54);--md-default-bg-color--lighter:hsla(var(--md-hue),15%,21%,0.26);--md-default-bg-color--lightest:hsla(var(--md-hue),15%,21%,0.07);--md-code-fg-color:hsla(var(--md-hue),18%,86%,1);--md-code-bg-color:hsla(var(--md-hue),15%,15%,1);--md-code-hl-color:rgba(66,135,255,.15);--md-code-hl-number-color:#e6695b;--md-code-hl-special-color:#f06090;--md-code-hl-function-color:#c973d9;--md-code-hl-constant-color:#9383e2;--md-code-hl-keyword-color:#6791e0;--md-code-hl-string-color:#2fb170;--md-code-hl-name-color:var(--md-code-fg-color);--md-code-hl-operator-color:var(--md-default-fg-color--light);--md-code-hl-punctuation-color:var(--md-default-fg-color--light);--md-code-hl-comment-color:var(--md-default-fg-color--light);--md-code-hl-generic-color:var(--md-default-fg-color--light);--md-code-hl-variable-color:var(--md-default-fg-color--light);--md-typeset-color:var(--md-default-fg-color);--md-typeset-a-color:var(--md-primary-fg-color);--md-typeset-mark-color:rgba(66,135,255,.3);--md-typeset-kbd-color:hsla(var(--md-hue),15%,94%,0.12);--md-typeset-kbd-accent-color:hsla(var(--md-hue),15%,94%,0.2);--md-typeset-kbd-border-color:hsla(var(--md-hue),15%,14%,1);--md-typeset-table-color:hsla(var(--md-hue),75%,95%,0.12);--md-admonition-fg-color:var(--md-default-fg-color);--md-admonition-bg-color:var(--md-default-bg-color);--md-footer-bg-color:hsla(var(--md-hue),15%,12%,0.87);--md-footer-bg-color--dark:hsla(var(--md-hue),15%,10%,1);--md-shadow-z1:0 0.2rem 0.5rem rgba(0,0,0,.2),0 0 0.05rem rgba(0,0,0,.1);--md-shadow-z2:0 0.2rem 0.5rem rgba(0,0,0,.3),0 0 0.05rem rgba(0,0,0,.25);--md-shadow-z3:0 0.2rem 0.5rem rgba(0,0,0,.4),0 0 0.05rem rgba(0,0,0,.35)}[data-md-color-scheme=slate] img[src$="#gh-light-mode-only"],[data-md-color-scheme=slate] img[src$="#only-light"]{display:none}[data-md-color-scheme=slate] img[src$="#gh-dark-mode-only"],[data-md-color-scheme=slate] img[src$="#only-dark"]{display:initial}[data-md-color-scheme=slate][data-md-color-primary=pink]{--md-typeset-a-color:#ed5487}[data-md-color-scheme=slate][data-md-color-primary=purple]{--md-typeset-a-color:#bd78c9}[data-md-color-scheme=slate][data-md-color-primary=deep-purple]{--md-typeset-a-color:#a682e3}[data-md-color-scheme=slate][data-md-color-primary=indigo]{--md-typeset-a-color:#6c91d5}[data-md-color-scheme=slate][data-md-color-primary=teal]{--md-typeset-a-color:#00ccb8}[data-md-color-scheme=slate][data-md-color-primary=green]{--md-typeset-a-color:#71c174}[data-md-color-scheme=slate][data-md-color-primary=deep-orange]{--md-typeset-a-color:#ff9575}[data-md-color-scheme=slate][data-md-color-primary=brown]{--md-typeset-a-color:#c7846b}[data-md-color-scheme=slate][data-md-color-primary=black],[data-md-color-scheme=slate][data-md-color-primary=blue-grey],[data-md-color-scheme=slate][data-md-color-primary=grey],[data-md-color-scheme=slate][data-md-color-primary=white]{--md-typeset-a-color:#6c91d5}[data-md-color-switching] *,[data-md-color-switching] :after,[data-md-color-switching] :before{transition-duration:0ms!important}}[data-md-color-accent=red]{--md-accent-fg-color:#ff1947;--md-accent-fg-color--transparent:rgba(255,25,71,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=pink]{--md-accent-fg-color:#f50056;--md-accent-fg-color--transparent:rgba(245,0,86,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=purple]{--md-accent-fg-color:#df41fb;--md-accent-fg-color--transparent:rgba(223,65,251,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=deep-purple]{--md-accent-fg-color:#7c4dff;--md-accent-fg-color--transparent:rgba(124,77,255,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=indigo]{--md-accent-fg-color:#526cfe;--md-accent-fg-color--transparent:rgba(82,108,254,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=blue]{--md-accent-fg-color:#4287ff;--md-accent-fg-color--transparent:rgba(66,135,255,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=light-blue]{--md-accent-fg-color:#0091eb;--md-accent-fg-color--transparent:rgba(0,145,235,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=cyan]{--md-accent-fg-color:#00bad6;--md-accent-fg-color--transparent:rgba(0,186,214,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=teal]{--md-accent-fg-color:#00bda4;--md-accent-fg-color--transparent:rgba(0,189,164,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=green]{--md-accent-fg-color:#00c753;--md-accent-fg-color--transparent:rgba(0,199,83,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=light-green]{--md-accent-fg-color:#63de17;--md-accent-fg-color--transparent:rgba(99,222,23,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=lime]{--md-accent-fg-color:#b0eb00;--md-accent-fg-color--transparent:rgba(176,235,0,.1);--md-accent-bg-color:rgba(0,0,0,.87);--md-accent-bg-color--light:rgba(0,0,0,.54)}[data-md-color-accent=yellow]{--md-accent-fg-color:#ffd500;--md-accent-fg-color--transparent:rgba(255,213,0,.1);--md-accent-bg-color:rgba(0,0,0,.87);--md-accent-bg-color--light:rgba(0,0,0,.54)}[data-md-color-accent=amber]{--md-accent-fg-color:#fa0;--md-accent-fg-color--transparent:rgba(255,170,0,.1);--md-accent-bg-color:rgba(0,0,0,.87);--md-accent-bg-color--light:rgba(0,0,0,.54)}[data-md-color-accent=orange]{--md-accent-fg-color:#ff9100;--md-accent-fg-color--transparent:rgba(255,145,0,.1);--md-accent-bg-color:rgba(0,0,0,.87);--md-accent-bg-color--light:rgba(0,0,0,.54)}[data-md-color-accent=deep-orange]{--md-accent-fg-color:#ff6e42;--md-accent-fg-color--transparent:rgba(255,110,66,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=red]{--md-primary-fg-color:#ef5552;--md-primary-fg-color--light:#e57171;--md-primary-fg-color--dark:#e53734;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=pink]{--md-primary-fg-color:#e92063;--md-primary-fg-color--light:#ec417a;--md-primary-fg-color--dark:#c3185d;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=purple]{--md-primary-fg-color:#ab47bd;--md-primary-fg-color--light:#bb69c9;--md-primary-fg-color--dark:#8c24a8;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=deep-purple]{--md-primary-fg-color:#7e56c2;--md-primary-fg-color--light:#9574cd;--md-primary-fg-color--dark:#673ab6;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=indigo]{--md-primary-fg-color:#4051b5;--md-primary-fg-color--light:#5d6cc0;--md-primary-fg-color--dark:#303fa1;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=blue]{--md-primary-fg-color:#2094f3;--md-primary-fg-color--light:#42a5f5;--md-primary-fg-color--dark:#1975d2;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=light-blue]{--md-primary-fg-color:#02a6f2;--md-primary-fg-color--light:#28b5f6;--md-primary-fg-color--dark:#0287cf;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=cyan]{--md-primary-fg-color:#00bdd6;--md-primary-fg-color--light:#25c5da;--md-primary-fg-color--dark:#0097a8;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=teal]{--md-primary-fg-color:#009485;--md-primary-fg-color--light:#26a699;--md-primary-fg-color--dark:#007a6c;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=green]{--md-primary-fg-color:#4cae4f;--md-primary-fg-color--light:#68bb6c;--md-primary-fg-color--dark:#398e3d;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=light-green]{--md-primary-fg-color:#8bc34b;--md-primary-fg-color--light:#9ccc66;--md-primary-fg-color--dark:#689f38;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=lime]{--md-primary-fg-color:#cbdc38;--md-primary-fg-color--light:#d3e156;--md-primary-fg-color--dark:#b0b52c;--md-primary-bg-color:rgba(0,0,0,.87);--md-primary-bg-color--light:rgba(0,0,0,.54)}[data-md-color-primary=yellow]{--md-primary-fg-color:#ffec3d;--md-primary-fg-color--light:#ffee57;--md-primary-fg-color--dark:#fbc02d;--md-primary-bg-color:rgba(0,0,0,.87);--md-primary-bg-color--light:rgba(0,0,0,.54)}[data-md-color-primary=amber]{--md-primary-fg-color:#ffc105;--md-primary-fg-color--light:#ffc929;--md-primary-fg-color--dark:#ffa200;--md-primary-bg-color:rgba(0,0,0,.87);--md-primary-bg-color--light:rgba(0,0,0,.54)}[data-md-color-primary=orange]{--md-primary-fg-color:#ffa724;--md-primary-fg-color--light:#ffa724;--md-primary-fg-color--dark:#fa8900;--md-primary-bg-color:rgba(0,0,0,.87);--md-primary-bg-color--light:rgba(0,0,0,.54)}[data-md-color-primary=deep-orange]{--md-primary-fg-color:#ff6e42;--md-primary-fg-color--light:#ff8a66;--md-primary-fg-color--dark:#f4511f;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=brown]{--md-primary-fg-color:#795649;--md-primary-fg-color--light:#8d6e62;--md-primary-fg-color--dark:#5d4037;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=grey]{--md-primary-fg-color:#757575;--md-primary-fg-color--light:#9e9e9e;--md-primary-fg-color--dark:#616161;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7);--md-typeset-a-color:#4051b5}[data-md-color-primary=blue-grey]{--md-primary-fg-color:#546d78;--md-primary-fg-color--light:#607c8a;--md-primary-fg-color--dark:#455a63;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7);--md-typeset-a-color:#4051b5}[data-md-color-primary=light-green]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#72ad2e}[data-md-color-primary=lime]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#8b990a}[data-md-color-primary=yellow]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#b8a500}[data-md-color-primary=amber]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#d19d00}[data-md-color-primary=orange]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#e68a00}[data-md-color-primary=white]{--md-primary-fg-color:#fff;--md-primary-fg-color--light:hsla(0,0%,100%,.7);--md-primary-fg-color--dark:rgba(0,0,0,.07);--md-primary-bg-color:rgba(0,0,0,.87);--md-primary-bg-color--light:rgba(0,0,0,.54);--md-typeset-a-color:#4051b5}[data-md-color-primary=white] .md-hero--expand{border-bottom:.05rem solid rgba(0,0,0,.07)}@media screen and (max-width:76.1875em){[data-md-color-primary=white] .md-hero{border-bottom:.05rem solid rgba(0,0,0,.07)}}@media screen and (min-width:60em){[data-md-color-primary=white] .md-search__form{background-color:rgba(0,0,0,.07)}[data-md-color-primary=white] .md-search__form:hover{background-color:rgba(0,0,0,.32)}[data-md-color-primary=white] .md-search__input+.md-search__icon{color:rgba(0,0,0,.87)}}@media screen and (min-width:76.25em){[data-md-color-primary=white] .md-tabs{border-bottom:.05rem solid rgba(0,0,0,.07)}}[data-md-color-primary=black]{--md-primary-fg-color:#000;--md-primary-fg-color--light:rgba(0,0,0,.54);--md-primary-fg-color--dark:#000;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7);--md-typeset-a-color:#4051b5}[data-md-color-primary=black] .md-header,[data-md-color-primary=black] .md-hero{background-color:#000}@media screen and (max-width:59.9375em){[data-md-color-primary=black] .md-nav__source{background-color:rgba(0,0,0,.87)}}@media screen and (min-width:60em){[data-md-color-primary=black] .md-search__form{background-color:hsla(0,0%,100%,.12)}[data-md-color-primary=black] .md-search__form:hover{background-color:hsla(0,0%,100%,.3)}}@media screen and (max-width:76.1875em){html [data-md-color-primary=black] .md-nav--primary .md-nav__title[for=__drawer]{background-color:#000}}@media screen and (min-width:76.25em){[data-md-color-primary=black] .md-tabs{background-color:#000}} +@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;src: url(fonts/2aadfad5aee7ceeaf4eb0924efabe5b4.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;src: url(fonts/8e48cf20cf9f9e5feb7197c79028132b.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;src: url(fonts/638764dc2513deb09c55fc025f6dd36c.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;src: url(fonts/8007dfe835cfb201b8caaa9651098588.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;src: url(fonts/8c3798e37724f71bc0c63c44a5307413.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;src: url(fonts/ca7eea0cf248d6e8442c01074765bd33.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;src: url(fonts/10b31f4cad9ea78d43449886bfbb88ac.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;src: url(fonts/0f303f31706d39866cced9dcc17b61fb.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;src: url(fonts/6de03a64aa8100032abc6e836b3ed803.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;src: url(fonts/0ec3cc19652785204ea2e322330f0f1b.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;src: url(fonts/b57a5ada789f195d5d42f4073a6cf313.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;src: url(fonts/4f17f22fc6bff4f3333ccf7ed7126e6d.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;src: url(fonts/daf12b5f1889502004bba85ad71f9fa4.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;src: url(fonts/7b63598dcc2a26583b82594bd0e36d5b.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;src: url(fonts/64a6b4e954cf84685cbf8de77eb47344.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;src: url(fonts/b19ac4e57f2a56639eebd1c35319e5a7.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;src: url(fonts/8c49ed8b472d38d3985ec9bbbccea601.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;src: url(fonts/435e4b7f9f250d9d9243d4754799fc96.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;src: url(fonts/47aa3bfad6cb9e2d63abdd58f4e6ce4f.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;src: url(fonts/20dc200cc43ab904876fb0c1697ebe39.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;src: url(fonts/455c2c1af0a2bf20047a1864d7d7c174.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;src: url(fonts/51f3f41805329fb8341beb56ded833ea.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;src: url(fonts/b076e86301cbee8c5c9aef51863a9c0a.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;src: url(fonts/f75911313e1c7802c23345ab57e754d8.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;src: url(fonts/28e6b81b1bc1964707edd4179e4268f5.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;src: url(fonts/e704ef18719c08839bc99a32437ef0f8.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;src: url(fonts/76945c7494c20515bb45d1dedab8f706.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;src: url(fonts/b5b4146d87e5d22d0a4e0d04f3ee5626.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;src: url(fonts/21953b998bab09c1f60c599caee56378.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;src: url(fonts/e33716333704ab19fdf9989e072ad49a.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;src: url(fonts/f53f3b5a15d717b6d21d7885285e90ed.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;src: url(fonts/bb8007225d94a099cddbade7ea904667.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;src: url(fonts/3254c528e2ab56454a9f22191035c5fe.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;src: url(fonts/b7ef2cd1159a8cbfd271ff2abe07f237.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;src: url(fonts/495d38d4b9741e8aa4204002414069e2.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;src: url(fonts/d368cf5bed7856dbafa2af36b51acb9c.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;src: url(fonts/daf51ab540602b2d0b87646621637bac.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;src: url(fonts/77b24796a3d4ab521f66765651875338.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;src: url(fonts/3c23eb02de6b34e30f18cfb7167abd81.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;src: url(fonts/f6734f8177112c0839b961f96d813fcb.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;src: url(fonts/0e326670106c8eb6a11a8c30734ecfc8.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;src: url(fonts/a6caf7b9888eb0c382948c1ca5e8bebb.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;src: url(fonts/a6933e678530b263486fa7b185a449ca.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;src: url(fonts/144860ed1e48e186f08997e6388a9c3f.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;src: url(fonts/2ea7a97b7c976b121112a088eb398561.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;src: url(fonts/0b68e8634c96265eb32a0c769416b5b0.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;src: url(fonts/9582ced8a675bf267cc7ac392a86413e.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;src: url(fonts/db0424fb67fb52e7e538490240cc7fb9.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;src: url(fonts/2096d27efc16cbdd79183bf295c8ebde.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;src: url(fonts/aeed0e51b0bac7c89e5c7e6cf086d7e0.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;src: url(fonts/3728fbdd191d75bad5b83a838dfe2fc1.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;src: url(fonts/ef8f0236a7e8b46bc9d642ecf4ab0cb7.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;src: url(fonts/713780d8b30bda5583052ea847cdcb4f.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;src: url(fonts/0948409a22b5979aa7e1ec20da9e61f1.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;src: url(fonts/7f1c829b0c90fd664a03bb714a74f7d3.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;src: url(fonts/b019538234514166ec7665359d097403.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;src: url(fonts/38f3ee1f96b758f95672c632d8759594.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;src: url(fonts/4c815fdc869f885520f7c8eae6730edf.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;src: url(fonts/6deb20301c65a96db17c433ad0cf8158.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;src: url(fonts/63111d307c01b52ffccf7b0319cb7917.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;src: url(fonts/e56cc9fb5272752b78f144b4be43175d.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;src: url(fonts/2e10480d4154762bc7c8fbb40877e104.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;src: url(fonts/7af61b2367eba2b1852e837c46a75696.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;src: url(fonts/661d4b208656c006e7aab58acf778485.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;src: url(fonts/ac848474638236e67a64bc654fb18de0.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;src: url(fonts/3c505383d37d2078648e37868bbd1fad.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;src: url(fonts/6a84eeee6a25e7c9a8a03191007a6720.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;src: url(fonts/5b6377da4c959db6d4b22738a27f1bee.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;src: url(fonts/1c9cc76fd52238330f0aabac35acd2ca.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;src: url(fonts/4ec57f2a80b91090971b83970230ca09.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;src: url(fonts/fc66f942651a9fe1a598770d3d896529.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;src: url(fonts/f5aebdfea35d1e7656ef4acc5db1f243.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;src: url(fonts/8aa562790559d61dd5178a88a296d70f.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;src: url(fonts/ccdebed88064e470c15f37c432922e57.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;src: url(fonts/c8a9fd4eab4e83382cc66fde70911b41.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;src: url(fonts/5d7ff31ac7bf945e8d61878f8a941239.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;src: url(fonts/2a8c422bef4a7099e99dbf0e61ed5e49.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;src: url(fonts/bdbb6b52604c2451fdcba9cdfd44f4e1.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;src: url(fonts/acaac043ca238f0e56e61864456777fa.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;src: url(fonts/6be97ca17228a69c406231d89c003194.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;src: url(fonts/84e959dd07f302392f0ffd86f87db888.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;src: url(fonts/f265cee675c0e5b2d6ab263d0edcc754.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;src: url(fonts/9fdb12ceee3a402d3a54afe354552459.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;src: url(fonts/76da333ab59c6d625cabfb0768f82b4a.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;src: url(fonts/2550c2e2d8495c3ed2d4d52f824374f1.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;src: url(fonts/3a38c967413f7bce36d3baefc321aade.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;src: url(fonts/2781e9e7c3f369b8fc7965e679b17b60.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;src: url(fonts/7e262106f82cc52663e403f5b73795bb.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;src: url(fonts/2f5c32f094829c0278bce28fe2bbe074.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;src: url(fonts/0d1b73eee266eabb2cff35dfa4ce25a3.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;src: url(fonts/da6cd48e6dad1888fccc91735e7522f7.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;src: url(fonts/50aacf068f685be0dd903a91d5bab7d8.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;src: url(fonts/1383417807f7965daaf94e7c497dcddb.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;src: url(fonts/3f1918538864f9681d47a4538d48289c.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;src: url(fonts/bfd1a0c9c783e84595589f33e1828a57.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;src: url(fonts/3cf78ad3bcd1324e10a4acdc34bfc4a1.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 100;src: url(fonts/c6dc61b627bbc5af9130518297bd4f17.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 100;src: url(fonts/78a9265759e7b861a1639a36f4c01d04.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 100;src: url(fonts/2f7c3c315334a99574ee4ceb21af654d.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 100;src: url(fonts/870e5928dd14fcfe0ce9386107666774.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 100;src: url(fonts/36e39c6463ae1c71c71e69c05e593e1b.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 100;src: url(fonts/cbfd26d5bcf084ee407a0b2b7599e84b.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 100;src: url(fonts/cce2217cc8323fe49789adefb3596291.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 200;src: url(fonts/7fa86b886bee5d6ab420a8e89b9f3052.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 200;src: url(fonts/4f93c2808e3b69e525c118074e5de31f.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 200;src: url(fonts/99be4d68845d66c27c7f7d3a48687b66.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 200;src: url(fonts/029e176ad602329b4434892101db9cf3.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 200;src: url(fonts/9095d663e4d450059bcc2260bb75cd62.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 200;src: url(fonts/1181a8e619707033241139715eca64c6.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 200;src: url(fonts/22aadc77cafa07b2db9ed560d0320616.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 300;src: url(fonts/6ad3f6bbe6220cc476a0d3c731d3fb04.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 300;src: url(fonts/5dc0e4b14e903ba7f45c581df7402b3f.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 300;src: url(fonts/63f4b74ebf127dbeb033126ea988f54e.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 300;src: url(fonts/f5f971e9640a9eb86ef553a7e7e999c7.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 300;src: url(fonts/0053ba6958e79f26751eabb555bd73d0.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 300;src: url(fonts/4207cbc8cb7bc2cbd0bcce565298cbbc.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 300;src: url(fonts/90ebb29b5cffa197b184773983ba7e91.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 400;src: url(fonts/6ac1ee292434fac2313c42b0dfb7897c.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 400;src: url(fonts/aa28d99c7db60ad23f96a5c317615c42.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 400;src: url(fonts/52f28cb4d065b4adfa78df4f9559c639.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 400;src: url(fonts/122802d03aed4bf8cd6a03997a97aca4.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 400;src: url(fonts/4039566f251699c4b421ed1a38a59b24.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 400;src: url(fonts/93b6c99d936df38895a0d95e3ffea2fd.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 400;src: url(fonts/32c8a74ac0816253d69a7cc68a60986d.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 500;src: url(fonts/1512b579343c6b61c7523cdd838d8328.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 500;src: url(fonts/d6f9cdf1a40893111566fcdee3bbe5a9.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 500;src: url(fonts/25c52b9af13f0d1b10719f5289e8c803.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 500;src: url(fonts/b4e42731e8d667ae87c3450c345754ae.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 500;src: url(fonts/214adfc289a2f2af8b0008c59ed0c7f2.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 500;src: url(fonts/f55dac651a40fce74a5cf5728d9f8ffc.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 500;src: url(fonts/0e1f73c6737cdf273efb4b79504e4c0a.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 600;src: url(fonts/bf2ad3287f13eb7076cccb516ec2986f.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 600;src: url(fonts/aab05142e0e2dadf7df633e061e612ad.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 600;src: url(fonts/8a8dca39f24b52e89e6fd6dcd8b6dd32.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 600;src: url(fonts/7b8c2179b6b778308d2ff39bdb82e926.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 600;src: url(fonts/77ff81100e5a1db3d925f713660700ad.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 600;src: url(fonts/101522bafe9c61c68698ecc784607772.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 600;src: url(fonts/c28a41f656599f6694528b5463c6a445.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 700;src: url(fonts/89b4f174a5a728d2d8c85b87990c9ab4.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 700;src: url(fonts/bcd47c2f3649cfcaa86a08fb741255d6.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 700;src: url(fonts/770518db51bed1e082feecc532cfcbf8.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 700;src: url(fonts/85a41b80c5fdc14e3dc48636a30d87dd.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 700;src: url(fonts/fb17f56622e45dd4ecee00bb5c63cd2b.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 700;src: url(fonts/cd3d1f17e048e2116f438bd7157baccf.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 700;src: url(fonts/6f8d857c5a8545e67de6b60aa0fe5c33.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 100;src: url(fonts/302b0425bf5ea66f37a822a61d723adc.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 100;src: url(fonts/c22066c14662d6c80415ae04c5dd9d51.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 100;src: url(fonts/de018865c95896bb57265fc97c48ebd7.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 100;src: url(fonts/3177dacffeac1eb4102852811ae4a2c7.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 100;src: url(fonts/5989ef3a21d7f252337ab3326f78bde7.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 100;src: url(fonts/dd719f1662079ce6a61260f9af972379.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 100;src: url(fonts/07ff82964967feebb9c96288e0e0df05.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 200;src: url(fonts/765bd4a97597a4d7781193793477a6cd.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 200;src: url(fonts/bd0efe13f0d9d591b337ddc7f289f494.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 200;src: url(fonts/ab03beb9091fa15ce4e783199e076bc6.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 200;src: url(fonts/a70ff2592da5e3453943f727633aff54.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 200;src: url(fonts/0a0ad0eae50e549ecd713b9ad417f1a1.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 200;src: url(fonts/d07f561ba87d93460742b060727d9e0d.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 200;src: url(fonts/43358c04243de546caddd0898dbf0757.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 300;src: url(fonts/71e06579279fba7436d58a1c49288909.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 300;src: url(fonts/fb1aaa90783b8cb9375265abeb91b153.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 300;src: url(fonts/2325b97b584755067ea4f7f56ee05430.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 300;src: url(fonts/f534242dea2255c25b9d05c2371986e3.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 300;src: url(fonts/9c9be791a58af8a04c611ca1d13f51c6.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 300;src: url(fonts/f2f69e8cd15fdd15a4244c95ec8a8514.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 300;src: url(fonts/555ceea3a65ffbbecf8b7e6d04966c7f.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 400;src: url(fonts/d98f35e926c11f3d5c0c8e3205d43907.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 400;src: url(fonts/b93199bb6f964f190f4da04ecdbaf5a4.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 400;src: url(fonts/99cf36e763be9cce7b4c59b91841af58.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 400;src: url(fonts/1488146d8b2e9859d6c90e6c2b48f7ef.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 400;src: url(fonts/255cf41e0317d95e3992683a76ef28a8.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 400;src: url(fonts/f154d62b4879af7a22895af7a4ef03f0.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 400;src: url(fonts/dc25cbf4baaf778bd8ae78fbc0e79479.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 500;src: url(fonts/bc67bba106323289ea3eda0826de1912.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 500;src: url(fonts/33c5d27ca0eaeb12ebe728ae2fc7106d.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 500;src: url(fonts/c13b34dd5b6a35b309944b61c91b2ace.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 500;src: url(fonts/392ff374142585f7b886ee1fe66e686e.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 500;src: url(fonts/1f1481679a64a39f3427547aa1b13f0f.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 500;src: url(fonts/f17ee050ada0453f3bd07bc466c2dde2.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 500;src: url(fonts/6725a7e91680edd1cdc9ed5c26ac05fd.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 600;src: url(fonts/cadfb311297a9362b07fab73934b432a.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 600;src: url(fonts/e99627cd27de169d23ece4573006af2a.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 600;src: url(fonts/bd51fb0ca67e64c809ffcf7e1370f969.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 600;src: url(fonts/437939342255944b82a49f916404c5fc.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 600;src: url(fonts/83614c36460a4a9734968789cb535de7.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 600;src: url(fonts/d9e6a498dac7e9e91f6e0b4f8930eba0.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 600;src: url(fonts/b4d3c40a77fd9e35a881a79077957055.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 700;src: url(fonts/d422317033deb87342a5e56c7be67458.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 700;src: url(fonts/2c0f74be498d2da814c0a84dd6833f70.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 700;src: url(fonts/9bcbc88b33b2efc2aee821b831499f1c.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 700;src: url(fonts/8898c4b754d5d96c1a5e1b1d54100554.woff2) format('woff2');unicode-range: U+0370-03FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 700;src: url(fonts/9a9bf2d91ebbb1b96eab8eb0b0514bcc.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 700;src: url(fonts/60eb682678bbea5e8ad71f66f2f65536.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 700;src: url(fonts/5ce47d5195e59af38114d0b70217baf2.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;} +:root{--si-icon--material_alert-circle:url('data:image/svg+xml;charset=utf-8,');--si-icon--material_delete:url('data:image/svg+xml;charset=utf-8,');}.md-typeset .si-icon-inline.material_alert-circle::before{-webkit-mask-image:var(--si-icon--material_alert-circle);mask-image:var(--si-icon--material_alert-circle);}.md-typeset .si-icon-inline.material_delete::before{-webkit-mask-image:var(--si-icon--material_delete);mask-image:var(--si-icon--material_delete);}.md-typeset .admonition.versionadded{border-color:rgb(72,138,87);}.md-typeset .versionadded>.admonition-title{background-color:rgba(72,138,87,0.1);border-color:rgb(72,138,87);}.md-typeset .versionadded>.admonition-title::before{background-color:rgb(72,138,87);-webkit-mask-image:var(--si-icon--material_alert-circle);mask-image:var(--si-icon--material_alert-circle);}.md-typeset .admonition.versionchanged{border-color:rgb(238,144,64);}.md-typeset .versionchanged>.admonition-title{background-color:rgba(238,144,64,0.1);border-color:rgb(238,144,64);}.md-typeset .versionchanged>.admonition-title::before{background-color:rgb(238,144,64);-webkit-mask-image:var(--si-icon--material_alert-circle);mask-image:var(--si-icon--material_alert-circle);}.md-typeset .admonition.deprecated{border-color:rgb(203,70,83);}.md-typeset .deprecated>.admonition-title{background-color:rgba(203,70,83,0.1);border-color:rgb(203,70,83);}.md-typeset .deprecated>.admonition-title::before{background-color:rgb(203,70,83);-webkit-mask-image:var(--si-icon--material_delete);mask-image:var(--si-icon--material_delete);} diff --git a/_static/white.svg b/_static/white.svg new file mode 100644 index 00000000..d80d1492 --- /dev/null +++ b/_static/white.svg @@ -0,0 +1,54 @@ + + \ No newline at end of file diff --git a/cli.html b/cli.html new file mode 100644 index 00000000..4c7905b1 --- /dev/null +++ b/cli.html @@ -0,0 +1,881 @@ + + + + + + + + + + + + + + + + Command-line Interface - Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +

Command-line Interface

+

Building design

+

To run Topwrap, use:

+
python -m topwrap build --design project.yml
+
+
+

Where project.yml should be your file with description of the top module.

+

You can specify a directory to be scanned for additional sources:

+
python -m topwrap build --sources src --design project.yml
+
+
+

To implement the design for a specific FPGA chip, provide the part name:

+
python -m topwrap build --sources src --design project.yml --part 'xc7z020clg400-3'
+
+
+

Connect Topwrap to Pipeline Manager

+

If you want to use Pipeline Manager as a UI for creating block design, you need to:

+
    +
  1. Build and run Pipeline Manager server application.

  2. +
+
python -m topwrap kpm_build_server
+python -m topwrap kpm_run_server
+
+
+
    +
  1. Run Topwrap’s client application, that will connect to a running Pipeline Manager server app.

  2. +
+
python -m topwrap kpm_client [-h ip_addr] [-p port] [-d FILE] FILES
+
+
+

Topwrap will then try to connect to the server running on ip_addr:port and send a specification generated from FILES, which should be IP core description yamls.

+

If -h or -p options are not specified, ip address 127.0.0.1 and port 9000 will be chosen by default.

+

If -d option is specified, kpm will start with specified design file loaded.

+

Generating IP core description YAMLs

+

You can also use Topwrap to generate ip core description yamls from HDL sources, +that can be later used in your project.yml:

+
python -m topwrap parse HDL_FILES
+
+
+

In HDL source files, ports that belong to the same interface (e.g. wishbone or AXI), +have often a common prefix, which corresponds to the interface name. If such naming +convention is followed in the HDL sources, Topwrap can also divide ports into user-specified +interfaces, or automatically deduce interfaces names when generating yaml file:

+
python -m topwrap parse --iface wishbone --iface s_axi HDL_FILES
+
+python -m topwrap parse --iface-deduce HDL_FILES
+
+
+

To get help, use:

+
python -m topwrap [build|kpm_client|parse] --help
+
+
+ + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/description_files.html b/description_files.html new file mode 100644 index 00000000..62386a70 --- /dev/null +++ b/description_files.html @@ -0,0 +1,1071 @@ + + + + + + + + + + + + + + + + Description files - Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +

Description files

+

Design Description

+

To create a complete, fully synthesizable design, a proper design file is needed. +It’s used to specify interconnects, IP cores, set their parameters’ values, describe hierarchies for the project, +connect the IPs and hierarchies, and pick external ports (those which will be connected to physical I/O).

+

You can see example design files in examples directory. The structure is as below:

+
ips:
+  # specify relations between IPs names in the design yaml
+  # and IP cores description yamls and modules
+  {ip_instance_name}:
+    file: {path_to_yaml_file_of_the_ip}
+    module: {name_of_the_HDL_module}
+  ...
+
+design:
+  name: {design_name} # optional name of the toplevel
+  hierarchies:
+      # see "Hierarchies" page for a detailed description of the format
+      ...
+  parameters: # specify IPs parameter values to be overridden
+    {ip_instance_name}:
+      {param_name} : {param_value}
+      ...
+
+  ports:
+    # specify incoming ports connections of an IP named `ip1_name`
+    {ip1_name}:
+      {port1_name} : [{ip2_name}, {port2_name}]
+      ...
+    # specify incoming ports connections of a hierarchy named `hier_name`
+    {hier_name}:
+      {port1_name} : [{ip_name}, {port2_name}]
+      ...
+    # specify external ports connections
+    {ip_instance_name}:
+      {port_name} : ext_port_name
+    ...
+
+  interfaces:
+    # specify incoming interfaces connections of `ip1_name` IP
+    {ip1_name}:
+      {iface1_name} : [{ip2_name}, {iface2_name}]
+      ...
+    # specify incoming interfaces connections of `hier_name` hierarchy
+    {hier_name}:
+      {iface1_name} : [{ip_name}, {iface2_name}]
+      ...
+    # specify external interfaces connections
+    {ip_instance_name}:
+      {iface_name} : ext_iface_name
+    ...
+
+  interconnects:
+    # see "Interconnect generation" page for a detailed description of the format
+    ...
+
+external: # specify names of external ports and interfaces of the top module
+  ports:
+    out:
+      - {ext_port_name}
+    inout:
+      - [{ip_name/hierarchy_name, port_name}]
+  interfaces:
+    in:
+      - {ext_iface_name}
+    # note that `inout:` is invalid in the interfaces section
+
+
+

inout ports are handled differently than in and out ports. When any IP has an inout port or when a hierarchy has an inout port specified in its external.ports.inout section, it must be included in external.ports.inout section of the parent design by specifying the name of the IP/hierarchy and port name that contains it. Name of the external port will be identical to the one in the IP core. In case of duplicate names a suffix $n is added (where n is a natural number) to the name of the second and subsequent duplicate names. inout ports cannot be connected to each other.

+

The design description yaml format allows creating hierarchical designs. In order to create a hierarchy, it suffices to add its name as a key in the design section and describe the hierarchy design “recursively” by using the same keys and values (ports, parameters etc.) as in the top-level design (see above). Hierarchies can be nested recursively, which means that you can create a hierarchy inside another one.

+

Note that IPs and hierarchies names cannot be duplicated on the same hierarchy level. For example, the design section cannot contain two identical keys, but it’s correct to have ip_name key in this section and ip_name in the design section of some hierarchy.

+

IP description files

+

Every IP wrapped by Topwrap needs a description file in YAML format.

+

The ports of an IP should be placed in global signals node, followed by the direction of in, out or inout. +Here’s an example description of ports of Clock Crossing IP:

+
# file: clock_crossing.yaml
+signals:
+    in:
+        - clkA
+        - A
+        - clkB
+    out:
+        - B
+
+
+

The previous example is enough to make use of any IP. However, in order to benefit from connecting whole interfaces at once, ports must belong to a named interface like in this example:

+
#file: axis_width_converter.yaml
+interfaces:
+    s_axis:
+        type: AXIStream
+        mode: slave
+        signals:
+            in:
+                TDATA: [s_axis_tdata, 63, 0]
+                TKEEP: [s_axis_tkeep, 7, 0]
+                TVALID: s_axis_tvalid
+                TLAST: s_axis_tlast
+                TID: [s_axis_tid, 7, 0]
+                TDEST: [s_axis_tdest, 7, 0]
+                TUSER: s_axis_tuser
+            out:
+                TREADY: s_axis_tready
+
+    m_axis:
+        type: AXIStream
+        mode: master
+        signals:
+            in:
+                TREADY: m_axis_tready
+            out:
+                TDATA: [m_axis_tdata, 31, 0]
+                TKEEP: [m_axis_tkeep, 3, 0]
+                TVALID: m_axis_tvalid
+                TLAST: m_axis_tlast
+                TID: [m_axis_tid, 7, 0]
+                TDEST: [m_axis_tdest, 7, 0]
+                TUSER: m_axis_tuser
+signals: # These ports don't belong to any interface
+    in:
+        - clk
+        - rst
+
+
+

Names s_axis and m_axis will be used to group the selected ports. +Each signal in an interface has a name which must match with the signal it’s supposed to be connected to, for example TDATA: port_name will be connected to TDATA: other_port_name.

+

Note that you don’t have to write IP core description yamls by hand. You can use Topwrap’s parse command (see Generating IP core description YAMLs) in order to generate yamls from HDL source files and then adjust the yaml to your needs.

+

Port widths

+

The width of every port defaults to 1. +You can specify the width using this notation:

+
interfaces:
+    s_axis:
+        type: AXIStream
+        mode: slave
+        signals:
+            in:
+                TDATA: [s_axis_tdata, 63, 0] # 64 bits
+                ...
+                TVALID: s_axis_tvalid # defaults to 1 bit
+
+signals:
+    in:
+        - [gpio_io_i, 31, 0] # 32 bits
+
+
+

Parameterization

+

Port widths don’t have to be hardcoded - you can use parameters to describe an IP core in a generic way. +Values specified in IP core yamls can be overridden in a design description file (see Design Description).

+
parameters:
+    DATA_WIDTH: 8
+    KEEP_WIDTH: (DATA_WIDTH+7)/8
+    ID_WIDTH: 8
+    DEST_WIDTH: 8
+    USER_WIDTH: 1
+
+interfaces:
+    s_axis:
+        type: AXI4Stream
+        mode: slave
+        signals:
+            in:
+                TDATA: [s_axis_tdata, DATA_WIDTH-1, 0]
+                TKEEP: [s_axis_tkeep, KEEP_WIDTH-1, 0]
+                ...
+                TID: [s_axis_tid, ID_WIDTH-1, 0]
+                TDEST: [s_axis_tdest, DEST_WIDTH-1, 0]
+                TUSER: [s_axis_tuser, USER_WIDTH-1, 0]
+
+
+

Parameters values can be integers or math expressions, which are evaluated using numexpr.evaluate().

+

Port slicing

+

You can also slice a port, to use some bits of the port as a signal that belongs to an interface. +The example below means:

+

Port m_axi_bid of the IP core is 36 bits wide. Use bits 23..12 as the BID signal of AXI master named m_axi_1

+
m_axi_1:
+    type: AXI
+    mode: master
+    signals:
+        in:
+            BID: [m_axi_bid, 35, 0, 23, 12]
+
+
+

Interface Description files

+

Topwrap can use predefined interfaces described in YAML files that come packaged with the tool. +Currently supported interfaces are AXI4, AXI3, AXI Stream, AXI Lite and Wishbone.

+

You can see an example file below:

+
name: AXI4Stream
+port_prefix: AXIS
+signals:
+    # convention assumes the AXI Stream transmitter (master) perspective
+    required:
+        out:
+            TVALID: tvalid
+            TDATA: tdata
+            TLAST: tlast
+        in:
+            TREADY: tready
+    optional:
+        out:
+            TID: tid
+            TDEST: tdest
+            TKEEP: tkeep
+            TSTRB: tstrb
+            TUSER: tuser
+            TWAKEUP: twakeup
+
+
+

The name of an interface has to be unique. +We also specify a prefix which will be used as a shortened identifier. +Signals are either required or optional. +Their direction is described from the the perspective of master (i.e. directionality of signals in the slave is flipped) - note that clock and reset are not included as these are usually inputs in both master and slave so they’re not supported in interface specification. +These distinctions are used when an option to check if all mandatory signals are present is enabled and when parsing an IP core with topwrap parse (not all required signals must necessarily be present but it’s taken into account). +Every signal is a key-value pair, where the key is a generic signal name (usually from interface specification) and value is a regex that is used to pair the generic name with a concrete signal name in the RTL source when using topwrap parse. +This pairing is performed on signal names that are transformed to lowercase and have a common prefix of an interface they belong to removed. +If a regexp occurs in such transformed signal name anywhere, that name is paired with the generic name. +Since this occurs on names that have all characters in lowercase, regex must be written in lowercase as well.

+ + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/developers_guide/config.html b/developers_guide/config.html new file mode 100644 index 00000000..48d6e81b --- /dev/null +++ b/developers_guide/config.html @@ -0,0 +1,895 @@ + + + + + + + + + + + + + + + + Config - Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +

Config

+

A Config object stores configuration values. +A global topwrap.config.config object is used throughout the codebase to access topwrap’s configuration. +This is created by ConfigManager that reads config files defined in topwrap.config.ConfigManager.DEFAULT_SEARCH_PATHS, with files most local to the project taking precedence.

+
+
+class Config(force_interface_compliance: bool | None = False, repositories: ~typing.List[~topwrap.config.RepositoryEntry] | None = <factory>)
+

Global topwrap configuration

+
+
+__init__(force_interface_compliance: bool | None = False, repositories: ~typing.List[~topwrap.config.RepositoryEntry] | None = <factory>)
+
+ +
+
+Schema
+

alias of Config

+
+ +
+ +
+
+class ConfigManager(search_paths: List[PathLike] | None = None)
+

Manager used to load topwrap’s configuration from files.

+

The configuration files are loaded in a specific order, which also +determines the priority of settings that are defined differently +in the files. The list of default search paths is defined in +the DEFAULT_SEARCH_PATH class variable. Configuration files that +are specified earlier in the list have higher priority and can +overwrite the settings from the files that follow. The default list of +search paths can be changed by passing a different list to +the ConfigManager constructor.

+
+
+__init__(search_paths: List[PathLike] | None = None)
+
+ +
+ + + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/developers_guide/elaboratable_wrapper.html b/developers_guide/elaboratable_wrapper.html new file mode 100644 index 00000000..f3c01c68 --- /dev/null +++ b/developers_guide/elaboratable_wrapper.html @@ -0,0 +1,914 @@ + + + + + + + + + + + + + + + + ElaboratableWrapper class - Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +

ElaboratableWrapper class

+

ElaboratableWrapper encapsulates an Amaranth’s Elaboratable and exposes an interface compatible with other wrappers which allows making connections with them. +Supplied elaboratable must contain a signature property and a conforming interface as specified by Amaranth docs. +Ports’ directionality, their names and widths are inferred from it.

+
+
+class ElaboratableWrapper(*args, src_loc_at=0, **kwargs)
+

Allows connecting an Amaranth’s Elaboratable with other +classes derived from Wrapper.

+
+
+__init__(name: str, elaboratable: Elaboratable)
+
+
Parameters:
+
+
name: str

name of this wrapper

+
+
elaboratable: Elaboratable

Amaranth’s Elaboratable object to wrap

+
+
+
+
+
+ +
+
+get_ports() List[WrapperPort]
+

Return a list of external ports.

+
+ +
+
+get_ports_hier() Mapping[str, Signal | Mapping[str, Signal | SignalMapping]]
+

Maps elaboratable’s Signature to a nested dictionary of WrapperPorts. +See _gather_signature_ports for more details.

+
+ +
+ + + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/developers_guide/examples.html b/developers_guide/examples.html new file mode 100644 index 00000000..1dcb7725 --- /dev/null +++ b/developers_guide/examples.html @@ -0,0 +1,802 @@ + + + + + + + + + + + + + + + + Examples - Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +

Examples

+
+

Note

+

Basic usage of examples is explained in the Getting started section.

+
+

Examples provided with this project should cover from very simple designs to complex fully synthesizable cores. +They should be sorted by increasing complexity and number of used features, e.g:

+
    +
  • 101: minimal base design

  • +
  • 102: introduce user to parameters

  • +
  • 103: introduce user to slicing

  • +
  • 104: introduce user to interfaces

  • +
  • 105: etc.

  • +
+

Developers are encouraged to create/add new examples in the same spirit. +Simple examples are used to teach how to use this tool and demonstrate its features. +Real-world use cases are also welcome to prove that the implementation is mature enough to handle practical designs.

+ + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/developers_guide/fusesocbuilder.html b/developers_guide/fusesocbuilder.html new file mode 100644 index 00000000..d8f83212 --- /dev/null +++ b/developers_guide/fusesocbuilder.html @@ -0,0 +1,974 @@ + + + + + + + + + + + + + + + + FuseSocBuilder - Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +

FuseSocBuilder

+

Topwrap has support for generating FuseSoC’s core files with FuseSocBuilder. +Such core file contains information about source files and synthesis tools. +Generation is based on a jinja template that defaults to topwrap/templates/core.yaml.j2 but can be overridden.

+

Here’s an example of how to generate a simple project:

+
from topwrap.fuse_helper import FuseSocBuilder
+fuse = FuseSocBuilder()
+
+# add source of the IPs used in the project
+fuse.add_source('DMATop.v', 'verilogSource')
+
+# add source of the top file
+fuse.add_source('top.v', 'verilogSource')
+
+# specify the names of the Core file and the directory where sources are stored
+# generate the project
+fuse.build('build/top.core', 'sources')
+
+
+
+

Warning

+

Default template in topwrap/templates/core.yaml.j2 does not make use of resources added with add_dependency() or add_external_ip(), i.e. they won’t be present in the generated core file.

+
+
+
+class FuseSocBuilder(part)
+

Use this class to generate a FuseSoC .core file

+
+
+__init__(part)
+
+ +
+
+add_dependency(dependency: str)
+

Adds a dependency to the list of dependencies in the core file

+
+ +
+
+add_external_ip(vlnv: str, name: str)
+

Store information about IP Cores from Vivado library +to generate hooks that will add the IPs in a TCL script.

+
+ +
+
+add_source(filename, type)
+

Adds an HDL source to the list of sources in the core file

+
+ +
+
+add_sources_dir(sources_dir)
+

Given a name of a directory, add all files found inside it. +Recognize VHDL, Verilog, and XDC files.

+
+ +
+
+build(core_filename, sources_dir=[], template_name=None)
+

Generate the final create .core file

+
+
Parameters:
+
+
sources_dir=[]

additional directory with source files to add

+
+
template_name=None

name of jinja2 template to be used, +either in working directory, or bundled with the package. +defaults to a bundled template

+
+
+
+
+
+ +
+ + + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/developers_guide/future_enhancements.html b/developers_guide/future_enhancements.html new file mode 100644 index 00000000..694be8cc --- /dev/null +++ b/developers_guide/future_enhancements.html @@ -0,0 +1,880 @@ + + + + + + + + + + + + + + + + Future enhancements - Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +

Future enhancements

+

Support for hierarchical block design in Pipeline Manager

+

Currently topwrap supports creating hierarchical designs only by manually writing the hierarchy in the design description YAML. +Supporting such feature in the Pipeline Manager via its subgraphs would be a huge improvement in terms of organizing complex designs.

+

Bus management

+

Another goal we’d like to achieve is to enable users to create full-featured designs with processors by providing proper support for bus management. +This should include features such as:

+
    +
  • ability to specify the address of a peripheral device on the bus

  • +
  • support for the most popular buses or the ones that we use (AXI, wishbone, Tile-link)

  • +
+

This will require writing or creating bus arbiters (round-robin, crossbar) and providing a mechanism for connecting master(s) and slave(s) together. +As a result, the user should be able to create complex SoC with Topwrap.

+

Currently only experimental support for Wishbone with a round-robin arbiter is available.

+

Improve the process of recreating a design from a YAML file

+

One of the main features that are supported by Topwrap and Pipeline Manager is exporting and importing user-created design to or from a design description YAML. However, during these conversions, information about the positions of user-added nodes is not preserved. This is cumbersome in the case of complicated designs since the imported nodes cannot be placed in the optimal positions.

+

Therefore, one of our objectives is to provide a convenient way of creating and restoring user-created designs in Pipeline Manager, so that the user doesn’t have to worry about node positions when importing a design to Pipeline Manager.

+

Support for parsing SystemVerilog sources

+

Information about IP cores is stored in IP core description YAMLs. These files can be generated automatically from HDL source files - currently Verilog and VHDL are supported. Our goal is to provide the possibility of generating such YAMLs from SystemVerilog too.

+

Provide a way to parse HDL sources from the Pipeline Manager level

+

Another issue related to HDL parsing is that the user has to manually parse HDL sources to obtain the IP core description YAMLs. Then the files need to be provided as command-line parameters when launching the Topwrap Pipeline Manager client application. Therefore, we aim to provide a way of parsing HDL files and including them in the editor directly from the Pipeline Manager level.

+

Ability to produce top-level wrappers in VHDL

+

Topwrap now uses Amaranth to generate top-level design in Verilog. We would also like to add the ability to produce such designs in VHDL.

+

Library of open-source cores

+

Currently user has to supply all of the cores used in the design manually or semi-manually (e.g. through FuseSoC). +A repository of open-source cores that could be easily reused in topwrap would improve convenience and allow quickly putting together a design from premade hardware blocks.

+

Integrating with other tools

+

Topwrap can build the design but testing and synthesis rely on the user - they have to automate this process themselves (e.g. with makefiles). +Ideally the user should be able to write scripts that integrate tools for synthesis, simulation and co-simulation (e.g. with Renode) with topwrap. +Some would come pre-packaged with topwrap (e.g. simulation with verilator, synthesis with vivado). +It should also be possible to invoke these from the Pipeline Manager GUI by using its ability to add custom buttons and integrated terminal.

+ + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/developers_guide/interface.html b/developers_guide/interface.html new file mode 100644 index 00000000..a616c07d --- /dev/null +++ b/developers_guide/interface.html @@ -0,0 +1,887 @@ + + + + + + + + + + + + + + + + Interface definition - Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +

Interface definition

+

Topwrap uses interface definition files for its parsing functionality. +These are used to match a given set of signals that appear in the HDL source with signals in the interface definition.

+

InterfaceDefinition is defined as a marshmallow_dataclass.dataclass - this enables loading YAML structure into Python objects and performs validation (that the YAML has the correct format) and typechecking (that the loaded values are of correct types).

+
+
+class InterfaceDefinition(name: str, port_prefix: str, signals: InterfaceDefinitionSignals)
+

Interface described in YAML interface definition file

+
+
+__init__(name: str, port_prefix: str, signals: InterfaceDefinitionSignals)
+
+ +
+
+Schema
+

alias of InterfaceDefinition

+
+ +
+ +
+
+get_interface_by_name(name: str) InterfaceDefinition | None
+

Retrieve interface definition by its name

+
+
Returns:
+

InterfaceDefinition object, or None if there’s no such interface

+
+
+
+ + + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/developers_guide/ipconnect.html b/developers_guide/ipconnect.html new file mode 100644 index 00000000..3e46c95e --- /dev/null +++ b/developers_guide/ipconnect.html @@ -0,0 +1,1686 @@ + + + + + + + + + + + + + + + + IPConnect class - Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +

IPConnect class

+

IPConnect provides means of connecting ports and interfaces of objects that are subclasses of Wrapper. +Since IPConnect is a subclass of Wrapper itself, this means that it also has IO - ports and interfaces, and that multiple IPConnects can have their ports and interfaces connected to each other (or other objects that subclass Wrapper).

+../_images/ipconnect.png +

Instances of Wrapper objects can be added to an IPConnect using add_component() method:

+
# create a wrapper for an IP
+dma = IPWrapper('DMATop.yaml', ip_name='DMATop', instance_name='DMATop0')
+ipc = IPConnect()
+ipc.add_component("dma", dma)
+
+
+

Connections between cores can then be made with connect_ports() and connect_interfaces() based on names of the components and names of ports/interfaces:

+
ipc.connect_ports("comp1_port_name", "comp1_name", "comp2_port_name", "comp2_name")
+ipc.connect_interfaces("comp1_interface_name", "comp1_name", "comp2_interface_name", "comp2_name")
+
+
+

Setting ports or interfaces of a module added to IPConnect as external with _set_port() and _set_interface() and allows these ports/interfaces to be connected to other Wrapper instances.

+
ipc._set_port("comp1_name", "comp1_port_name", "external_port_name")
+ipc._set_interface("comp1_name", "comp1_interface_name", "external_interface_name")
+
+
+

This is done automatically in make_connections() method when the design is built based on the data from the YAML design description.

+
+
+class IPConnect(*args, src_loc_at=0, **kwargs)
+

Connector for multiple IPs, capable of connecting their interfaces +as well as individual ports.

+
+
+__init__(name: str = 'ip_connector')
+
+ +
+
+_connect_external_ports(internal: WrapperPort, external: WrapperPort)
+

Makes a pass-through connection - port of an internal module in IPConnect +is connected to an external IPConnect port.

+
+
Parameters:
+
+
internal: WrapperPort

port of an internal module of IPConnect

+
+
external: WrapperPort

external IPConnect port

+
+
+
+
+
+ +
+
+_connect_internal_ports(port1: WrapperPort, port2: WrapperPort)
+

Connects two ports with matching directionality. Disallowed configurations are: +- input to input +- output to output +- inout to inout +All other configurations are allowed.

+
+
Parameters:
+
+
port1: WrapperPort

1st port to connect

+
+
port2: WrapperPort

2nd port to connect

+
+
+
+
+
+ +
+
+_connect_to_external_port(internal_port: str, internal_comp: str, external_port: str, external: DesignExternalPorts) None
+

Connect internal port of a component to an external port

+
+
Parameters:
+
+
internal_port: str

internal port name in internal_component to connect to external_port

+
+
internal_comp: str

internal component name

+
+
external_port: str

external port name

+
+
external: DesignExternalPorts

dictionary in the form of {“in”: list, “out”: list, “inout”: list} containing +port names specified as external in each of the three categories. All keys are +optional and lack of a category implies an empty list

+
+
+
+
+
+ +
+
+_set_interface(comp_name: str, iface_name: str, external_iface_name: str) None
+

Set interface specified by name as an external interface

+
+
Parameters:
+
+
comp_name: str

name of the component - hierarchy or IP core

+
+
iface_name: str

interface name in the component

+
+
external_iface_name: str

external name of the interface specified in “external” section

+
+
+
+
Raises:
+

ValueError – if such interface doesn’t exist

+
+
+
+ +
+
+_set_port(comp_name: str, port_name: str, external_name: str) None
+

Set port specified by name as an external port

+
+
Parameters:
+
+
comp_name: str

name of the component - hierarchy or IP core

+
+
port_name: str

port name in the component

+
+
external_name: str

external name of the port specified in “external” section

+
+
+
+
Raises:
+

ValueError – if such port doesn’t exist

+
+
+
+ +
+
+add_component(name: str, component: Wrapper) None
+

Add a new component to this IPConnect, allowing to make connections with it

+
+
Parameters:
+
+
name: str

name of the component

+
+
component: Wrapper

Wrapper object

+
+
+
+
+
+ +
+
+connect_interfaces(iface1: str, comp1_name: str, iface2: str, comp2_name: str) None
+

Make connections between all matching ports of the interfaces

+
+
Parameters:
+
+
iface1: str

name of the 1st interface

+
+
comp1_name: str

name of the 1st IP

+
+
iface2: str

name of the 2nd interface

+
+
comp2_name: str

name of the 2nd IP

+
+
+
+
Raises:
+

ValueError – if any of the IPs doesn’t exist

+
+
+
+ +
+
+connect_ports(port1_name: str, comp1_name: str, port2_name: str, comp2_name: str) None
+

Connect ports of IPs previously added to this Connector

+
+
Parameters:
+
+
port1_name: str

name of the port of the 1st IP

+
+
comp1_name: str

name of the 1st IP

+
+
port2_name: str

name of the port of the 2nd IP

+
+
comp2_name: str

name of the 2nd IP

+
+
+
+
Raises:
+

ValueError – if such IP doesn’t exist

+
+
+
+ +
+
+get_ports() list
+

Return a list of external ports of this module

+
+ +
+
+make_connections(ports: DS_PortsT, interfaces: DS_InterfacesT, external: DesignExternalSection) None
+

Use names of port and names of ips to make connections

+
+
Parameters:
+
+
ports: DS_PortsT

“ports” section in the YAML design specification

+
+
interfaces: DS_InterfacesT

“interfaces” section in the YAML design specification

+
+
external: DesignExternalSection

“external” section in the YAML design specification

+
+
+
+
+
+ +
+
+make_interconnect_connections(interconnects: Dict[str, DesignSectionInterconnect], external: DesignExternalSection)
+

Connect slaves and masters to their respective interfaces in the interconnect

+
+
Parameters:
+
+
interconnects: Dict[str, DesignSectionInterconnect]

“interconnects” section in the YAML design specification

+
+
external: DesignExternalSection

“external” section in the YAML design specification

+
+
+
+
+
+ +
+
+set_constant(comp_name: str, comp_port: str, target: int) None
+

Set a constant value on a port of an IP

+
+
Parameters:
+
+
comp_name: str

name of the IP or hierarchy

+
+
comp_port: str

name of the port of the IP or hierarchy

+
+
target: int

int value to be assigned

+
+
+
+
Raises:
+

ValueError – if such IP doesn’t exist

+
+
+
+ +
+
+validate_inout_connections(inouts: Collection[Tuple[str, str]])
+

Checks that all inout ports of any IP or hierarchy in the design are explicitly +listed in the ‘external’ section.

+
+
Parameters:
+
+
inouts: Collection[Tuple[str, str]]

external.ports.inout section of the design description YAML

+
+
+
+
+
+ +
+ + + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/developers_guide/ipwrapper.html b/developers_guide/ipwrapper.html new file mode 100644 index 00000000..816cfc8c --- /dev/null +++ b/developers_guide/ipwrapper.html @@ -0,0 +1,921 @@ + + + + + + + + + + + + + + + + IPWrapper class - Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +

IPWrapper class

+

IPWrapper provides an abstraction over a raw HDL source file. +Instances of this class can be created from a loaded YAML IP-core description.

+

Under the hood it will create Amaranth’s Instance object during elaboration, referencing a particular HDL module and it will appear as a module instantiation in the generated toplevel. +Ports and interfaces (lists of ports) can be retrieved via standard methods of Wrapper. +These are instances of WrapperPorts.

+../_images/wrapper.png +
+
+class IPWrapper(*args, src_loc_at=0, **kwargs)
+

This class instantiates an IP in a wrapper to use its individual ports +or grouped ports as interfaces.

+
+
+__init__(yaml_path: Path, ip_name: str, instance_name: str, params={})
+
+
Parameters:
+
+
yaml_path: Path

path to the IP Core description yaml file

+
+
ip_name: str

name of the module to wrap

+
+
instance_name: str

name of this instance

+
+
params={}

optional, HDL parameters of this instance

+
+
+
+
+
+ +
+
+get_ports() List[WrapperPort]
+

Return a list of all ports that belong to this IP.

+
+ +
+ + + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/developers_guide/parsing.html b/developers_guide/parsing.html new file mode 100644 index 00000000..6dc915d8 --- /dev/null +++ b/developers_guide/parsing.html @@ -0,0 +1,904 @@ + + + + + + + + + + + + + + + + Deducing interfaces - Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +

Deducing interfaces

+

This section describes how inferring interfaces works when using topwrap parse with --iface-deduce, --iface or --use-yosys options.

+

The problem can be described as follows: given a set of signals, infer what interfaces are present in this set and assign signals to appropriate interfaces. +Interface names and types (AXI4, AXI Stream, Wishbone, etc.) are, in the general case, not given in advance. +Algorithm implemented in topwrap works roughly as follows:

+
    +
  1. Split the given signal set into disjoint subsets of signals based on common prefixes in their names

  2. +
  3. For a given subset, try to pair each signal name (as it appears in the RTL) with the name of an interface signal (as it is defined in the specification of a particular interface). +This pairing is called “a matching”. +Matching with signals from all defined interfaces is tried.

  4. +
  5. For a given subset and matched interface, infer the interface direction (master/slave) based on the direction of some signal in this set.

  6. +
  7. Compute score for each matching, e.g. if signal names contain cyc, stb and ack (and possibly more) it’s likely that this set is a Wishbone interface. +Among all interfaces, interface that has the highest matching score is selected.

  8. +
+

Step 1. - splitting ports into subsets

+

First, all ports of a module are grouped into disjoint subsets. Execution of this step differs based on the options supplied to topwrap parse:

+
    +
  • with --iface the user supplies topwrap with interface names - ports with names starting with a given interface name will be put in the same subset.

  • +
  • with --use-yosys grouping is done by parsing the RTL source with yosys, where ports have attributes in the form of (* interface="interface_name" *). +Ports with the same interface_name will be put in the same subset.

  • +
  • with --iface-deduce grouping is done by computing longest common prefixes among all ports. +This is done with the help of a trie and only allows prefixes that would split the port name on an underscore (e.g. in under_score valid prefixes are an empty string, under and under_score) or a camel-case word boundary (e.g. in wordBoundary valid prefixes are an empty string, word and wordBoundary). +As with user-supplied prefixes, ports with names starting with a given prefix will be put in the same subset.

  • +
+

Step 2. - matching ports with interface signal names

+

Given a subset of ports from a previous step, this step tries to match a regexp from an interface definition YAML for a given interface signal to one of the port names and returns a collection of pairs: RTL port + interface port. +For example, when matching against AXI4, a port named axi_a_arvalid should match to an interface port named ARVALID in the interface definition YAML.

+

This operation is performed for all defined interfaces per a given subset of ports so the overall result of this step is a collection of matchings. +For most interfaces these matching will be poor - e.g. axi_a_arvalid or other AXI4 signals won’t match to most Wishbone interface signals, but an interface that a human would usually assign to a given set of signals will have the most signals matched.

+

Step 3. - inferring interface direction

+

This step picks a representative RTL signal from a single signal matching from the previous step and checks its direction against direction of the corresponding interface signal in interface definition YAML - if it’s the same then it’s a master interface (since the convention in interface description files is to describe signals from the master’s perspective), otherwise it’s a slave.

+

Step 4. - computing interface matching score

+

This step computes a score for each matching returned by step 2. +This score is based on the number of matched/unmatched optional/required signals in each matching.

+

Not matching some signals in a given group (from step 1.) is heavily penalized to encourage selecting interface that “fits” a given group best. +For example, AXI Lite is a subset of AXI4, so a set of signals that should be assigned AXI4 interface could very well fit the description of AXI Lite, but this mechanism discourages selecting such matching in favor of selecting the other.

+

Not matching some signals of a given interface (from interface description YAML) is also penalized. +Inverting the previous example, a set of signals that should be assigned AXI Lite interface could very well fit the description of AXI4, but because it’s missing a few AXI4 signals so selecting this matching is discouraged in favor of selecting the other.

+

Good scoring function

+

A well-behaving scoring function should satisfy some properties to ensure that the best “fitting” interface is selected. +To describe these we introduce the following terminology:

+
    +
  • >/>=/== should be read as “must have a greater/greater or equal/equal score than”.

  • +
  • Partial matching means matching where some rtl signals haven’t been matched to interface signals, full matching means matching where all have been matched.

  • +
+

Current implementation when used with default config values satisfies these properties:

+
    +
  1. full matching with N+1 signals matched (same type) == full matching with N signals matched (same type)

  2. +
  3. full matching with N signals matched (same type) > partial matching with N signals matched (same type)

  4. +
  5. partial matching with N+1 signals matched (same type) > partial matching with N signals matched (same type)

  6. +
  7. full matching with N+1 required, M+1 optional signals >= full matching with N+1 optional, M optional signals >= full matching with N required, M+1 optional signals >= full matching with N required, M optional signals

  8. +
+

Properties 2-4 generally ensure that interfaces with more signals matched are favored more over those with less signals matched. +Property 1. follows from the current implementation and is not needed in all implementations.

+

Full details can be found in the implementation itself.

+ + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/developers_guide/setup.html b/developers_guide/setup.html new file mode 100644 index 00000000..132e85a3 --- /dev/null +++ b/developers_guide/setup.html @@ -0,0 +1,794 @@ + + + + + + + + + + + + + + + + Setup - Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +

Setup

+

It is required for developers to keep code style and recommended to frequently run tests. +In order to setup the developer’s environment install optional dependency groups topwrap-parse, tests and lint specified in pyproject.toml which include nox and pre-commit:

+
python -m venv venv
+source venv/bin/activate
+pip install -e ".[topwrap-parse,tests,lint]"
+
+
+

The -e option is for installing in editable mode - meaning changes in the code under development will be immediately visible when using the package.

+ + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/developers_guide/style.html b/developers_guide/style.html new file mode 100644 index 00000000..43164024 --- /dev/null +++ b/developers_guide/style.html @@ -0,0 +1,886 @@ + + + + + + + + + + + + + + + + Code style - Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +

Code style

+

Automatic formatting and linting of the code can be performed with either nox or pre-commit.

+

Lint with nox

+

After successful setup, nox sessions can be executed to perform lint checks:

+
nox -s lint
+
+
+

This runs isort, black, flake8 and codespell and fixes almost all formatting and linting problems automatically, but a small minority has to be fixed by hand (e.g. unused imports).

+
+

Note

+

To reuse current virtual environment and avoid long installation time use -R option:

+
nox -R -s lint
+
+
+
+
+

Note

+

pre-commit can also be run from nox:

+
nox -s pre_commit
+
+
+
+

Lint with pre-commit

+

Alternatively, you can use pre-commit to perform the same job. +Pre-commit hooks need to be installed:

+
pre-commit install
+
+
+

Now, each use of git commit in the shell will trigger actions defined in the .pre-commit-config.yaml file. +Pre-commit can be easily disabled with a similar command:

+
pre-commit uninstall
+
+
+

If you wish to run pre-commit asynchronously, then use:

+
pre-commit run --all-files
+
+
+
+

Note

+

pre-commit by default also runs nox with isort,flake8, black and codespell sessions

+
+

Tools

+

Tools used in project for maintaining code style:

+ + + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/developers_guide/tests.html b/developers_guide/tests.html new file mode 100644 index 00000000..ec368209 --- /dev/null +++ b/developers_guide/tests.html @@ -0,0 +1,877 @@ + + + + + + + + + + + + + + + + Tests - Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +

Tests

+

Topwrap functionality is validated with tests, leveraging the pytest library.

+

Test execution

+

Tests are located in the tests directory. +All tests can be run with nox by specifying the tests session:

+
nox -s tests
+
+
+

This only runs tests on python interpreter versions that are available locally. +There is also a session tests_in_env that will automatically install all required python versions, provided you have pyenv installed:

+
nox -s tests_in_env
+
+
+
+

Note

+

To reuse existing virtual environment and avoid long installation time use -R option:

+
nox -R -s tests_in_env
+
+
+
+

To force a specific Python version and avoid running tests for all listed versions, use -p VERSION option:

+
nox -p 3.10 -s tests_in_env
+
+
+

Tests can also be launched without nox by executing:

+
python -m pytest
+
+
+
+

Warning

+

When running tests by invoking pytest directly, tests are ran only on the locally selected python interpreter. +As CI runs them on all supported Python versions it’s recommended to run tests with nox on all versions before pushing.

+
+

Ignoring particular test can be done with --ignore=test_path, e.g:

+
python -m pytest --ignore=tests/tests_build/test_interconnect.py
+
+
+

Sometimes it’s useful to see what’s being printed by the test for debugging purposes. +Pytest captures all output from the test and displays it when all tests finish. +To see the output immediately, pass -s option to pytest:

+
python -m pytest -s
+
+
+

Test coverage

+

Test coverage is automatically generated when running tests with nox. +When invoking pytest directly it can be generated with --cov=topwrap option. +This will generate a summary of coverage displayed in CLI.

+
python -m pytest --cov=topwrap
+
+
+

Additionally, the summary can be generated in HTML with --cov=topwrap --cov-report html, where lines that were not covered by tests can be browsed:

+
python -m pytest --cov=topwrap --cov-report html
+
+
+

Generated report is available at htmlcov/index.html

+ + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/developers_guide/wrapper.html b/developers_guide/wrapper.html new file mode 100644 index 00000000..433e13ed --- /dev/null +++ b/developers_guide/wrapper.html @@ -0,0 +1,920 @@ + + + + + + + + + + + + + + + + Wrapper - Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +

Wrapper

+

Wrapper is an abstraction over entities that have ports - examples include IP cores written in Verilog/VHDL, cores written in Amaranth and hierarchical collections for these that expose some external ports. +Subclasses of this class have to supply implementation of property get_ports() that has to return a list of all ports of the entity.

+
+
+class Wrapper(*args, src_loc_at=0, **kwargs)
+

Base class for modules that want to connect to each other.

+

Derived classes must implement get_ports method that returns +a list of WrapperPort’s - external ports of a class that can +be used as endpoints for connections.

+
+
+__init__(name: str)
+
+ +
+
+get_port_by_name(name: str) WrapperPort
+

Given port’s name, return the port as WrapperPort object.

+
+
Raises:
+

ValueError – If such port doesn’t exist.

+
+
+
+ +
+
+get_ports() List[WrapperPort]
+

Return a list of external ports.

+
+ +
+
+get_ports_of_interface(iface_name: str) List[WrapperPort]
+

Return a list of ports of specific interface.

+
+
Raises:
+

ValueError – if such interface doesn’t exist.

+
+
+
+ +
+ + + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/developers_guide/wrapper_port.html b/developers_guide/wrapper_port.html new file mode 100644 index 00000000..b65aa85e --- /dev/null +++ b/developers_guide/wrapper_port.html @@ -0,0 +1,986 @@ + + + + + + + + + + + + + + + + Wrapper Port - Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +

Wrapper Port

+

Class WrapperPort is an extension to Amaranth’s Signal. +It wraps a port, adding a new name and optionally slicing the signal. +It adds these attributes:

+
WrapperPort.internal_name     # name of the port in internal source to be wrapped
+WrapperPort.direction         # DIR_FANIN, DIR_FANOUT or DIR_NONE
+WrapperPort.interface_name    # name of the group of ports (interface)
+WrapperPort.bounds            # range of bits that belong to the port
+                              # and range which is sliced from the port
+
+
+

See Port slicing to know more about bounds.

+

This is used in IPWrapper class implementation and there should be no need to use WrapperPort individually.

+
+

Warning

+

WrapperPort is scheduled to be replaced in favor of plain Amaranth’s Signal so it should not be used in any new functionality.

+
+
+
+class WrapperPort(shape=None, src_loc_at=0, **kwargs)
+
+
+__init__(shape=None, src_loc_at=0, *, bounds: List[int], name: str, internal_name: str, interface_name: str | None = None, direction: PortDirection)
+

Wraps a port, adding a new name and optionally slicing the signal

+
+
Parameters:
+
+
bounds: List[int]

4-element list where: +[0:1] - upper and lower bounds of reference signal, +[2:3] - upper and lower bounds of internal port, +which are either the same as reference port, +or a slice of the reference port

+
+
name: str

a new name for the signal

+
+
internal_name: str

name of the port to be wrapped/sliced

+
+
interface_name: str | None = None

name of the interface the port belongs to

+
+
direction: PortDirection

one of PortDirection, e.g. DIR_OUT

+
+
+
+
+
+ +
+
+static like(other, **kwargs)
+

Creates a WrapperPort object with identical parameters as other object

+
+
Parameters:
+
+
other

object to clone data from

+
+
**kwargs

optional constructor parameters to override

+
+
+
+
+
+ +
+ + + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/fusesoc.html b/fusesoc.html new file mode 100644 index 00000000..4f580592 --- /dev/null +++ b/fusesoc.html @@ -0,0 +1,796 @@ + + + + + + + + + + + + + + + + FuseSoC - Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +

FuseSoC

+

Topwrap uses FuseSoC to automate project generation and build process. +When topwrap build is invoked it generates a FuseSoC core file along with the top-level wrapper.

+

A template for the core file is bundled with Topwrap (templates/core.yaml.j2). +You may need to edit the file to change the backend tool, set additional Hooks and change the FPGA part name or other parameters. +By default, topwrap.fuse_helper.FuseSocBuilder searches for the template file in the directory you work in, so you should first copy the template into the project’s location.

+

After generating the core file you can run FuseSoC to generate bitstream and program FPGA:

+
fusesoc --cores-root build run project_1
+
+
+

This requires having the suitable backend tool in your PATH (Vivado, for example).

+ + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/genindex.html b/genindex.html new file mode 100644 index 00000000..55e8dcdc --- /dev/null +++ b/genindex.html @@ -0,0 +1,741 @@ + + + + + + + + + + + + + + + + None - Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +None + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ +
+ + + + +
+ +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/getting_started.html b/getting_started.html new file mode 100644 index 00000000..795c9ae3 --- /dev/null +++ b/getting_started.html @@ -0,0 +1,1037 @@ + + + + + + + + + + + + + + + + Getting started - Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +

Getting started

+

Installation

+
    +
  1. Install required system packages:

    +

    Debian:

    +
    apt install -y git g++ make python3 python3-pip antlr4 libantlr4-runtime-dev yosys npm
    +
    +
    +

    Arch:

    +
    pacman -Syu git gcc make python3 python-pip antlr4 antlr4-runtime yosys npm
    +
    +
    +

    Fedora:

    +
    dnf install git g++ make python3 python3-pip python3-devel antlr4 antlr4-cpp-runtime-devel yosys npm
    +
    +
    +
  2. +
  3. Install the Topwrap package (It is highly recommended to run this step in a Python virtual environment, e.g. venv):

    +
    pip install .
    +
    +
    +
  4. +
+
+

Note

+

To use topwrap parse command you also need to install optional dependencies:

+
pip install ".[topwrap-parse]"
+
+
+

On Arch-based distributions a symlink to antlr4 runtime library needs to created and an environment variable set:

+
ln -s /usr/share/java/antlr-complete.jar antlr4-complete.jar
+ANTLR_COMPLETE_PATH=`pwd` pip install ".[topwrap-parse]"
+
+
+

On Fedora-based distributions symlinks need to be made inside /usr/share/java directory itself:

+
sudo ln -s /usr/share/java/stringtemplate4/ST4.jar /usr/share/java/stringtemplate4.jar
+sudo ln -s /usr/share/java/antlr4/antlr4.jar /usr/share/java/antlr4.jar
+sudo ln -s /usr/share/java/antlr4/antlr4-runtime.jar /usr/share/java/antlr4-runtime.jar
+sudo ln -s /usr/share/java/treelayout/org.abego.treelayout.core.jar /usr/share/java/treelayout.jar
+pip install ".[topwrap-parse]"
+
+
+
+

Example usage

+

This section demonstrates the basic usage of Topwrap to generate IP wrappers and a top module.

+
    +
  1. Create IP core description file for every IP Core you want to use or let topwrap parse handle this for you. This file describes the ports, parameters and interfaces of an IP core.

  2. +
+

As an example, Verilog module such as:

+
module ibuf (
+    input  wire clk,
+    input  wire rst,
+    input  wire a,
+    output reg z
+);
+    // ...
+endmodule
+
+
+

Needs this corresponding description:

+
signals:
+  in:
+    - clk
+    - rst
+    - a
+  out:
+    - z
+
+
+
    +
  1. Create a design description file where you can specify all instances of IP cores and connections between them (project.yaml in this example)

  2. +
+
    +
  • Create instances of IP cores:

  • +
+
ips:
+  vexriscv_instance:
+    file: ipcores/gen_VexRiscv.yaml
+    module: VexRiscv
+  wb_ram_data_instance:
+    file: ipcores/gen_mem.yaml
+    module: mem
+  wb_ram_instr_instance:
+    file: ipcores/gen_mem.yaml
+    module: mem
+
+
+

file and module are mandatory fields providing the IP description file and the name of the HDL module as it appears in the source.

+
    +
  • (Optional) Set parameters for IP core instances:

  • +
+
parameters:
+  wb_ram_data_instance:
+    depth: 0x1000
+    memfile: "top_sram.init"
+  wb_ram_instr_instance:
+    depth: 0xA000
+    memfile: "bios.init"
+
+
+
    +
  • Connect desired ports of the IP cores:

  • +
+
ports:
+  wb_ram_data_instance:
+    clk: [some_other_ip, clk_out]
+    rst: [reset_core, reset0]
+  wb_ram_instr_instance:
+    clk: [some_other_ip, clk_out]
+    rst: [reset_core, reset0]
+  vexriscv_instance:
+    softwareInterrupt: [some_other_ip, sw_interrupt]
+    ...
+
+
+

Connections only need to be written once, i.e. if A connects to B, then only a connection A: B has to be specified (B: A is redundant).

+
    +
  • Connect desired interfaces of the IP cores:

  • +
+
interfaces:
+  vexriscv_instance:
+    iBusWishbone: [wb_ram_instr_instance, mem_bus]
+    dBusWishbone: [wb_ram_data_instance, mem_bus]
+
+
+
    +
  • Specify external ports or interfaces of the top module and connect them with chosen IP cores’ ports or interfaces:

  • +
+
ports:
+  vexriscv_instance:
+    timerInterrupt: ext_timer_interrupt
+
+...
+
+external:
+  ports:
+    out:
+      - ext_timer_interrupt
+  interfaces:
+    ...
+
+
+
    +
  1. Create a Core file template for FuseSoC, or use a default one bundled with Topwrap.

  2. +
+

You may want to modify the file to add dependencies, source files, or change the target board. +The file should be named core.yaml.j2. You can find an example template in examples/hdmi directory of the project. +If you don’t create any template a default template bundled with Topwrap will be used (stored in templates directory).

+
    +
  1. Place any additional source files in a directory (sources in this example).

  2. +
  3. Run Topwrap:

    +
    python -m topwrap build --design project.yaml --sources sources
    +
    +
    +
  4. +
+

Example PWM design

+

There’s an example setup in examples/pwm.

+

In order to generate the top module, run:

+
make generate
+
+
+

In order to generate bitstream, add Vivado to your path and run:

+
make
+
+
+

The FPGA design utilizes an AXI-mapped PWM IP Core. +You can access its registers starting from address 0x4000000 (that’s the base address of AXI_GP0 on ZYNQ). +Each IP Core used in the project is declared in ips section in project.yml file. +ports section allows to connect individual ports of IP Cores, and interfaces is used analogously for connecting whole interfaces. +Finally, you can specify which ports will be used as external I/O in external section.

+

To connect the I/O signals to specific FPGA pins, you need proper mappings in a constraints file. See zynq.xdc used in the setup and modify it accordingly.

+_images/pwm.png +

Example HDMI design

+

There’s an example setup stored in examples/hdmi.

+

You can generate bitstream for desired target:

+
+
    +
  • Snickerdoodle Black:

    +
    make snickerdoodle
    +
    +
    +
  • +
  • Zynq Video Board:

    +
    make zvb
    +
    +
    +
  • +
+
+

If you wish to generate HDL sources without running Vivado, you can use:

+
make generate
+
+
+

You can find more information in README of the example setup.

+ + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/hierarchies.html b/hierarchies.html new file mode 100644 index 00000000..12c848de --- /dev/null +++ b/hierarchies.html @@ -0,0 +1,854 @@ + + + + + + + + + + + + + + + + Hierarchies - Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +

Hierarchies

+

Hierarchies allow for creating designs with subgraphs in them. +Subgraphs can contain multiple IP-cores and other subgraphs. +This allows creating nested designs in topwrap.

+

Format

+

All information about hierarchies is specified in design description. +hierarchies key must be a direct descendant of the design key. +Format is as follows:

+
hierarchies:
+    {hierarchy_name_1}:
+      ips: # ips that are used on this hierarchy level
+        {ip_name}:
+          ...
+
+      design:
+        parameters:
+          ...
+        ports: # ports connections internal to this hierarchy
+          # note that also you have to connect port to it's external port equivalent (if exists)
+          {ip1_name}:
+              {port1_name} : [{ip2_name}, {port2_name}]
+              {port2_name} : {port2_external_equivalent} # connection to external port equivalent. Note that it has to be to the parent port
+            ...
+        hierarchies:
+          {nested_hierarchy_name}:
+            # structure here will be the same as for {hierarchy_name_1}
+            ...
+      external:
+        # external ports and/or interfaces of this hierarchy; these can be
+        # referenced in the upper-level `ports`, `interfaces` or `external` section
+        ports:
+            in:
+              - {port2_external_equivalent}
+        ...
+    {hierarchy_name_2}:
+      ...
+
+
+

More complex hierarchy example can be found in examples/hierarchy.

+ + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..434dc18b --- /dev/null +++ b/index.html @@ -0,0 +1,871 @@ + + + + + + + + + + + + + + + + Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +

Welcome to Topwrap!

+ + + + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/interconnect_gen.html b/interconnect_gen.html new file mode 100644 index 00000000..30695bb6 --- /dev/null +++ b/interconnect_gen.html @@ -0,0 +1,904 @@ + + + + + + + + + + + + + + + + Interconnect generation - Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +

Interconnect generation

+

Generating interconnects is an experimental feature of topwrap. +With a specification of which interfaces are masters or slaves and their address ranges, topwrap is able to automatically generate an interconnect conforming to this description. Currently supported interconnect types are:

+
    +
  • Wishbone round-robin

  • +
+

Format

+

The format for describing interconnects is specified below. interconnects key must be a direct descendant of the design key in the design description.

+
interconnects:
+  {interconnect1_name}:
+    # specify clock and reset to drive the interconnect with
+    clock: [{ip_name, clk_port_name}]
+    reset: [{ip_name, rst_port_name}]
+    # alternatively you can specify a connection to an external interface:
+    # clock: ext_clk_port_name
+    # reset: ext_rst_port_name
+
+    # specify interconnect type
+    type: {interconnect_type}
+
+    # specify interconnect parameters - interconnect-type-dependent (see "Interconnect params" section):
+    params:
+      {param_name1}: param_value1
+      ...
+
+    # specify masters and their interfaces connected to the bus
+    masters:
+    {master1_name}:
+      - {master1_iface1_name}
+      ...
+    ...
+
+    # specify slaves, their interfaces connected to the bus and their bus parameters
+    slaves:
+    {slave1_name}:
+      {slave1_interface1_name}:
+      # requests in address range [address, address+size) will be routed to this interface
+      address: {start_address}
+      size: {range_size}
+      ...
+    ...
+
+
+

Interconnect params

+

Different interconnect types may provide different configuration options. +This section lists parameter names for available interconnects for use in the params section of interconnect specification.

+

Wishbone round-robin

+

Corresponds to type: wishbone_roundrobin

+
    +
  • addr_width - bit width of the address line (addresses access data_width-sized chunks)

  • +
  • data_width - bit width of the data line

  • +
  • granularity - access granularity - smallest unit of data transfer that the interconnect is capable of transferring. Must be one of: 8, 16, 32, 64

  • +
  • features - optional, list of optional wishbone signals, can contain: err, rty, stall, lock, cti, bte

  • +
+

Limitations

+

Known limitations currently are:

+
    +
  • only word-sized addressing is supported (in other words - consecutive addresses access word-sized chunks of data)

  • +
  • crossing clock domains is not supported

  • +
  • down-converting (initiating multiple transactions on a narrow bus per one transaction on a wider bus) is not supported

  • +
  • up-converting is not supported

  • +
+ + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/introduction.html b/introduction.html new file mode 100644 index 00000000..cb30a592 --- /dev/null +++ b/introduction.html @@ -0,0 +1,797 @@ + + + + + + + + + + + + + + + + Introduction - Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +

Introduction

+

ASIC and FPGA designs consist of distinct blocks of logic bound together by a top-level design. +To take advantage of this modularity and enable reuse of blocks across designs and so facilitate the shift towards automation in logic design, it is necessary to derive a generic way to aggregate the blocks in various configurations and make the top-level design easy to parse and process automatically.

+

Topwrap is an open source command line toolkit for connecting individual HDL modules into full designs of varying complexity. +The toolkit is designed to take advantage of the ever-growing availability of open source digital logic designs and offers a user-friendly graphical interface which lets you mix-and-match GUI-driven design with CLI-based adjustments and present designs in a diagram form thanks to the integration with Antmicro’s Pipeline Manager.

+

Topwrap’s most notable features are:

+
    +
  • Parsing HDL design files with automatic recognition of common interfaces

  • +
  • Simple YAML-based description for command-line use

  • +
  • Capability to create a custom libraries for reuse across projects

  • +
  • User-friendly GUI powered by Kenning Pipeline Manager.

  • +
+ + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 00000000..aff13eba Binary files /dev/null and b/objects.inv differ diff --git a/pipeline_manager.html b/pipeline_manager.html new file mode 100644 index 00000000..1391247d --- /dev/null +++ b/pipeline_manager.html @@ -0,0 +1,934 @@ + + + + + + + + + + + + + + + + Kenning Pipeline Manager - Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +

Kenning Pipeline Manager

+

Topwrap can make use of Kenning Pipeline Manager to visualize the process of creating block design.

+

Run Topwrap with Pipeline Manager

+
    +
  1. Build and run Pipeline Manager server

    +

    In order to start creating block design in Pipeline Manager, you need to first build and run a server application - here is a brief instruction on how to achieve this (the process of building and installation of Pipeline Manager is described in detail in its documentation):

    +
    python -m topwrap kpm_build_server
    +python -m topwrap kpm_run_server
    +
    +
    +

    After executing the above-mentioned commands, the Pipeline Manager server is waiting for an external application (i.e. Topwrap) to connect on 127.0.0.1:9000 and you can connect to the web GUI frontend in your browser on http://127.0.0.1:5000.

    +
  2. +
  3. Establish connection with Topwrap

    +

    Once the Pipeline Manager server is running, you can now launch Topwrap’s client application in order to connect to the server. You need to specify:

    +
      +
    • IP address (127.0.0.1 is default)

    • +
    • listening port (9000 is default)

    • +
    • yamls describing IP cores, that will be used in the block design

    • +
    • design to load initially (None by default)

    • +
    +

    An example command, that runs Topwrap’s client, may look like this:

    +
    python -m topwrap kpm_client -h 127.0.0.1 -p 9000 \
    +    topwrap/ips/axi/axi_axil_adapter.yaml \
    +    examples/pwm/ipcores/{litex_pwm.yml,ps7.yaml} -d examples/pwm/project.yml
    +
    +
    +
  4. +
  5. Create block design in Pipeline Manager

    +

    Upon successful connection to a Pipeline Manager server, Topwrap will generate and send to the server a specification describing the structure of previously selected IP cores. After that, you are free to create a custom block design by means of:

    +
      +
    • adding IP core instances to the block design. Each Pipeline Manager’s node has delete and rename options, which make it possible to remove the selected node and change its name respectively. This means that you can create multiple instances of the same IP core.

    • +
    • adjusting IP cores’ parameters values. Each node may have input boxes in which you can enter parameters’ values (default parameter values are added while adding an IP core to the block design):

    • +
    +_images/node_parameters.png +
      +
    • connecting IP cores’ ports and interfaces. Only connections between ports or interfaces of matching types are allowed. This is automatically checked by Pipeline Manager, as the types of nodes’ ports and interfaces are contained in the loaded specification, so Pipeline Manager will prevent you from connecting non-matching interfaces (e.g. AXI4 with AXI4Lite or a port with an interface). A green line will be displayed if a connection is possible to create, or a red line elsewhere:

    • +
    +_images/invalid_connection.png +
      +
    • specifying external ports or interfaces in the top module. This can be done by adding External Input, External Output or External Inout metanodes and creating connections between them and chosen ports or interfaces. Note that you should adjust the name of the external port or interface in a textbox inside selected metanode. In the example below, output port pwm of litex_pwm_top IP core will be made external in the generated top module and the external port name will be set to ext_pwm:

    • +
    +_images/external_port.png +

    Note, that you don’t always have to create a new block design by hand - you can use a design import feature to load an existing block design from a description in Topwrap’s yaml format.

    +

    An example block design in Pipeline Manager for the PWM project may look like this:

    +_images/pwm_design.png +
  6. +
+

Pipeline Manager features

+

While creating a custom block design, you can make use of the following Pipeline Manager’s features:

+
    +
  • export (save) design to a file

  • +
  • import (load) design from a file

  • +
  • validate design

  • +
  • build design

  • +
+

Export design to yaml description file

+

Created block design can be saved to a design description file in yaml format, using Pipeline Manager’s Save file option. +Target location on the filesystem can then be browsed in a filesystem dialog window.

+

Import design from yaml description file

+

Topwrap also supports conversion in the opposite way - block design in Pipeline Manager can be generated from a yaml design description file using Load file feature.

+

Design validation

+

Pipeline Manager is capable of performing some basic checks at runtime such as interface type checking while creating a connection. However you can also run more complex tests by using Pipeline Manager’s Validate option. Topwrap will then respond with a validity confirmation or error messages. The rules you need to follow in order to keep your block design valid are:

+
    +
  • multiple IP cores with the same name are not allowed (except from external metanodes).

  • +
  • parameters values can be integers of different bases (e.g. 0x28, 40 or 0b101000) or arithmetic expressions, that are later evaluated using numexpr.evaluate() function (e.g. (AXI_DATA_WIDTH+1)/4 is a valid parameter value assuming that a parameter named AXI_DATA_WIDTH exists in the same IP core). You can also write a parameter value in a Verilog format (e.g. 8'b00011111 or 8'h1F) - in such case it will be interpreted as a fixed-width bit vector.

  • +
  • a single port or interface cannot be external and connected to another IP core at the same time.

  • +
  • connections between two external metanodes are not allowed.

  • +
  • all the created external output or inout ports must have unique names. Only multiple input ports of IP cores can be driven be the same external signal.

  • +
+

Topwrap can also generate warnings if:

+
    +
  • some ports or interfaces remain unconnected.

  • +
  • multiple ports are connected to an External Input metanode with an empty External Name property.

  • +
  • inout ports of two modules are connected together (all inout ports are required to be directly connected to External Inout metanodes)

  • +
+

If a block design validation returns a warning, it means that the block design can be successfully built, but it is recommended to follow the suggestion and resolve a particular issue.

+

Building design

+

Once the design has been created and tested for validity, you can build design using Run button. If the design does not contain any errors, this will result in creating a top module in a directory where topwrap kpm_client was ran, similarly when using Topwrap’s topwrap build command.

+ + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 00000000..d0bea7e6 --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"alltitles": {"Ability to produce top-level wrappers in VHDL": [[6, "ability-to-produce-top-level-wrappers-in-vhdl"]], "Building design": [[0, "building-design"], [22, "building-design"]], "Bus management": [[6, "bus-management"]], "Code style": [[12, "code-style"]], "Command-line Interface": [[0, "command-line-interface"]], "Config": [[2, "config"]], "Connect Topwrap to Pipeline Manager": [[0, "connect-topwrap-to-pipeline-manager"]], "Deducing interfaces": [[10, "deducing-interfaces"]], "Description files": [[1, "description-files"]], "Design Description": [[1, "design-description"]], "Design validation": [[22, "design-validation"]], "Developer's Guide": [[19, null]], "Documentation": [[19, null]], "ElaboratableWrapper class": [[3, "elaboratablewrapper-class"]], "Example HDMI design": [[17, "example-hdmi-design"]], "Example PWM design": [[17, "example-pwm-design"]], "Example usage": [[17, "example-usage"]], "Examples": [[4, "examples"]], "Export design to yaml description file": [[22, "export-design-to-yaml-description-file"]], "Format": [[18, "format"], [20, "format"]], "FuseSoC": [[16, "fusesoc"]], "FuseSocBuilder": [[5, "fusesocbuilder"]], "Future enhancements": [[6, "future-enhancements"]], "Generating IP core description YAMLs": [[0, "generating-ip-core-description-yamls"]], "Getting started": [[17, "getting-started"]], "Good scoring function": [[10, "good-scoring-function"]], "Hierarchies": [[18, "hierarchies"]], "IP description files": [[1, "ip-description-files"]], "IPConnect class": [[8, "ipconnect-class"]], "IPWrapper class": [[9, "ipwrapper-class"]], "Import design from yaml description file": [[22, "import-design-from-yaml-description-file"]], "Improve the process of recreating a design from a YAML file": [[6, "improve-the-process-of-recreating-a-design-from-a-yaml-file"]], "Installation": [[17, "installation"]], "Integrating with other tools": [[6, "integrating-with-other-tools"]], "Interconnect generation": [[20, "interconnect-generation"]], "Interconnect params": [[20, "interconnect-params"]], "Interface Description files": [[1, "interface-description-files"]], "Interface definition": [[7, "interface-definition"]], "Introduction": [[21, "introduction"]], "Kenning Pipeline Manager": [[22, "kenning-pipeline-manager"]], "Library of open-source cores": [[6, "library-of-open-source-cores"]], "Limitations": [[20, "limitations"]], "Lint with nox": [[12, "lint-with-nox"]], "Lint with pre-commit": [[12, "lint-with-pre-commit"]], "Parameterization": [[1, "parameterization"]], "Pipeline Manager features": [[22, "pipeline-manager-features"]], "Port slicing": [[1, "port-slicing"]], "Port widths": [[1, "port-widths"]], "Provide a way to parse HDL sources from the Pipeline Manager level": [[6, "provide-a-way-to-parse-hdl-sources-from-the-pipeline-manager-level"]], "Run Topwrap with Pipeline Manager": [[22, "run-topwrap-with-pipeline-manager"]], "Setup": [[11, "setup"]], "Step 1. - splitting ports into subsets": [[10, "step-1-splitting-ports-into-subsets"]], "Step 2. - matching ports with interface signal names": [[10, "step-2-matching-ports-with-interface-signal-names"]], "Step 3. - inferring interface direction": [[10, "step-3-inferring-interface-direction"]], "Step 4. - computing interface matching score": [[10, "step-4-computing-interface-matching-score"]], "Support for hierarchical block design in Pipeline Manager": [[6, "support-for-hierarchical-block-design-in-pipeline-manager"]], "Support for parsing SystemVerilog sources": [[6, "support-for-parsing-systemverilog-sources"]], "Test coverage": [[13, "test-coverage"]], "Test execution": [[13, "test-execution"]], "Tests": [[13, "tests"]], "Tools": [[12, "tools"]], "User repositories": [[23, "user-repositories"]], "Welcome to Topwrap!": [[19, "welcome-to-topwrap"]], "Wishbone round-robin": [[20, "wishbone-round-robin"]], "Wrapper": [[14, "wrapper"]], "Wrapper Port": [[15, "wrapper-port"]]}, "docurls": ["cli.html", "description_files.html", "developers_guide/config.html", "developers_guide/elaboratable_wrapper.html", "developers_guide/examples.html", "developers_guide/fusesocbuilder.html", "developers_guide/future_enhancements.html", "developers_guide/interface.html", "developers_guide/ipconnect.html", "developers_guide/ipwrapper.html", "developers_guide/parsing.html", "developers_guide/setup.html", "developers_guide/style.html", "developers_guide/tests.html", "developers_guide/wrapper.html", "developers_guide/wrapper_port.html", "fusesoc.html", "getting_started.html", "hierarchies.html", "index.html", "interconnect_gen.html", "introduction.html", "pipeline_manager.html", "user_repositories.html"], "envversion": {"sphinx": 61, "sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.todo": 2}, "indexentries": {"__init__() (config method)": [[2, "topwrap.config.Config.__init__", false]], "__init__() (configmanager method)": [[2, "topwrap.config.ConfigManager.__init__", false]], "__init__() (elaboratablewrapper method)": [[3, "topwrap.elaboratable_wrapper.ElaboratableWrapper.__init__", false]], "__init__() (fusesocbuilder method)": [[5, "topwrap.fuse_helper.FuseSocBuilder.__init__", false]], "__init__() (interfacedefinition method)": [[7, "topwrap.interface.InterfaceDefinition.__init__", false]], "__init__() (ipconnect method)": [[8, "topwrap.ipconnect.IPConnect.__init__", false]], "__init__() (ipwrapper method)": [[9, "topwrap.ipwrapper.IPWrapper.__init__", false]], "__init__() (wrapper method)": [[14, "topwrap.wrapper.Wrapper.__init__", false]], "__init__() (wrapperport method)": [[15, "topwrap.amaranth_helpers.WrapperPort.__init__", false]], "_connect_external_ports() (ipconnect method)": [[8, "topwrap.ipconnect.IPConnect._connect_external_ports", false]], "_connect_internal_ports() (ipconnect method)": [[8, "topwrap.ipconnect.IPConnect._connect_internal_ports", false]], "_connect_to_external_port() (ipconnect method)": [[8, "topwrap.ipconnect.IPConnect._connect_to_external_port", false]], "_set_interface() (ipconnect method)": [[8, "topwrap.ipconnect.IPConnect._set_interface", false]], "_set_port() (ipconnect method)": [[8, "topwrap.ipconnect.IPConnect._set_port", false]], "add_component() (ipconnect method)": [[8, "topwrap.ipconnect.IPConnect.add_component", false]], "add_dependency() (fusesocbuilder method)": [[5, "topwrap.fuse_helper.FuseSocBuilder.add_dependency", false]], "add_external_ip() (fusesocbuilder method)": [[5, "topwrap.fuse_helper.FuseSocBuilder.add_external_ip", false]], "add_source() (fusesocbuilder method)": [[5, "topwrap.fuse_helper.FuseSocBuilder.add_source", false]], "add_sources_dir() (fusesocbuilder method)": [[5, "topwrap.fuse_helper.FuseSocBuilder.add_sources_dir", false]], "build() (fusesocbuilder method)": [[5, "topwrap.fuse_helper.FuseSocBuilder.build", false]], "config (class in topwrap.config)": [[2, "topwrap.config.Config", false]], "configmanager (class in topwrap.config)": [[2, "topwrap.config.ConfigManager", false]], "connect_interfaces() (ipconnect method)": [[8, "topwrap.ipconnect.IPConnect.connect_interfaces", false]], "connect_ports() (ipconnect method)": [[8, "topwrap.ipconnect.IPConnect.connect_ports", false]], "elaboratablewrapper (class in topwrap.elaboratable_wrapper)": [[3, "topwrap.elaboratable_wrapper.ElaboratableWrapper", false]], "fusesocbuilder (class in topwrap.fuse_helper)": [[5, "topwrap.fuse_helper.FuseSocBuilder", false]], "get_interface_by_name() (in module topwrap.interface)": [[7, "topwrap.interface.get_interface_by_name", false]], "get_port_by_name() (wrapper method)": [[14, "topwrap.wrapper.Wrapper.get_port_by_name", false]], "get_ports() (elaboratablewrapper method)": [[3, "topwrap.elaboratable_wrapper.ElaboratableWrapper.get_ports", false]], "get_ports() (ipconnect method)": [[8, "topwrap.ipconnect.IPConnect.get_ports", false]], "get_ports() (ipwrapper method)": [[9, "topwrap.ipwrapper.IPWrapper.get_ports", false]], "get_ports() (wrapper method)": [[14, "topwrap.wrapper.Wrapper.get_ports", false]], "get_ports_hier() (elaboratablewrapper method)": [[3, "topwrap.elaboratable_wrapper.ElaboratableWrapper.get_ports_hier", false]], "get_ports_of_interface() (wrapper method)": [[14, "topwrap.wrapper.Wrapper.get_ports_of_interface", false]], "interfacedefinition (class in topwrap.interface)": [[7, "topwrap.interface.InterfaceDefinition", false]], "ipconnect (class in topwrap.ipconnect)": [[8, "topwrap.ipconnect.IPConnect", false]], "ipwrapper (class in topwrap.ipwrapper)": [[9, "topwrap.ipwrapper.IPWrapper", false]], "like() (wrapperport static method)": [[15, "topwrap.amaranth_helpers.WrapperPort.like", false]], "make_connections() (ipconnect method)": [[8, "topwrap.ipconnect.IPConnect.make_connections", false]], "make_interconnect_connections() (ipconnect method)": [[8, "topwrap.ipconnect.IPConnect.make_interconnect_connections", false]], "schema (config attribute)": [[2, "topwrap.config.Config.Schema", false]], "schema (interfacedefinition attribute)": [[7, "topwrap.interface.InterfaceDefinition.Schema", false]], "set_constant() (ipconnect method)": [[8, "topwrap.ipconnect.IPConnect.set_constant", false]], "validate_inout_connections() (ipconnect method)": [[8, "topwrap.ipconnect.IPConnect.validate_inout_connections", false]], "wrapper (class in topwrap.wrapper)": [[14, "topwrap.wrapper.Wrapper", false]], "wrapperport (class in topwrap.amaranth_helpers)": [[15, "topwrap.amaranth_helpers.WrapperPort", false]]}, "objects": {"topwrap.amaranth_helpers": [[15, 0, 1, 0, "WrapperPort", "Wraps a port, adding a new name and optionally slicing the signal"]], "topwrap.amaranth_helpers.WrapperPort": [[15, 1, 1, 0, "__init__", "Wraps a port, adding a new name and optionally slicing the signal"], [15, 1, 1, 0, "like", "Creates a WrapperPort object with identical parameters as other object"]], "topwrap.amaranth_helpers.WrapperPort.__init__": [[15, 2, 2, 0, "bounds", "4-element list where: [0:1] - upper and lower bounds of reference signal, [2:3] - upper and lower bounds of internal port, which are either the same as reference port, or a slice of the reference port"], [15, 2, 2, 0, "direction", "one of PortDirection, e.g. DIR_OUT"], [15, 2, 2, 0, "interface_name", "name of the interface the port belongs to"], [15, 2, 2, 0, "internal_name", "name of the port to be wrapped/sliced"], [15, 2, 2, 0, "name", "a new name for the signal"]], "topwrap.amaranth_helpers.WrapperPort.like": [[15, 2, 2, 0, "kwargs", "optional constructor parameters to override"], [15, 2, 2, 0, "other", "object to clone data from"]], "topwrap.config": [[2, 0, 1, 0, "Config", "Global topwrap configuration"], [2, 0, 1, 0, "ConfigManager", "Manager used to load topwrap's configuration from files."]], "topwrap.config.Config": [[2, 3, 1, 0, "Schema", "alias of Config"], [2, 1, 1, 0, "__init__", ""]], "topwrap.config.ConfigManager": [[2, 1, 1, 0, "__init__", ""]], "topwrap.elaboratable_wrapper": [[3, 0, 1, 0, "ElaboratableWrapper", "Allows connecting an Amaranth's Elaboratable with other classes derived from Wrapper."]], "topwrap.elaboratable_wrapper.ElaboratableWrapper": [[3, 1, 1, 0, "__init__", "name of this wrapper"], [3, 1, 1, 0, "get_ports", "Return a list of external ports."], [3, 1, 1, 0, "get_ports_hier", "Maps elaboratable's Signature to a nested dictionary of WrapperPorts. See _gather_signature_ports for more details."]], "topwrap.elaboratable_wrapper.ElaboratableWrapper.__init__": [[3, 2, 2, 0, "elaboratable", "Amaranth's Elaboratable object to wrap"], [3, 2, 2, 0, "name", "name of this wrapper"]], "topwrap.fuse_helper": [[5, 0, 1, 0, "FuseSocBuilder", "Use this class to generate a FuseSoC .core file"]], "topwrap.fuse_helper.FuseSocBuilder": [[5, 1, 1, 0, "__init__", ""], [5, 1, 1, 0, "add_dependency", "Adds a dependency to the list of dependencies in the core file"], [5, 1, 1, 0, "add_external_ip", "Store information about IP Cores from Vivado library to generate hooks that will add the IPs in a TCL script."], [5, 1, 1, 0, "add_source", "Adds an HDL source to the list of sources in the core file"], [5, 1, 1, 0, "add_sources_dir", "Given a name of a directory, add all files found inside it. Recognize VHDL, Verilog, and XDC files."], [5, 1, 1, 0, "build", "Generate the final create .core file"]], "topwrap.fuse_helper.FuseSocBuilder.build": [[5, 2, 2, 0, "sources_dir", "additional directory with source files to add"], [5, 2, 2, 0, "template_name", "name of jinja2 template to be used, either in working directory, or bundled with the package. defaults to a bundled template"]], "topwrap.interface": [[7, 0, 1, 0, "InterfaceDefinition", "Interface described in YAML interface definition file"], [7, 4, 1, 0, "get_interface_by_name", "Retrieve interface definition by its name"]], "topwrap.interface.InterfaceDefinition": [[7, 3, 1, 0, "Schema", "alias of InterfaceDefinition"], [7, 1, 1, 0, "__init__", ""]], "topwrap.ipconnect": [[8, 0, 1, 0, "IPConnect", "Connector for multiple IPs, capable of connecting their interfaces as well as individual ports."]], "topwrap.ipconnect.IPConnect": [[8, 1, 1, 0, "__init__", ""], [8, 1, 1, 0, "_connect_external_ports", "Makes a pass-through connection - port of an internal module in IPConnect is connected to an external IPConnect port."], [8, 1, 1, 0, "_connect_internal_ports", "Connects two ports with matching directionality. Disallowed configurations are: - input to input - output to output - inout to inout All other configurations are allowed."], [8, 1, 1, 0, "_connect_to_external_port", "Connect internal port of a component to an external port"], [8, 1, 1, 0, "_set_interface", "Set interface specified by name as an external interface"], [8, 1, 1, 0, "_set_port", "Set port specified by name as an external port"], [8, 1, 1, 0, "add_component", "Add a new component to this IPConnect, allowing to make connections with it"], [8, 1, 1, 0, "connect_interfaces", "Make connections between all matching ports of the interfaces"], [8, 1, 1, 0, "connect_ports", "Connect ports of IPs previously added to this Connector"], [8, 1, 1, 0, "get_ports", "Return a list of external ports of this module"], [8, 1, 1, 0, "make_connections", "Use names of port and names of ips to make connections"], [8, 1, 1, 0, "make_interconnect_connections", "Connect slaves and masters to their respective interfaces in the interconnect"], [8, 1, 1, 0, "set_constant", "Set a constant value on a port of an IP"], [8, 1, 1, 0, "validate_inout_connections", "Checks that all inout ports of any IP or hierarchy in the design are explicitly listed in the 'external' section."]], "topwrap.ipconnect.IPConnect._connect_external_ports": [[8, 2, 2, 0, "external", "external IPConnect port"], [8, 2, 2, 0, "internal", "port of an internal module of IPConnect"]], "topwrap.ipconnect.IPConnect._connect_internal_ports": [[8, 2, 2, 0, "port1", "1st port to connect"], [8, 2, 2, 0, "port2", "2nd port to connect"]], "topwrap.ipconnect.IPConnect._connect_to_external_port": [[8, 2, 2, 0, "external", "dictionary in the form of {\"in\": list, \"out\": list, \"inout\": list} containing port names specified as external in each of the three categories. All keys are optional and lack of a category implies an empty list"], [8, 2, 2, 0, "external_port", "external port name"], [8, 2, 2, 0, "internal_comp", "internal component name"], [8, 2, 2, 0, "internal_port", "internal port name in internal_component to connect to external_port"]], "topwrap.ipconnect.IPConnect._set_interface": [[8, 2, 2, 0, "comp_name", "name of the component - hierarchy or IP core"], [8, 2, 2, 0, "external_iface_name", "external name of the interface specified in \"external\" section"], [8, 2, 2, 0, "iface_name", "interface name in the component"]], "topwrap.ipconnect.IPConnect._set_port": [[8, 2, 2, 0, "comp_name", "name of the component - hierarchy or IP core"], [8, 2, 2, 0, "external_name", "external name of the port specified in \"external\" section"], [8, 2, 2, 0, "port_name", "port name in the component"]], "topwrap.ipconnect.IPConnect.add_component": [[8, 2, 2, 0, "component", "Wrapper object"], [8, 2, 2, 0, "name", "name of the component"]], "topwrap.ipconnect.IPConnect.connect_interfaces": [[8, 2, 2, 0, "comp1_name", "name of the 1st IP"], [8, 2, 2, 0, "comp2_name", "name of the 2nd IP"], [8, 2, 2, 0, "iface1", "name of the 1st interface"], [8, 2, 2, 0, "iface2", "name of the 2nd interface"]], "topwrap.ipconnect.IPConnect.connect_ports": [[8, 2, 2, 0, "comp1_name", "name of the 1st IP"], [8, 2, 2, 0, "comp2_name", "name of the 2nd IP"], [8, 2, 2, 0, "port1_name", "name of the port of the 1st IP"], [8, 2, 2, 0, "port2_name", "name of the port of the 2nd IP"]], "topwrap.ipconnect.IPConnect.make_connections": [[8, 2, 2, 0, "external", "\"external\" section in the YAML design specification"], [8, 2, 2, 0, "interfaces", "\"interfaces\" section in the YAML design specification"], [8, 2, 2, 0, "ports", "\"ports\" section in the YAML design specification"]], "topwrap.ipconnect.IPConnect.make_interconnect_connections": [[8, 2, 2, 0, "external", "\"external\" section in the YAML design specification"], [8, 2, 2, 0, "interconnects", "\"interconnects\" section in the YAML design specification"]], "topwrap.ipconnect.IPConnect.set_constant": [[8, 2, 2, 0, "comp_name", "name of the IP or hierarchy"], [8, 2, 2, 0, "comp_port", "name of the port of the IP or hierarchy"], [8, 2, 2, 0, "target", "int value to be assigned"]], "topwrap.ipconnect.IPConnect.validate_inout_connections": [[8, 2, 2, 0, "inouts", "external.ports.inout section of the design description YAML"]], "topwrap.ipwrapper": [[9, 0, 1, 0, "IPWrapper", "This class instantiates an IP in a wrapper to use its individual ports or grouped ports as interfaces."]], "topwrap.ipwrapper.IPWrapper": [[9, 1, 1, 0, "__init__", "path to the IP Core description yaml file"], [9, 1, 1, 0, "get_ports", "Return a list of all ports that belong to this IP."]], "topwrap.ipwrapper.IPWrapper.__init__": [[9, 2, 2, 0, "instance_name", "name of this instance"], [9, 2, 2, 0, "ip_name", "name of the module to wrap"], [9, 2, 2, 0, "params", "optional, HDL parameters of this instance"], [9, 2, 2, 0, "yaml_path", "path to the IP Core description yaml file"]], "topwrap.wrapper": [[14, 0, 1, 0, "Wrapper", "Base class for modules that want to connect to each other."]], "topwrap.wrapper.Wrapper": [[14, 1, 1, 0, "__init__", ""], [14, 1, 1, 0, "get_port_by_name", "Given port's name, return the port as WrapperPort object."], [14, 1, 1, 0, "get_ports", "Return a list of external ports."], [14, 1, 1, 0, "get_ports_of_interface", "Return a list of ports of specific interface."]]}, "objnames": {"0": ["py", "class", "Python class"], "1": ["py", "method", "Python method"], "2": ["py", "parameter", "Python parameter"], "3": ["py", "attribute", "Python attribute"], "4": ["py", "function", "Python function"]}, "objtypes": {"0": "py:class", "1": "py:method", "2": "py:parameter", "3": "py:attribute", "4": "py:function"}, "terms": {"": [0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 21, 22, 23], "0": [0, 1, 3, 8, 9, 14, 15, 22], "0b101000": 22, "0x1000": 17, "0x28": 22, "0x4000000": 17, "0xa000": 17, "1": [0, 1, 15, 19, 22], "10": 13, "101": 4, "102": 4, "103": 4, "104": 4, "105": 4, "12": 1, "127": [0, 22], "16": 20, "1st": 8, "2": [15, 19], "23": 1, "2nd": 8, "3": [0, 1, 13, 15, 19], "31": 1, "32": [1, 20], "35": 1, "36": 1, "4": [15, 19, 22], "40": 22, "5000": 22, "63": 1, "64": [1, 20], "7": 1, "8": [1, 20, 22], "9000": [0, 22], "A": [1, 2, 6, 10, 16, 17, 22], "As": [6, 10, 13, 17], "By": 16, "For": [1, 10], "If": [0, 1, 12, 14, 17, 22], "In": [0, 1, 11, 17, 22], "It": [1, 6, 11, 15, 17, 23], "Not": 10, "On": 17, "One": 6, "Such": 5, "The": [1, 2, 10, 11, 17, 20, 21, 22], "Their": 1, "Then": 6, "There": [13, 17, 23], "These": [1, 6, 7, 9], "To": [0, 1, 10, 12, 13, 17, 21], "With": 20, "__init__": [2, 3, 5, 7, 8, 9, 14, 15], "_connect_external_port": 8, "_connect_internal_port": 8, "_connect_to_external_port": 8, "_gather_signature_port": 3, "_set_interfac": 8, "_set_port": 8, "abego": 17, "abil": 19, "abl": [6, 20], "about": [5, 6, 15, 18], "abov": [1, 22], "abstract": [9, 14], "access": [2, 17, 20], "accordingli": 17, "account": 1, "achiev": [6, 22], "ack": 10, "across": 21, "action": 12, "activ": 11, "ad": [1, 5, 6, 8, 15, 22], "add": [1, 4, 5, 6, 8, 15, 17, 23], "add_compon": 8, "add_depend": 5, "add_external_ip": 5, "add_sourc": 5, "add_sources_dir": 5, "addit": [0, 5, 16, 17], "addition": 13, "addr_width": 20, "address": [0, 6, 17, 20, 22], "adjust": [1, 21, 22], "advanc": 10, "advantag": 21, "after": [12, 16, 22], "against": 10, "aggreg": 21, "aim": 6, "algorithm": 10, "alia": [2, 7], "all": [1, 5, 6, 8, 9, 10, 12, 13, 14, 17, 18, 22], "allow": [1, 3, 6, 8, 10, 17, 18, 22, 23], "almost": 12, "along": 16, "alphabet": 12, "also": [0, 1, 2, 4, 6, 8, 10, 12, 13, 17, 18, 22], "altern": [12, 20], "alwai": 22, "amaranth": [3, 6, 9, 14, 15], "among": 10, "an": [1, 3, 5, 8, 9, 10, 14, 15, 17, 20, 21, 22], "analog": 17, "analysi": 12, "ani": [1, 8, 15, 17, 22], "anoth": [1, 6, 22], "antlr": 17, "antlr4": 17, "antlr_complete_path": 17, "antmicro": 21, "anywher": 1, "api": 23, "app": 0, "appear": [7, 9, 10, 17], "applic": [0, 6, 22], "appropri": 10, "apt": 17, "ar": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 13, 15, 17, 18, 20, 21, 22, 23], "arbit": 6, "arch": 17, "arg": [3, 8, 9, 14], "arithmet": 22, "arvalid": 10, "asic": 21, "assign": [8, 10], "assum": [1, 22], "asynchron": 12, "attribut": [10, 15], "autom": [6, 16, 21], "automat": [0, 6, 8, 12, 13, 20, 21, 22], "avail": [6, 13, 20, 21], "avoid": [12, 13], "axi": [0, 1, 6, 10, 17, 22], "axi3": 1, "axi4": [1, 10, 22], "axi4lit": 22, "axi4stream": 1, "axi_a_arvalid": 10, "axi_axil_adapt": 22, "axi_data_width": 22, "axi_gp0": 17, "axis_width_convert": 1, "axistream": 1, "b": [1, 17], "b00011111": 22, "backend": 16, "base": [4, 5, 8, 10, 14, 17, 21, 22], "basic": [4, 17, 22], "becaus": 10, "been": [10, 22], "befor": 13, "behav": 10, "being": 13, "belong": [0, 1, 9, 15], "below": [1, 20, 22], "benefit": 1, "best": 10, "between": [1, 8, 17, 22], "bid": 1, "bin": 11, "bio": 17, "bit": [1, 15, 20, 22], "bitstream": [16, 17], "black": [12, 17], "block": [0, 19, 21, 22], "board": 17, "bool": 2, "both": 1, "bound": [15, 21], "boundari": 10, "box": 22, "brief": 22, "brows": [13, 22], "browser": 22, "bte": 20, "bu": [19, 20], "build": [5, 6, 16, 17, 19], "built": [8, 22], "bundl": [5, 16, 17], "buse": 6, "button": [6, 22], "call": 10, "camel": 10, "can": [0, 1, 2, 5, 6, 8, 9, 10, 12, 13, 14, 16, 17, 18, 20, 22, 23], "cannot": [1, 6, 22], "capabl": [8, 12, 20, 21, 22], "captur": 13, "case": [1, 4, 6, 10, 22], "catalog": 23, "categori": 8, "chang": [2, 11, 16, 17, 22], "charact": 1, "check": [1, 8, 10, 12, 22], "chip": 0, "chosen": [0, 17, 22], "chunk": 20, "ci": 13, "class": [2, 5, 7, 14, 15, 19], "cli": [13, 21], "client": [0, 6, 22], "clk": [1, 17], "clk_out": 17, "clk_port_nam": 20, "clka": 1, "clkb": 1, "clock": [1, 20], "clock_cross": 1, "clone": 15, "co": 6, "code": [11, 19, 23], "codebas": 2, "codespel": 12, "collect": [8, 10, 14], "come": [1, 6], "command": [1, 6, 12, 17, 19, 21, 22], "commit": [11, 19], "common": [0, 1, 10, 12, 21], "comp1_interface_nam": 8, "comp1_nam": 8, "comp1_port_nam": 8, "comp2_interface_nam": 8, "comp2_nam": 8, "comp2_port_nam": 8, "comp_nam": 8, "comp_port": 8, "compat": 3, "complet": [1, 17], "complex": [4, 6, 12, 18, 21, 22], "complic": 6, "compon": 8, "comput": 19, "concret": 1, "config": [10, 12, 19, 23], "configmanag": [2, 19], "configur": [2, 8, 20, 21, 23], "confirm": 22, "conform": [3, 20], "connect": [1, 3, 6, 8, 14, 17, 18, 19, 20, 21, 22], "connect_interfac": 8, "connect_port": 8, "connector": 8, "consecut": 20, "consist": 21, "constant": 8, "constraint": 17, "construct": 23, "constructor": [2, 15], "contain": [1, 3, 5, 8, 10, 18, 20, 22], "content": 23, "conveni": 6, "convent": [0, 1, 10], "convers": [6, 22], "convert": 20, "copi": 16, "core": [1, 4, 5, 8, 9, 14, 16, 17, 18, 19, 22, 23], "core_filenam": 5, "correct": [1, 7], "correspond": [0, 10, 17, 20], "could": [6, 10], "cov": 13, "cover": [4, 13], "coverag": 19, "cpp": 17, "creat": [0, 1, 2, 4, 5, 6, 8, 9, 15, 17, 18, 21, 22], "cross": [1, 20], "crossbar": 6, "cti": 20, "cumbersom": 6, "current": [1, 6, 10, 12, 20], "custom": [6, 21, 22], "cyc": 10, "d": [0, 6, 22], "data": [8, 15, 20], "data_width": [1, 20], "dataclass": 7, "dbuswishbon": 17, "debian": 17, "debug": 13, "declar": 17, "deduc": [0, 19], "default": [0, 1, 2, 5, 10, 12, 16, 17, 22], "default_search_path": 2, "defin": [2, 7, 10, 12], "definit": [10, 19], "delet": 22, "demonstr": [4, 17], "depend": [5, 11, 17, 20], "depth": 17, "deriv": [3, 14, 21], "descend": [18, 20], "describ": [1, 7, 10, 17, 20, 22], "descript": [6, 8, 9, 10, 17, 18, 19, 20, 21], "design": [4, 8, 18, 19, 20, 21, 23], "design_nam": 1, "designexternalport": 8, "designexternalsect": 8, "designsectioninterconnect": 8, "desir": 17, "dest_width": 1, "detail": [1, 3, 10, 22], "determin": 2, "dev": 17, "devel": 17, "develop": [4, 11], "devic": 6, "diagram": 21, "dialog": 22, "dict": 8, "dictionari": [3, 8], "differ": [1, 2, 10, 20, 22], "digit": 21, "dir_fanin": 15, "dir_fanout": 15, "dir_non": 15, "dir_out": 15, "direct": [1, 15, 18, 19, 20], "direction": [1, 3, 8], "directli": [6, 13, 22], "directori": [0, 1, 5, 13, 16, 17, 22], "disabl": 12, "disallow": 8, "discourag": 10, "disjoint": 10, "displai": [13, 22], "distinct": [1, 21], "distribut": 17, "divid": 0, "dma": 8, "dmatop": [5, 8], "dmatop0": 8, "dnf": 17, "doc": 3, "document": 22, "doe": [5, 22], "doesn": [6, 8, 14], "domain": 20, "don": [1, 17, 22], "done": [8, 10, 13, 22], "down": 20, "drive": 20, "driven": [21, 22], "ds_interfacest": 8, "ds_portst": 8, "duplic": 1, "dure": [6, 9], "e": [0, 1, 4, 5, 6, 10, 11, 12, 13, 15, 17, 22], "each": [1, 8, 10, 12, 14, 17, 22, 23], "earlier": 2, "easi": [21, 23], "easili": [6, 12], "edit": [11, 16], "editor": 6, "either": [1, 5, 12, 15], "elabor": 9, "elaborat": 3, "elaboratablewrapp": 19, "element": 15, "elsewher": 22, "empti": [8, 10, 22], "enabl": [1, 6, 7, 21], "encapsul": 3, "encourag": [4, 10], "endmodul": 17, "endpoint": 14, "enhanc": 19, "enough": [1, 4], "ensur": 10, "enter": 22, "entiti": 14, "environ": [11, 12, 13, 17], "equal": 10, "equival": 18, "err": 20, "error": 22, "establish": 22, "etc": [1, 4, 10], "evalu": [1, 22], "ever": 21, "everi": [1, 17], "exampl": [1, 5, 10, 14, 16, 18, 19, 22, 23], "except": 22, "execut": [10, 12, 19, 22], "exist": [8, 13, 14, 18, 22], "experiment": [6, 20], "explain": 4, "explicitli": 8, "export": 6, "expos": [3, 14], "express": [1, 22], "ext_clk_port_nam": 20, "ext_iface_nam": 1, "ext_port_nam": 1, "ext_pwm": 22, "ext_rst_port_nam": 20, "ext_timer_interrupt": 17, "extens": 15, "extern": [1, 3, 8, 14, 17, 18, 20, 22], "external_iface_nam": 8, "external_interface_nam": 8, "external_nam": 8, "external_port": 8, "external_port_nam": 8, "facilit": 21, "factori": 2, "fals": 2, "favor": [10, 15], "featur": [4, 6, 19, 20, 21], "fedora": 17, "few": 10, "field": 17, "file": [0, 2, 5, 7, 9, 10, 12, 16, 17, 19, 21, 23], "file1": 23, "filenam": 5, "filesystem": 22, "final": [5, 17], "find": 17, "finish": 13, "first": [10, 16, 22], "fit": 10, "fix": [12, 22], "flake8": 12, "flip": 1, "follow": [0, 1, 2, 10, 18, 22, 23], "forc": 13, "force_interface_compli": [2, 23], "form": [8, 10, 21], "format": [1, 7, 12, 19, 22], "formatt": 12, "found": [5, 10, 18, 23], "fpga": [0, 16, 17, 21], "framework": 12, "free": 22, "frequent": 11, "friendli": 21, "from": [0, 1, 2, 3, 4, 5, 8, 9, 10, 12, 13, 15, 17, 19], "frontend": 22, "full": [6, 10, 21], "fulli": [1, 4], "function": [7, 13, 15, 22], "fuse": 5, "fuse_help": [5, 16], "fusesoc": [5, 6, 17, 19], "fusesocbuild": [16, 19], "futur": 19, "g": [0, 4, 6, 10, 12, 13, 15, 17, 22], "gcc": 17, "gen_mem": 17, "gen_vexriscv": 17, "gener": [1, 5, 6, 9, 10, 13, 16, 17, 19, 21, 22], "get": [0, 4, 19], "get_interface_by_nam": [7, 19], "get_port": [3, 8, 9, 14], "get_port_by_nam": 14, "get_ports_hi": 3, "get_ports_of_interfac": 14, "git": [12, 17], "given": [5, 7, 10, 14], "global": [1, 2], "goal": 6, "gpio_io_i": 1, "granular": 20, "graphic": 21, "greater": 10, "green": 22, "group": [1, 9, 10, 11, 15], "grow": 21, "gui": [6, 21, 22], "h": [0, 22], "h1f": 22, "ha": [1, 5, 6, 7, 8, 10, 12, 14, 17, 18, 22, 23], "hand": [1, 12, 22], "handl": [1, 4, 17], "hardcod": 1, "hardwar": 6, "have": [0, 1, 2, 6, 8, 10, 13, 14, 16, 18, 22], "haven": 10, "hdl": [0, 1, 5, 7, 9, 17, 19, 21], "hdl_file": 0, "heavili": 10, "help": [0, 10], "here": [1, 5, 18, 22, 23], "hier_nam": 1, "hierarch": [1, 14, 19], "hierarchi": [1, 6, 8, 19], "hierarchy_nam": 1, "hierarchy_name_1": 18, "hierarchy_name_2": 18, "higher": 2, "highest": 10, "highli": 17, "hood": 9, "hook": [5, 12, 16], "how": [4, 5, 10, 22], "howev": [1, 6, 22], "html": 13, "htmlcov": 13, "http": 22, "huge": 6, "human": 10, "i": [0, 1, 2, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23], "ibuf": 17, "ibuswishbon": 17, "id_width": 1, "ideal": 6, "ident": [1, 15], "identifi": 1, "ifac": [0, 10], "iface1": 8, "iface1_nam": 1, "iface2": 8, "iface2_nam": 1, "iface_nam": [1, 8, 14], "ignor": 13, "immedi": [11, 13], "implement": [0, 4, 10, 14, 15], "impli": 8, "import": [5, 6, 12], "improv": 19, "includ": [1, 6, 11, 14], "incom": 1, "increas": 4, "index": 13, "individu": [8, 9, 15, 17, 21], "infer": [3, 19], "inform": [5, 6, 17, 18], "init": 17, "initi": [20, 22], "inout": [1, 8, 22], "input": [1, 8, 17, 22], "insid": [1, 5, 17, 22, 23], "instal": [11, 12, 13, 19, 22], "instanc": [8, 9, 17, 22], "instance_nam": [8, 9], "instanti": 9, "instruct": 22, "int": [8, 15], "integ": [1, 22], "integr": [19, 21], "interconnect": [1, 8, 19], "interconnect1_nam": 20, "interconnect_typ": 20, "interfac": [3, 4, 8, 9, 14, 15, 17, 18, 19, 20, 21, 22, 23], "interface1": 23, "interface2": 23, "interface_nam": [10, 15], "interfacedefinit": [7, 19], "interfacedefinitionsign": 7, "intern": [8, 15, 18, 23], "internal_comp": 8, "internal_compon": 8, "internal_nam": 15, "internal_port": 8, "interpret": [13, 22], "introduc": [4, 10], "introduct": 19, "invalid": 1, "invert": 10, "invok": [6, 13, 16], "io": 8, "ip": [5, 6, 8, 9, 14, 17, 18, 19, 22, 23], "ip1_nam": [1, 18], "ip2_nam": [1, 18], "ip_addr": 0, "ip_connector": 8, "ip_instance_nam": 1, "ip_nam": [1, 8, 9, 18, 20], "ipc": 8, "ipconnect": 19, "ipcor": [17, 22], "ipwrapp": [8, 15, 19], "isort": 12, "issu": [6, 22], "its": [1, 4, 6, 7, 9, 10, 17, 22], "itself": [8, 10, 17], "j2": [5, 16, 17], "jar": 17, "java": 17, "jinja": 5, "jinja2": 5, "job": 12, "keep": [11, 22], "keep_width": 1, "kei": [1, 8, 18, 20], "ken": [19, 21], "know": 15, "known": 20, "kpm": 0, "kpm_build_serv": [0, 22], "kpm_client": [0, 22], "kpm_run_serv": [0, 22], "kwarg": [3, 8, 9, 14, 15], "lack": 8, "languag": 12, "later": [0, 22], "launch": [6, 13, 22], "less": 10, "let": [17, 21], "level": [1, 16, 18, 19, 21], "leverag": 13, "libantlr4": 17, "librari": [5, 13, 17, 19, 21], "like": [1, 6, 10, 15, 22], "limit": 19, "line": [6, 13, 19, 20, 21, 22], "link": 6, "lint": [11, 19], "list": [2, 3, 5, 8, 9, 13, 14, 15, 20], "listen": 22, "lite": [1, 10], "litex_pwm": 22, "litex_pwm_top": 22, "ln": 17, "load": [0, 2, 7, 9, 22, 23], "local": [2, 13], "locat": [13, 16, 22, 23], "lock": 20, "logic": 21, "long": [12, 13], "longest": 10, "look": 22, "lower": 15, "lowercas": 1, "m": [0, 10, 11, 13, 17, 22], "m_axi": 1, "m_axi_1": 1, "m_axi_bid": 1, "m_axis_tdata": 1, "m_axis_tdest": 1, "m_axis_tid": 1, "m_axis_tkeep": 1, "m_axis_tlast": 1, "m_axis_treadi": 1, "m_axis_tus": 1, "m_axis_tvalid": 1, "made": [8, 17, 22], "mai": [16, 17, 20, 22], "main": [6, 23], "maintain": 12, "make": [1, 3, 5, 8, 17, 21, 22], "make_connect": 8, "make_interconnect_connect": 8, "makefil": 6, "manag": [2, 12, 19, 21], "mandatori": [1, 17], "manual": 6, "map": [3, 17], "marshmallow_dataclass": 7, "master": [1, 6, 8, 10, 20], "master1_iface1_nam": 20, "master1_nam": 20, "match": [1, 7, 8, 19, 21, 22], "math": 1, "matur": 4, "mean": [1, 8, 10, 11, 22], "mechan": [6, 10], "mem": 17, "mem_bu": 17, "memfil": 17, "mention": 22, "messag": 22, "metanod": 22, "method": [8, 9, 14], "minim": 4, "minor": 12, "miss": 10, "mistak": 12, "mix": 21, "mode": [1, 11], "modifi": 17, "modul": [0, 1, 8, 9, 10, 14, 17, 21, 22], "modular": 21, "more": [3, 10, 15, 17, 18, 22], "most": [2, 6, 10, 21], "multi": 12, "multipl": [8, 18, 20, 22], "must": [1, 3, 10, 14, 18, 20, 22], "n": [1, 10], "name": [0, 1, 3, 5, 7, 8, 9, 14, 15, 16, 17, 19, 20, 22, 23], "name_of_the_hdl_modul": 1, "narrow": 20, "natur": 1, "necessari": 21, "necessarili": 1, "need": [0, 1, 6, 10, 12, 15, 16, 17, 22], "nest": [1, 3, 18], "nested_hierarchy_nam": 18, "new": [4, 8, 15, 22], "node": [1, 6, 22], "non": 22, "none": [2, 5, 7, 8, 15, 22], "notabl": 21, "notat": 1, "note": [1, 18, 22], "now": [6, 12, 22], "nox": [11, 13, 19], "npm": 17, "number": [1, 4, 10], "numexpr": [1, 22], "o": [1, 17], "object": [2, 3, 6, 7, 8, 9, 14, 15], "obtain": 6, "occur": 1, "offer": 21, "often": 0, "onc": [1, 17, 22], "one": [1, 6, 10, 15, 17, 20, 23], "ones": 6, "onli": [6, 10, 13, 17, 20, 22], "open": [19, 21], "oper": 10, "opposit": 22, "optim": 6, "option": [0, 1, 8, 9, 10, 11, 12, 13, 15, 17, 20, 22, 23], "order": [1, 2, 11, 17, 22], "org": 17, "organ": 6, "other": [1, 3, 8, 10, 14, 15, 16, 18, 19, 20], "other_port_nam": 1, "otherwis": 10, "our": 6, "out": [1, 8, 17], "output": [8, 13, 17, 22], "over": [9, 10, 14], "overal": 10, "overrid": 15, "overridden": [1, 5], "overwrit": 2, "own": 23, "p": [0, 13, 22], "packag": [1, 5, 6, 11, 17, 23], "pacman": 17, "page": 1, "pair": [1, 10], "param": [9, 19], "param_nam": 1, "param_name1": 20, "param_valu": 1, "param_value1": 20, "paramet": [1, 3, 4, 5, 6, 8, 9, 15, 16, 17, 18, 20, 22], "parent": [1, 18], "pars": [0, 1, 7, 10, 11, 17, 19, 21], "part": [0, 5, 16], "partial": 10, "particular": [9, 10, 13, 22], "pass": [2, 8, 13], "path": [2, 9, 16, 17, 23], "path_to_repo": 23, "path_to_repositori": 23, "path_to_yaml_file_of_the_ip": 1, "pathlik": 2, "penal": 10, "per": [10, 20], "perform": [1, 7, 10, 12, 22], "peripher": 6, "perspect": [1, 10], "physic": 1, "pick": [1, 10], "pin": 17, "pip": [11, 17], "pipelin": [19, 21], "place": [1, 6, 17], "plain": 15, "poor": 10, "popular": 6, "port": [0, 3, 8, 9, 14, 17, 18, 19, 22], "port1": 8, "port1_nam": [1, 8, 18], "port2": 8, "port2_external_equival": 18, "port2_nam": [1, 8, 18], "port_nam": [1, 8], "port_prefix": [1, 7], "portdirect": 15, "posit": 6, "possibl": [6, 22], "possibli": 10, "power": 21, "practic": 4, "pre": [6, 11, 19], "pre_commit": 12, "preced": 2, "predefin": 1, "prefix": [0, 1, 10], "premad": 6, "present": [1, 5, 10, 21], "preserv": 6, "prevent": 22, "previou": [1, 10], "previous": [8, 22], "print": 13, "prioriti": 2, "problem": [10, 12], "process": [16, 19, 21, 22], "processor": 6, "produc": 19, "program": 16, "project": [0, 1, 2, 4, 5, 12, 16, 17, 21, 22], "project_1": 16, "proper": [1, 6, 17], "properti": [3, 10, 14, 22], "prove": 4, "provid": [0, 4, 8, 9, 13, 17, 19, 20, 23], "ps7": 22, "purpos": 13, "push": 13, "put": [6, 10], "pwd": 17, "pwm": 22, "py": 13, "pyenv": 13, "pyproject": 11, "pytest": 13, "python": [0, 7, 11, 12, 13, 17, 22, 23], "python3": 17, "quickli": 6, "r": [12, 13], "rais": [8, 14], "ran": [13, 22, 23], "rang": [15, 20], "range_s": 20, "raw": 9, "re": 1, "read": [2, 10], "readm": 17, "real": 4, "recogn": 5, "recognit": 21, "recommend": [11, 13, 17, 22], "recreat": 19, "recurs": 1, "red": 22, "redund": 17, "refer": 15, "referenc": [9, 18], "reg": 17, "regex": 1, "regexp": [1, 10], "regist": 17, "relat": [1, 6], "reli": 6, "remain": 22, "remov": [1, 22], "renam": 22, "renod": 6, "replac": 15, "repo": 23, "report": 13, "repositori": [2, 6, 12, 19], "repositoryentri": 2, "repres": 10, "request": 20, "requir": [1, 6, 10, 11, 13, 16, 17, 22], "reset": [1, 20], "reset0": 17, "reset_cor": 17, "resolv": 22, "resourc": 5, "respect": [8, 22], "respond": 22, "restor": 6, "result": [6, 10, 22], "retriev": [7, 9], "return": [3, 7, 8, 9, 10, 14, 22], "reus": [6, 12, 13, 21], "robin": 6, "root": 16, "roughli": 10, "round": 6, "rout": 20, "rst": [1, 17], "rst_port_nam": 20, "rtl": [1, 10], "rty": 20, "rule": 22, "run": [0, 11, 12, 13, 16, 17, 19], "runtim": [17, 22], "s_axi": [0, 1], "s_axis_tdata": 1, "s_axis_tdest": 1, "s_axis_tid": 1, "s_axis_tkeep": 1, "s_axis_tlast": 1, "s_axis_treadi": 1, "s_axis_tus": 1, "s_axis_tvalid": 1, "same": [0, 1, 4, 10, 12, 15, 18, 22], "satisfi": 10, "save": 22, "scan": 0, "schedul": 15, "schema": [2, 7], "score": 19, "script": [5, 6], "search": [2, 16], "search_path": 2, "second": 1, "section": [1, 4, 8, 10, 17, 18, 20], "see": [1, 3, 13, 15, 17, 20], "select": [1, 10, 13, 22], "semi": 6, "send": [0, 22], "server": [0, 22], "session": [12, 13], "set": [1, 2, 7, 8, 10, 16, 17, 22], "set_const": 8, "setup": [12, 17, 19], "shape": 15, "share": 17, "shell": 12, "shift": 21, "shorten": 1, "should": [0, 1, 4, 6, 10, 15, 16, 17, 22], "signal": [1, 3, 7, 15, 17, 19, 20, 22], "signalmap": 3, "signatur": 3, "similar": 12, "similarli": 22, "simpl": [4, 5, 21], "simplifi": 12, "simul": 6, "sinc": [1, 6, 8, 10], "singl": [10, 22], "size": 20, "slave": [1, 6, 8, 10, 20], "slave1_interface1_nam": 20, "slave1_nam": 20, "slice": [4, 15], "small": 12, "smallest": 20, "snickerdoodl": 17, "so": [1, 6, 10, 15, 16, 21, 22], "soc": 6, "softwareinterrupt": 17, "some": [1, 6, 10, 14, 22], "some_other_ip": 17, "somecore1": 23, "sometim": 13, "sort": [4, 12], "sourc": [0, 1, 5, 7, 9, 10, 11, 15, 17, 19, 21], "sources_dir": 5, "specif": [0, 1, 2, 8, 10, 13, 14, 17, 20, 22], "specifi": [0, 1, 2, 3, 5, 6, 8, 11, 13, 17, 18, 20, 22, 23], "spell": 12, "spirit": 4, "split": 19, "src": [0, 23], "src_loc_at": [3, 8, 9, 14, 15], "st4": 17, "stall": 20, "standard": 9, "start": [0, 4, 10, 19, 22], "start_address": 20, "static": 15, "stb": 10, "step": [17, 19], "store": [2, 5, 6, 17, 23], "str": [3, 5, 7, 8, 9, 14, 15], "stream": [1, 10], "string": 10, "stringtemplate4": 17, "structur": [1, 7, 18, 22, 23], "style": [11, 19], "subclass": [8, 14], "subgraph": [6, 18], "subsequ": 1, "subset": 19, "success": [12, 22], "successfulli": 22, "sudo": 17, "suffic": 1, "suffix": 1, "suggest": 22, "suitabl": 16, "summari": 13, "suppli": [3, 6, 10, 14], "support": [1, 5, 13, 19, 20, 22], "suppos": 1, "sw_interrupt": 17, "symlink": 17, "synthesi": [5, 6], "synthesiz": [1, 4], "system": 17, "systemverilog": 19, "syu": 17, "t": [1, 5, 6, 8, 10, 14, 17, 22], "take": [2, 21], "taken": 1, "target": [8, 17, 22], "tcl": 5, "tdata": 1, "tdest": 1, "teach": 4, "templat": [5, 16, 17], "template_nam": 5, "term": 6, "termin": 6, "terminologi": 10, "test": [6, 11, 12, 19, 22], "test_interconnect": 13, "test_path": 13, "tests_build": 13, "tests_in_env": 13, "text": 12, "textbox": 22, "than": [1, 10], "thank": 21, "thei": [1, 4, 5, 6], "them": [3, 6, 13, 17, 18, 22, 23], "themselv": 6, "therefor": 6, "thi": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22], "those": [1, 10], "three": 8, "through": [6, 8], "throughout": 2, "tid": 1, "tile": 6, "time": [12, 13, 22, 23], "timerinterrupt": 17, "tkeep": 1, "tlast": 1, "togeth": [6, 21, 22], "toml": 11, "too": 6, "tool": [1, 4, 5, 16, 19], "toolkit": 21, "top": [0, 1, 5, 16, 17, 19, 21, 22], "top_sram": 17, "toplevel": [1, 9], "topwrap": [1, 2, 5, 6, 7, 10, 11, 13, 16, 17, 18, 20, 21, 23], "toward": 21, "transact": 20, "transfer": 20, "transform": 1, "transmitt": 1, "treadi": 1, "treelayout": 17, "tri": 10, "trie": 10, "trigger": 12, "true": 23, "try": [0, 10], "tstrb": 1, "tupl": 8, "tuser": 1, "tvalid": 1, "twakeup": 1, "two": [1, 8, 22, 23], "type": [1, 2, 5, 7, 10, 20, 22], "typecheck": 7, "ui": 0, "unconnect": 22, "under": [9, 10, 11], "under_scor": 10, "underscor": 10, "uninstal": 12, "uniqu": [1, 22], "unit": 20, "unmatch": 10, "unus": 12, "up": 20, "upon": 22, "upper": [15, 18], "us": [0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22], "usag": [4, 19], "user": [0, 4, 6, 10, 19, 21], "user_repositori": 23, "user_width": 1, "usr": 17, "usual": [1, 10], "util": [12, 17], "v": [5, 23], "valid": [7, 10, 13], "validate_inout_connect": 8, "valu": [1, 2, 7, 8, 10, 22], "valueerror": [8, 14], "vari": 21, "variabl": [2, 17], "variou": 21, "vector": 22, "venv": [11, 17], "veri": [4, 10], "veril": 6, "verilog": [5, 6, 14, 17, 22, 23], "verilogsourc": 5, "version": 13, "vexriscv": 17, "vexriscv_inst": 17, "vhdl": [5, 14, 19, 23], "via": [6, 9], "video": 17, "virtual": [12, 13, 17], "visibl": 11, "visit": 12, "visual": 22, "vivado": [5, 6, 16, 17], "vlnv": 5, "wa": 22, "wai": [1, 19, 21, 22], "wait": 22, "want": [0, 14, 17], "warn": 22, "wb_ram_data_inst": 17, "wb_ram_instr_inst": 17, "we": [1, 6, 10], "web": 22, "websit": 12, "welcom": 4, "well": [1, 8, 10], "were": 13, "what": [10, 13], "when": [0, 1, 6, 8, 10, 11, 13, 16, 22], "where": [0, 1, 5, 10, 13, 15, 17, 22, 23], "which": [0, 1, 2, 3, 11, 12, 15, 17, 20, 21, 22, 23], "while": 22, "whole": [1, 17], "wide": 1, "wider": 20, "width": [3, 20, 22], "window": 22, "wire": 17, "wish": [12, 17], "wishbon": [0, 1, 6, 10], "wishbone_roundrobin": 20, "without": [13, 17], "won": [5, 10], "word": [10, 20], "wordboundari": 10, "work": [5, 10, 16], "world": 4, "worri": 6, "would": [6, 10], "wrap": [1, 3, 9, 15], "wrapper": [3, 8, 9, 16, 17, 19], "wrapperport": [3, 8, 9, 14, 15, 19], "write": [1, 6, 22], "written": [1, 14, 17], "xc7z020clg400": 0, "xdc": [5, 17], "y": 17, "yaml": [1, 5, 7, 8, 9, 10, 12, 16, 17, 19, 21, 23], "yaml_path": 9, "yml": [0, 17, 22], "yosi": [10, 17], "you": [0, 1, 12, 13, 16, 17, 18, 20, 21, 22, 23], "your": [0, 1, 16, 17, 22], "z": 17, "zvb": 17, "zynq": 17}, "titles": ["Command-line Interface", "Description files", "Config", "ElaboratableWrapper class", "Examples", "FuseSocBuilder", "Future enhancements", "Interface definition", "IPConnect class", "IPWrapper class", "Deducing interfaces", "Setup", "Code style", "Tests", "Wrapper", "Wrapper Port", "FuseSoC", "Getting started", "Hierarchies", "Welcome to Topwrap!", "Interconnect generation", "Introduction", "Kenning Pipeline Manager", "User repositories"], "titleterms": {"": 19, "1": 10, "2": 10, "3": 10, "4": 10, "abil": 6, "block": 6, "bu": 6, "build": [0, 22], "class": [3, 8, 9], "code": 12, "command": 0, "commit": 12, "comput": 10, "config": 2, "connect": 0, "core": [0, 6], "coverag": 13, "deduc": 10, "definit": 7, "descript": [0, 1, 22], "design": [0, 1, 6, 17, 22], "develop": 19, "direct": 10, "document": 19, "elaboratablewrapp": 3, "enhanc": 6, "exampl": [4, 17], "execut": 13, "export": 22, "featur": 22, "file": [1, 6, 22], "format": [18, 20], "from": [6, 22], "function": 10, "fusesoc": 16, "fusesocbuild": 5, "futur": 6, "gener": [0, 20], "get": 17, "good": 10, "guid": 19, "hdl": 6, "hdmi": 17, "hierarch": 6, "hierarchi": 18, "import": 22, "improv": 6, "infer": 10, "instal": 17, "integr": 6, "interconnect": 20, "interfac": [0, 1, 7, 10], "introduct": 21, "ip": [0, 1], "ipconnect": 8, "ipwrapp": 9, "ken": 22, "level": 6, "librari": 6, "limit": 20, "line": 0, "lint": 12, "manag": [0, 6, 22], "match": 10, "name": 10, "nox": 12, "open": 6, "other": 6, "param": 20, "parameter": 1, "pars": 6, "pipelin": [0, 6, 22], "port": [1, 10, 15], "pre": 12, "process": 6, "produc": 6, "provid": 6, "pwm": 17, "recreat": 6, "repositori": 23, "robin": 20, "round": 20, "run": 22, "score": 10, "setup": 11, "signal": 10, "slice": 1, "sourc": 6, "split": 10, "start": 17, "step": 10, "style": 12, "subset": 10, "support": 6, "systemverilog": 6, "test": 13, "tool": [6, 12], "top": 6, "topwrap": [0, 19, 22], "usag": 17, "user": 23, "valid": 22, "vhdl": 6, "wai": 6, "welcom": 19, "width": 1, "wishbon": 20, "wrapper": [6, 14, 15], "yaml": [0, 6, 22]}}) \ No newline at end of file diff --git a/topwrap.pdf b/topwrap.pdf new file mode 100644 index 00000000..2a2528a3 Binary files /dev/null and b/topwrap.pdf differ diff --git a/user_repositories.html b/user_repositories.html new file mode 100644 index 00000000..0803cb83 --- /dev/null +++ b/user_repositories.html @@ -0,0 +1,823 @@ + + + + + + + + + + + + + + + + User repositories - Topwrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + + + +

User repositories

+

Repositories allow for easy loading packages with IP-cores.

+

You can add repositories to be loaded each time topwrap is ran by specifying them in configuration file.

+

It has to be located in one of the following locations:

+
topwrap.yaml
+~/.config/topwrap/topwrap.yaml
+~/.config/topwrap/config.yaml
+
+
+

Example contents of user config:

+
force_interface_compliance: true
+repositories:
+  - name: name of repo
+    path: ~/path_to_repo/repo
+
+
+

Topwrap provides internal API for constructing repositories in python code which can be found here

+

Structure of repository has to be as follows:

+
path_to_repository/
+|───cores
+|   |───someCore1
+|   |   |───srcs
+|   |   |   |   file1.v
+|   |   |   design.yaml
+|   |
+|   |───someCore1
+|       |───srcs
+|       |   |   file1.v
+|       |   design.yaml
+|
+|───interfaces(Optional)
+|   interface1.yaml
+|   interface2.yaml
+
+
+

Repository has two main catalogs: cores and interfaces. Inside cores each core has it’s own catalog with it’s design file and srcs where are stored verilog/VHDL files.

+

There is optional interfaces catalog where can be stored interfaces for cores.

+

Example User Repo can be found in examples/user_repository.

+ + +
+
+ + + Last update: + 2024-08-30 + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file