diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 00000000..17017ddc --- /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: f2296f28fd7fc2c9803172c92da3cf4b +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/Doc-License.html b/Doc-License.html new file mode 100644 index 00000000..0e8d6bfa --- /dev/null +++ b/Doc-License.html @@ -0,0 +1,648 @@ + + + + + + + + + Creative Commons Attribution 4.0 International - GHDL-cosim latest documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+ +
+ +
+ +
+
+ +
+

Attention

+

This CC BY 4.0 license applies only to the documentation of this project.

+
+
+

Creative Commons Attribution 4.0 International

+

Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. +Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. +Creative Commons makes its licenses and related information available on an “as-is” basis. +Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or +any related information. +Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible.

+
+

Using Creative Commons Public Licenses

+

Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders +may use to share original works of authorship and other material subject to copyright and certain other rights specified +in the public license below. +The following considerations are for informational purposes only, are not exhaustive, and do not form part of our +licenses.

+
    +
  • Considerations for licensors: Our public licenses are intended for use by those authorized to give the public +permission to use material in ways otherwise restricted by copyright and certain other rights. +Our licenses are irrevocable. +Licensors should read and understand the terms and conditions of the license they choose before applying it. +Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the +material as expected. +Licensors should clearly mark any material not subject to the license. +This includes other CC-licensed material, or material used under an exception or limitation to copyright. +More considerations for licensors.

  • +
  • Considerations for the public: By using one of our public licenses, a licensor grants the public permission to use +the licensed material under specified terms and conditions. +If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or +limitation to copyright–then that use is not regulated by the license. +Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. +Use of the licensed material may still be restricted for other reasons, including because others have copyright or +other rights in the material. +A licensor may make special requests, such as asking that all changes be marked or described. +Although not required by our licenses, you are encouraged to respect those requests where reasonable. +More considerations for the public.

  • +
+
+
+

Creative Commons Attribution 4.0 International Public License

+

By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this +Creative Commons Attribution 4.0 International Public License (“Public License”). +To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration +of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits +the Licensor receives from making the Licensed Material available under these terms and conditions.

+
+

Section 1 – Definitions

+
    +
  1. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the +Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise +modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. +For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, +Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image.

  2. +
  3. Adapter’s License means the license You apply to Your Copyright and Similar Rights in Your contributions to +Adapted Material in accordance with the terms and conditions of this Public License.

  4. +
  5. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, +without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how +the rights are labeled or categorized. +For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.

  6. +
  7. Effective Technological Measures means those measures that, in the absence of proper authority, may not be +circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, +1996, and/or similar international agreements.

  8. +
  9. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright +and Similar Rights that applies to Your use of the Licensed Material.

  10. +
  11. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied +this Public License.

  12. +
  13. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which +are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor +has authority to license.

  14. +
  15. Licensor means the individual(s) or entity(ies) granting rights under this Public License.

  16. +
  17. Share means to provide material to the public by any means or process that requires permission under the Licensed +Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or +importation, and to make material available to the public including in ways that members of the public may access the +material from a place and at a time individually chosen by them.

  18. +
  19. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European +Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as +well as other essentially equivalent rights anywhere in the world.

  20. +
  21. You means the individual or entity exercising the Licensed Rights under this Public License. +Your has a corresponding meaning.

  22. +
+
+
+

Section 2 – Scope

+
    +
  1. License grant.

    +
      +
    1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, +royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the +Licensed Material to:

      +
      +
        +
      1. reproduce and Share the Licensed Material, in whole or in part; and

      2. +
      3. produce, reproduce, and Share Adapted Material.

      4. +
      +
      +
    2. +
    3. Exceptions and Limitations. +For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not +apply, and You do not need to comply with its terms and conditions.

    4. +
    5. Term. +The term of this Public License is specified in Section 6(a).

    6. +
    7. Media and formats; technical modifications allowed. +The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or +hereafter created, and to make technical modifications necessary to do so. +The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical +modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent +Effective Technological Measures. +For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces +Adapted Material.

    8. +
    9. Downstream recipients.

      +
      +
        +
      1. Offer from the Licensor – Licensed Material. +Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the +Licensed Rights under the terms and conditions of this Public License.

      2. +
      3. No downstream restrictions. +You may not offer or impose any additional or different terms or conditions on, or apply any Effective +Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any +recipient of the Licensed Material.

      4. +
      +
      +
    10. +
    11. No endorsement. +Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or +that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, +the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i).

    12. +
    +
  2. +
  3. Other rights.

    +
      +
    1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, +privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or +agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise +the Licensed Rights, but not otherwise.

    2. +
    3. Patent and trademark rights are not licensed under this Public License.

    4. +
    5. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the +Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or +compulsory licensing scheme. +In all other cases the Licensor expressly reserves any right to collect such royalties.

    6. +
    +
  4. +
+
+
+

Section 3 – License Conditions

+

Your exercise of the Licensed Rights is expressly made subject to the following conditions.

+
    +
  1. Attribution.

    +
      +
    1. If You Share the Licensed Material (including in modified form), You must:

      +
      +
        +
      1. retain the following if it is supplied by the Licensor with the Licensed Material:

      2. +
      +
      +
        +
      1. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, +in any reasonable manner requested by the Licensor (including by pseudonym if designated);

      2. +
      3. a copyright notice;

      4. +
      5. a notice that refers to this Public License;

      6. +
      7. a notice that refers to the disclaimer of warranties;

      8. +
      9. a URI or hyperlink to the Licensed Material to the extent reasonably practicable;

      10. +
      +
      +
        +
      1. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and

      2. +
      3. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or +hyperlink to, this Public License.

      4. +
      +
      +
    2. +
    3. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context +in which You Share the Licensed Material. +For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that +includes the required information.

    4. +
    5. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent +reasonably practicable.

    6. +
    7. If You Share Adapted Material You produce, the Adapter’s License You apply must not prevent recipients of the +Adapted Material from complying with this Public License.

    8. +
    +
  2. +
+
+
+

Section 4 – Sui Generis Database Rights

+

Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material:

+
    +
  1. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a +substantial portion of the contents of the database;

  2. +
  3. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis +Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is +Adapted Material; and

  4. +
  5. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the +database.

  6. +
+

For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License +where the Licensed Rights include other Copyright and Similar Rights.

+
+
+

Section 5 – Disclaimer of Warranties and Limitation of Liability

+
    +
  1. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed +Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed +Material, whether express, implied, statutory, or other. +This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, +non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not +known or discoverable. +Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.

  2. +
  3. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without +limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, +exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed +Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. +Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.

  4. +
  5. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the +extent possible, most closely approximates an absolute disclaimer and waiver of all liability.

  6. +
+
+
+

Section 6 – Term and Termination

+
    +
  1. This Public License applies for the term of the Copyright and Similar Rights licensed here. +However, if You fail to comply with this Public License, then Your rights under this Public License terminate +automatically.

  2. +
  3. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates:

    +
      +
    1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the +violation; or

    2. +
    3. upon express reinstatement by the Licensor.

    4. +
    +

    For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for +Your violations of this Public License.

    +
  4. +
  5. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or +stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License.

  6. +
  7. Sections 1, 5, 6, 7, and 8 survive termination of this Public License.

  8. +
+
+
+

Section 7 – Other Terms and Conditions

+
    +
  1. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless +expressly agreed.

  2. +
  3. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from +and independent of the terms and conditions of this Public License.

  4. +
+
+
+

Section 8 – Interpretation

+
    +
  1. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, +or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this +Public License.

  2. +
  3. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically +reformed to the minimum extent necessary to make it enforceable. +If the provision cannot be reformed, it shall be severed from this Public License without affecting the +enforceability of the remaining terms and conditions.

  4. +
  5. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly +agreed to by the Licensor.

  6. +
  7. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges +and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or +authority.

  8. +
+
+

Creative Commons is not a party to its public licenses. +Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those +instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under +a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at creativecommons.org/policies, +Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of +Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized +modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of +licensed material. +For the avoidance of doubt, this paragraph does not form part of the public licenses.

+

Creative Commons may be contacted at creativecommons.org

+
+
+
+ +
+
+ +
+ +
+
+ + + + + \ No newline at end of file diff --git a/License.html b/License.html new file mode 100644 index 00000000..41b57e86 --- /dev/null +++ b/License.html @@ -0,0 +1,527 @@ + + + + + + + + + Apache License 2.0 - GHDL-cosim latest documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+ +
+ +
+ +
+
+
+

Note

+

This is a local copy of the Apache License Version 2.0.

+
+
+

Attention

+

This Apache License, 2.0 applies to all source and configuration files of project, except documentation.

+
+
+

Apache License 2.0

+

Version 2.0, January 2004

+

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

+
+

1. Definitions

+

“License” shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 +through 9 of this document.

+

“Licensor” shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.

+

“Legal Entity” shall mean the union of the acting entity and all other entities that control, are controlled by, or +are under common control with that entity. +For the purposes of this definition, “control” means (i) the power, direct or indirect, to cause the direction or +management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity.

+

“You” (or “Your”) shall mean an individual or Legal Entity exercising permissions granted by this License.

+

“Source” form shall mean the preferred form for making modifications, including but not limited to software source +code, documentation source, and configuration files.

+

“Object” form shall mean any form resulting from mechanical transformation or translation of a Source form, +including but not limited to compiled object code, generated documentation, and conversions to other media types.

+

“Work” shall mean the work of authorship, whether in Source or Object form, made available under the License, as +indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix +below).

+

“Derivative Works” shall mean any work, whether in Source or Object form, that is based on (or derived from) the +Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. +For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link +(or bind by name) to the interfaces of, the Work and Derivative Works thereof.

+

“Contribution” shall mean any work of authorship, including the original version of the Work and any modifications +or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the +Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. +For the purposes of this definition, “submitted” means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source +code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of +discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in +writing by the copyright owner as “Not a Contribution.”

+

“Contributor” shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been +received by Licensor and subsequently incorporated within the Work.

+
+ +
+

3. Grant of Patent License

+

Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, +non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent +claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of +their Contribution(s) with the Work to which such Contribution(s) was submitted. +If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging +that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, +then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation +is filed.

+
+
+

4. Redistribution

+

You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without +modifications, and in Source or Object form, provided that You meet the following conditions:

+
    +
  • You must give any other recipients of the Work or Derivative Works a copy of this License; and

  • +
  • You must cause any modified files to carry prominent notices stating that You changed the files; and

  • +
  • You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and +attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and

  • +
  • If the Work includes a “NOTICE” text file as part of its distribution, then any Derivative Works that You +distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those +notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a +NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided +along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such +third-party notices normally appear. +The contents of the NOTICE file are for informational purposes only and do not modify the License. +You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to +the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the +License.

  • +
+

You may add Your own copyright statement to Your modifications and may provide additional or different license terms and +conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this +License.

+
+
+

5. Submission of Contributions

+

Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the +Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may +have executed with Licensor regarding such Contributions.

+
+
+

6. Trademarks

+

This License does not grant permission to use the trade names, trademarks, service marks, or product names of the +Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the +content of the NOTICE file.

+
+
+

7. Disclaimer of Warranty

+

Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its +Contributions) on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, +without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. +You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks +associated with Your exercise of permissions under this License.

+
+
+

8. Limitation of Liability

+

In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required +by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any +character arising as a result of this License or out of the use or inability to use the Work (including but not limited +to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages +or losses), even if such Contributor has been advised of the possibility of such damages.

+
+
+

9. Accepting Warranty or Additional Liability

+

While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of +support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. +However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on +behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any +liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or +additional liability.

+
+
+

Appendix: How to apply the Apache License to your work

+

To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets +“[]” replaced with your own identifying information. +(Don’t include the brackets!) +The text should be enclosed in the appropriate comment syntax for the file format. +We also recommend that a file or class name and description of purpose be included on the same “printed page” as the +copyright notice for easier identification within third-party archives.

+
Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+
+
+
+ +
+
+ +
+ +
+
+ + + + + \ No newline at end of file diff --git a/_images/logo.png b/_images/logo.png new file mode 100644 index 00000000..56804ec6 Binary files /dev/null and b/_images/logo.png differ diff --git a/_images/matrices_array_axis_vcs.png b/_images/matrices_array_axis_vcs.png new file mode 100644 index 00000000..60987c0d Binary files /dev/null and b/_images/matrices_array_axis_vcs.png differ diff --git a/_images/matrices_vunit_axis_vcs.png b/_images/matrices_vunit_axis_vcs.png new file mode 100644 index 00000000..e3087345 Binary files /dev/null and b/_images/matrices_vunit_axis_vcs.png differ diff --git a/_sources/Doc-License.rst.txt b/_sources/Doc-License.rst.txt new file mode 100644 index 00000000..86dc3d10 --- /dev/null +++ b/_sources/Doc-License.rst.txt @@ -0,0 +1,299 @@ +.. _DOCLICENSE: + +.. Note:: This is a local copy of the `Creative Commons - Attribution 4.0 International (CC BY 4.0) `__. + +.. Attention:: This **CC BY 4.0** license applies only to the **documentation** of this project. + + +Creative Commons Attribution 4.0 International +############################################## + +Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. +Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. +Creative Commons makes its licenses and related information available on an “as-is” basis. +Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or +any related information. +Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. + +Using Creative Commons Public Licenses +====================================== + +Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders +may use to share original works of authorship and other material subject to copyright and certain other rights specified +in the public license below. +The following considerations are for informational purposes only, are not exhaustive, and do not form part of our +licenses. + +* **Considerations for licensors:** Our public licenses are intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by copyright and certain other rights. + Our licenses are irrevocable. + Licensors should read and understand the terms and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the + material as expected. + Licensors should clearly mark any material not subject to the license. + This includes other CC-licensed material, or material used under an exception or limitation to copyright. + `More considerations for licensors `__. + +* **Considerations for the public:** By using one of our public licenses, a licensor grants the public permission to use + the licensed material under specified terms and conditions. + If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or + limitation to copyright–then that use is not regulated by the license. + Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. + Use of the licensed material may still be restricted for other reasons, including because others have copyright or + other rights in the material. + A licensor may make special requests, such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to respect those requests where reasonable. + `More considerations for the public `__. + +Creative Commons Attribution 4.0 International Public License +============================================================= + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this +Creative Commons Attribution 4.0 International Public License ("Public License"). +To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration +of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits +the Licensor receives from making the Licensed Material available under these terms and conditions. + +Section 1 – Definitions +----------------------- + +a. **Adapted Material** means material subject to Copyright and Similar Rights that is derived from or based upon the + Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise + modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. + For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + +b. **Adapter's License** means the license You apply to Your Copyright and Similar Rights in Your contributions to + Adapted Material in accordance with the terms and conditions of this Public License. + +c. **Copyright and Similar Rights** means copyright and/or similar rights closely related to copyright including, + without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how + the rights are labeled or categorized. + For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + +d. **Effective Technological Measures** means those measures that, in the absence of proper authority, may not be + circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, + 1996, and/or similar international agreements. + +e. **Exceptions and Limitations** means fair use, fair dealing, and/or any other exception or limitation to Copyright + and Similar Rights that applies to Your use of the Licensed Material. + +f. **Licensed Material** means the artistic or literary work, database, or other material to which the Licensor applied + this Public License. + +g. **Licensed Rights** means the rights granted to You subject to the terms and conditions of this Public License, which + are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor + has authority to license. + +h. **Licensor** means the individual(s) or entity(ies) granting rights under this Public License. + +i. **Share** means to provide material to the public by any means or process that requires permission under the Licensed + Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or + importation, and to make material available to the public including in ways that members of the public may access the + material from a place and at a time individually chosen by them. + +j. **Sui Generis Database Rights** means rights other than copyright resulting from Directive 96/9/EC of the European + Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as + well as other essentially equivalent rights anywhere in the world. + +k. **You** means the individual or entity exercising the Licensed Rights under this Public License. + **Your** has a corresponding meaning. + +Section 2 – Scope +----------------- + +a. **License grant.** + + 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, + royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the + Licensed Material to: + + A. reproduce and Share the Licensed Material, in whole or in part; and + + B. produce, reproduce, and Share Adapted Material. + + 2. **Exceptions and Limitations.** + For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not + apply, and You do not need to comply with its terms and conditions. + + 3. **Term.** + The term of this Public License is specified in Section 6(a). + + 4. **Media and formats; technical modifications allowed.** + The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or + hereafter created, and to make technical modifications necessary to do so. + The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical + modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent + Effective Technological Measures. + For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces + Adapted Material. + + 5. **Downstream recipients.** + + A. **Offer from the Licensor – Licensed Material.** + Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this Public License. + + B. **No downstream restrictions.** + You may not offer or impose any additional or different terms or conditions on, or apply any Effective + Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any + recipient of the Licensed Material. + + 6. **No endorsement.** + Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or + that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + +b. **Other rights.** + + 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or + agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise + the Licensed Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this Public License. + + 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the + Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or + compulsory licensing scheme. + In all other cases the Licensor expressly reserves any right to collect such royalties. + +Section 3 – License Conditions +------------------------------ + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + +a. **Attribution.** + + 1. If You Share the Licensed Material (including in modified form), You must: + + A. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, + in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context + in which You Share the Licensed Material. + For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that + includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the + Adapted Material from complying with this Public License. + +Section 4 – Sui Generis Database Rights +--------------------------------------- + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + +a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a + substantial portion of the contents of the database; + +b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis + Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is + Adapted Material; and + +c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the + database. + +For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License +where the Licensed Rights include other Copyright and Similar Rights. + +Section 5 – Disclaimer of Warranties and Limitation of Liability +---------------------------------------------------------------- + +a. **Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed + Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed + Material, whether express, implied, statutory, or other. + This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, + non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not + known or discoverable. + Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.** + +b. **To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without + limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, + exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed + Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. + Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.** + +c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the + extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +Section 6 – Term and Termination +-------------------------------- + +a. This Public License applies for the term of the Copyright and Similar Rights licensed here. + However, if You fail to comply with this Public License, then Your rights under this Public License terminate + automatically. + +b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for + Your violations of this Public License. + +c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or + stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + +d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +Section 7 – Other Terms and Conditions +-------------------------------------- + +a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless + expressly agreed. + +b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from + and independent of the terms and conditions of this Public License. + +Section 8 – Interpretation +-------------------------- + +a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, + or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this + Public License. + +b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically + reformed to the minimum extent necessary to make it enforceable. + If the provision cannot be reformed, it shall be severed from this Public License without affecting the + enforceability of the remaining terms and conditions. + +c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly + agreed to by the Licensor. + +d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges + and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or + authority. + +------------------ + +Creative Commons is not a party to its public licenses. +Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those +instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under +a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at `creativecommons.org/policies `__, +Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of +Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized +modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of +licensed material. +For the avoidance of doubt, this paragraph does not form part of the public licenses. + +Creative Commons may be contacted at `creativecommons.org `__ diff --git a/_sources/License.rst.txt b/_sources/License.rst.txt new file mode 100644 index 00000000..5a5f3ea1 --- /dev/null +++ b/_sources/License.rst.txt @@ -0,0 +1,178 @@ +.. _SRCLICENSE: + +.. Note:: + This is a local copy of the `Apache License Version 2.0 `__. + +.. Attention:: + This **Apache License, 2.0** applies to all **source and configuration files of project**, **except documentation**. + +Apache License 2.0 +################## + +Version 2.0, January 2004 + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + +1. Definitions +============== + +**"License"** shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 +through 9 of this document. + +**"Licensor"** shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +**"Legal Entity"** shall mean the union of the acting entity and all other entities that control, are controlled by, or +are under common control with that entity. +For the purposes of this definition, **"control"** means (i) the power, direct or indirect, to cause the direction or +management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +**"You"** (or **"Your"**) shall mean an individual or Legal Entity exercising permissions granted by this License. + +**"Source"** form shall mean the preferred form for making modifications, including but not limited to software source +code, documentation source, and configuration files. + +**"Object"** form shall mean any form resulting from mechanical transformation or translation of a Source form, +including but not limited to compiled object code, generated documentation, and conversions to other media types. + +**"Work"** shall mean the work of authorship, whether in Source or Object form, made available under the License, as +indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix +below). + +**"Derivative Works"** shall mean any work, whether in Source or Object form, that is based on (or derived from) the +Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. +For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link +(or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +**"Contribution"** shall mean any work of authorship, including the original version of the Work and any modifications +or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the +Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. +For the purposes of this definition, **"submitted"** means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source +code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of +discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in +writing by the copyright owner as **"Not a Contribution."** + +**"Contributor"** shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been +received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License +============================= + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, +non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object +form. + +3. Grant of Patent License +========================== + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, +non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent +claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of +their Contribution(s) with the Work to which such Contribution(s) was submitted. +If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging +that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, +then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation +is filed. + +4. Redistribution +================= + +You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without +modifications, and in Source or Object form, provided that You meet the following conditions: + +* You must give any other recipients of the Work or Derivative Works a copy of this License; and +* You must cause any modified files to carry prominent notices stating that You changed the files; and +* You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the + Derivative Works; and +* If the Work includes a **"NOTICE"** text file as part of its distribution, then any Derivative Works that You + distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those + notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a + NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided + along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such + third-party notices normally appear. + The contents of the NOTICE file are for informational purposes only and do not modify the License. + You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to + the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the + License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and +conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this +License. + +5. Submission of Contributions +============================== + +Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the +Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may +have executed with Licensor regarding such Contributions. + +6. Trademarks +============= + +This License does not grant permission to use the trade names, trademarks, service marks, or product names of the +Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the +content of the NOTICE file. + +7. Disclaimer of Warranty +========================= + +Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its +Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, +without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. +You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks +associated with Your exercise of permissions under this License. + +8. Limitation of Liability +========================== + +In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required +by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any +character arising as a result of this License or out of the use or inability to use the Work (including but not limited +to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages +or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability +============================================= + +While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of +support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. +However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on +behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any +liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or +additional liability. + +Appendix: How to apply the Apache License to your work +====================================================== + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets +"[]" replaced with your own identifying information. +(Don't include the brackets!) +The text should be enclosed in the appropriate comment syntax for the file format. +We also recommend that a file or class name and description of purpose be included on the same "printed page" as the +copyright notice for easier identification within third-party archives. + +.. code-block:: none + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/_sources/ci.rst.txt b/_sources/ci.rst.txt new file mode 100644 index 00000000..e7086149 --- /dev/null +++ b/_sources/ci.rst.txt @@ -0,0 +1,33 @@ +.. program:: ghdl +.. _COSIM:CI: + +Continuous Integration +###################### + +Since the main purpose of this repository is to provide reproducible and documented examples for users to learn, all of +them are tested periodically in a `Continuous Integration (CI) `_ +service. Currently, `GitHub Actions `_ is used and four different jobs/environments +are tested: + +* GNU/Linux: + + * Docker image ``ghdl/vunit:llvm`` from `ghdl/docker `_. + * Latest *nightly* release installed through Action `ghdl/setup-ghdl-ci `_ on + Ubuntu. + +* Windows: + + * Latest stable release for MINGW64 with LLVM backend. + * Latest *nightly* release installed through Action `ghdl/setup-ghdl-ci `_ on + MINGW64. + + .. NOTE:: + MSYS2 is set up with Action `msys2/setup-msys2 `_. + +The entrypoints of the examples are shell scripts (``run.sh``), makefiles (see :cosimsharp:`24`), or Python scripts +(``run.py``). To handle all of them with a common interface, `pytest `_ is used. Hence the full test suite +is defined in :cosimtree:`test.py `. Details about which examples are not supported on specific platforms can +be found there. + +Past runs can be inspected at `ghdl/ghdl-cosim/actions `_. +It can be useful for users to know what to expect before executing the examples themselves. diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt new file mode 100644 index 00000000..b29ff788 --- /dev/null +++ b/_sources/index.rst.txt @@ -0,0 +1,123 @@ +.. program:: ghdl + +.. _COSIM: + +Co-simulation with GHDL +####################### + +.. index:: interfacing + +.. index:: other languages + +.. index:: foreign + +.. index:: VPI + +.. index:: VHPI + +.. index:: VHPIDIRECT + +.. index:: SystemC + + +.. image:: _static/logo.png + :width: 500 px + :align: center + :target: https://github.com/ghdl/ghdl-cosim + +.. raw:: html + +
+ +

+ + + + + +

+ +
+ +This repository contains **documentation** and **working examples** about how to co-simulate VHDL and other languages through +GHDL's foreign interfaces. Since specific features of the language and the tool are used, it is suggested for users +who are new to either `GHDL` or `VHDL` to first read the :ref:`USING:QuickStart` in the main documentation +(`ghdl.github.io/ghdl `_). + +Three main approaches are used to co-simulate (co-execute) VHDL sources along with software applications written in a +language other than VHDL (typically C/C++/SystemC): + +* `Verilog Procedural Interface `_ (VPI), also known as + Program Language Interface (PLI) 2.0. + +* `VHDL Programming Interface `_ (VHPI), or specific implementations, + such as Foreign Language Interface (FLI). + +* Generation of C/C++ models/sources through a transpiler. + +VPI and VHPI are complex APIs which allow to inspect the hierarchy, set callbacks and/or assign signals. Because +provided features are similar but VPI was published years before VHPI, GHDL supports VPI only. Furthermore, as an +easier to use alternative, GHDL features a custom coexecution interface named VHPIDIRECT, similar to SystemVerilog's +DPI (`Direct Programming Interface `_). +As of today, generation of C++/SystemC models à la `Verilator `_ is not +supported. However, a *vhdlator*/*ghdlator* might be available in the future. + +.. ATTENTION:: In fact, VHPIDIRECT is defined as part of VHPI in VHDL 2008 LRM. However, GHDL's implementation is not + compliant with the standard. This is probably because VHPIDIRECT was implemented in GHDL based on some draft, + before VHDL 2008 was official. Nevertheless, the VASG is currently discussing the addition of a Foreign Function + Interface (FFI) or Direct Programming Interface (DPI) to the next revision of the standard. See `[LCS-202x] VHDL DPI/FFI based on GHDL’s implementation of VHPIDIRECT `_ + (`PDF `_). + +:ref:`VHPIDIRECT ` is easier to use than :ref:`VPI `/:ref:`VHPI ` +because, as the name suggests, it is a direct interface. However, on the one hand VHPIDIRECT requires modification of +VHDL sources, which might not be possible or desirable in certain contexts. On the other hand, VPI/VHPI allow use cases +which are not yet possible with VHPIDIRECT, such as controlling execution time steps. It is suggested to read the quick +start examples of both interfacing mechanisms, in order to get a feel for the differences. + + +.. toctree:: + :hidden: + + ci + + +.. toctree:: + :caption: VHPIDIRECT + :hidden: + + vhpidirect/index + vhpidirect/declarations + vhpidirect/wrapping + vhpidirect/linking + vhpidirect/dynamic + vhpidirect/grt + vhpidirect/examples/index + vhpidirect/notebook/index + + +.. toctree:: + :caption: VPI + :hidden: + + vpi/index + vpi/examples/index + + +.. toctree:: + :caption: VPHI + :hidden: + + vhpi/index + + +.. toctree:: + :caption: Appendix + :hidden: + + License + Doc-License diff --git a/_sources/vhpi/index.rst.txt b/_sources/vhpi/index.rst.txt new file mode 100644 index 00000000..7f85ede2 --- /dev/null +++ b/_sources/vhpi/index.rst.txt @@ -0,0 +1,20 @@ +.. program:: ghdl + +.. _COSIM:VHPI:Intro: + +Introduction +============ + +.. ATTENTION:: + Since VPI and VHPI provide very similar features, and because VPI is already supported in GHDL, VHPI is not available + (yet). Hence, the information in this section is provided for completeness only. + +VHDL Programming Interface (VHPI) was introduced in 2007, as an ammendment to IEEE Std 1076-2002: `1076c-2007 - IEEE Standard VHDL Language Reference Manual - Procedural Language Application Interface `_. +In the 2009, the programming interface was published as part of `1076-2008 - IEEE Standard VHDL Language Reference Manual `_. +The latest version was published in 2019: `1076-2019 - IEEE Standard for VHDL Language Reference Manual `_. + +Some vendors support C programming interfaces similar to VHPI. For example, Mentor Graphics' ModelSim/QuestaSim supports +a Foreign Language Interface (FLI) that provides functions to have procedural access to information within the simulator, +``vsim``. These functions allow traversing the hierarchy, getting/setting values and controlling a simulation run. See +`Using ModelSim Foreign Language Interface for c – VHDL CoSimulation and for Simulator Control on Linux x86 Platform `_ +and `github.com/andrepool/fli `_. diff --git a/_sources/vhpidirect/declarations.rst.txt b/_sources/vhpidirect/declarations.rst.txt new file mode 100644 index 00000000..7ee0938c --- /dev/null +++ b/_sources/vhpidirect/declarations.rst.txt @@ -0,0 +1,113 @@ +.. program:: ghdl + +.. _COSIM:VHPIDIRECT:Declarations: + +Type declarations +================= + +Only subprograms (**functions** or **procedures**) can be imported using the foreign +attribute. In the following minimal :ref:`example `, +the `sin` function is imported: + +.. code-block:: VHDL + + package math is + function sin (v : real) return real; + attribute foreign of sin : function is "VHPIDIRECT sin"; + end math; + + package body math is + function sin (v : real) return real is + begin + assert false severity failure; + end sin; + end math; + +Requirements: + +* A subprogram is made foreign if the ``foreign`` attribute decorates + it. + +* The ``attribute`` specification must be in the same declarative part as the + subprogram and must be after it. This is a general rule for specifications. + +* The value of the specification must be a locally static string. + +* The value of the attribute must start with ``VHPIDIRECT`` (an upper-case keyword + followed by one or more blanks). The linkage name of the subprogram follows. The + path to a shared library can be optionally specified between the keyword and the + name of the subprogram (see :ref:`COSIM:VHPIDIRECT:Examples:shared:shlib`). + +* Even when a subprogram is foreign, its body must be present in VHDL. However, since + it won't be called, you can make it empty or simply put an assertion. If the body + is ever executed, that will mean that the foreign resource was not properly linked. + +* Except for resources in the standard C library (which is linked by default), the + object file with the source code for foreign subprogram(s) must then be linked to + GHDL, expanded upon in :ref:`COSIM:VHPIDIRECT:Linking`. + +.. NOTE:: + Attribute ``foreign`` is declared in the 1993 revision of the ``std.standard`` package. + Therefore, it cannot be used in VHDL 1987. + +.. _Restrictions_on_foreign_declarations: + +Restrictions on type declarations +--------------------------------- + +Any subprogram can be imported. GHDL puts no restrictions on foreign +subprograms. However, the representation of a type or of an interface in a +foreign language may be obscure. Most non-composite types are easily imported: + +*integer types* + 32 bit word. Generally, `int` for `C` or `Integer` for `Ada`. + +*physical types* + 64 bit word. Generally, `long long` for `C` or `Long_Long_Integer` for `Ada`. + +*floating point types* + 64 bit floating point word. Generally, `double` for `C` or `Long_Float` for `Ada`. + +*enumeration types* + 8 bit word, or, if the number of literals is greater than 256, by a 32 bit word. + There is no corresponding C type, since arguments are not promoted. + +Non-composite types are passed by value. For the `in` mode (default), this corresponds +to the `C` or `Ada` mechanism. `out` and `inout` interfaces are gathered in a record and +this record is passed by reference as the first argument to the subprogram. As a +consequence, it is not suggested to use `out` and/or `inout` modes in foreign +subprograms, since they are not portable. + +Composite types: + +* Records are represented like a `C` structure and are passed by reference to subprograms. + +* Arrays with static bounds are represented like a `C` array, whose length is the number + of elements, and are passed by reference to subprograms. + +* Unconstrained arrays are represented by a fat pointer. It is not suggested to use + unconstrained arrays in foreign subprograms. + +* Accesses to an unconstrained array are fat pointers. Other accesses correspond to an + address/pointer and are passed to a subprogram like other non-composite types. + +* Files are represented by a 32 bit word, which corresponds to an index in a table. + +.. ATTENTION:: + The internal representation of arrays is little-endian left-to-right, regardless of the + bounds. As a result, when used from C, indexes always correspond to direction ``to``; thus, + indexes for arrays with direction ``downto`` are reversed between VHDL and C: + + .. code-block:: vhdl + + constant stdv: std_logic_vector(3 downto 0) := "UX10"; -- a(0) in VHDL corresponds to a[3] in C, both print '0' + constant stdv: std_logic_vector(0 to 3) := "UX10"; -- a(0) in VHDL corresponds to a[0] in C, both print 'U' + +.. ATTENTION:: + Since both constrained arrays and accesses to constrained arrays are passed by reference, + distinct VHDL types are mapped to the same types in C. For example, an array of integers and + an access to array of integers are both passed as ``int*``. + + As a result, it is typically possible to reuse the same C implementation for handling VHDL + arrays/records or their accesses/pointers. See, for example, :ref:`COSIM:VHPIDIRECT:Examples:arrays:intvector:vhdlsized` + and/or :ref:`COSIM:VHPIDIRECT:Examples:quickstart:shrecord`. diff --git a/_sources/vhpidirect/dynamic.rst.txt b/_sources/vhpidirect/dynamic.rst.txt new file mode 100644 index 00000000..f488d4fc --- /dev/null +++ b/_sources/vhpidirect/dynamic.rst.txt @@ -0,0 +1,111 @@ +.. program:: ghdl + +.. _COSIM:VHPIDIRECT:Dynamic: + +Dynamic loading +############### + +Building either foreign resources or the VHDL simulation model as shared libraries allows to decouple the build procedures. + +.. _COSIM:VHPIDIRECT:Dynamic:loading_within_a_simulation: + +Loading foreign objects from within a simulation +================================================ + +Instead of linking and building foreign objects along with GHDL, it is also possible to load foreign resources dynamically. +In order to do so, provide the path and name of the shared library where the resource is to be loaded from. For example: + +.. code-block:: VHDL + + attribute foreign of get_rand: function is "VHPIDIRECT ./getrand.so get_rand"; + +.. _COSIM:VHPIDIRECT:Dynamic:generating_shared_libraries: + +Generating shared libraries +=========================== + +.. TIP:: + Ensure reading and understanding :ref:`COSIM:VHPIDIRECT:Linking` before this one. + +There are three possibilities to elaborate simulation models as shared libraries, instead of executable binaries: + +* ``ghdl -e -shared [options...] primary_unit [secondary_unit]`` + +* ``ghdl -e -Wl,-shared -Wl,-Wl,--version-script=./file.ver -Wl,-Wl,-u,ghdl_main [options...] primary_unit [secondary_unit]`` + +* ``gcc -shared -Wl,`ghdl --list-link tb` -Wl,--version-script=./file.ver -Wl,-u,ghdl_main`` + +The only difference between the two later procedures is the entrypoint (GHDL or GCC). Preference depends on the additional +options that users need to provide. The main difference with the former is that it will make all symbols visible in the +resulting shared library. In the other two procedures, visible symbols will be the ones defined in the default ``grt.ver`` +added by GHDL and the ``file.ver`` provided by the user. Note that ``file.ver`` must include ``ghdl_main`` and any other +added by the user. See example :ref:`COSIM:VHPIDIRECT:Examples:shared:shghdl` and :cosimsharp:`2`. + +.. HINT:: + When GHDL is configured with ``--default-pic`` explicitly, it uses it implicitly when executing any :option:`-a`, + :option:`-e` or :option:`-r` command. Hence, it is not required to provide these arguments (fPIC/PIE) to GHDL. However, + these might need to be provided when building C sources with GCC. Otherwise linker errors such as the following are produced: + + .. code-block:: + + relocation R_X86_64_PC32 against symbol * can not be used when making a shared object; recompile with -fPIC + +.. HINT:: + For further details regarding how to call ``ghdl_main`` see :ref:`Starting_a_simulation_from_a_foreign_program`. + +.. NOTE:: + Alternatively, if the shared library is built with :option:`--bind` and :option:`--list-link`, the output from the later + can be filtered with tools such as ``sed`` in order to remove the default version script (accomplished in :ghdlsharp:`640`), + and make all symbols visible by default. However, this procedure is only recommended in edge cases where other solutions + don't fit. + +.. _COSIM:VHPIDIRECT:Dynamic:loading_a_simulation: + +Loading a simulation +==================== + +.. ATTENTION:: + By default, GHDL uses ``grt.ver`` to limit which symbols are exposed in the generated artifacts, and ``ghdl_main`` is not + included. See :ref:`COSIM:VHPIDIRECT:Dynamic:generating_shared_libraries` for guidelines to generate shared objects with + visible or filtered symbols. + +In order to generate a position independent executable (PIE), be it an executable binary +or a shared library, GHDL must be built with config option ``--default-pic``. This will ensure +that all the libraries and sources analyzed by GHDL generate position independent code (PIC). + +PIE binaries can be loaded and executed from any language that supports C-alike signatures and types +(C, C++, golang, Python, Rust, etc.). This allows seamless co-simulation using concurrent/parallel execution features available +in each language: pthreads, goroutines/gochannels, multiprocessing/queues, etc. Moreover, it provides a mechanism to execute +multiple GHDL simulations in parallel. + +For example, in Python: + +.. code-block:: Python + + import ctypes + gbin = ctypes.CDLL(bin_path) + + args = ['-gGENA="value"', 'gGENB="value"'] + + xargs = (ctypes.POINTER(ctypes.c_char) * (len(args)+1))() + for idx, arg in enumerate(args): + xargs[idx+1] = ctypes.create_string_buffer(arg.encode('utf-8')) + + gbin.main(len(xargs)-1, xargs) + + import _ctypes + # On GNU/Linux + _ctypes.dlclose(gbin._handle) + # On Windows + #_ctypes.FreeLibrary(gbin._handle) + +See a complete example written in C in :ref:`COSIM:VHPIDIRECT:Examples:shared:shghdl`. + +.. TIP:: + As explained in :ref:`Starting_a_simulation_from_a_foreign_program`, ``ghdl_main`` must be called once, since reseting/restarting + the simulation runtime is not supported yet (see :ghdlsharp:`1184`). When it is loaded dynamically, this means that the binary + file/library needs to be unloaded from memory and loaded again (as in :ref:`COSIM:VHPIDIRECT:Examples:shared:shghdl`). + +.. TIP:: + See :ghdlsharp:`803` for details about expected differences in the exit codes, depending on the version of the VHDL standard + that is used. diff --git a/_sources/vhpidirect/examples/arrays.rst.txt b/_sources/vhpidirect/examples/arrays.rst.txt new file mode 100644 index 00000000..212bf2dc --- /dev/null +++ b/_sources/vhpidirect/examples/arrays.rst.txt @@ -0,0 +1,267 @@ +.. program:: ghdl +.. _COSIM:VHPIDIRECT:Examples:arrays: + +Arrays +####### + +.. IMPORTANT:: + A VHDL access that is used for a constrained/bounded array is tied to a type that specifies its length. In + :ref:`COSIM:VHPIDIRECT:Examples:arrays:intvector` and :ref:`COSIM:VHPIDIRECT:Examples:arrays:matrices` below, one and + two dimensional lengths are specified, respectively. + This means that a separate type needs to be declared for an array with different dimensions and/or different sizes in + any dimension. In order to create a single type for many differently shaped arrays, it would need to be unconstrained. + See :cosimsharp:`3` for work in progress regarding unconstrained types. + +.. _COSIM:VHPIDIRECT:Examples:arrays:intvector: + +Constrained/bounded integer arrays +********************************** + +As explained in :ref:`Restrictions_on_foreign_declarations`, unconstrained arrays are represented by a fat pointer in C, +and it is not suggested to use fat pointers unless it is unavoidable. Hence, it is desirable for data buffers which are +to be represented as arrays to be constrained. However, constraining arrays in VHDL and C separately is error prone. + +This example includes multiple solutions to set the bounding size once only (either in C or in VHDL), and have the +parameter passed to the other language so that matching types are defined. Moreover, independently of where the size is +defined, it is possible to allocate and free the buffers in any of the languages. The following examples show how to +define them in C or VHDL and have them (de)allocated in either of them. + +.. ATTENTION:: + Pointers/accesses MUST be freed/deallocated in the same language that was used to allocate them. Hence, it is not + possible to allocate in VHDL and free in C, nor *vice versa*. + +.. _COSIM:VHPIDIRECT:Examples:arrays:intvector:csized: + +:cosimtree:`Sized in C ` +============================================================ + +Integer arrays with the content fully defined in C can be passed to VHDL by first passing their size, so that an +appropriate array type can be created in VHDL. After that, another VHPIDIRECT subprogram can be defined either to pass +the array to be filled (allocated in VHDL), or to return the array access (pointer) allocated in C. + +This example shows how to hardcode both the length and the content of an array in C, with matching types are created in +VHDL: + +* :cosimtree:`proc `: an array is allocated in VHDL and a procedure is used. + After filling the array in C, it is read and modified from VHDL. + +* :cosimtree:`fcn `: an array is allocated in C and the pointer is passed to + VHDL, where the content is read and modified. + + If the integer array must be created or filled at runtime by some more advanced process, it is possible to execute the GHDL + simulation within a custom ``main()`` entrypoint (see :ref:`COSIM:VHPIDIRECT:Examples:quickstart:wrapping:basic`). By using + ``main.c`` instead of ``caux.c``, the content of the array is written programatically in C, before calling ``ghdl_main``. + Note that the content of the array is read from C both before and after executing the simulation. + +.. NOTE:: + The length (or any other argument) can also be set through top level generics and/or as a custom CLI argument. See + :ref:`COSIM:VHPIDIRECT:Examples:quickstart:cli`. + +.. _COSIM:VHPIDIRECT:Examples:arrays:intvector:vhdlsized: + +:cosimtree:`Sized in VHDL ` +================================================================== + +Complementing the examples above, when the size of a bounded/constrained array is defined in VHDL, it is possible to have +the (de)allocation performed in either VHDL or C. However, while accesses to constrained VHDL types do contain metada about +the bounds, pointers in C do not. Hence, in these examples, the length is explicitly passed along with the pointer/access. +Note that other possible implementations would save the length in a variable in C, so that it does not need to be passed +each time. This is done in ``fcn`` :ref:`above `. + +In this example three equivalent architectures are provided. + +* **calloc**: allocation and deallocation is done in C, invoked from VHDL through ``[c_]allocIntArr`` and ``[c_]freePointer``, + respectively. +* **vhdlallocarr**: allocation of an array is done in VHDL. +* **vhdlallocacc**: allocation of an access is done in VHDL. + +Apart from that, all three implementations are functionally equivalent: + +* A constrained array is allocated. +* The content is initialized from C. +* The content is read and modified from VHDL. +* A function in C is used to assert the modifications and to print the results. +* The array is deallocated. + +Note that VHPIDIRECT resources are defined in a package (as shown in :ref:`COSIM:VHPIDIRECT:Examples:quickstart:package`). +The same package and the corresponding C source file (``caux.c``) are used in all three examples; however: + +* ``[c_]allocIntArr`` and ``[c_]freePointer`` are used by ``calloc`` only. +* The C implementation of the functions used in ``vhdlallocarr`` and ``vhdlallocacc`` is the same, even though the definitions + in VHDL are different. This is because both constrained arrays and accesses to constrained arrays are mapped to the same types + in C. See :ref:`Restrictions_on_foreign_declarations`. + +.. _COSIM:VHPIDIRECT:Examples:arrays:logicvectors: + +:cosimtree:`Vector of std_logic ` +**************************************************************** + +Commonly signals in VHDL are of a logic type or a vector thereof (``std_logic`` and ``std_logic_vector``), coming from IEEE's +``std_logic_1164`` package. These types can hold values other than high and low (``1`` and ``0``) and are enumerated as: +``0 = 'U'``, ``1 = 'X'``, ``2 = '0'``, ``3 = '1'``, ``4 = 'Z'``, ``5 = 'W'``, ``6 = 'L'``, ``7 = 'H'`` and ``8 = '-'``. +As mentioned in :ref:`Restrictions_on_foreign_declarations`: + +* Because the number of enumeration values is less than 256, logic values are transported in 8 bit words (a ``char`` type in C). + + * In this example two declarations make handling logic values in C a bit easier: + + * Providing logic values in C as their enumeration numbers is simplified with the use of a matching enumeration, + ``HDL_LOGIC_STATES``. + * Printing out a logic value's associated character is also simplified with the ``const char HDL_LOGIC_CHAR[]`` + declaration. + + * Logic vectors, of a bounded size, can be easily used in C as a ``char[]`` and passed to VHDL. These can be read as either + an ``access`` of a subtype of ``std_logic_vector``, or as the subtype itself. + +This example builds on the integer vector example (:ref:`COSIM:VHPIDIRECT:Examples:arrays:intvector`), by instead passing an +array of logic values. Foreign subprograms are declared that enable receiving the size of two different logic vectors from C. +There is only one subprogram to get the size of both C arrays, and it takes in an argument to determine which array's size gets +returned. + +.. HINT:: + The ``getLogicVecSize`` in VHDL is declared as receiving a ``boolean`` argument. In C the function is declared to receive a + ``char`` argument. The VHDL booleans ``false`` and ``true`` are enumerations, and have integer values, ``0`` and ``1`` + respectively. As with the logic values, the boolean enumerations use fewer than 8 bits, so the single byte in C's ``char`` + variable receives the VHDL enumeration correctly. + +For illustrative purposes, the two vectors are allocated and populated with logic values in different ways: + +* logicVecA is allocated in C, it is returned as an access type through a function, and indices are manually filled with + enumeration values from ``HDL_LOGIC_STATES``: ``vec[0] = HDL_U;``. + +* logicVecB is allocated in VHDL, it is passed as an ``std_logic_vector`` subtype (by reference) through a procedure, and + indices are filled with integer values: ``for(int i = 0; i < SIZE_LOGIC_VEC_B; i++){ vec[i] = 8-i; }``. + +.. ATTENTION:: + The integer values that are given to ``char`` variables in C which are intended to be read as VHDL logic values, must be + limited to [0, 8]. This ensures that they represent one of the 9 enumerated logic values. + +.. _COSIM:VHPIDIRECT:Examples:arrays:matrices: + +:cosimtree:`Matrices ` +************************************************** + +Constrained multidimensional arrays of doubles/reals +==================================================== + +In many signal and image processing applications, large amounts of data need to be transferred between software and +hardware. In software, it is common to use floating-point data types, since most general-purpose processors include +hard floating-point units. Conversely, fixed-point formats are used in hardware, in order to optimise area and power. +Converting data formats and using intermediate files to transfer test data to/from a simulation model can be tedious +and error-prone. + +This example builds on :ref:`intvector `. Precisely, it's an extension of +case :ref:`COSIM:VHPIDIRECT:Examples:arrays:intvector:csized`. A general procedure to share constrained multidimensional +arrays of any size is shown. Dimensions of a 2D matrix of doubles are defined in C and a helper function is used for +VHDL to read those values into the declaration of an *array of reals* type. Then, the pointer to the matrix (in C) is +retrieved as an access (in VHDL), through another helper function. + +For completeness, IEEE's ``fixed_generic_pkg`` package is used to multiply each value with a constant using fixed-point +formats. This is to illustrate that VHDL 2008 can be used as *fixed-point toolbox* in numerical processing environments. + +.. _COSIM:VHPIDIRECT:Examples:arrays:matrices:axis: + +:cosimtree:`Array and AXI4 Stream Verification Components ` +====================================================================================================== + +.. HINT:: + This example is based on `VUnit `_, an open source unit testing framework for VHDL/SystemVerilog. + Instead of a shell script, the main entrypoint to this example is a ``run.py`` Python script. Users who are not familiar + with VUnit are encouraged to first read :ref:`vunit:user_guide` and get familiar with VUnit example `array_axis_vcs `_. + +.. figure:: img/matrices_array_axis_vcs.png + :alt: VUnit example `array_axis_vcs `_ + :align: center + :width: 500px + + Block diagram of VUnit example ``array_axis_vcs``. + +`VUnit `_ provides an :ref:`integer_array ` package with ``load_csv`` +and ``save_csv`` functions. Those are used in `Array and AXI4 Stream Verification Components `_, +along with AXI4 Stream components from the :ref:`vunit:vc_library`, to load data from CSV files to a UUT. While CSVs as +intermediate files are useful for integration with Matlab, Octave, NumPy, etc., not having an equivalent `real_array` +package posses an additional complexity in applications such as DSP or machine learning. This is because values to be +handled in fixed-point need to be first converted from doubles to integers. + +.. figure:: img/matrices_vunit_axis_vcs.png + :alt: Modified version of the example, renamed to :cosimtree:`vunit_axis_vcs ` + :align: center + :width: 500px + + Block diagram of the modified version of the VUnit example, renamed to :cosimtree:`vunit_axis_vcs `. + +Subdir :cosimtree:`vunit_axis_vcs ` of this example contains a modified +version of a VUnit example (`array_axis_vcs `_), where ``integer_array`` +and CSV files are replaced with VHPIDIRECT functions, so that data is read from C directly. In fact, no additional +co-simulation sources are included in the subdir because the ``main.c`` and ``pkg.vhd`` from the parent dir are used. +These will share the matrix as in the parent example, which is then passed to/from the verification components to test +the AXI Stream master/slave setup. The top-level processes ``stimuli`` and ``receive`` are the master sending and the +slave receiving, respectively, data from/to the matrix variable. For completeness only, ``stimuli`` verifies the contents +of the matrix before sending it, row by row. + +This example illustrates how to separate sources for synthesis from testbench/simulation resources, enhanced with GHDL's +co-simulation features and with VUnit's verification components. At the same time, this is a showcase of how to combine +a VUnit ``run.py`` script (for building and test management) along with custom VHPIDIRECT resources. + +.. HINT:: + Combining VUnit's verification components with VHPIDIRECT allows to build simulation models for VHDL designs + with complex top-level interfaces, while providing a C API to interact with them. Find work in progress in this regard + at `VUnit/cosim `_. + +.. _COSIM:VHPIDIRECT:Examples:arrays:matrices:vga: + +:cosimtree:`VGA (RGB image buffer) ` +============================================================================ + +.. ATTENTION:: + These examples require `ImageMagick `_ and/or `Xlib `_. + +In image generation and processing applications, it can be tedious to debug the designs by looking at waveforms or +logs. Saving data from RAMs and/or typical graphics standards to images or video allows to spot visual artifacts easily. + +This example is based on :ref:`COSIM:VHPIDIRECT:Examples:arrays:intvector:vhdlsized` from :ref:`intvector `. +A 2D array of integers is allocated in a (generic) VHDL package and it is used as a frame buffer. Each integer represents a +pixel: the 24 least significant bits are used for R, G and B (8 bits each); while the 8 most significant are not used. +See `Wikipedia: Color_depth#True_color_(24-bit) `_. + +In the same package, foreign function ``save_screenshot`` is defined. It accepts a pointer to an array of integers, along +with integers defining the width and the height, and an integer used as an identifier of the frame number. Hence, unlike +previous examples with matrices, in this example calls to the VHPIDIRECT function are atomic and do not depend on passing +any parameter beforehand. + +In practice, this example provides the foundation to build *virtual screens* for simulation purposes. Two different +implementations are shown: + +* With :cosimtree:`caux.c `, the content of the frame buffer is saved to a binary + file in RGB24 format. Then, ``convert`` from `ImageMagick `_ is used to convert it to PNG. + When the simulation ends, ``convert`` is used again, to merge all the PNGs into an animated GIF. + +* With :cosimtree:`caux_x11.c `, X11 libraries are used to generate a + window on the desktop. Then, when ``save_screenshot`` is called, the canvas is updated with the content of the frame buffer. + +.. HINT:: + The resolution of the screen (frame buffer) is defined in :cosimtree:`pkg.vhd `, + which is a generic package. Corresponding generics are defined in the top-level entity (testbench). Hence, it is possible to + modify the size of the screen through CLI args. + At the same time, the size of the canvas (X11 window) is defined in the testbench and passed to C as arguments of ``sim_init`` + (see :cosimtree:`caux.c `). By default, the size of the window matches the + size of the screen (frame buffer). However, this is not a requirement. + +Moreover, two different architectures are provided for the testbench (:cosimtree:`tb.vhd `): + +* In architecture ``test``, 16 frames/images are generated. The content of the buffer is set through literal assignments + such as ``screen(j,i) := 16#FFFF00#;``. The generated pattern is a yellow background and an animated cyan box (it is moved to the + right and to the bottom as frames advance). + +* In architecture ``bars``, a single frame/image is generated. The content of the buffer is set through an ``std_logic_vector(2 downto 0)`` + (RGB) signal. A helper function (``RGB_to_integer``, provided in the package) is used to convert the 3 bit signal into + RGB24. The generated static pattern is eight equally spaced vertical bars, each correponding to a value of the 3 bit + signal; from left to right: black, red, green, yellow, blue, magenta, cyan and white. + +.. TIP:: + In `dbhi/vboard: VGA test pattern `_ a *virtual VGA screen* is implemented based + on this shared frame buffer example. A test core is provided, which captures the VSYNC, HSYNC and RGB signals of a UUT, and writes + RGB24 integers to the buffer. Then, apart from Imagemagick, `Tkinter `_ + is supported. Tkinter is the Tcl/Tk interface built in Python. Hence, `dbhi/vboard: vga/test/tkinter `_ + shows how to combine this framebuffer example with :ref:`COSIM:VHPIDIRECT:Examples:shared:pycb`. The result is similar to + using ``X11/Xlib.h``, but `NumPy `_ and `Pillow `_ are used, instead of coding in C. diff --git a/_sources/vhpidirect/examples/grt.rst.txt b/_sources/vhpidirect/examples/grt.rst.txt new file mode 100644 index 00000000..f695c59f --- /dev/null +++ b/_sources/vhpidirect/examples/grt.rst.txt @@ -0,0 +1,17 @@ +.. program:: ghdl +.. _COSIM:VHPIDIRECT:Examples:grt: + +GRT +### + +.. _COSIM:VHPIDIRECT:Examples:grt:step: + +:cosimtree:`step ` +*************************************** + +As explained in :ref:`COSIM:VHPIDIRECT:Wrapping:Step`, GHDL allows executing simulations step by step when wrapped in a +foreign language. This is a minimal showcase. + +The testbench in this example is a single process that prints a message 10 times, every ``10 ns``; then it waits indefinitely. +The wrapper uses a ``do {} while`` loop for printing the return code of each step. If/when the return code is ``>2``, the +simulation is either finished or stopped, so the program exits. diff --git a/_sources/vhpidirect/examples/index.rst.txt b/_sources/vhpidirect/examples/index.rst.txt new file mode 100644 index 00000000..cd295f9a --- /dev/null +++ b/_sources/vhpidirect/examples/index.rst.txt @@ -0,0 +1,13 @@ +.. _COSIM:VHPIDIRECT:Examples: + +Examples +######## + +.. toctree:: + + quickstart + grt + shared + arrays + vffi_user + other diff --git a/_sources/vhpidirect/examples/other.rst.txt b/_sources/vhpidirect/examples/other.rst.txt new file mode 100644 index 00000000..f7711fe8 --- /dev/null +++ b/_sources/vhpidirect/examples/other.rst.txt @@ -0,0 +1,52 @@ +.. _COSIM:VHPIDIRECT:Examples:other: + +Other co-simulation projects +############################ + +This section contains references to other co-simulation projects based on GHDL and VHPIDIRECT. + + +ghdlex and netpp +================ + +`netpp (network property protocol) `_ is a communication library allowing to expose +variables or other properties of an application to the network as abstract 'Properties'. Its basic philosophy is that a +device always knows its capabilities. netpp capable devices can be explored by command line, Python scripts or GUI applications. +Properties of a device - be it virtual or real - are typically described by a static description in an XML device description +language, but they can also be constructed on the fly. + +`ghdlex `_ is a set of C extensions to facilitate data exchange between a GHDL simulation +and external applications. VHPIDIRECT mechanisms are used to wrap GHDL data types into structures usable from a C library. +`ghdlex` uses the `netpp `_ library to expose virtual entities (such as pins or RAM) +to the network. It also demonstrates simple data I/O through unix pipes. A few VHDL example entities are provided, such as +a virtual console, FIFOs, RAM. + +The author of `netpp` and `ghdlex` is also working on `MaSoCist `_, a linux'ish build +system for System on Chip designs, based on GHDL. It allows to handle more complex setup, e.g. how a RISC-V architecture +(for example) is regress-tested using a virtual debug interface. + + +VUnit +===== + +`VUnit `_ is an open source unit testing framework for VHDL/SystemVerilog. Sharing memory +buffers between foreign C or Python applications and VHDL testbenches is supported through GHDL's VHPIDIRECT features. +Buffers are accessed from VHDL as either strings, arrays of bytes or arrays of 32 bit integers. See +`VUnit/cosim `_ for details about the API. + + +ygdes.com +========= + +Yann Guidon is a many-hack who tried to push GHDL's VHPIDIRECT over the edge in a series of articles around 2010 (as +you can read this, GHDL recovered very well since). + +GHDL is an essential tool to design Free HW designs and Yann is still trying to hack it beyond its intended scope, to +fill voids in the Free Software landscape that keep him from designing more microprocessor cores. +He is mostly active on Hackaday.io (`hackaday.io/whygee `_) and working on converging +projects such as: + +* The YGREC8 microcontroller core: `ygrec8.com `_. +* An embedded webserver for co-simulations: `micro HTTP server in C `_. +* A VHDL library of gates that doubles as other verification tool (including hopefully an Automatic Test Pattern Generator): + `VHDL library for gate-level verification `_. diff --git a/_sources/vhpidirect/examples/quickstart.rst.txt b/_sources/vhpidirect/examples/quickstart.rst.txt new file mode 100644 index 00000000..90eb3715 --- /dev/null +++ b/_sources/vhpidirect/examples/quickstart.rst.txt @@ -0,0 +1,257 @@ +.. program:: ghdl +.. _COSIM:VHPIDIRECT:Examples:quickstart: + +Quick Start +########### + +.. _COSIM:VHPIDIRECT:Examples:quickstart:random: + +:cosimtree:`'rand' from stdlib ` +************************************************************** + +By default, GHDL includes the standard C library in the generated simulation models. Hence, resources from ``stdlib`` +can be used without any modification to the build procedure. + +This example shows how to import and use ``rand`` to generate and print 10 integer numbers. The VHDL code is equivalent +to the following C snippet. However, note that this C source is NOT required, because ``stdlib`` is already built in. + +.. code-block:: C + + #include + #include + + int main (void) { + int i; + for (i = 0; i < 10; i++) + printf ("%d\n", rand ()); + return 0; + } + +.. _COSIM:VHPIDIRECT:Examples:quickstart:math: + +:cosimtree:`'sin' from libmath ` +************************************************************ + +By the same token, it is possible to include functions from system library by just providing the corresponding linker +flag. + +In this example, function ``sin`` from the ``math`` library is used to compute 10 values. As in the previous example, +no additional C sources are required, because the ``math`` library is already compiled and installed in the system. + +.. _COSIM:VHPIDIRECT:Examples:quickstart:customc: + +:cosimtree:`custom C ` +***************************************************** + +When the required functionality is not available in pre-built libraries, custom C sources and/or objects can be added +to the elaboration and/or linking. + +This example shows how to bind custom C functions in VHDL as either procedures or functions. Four cases are included: +``custom_procedure``, ``custom_procedure_withargs``, ``custom_function`` and ``custom_function_withargs``. In all +cases, the parameters are defined as integers, in order to keep it simple. See :ref:`COSIM:VHPIDIRECT:Declarations` +for further details. + +Since either C sources or pre-compiled ``.o`` objects can be added, in C/C++ projects of moderate complexity, it might +be desirable to merge all the C sources in a single object before elaborating the design. + +.. _COSIM:VHPIDIRECT:Examples:wrapping: + +Wrapping ghdl_main +****************** + +.. _COSIM:VHPIDIRECT:Examples:quickstart:wrapping:basic: + +:cosimtree:`basic ` +--------------------------------------------------------- + +Instead of using GHDL's own entrypoint to the execution, it is possible to wrap it by providing a custom program +entrypoint (``main`` function), wherein the execution of the simulation is triggered by calling ``ghdl_main``. + +This example shows the most basic of such usage. ``ghdl_main`` is declared as ``extern`` in C, and arguments ``argc`` +and ``argv`` are passed without modification. However, this sets the ground for custom prepocessing and postprocessing +in a foreign language. + +Other options are to just pass empty arguments (``ghdl_main(0, NULL)``) or to customize them: + +.. code-block:: C + + char* args[] = {NULL, "--wave=wave.ghw"}; + ghdl_main(2, args); + +See :ref:`COSIM:VHPIDIRECT:Wrapping` for further details about the constraints of ``argv``. Furthermore, section +:ref:`COSIM:VHPIDIRECT:Examples:quickstart:cli` below shows argument parsing/manipulation strategies. + +:cosimtree:`time ` +------------------------------------------------------- + +Although most of the provided examples are written in C, VHPIDIRECT can be used with any language that supports a +C-like compile and link model. + +This example shows how to time the execution of a simulation from either C or Ada. In both cases, function ``clock`` is +used to get the time before and after calling ``ghdl_main``. Regarding the build procedure, it is to be noted that C +sources are elaborated with :option:`-e`, because GHDL allows passing parameters (in this case, additional C sources) +to the compiler and/or linker. However, since it is not possible to do so with Ada, ``gnatmake``, :option:`--bind` and +:option:`--list-link` are used instead. See :ref:`COSIM:VHPIDIRECT:Linking` for further info about custom linking setups. + +.. HINT:: + Compared to the previous example, the declaration of ``ghdl_main`` includes three arguments in this example: + ``int argc, void** argv, void** envp``. This is done for illustration purposes only, as it has no real effect on the + exercise. + +.. _COSIM:VHPIDIRECT:Examples:quickstart:wrapping:exitcb: + +:cosimtree:`exitcb ` +----------------------------------------------------------- + +When wrapped in a foreign language, calls to ``ghdl_main`` should return an exit code and allow the regular execution of the +wrapper, so that users can handle simulation results in there. However, bugs might result in failures that exit immediately +through an abortion signal. This example shows how to register an exit handler and a signal handler, to allow executing +custom code regardless of crashes in the simulation. + +In VHDL 1993, simulation termination statements and exit codes that simulators should produce were undefined. Therefore, it was +common practice to termine the simulations through reports of severity ``failure``. When wrapping GHDL, such strategies +might result in undesired exit procedures. Using VHDL 2008 is suggested. + +.. _COSIM:VHPIDIRECT:Examples:quickstart:linking: + +Linking +******* + +:cosimtree:`bind ` +------------------------------------------------------ + +Although GHDL's elaborate command can compile and link C sources, it is sometimes preferred or required to call a +compiler explicitly with custom arguments. This is useful, e.g., when a simulation is to be embedded in the build of an +existing C/C++ application. + +This example is equivalent to :ref:`COSIM:VHPIDIRECT:Examples:quickstart:wrapping:basic`, but it shows how to use +:option:`--bind` and :option:`--list-link` instead of :option:`-e`. See :ref:`COSIM:VHPIDIRECT:Linking` for further +details. + +.. HINT:: + Objects generated by :option:`--bind` are created in the working directory. See :ref:`gccllvm-only-programs` and + :ghdlsharp:`781`. + + +.. _COSIM:VHPIDIRECT:Examples:quickstart:package: + +:cosimtree:`package ` +**************************************************** + +If the auxillary VHPIDIRECT subprograms need to be accessed in more than one entity, it is possible to package the +subprograms. This also makes it very easy to reuse the VHPIDIRECT declarations in different projects. + +In this example two different entities use a C defined ``c_printInt(val: integer)`` subprogram to print two different +numbers. Subprogram declaration requirements are detailed under the :ref:`COSIM:VHPIDIRECT:Declarations` section. + +.. _COSIM:VHPIDIRECT:Examples:quickstart:sharedvar: + +:cosimtree:`sharedvar ` +******************************************************** + +While sharing variables through packages in VHDL 1993 is flexible, in VHDL 2008 protected types need to be used. +However, GHDL allows to relax some rules of the LRM through :option:`-frelaxed`. + +This example showcases multiple ways of sharing variables through packages, depending on the target version of the +standard. Three different binaries are built from the same entity, using: + +* A VHDL 1993 package with ``--std=93``. +* A VHDL 1993 package with ``--std=08 -frelaxed``. +* A VHDL 2008 package with ``--std=08``. + +.. NOTE:: + Procedure ``setVar`` is not strictly required. It is used to allow the same descriptions of the entity/architectures + to work with both VHDL 1993 and VHDL 2008. See the bodies of the procedure in :cosimtree:`pkg_93.vhd ` and :cosimtree:`pkg_08.vhd `. + +.. _COSIM:VHPIDIRECT:Examples:quickstart:shint: + +:cosimtree:`shint ` +------------------------------------------------------------- + +As an alternative to using a shared variable in VHDL, subdir :cosimtree:`shint ` +contains an approach based on a helper record type which is used as a handle. Mimicking the concept of *methods* from +Object Oriented (OO) programming, helper C functions are used to read/write the actual variables, instead of sharing +data through an access/pointer. This approach is more verbose than others, but it works with either VHDL 1993 or VHDL +2008 without modification and without requiring :option:`-frelaxed`. Moreover, it enhances encapsulation, as it provides +a user-defined API between VHDL and C, which can improve maintainability when sources are reused. As a matter of fact, +this approach is found in verification projects such as `VUnit `_ and `OSVVM `_. + +.. _COSIM:VHPIDIRECT:Examples:quickstart:shrecord: + +:cosimtree:`shrecord ` +---------------------------------------------------------------- + +Records are contiguous collections of types in VHDL, analogous to ``struct`` in C. This subexample quickly showcases: + + - sharing a C declared struct between VHDL entities + - sharing a VHDL declared record with C functions + +This example only uses two subprograms, and does not have a globally shared variable like the other *sharedvar* examples. +This is in order to keep the package compatible with both VHDL 93 and 08, and keep the focus on sharing a record variable. + +.. NOTE:: + The records/structs have a field of type `std_logic_vector`/`char[]`, which is a variable that is more complicated than + the integer's in previous examples. The :ref:`COSIM:VHPIDIRECT:Examples:arrays:logicvectors` example fully explains this + variable. + +As mentioned in :ref:`Restrictions_on_foreign_declarations`, both records and accesses to records are passed by reference. +This means that the functions in C receive and return ``struct *``, regardless of the VHDL type being an access. + +.. _COSIM:VHPIDIRECT:Examples:quickstart:cli: + +:cosimtree:`Command-Line Arguments ` +*************************************************************** + +Top-level generics +------------------ + +As explained in :ref:`simulation_options`, there is no standard method in VHDL to obtain command-line arguments. However, +GHDL allows to override top-level generics, with certain restrictions. See :option:`-gGENERIC` and :ghdlsharp:`1388` for +further details. + +In this example, two top-level generics of types ``string`` and ``integer`` are used. First, default values are +used. Then, both are overriden through CLI arguments. Note that top-level generics cannot be undefined; hence, the user must +provide either default values or CLI arguments. + +Parsing/customizing ``argv`` +---------------------------- + +By the same token, when wrapping a simulation, ``ghdl_main`` receives ``argc``, ``argv`` and ``env`` as any regular +``main`` function in C. Hence, when GHDL is wrapped as explained in :ref:`Starting_a_simulation_from_a_foreign_program`, +it is possible to either pass raw arguments or to process them before calling ``ghdl_main``. As a result, overrides for +top-level generics can be defined in C sources. Otherwise, GHDL will complain by producing an error. + +These examples showcase multiple approaches to manipulate top-level generics when GHDL is wrapped: + +* :cosimtree:`rawargs `: pass arguments without modification. This, which is equivalent + to :ref:`COSIM:VHPIDIRECT:Examples:quickstart:wrapping:basic` above, is the minimal requirement for default CLI features + to be available when wrapping GHDL. +* :cosimtree:`procargs `: pass arguments and set/add some. First, no argument is + provided and ``genStr`` is assigned a value in C. Then, ``genInt`` is provided and ``genStr`` is added in C. + + .. NOTE:: + This is a naive approach without any specific library. `getopt `_ + and/or `Argp `_ are popular ways to parse arguments + in C. A complete example that uses *getopt* or *Argp* would be very welcome, since it would allow non trivial arguments + (``[c options] -- [ghdl options]`` or ``[ghdl options] -- [c options]``). Feel free to `open a PR `_! + +* :cosimtree:`fcnargs `: pass arguments without modification, but use a function call + to set the default of top-level generics. That is, when no arguments are provided, the value defined in C is used. However, + when ``-ggenInt=`` is provided, it overrides the value of the top-level generic. + +:cosimtree:`Setting parameters in C through VHDL generics ` +--------------------------------------------------------------------------------------------- + +This example is the opposite of ``fcnargs``. A VHDL generic is passed to C when calling an external subprogram. Although +this might feel as a rare use case, it is common when adapting designs that are not aware of VHPIDIRECT features, to +enhance them with external snippets/libraries in a testbench. + +JSON-for-VHDL +------------- + +`JSON-for-VHDL `_ is a synthesizable VHDL library that allows to provide +configuration parameters through either a JSON file or an stringified (and optionally base16 encoded) top-level generic. +Together with `jq `_ or the libraries available for almost any language, it is a very +powerful resource to pass large amounts of params with minimal maintenance effort. + +Examples are available at `Paebbels/JSON-for-VHDL:tests `_. diff --git a/_sources/vhpidirect/examples/shared.rst.txt b/_sources/vhpidirect/examples/shared.rst.txt new file mode 100644 index 00000000..61d0b694 --- /dev/null +++ b/_sources/vhpidirect/examples/shared.rst.txt @@ -0,0 +1,144 @@ +.. program:: ghdl +.. _COSIM:VHPIDIRECT:Examples:shared: + +Shared libs and dynamic loading +############################### + +.. IMPORTANT:: + As explained in :ref:`COSIM:VHPIDIRECT:Dynamic:loading_a_simulation`, in order to load binaries/libraries dynamically, + those need to be built as position independent code/executables (PIC/PIE). + +This set of examples is an introduction from scratch for users who are familiar with C, but who have never built or loaded +shared libraries (``*.so``, ``*.dll`` or ``*.dyn``): + +* :ref:`COSIM:VHPIDIRECT:Examples:shared:shlib`: write C code and compile it as a shared library. +* :ref:`COSIM:VHPIDIRECT:Examples:shared:dlopen`: write two shared libraries in C, and write a main C program for loading and executing both of them. +* :ref:`COSIM:VHPIDIRECT:Examples:shared:shghdl`: build a simulation as a shared library, and write a main C program for loading and executing it. +* :ref:`COSIM:VHPIDIRECT:Examples:shared:py`: build a simulation as a shared library, and write a Python script for loading and executing it. +* :ref:`COSIM:VHPIDIRECT:Examples:shared:pycb`: build a simulation as a shared library, and write a Python script for loading it and replacing callbacks + through ``ctypes`` before executing the simulation. + +.. _COSIM:VHPIDIRECT:Examples:shared:shlib: + +:cosimtree:`shlib ` +******************************************** + +This example features the same functionality as :ref:`COSIM:VHPIDIRECT:Examples:quickstart:random`. However, custom C +sources are used (as in :ref:`COSIM:VHPIDIRECT:Examples:quickstart:customc`) and these are built as a shared library. +See :ref:`COSIM:VHPIDIRECT:Dynamic:loading_within_a_simulation` for further info. + +.. _COSIM:VHPIDIRECT:Examples:shared:dlopen: + +:cosimtree:`dlopen ` +********************************************** + +Although this example does not include a simulation built with GHDL, it is a test and the introduction to the next +example. In this test, two separate shared libraries are built from C sources, both including a function named +``ghdl_main``. Then, in a main C application, both shared libraries are dynamically loaded at the same time, and both +are executed (one after the other). + +This example tests whether symbol ``ghdl_main`` is visible in the shared libraries, and whether the same symbol name +can be loaded from multiple shared libraries (and used) at the same time. + +.. TIP:: + If the symbol is not found, try adding `-g`, `-rdynamic` and/or `-O0` when building the shared libraries. Tools such + as ``objdump``, ``readelf`` or ``nm`` can be used to check if a symbol is visible. For instance, ``objdump -d corea.so | grep ghdl_main``. + +.. HINT:: + Building multiple designs as separate artifacts and dynamically loading them at the same time is a naive approach to + multi-core simulation with GHDL. It is also a possible solution for coarse grained co-simulation with Verilator. + +.. _COSIM:VHPIDIRECT:Examples:shared:shghdl: + +:cosimtree:`shghdl ` +********************************************** + +This example is complementary to :ref:`COSIM:VHPIDIRECT:Examples:shared:shlib`, since the VHDL simulation is built as a +shared library, which is then loaded from a main C application (as in :ref:`COSIM:VHPIDIRECT:Examples:shared:dlopen`). + +When ``main`` is executed: + +* The shared libray is loaded, symbol ``print_something`` is searched for, and it is executed. +* Symbol ``ghdl_main`` is searched for, and it is executed three times. Unfortunately, GHDL does not currently support + reseting/restarting the simulation runtime. Hence, in this example the shared library is unloaded and loaded again + before calling ``ghdl_main`` after the first time. + +See :ref:`COSIM:VHPIDIRECT:Dynamic:generating_shared_libraries` for further details with regard to the visibility of +symbols in the shared libraries. + +.. NOTE:: + On GNU/linux, both executable binaries and shared libraries use the ELF format. As a result, although hackish, it is + possible to load an executable binary dynamically, i.e. without using any of the ``shared`` options explained in + :ref:`COSIM:VHPIDIRECT:Dynamic:generating_shared_libraries`. In this example, this case is also tested. However, this + is not suggested at all, since it won't work on all platforms. + +.. _COSIM:VHPIDIRECT:Examples:shared:py: + +:cosimtree:`py ` +************************************** + +`Python `_'s :py:mod:`ctypes` module is a built-in "*foreign function library for Python*", which +"*provides C compatible data types, and allows calling functions in DLLs or shared libraries*". Thus, it is posible to +reproduce :ref:`COSIM:VHPIDIRECT:Examples:shared:shghdl` by loading and executing the simulation from Python, instead of +C. + +This example uses the testbench and C sources from :ref:`COSIM:VHPIDIRECT:Examples:quickstart:wrapping:exitcb`, but the simulation +is built as a shared library and loaded dynamically from Python. A helper Python module is used for providing OS agnostic +utilities (see :cosimtree:`pyaux.py `). + +.. WARNING:: + On some Linux environments, failing simulations that are dynamically loaded from Python do produce an *Abortion*. This + forces the wrapper/caller to exit inmediately, without running any post-check. See :ghdlsharp:`803` and :cosimsharp:`15` for + further details. + +:cosimtree:`py/vunit ` +================================================== + +This is equivalent to the previous example (:ref:`COSIM:VHPIDIRECT:Examples:shared:py`). Instead of calling GHDL's CLI explicitly, +VUnit's Python aided plumbing is used. This allows including any of VUnit's VHDL features into the simulation models, which +are then to be loaded dynamically from Python. In fact, this is the foundation of `VUnit/cosim `_. + +.. WARNING:: + On some Linux environments, using VHDL 2008 works but VHDL 1993 does not return cleanly in case of failure. An *Abortion* is + produced, which prevents the regular after-simulation execution of VUnit. See :ghdlsharp:`803` and :cosimsharp:`15` for + further details. + +.. _COSIM:VHPIDIRECT:Examples:shared:pycb: + +:cosimtree:`pycb ` +****************************************** + +.. ATTENTION:: + This example is conceptually built on top of :ref:`COSIM:VHPIDIRECT:Examples:shared:shghdl` and :ref:`COSIM:VHPIDIRECT:Examples:shared:py`; + so it is strongly suggested to carefully read those first. Since Pyhon and :py:mod:`ctypes` are used, a good understanding of + the underlaying C syntax and semantics is required. + +The main purpose of this example is to showcase how to execute an arbitrary Python function from a VHDL testbench, by calling +it as a regular VHDL procedure/function and passing (complex) parameters from the VHDL domain. Precisely, function ``plot(x,y)`` +from :mod:`matplotlib.pyplot` is used to draw ``x,y`` graphs from constrained arrays of integers in VHDL. The scheme is as +follows: + +* A **function prototype is defined in C**. This is the definition that will be *common* to C, VHDL and Python. The prototype + in this example is ``(int* x, int* y, int l)``, i.e. two pointers to arrays of integers are passed, and a third argument + tells the length. +* (optional) A default implementation of the function is written in C. This is just a placeholder/canary. +* A **function pointer variable is created**, and it is initialized to the address of the default implementation. +* The **function pointer variable is used** (dereferenced and executed) **either from C, or from VHDL through VHPIDIRECT**. +* **C/VHDL sources are built as a shared library**. +* **From Python**, an alternative implementation of the function is written. **After loading the library, but before executing + the simulation, the function pointer variable is set** to the address of the alternative implementation. + +As a result, at runtime, when VHDL calls the external function, the Python callback is executed. + +.. NOTE:: + For didactic purposes, the run script in this example first uses C and Python only. I.e., arrays are initialized in C and + plotted in Python. Then, in subdir :cosimtree:`pycb `, arrays are initialized in a VHDL + testbench instead. + +.. TIP:: + In `dbhi/vboard: VGA test pattern `_, this example and :ref:`COSIM:VHPIDIRECT:Examples:arrays:matrices:vga` + are combined for providing a *virtual VGA screen* using Python's `NumPy `_, `Pillow `_ + and `Tkinter `_. + Equivalent solutions can be implemented using Python libraries such as `matplotlib `_, + `panda3d `_, `pygame `_, `cocos2dpy `_, `pyglet `_, etc. + Do you want to take up the challenge? `Propose a PR `_! diff --git a/_sources/vhpidirect/examples/vffi_user.rst.txt b/_sources/vhpidirect/examples/vffi_user.rst.txt new file mode 100644 index 00000000..21936e9d --- /dev/null +++ b/_sources/vhpidirect/examples/vffi_user.rst.txt @@ -0,0 +1,301 @@ +.. program:: ghdl +.. _COSIM:VHPIDIRECT:Examples:cinterface: + +FFI/DPI Header +############## + +As explained in :ref:`COSIM:VHPIDIRECT:Declarations`, dealing with some types directly as exported to C can be cumbersome: + +* Some VHDL types are exposed as fat pointers. Hence, dealing with unconstrained arrays and accesses is not straightforward. +* Indexes of arrays with bounds of direction ``downto`` are reversed. +* ``std_logic`` values correspond to an specific enumeration. +* Etc. + +:cosimtree:`vffi_user.h ` and :cosimtree:`vffi_user.vhd ` are utility headers/packages +for easing the usage of those complex types. The examples in this section showcase the usage of those utilities. +These examples are based on the foundations shown in previous examples. Hence, reading those is strongly suggested for understanding +the implementation details. + +.. ATTENTION:: As explained in the :ref:`home page `, GHDL's implementation of VHPIDIRECT is not compliant with the standard, + and the standarization of a FFI/DPI is being discussed in the VASG (see `[LCS-202x] VHDL DPI/FFI based on GHDL’s implementation of VHPIDIRECT `_). + The ``vffi_user.h`` file available in this repo corresponds to the current implementation in GHDL. As the standarization process + goes forward, GHDL is expected to be adapted. Therefore, users should expect probably breaking changes in the header file. + +.. _COSIM:VHPIDIRECT:Examples:vffi_user:demo: + +:cosimtree:`demo ` +********************************************* + +This is a synthetic example that uses all the supported/defined data types and the helper functions in ``vffi_user.h`` for converting +simple values, constrained arrays and multidimensional unconstrained arrays (fat pointers) to sets of C types. Hence, it is a +regression test for the header file. + +.. _COSIM:VHPIDIRECT:Examples:vffi_user:crypto: + +:cosimtree:`crypto ` +************************************************* + +In this example, a data value and key generated in VHDL are used to compute the AES cypher using `OpenSSL `_. +The data, the key and the output are of type ``std_logic_vector(0 to 127)`` and all of them are allocated in VHDL and passed to C +by reference, as shown in ``vhdlallocarr`` from :ref:`COSIM:VHPIDIRECT:Examples:arrays:intvector:vhdlsized`. + +.. HINT:: + This example is a reduced version of the testing infrastructure of `tmeissner/cryptocores `_. + In that repository both encryption and decryption features of an AES IP core written in VHDL are tested using VHPIDIRECT and OpenSSL. + See `tmeissner/cryptocores: aes/sim/vhdl `_. + +As explained in :ref:`Restrictions_on_foreign_declarations` and shown in :ref:`COSIM:VHPIDIRECT:Examples:arrays:logicvectors`, VHDL +variables of types ``std_logic``or ``std_logic_vector`` are not very usable in C being arrays of ``char``. That's specially so because +the default encoding of ``HDL_0`` and ``HDL_1`` is ``2`` and ``3``, respectively. Hence, it is almost a requirement to convert them +into a format that is suitable for the target C function. + +In C, the function provided by OpenSSL expects data as arrays of bits. Hence, variables need to be converted for the memory layout +of the data to match. This can be done in C only, and/or in VHDL too. Apart from the encryption function (:cosimtree:`encrypt.c `), +an intermediate function (``cryptData``) is used (:cosimtree:`caux.c `). The intermediate +function uses enums and two helper functions (``vfficharArr2bitArr`` and ``vffibitArr2charArr``) defined in :cosimtree:`vffi_user.h `. +Furthermore, a ``reverseBitsInBytes`` function written in VHDL is used for reordering (see :cosimtree:`vffi_user-body.vhd `). + +.. TIP:: This example is based on VHDL and C. However, as show in :ref:`COSIM:VHPIDIRECT:Examples:shared:pycb`, using Python modules/functions + from VHDL is also possible. Projects such as `pyca/cryptography `_ provide equivalent features + to OpenSSL. Are you up to writting a variant of this example using Python? `Propose a PR `_! + +.. _COSIM:VHPIDIRECT:Examples:vffi_user:xyce: + +:cosimtree:`xyce ` +********************************************* + +.. + + "*Xyce is an open source, SPICE-compatible, high-performance analog circuit simulator, capable of solving extremely + large circuit problems by supporting large-scale parallel computing platforms. + It also supports serial execution on all common desktop platforms, and small-scale parallel runs on Unix-like + systems*". + + -- `xyce.sandia.gov `_ + +Xyce provides two mechanisms for external tools/simulation codes to use it: + +**General External Interface (GenExt)** + Comprenhensive interface aimed at developers who wish to couple other external codes written in C++. See AppNote + `Coupled Simulation with the Xyce General External Interface `_. + +**Mixed Signal Interface (MixedSignal)** + Interface to use Xyce as a shared library/object, either from C/C++ codes or through Python's ``ctypes``. Class + `XyceCInterface `_ provides methods to work with a + pointer to the topmost object in a Xyce simulation; and corresponding Python bindings are provided. See AppNote + `Mixed Signal Simulation with Xyce 6.11 `_ + (other versions: `October 2018 `_, `June 2020 `_). + +Regarding integration with GHDL, both interfaces might be suitable for different targets: + +* ``GenExt`` might allow GHDL to provide VHDL-AMS support to Xyce, as the interface allows Xyce to execute callbacks defined in + a foreign tool. However, VHDL-AMS support in GHDL is incomplete. Currently, the parsing stage is implemented only. See + :ghdlsharp:`1052`. +* ``MixedSignal`` provides a higher abstraction level mechanism, which allows for co-execution of otherwise atomic modules. + +In this examples, a simplified C API based on ``MixedSignal`` is used. Moreover, VHDL bindings based on :cosimtree:`vffi_user.h ` +are used for driving the co-simulation from VHDL. The main differences between this simplified API and ``XyceCInterface`` are: + +* ``XyceCInterface`` is designed to use a variable of type ``void**`` as the handler of a simulation object. + Unfortunately, such a type is not cleanly mapped to VHDL. Instead, identifiers of type `string` are used in VHDL, + and this bridge provides a storage mechanism to keep track of the correspondence. +* VHDL's type system, which is based on Ada's, avoids the requirement of using additional function/procedure parameters + for passing array constraints. + +This simplified API is targeted at developers who use VHDL as the main language to orchestrate the co-execution. Hence, +existence of C sources is expected to be transparent. :ref:`xyce_pkg` provides the public VHDL API for end-users. Note that +it is possible to run multiple analog simulations by handling multiple instances of ``xyce_t`` from different VHDL +modules. Find usage details in :ref:`xyce_egs`. + +.. note:: Currently, the C implementation is based on :cosimtree:`vffi_user.h `; hence, it is + specific to GHDL. Nevertheless, it should be possible to adapt it for simulators that support FLI or XSI. Contributions + are welcome! + +.. note:: Although the C implementation is not expected to be used directly, it can be useful to access it when the + simulation executable is to be dynamically loaded. In these contexts, it might be handy to initialize and close the Xyce + simulations from, say, Python, while VHDL is used to run steps and handle I/O. Even though specific examples are not + available yet, this is a supported use case. + +.. note:: The current implementation of the storage mechanism is likely to be replaced as a result of the discussions + in `VUnit/vunit#603 `_. Such a replacement should be transparent to + end-users. However, since this is a very experimental project yet, note that disruptive changes might be required. + +.. _xyce_c: + +Xyce: C interface +================= + +This is a simplified API based on `XyceCInterface `_. It +seems that binding ``void** ptr`` from C to VHDL is not supported. So, unconstrained strings are used instead. Unconstrained +strings can be accesed as ``char** id`` from C. A storage mechanism is used to manage actual pointers associated to each id +(string). + +.. code-block:: c + + uint32_t xhdl_init( + vffiNaturalDimArr_t* ptr, + vffiNaturalDimArr_t* cir + ); + + uint32_t xhdl_run( + vffiNaturalDimArr_t* ptr, + double requestedUntilTime + ); + + uint32_t xhdl_run_1D( + vffiNaturalDimArr_t* ptr, + double requestedUntilTime, + vffiNaturalDimArr_t* tArray, + vffiNaturalDimArr_t* vArray + ); + + uint32_t xhdl_run_2D( + vffiNaturalDimArr_t* ptr, + double requestedUntilTime, + vffiNaturalDimArr_t* array2D + ); + + double xhdl_read( + vffiNaturalDimArr_t* ptr, + vffiNaturalDimArr_t* name + ); + + void xhdl_close( + vffiNaturalDimArr_t* ptr + ); + +.. NOTE:: + Given the similarity between ``void**`` and ``char**`` (pointers), it might be possible to define a custom subtype of any + type and use an access type to it as a placeholder for managing C void pointers in VHDL. To be investigated... + +.. _xyce_vhdl: + +Xyce: VHDL interface +==================== + +.. _xyce_pkg: + +*xyce* package +-------------- + +Provides the user interface to co-execute Xyce simulations from VHDL. It is a protected type, which resembles OOP. + +.. literalinclude:: ../../../vhpidirect/vffi_user/xyce/pkg/xyce_pkg.vhd + :language: vhdl + +.. _xyce_xhdl_pkg: + +*xyce_xhdl* package +------------------- + +Provides bindings between VHDL and a foreign language through VHPIDIRECT. This source needs to be included in the design, but users are not expected to use it explicitly. + +.. literalinclude:: ../../../vhpidirect/vffi_user/xyce/pkg/xyce_xhdl_pkg.vhd + :language: vhdl + +.. _xyce_egs: + +Examples +======== + +Xyce developers provide two versions of the same three examples (`utils/XyceCInterface `_): + +**Python_examples** + Use ``xyce_interface.py`` to manage a Xyce simulation from Python. No HDL is used. + +**VPI_examples** + Use Verilog to trigger the Xyce simulations. However, all the logic is implemented in C. + As explained in Section 7 of `Mixed Signal Simulation with Xyce 6.11 `_: + + "*The primary issue with the VPI capability is the lack of standards compliance. The example (...) uses the C++ + features of the `XyceCInterface` directly. Wrapper functions, that only use ANSI C and the native PLI + data-types in their function calls, still need to beimplemented.*" + +The examples in this repo are an adaptation of the VPI_examples from Xyce's repo. Here, VHDL is used through VHPIDIRECT +bindings, instead of Verilog. The management of the execution flow is handled from VHDL, so that developers don't need to +code in C/C++. Regarding data types, native VHDL types are used. Precisely, unconstrained strings and unconstrained +``real_vector``. + +:cosimtree:`runACircuit ` +---------------------------------------------------------------- + +``runACircuit`` is the most simple use case, where a single VHDL test bench and a single C file are used. It shows how to +call Xyce from VHDL, but no data is passed and neither :ref:`xyce_c` nor :ref:`xyce_vhdl` are used. + +.. NOTE:: Currently, ``XyceCInterface`` requires circuit models to be passed as a path to a file. Providing a pointer to a + string or using ``stdin`` is not supported yet. However, the feature has been requested to developers of Xyce and + it might be available in future versions. + +:cosimtree:`runACircuitInSteps ` +------------------------------------------------------------------------------ + +``runACircuitInSteps`` is based on :ref:`xyce_c` and :ref:`xyce_vhdl`. Precisely, ``xyce_t`` and +from :ref:`xyce_pkg` is used. This allows controlling the execution flow from VHDL, unlike ``runACircuit`` +or the versions in Xyce's repo; where all the relevant logic is implemented in C and HDL is only used as a trigger. + +.. NOTE:: See Section 7.1 of `Mixed Signal Simulation with Xyce 6.11 `_ + for information regarding *known issues with coordinated timestepping*. + +:cosimtree:`runWithDACs ` +---------------------------------------------------------------- + +``runWithDACs`` is also based on :ref:`xyce_c` and :ref:`xyce_vhdl`. On top of controlling the execution flow, in this example +DAC/ADC models provided by Xyce are used for passing data between the digital domain and the analog domain. So, the previous +two examples (``runACircuit`` and ``runACircuitInSteps``) are not proper digital/analog co-simulations, because there +is no communication between digital and analog domains. Those examples are provided for illustrative purposes only, as an +introduction to this one. Here, vectors containing voltage and time need to be passed from VHDL to C. Then, an a value from +the analog circuit is read and passed to VHDL. Two equivalent implementations/tests are shown: + +* :cosimtree:`tb_xyce_eg_with_dacs_1D `: two `real_vector` variables are used for passing an array of time values and an array of voltage values as separate arguments. Checking that the length of both arrays match is done explicitly. +* :cosimtree:`tb_xyce_eg_with_dacs_2D `: a single multidimensional array of `real` is used for passing time and voltage values in a single argument. As a result, all the vectors are guaranteed to have the same length. + +The behaviour of both tests is exactly the same. However, the 2D variant makes it easier to extend the example for handling multiple DACs. Overall, both cases are provided for illustrative purposes, as both 1D and 2D unconstrained arrays are fat pointers and helper functions from :cosimtree:`vffi_user.h ` are used. + +.. NOTE:: The YADC and YDAC device models in Xyce, are not realistic device models. Important issues like rise/fall times and + drive/sink currents are not modelled. Hence, they are adequate for artificial transferring signal values between digital + and analog domains, but those models need to be improved. See Section 5 of `Mixed Signal Simulation with Xyce 6.11 `_. + +Usage +----- + +Two `VUnit `_ scripts are provided: :cosimtree:`run_minimal.py ` +builds and executes ``runACircuit``, and :cosimtree:`run.py ` takes care of the others. + +Since Xyce's Mixed Signal Interface is an experimental feature yet, specific versions of the tools are required, and +configuration options need to be correctly chosen for producing shared libraries. In order to make getting a working +environment easier, a :cosimtree:`Dockerfile ` is provided. Moreover, an image is built +periodically and published as `umarcor/cosim:xyce `_. +The image is based on `ghdl/vunit:llvm-master `_ and includes GHDL (``master``), +Python 3, VUnit (``master``) and Xyce. + +.. NOTE:: In these examples, VUnit is used for automatic dependency scanning, incremental builds and unit testing only. + Other features, such as communication libraries and verification components, are not used. + + Moreover, should :cosimtree:`vffi_user.h ` be standardized (see `VHDL DPI/FFI based on GHDL + `_), VUnit would allow testing multiple simulators easily. + +.. NOTE:: As explained in AppNote `Digital/Analog Cosimulation using CocoTB and Xyce `_, + cocotb can be used to co-simulate GHDL and Xyce through VPI, as an alternative to using VHPIDIRECT. Such an approach + might be preferred when Python is to be used as the orchestrator. Moreover, the report introduces an interesting use + case where digital and analog versions of the same module are used. Unfortunately, sources of that example are not + publicly available. + +GUI features +============ + +Neither GHDL nor Xyce provide built-in features for graphical schematic capture or plotting/viewing of simulation +signals. Fortunately, both of them support generating traces that can be visualised with specific free and open source +tools. If GHDL is used for generating waveforms, which might include digitalised analog signals, `GTKWave `_ +can be used. Note that GTKWave provides an *analog* visualization type. Regarding Xyce, see AppNote `Using Open Source Schematic +Capture Tools With Xyce `_ for information about +schematic capture and plotting tools. See also `Reading waveforms from HDL simulators with PulseView `_ +and `Data type exploration and visualization in arithmetic algorithms/circuits `_. + +Analog modelling +================ + +Xyce supports Verilog-A through Automatic Device Model Synthesizer (ADMS), an open-source translator. Xyce/ADMS is a +set of XML templates for use with ADMS, which allows to emit C++ for a device model. See `Xyce/ADMS Users Guide `_. + +Unfortunately, for VHDL-AMS there is neither built-in support nor a similar translation tool (yet). See related +discussion in `ghdl/ghdl#1052 `_. diff --git a/_sources/vhpidirect/grt.rst.txt b/_sources/vhpidirect/grt.rst.txt new file mode 100644 index 00000000..02fcc51e --- /dev/null +++ b/_sources/vhpidirect/grt.rst.txt @@ -0,0 +1,101 @@ +.. program:: ghdl + +.. _COSIM:VHPIDIRECT:GRT: + +Using GRT +######### + +From Ada +======== + +.. WARNING:: + This topic is only for advanced users who know how to use `Ada` + and `GNAT`. This is provided only for reference; we have tested + this once before releasing `GHDL` 0.19, but this is not checked at + each release. + +The simulator kernel of `GHDL` named :dfn:`GRT` is written in +`Ada95` and contains a very light and slightly adapted version +of `VHPI`. Since it is an `Ada` implementation it is +called :dfn:`AVHPI`. Although being tough, you may interface to `AVHPI`. + +For using `AVHPI`, you need the sources of `GHDL` and to recompile +them (at least the `GRT` library). This library is usually compiled with +a `No_Run_Time` pragma, so that the user does not need to install the +`GNAT` runtime library. However, you certainly want to use the usual +runtime library and want to avoid this pragma. For this, reset the +`GRT_PRAGMA_FLAG` variable. + +:: + + $ make GRT_PRAGMA_FLAG= grt-all + + +Since `GRT` is a self-contained library, you don't want +`gnatlink` to fetch individual object files (furthermore this +doesn't always work due to tricks used in `GRT`). For this, +remove all the object files and make the :file:`.ali` files read-only. + +:: + + $ rm *.o + $ chmod -w *.ali + + +You may then install the sources files and the :file:`.ali` files. I have never +tested this step. + +You are now ready to use it. + +Here is an example, :file:`test_grt.adb` which displays the top +level design name. + +.. code-block:: Ada + + with System; use System; + with Grt.Avhpi; use Grt.Avhpi; + with Ada.Text_IO; use Ada.Text_IO; + with Ghdl_Main; + + procedure Test_Grt is + -- VHPI handle. + H : VhpiHandleT; + Status : Integer; + + -- Name. + Name : String (1 .. 64); + Name_Len : Integer; + begin + -- Elaborate and run the design. + Status := Ghdl_Main (0, Null_Address); + + -- Display the status of the simulation. + Put_Line ("Status is " & Integer'Image (Status)); + + -- Get the root instance. + Get_Root_Inst(H); + + -- Disp its name using vhpi API. + Vhpi_Get_Str (VhpiNameP, H, Name, Name_Len); + Put_Line ("Root instance name: " & Name (1 .. Name_Len)); + end Test_Grt; + + +First, analyze and bind your design:: + + $ ghdl -a counter.vhdl + $ ghdl --bind counter + + +Then build the whole:: + + $ gnatmake test_grt -aL`grt_ali_path` -aI`grt_src_path` -largs + `ghdl --list-link counter` + + +Finally, run your design:: + + $ ./test_grt + Status is 0 + Root instance name: counter + diff --git a/_sources/vhpidirect/index.rst.txt b/_sources/vhpidirect/index.rst.txt new file mode 100644 index 00000000..b825e766 --- /dev/null +++ b/_sources/vhpidirect/index.rst.txt @@ -0,0 +1,26 @@ +.. program:: ghdl + +.. _COSIM:VHPIDIRECT:Intro: + +Introduction +============ + +.. ATTENTION:: As explained in the :ref:`home page `, GHDL's implementation of VHPIDIRECT is not compliant with the standard, + and the standarization of a FFI/DPI is being discussed in the VASG. As a result, in this documentation VHPIDIRECT, VFFI, FFI, + VDPI and/or DPI might be used as synonyms for referring to the new standardized interface, which is currently work in progress. + +Interfacing with foreign languages through VHPIDIRECT is possible on any platform. You can reuse or define a subprogram +in a foreign language (such as `C` or `Ada`) and import it into a VHDL design. + +.. NOTE:: + GHDL supports different backends, and not all of them generate binary artifacts. Precisely, ``mcode`` is an in-memory + backend. Hence, the examples need to be built/executed with either LLVM or GCC backends. A few of them, the ones that + do not require linking object files, can be used with mcode. + +.. ATTENTION:: + As a consequence of the runtime copyright, you are not allowed to distribute an + executable produced by GHDL without allowing access to the VHDL sources. See + :ref:`INTRO:Copyrights`. + +.. TIP:: + See :ghdlsharp:`1053` for on-going work with regard to VHPIDIRECT. diff --git a/_sources/vhpidirect/linking.rst.txt b/_sources/vhpidirect/linking.rst.txt new file mode 100644 index 00000000..b2a4588f --- /dev/null +++ b/_sources/vhpidirect/linking.rst.txt @@ -0,0 +1,75 @@ +.. program:: ghdl + +.. _COSIM:VHPIDIRECT:Linking: + +Linking object files +#################### + +.. _Linking_with_foreign_object_files: + +Linking foreign object files to GHDL +==================================== + +You may add additional files or options during the link of `GHDL` using +``-Wl,`` as described in :ref:`passing-options-to-other-programs`. +For example:: + + ghdl -e -Wl,-lm math_tb + +will create the :file:`math_tb` executable with the :file:`lm` (mathematical) +library. + +Note the :file:`c` library is always linked with an executable. + +.. HINT:: + The process for personal code is the same, provided the code is provided as a C source or compiled to an object file. + Analysis must be made of the HDL files, then elaboration with ``-e -Wl,personal.c [options...] primary_unit [secondary_unit]`` as arguments. + Additional C or object files are flagged as separate ``-Wl,*`` arguments. The elaboration step will compile the executable with the custom resources. + Further reading (particularly about the backend particularities) is at :ref:`Elaboration:command` and :ref:`Run:command`. + +.. _Linking_with_Ada: + +Linking GHDL object files to Ada/C +================================== + +As explained previously in :ref:`Starting_a_simulation_from_a_foreign_program`, +you can start a simulation from an `Ada` or `C` program. However the build +process is not trivial: you have to elaborate your program and your +`VHDL` design. + +.. HINT:: + If the foreign language is C, this procedure is equivalent to the one described in + :ref:`Linking_with_foreign_object_files`, which is easier. Thus, this procedure is + explained for didactic purposes. When suitable, we suggest to use :option:`-e`, instead + of :option:`--bind` and :option:`--list-link`. + +First, you have to analyze all your design files. In this example, we +suppose there is only one design file, :file:`design.vhdl`. + +:: + + $ ghdl -a design.vhdl + +Then, bind your design. In this example, we suppose the entity at the +design apex is ``design``. + +:: + + $ ghdl --bind design + +Finally, compile/bind your program and link it with your `VHDL` +design: + +in C: + +:: + + gcc my_prog.c -Wl,`ghdl --list-link design` + +in Ada: + +:: + + $ gnatmake my_prog -largs `ghdl --list-link design` + +See :ref:`gccllvm-only-programs` for further details about :option:`--bind` and :option:`--list-link`. diff --git a/_sources/vhpidirect/notebook/howtouseghdlfromc.rst.txt b/_sources/vhpidirect/notebook/howtouseghdlfromc.rst.txt new file mode 100644 index 00000000..6c9621b1 --- /dev/null +++ b/_sources/vhpidirect/notebook/howtouseghdlfromc.rst.txt @@ -0,0 +1,282 @@ +.. program:: ghdl + +.. _COSIM:VHPIDIRECT:Notebook:HowToUseGHDLFromC: + +How to use GHDL from an external C program? +=========================================== + +.. NOTE:: This content was a dialogue between `@hrvach `_ and `@umarcor `_ + in a question/issue in GHDL's repo, about co-simulation of a Verilog machine around a VHDL CPU: :ghdlsharp:`1512`. + +---- + +@hrvach: + +I would be very grateful for some advice. I'm trying to do a project and the CPU core I need to test against only has a VHDL +implementation. My question is - what is the easiest way for me to include the generated ``.o`` in my own project, and then provide +a set of values to the CPU pins and a single clock pulse, read the output, provide new set of values, repeat etc. + +---- + +@umarcor: + +HDL simulators need to be the root and absolute managers of their own execution. You can instruct them to execute your foreign +software routines at specific instants or under specific circumstances, but you cannot dethrone them. This is because +"standard" co-simulation interfaces define how to import foreign resources only, not how to export HDL subprograms/components. +That is true for VPI, VHPI, DPI, whatever... + +Nevertheless, what you want to achieve is possible for sure, since that is one of the main use cases for co-simulation. +You/we just need to think it upside down. + +Before going into further detail, which of the following alternatives do you prefer? + +- Write a VHDL testbench where VHDL sources are instantiated, and combine that with C and/or Python resources. +- Keep the VHDL sources untouched and write C and/or Python only. + +Both alternatives are functionally equivalent, require a similar level of expertise, and take a similar amount of work/code +length. The answer depends mostly on how comfortable you feel with "writing software in HDL", or whether you identify yourself +as a "mostly software guy who is happier with Python". If you are a C guy, you will lie in-between. In the former, I'll recommend +you to use GHDL's VHPIDIRECT interface, which is what ghdl-cosim repo is mostly about. Otherwise, I'll suggest to use VPI, either +in C or through cocotb. + +---- + +@hrvach: + +My goal is to recreate a very old Unix 68010 based machine in Verilog. I use Verilator, the Verilog -> C++ translation and splice +in a software CPU core in C because that's fast enough for a near realtime simulation. + +However, after getting the basic functionality done, in order to make it work with actual CPU, I need to get the bus timings +correctly (test and verify handling acknowledgments, cpu-space cycles etc) and the only 68010 model I know of is in VHDL. So, +at the moment I have the memory, bus, logic and peripherals in Verilog, testbench in C that actually has UI in SDL and soft CPU +in C I am looking to replace with the compiled VHDL. All of this is to avoid having to to actual FPGA synthesis for every change +because that takes forever. + +I am not that skilled in VHDL, but I could learn how to make a wrapper around the VHDL CPU model if needed. Now that you know +what I'm after, what do you suggest? Once again, thanks for your time and advice! + +---- + +@umarcor: + +For clarification, regarding my previous explanation about HDL simulators needing "*to be the root and absolute managers*", +note that Verilator is precisely a way to work around that: it provides everything except the root of the runtime, which you +are in charge of. The concept of a 'ghdlator'|'vhdlator' has been discussed before, but it's not implemented. + +The quick answer is, you cannot generate ``*.o`` objects from VHDL (components) and have them included in your C root, the same +way you are including you Verilated (C++) modules. You need to forget about that code structure/architecture. I'm not saying +it is not technically possible; it might be, but not with the currently available open source tools. + +Let's leave the VHDL-Verilog co-simulation aside, for now. We'll get back to that later. Let's focus on testing an existing +CPU in VHDL only. As a reference, the CPU will have a single (registered) input port and a single output port, apart from CLK +and RST. + +.. code-block:: vhdl + + entity tb is + end entity; + + architecture test of tb is + + signal clk, rst : std_logic := '0'; + signal iport, oport : std_logic_vector(31 downto 0); + + begin + + clk <= not clk after 10 ns; -- 50 MHz + + process + begin + report "Start simulation"; + rst <= '0'; + wait for 100 ns; + rst <= '1'; + wait for 1 ms; + report "End simulation"; + std.env.stop(0); + wait; + end process; + + process(clk) + begin + if rising_edge(clk) then + + iport <= COSIM_FUNCTION(oport); + + end if; + end process; + + UUT: entity work.CPU + port map ( + CLK => clk, + RST => rst, + IPORT => iport, + OPORT => oport + ); + + end; + +That's a very basic VHDL testbench, where RST is kept high for 100 ns and the simulation lasts 1 ms. In each rising edge of +clk, a function receives ``oport`` (the output of the CPU) and generates ``iport`` (the input of the CPU). + +You might implement that COSIM_FUNCTION as a plain VHDL function that reads a text file (maybe a CSV) or a binary file (see +`Files – theory & examples `_). It would be a two column table. In +each execution after the first one, you compare the ``oport`` with the expected output from the previous cycle, and you load +the new value for ``iport``. + +However, generating text files in a different language and reading them in VHDL is cumbersome. Binary files make it slightly +easier, but it is not comfortable for handling tables/matrices. Instead, we can implement COSIM_FUNCTION in C. That's what +the VHPIDIRECT examples are about. These are the prototypes of the VHDL function and the corresponding C function: + +.. code-block:: vhdl + + function COSIM_FUNCTION ( oport : std_logic_vector(31 downto 0) ) return std_logic_vector(31 downto 0); + +.. code-block:: c + + char* COSIM_FUNCTION (char* oport); + +``std_logic`` are 9-value enumerations (see :ref:`COSIM:VHPIDIRECT:Declarations`). That's why the vectors are ``char*`` in C. +Typically, we will want to manipulate 32 bit vectors as signed/unsigned integers. Let's fix that: + +.. code-block:: vhdl + + process(clk) + begin + if rising_edge(clk) then + iport := std_logic_vector(to_signed( + COSIM_FUNCTION( integer(signed(oport)) ) + , 32)); + end if; + end process; + +.. code-block:: vhdl + + function COSIM_FUNCTION ( oport : integer ) return integer; + +.. code-block:: c + + int32_t COSIM_FUNCTION (int32_t oport); + +Now, we can use C for evaluating each call to ``COSIM_FUNCTION`` by using an integer representing 32 bit input/output ports. +For example, assuming that the CPU adds 10 to the input every clock cycle and provides it through the output: + +.. code-block:: c + + int32_t TABLE[5][2] = { + { 0, 10 }, + { 1, 11 }, + { 2, 12 }, + { 3, 13 }, + { 4, 14 }, + } + + uint8_t id = 0; + + int32_t COSIM_FUNCTION (int32_t oport) { + if ( id == 0 ) { + return TABLE[0][0]; + } + // Avoid crashing if the simulation is 'too long' + if ( id > 4 ) { + return 0; + } + assert( oport == TABLE[id++][0]); + return TABLE[id][1]; + } + +In practice, all the C code is loaded in the same memory space as the simulation. Hence, the global variables in the C sources +retain their values for all the duration. Nevertheless, we might keep track of ``id`` in VHDL instead, and pass it as an +additional argument to ``COSIM_FUNCTION``. That's how "frames" are marked in :ref:`COSIM:VHPIDIRECT:Examples:arrays:matrices:vga` +(see also `VGA test pattern `_). + +If you don't provide your own ``main`` function, GHDL will take care of that. Yet, you can provide it: + +.. code-block:: c + + int32_t TABLE[5][2]; + + uint8_t id; + + int32_t COSIM_FUNCTION (int32_t oport) { + if ( id == 0 ) { + return TABLE[0][0]; + } + // Avoid crashing if the simulation is 'too long' + if ( id > 4 ) { + return 0; + } + assert( oport == TABLE[id++][0]); + return TABLE[id][1]; + } + + int main(int argc, char* argv) { + id = 0; + TABLE = { + { 0, 10 }, + { 1, 11 }, + { 2, 12 }, + { 3, 13 }, + { 4, 14 }, + }; + return ghdl_main(argc, argv); + } + +Writing your custom ``main`` allows dynamically generating test data before starting the simulation, and/or manipulating GHDL's +CLI arguments. This is explained in :ref:`COSIM:VHPIDIRECT:Wrapping` (see examples in :ref:`COSIM:VHPIDIRECT:Examples:wrapping`). + +Effectively, we now have a C interface. Instead of generating an executable binary, we can let GHDL generate a shared library. +That allows loading it in e.g. Python, to have the TABLE generated with, say, some SciPy module. That's what :ref:`COSIM:VHPIDIRECT:Examples:shared` +is about. See also :ghdlsharp:`1398`. Note that you cannot generate a shared lib with a ``main`` function. That's why Python examples +use something else. + +Summarising, we defined a callback using VHDL for describing precisely where in the hierarchy to call it and with which frequency +it needs to be called. We also used VHDL for converting the data types to some which are friendly for binding to C. This meaningful +because VHDL is much better designed for manipulating bits/slices that C. + +At this point, from a higher level perspective, it is easy to understand VPI. With VPI, you don't need to write the VHDL testbench, +and you don't need to define a ``COSIM_FUNCTION`` providing prototypes in VHDL and C. Instead, you can use the UUT as the top level +of the HDL hierarchy, and there is an interface in C that allows you to "register a callback that is executed every X time". That +callback receives the model/hierarchy of the simulation, which you can navigate through the API for reading/writing values. It +might be misleading with VPI that, despite writting the entrypoint and registering everythin in C, the simulator is still the root +of the execution. + +In my opinion, the main limitation of not writing any VHDL testbench is that you are forced to doing all hierarchy navigation and +the type manipulation in C. Moreover, accessing arrays/records through VPI is not supported in GHDL yet (see #1249). However, if +you want to manipulate top-level ports only, it fits the purpose. + +Instead of dealing with VPI in C, you can use cocotb, which is a Python wrapper around VPI. Although not exactly my cup of tea +(I'm a VHDL person), cocotb is the fastest growing verification/testing approach: `GitHub Facts About the HDL Industry: Verification Practices `_. +You might want to have a look at this WIP discussion about combining cocotb and a top-level VHDL testbench: `umarcor/vunit-cocotb `_. + +Therefore, and this is very important, GHDL's VHPIDIRECT and VPI are mostly equivalent. The main difference is the language you +use for writing your test code. In both cases, GHDL is the root and it executes callbacks. Verbosity is different, each has some +specific features which make things easier/harder, etc. so it's not exactly the same, but almost. + +Now, back to your context. You don't want to generate ``iport`` values and/or to assert ``oport`` values in C/Python. You want to +plug the rest of the machine (written in Verilog): + +- Option 1. Take ``COSIM_FUNCTION`` and put all your Verilated models inside. That is, let GHDL be the root, and evaluate the C++ + models with a fixed frequency (in terms of simulation time). See :ghdlsharp:`1335`, where a user reported co-simulating microwatt + (VHDL) and Litedram (Verilog) using this approach. I am not aware of a similar example using VPI, but it should be equivalent. +- Option 2. Forget about this issue. Take VHDL + Verilog sources and synthesise them with ghdl-yosys-plugin + Yosys. + + * Option 2.a. Use Yosys' ``write_verilog`` command for generating post-synthesis Verilog sources. Process those with Verilator. + * Option 2.b. Use CXXRTL, instead of ``write_verilog``. + * In any case, simulate as if VHDL or GHDL did never exist; i.e., be the manager of the simulation as you are used to doing with Verilator. + +Naturally, options 2.a and 2.b have some caveats, such as not being able to simulate non-synthesisable VHDL models (Verilator is +constrained to the synthesisable subset of Verilog anyway), or being lost in the conversion/mangling/flattening/casing. That's +why I explained all the details about VHPIDIRECT, and that's why I think that VHPIDIRECT + Verilator is the way to go. Still, +if you want to treat VHDL sources as a black box with "simple" port types, Yosys might be the best approach. Yosys/CXXRTL is +also useful for comparing pre-synthesis and post-synthesis behaviour, even if you pick VHPIDIRECT/VPI + Verilator for development. + +Closing remarks: + +* I wrote all the code examples above off the top of my head. There might be a lot of typos/bugs. Please, find working examples + in :ref:`COSIM:VHPIDIRECT:Examples` (all of those are tested in CI). +* I did never use CXXRTL, and I just run a couple of examples with cocotb. +* GHDL's implementation of VHPIDIRECT is not compliant with the usage of the term/keyword VHPIDIRECT in the VHDL LRM, where it's + part of VHPI. The concept of how VHPI/VHPIDIRECT work in the LRM is closer to VPI than to a Foreign Function Interface (FFI). + However, what I explained above is essentially a FFI. That's why there is an on-going discussion in the VHDL Analysis and + Standardisation Group (VASG) about including a FFI in the next revision of the standard: `[LCS-202x] VHDL DPI/FFI based on GHDL’s implementation of VHPIDIRECT `_. diff --git a/_sources/vhpidirect/notebook/index.rst.txt b/_sources/vhpidirect/notebook/index.rst.txt new file mode 100644 index 00000000..9c61f681 --- /dev/null +++ b/_sources/vhpidirect/notebook/index.rst.txt @@ -0,0 +1,14 @@ +.. program:: ghdl +.. _COSIM:Notebook: + +Notebook +######## + +While other sections related to VHPIDIRECT are meant for reference or for showcasing specific features, this section +contains articles and discussions to address common questions and mistakes. + +.. toctree:: + + howtouseghdlfromc + memorylayout + mistakes diff --git a/_sources/vhpidirect/notebook/memorylayout.rst.txt b/_sources/vhpidirect/notebook/memorylayout.rst.txt new file mode 100644 index 00000000..797292a3 --- /dev/null +++ b/_sources/vhpidirect/notebook/memorylayout.rst.txt @@ -0,0 +1,12 @@ +.. program:: ghdl + +.. _COSIM:VHPIDIRECT:Notebook:MemoryLayout: + +Memory Layout +============= + +*TBC* + +* ``to`` vs ``downto`` +* Bit ordering within bytes. ``reverseBitsInBytes``, ``vfficharArr2bitArr`` and ``vffibitArr2charArr``. +* Multidimensional arrays. diff --git a/_sources/vhpidirect/notebook/mistakes.rst.txt b/_sources/vhpidirect/notebook/mistakes.rst.txt new file mode 100644 index 00000000..6a50d01e --- /dev/null +++ b/_sources/vhpidirect/notebook/mistakes.rst.txt @@ -0,0 +1,39 @@ +.. program:: ghdl + +.. _COSIM:VHPIDIRECT:Notebook:Mistakes: + +Common mistakes +=============== + +* Although function overloading is supported in VHDL, it is not possible in C. + Hence, it should be avoided to declare multiple procedures/functions which map to the same foreign subprogram. + For the compiler, there is only one definition of the imported function. + So, if different prototypes/profiles are declared, weird things may happen. + See :ghdlsharp:`639`. + +* If a procedure/function is decorated with the ``foreign`` attribute, apart from a matching body in VHDL, the foreign + subprogram **must** be defined (linked) for elaboration to succeed. + This is required even when it is not used in the design. + In context where conditional inclusion of VHPIDIRECT features is required, it is suggested to provide alternative + (dummy) sources for either VHDL packages or C sources (see :ghdlsharp:`793`). + +* There are some corner cases when using large variables/signals. + When you try to allocate a single object which is too large, GHDL will complain. + That can be fixed with :option:`--max-stack-alloc`. + However, when you allocate multiple objects which are smaller than the limit, but the last one overflows, GHDL will + not complain, it will crash instead. + In this case, ``ulimit`` needs to be modified/increased. + To remove the limit, set ``ulimit -s unlimited``. + See :ghdlsharp:`1112`. + + * In Python (say, when using VUnit or cocotb), the stack size can be increased by using the `resource module`_. + For example ``resource.setrlimit(resource.RLIMIT_STACK, (resource.RLIM_INFINITY, resource.RLIM_INFINITY))``. + +.. _resource module: https://docs.python.org/3/library/resource.html#resource.setrlimit + +* The size of objects is supposed to be limited to 4GB. + However, users finding the limit might get different constraints, depending on the backend. See :ghdlsharp:`822`. + +* Waveform buffering can prevent the last cycles being flushed when a foreign subprogram is executed. + Use ``fflush(NULL);`` at the beginning of the foreign subprogram. + See :ghdlsharp:`1855`. diff --git a/_sources/vhpidirect/wrapping.rst.txt b/_sources/vhpidirect/wrapping.rst.txt new file mode 100644 index 00000000..a94d4d15 --- /dev/null +++ b/_sources/vhpidirect/wrapping.rst.txt @@ -0,0 +1,82 @@ +.. program:: ghdl + +.. _COSIM:VHPIDIRECT:Wrapping: + +.. _Starting_a_simulation_from_a_foreign_program: + +Wrapping a simulation +##################### + +By default, GHDL generates an internal ``main`` function, which is the entrypoint to executable binaries/simulations. However, +simulation can be optionally executed from external programs, by declaring given functions as externally defined resources. Should +an alternative ``main`` function be defined, that will be used by the executable, instead of the one from GHDL. + +Wrapping the simulation allows dynamically generating test data, and/or manipulating CLI arguments. + +.. ATTENTION:: + Shared libraries should not contain a ``main`` symbol, but explicitly named entrypoints. When :ref:`COSIM:VHPIDIRECT:Dynamic:generating_shared_libraries` + or :ref:`COSIM:VHPIDIRECT:Dynamic:loading_a_simulation`, wrapping ``ghdl_main`` is required. + +Single function exection (ghdl_main) +==================================== + +Function ``ghdl_main`` allows executing the simulation until termination. When called, GRT takes control and drives the simulation, +without intervention from the wrapper. However, if VHPIDIRECT or VPI functions/callbacks were registered, those are triggered +at the corresponding simulation time. + +In your foreign sources, define the external prototype of ``ghdl_main`` as follows: + +in C: + +.. code-block:: C + + extern int ghdl_main (int argc, char **argv); + +in Ada: + +.. code-block:: Ada + + with System; + ... + function Ghdl_Main (Argc : Integer; Argv : System.Address) + return Integer; + pragma import (C, Ghdl_Main, "ghdl_main"); + +.. TIP:: + Don't forget to list the object file(s) of this entry point and other foreign sources, as per + :ref:`Linking_with_foreign_object_files`. + +.. ATTENTION:: + The ``ghdl_main`` function must be called once, since reseting/restarting the simulation runtime is not supported yet. A + workaround is to build the simulation as a shared object and load the ``ghdl_main`` symbol from it (see :ref:`COSIM:VHPIDIRECT:Examples:shared:shghdl`). + +.. HINT:: + Immitating the run time flags, such as ``-gDEPTH=12`` from :option:`-gGENERIC`, requires the ``argv`` to have the + executable's path at index 0, effectively shifting all other indicies along by 1. This can be taken from the 0 index of the + ``argv`` passed to ``main()``, or (not suggested, despite a lack of consequences) left empty/null. + + Since ``ghdl_main`` is the entrypoint to the design (the simulation kernel/runtime named GRT), the supported CLI options + are the ones shown in :ref:`USING:Simulation`. Options for analysis/elaboration are not required and will NOT work. See :option:`-r`. + +.. _COSIM:VHPIDIRECT:Wrapping:Step: + +Step by step execution +====================== + +For finer grained control of the simulation steps, a set of lower level functions can be used instead of ``ghdl_main``. +Those are provided in :cosimtree:`grt.h `. After initializing GRT, providing arguments and initializing +the simulation, a loop allows checking the return value of each step: + +.. code-block:: C + + // 0: delta cycle + // 1: non-delta cycle + // 2: stop + // 3: finished + // 4: stop-time reached + // 5: stop-delta reached + int ecode; + do { + ecode = __ghdl_simulation_step (); + printf("ecode: %d\n", ecode); + } while (ecode<3); diff --git a/_sources/vpi/examples/index.rst.txt b/_sources/vpi/examples/index.rst.txt new file mode 100644 index 00000000..90e20203 --- /dev/null +++ b/_sources/vpi/examples/index.rst.txt @@ -0,0 +1,21 @@ +.. program:: ghdl +.. _COSIM:VPI:Examples: + +Examples +######## + +A very brief description of how to use VPI is that ``vpi_user.h`` provides dozens of functions to scan/navigate the hierarchy +of the elaborated hardware design, and it allows setting callbacks for specific events/signals. + +.. NOTE:: + Since VHDL sources are agnostic to the usage of VPI modules, most of the examples in this section reuse the same VHDL + sources. Readers should focus on the differences between the provided C files. + +.. ATTENTION:: + On Windows, the directory containing ``libghdlvpi.dll`` needs to be added to the ``PATH``. This can be achieved with + :option:`--vpi-library-dir`, :option:`--vpi-library-dir-unix` or ``$(cd $(dirname $(which ghdl))/../lib; pwd)``. + +.. toctree:: + + quickstart + other diff --git a/_sources/vpi/examples/other.rst.txt b/_sources/vpi/examples/other.rst.txt new file mode 100644 index 00000000..4e3dd5bb --- /dev/null +++ b/_sources/vpi/examples/other.rst.txt @@ -0,0 +1,45 @@ +.. _COSIM:VPI:Examples:other: + +Other co-simulation projects +############################ + +This section contains references to other co-simulation projects based on GHDL and VPI. + +cocotb +====== + +`cocotb `__ is a coroutine based cosimulation library for writing VHDL and Verilog +testbenches in Python. It provides a shared library for binding the VPI interface to Python scripts. As a result, from +Python, users can read/set top-level ports or signals in the testbench, without modifying HDL sources at all. Cocotb +supports other open source simulators (Icarus Verilog or Verilator) and it can also interact with commercial tools through +VHPI. + +GHDL VPI virtual board +====================== + +`GHDL VPI virtual board `__ is a VPI application that +virtualizes the IOs of a Digilent Nexys-4 like board. It provides a testbench and a matching GUI for users/students to test +their designs as if they had a physical board, instead of examining waveforms. Yet, waves are dumped and can be inspected in +GTKWave, as in a traditional workflow. Available peripherals are 7 segment displays, buttons, switches and LEDs. + +.. image:: https://gitlab.ensta-bretagne.fr/bollenth/ghdl-vpi-virtual-board/-/raw/master/images/screenshot_main_window.png + :align: center + :target: https://gitlab.ensta-bretagne.fr/bollenth/ghdl-vpi-virtual-board + +|br| + +GHDL-Cocotb GUI Simulation +========================== + +`blog.chuckstechtalk.com: An Interactive VHDL Testbench Using GHDL, Python, and Cocotb `__ +is a VPI application that demonstrates how to create a Python-based interactive GUI simulation using ghdl, cocotb, and +pygame. +It provides a testbench and a matching GUI with I/O peripherals for testing a design, instead of examining waveforms. +While similar to the `GHDL VPI virtual board `__ +example, using `cocotb `__ and `pygame `__ makes interactive +GUI creation more dynamic than using a compiled language (such as C++). + +.. image:: https://github.com/chuckb/ghdl-interactive-sim/raw/8a466215dd18c6c809dd96f8d03fa53cad8417c2/test/images/screen_shot.png + :align: center + :height: 400px + :target: https://github.com/chuckb/ghdl-interactive-sim diff --git a/_sources/vpi/examples/quickstart.rst.txt b/_sources/vpi/examples/quickstart.rst.txt new file mode 100644 index 00000000..bce914eb --- /dev/null +++ b/_sources/vpi/examples/quickstart.rst.txt @@ -0,0 +1,17 @@ +.. program:: ghdl +.. _COSIM:VPI:Examples:quickstart: + +Quick Start +########### + +.. _COSIM:VPI:Examples:quickstart:hello: + +:cosimtree:`hello ` +*********************************************** + +This is the most minimal example, where a single callback is registered at the beginning of the simulation. The callback just +prints ``Hello!``. Then, the simulation is executed as usual. + +VPI allows registering callbacks at multiple events and to optionally delay their execution after the event is triggered. +The list of available callback reasons is defined in :ghdlsrc:`vpi_user.h `. The structure type that is used +and required to register a callback, ``s_cb_data``, is also defined in the same header file. diff --git a/_sources/vpi/index.rst.txt b/_sources/vpi/index.rst.txt new file mode 100644 index 00000000..3a7e337d --- /dev/null +++ b/_sources/vpi/index.rst.txt @@ -0,0 +1,19 @@ +.. program:: ghdl +.. _COSIM:VPI:Intro: + +Introduction +============ + +Verilog Procedural Interface (VPI) is part of the IEEE Std 1364: `1364-2005 - IEEE Standard for Verilog Hardware Description Language `_. +It allows Verilog code to invoke C functions, and C functions to invoke Verilog system tasks. VPI is sometimes referred to +as PLI 2, because it replaced the deprecated Program Language Interface (PLI). + +VPI provides advanced features, at the cost of having to learn the API. Since this is the user and reference manual for GHDL, +an introduction to VPI is not included. Thus, the reader should have at least a basic knowledge of the interface. A good knowledge of the reference manual. + +Unlike VHPIDIRECT, which allows and requires the user to define a custom API between VHDL and C, VPI is itself a pre-defined +API. Hence, all VPI modules need to include a standard header file, ``vpi_user.h``. At the same time, VPI modules need to be +built as shared libraries, and they are dynamically loaded at runtime. This is similar to example :ref:`COSIM:VHPIDIRECT:Examples:shared:shlib`. +However, when using VPI, VHDL sources are agnostic to the existence of C sources. + +Information about GHDL's commands related to VPI is available at :ref:`VPI_build_commands` and :option:`--vpi`. diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 00000000..30fee9d0 --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/debug.css b/_static/debug.css new file mode 100644 index 00000000..74d4aec3 --- /dev/null +++ b/_static/debug.css @@ -0,0 +1,69 @@ +/* + This CSS file should be overridden by the theme authors. It's + meant for debugging and developing the skeleton that this theme provides. +*/ +body { + font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, + "Apple Color Emoji", "Segoe UI Emoji"; + background: lavender; +} +.sb-announcement { + background: rgb(131, 131, 131); +} +.sb-announcement__inner { + background: black; + color: white; +} +.sb-header { + background: lightskyblue; +} +.sb-header__inner { + background: royalblue; + color: white; +} +.sb-header-secondary { + background: lightcyan; +} +.sb-header-secondary__inner { + background: cornflowerblue; + color: white; +} +.sb-sidebar-primary { + background: lightgreen; +} +.sb-main { + background: blanchedalmond; +} +.sb-main__inner { + background: antiquewhite; +} +.sb-header-article { + background: lightsteelblue; +} +.sb-article-container { + background: snow; +} +.sb-article-main { + background: white; +} +.sb-footer-article { + background: lightpink; +} +.sb-sidebar-secondary { + background: lightgoldenrodyellow; +} +.sb-footer-content { + background: plum; +} +.sb-footer-content__inner { + background: palevioletred; +} +.sb-footer { + background: pink; +} +.sb-footer__inner { + background: salmon; +} +.sb-article { + background: white; +} diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 00000000..d06a71d7 --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 00000000..08886833 --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: 'latest', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/_static/file.png differ diff --git a/_static/icon.ico b/_static/icon.ico new file mode 100644 index 00000000..18b7a7d1 Binary files /dev/null and b/_static/icon.ico differ diff --git a/_static/language_data.js b/_static/language_data.js new file mode 100644 index 00000000..250f5665 --- /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-2023 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, is 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/logo.png b/_static/logo.png new file mode 100644 index 00000000..56804ec6 Binary files /dev/null and b/_static/logo.png differ diff --git a/_static/logo.svg b/_static/logo.svg new file mode 100644 index 00000000..b73d2cbf --- /dev/null +++ b/_static/logo.svg @@ -0,0 +1,662 @@ + +image/svg+xml + + + +co-simulation + \ No newline at end of file diff --git a/_static/logol.png b/_static/logol.png new file mode 100644 index 00000000..bc2d133f Binary files /dev/null and b/_static/logol.png differ diff --git a/_static/minus.png b/_static/minus.png new file mode 100644 index 00000000..d96755fd Binary files /dev/null and b/_static/minus.png differ diff --git a/_static/plus.png b/_static/plus.png new file mode 100644 index 00000000..7107cec9 Binary files /dev/null and b/_static/plus.png differ diff --git a/_static/pygments.css b/_static/pygments.css new file mode 100644 index 00000000..c2e07c71 --- /dev/null +++ b/_static/pygments.css @@ -0,0 +1,258 @@ +.highlight pre { line-height: 125%; } +.highlight td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +.highlight span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +.highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f8f8f8; } +.highlight .c { color: #8f5902; font-style: italic } /* Comment */ +.highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */ +.highlight .g { color: #000000 } /* Generic */ +.highlight .k { color: #204a87; font-weight: bold } /* Keyword */ +.highlight .l { color: #000000 } /* Literal */ +.highlight .n { color: #000000 } /* Name */ +.highlight .o { color: #ce5c00; font-weight: bold } /* Operator */ +.highlight .x { color: #000000 } /* Other */ +.highlight .p { color: #000000; font-weight: bold } /* Punctuation */ +.highlight .ch { color: #8f5902; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #8f5902; font-style: italic } /* Comment.Preproc */ +.highlight .cpf { color: #8f5902; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #a40000 } /* Generic.Deleted */ +.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */ +.highlight .ges { color: #000000; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.highlight .gr { color: #ef2929 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #000000; font-style: italic } /* Generic.Output */ +.highlight .gp { color: #8f5902 } /* Generic.Prompt */ +.highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */ +.highlight .kc { color: #204a87; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #204a87; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #204a87; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #204a87; font-weight: bold } /* Keyword.Pseudo */ +.highlight .kr { color: #204a87; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #204a87; font-weight: bold } /* Keyword.Type */ +.highlight .ld { color: #000000 } /* Literal.Date */ +.highlight .m { color: #0000cf; font-weight: bold } /* Literal.Number */ +.highlight .s { color: #4e9a06 } /* Literal.String */ +.highlight .na { color: #c4a000 } /* Name.Attribute */ +.highlight .nb { color: #204a87 } /* Name.Builtin */ +.highlight .nc { color: #000000 } /* Name.Class */ +.highlight .no { color: #000000 } /* Name.Constant */ +.highlight .nd { color: #5c35cc; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #ce5c00 } /* Name.Entity */ +.highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #000000 } /* Name.Function */ +.highlight .nl { color: #f57900 } /* Name.Label */ +.highlight .nn { color: #000000 } /* Name.Namespace */ +.highlight .nx { color: #000000 } /* Name.Other */ +.highlight .py { color: #000000 } /* Name.Property */ +.highlight .nt { color: #204a87; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #000000 } /* Name.Variable */ +.highlight .ow { color: #204a87; font-weight: bold } /* Operator.Word */ +.highlight .pm { color: #000000; font-weight: bold } /* Punctuation.Marker */ +.highlight .w { color: #f8f8f8 } /* Text.Whitespace */ +.highlight .mb { color: #0000cf; font-weight: bold } /* Literal.Number.Bin */ +.highlight .mf { color: #0000cf; font-weight: bold } /* Literal.Number.Float */ +.highlight .mh { color: #0000cf; font-weight: bold } /* Literal.Number.Hex */ +.highlight .mi { color: #0000cf; font-weight: bold } /* Literal.Number.Integer */ +.highlight .mo { color: #0000cf; font-weight: bold } /* Literal.Number.Oct */ +.highlight .sa { color: #4e9a06 } /* Literal.String.Affix */ +.highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */ +.highlight .sc { color: #4e9a06 } /* Literal.String.Char */ +.highlight .dl { color: #4e9a06 } /* Literal.String.Delimiter */ +.highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4e9a06 } /* Literal.String.Double */ +.highlight .se { color: #4e9a06 } /* Literal.String.Escape */ +.highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */ +.highlight .si { color: #4e9a06 } /* Literal.String.Interpol */ +.highlight .sx { color: #4e9a06 } /* Literal.String.Other */ +.highlight .sr { color: #4e9a06 } /* Literal.String.Regex */ +.highlight .s1 { color: #4e9a06 } /* Literal.String.Single */ +.highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */ +.highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #000000 } /* Name.Function.Magic */ +.highlight .vc { color: #000000 } /* Name.Variable.Class */ +.highlight .vg { color: #000000 } /* Name.Variable.Global */ +.highlight .vi { color: #000000 } /* Name.Variable.Instance */ +.highlight .vm { color: #000000 } /* Name.Variable.Magic */ +.highlight .il { color: #0000cf; font-weight: bold } /* Literal.Number.Integer.Long */ +@media not print { +body[data-theme="dark"] .highlight pre { line-height: 125%; } +body[data-theme="dark"] .highlight td.linenos .normal { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; } +body[data-theme="dark"] .highlight span.linenos { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; } +body[data-theme="dark"] .highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +body[data-theme="dark"] .highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +body[data-theme="dark"] .highlight .hll { background-color: #404040 } +body[data-theme="dark"] .highlight { background: #202020; color: #d0d0d0 } +body[data-theme="dark"] .highlight .c { color: #ababab; font-style: italic } /* Comment */ +body[data-theme="dark"] .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ +body[data-theme="dark"] .highlight .esc { color: #d0d0d0 } /* Escape */ +body[data-theme="dark"] .highlight .g { color: #d0d0d0 } /* Generic */ +body[data-theme="dark"] .highlight .k { color: #6ebf26; font-weight: bold } /* Keyword */ +body[data-theme="dark"] .highlight .l { color: #d0d0d0 } /* Literal */ +body[data-theme="dark"] .highlight .n { color: #d0d0d0 } /* Name */ +body[data-theme="dark"] .highlight .o { color: #d0d0d0 } /* Operator */ +body[data-theme="dark"] .highlight .x { color: #d0d0d0 } /* Other */ +body[data-theme="dark"] .highlight .p { color: #d0d0d0 } /* Punctuation */ +body[data-theme="dark"] .highlight .ch { color: #ababab; font-style: italic } /* Comment.Hashbang */ +body[data-theme="dark"] .highlight .cm { color: #ababab; font-style: italic } /* Comment.Multiline */ +body[data-theme="dark"] .highlight .cp { color: #ff3a3a; font-weight: bold } /* Comment.Preproc */ +body[data-theme="dark"] .highlight .cpf { color: #ababab; font-style: italic } /* Comment.PreprocFile */ +body[data-theme="dark"] .highlight .c1 { color: #ababab; font-style: italic } /* Comment.Single */ +body[data-theme="dark"] .highlight .cs { color: #e50808; font-weight: bold; background-color: #520000 } /* Comment.Special */ +body[data-theme="dark"] .highlight .gd { color: #d22323 } /* Generic.Deleted */ +body[data-theme="dark"] .highlight .ge { color: #d0d0d0; font-style: italic } /* Generic.Emph */ +body[data-theme="dark"] .highlight .ges { color: #d0d0d0; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +body[data-theme="dark"] .highlight .gr { color: #d22323 } /* Generic.Error */ +body[data-theme="dark"] .highlight .gh { color: #ffffff; font-weight: bold } /* Generic.Heading */ +body[data-theme="dark"] .highlight .gi { color: #589819 } /* Generic.Inserted */ +body[data-theme="dark"] .highlight .go { color: #cccccc } /* Generic.Output */ +body[data-theme="dark"] .highlight .gp { color: #aaaaaa } /* Generic.Prompt */ +body[data-theme="dark"] .highlight .gs { color: #d0d0d0; font-weight: bold } /* Generic.Strong */ +body[data-theme="dark"] .highlight .gu { color: #ffffff; text-decoration: underline } /* Generic.Subheading */ +body[data-theme="dark"] .highlight .gt { color: #d22323 } /* Generic.Traceback */ +body[data-theme="dark"] .highlight .kc { color: #6ebf26; font-weight: bold } /* Keyword.Constant */ +body[data-theme="dark"] .highlight .kd { color: #6ebf26; font-weight: bold } /* Keyword.Declaration */ +body[data-theme="dark"] .highlight .kn { color: #6ebf26; font-weight: bold } /* Keyword.Namespace */ +body[data-theme="dark"] .highlight .kp { color: #6ebf26 } /* Keyword.Pseudo */ +body[data-theme="dark"] .highlight .kr { color: #6ebf26; font-weight: bold } /* Keyword.Reserved */ +body[data-theme="dark"] .highlight .kt { color: #6ebf26; font-weight: bold } /* Keyword.Type */ +body[data-theme="dark"] .highlight .ld { color: #d0d0d0 } /* Literal.Date */ +body[data-theme="dark"] .highlight .m { color: #51b2fd } /* Literal.Number */ +body[data-theme="dark"] .highlight .s { color: #ed9d13 } /* Literal.String */ +body[data-theme="dark"] .highlight .na { color: #bbbbbb } /* Name.Attribute */ +body[data-theme="dark"] .highlight .nb { color: #2fbccd } /* Name.Builtin */ +body[data-theme="dark"] .highlight .nc { color: #71adff; text-decoration: underline } /* Name.Class */ +body[data-theme="dark"] .highlight .no { color: #40ffff } /* Name.Constant */ +body[data-theme="dark"] .highlight .nd { color: #ffa500 } /* Name.Decorator */ +body[data-theme="dark"] .highlight .ni { color: #d0d0d0 } /* Name.Entity */ +body[data-theme="dark"] .highlight .ne { color: #bbbbbb } /* Name.Exception */ +body[data-theme="dark"] .highlight .nf { color: #71adff } /* Name.Function */ +body[data-theme="dark"] .highlight .nl { color: #d0d0d0 } /* Name.Label */ +body[data-theme="dark"] .highlight .nn { color: #71adff; text-decoration: underline } /* Name.Namespace */ +body[data-theme="dark"] .highlight .nx { color: #d0d0d0 } /* Name.Other */ +body[data-theme="dark"] .highlight .py { color: #d0d0d0 } /* Name.Property */ +body[data-theme="dark"] .highlight .nt { color: #6ebf26; font-weight: bold } /* Name.Tag */ +body[data-theme="dark"] .highlight .nv { color: #40ffff } /* Name.Variable */ +body[data-theme="dark"] .highlight .ow { color: #6ebf26; font-weight: bold } /* Operator.Word */ +body[data-theme="dark"] .highlight .pm { color: #d0d0d0 } /* Punctuation.Marker */ +body[data-theme="dark"] .highlight .w { color: #666666 } /* Text.Whitespace */ +body[data-theme="dark"] .highlight .mb { color: #51b2fd } /* Literal.Number.Bin */ +body[data-theme="dark"] .highlight .mf { color: #51b2fd } /* Literal.Number.Float */ +body[data-theme="dark"] .highlight .mh { color: #51b2fd } /* Literal.Number.Hex */ +body[data-theme="dark"] .highlight .mi { color: #51b2fd } /* Literal.Number.Integer */ +body[data-theme="dark"] .highlight .mo { color: #51b2fd } /* Literal.Number.Oct */ +body[data-theme="dark"] .highlight .sa { color: #ed9d13 } /* Literal.String.Affix */ +body[data-theme="dark"] .highlight .sb { color: #ed9d13 } /* Literal.String.Backtick */ +body[data-theme="dark"] .highlight .sc { color: #ed9d13 } /* Literal.String.Char */ +body[data-theme="dark"] .highlight .dl { color: #ed9d13 } /* Literal.String.Delimiter */ +body[data-theme="dark"] .highlight .sd { color: #ed9d13 } /* Literal.String.Doc */ +body[data-theme="dark"] .highlight .s2 { color: #ed9d13 } /* Literal.String.Double */ +body[data-theme="dark"] .highlight .se { color: #ed9d13 } /* Literal.String.Escape */ +body[data-theme="dark"] .highlight .sh { color: #ed9d13 } /* Literal.String.Heredoc */ +body[data-theme="dark"] .highlight .si { color: #ed9d13 } /* Literal.String.Interpol */ +body[data-theme="dark"] .highlight .sx { color: #ffa500 } /* Literal.String.Other */ +body[data-theme="dark"] .highlight .sr { color: #ed9d13 } /* Literal.String.Regex */ +body[data-theme="dark"] .highlight .s1 { color: #ed9d13 } /* Literal.String.Single */ +body[data-theme="dark"] .highlight .ss { color: #ed9d13 } /* Literal.String.Symbol */ +body[data-theme="dark"] .highlight .bp { color: #2fbccd } /* Name.Builtin.Pseudo */ +body[data-theme="dark"] .highlight .fm { color: #71adff } /* Name.Function.Magic */ +body[data-theme="dark"] .highlight .vc { color: #40ffff } /* Name.Variable.Class */ +body[data-theme="dark"] .highlight .vg { color: #40ffff } /* Name.Variable.Global */ +body[data-theme="dark"] .highlight .vi { color: #40ffff } /* Name.Variable.Instance */ +body[data-theme="dark"] .highlight .vm { color: #40ffff } /* Name.Variable.Magic */ +body[data-theme="dark"] .highlight .il { color: #51b2fd } /* Literal.Number.Integer.Long */ +@media (prefers-color-scheme: dark) { +body:not([data-theme="light"]) .highlight pre { line-height: 125%; } +body:not([data-theme="light"]) .highlight td.linenos .normal { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; } +body:not([data-theme="light"]) .highlight span.linenos { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; } +body:not([data-theme="light"]) .highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +body:not([data-theme="light"]) .highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +body:not([data-theme="light"]) .highlight .hll { background-color: #404040 } +body:not([data-theme="light"]) .highlight { background: #202020; color: #d0d0d0 } +body:not([data-theme="light"]) .highlight .c { color: #ababab; font-style: italic } /* Comment */ +body:not([data-theme="light"]) .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ +body:not([data-theme="light"]) .highlight .esc { color: #d0d0d0 } /* Escape */ +body:not([data-theme="light"]) .highlight .g { color: #d0d0d0 } /* Generic */ +body:not([data-theme="light"]) .highlight .k { color: #6ebf26; font-weight: bold } /* Keyword */ +body:not([data-theme="light"]) .highlight .l { color: #d0d0d0 } /* Literal */ +body:not([data-theme="light"]) .highlight .n { color: #d0d0d0 } /* Name */ +body:not([data-theme="light"]) .highlight .o { color: #d0d0d0 } /* Operator */ +body:not([data-theme="light"]) .highlight .x { color: #d0d0d0 } /* Other */ +body:not([data-theme="light"]) .highlight .p { color: #d0d0d0 } /* Punctuation */ +body:not([data-theme="light"]) .highlight .ch { color: #ababab; font-style: italic } /* Comment.Hashbang */ +body:not([data-theme="light"]) .highlight .cm { color: #ababab; font-style: italic } /* Comment.Multiline */ +body:not([data-theme="light"]) .highlight .cp { color: #ff3a3a; font-weight: bold } /* Comment.Preproc */ +body:not([data-theme="light"]) .highlight .cpf { color: #ababab; font-style: italic } /* Comment.PreprocFile */ +body:not([data-theme="light"]) .highlight .c1 { color: #ababab; font-style: italic } /* Comment.Single */ +body:not([data-theme="light"]) .highlight .cs { color: #e50808; font-weight: bold; background-color: #520000 } /* Comment.Special */ +body:not([data-theme="light"]) .highlight .gd { color: #d22323 } /* Generic.Deleted */ +body:not([data-theme="light"]) .highlight .ge { color: #d0d0d0; font-style: italic } /* Generic.Emph */ +body:not([data-theme="light"]) .highlight .ges { color: #d0d0d0; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +body:not([data-theme="light"]) .highlight .gr { color: #d22323 } /* Generic.Error */ +body:not([data-theme="light"]) .highlight .gh { color: #ffffff; font-weight: bold } /* Generic.Heading */ +body:not([data-theme="light"]) .highlight .gi { color: #589819 } /* Generic.Inserted */ +body:not([data-theme="light"]) .highlight .go { color: #cccccc } /* Generic.Output */ +body:not([data-theme="light"]) .highlight .gp { color: #aaaaaa } /* Generic.Prompt */ +body:not([data-theme="light"]) .highlight .gs { color: #d0d0d0; font-weight: bold } /* Generic.Strong */ +body:not([data-theme="light"]) .highlight .gu { color: #ffffff; text-decoration: underline } /* Generic.Subheading */ +body:not([data-theme="light"]) .highlight .gt { color: #d22323 } /* Generic.Traceback */ +body:not([data-theme="light"]) .highlight .kc { color: #6ebf26; font-weight: bold } /* Keyword.Constant */ +body:not([data-theme="light"]) .highlight .kd { color: #6ebf26; font-weight: bold } /* Keyword.Declaration */ +body:not([data-theme="light"]) .highlight .kn { color: #6ebf26; font-weight: bold } /* Keyword.Namespace */ +body:not([data-theme="light"]) .highlight .kp { color: #6ebf26 } /* Keyword.Pseudo */ +body:not([data-theme="light"]) .highlight .kr { color: #6ebf26; font-weight: bold } /* Keyword.Reserved */ +body:not([data-theme="light"]) .highlight .kt { color: #6ebf26; font-weight: bold } /* Keyword.Type */ +body:not([data-theme="light"]) .highlight .ld { color: #d0d0d0 } /* Literal.Date */ +body:not([data-theme="light"]) .highlight .m { color: #51b2fd } /* Literal.Number */ +body:not([data-theme="light"]) .highlight .s { color: #ed9d13 } /* Literal.String */ +body:not([data-theme="light"]) .highlight .na { color: #bbbbbb } /* Name.Attribute */ +body:not([data-theme="light"]) .highlight .nb { color: #2fbccd } /* Name.Builtin */ +body:not([data-theme="light"]) .highlight .nc { color: #71adff; text-decoration: underline } /* Name.Class */ +body:not([data-theme="light"]) .highlight .no { color: #40ffff } /* Name.Constant */ +body:not([data-theme="light"]) .highlight .nd { color: #ffa500 } /* Name.Decorator */ +body:not([data-theme="light"]) .highlight .ni { color: #d0d0d0 } /* Name.Entity */ +body:not([data-theme="light"]) .highlight .ne { color: #bbbbbb } /* Name.Exception */ +body:not([data-theme="light"]) .highlight .nf { color: #71adff } /* Name.Function */ +body:not([data-theme="light"]) .highlight .nl { color: #d0d0d0 } /* Name.Label */ +body:not([data-theme="light"]) .highlight .nn { color: #71adff; text-decoration: underline } /* Name.Namespace */ +body:not([data-theme="light"]) .highlight .nx { color: #d0d0d0 } /* Name.Other */ +body:not([data-theme="light"]) .highlight .py { color: #d0d0d0 } /* Name.Property */ +body:not([data-theme="light"]) .highlight .nt { color: #6ebf26; font-weight: bold } /* Name.Tag */ +body:not([data-theme="light"]) .highlight .nv { color: #40ffff } /* Name.Variable */ +body:not([data-theme="light"]) .highlight .ow { color: #6ebf26; font-weight: bold } /* Operator.Word */ +body:not([data-theme="light"]) .highlight .pm { color: #d0d0d0 } /* Punctuation.Marker */ +body:not([data-theme="light"]) .highlight .w { color: #666666 } /* Text.Whitespace */ +body:not([data-theme="light"]) .highlight .mb { color: #51b2fd } /* Literal.Number.Bin */ +body:not([data-theme="light"]) .highlight .mf { color: #51b2fd } /* Literal.Number.Float */ +body:not([data-theme="light"]) .highlight .mh { color: #51b2fd } /* Literal.Number.Hex */ +body:not([data-theme="light"]) .highlight .mi { color: #51b2fd } /* Literal.Number.Integer */ +body:not([data-theme="light"]) .highlight .mo { color: #51b2fd } /* Literal.Number.Oct */ +body:not([data-theme="light"]) .highlight .sa { color: #ed9d13 } /* Literal.String.Affix */ +body:not([data-theme="light"]) .highlight .sb { color: #ed9d13 } /* Literal.String.Backtick */ +body:not([data-theme="light"]) .highlight .sc { color: #ed9d13 } /* Literal.String.Char */ +body:not([data-theme="light"]) .highlight .dl { color: #ed9d13 } /* Literal.String.Delimiter */ +body:not([data-theme="light"]) .highlight .sd { color: #ed9d13 } /* Literal.String.Doc */ +body:not([data-theme="light"]) .highlight .s2 { color: #ed9d13 } /* Literal.String.Double */ +body:not([data-theme="light"]) .highlight .se { color: #ed9d13 } /* Literal.String.Escape */ +body:not([data-theme="light"]) .highlight .sh { color: #ed9d13 } /* Literal.String.Heredoc */ +body:not([data-theme="light"]) .highlight .si { color: #ed9d13 } /* Literal.String.Interpol */ +body:not([data-theme="light"]) .highlight .sx { color: #ffa500 } /* Literal.String.Other */ +body:not([data-theme="light"]) .highlight .sr { color: #ed9d13 } /* Literal.String.Regex */ +body:not([data-theme="light"]) .highlight .s1 { color: #ed9d13 } /* Literal.String.Single */ +body:not([data-theme="light"]) .highlight .ss { color: #ed9d13 } /* Literal.String.Symbol */ +body:not([data-theme="light"]) .highlight .bp { color: #2fbccd } /* Name.Builtin.Pseudo */ +body:not([data-theme="light"]) .highlight .fm { color: #71adff } /* Name.Function.Magic */ +body:not([data-theme="light"]) .highlight .vc { color: #40ffff } /* Name.Variable.Class */ +body:not([data-theme="light"]) .highlight .vg { color: #40ffff } /* Name.Variable.Global */ +body:not([data-theme="light"]) .highlight .vi { color: #40ffff } /* Name.Variable.Instance */ +body:not([data-theme="light"]) .highlight .vm { color: #40ffff } /* Name.Variable.Magic */ +body:not([data-theme="light"]) .highlight .il { color: #51b2fd } /* Literal.Number.Integer.Long */ +} +} \ No newline at end of file diff --git a/_static/scripts/furo-extensions.js b/_static/scripts/furo-extensions.js new file mode 100644 index 00000000..e69de29b diff --git a/_static/scripts/furo.js b/_static/scripts/furo.js new file mode 100644 index 00000000..0abb2afa --- /dev/null +++ b/_static/scripts/furo.js @@ -0,0 +1,3 @@ +/*! For license information please see furo.js.LICENSE.txt */ +(()=>{var t={856:function(t,e,n){var o,r;r=void 0!==n.g?n.g:"undefined"!=typeof window?window:this,o=function(){return function(t){"use strict";var e={navClass:"active",contentClass:"active",nested:!1,nestedClass:"active",offset:0,reflow:!1,events:!0},n=function(t,e,n){if(n.settings.events){var o=new CustomEvent(t,{bubbles:!0,cancelable:!0,detail:n});e.dispatchEvent(o)}},o=function(t){var e=0;if(t.offsetParent)for(;t;)e+=t.offsetTop,t=t.offsetParent;return e>=0?e:0},r=function(t){t&&t.sort((function(t,e){return o(t.content)=Math.max(document.body.scrollHeight,document.documentElement.scrollHeight,document.body.offsetHeight,document.documentElement.offsetHeight,document.body.clientHeight,document.documentElement.clientHeight)},l=function(t,e){var n=t[t.length-1];if(function(t,e){return!(!s()||!c(t.content,e,!0))}(n,e))return n;for(var o=t.length-1;o>=0;o--)if(c(t[o].content,e))return t[o]},a=function(t,e){if(e.nested&&t.parentNode){var n=t.parentNode.closest("li");n&&(n.classList.remove(e.nestedClass),a(n,e))}},i=function(t,e){if(t){var o=t.nav.closest("li");o&&(o.classList.remove(e.navClass),t.content.classList.remove(e.contentClass),a(o,e),n("gumshoeDeactivate",o,{link:t.nav,content:t.content,settings:e}))}},u=function(t,e){if(e.nested){var n=t.parentNode.closest("li");n&&(n.classList.add(e.nestedClass),u(n,e))}};return function(o,c){var s,a,d,f,m,v={setup:function(){s=document.querySelectorAll(o),a=[],Array.prototype.forEach.call(s,(function(t){var e=document.getElementById(decodeURIComponent(t.hash.substr(1)));e&&a.push({nav:t,content:e})})),r(a)},detect:function(){var t=l(a,m);t?d&&t.content===d.content||(i(d,m),function(t,e){if(t){var o=t.nav.closest("li");o&&(o.classList.add(e.navClass),t.content.classList.add(e.contentClass),u(o,e),n("gumshoeActivate",o,{link:t.nav,content:t.content,settings:e}))}}(t,m),d=t):d&&(i(d,m),d=null)}},h=function(e){f&&t.cancelAnimationFrame(f),f=t.requestAnimationFrame(v.detect)},g=function(e){f&&t.cancelAnimationFrame(f),f=t.requestAnimationFrame((function(){r(a),v.detect()}))};return v.destroy=function(){d&&i(d,m),t.removeEventListener("scroll",h,!1),m.reflow&&t.removeEventListener("resize",g,!1),a=null,s=null,d=null,f=null,m=null},m=function(){var t={};return Array.prototype.forEach.call(arguments,(function(e){for(var n in e){if(!e.hasOwnProperty(n))return;t[n]=e[n]}})),t}(e,c||{}),v.setup(),v.detect(),t.addEventListener("scroll",h,!1),m.reflow&&t.addEventListener("resize",g,!1),v}}(r)}.apply(e,[]),void 0===o||(t.exports=o)}},e={};function n(o){var r=e[o];if(void 0!==r)return r.exports;var c=e[o]={exports:{}};return t[o].call(c.exports,c,c.exports,n),c.exports}n.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return n.d(e,{a:e}),e},n.d=(t,e)=>{for(var o in e)n.o(e,o)&&!n.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:e[o]})},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),n.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),(()=>{"use strict";var t=n(856),e=n.n(t),o=null,r=null,c=document.documentElement.scrollTop;const s=64;function l(){const t=localStorage.getItem("theme")||"auto";var e;"light"!==(e=window.matchMedia("(prefers-color-scheme: dark)").matches?"auto"===t?"light":"light"==t?"dark":"auto":"auto"===t?"dark":"dark"==t?"light":"auto")&&"dark"!==e&&"auto"!==e&&(console.error(`Got invalid theme mode: ${e}. Resetting to auto.`),e="auto"),document.body.dataset.theme=e,localStorage.setItem("theme",e),console.log(`Changed to ${e} mode.`)}function a(){!function(){const t=document.getElementsByClassName("theme-toggle");Array.from(t).forEach((t=>{t.addEventListener("click",l)}))}(),function(){let t=0,e=!1;window.addEventListener("scroll",(function(n){t=window.scrollY,e||(window.requestAnimationFrame((function(){var n;(function(t){const e=Math.floor(r.getBoundingClientRect().top);console.log(`headerTop: ${e}`),0==e&&t!=e?r.classList.add("scrolled"):r.classList.remove("scrolled")})(n=t),function(t){tc&&document.documentElement.classList.remove("show-back-to-top"),c=t}(n),function(t){null!==o&&(0==t?o.scrollTo(0,0):Math.ceil(t)>=Math.floor(document.documentElement.scrollHeight-window.innerHeight)?o.scrollTo(0,o.scrollHeight):document.querySelector(".scroll-current"))}(n),e=!1})),e=!0)})),window.scroll()}(),null!==o&&new(e())(".toc-tree a",{reflow:!0,recursive:!0,navClass:"scroll-current",offset:()=>{let t=parseFloat(getComputedStyle(document.documentElement).fontSize);return r.getBoundingClientRect().height+2.5*t+1}})}document.addEventListener("DOMContentLoaded",(function(){document.body.parentNode.classList.remove("no-js"),r=document.querySelector("header"),o=document.querySelector(".toc-scroll"),a()}))})()})(); +//# sourceMappingURL=furo.js.map \ No newline at end of file diff --git a/_static/scripts/furo.js.LICENSE.txt b/_static/scripts/furo.js.LICENSE.txt new file mode 100644 index 00000000..1632189c --- /dev/null +++ b/_static/scripts/furo.js.LICENSE.txt @@ -0,0 +1,7 @@ +/*! + * gumshoejs v5.1.2 (patched by @pradyunsg) + * A simple, framework-agnostic scrollspy script. + * (c) 2019 Chris Ferdinandi + * MIT License + * http://github.com/cferdinandi/gumshoe + */ diff --git a/_static/scripts/furo.js.map b/_static/scripts/furo.js.map new file mode 100644 index 00000000..80ea12b8 --- /dev/null +++ b/_static/scripts/furo.js.map @@ -0,0 +1 @@ +{"version":3,"file":"scripts/furo.js","mappings":";iCAAA,MAQWA,SAWS,IAAX,EAAAC,EACH,EAAAA,EACkB,oBAAXC,OACLA,OACAC,KAbO,EAAF,WACP,OAaJ,SAAUD,GACR,aAMA,IAAIE,EAAW,CAEbC,SAAU,SACVC,aAAc,SAGdC,QAAQ,EACRC,YAAa,SAGbC,OAAQ,EACRC,QAAQ,EAGRC,QAAQ,GA6BNC,EAAY,SAAUC,EAAMC,EAAMC,GAEpC,GAAKA,EAAOC,SAASL,OAArB,CAGA,IAAIM,EAAQ,IAAIC,YAAYL,EAAM,CAChCM,SAAS,EACTC,YAAY,EACZL,OAAQA,IAIVD,EAAKO,cAAcJ,EAVgB,CAWrC,EAOIK,EAAe,SAAUR,GAC3B,IAAIS,EAAW,EACf,GAAIT,EAAKU,aACP,KAAOV,GACLS,GAAYT,EAAKW,UACjBX,EAAOA,EAAKU,aAGhB,OAAOD,GAAY,EAAIA,EAAW,CACpC,EAMIG,EAAe,SAAUC,GACvBA,GACFA,EAASC,MAAK,SAAUC,EAAOC,GAG7B,OAFcR,EAAaO,EAAME,SACnBT,EAAaQ,EAAMC,UACF,EACxB,CACT,GAEJ,EAwCIC,EAAW,SAAUlB,EAAME,EAAUiB,GACvC,IAAIC,EAASpB,EAAKqB,wBACd1B,EAnCU,SAAUO,GAExB,MAA+B,mBAApBA,EAASP,OACX2B,WAAWpB,EAASP,UAItB2B,WAAWpB,EAASP,OAC7B,CA2Be4B,CAAUrB,GACvB,OAAIiB,EAEAK,SAASJ,EAAOD,OAAQ,KACvB/B,EAAOqC,aAAeC,SAASC,gBAAgBC,cAG7CJ,SAASJ,EAAOS,IAAK,KAAOlC,CACrC,EAMImC,EAAa,WACf,OACEC,KAAKC,KAAK5C,EAAOqC,YAAcrC,EAAO6C,cAnCjCF,KAAKG,IACVR,SAASS,KAAKC,aACdV,SAASC,gBAAgBS,aACzBV,SAASS,KAAKE,aACdX,SAASC,gBAAgBU,aACzBX,SAASS,KAAKP,aACdF,SAASC,gBAAgBC,aAkC7B,EAmBIU,EAAY,SAAUzB,EAAUX,GAClC,IAAIqC,EAAO1B,EAASA,EAAS2B,OAAS,GACtC,GAbgB,SAAUC,EAAMvC,GAChC,SAAI4B,MAAgBZ,EAASuB,EAAKxB,QAASf,GAAU,GAEvD,CAUMwC,CAAYH,EAAMrC,GAAW,OAAOqC,EACxC,IAAK,IAAII,EAAI9B,EAAS2B,OAAS,EAAGG,GAAK,EAAGA,IACxC,GAAIzB,EAASL,EAAS8B,GAAG1B,QAASf,GAAW,OAAOW,EAAS8B,EAEjE,EAOIC,EAAmB,SAAUC,EAAK3C,GAEpC,GAAKA,EAAST,QAAWoD,EAAIC,WAA7B,CAGA,IAAIC,EAAKF,EAAIC,WAAWE,QAAQ,MAC3BD,IAGLA,EAAGE,UAAUC,OAAOhD,EAASR,aAG7BkD,EAAiBG,EAAI7C,GAV0B,CAWjD,EAOIiD,EAAa,SAAUC,EAAOlD,GAEhC,GAAKkD,EAAL,CAGA,IAAIL,EAAKK,EAAMP,IAAIG,QAAQ,MACtBD,IAGLA,EAAGE,UAAUC,OAAOhD,EAASX,UAC7B6D,EAAMnC,QAAQgC,UAAUC,OAAOhD,EAASV,cAGxCoD,EAAiBG,EAAI7C,GAGrBJ,EAAU,oBAAqBiD,EAAI,CACjCM,KAAMD,EAAMP,IACZ5B,QAASmC,EAAMnC,QACff,SAAUA,IAjBM,CAmBpB,EAOIoD,EAAiB,SAAUT,EAAK3C,GAElC,GAAKA,EAAST,OAAd,CAGA,IAAIsD,EAAKF,EAAIC,WAAWE,QAAQ,MAC3BD,IAGLA,EAAGE,UAAUM,IAAIrD,EAASR,aAG1B4D,EAAeP,EAAI7C,GAVS,CAW9B,EA6LA,OA1JkB,SAAUsD,EAAUC,GAKpC,IACIC,EAAU7C,EAAU8C,EAASC,EAAS1D,EADtC2D,EAAa,CAUjBA,MAAmB,WAEjBH,EAAWhC,SAASoC,iBAAiBN,GAGrC3C,EAAW,GAGXkD,MAAMC,UAAUC,QAAQC,KAAKR,GAAU,SAAUjB,GAE/C,IAAIxB,EAAUS,SAASyC,eACrBC,mBAAmB3B,EAAK4B,KAAKC,OAAO,KAEjCrD,GAGLJ,EAAS0D,KAAK,CACZ1B,IAAKJ,EACLxB,QAASA,GAEb,IAGAL,EAAaC,EACf,EAKAgD,OAAoB,WAElB,IAAIW,EAASlC,EAAUzB,EAAUX,GAG5BsE,EASDb,GAAWa,EAAOvD,UAAY0C,EAAQ1C,UAG1CkC,EAAWQ,EAASzD,GAzFT,SAAUkD,EAAOlD,GAE9B,GAAKkD,EAAL,CAGA,IAAIL,EAAKK,EAAMP,IAAIG,QAAQ,MACtBD,IAGLA,EAAGE,UAAUM,IAAIrD,EAASX,UAC1B6D,EAAMnC,QAAQgC,UAAUM,IAAIrD,EAASV,cAGrC8D,EAAeP,EAAI7C,GAGnBJ,EAAU,kBAAmBiD,EAAI,CAC/BM,KAAMD,EAAMP,IACZ5B,QAASmC,EAAMnC,QACff,SAAUA,IAjBM,CAmBpB,CAqEIuE,CAASD,EAAQtE,GAGjByD,EAAUa,GAfJb,IACFR,EAAWQ,EAASzD,GACpByD,EAAU,KAchB,GAMIe,EAAgB,SAAUvE,GAExByD,GACFxE,EAAOuF,qBAAqBf,GAI9BA,EAAUxE,EAAOwF,sBAAsBf,EAAWgB,OACpD,EAMIC,EAAgB,SAAU3E,GAExByD,GACFxE,EAAOuF,qBAAqBf,GAI9BA,EAAUxE,EAAOwF,uBAAsB,WACrChE,EAAaC,GACbgD,EAAWgB,QACb,GACF,EAkDA,OA7CAhB,EAAWkB,QAAU,WAEfpB,GACFR,EAAWQ,EAASzD,GAItBd,EAAO4F,oBAAoB,SAAUN,GAAe,GAChDxE,EAASN,QACXR,EAAO4F,oBAAoB,SAAUF,GAAe,GAItDjE,EAAW,KACX6C,EAAW,KACXC,EAAU,KACVC,EAAU,KACV1D,EAAW,IACb,EAOEA,EA3XS,WACX,IAAI+E,EAAS,CAAC,EAOd,OANAlB,MAAMC,UAAUC,QAAQC,KAAKgB,WAAW,SAAUC,GAChD,IAAK,IAAIC,KAAOD,EAAK,CACnB,IAAKA,EAAIE,eAAeD,GAAM,OAC9BH,EAAOG,GAAOD,EAAIC,EACpB,CACF,IACOH,CACT,CAkXeK,CAAOhG,EAAUmE,GAAW,CAAC,GAGxCI,EAAW0B,QAGX1B,EAAWgB,SAGXzF,EAAOoG,iBAAiB,SAAUd,GAAe,GAC7CxE,EAASN,QACXR,EAAOoG,iBAAiB,SAAUV,GAAe,GAS9CjB,CACT,CAOF,CArcW4B,CAAQvG,EAChB,UAFM,SAEN,uBCXDwG,EAA2B,CAAC,EAGhC,SAASC,EAAoBC,GAE5B,IAAIC,EAAeH,EAAyBE,GAC5C,QAAqBE,IAAjBD,EACH,OAAOA,EAAaE,QAGrB,IAAIC,EAASN,EAAyBE,GAAY,CAGjDG,QAAS,CAAC,GAOX,OAHAE,EAAoBL,GAAU1B,KAAK8B,EAAOD,QAASC,EAAQA,EAAOD,QAASJ,GAGpEK,EAAOD,OACf,CCrBAJ,EAAoBO,EAAKF,IACxB,IAAIG,EAASH,GAAUA,EAAOI,WAC7B,IAAOJ,EAAiB,QACxB,IAAM,EAEP,OADAL,EAAoBU,EAAEF,EAAQ,CAAEG,EAAGH,IAC5BA,CAAM,ECLdR,EAAoBU,EAAI,CAACN,EAASQ,KACjC,IAAI,IAAInB,KAAOmB,EACXZ,EAAoBa,EAAED,EAAYnB,KAASO,EAAoBa,EAAET,EAASX,IAC5EqB,OAAOC,eAAeX,EAASX,EAAK,CAAEuB,YAAY,EAAMC,IAAKL,EAAWnB,IAE1E,ECNDO,EAAoBxG,EAAI,WACvB,GAA0B,iBAAf0H,WAAyB,OAAOA,WAC3C,IACC,OAAOxH,MAAQ,IAAIyH,SAAS,cAAb,EAChB,CAAE,MAAOC,GACR,GAAsB,iBAAX3H,OAAqB,OAAOA,MACxC,CACA,CAPuB,GCAxBuG,EAAoBa,EAAI,CAACrB,EAAK6B,IAAUP,OAAOzC,UAAUqB,eAAenB,KAAKiB,EAAK6B,4CCK9EC,EAAY,KACZC,EAAS,KACTC,EAAgBzF,SAASC,gBAAgByF,UAC7C,MAAMC,EAAmB,GA8EzB,SAASC,IACP,MAAMC,EAAeC,aAAaC,QAAQ,UAAY,OAZxD,IAAkBC,EACH,WADGA,EAaItI,OAAOuI,WAAW,gCAAgCC,QAI/C,SAAjBL,EACO,QACgB,SAAhBA,EACA,OAEA,OAIU,SAAjBA,EACO,OACgB,QAAhBA,EACA,QAEA,SA9BoB,SAATG,GAA4B,SAATA,IACzCG,QAAQC,MAAM,2BAA2BJ,yBACzCA,EAAO,QAGThG,SAASS,KAAK4F,QAAQC,MAAQN,EAC9BF,aAAaS,QAAQ,QAASP,GAC9BG,QAAQK,IAAI,cAAcR,UA0B5B,CAkDA,SAASnC,KART,WAEE,MAAM4C,EAAUzG,SAAS0G,uBAAuB,gBAChDrE,MAAMsE,KAAKF,GAASlE,SAASqE,IAC3BA,EAAI9C,iBAAiB,QAAS8B,EAAe,GAEjD,CAGEiB,GA9CF,WAEE,IAAIC,EAA6B,EAC7BC,GAAU,EAEdrJ,OAAOoG,iBAAiB,UAAU,SAAUuB,GAC1CyB,EAA6BpJ,OAAOsJ,QAE/BD,IACHrJ,OAAOwF,uBAAsB,WAzDnC,IAAuB+D,GAxDvB,SAAgCA,GAC9B,MAAMC,EAAY7G,KAAK8G,MAAM3B,EAAO7F,wBAAwBQ,KAE5DgG,QAAQK,IAAI,cAAcU,KACT,GAAbA,GAAkBD,GAAaC,EACjC1B,EAAOjE,UAAUM,IAAI,YAErB2D,EAAOjE,UAAUC,OAAO,WAE5B,EAgDE4F,CADqBH,EA0DDH,GAvGtB,SAAmCG,GAC7BA,EAAYtB,EACd3F,SAASC,gBAAgBsB,UAAUC,OAAO,oBAEtCyF,EAAYxB,EACdzF,SAASC,gBAAgBsB,UAAUM,IAAI,oBAC9BoF,EAAYxB,GACrBzF,SAASC,gBAAgBsB,UAAUC,OAAO,oBAG9CiE,EAAgBwB,CAClB,CAoCEI,CAA0BJ,GAlC5B,SAA6BA,GACT,OAAd1B,IAKa,GAAb0B,EACF1B,EAAU+B,SAAS,EAAG,GAGtBjH,KAAKC,KAAK2G,IACV5G,KAAK8G,MAAMnH,SAASC,gBAAgBS,aAAehD,OAAOqC,aAE1DwF,EAAU+B,SAAS,EAAG/B,EAAU7E,cAGhBV,SAASuH,cAAc,mBAc3C,CAKEC,CAAoBP,GAwDdF,GAAU,CACZ,IAEAA,GAAU,EAEd,IACArJ,OAAO+J,QACT,CA6BEC,GA1BkB,OAAdnC,GAKJ,IAAI,IAAJ,CAAY,cAAe,CACzBrH,QAAQ,EACRyJ,WAAW,EACX9J,SAAU,iBACVI,OAAQ,KACN,IAAI2J,EAAMhI,WAAWiI,iBAAiB7H,SAASC,iBAAiB6H,UAChE,OAAOtC,EAAO7F,wBAAwBoI,OAAS,IAAMH,EAAM,CAAC,GAiBlE,CAcA5H,SAAS8D,iBAAiB,oBAT1B,WACE9D,SAASS,KAAKW,WAAWG,UAAUC,OAAO,SAE1CgE,EAASxF,SAASuH,cAAc,UAChChC,EAAYvF,SAASuH,cAAc,eAEnC1D,GACF","sources":["webpack:///./src/furo/assets/scripts/gumshoe-patched.js","webpack:///webpack/bootstrap","webpack:///webpack/runtime/compat get default export","webpack:///webpack/runtime/define property getters","webpack:///webpack/runtime/global","webpack:///webpack/runtime/hasOwnProperty shorthand","webpack:///./src/furo/assets/scripts/furo.js"],"sourcesContent":["/*!\n * gumshoejs v5.1.2 (patched by @pradyunsg)\n * A simple, framework-agnostic scrollspy script.\n * (c) 2019 Chris Ferdinandi\n * MIT License\n * http://github.com/cferdinandi/gumshoe\n */\n\n(function (root, factory) {\n if (typeof define === \"function\" && define.amd) {\n define([], function () {\n return factory(root);\n });\n } else if (typeof exports === \"object\") {\n module.exports = factory(root);\n } else {\n root.Gumshoe = factory(root);\n }\n})(\n typeof global !== \"undefined\"\n ? global\n : typeof window !== \"undefined\"\n ? window\n : this,\n function (window) {\n \"use strict\";\n\n //\n // Defaults\n //\n\n var defaults = {\n // Active classes\n navClass: \"active\",\n contentClass: \"active\",\n\n // Nested navigation\n nested: false,\n nestedClass: \"active\",\n\n // Offset & reflow\n offset: 0,\n reflow: false,\n\n // Event support\n events: true,\n };\n\n //\n // Methods\n //\n\n /**\n * Merge two or more objects together.\n * @param {Object} objects The objects to merge together\n * @returns {Object} Merged values of defaults and options\n */\n var extend = function () {\n var merged = {};\n Array.prototype.forEach.call(arguments, function (obj) {\n for (var key in obj) {\n if (!obj.hasOwnProperty(key)) return;\n merged[key] = obj[key];\n }\n });\n return merged;\n };\n\n /**\n * Emit a custom event\n * @param {String} type The event type\n * @param {Node} elem The element to attach the event to\n * @param {Object} detail Any details to pass along with the event\n */\n var emitEvent = function (type, elem, detail) {\n // Make sure events are enabled\n if (!detail.settings.events) return;\n\n // Create a new event\n var event = new CustomEvent(type, {\n bubbles: true,\n cancelable: true,\n detail: detail,\n });\n\n // Dispatch the event\n elem.dispatchEvent(event);\n };\n\n /**\n * Get an element's distance from the top of the Document.\n * @param {Node} elem The element\n * @return {Number} Distance from the top in pixels\n */\n var getOffsetTop = function (elem) {\n var location = 0;\n if (elem.offsetParent) {\n while (elem) {\n location += elem.offsetTop;\n elem = elem.offsetParent;\n }\n }\n return location >= 0 ? location : 0;\n };\n\n /**\n * Sort content from first to last in the DOM\n * @param {Array} contents The content areas\n */\n var sortContents = function (contents) {\n if (contents) {\n contents.sort(function (item1, item2) {\n var offset1 = getOffsetTop(item1.content);\n var offset2 = getOffsetTop(item2.content);\n if (offset1 < offset2) return -1;\n return 1;\n });\n }\n };\n\n /**\n * Get the offset to use for calculating position\n * @param {Object} settings The settings for this instantiation\n * @return {Float} The number of pixels to offset the calculations\n */\n var getOffset = function (settings) {\n // if the offset is a function run it\n if (typeof settings.offset === \"function\") {\n return parseFloat(settings.offset());\n }\n\n // Otherwise, return it as-is\n return parseFloat(settings.offset);\n };\n\n /**\n * Get the document element's height\n * @private\n * @returns {Number}\n */\n var getDocumentHeight = function () {\n return Math.max(\n document.body.scrollHeight,\n document.documentElement.scrollHeight,\n document.body.offsetHeight,\n document.documentElement.offsetHeight,\n document.body.clientHeight,\n document.documentElement.clientHeight,\n );\n };\n\n /**\n * Determine if an element is in view\n * @param {Node} elem The element\n * @param {Object} settings The settings for this instantiation\n * @param {Boolean} bottom If true, check if element is above bottom of viewport instead\n * @return {Boolean} Returns true if element is in the viewport\n */\n var isInView = function (elem, settings, bottom) {\n var bounds = elem.getBoundingClientRect();\n var offset = getOffset(settings);\n if (bottom) {\n return (\n parseInt(bounds.bottom, 10) <\n (window.innerHeight || document.documentElement.clientHeight)\n );\n }\n return parseInt(bounds.top, 10) <= offset;\n };\n\n /**\n * Check if at the bottom of the viewport\n * @return {Boolean} If true, page is at the bottom of the viewport\n */\n var isAtBottom = function () {\n if (\n Math.ceil(window.innerHeight + window.pageYOffset) >=\n getDocumentHeight()\n )\n return true;\n return false;\n };\n\n /**\n * Check if the last item should be used (even if not at the top of the page)\n * @param {Object} item The last item\n * @param {Object} settings The settings for this instantiation\n * @return {Boolean} If true, use the last item\n */\n var useLastItem = function (item, settings) {\n if (isAtBottom() && isInView(item.content, settings, true)) return true;\n return false;\n };\n\n /**\n * Get the active content\n * @param {Array} contents The content areas\n * @param {Object} settings The settings for this instantiation\n * @return {Object} The content area and matching navigation link\n */\n var getActive = function (contents, settings) {\n var last = contents[contents.length - 1];\n if (useLastItem(last, settings)) return last;\n for (var i = contents.length - 1; i >= 0; i--) {\n if (isInView(contents[i].content, settings)) return contents[i];\n }\n };\n\n /**\n * Deactivate parent navs in a nested navigation\n * @param {Node} nav The starting navigation element\n * @param {Object} settings The settings for this instantiation\n */\n var deactivateNested = function (nav, settings) {\n // If nesting isn't activated, bail\n if (!settings.nested || !nav.parentNode) return;\n\n // Get the parent navigation\n var li = nav.parentNode.closest(\"li\");\n if (!li) return;\n\n // Remove the active class\n li.classList.remove(settings.nestedClass);\n\n // Apply recursively to any parent navigation elements\n deactivateNested(li, settings);\n };\n\n /**\n * Deactivate a nav and content area\n * @param {Object} items The nav item and content to deactivate\n * @param {Object} settings The settings for this instantiation\n */\n var deactivate = function (items, settings) {\n // Make sure there are items to deactivate\n if (!items) return;\n\n // Get the parent list item\n var li = items.nav.closest(\"li\");\n if (!li) return;\n\n // Remove the active class from the nav and content\n li.classList.remove(settings.navClass);\n items.content.classList.remove(settings.contentClass);\n\n // Deactivate any parent navs in a nested navigation\n deactivateNested(li, settings);\n\n // Emit a custom event\n emitEvent(\"gumshoeDeactivate\", li, {\n link: items.nav,\n content: items.content,\n settings: settings,\n });\n };\n\n /**\n * Activate parent navs in a nested navigation\n * @param {Node} nav The starting navigation element\n * @param {Object} settings The settings for this instantiation\n */\n var activateNested = function (nav, settings) {\n // If nesting isn't activated, bail\n if (!settings.nested) return;\n\n // Get the parent navigation\n var li = nav.parentNode.closest(\"li\");\n if (!li) return;\n\n // Add the active class\n li.classList.add(settings.nestedClass);\n\n // Apply recursively to any parent navigation elements\n activateNested(li, settings);\n };\n\n /**\n * Activate a nav and content area\n * @param {Object} items The nav item and content to activate\n * @param {Object} settings The settings for this instantiation\n */\n var activate = function (items, settings) {\n // Make sure there are items to activate\n if (!items) return;\n\n // Get the parent list item\n var li = items.nav.closest(\"li\");\n if (!li) return;\n\n // Add the active class to the nav and content\n li.classList.add(settings.navClass);\n items.content.classList.add(settings.contentClass);\n\n // Activate any parent navs in a nested navigation\n activateNested(li, settings);\n\n // Emit a custom event\n emitEvent(\"gumshoeActivate\", li, {\n link: items.nav,\n content: items.content,\n settings: settings,\n });\n };\n\n /**\n * Create the Constructor object\n * @param {String} selector The selector to use for navigation items\n * @param {Object} options User options and settings\n */\n var Constructor = function (selector, options) {\n //\n // Variables\n //\n\n var publicAPIs = {};\n var navItems, contents, current, timeout, settings;\n\n //\n // Methods\n //\n\n /**\n * Set variables from DOM elements\n */\n publicAPIs.setup = function () {\n // Get all nav items\n navItems = document.querySelectorAll(selector);\n\n // Create contents array\n contents = [];\n\n // Loop through each item, get it's matching content, and push to the array\n Array.prototype.forEach.call(navItems, function (item) {\n // Get the content for the nav item\n var content = document.getElementById(\n decodeURIComponent(item.hash.substr(1)),\n );\n if (!content) return;\n\n // Push to the contents array\n contents.push({\n nav: item,\n content: content,\n });\n });\n\n // Sort contents by the order they appear in the DOM\n sortContents(contents);\n };\n\n /**\n * Detect which content is currently active\n */\n publicAPIs.detect = function () {\n // Get the active content\n var active = getActive(contents, settings);\n\n // if there's no active content, deactivate and bail\n if (!active) {\n if (current) {\n deactivate(current, settings);\n current = null;\n }\n return;\n }\n\n // If the active content is the one currently active, do nothing\n if (current && active.content === current.content) return;\n\n // Deactivate the current content and activate the new content\n deactivate(current, settings);\n activate(active, settings);\n\n // Update the currently active content\n current = active;\n };\n\n /**\n * Detect the active content on scroll\n * Debounced for performance\n */\n var scrollHandler = function (event) {\n // If there's a timer, cancel it\n if (timeout) {\n window.cancelAnimationFrame(timeout);\n }\n\n // Setup debounce callback\n timeout = window.requestAnimationFrame(publicAPIs.detect);\n };\n\n /**\n * Update content sorting on resize\n * Debounced for performance\n */\n var resizeHandler = function (event) {\n // If there's a timer, cancel it\n if (timeout) {\n window.cancelAnimationFrame(timeout);\n }\n\n // Setup debounce callback\n timeout = window.requestAnimationFrame(function () {\n sortContents(contents);\n publicAPIs.detect();\n });\n };\n\n /**\n * Destroy the current instantiation\n */\n publicAPIs.destroy = function () {\n // Undo DOM changes\n if (current) {\n deactivate(current, settings);\n }\n\n // Remove event listeners\n window.removeEventListener(\"scroll\", scrollHandler, false);\n if (settings.reflow) {\n window.removeEventListener(\"resize\", resizeHandler, false);\n }\n\n // Reset variables\n contents = null;\n navItems = null;\n current = null;\n timeout = null;\n settings = null;\n };\n\n /**\n * Initialize the current instantiation\n */\n var init = function () {\n // Merge user options into defaults\n settings = extend(defaults, options || {});\n\n // Setup variables based on the current DOM\n publicAPIs.setup();\n\n // Find the currently active content\n publicAPIs.detect();\n\n // Setup event listeners\n window.addEventListener(\"scroll\", scrollHandler, false);\n if (settings.reflow) {\n window.addEventListener(\"resize\", resizeHandler, false);\n }\n };\n\n //\n // Initialize and return the public APIs\n //\n\n init();\n return publicAPIs;\n };\n\n //\n // Return the Constructor\n //\n\n return Constructor;\n },\n);\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","import Gumshoe from \"./gumshoe-patched.js\";\n\n////////////////////////////////////////////////////////////////////////////////\n// Scroll Handling\n////////////////////////////////////////////////////////////////////////////////\nvar tocScroll = null;\nvar header = null;\nvar lastScrollTop = document.documentElement.scrollTop;\nconst GO_TO_TOP_OFFSET = 64;\n\nfunction scrollHandlerForHeader(positionY) {\n const headerTop = Math.floor(header.getBoundingClientRect().top);\n\n console.log(`headerTop: ${headerTop}`);\n if (headerTop == 0 && positionY != headerTop) {\n header.classList.add(\"scrolled\");\n } else {\n header.classList.remove(\"scrolled\");\n }\n}\n\nfunction scrollHandlerForBackToTop(positionY) {\n if (positionY < GO_TO_TOP_OFFSET) {\n document.documentElement.classList.remove(\"show-back-to-top\");\n } else {\n if (positionY < lastScrollTop) {\n document.documentElement.classList.add(\"show-back-to-top\");\n } else if (positionY > lastScrollTop) {\n document.documentElement.classList.remove(\"show-back-to-top\");\n }\n }\n lastScrollTop = positionY;\n}\n\nfunction scrollHandlerForTOC(positionY) {\n if (tocScroll === null) {\n return;\n }\n\n // top of page.\n if (positionY == 0) {\n tocScroll.scrollTo(0, 0);\n } else if (\n // bottom of page.\n Math.ceil(positionY) >=\n Math.floor(document.documentElement.scrollHeight - window.innerHeight)\n ) {\n tocScroll.scrollTo(0, tocScroll.scrollHeight);\n } else {\n // somewhere in the middle.\n const current = document.querySelector(\".scroll-current\");\n if (current == null) {\n return;\n }\n\n // https://github.com/pypa/pip/issues/9159 This breaks scroll behaviours.\n // // scroll the currently \"active\" heading in toc, into view.\n // const rect = current.getBoundingClientRect();\n // if (0 > rect.top) {\n // current.scrollIntoView(true); // the argument is \"alignTop\"\n // } else if (rect.bottom > window.innerHeight) {\n // current.scrollIntoView(false);\n // }\n }\n}\n\nfunction scrollHandler(positionY) {\n scrollHandlerForHeader(positionY);\n scrollHandlerForBackToTop(positionY);\n scrollHandlerForTOC(positionY);\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Theme Toggle\n////////////////////////////////////////////////////////////////////////////////\nfunction setTheme(mode) {\n if (mode !== \"light\" && mode !== \"dark\" && mode !== \"auto\") {\n console.error(`Got invalid theme mode: ${mode}. Resetting to auto.`);\n mode = \"auto\";\n }\n\n document.body.dataset.theme = mode;\n localStorage.setItem(\"theme\", mode);\n console.log(`Changed to ${mode} mode.`);\n}\n\nfunction cycleThemeOnce() {\n const currentTheme = localStorage.getItem(\"theme\") || \"auto\";\n const prefersDark = window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n\n if (prefersDark) {\n // Auto (dark) -> Light -> Dark\n if (currentTheme === \"auto\") {\n setTheme(\"light\");\n } else if (currentTheme == \"light\") {\n setTheme(\"dark\");\n } else {\n setTheme(\"auto\");\n }\n } else {\n // Auto (light) -> Dark -> Light\n if (currentTheme === \"auto\") {\n setTheme(\"dark\");\n } else if (currentTheme == \"dark\") {\n setTheme(\"light\");\n } else {\n setTheme(\"auto\");\n }\n }\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Setup\n////////////////////////////////////////////////////////////////////////////////\nfunction setupScrollHandler() {\n // Taken from https://developer.mozilla.org/en-US/docs/Web/API/Document/scroll_event\n let last_known_scroll_position = 0;\n let ticking = false;\n\n window.addEventListener(\"scroll\", function (e) {\n last_known_scroll_position = window.scrollY;\n\n if (!ticking) {\n window.requestAnimationFrame(function () {\n scrollHandler(last_known_scroll_position);\n ticking = false;\n });\n\n ticking = true;\n }\n });\n window.scroll();\n}\n\nfunction setupScrollSpy() {\n if (tocScroll === null) {\n return;\n }\n\n // Scrollspy -- highlight table on contents, based on scroll\n new Gumshoe(\".toc-tree a\", {\n reflow: true,\n recursive: true,\n navClass: \"scroll-current\",\n offset: () => {\n let rem = parseFloat(getComputedStyle(document.documentElement).fontSize);\n return header.getBoundingClientRect().height + 2.5 * rem + 1;\n },\n });\n}\n\nfunction setupTheme() {\n // Attach event handlers for toggling themes\n const buttons = document.getElementsByClassName(\"theme-toggle\");\n Array.from(buttons).forEach((btn) => {\n btn.addEventListener(\"click\", cycleThemeOnce);\n });\n}\n\nfunction setup() {\n setupTheme();\n setupScrollHandler();\n setupScrollSpy();\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Main entrypoint\n////////////////////////////////////////////////////////////////////////////////\nfunction main() {\n document.body.parentNode.classList.remove(\"no-js\");\n\n header = document.querySelector(\"header\");\n tocScroll = document.querySelector(\".toc-scroll\");\n\n setup();\n}\n\ndocument.addEventListener(\"DOMContentLoaded\", main);\n"],"names":["root","g","window","this","defaults","navClass","contentClass","nested","nestedClass","offset","reflow","events","emitEvent","type","elem","detail","settings","event","CustomEvent","bubbles","cancelable","dispatchEvent","getOffsetTop","location","offsetParent","offsetTop","sortContents","contents","sort","item1","item2","content","isInView","bottom","bounds","getBoundingClientRect","parseFloat","getOffset","parseInt","innerHeight","document","documentElement","clientHeight","top","isAtBottom","Math","ceil","pageYOffset","max","body","scrollHeight","offsetHeight","getActive","last","length","item","useLastItem","i","deactivateNested","nav","parentNode","li","closest","classList","remove","deactivate","items","link","activateNested","add","selector","options","navItems","current","timeout","publicAPIs","querySelectorAll","Array","prototype","forEach","call","getElementById","decodeURIComponent","hash","substr","push","active","activate","scrollHandler","cancelAnimationFrame","requestAnimationFrame","detect","resizeHandler","destroy","removeEventListener","merged","arguments","obj","key","hasOwnProperty","extend","setup","addEventListener","factory","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","exports","module","__webpack_modules__","n","getter","__esModule","d","a","definition","o","Object","defineProperty","enumerable","get","globalThis","Function","e","prop","tocScroll","header","lastScrollTop","scrollTop","GO_TO_TOP_OFFSET","cycleThemeOnce","currentTheme","localStorage","getItem","mode","matchMedia","matches","console","error","dataset","theme","setItem","log","buttons","getElementsByClassName","from","btn","setupTheme","last_known_scroll_position","ticking","scrollY","positionY","headerTop","floor","scrollHandlerForHeader","scrollHandlerForBackToTop","scrollTo","querySelector","scrollHandlerForTOC","scroll","setupScrollHandler","recursive","rem","getComputedStyle","fontSize","height"],"sourceRoot":""} \ No newline at end of file diff --git a/_static/searchtools.js b/_static/searchtools.js new file mode 100644 index 00000000..7918c3fa --- /dev/null +++ b/_static/searchtools.js @@ -0,0 +1,574 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + `Search finished, found ${resultCount} page(s) matching the search query.` + ); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent !== undefined) return docContent.textContent; + console.warn( + "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + /** + * execute search (requires search index to be loaded) + */ + query: (query) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + // array of [docname, title, anchor, descr, score, filename] + let results = []; + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + results.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id] of foundEntries) { + let score = Math.round(100 * queryLower.length / entry.length) + results.push([ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // lookup as object + objectTerms.forEach((term) => + results.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); + + // now sort the results by score (in opposite order of appearance, since the + // display function below uses pop() to retrieve items) and then + // alphabetically + results.sort((a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; + }); + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + results = results.reverse(); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord) && !terms[word]) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord) && !titleTerms[word]) + arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); + }); + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) + fileMap.get(file).push(word); + else fileMap.set(file, [word]); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords) => { + const text = Search.htmlToText(htmlText); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/_static/skeleton.css b/_static/skeleton.css new file mode 100644 index 00000000..467c878c --- /dev/null +++ b/_static/skeleton.css @@ -0,0 +1,296 @@ +/* Some sane resets. */ +html { + height: 100%; +} + +body { + margin: 0; + min-height: 100%; +} + +/* All the flexbox magic! */ +body, +.sb-announcement, +.sb-content, +.sb-main, +.sb-container, +.sb-container__inner, +.sb-article-container, +.sb-footer-content, +.sb-header, +.sb-header-secondary, +.sb-footer { + display: flex; +} + +/* These order things vertically */ +body, +.sb-main, +.sb-article-container { + flex-direction: column; +} + +/* Put elements in the center */ +.sb-header, +.sb-header-secondary, +.sb-container, +.sb-content, +.sb-footer, +.sb-footer-content { + justify-content: center; +} +/* Put elements at the ends */ +.sb-article-container { + justify-content: space-between; +} + +/* These elements grow. */ +.sb-main, +.sb-content, +.sb-container, +article { + flex-grow: 1; +} + +/* Because padding making this wider is not fun */ +article { + box-sizing: border-box; +} + +/* The announcements element should never be wider than the page. */ +.sb-announcement { + max-width: 100%; +} + +.sb-sidebar-primary, +.sb-sidebar-secondary { + flex-shrink: 0; + width: 17rem; +} + +.sb-announcement__inner { + justify-content: center; + + box-sizing: border-box; + height: 3rem; + + overflow-x: auto; + white-space: nowrap; +} + +/* Sidebars, with checkbox-based toggle */ +.sb-sidebar-primary, +.sb-sidebar-secondary { + position: fixed; + height: 100%; + top: 0; +} + +.sb-sidebar-primary { + left: -17rem; + transition: left 250ms ease-in-out; +} +.sb-sidebar-secondary { + right: -17rem; + transition: right 250ms ease-in-out; +} + +.sb-sidebar-toggle { + display: none; +} +.sb-sidebar-overlay { + position: fixed; + top: 0; + width: 0; + height: 0; + + transition: width 0ms ease 250ms, height 0ms ease 250ms, opacity 250ms ease; + + opacity: 0; + background-color: rgba(0, 0, 0, 0.54); +} + +#sb-sidebar-toggle--primary:checked + ~ .sb-sidebar-overlay[for="sb-sidebar-toggle--primary"], +#sb-sidebar-toggle--secondary:checked + ~ .sb-sidebar-overlay[for="sb-sidebar-toggle--secondary"] { + width: 100%; + height: 100%; + opacity: 1; + transition: width 0ms ease, height 0ms ease, opacity 250ms ease; +} + +#sb-sidebar-toggle--primary:checked ~ .sb-container .sb-sidebar-primary { + left: 0; +} +#sb-sidebar-toggle--secondary:checked ~ .sb-container .sb-sidebar-secondary { + right: 0; +} + +/* Full-width mode */ +.drop-secondary-sidebar-for-full-width-content + .hide-when-secondary-sidebar-shown { + display: none !important; +} +.drop-secondary-sidebar-for-full-width-content .sb-sidebar-secondary { + display: none !important; +} + +/* Mobile views */ +.sb-page-width { + width: 100%; +} + +.sb-article-container, +.sb-footer-content__inner, +.drop-secondary-sidebar-for-full-width-content .sb-article, +.drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 100vw; +} + +.sb-article, +.match-content-width { + padding: 0 1rem; + box-sizing: border-box; +} + +@media (min-width: 32rem) { + .sb-article, + .match-content-width { + padding: 0 2rem; + } +} + +/* Tablet views */ +@media (min-width: 42rem) { + .sb-article-container { + width: auto; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 42rem; + } + .sb-article, + .match-content-width { + width: 42rem; + } +} +@media (min-width: 46rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 46rem; + } + .sb-article, + .match-content-width { + width: 46rem; + } +} +@media (min-width: 50rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 50rem; + } + .sb-article, + .match-content-width { + width: 50rem; + } +} + +/* Tablet views */ +@media (min-width: 59rem) { + .sb-sidebar-secondary { + position: static; + } + .hide-when-secondary-sidebar-shown { + display: none !important; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 59rem; + } + .sb-article, + .match-content-width { + width: 42rem; + } +} +@media (min-width: 63rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 63rem; + } + .sb-article, + .match-content-width { + width: 46rem; + } +} +@media (min-width: 67rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 67rem; + } + .sb-article, + .match-content-width { + width: 50rem; + } +} + +/* Desktop views */ +@media (min-width: 76rem) { + .sb-sidebar-primary { + position: static; + } + .hide-when-primary-sidebar-shown { + display: none !important; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 59rem; + } + .sb-article, + .match-content-width { + width: 42rem; + } +} + +/* Full desktop views */ +@media (min-width: 80rem) { + .sb-article, + .match-content-width { + width: 46rem; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 63rem; + } +} + +@media (min-width: 84rem) { + .sb-article, + .match-content-width { + width: 50rem; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 67rem; + } +} + +@media (min-width: 88rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 67rem; + } + .sb-page-width { + width: 88rem; + } +} diff --git a/_static/sphinx_highlight.js b/_static/sphinx_highlight.js new file mode 100644 index 00000000..8a96c69a --- /dev/null +++ b/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/_static/styles/furo-extensions.css b/_static/styles/furo-extensions.css new file mode 100644 index 00000000..82295876 --- /dev/null +++ b/_static/styles/furo-extensions.css @@ -0,0 +1,2 @@ +#furo-sidebar-ad-placement{padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)}#furo-sidebar-ad-placement .ethical-sidebar{background:var(--color-background-secondary);border:none;box-shadow:none}#furo-sidebar-ad-placement .ethical-sidebar:hover{background:var(--color-background-hover)}#furo-sidebar-ad-placement .ethical-sidebar a{color:var(--color-foreground-primary)}#furo-sidebar-ad-placement .ethical-callout a{color:var(--color-foreground-secondary)!important}#furo-readthedocs-versions{background:transparent;display:block;position:static;width:100%}#furo-readthedocs-versions .rst-versions{background:#1a1c1e}#furo-readthedocs-versions .rst-current-version{background:var(--color-sidebar-item-background);cursor:unset}#furo-readthedocs-versions .rst-current-version:hover{background:var(--color-sidebar-item-background)}#furo-readthedocs-versions .rst-current-version .fa-book{color:var(--color-foreground-primary)}#furo-readthedocs-versions>.rst-other-versions{padding:0}#furo-readthedocs-versions>.rst-other-versions small{opacity:1}#furo-readthedocs-versions .injected .rst-versions{position:unset}#furo-readthedocs-versions:focus-within,#furo-readthedocs-versions:hover{box-shadow:0 0 0 1px var(--color-sidebar-background-border)}#furo-readthedocs-versions:focus-within .rst-current-version,#furo-readthedocs-versions:hover .rst-current-version{background:#1a1c1e;font-size:inherit;height:auto;line-height:inherit;padding:12px;text-align:right}#furo-readthedocs-versions:focus-within .rst-current-version .fa-book,#furo-readthedocs-versions:hover .rst-current-version .fa-book{color:#fff;float:left}#furo-readthedocs-versions:focus-within .fa-caret-down,#furo-readthedocs-versions:hover .fa-caret-down{display:none}#furo-readthedocs-versions:focus-within .injected,#furo-readthedocs-versions:focus-within .rst-current-version,#furo-readthedocs-versions:focus-within .rst-other-versions,#furo-readthedocs-versions:hover .injected,#furo-readthedocs-versions:hover .rst-current-version,#furo-readthedocs-versions:hover .rst-other-versions{display:block}#furo-readthedocs-versions:focus-within>.rst-current-version,#furo-readthedocs-versions:hover>.rst-current-version{display:none}.highlight:hover button.copybtn{color:var(--color-code-foreground)}.highlight button.copybtn{align-items:center;background-color:var(--color-code-background);border:none;color:var(--color-background-item);cursor:pointer;height:1.25em;right:.5rem;top:.625rem;transition:color .3s,opacity .3s;width:1.25em}.highlight button.copybtn:hover{background-color:var(--color-code-background);color:var(--color-brand-content)}.highlight button.copybtn:after{background-color:transparent;color:var(--color-code-foreground);display:none}.highlight button.copybtn.success{color:#22863a;transition:color 0ms}.highlight button.copybtn.success:after{display:block}.highlight button.copybtn svg{padding:0}body{--sd-color-primary:var(--color-brand-primary);--sd-color-primary-highlight:var(--color-brand-content);--sd-color-primary-text:var(--color-background-primary);--sd-color-shadow:rgba(0,0,0,.05);--sd-color-card-border:var(--color-card-border);--sd-color-card-border-hover:var(--color-brand-content);--sd-color-card-background:var(--color-card-background);--sd-color-card-text:var(--color-foreground-primary);--sd-color-card-header:var(--color-card-marginals-background);--sd-color-card-footer:var(--color-card-marginals-background);--sd-color-tabs-label-active:var(--color-brand-content);--sd-color-tabs-label-hover:var(--color-foreground-muted);--sd-color-tabs-label-inactive:var(--color-foreground-muted);--sd-color-tabs-underline-active:var(--color-brand-content);--sd-color-tabs-underline-hover:var(--color-foreground-border);--sd-color-tabs-underline-inactive:var(--color-background-border);--sd-color-tabs-overline:var(--color-background-border);--sd-color-tabs-underline:var(--color-background-border)}.sd-tab-content{box-shadow:0 -2px var(--sd-color-tabs-overline),0 1px var(--sd-color-tabs-underline)}.sd-card{box-shadow:0 .1rem .25rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)}.sd-shadow-sm{box-shadow:0 .1rem .25rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)!important}.sd-shadow-md{box-shadow:0 .3rem .75rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)!important}.sd-shadow-lg{box-shadow:0 .6rem 1.5rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)!important}.sd-card-hover:hover{transform:none}.sd-cards-carousel{gap:.25rem;padding:.25rem}body{--tabs--label-text:var(--color-foreground-muted);--tabs--label-text--hover:var(--color-foreground-muted);--tabs--label-text--active:var(--color-brand-content);--tabs--label-text--active--hover:var(--color-brand-content);--tabs--label-background:transparent;--tabs--label-background--hover:transparent;--tabs--label-background--active:transparent;--tabs--label-background--active--hover:transparent;--tabs--padding-x:0.25em;--tabs--margin-x:1em;--tabs--border:var(--color-background-border);--tabs--label-border:transparent;--tabs--label-border--hover:var(--color-foreground-muted);--tabs--label-border--active:var(--color-brand-content);--tabs--label-border--active--hover:var(--color-brand-content)}[role=main] .container{max-width:none;padding-left:0;padding-right:0}.shadow.docutils{border:none;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 .0625rem rgba(0,0,0,.1)!important}.sphinx-bs .card{background-color:var(--color-background-secondary);color:var(--color-foreground)} +/*# sourceMappingURL=furo-extensions.css.map*/ \ No newline at end of file diff --git a/_static/styles/furo-extensions.css.map b/_static/styles/furo-extensions.css.map new file mode 100644 index 00000000..c26eac7f --- /dev/null +++ b/_static/styles/furo-extensions.css.map @@ -0,0 +1 @@ +{"version":3,"file":"styles/furo-extensions.css","mappings":"AAGA,2BACE,oFACA,4CAKE,6CAHA,YACA,eAEA,CACA,kDACE,yCAEF,8CACE,sCAEJ,8CACE,kDAEJ,2BAGE,uBACA,cAHA,gBACA,UAEA,CAGA,yCACE,mBAEF,gDAEE,gDADA,YACA,CACA,sDACE,gDACF,yDACE,sCAEJ,+CACE,UACA,qDACE,UAGF,mDACE,eAEJ,yEAEE,4DAEA,mHASE,mBAPA,kBAEA,YADA,oBAGA,aADA,gBAIA,CAEA,qIAEE,WADA,UACA,CAEJ,uGACE,aAEF,iUAGE,cAEF,mHACE,aC1EJ,gCACE,mCAEF,0BAEE,mBAUA,8CACA,YAFA,mCAKA,eAZA,cAIA,YADA,YAYA,iCAdA,YAcA,CAEA,gCAEE,8CADA,gCACA,CAEF,gCAGE,6BADA,mCADA,YAEA,CAEF,kCAEE,cADA,oBACA,CACA,wCACE,cAEJ,8BACE,UCzCN,KAEE,6CAA8C,CAC9C,uDAAwD,CACxD,uDAAwD,CAGxD,iCAAsC,CAGtC,+CAAgD,CAChD,uDAAwD,CACxD,uDAAwD,CACxD,oDAAqD,CACrD,6DAA8D,CAC9D,6DAA8D,CAG9D,uDAAwD,CACxD,yDAA0D,CAC1D,4DAA6D,CAC7D,2DAA4D,CAC5D,8DAA+D,CAC/D,iEAAkE,CAClE,uDAAwD,CACxD,wDAAyD,CAG3D,gBACE,qFAGF,SACE,6EAEF,cACE,uFAEF,cACE,uFAEF,cACE,uFAGF,qBACE,eAEF,mBACE,WACA,eChDF,KACE,gDAAiD,CACjD,uDAAwD,CACxD,qDAAsD,CACtD,4DAA6D,CAC7D,oCAAqC,CACrC,2CAA4C,CAC5C,4CAA6C,CAC7C,mDAAoD,CACpD,wBAAyB,CACzB,oBAAqB,CACrB,6CAA8C,CAC9C,gCAAiC,CACjC,yDAA0D,CAC1D,uDAAwD,CACxD,8DAA+D,CCbjE,uBACE,eACA,eACA,gBAGF,iBACE,YACA,+EAGF,iBACE,mDACA","sources":["webpack:///./src/furo/assets/styles/extensions/_readthedocs.sass","webpack:///./src/furo/assets/styles/extensions/_copybutton.sass","webpack:///./src/furo/assets/styles/extensions/_sphinx-design.sass","webpack:///./src/furo/assets/styles/extensions/_sphinx-inline-tabs.sass","webpack:///./src/furo/assets/styles/extensions/_sphinx-panels.sass"],"sourcesContent":["// This file contains the styles used for tweaking how ReadTheDoc's embedded\n// contents would show up inside the theme.\n\n#furo-sidebar-ad-placement\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n .ethical-sidebar\n // Remove the border and box-shadow.\n border: none\n box-shadow: none\n // Manage the background colors.\n background: var(--color-background-secondary)\n &:hover\n background: var(--color-background-hover)\n // Ensure the text is legible.\n a\n color: var(--color-foreground-primary)\n\n .ethical-callout a\n color: var(--color-foreground-secondary) !important\n\n#furo-readthedocs-versions\n position: static\n width: 100%\n background: transparent\n display: block\n\n // Make the background color fit with the theme's aesthetic.\n .rst-versions\n background: rgb(26, 28, 30)\n\n .rst-current-version\n cursor: unset\n background: var(--color-sidebar-item-background)\n &:hover\n background: var(--color-sidebar-item-background)\n .fa-book\n color: var(--color-foreground-primary)\n\n > .rst-other-versions\n padding: 0\n small\n opacity: 1\n\n .injected\n .rst-versions\n position: unset\n\n &:hover,\n &:focus-within\n box-shadow: 0 0 0 1px var(--color-sidebar-background-border)\n\n .rst-current-version\n // Undo the tweaks done in RTD's CSS\n font-size: inherit\n line-height: inherit\n height: auto\n text-align: right\n padding: 12px\n\n // Match the rest of the body\n background: #1a1c1e\n\n .fa-book\n float: left\n color: white\n\n .fa-caret-down\n display: none\n\n .rst-current-version,\n .rst-other-versions,\n .injected\n display: block\n\n > .rst-current-version\n display: none\n",".highlight\n &:hover button.copybtn\n color: var(--color-code-foreground)\n\n button.copybtn\n // Align things correctly\n align-items: center\n\n height: 1.25em\n width: 1.25em\n\n top: 0.625rem // $code-spacing-vertical\n right: 0.5rem\n\n // Make it look better\n color: var(--color-background-item)\n background-color: var(--color-code-background)\n border: none\n\n // Change to cursor to make it obvious that you can click on it\n cursor: pointer\n\n // Transition smoothly, for aesthetics\n transition: color 300ms, opacity 300ms\n\n &:hover\n color: var(--color-brand-content)\n background-color: var(--color-code-background)\n\n &::after\n display: none\n color: var(--color-code-foreground)\n background-color: transparent\n\n &.success\n transition: color 0ms\n color: #22863a\n &::after\n display: block\n\n svg\n padding: 0\n","body\n // Colors\n --sd-color-primary: var(--color-brand-primary)\n --sd-color-primary-highlight: var(--color-brand-content)\n --sd-color-primary-text: var(--color-background-primary)\n\n // Shadows\n --sd-color-shadow: rgba(0, 0, 0, 0.05)\n\n // Cards\n --sd-color-card-border: var(--color-card-border)\n --sd-color-card-border-hover: var(--color-brand-content)\n --sd-color-card-background: var(--color-card-background)\n --sd-color-card-text: var(--color-foreground-primary)\n --sd-color-card-header: var(--color-card-marginals-background)\n --sd-color-card-footer: var(--color-card-marginals-background)\n\n // Tabs\n --sd-color-tabs-label-active: var(--color-brand-content)\n --sd-color-tabs-label-hover: var(--color-foreground-muted)\n --sd-color-tabs-label-inactive: var(--color-foreground-muted)\n --sd-color-tabs-underline-active: var(--color-brand-content)\n --sd-color-tabs-underline-hover: var(--color-foreground-border)\n --sd-color-tabs-underline-inactive: var(--color-background-border)\n --sd-color-tabs-overline: var(--color-background-border)\n --sd-color-tabs-underline: var(--color-background-border)\n\n// Tabs\n.sd-tab-content\n box-shadow: 0 -2px var(--sd-color-tabs-overline), 0 1px var(--sd-color-tabs-underline)\n\n// Shadows\n.sd-card // Have a shadow by default\n box-shadow: 0 0.1rem 0.25rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1)\n\n.sd-shadow-sm\n box-shadow: 0 0.1rem 0.25rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n.sd-shadow-md\n box-shadow: 0 0.3rem 0.75rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n.sd-shadow-lg\n box-shadow: 0 0.6rem 1.5rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n// Cards\n.sd-card-hover:hover // Don't change scale on hover\n transform: none\n\n.sd-cards-carousel // Have a bit of gap in the carousel by default\n gap: 0.25rem\n padding: 0.25rem\n","// This file contains styles to tweak sphinx-inline-tabs to work well with Furo.\n\nbody\n --tabs--label-text: var(--color-foreground-muted)\n --tabs--label-text--hover: var(--color-foreground-muted)\n --tabs--label-text--active: var(--color-brand-content)\n --tabs--label-text--active--hover: var(--color-brand-content)\n --tabs--label-background: transparent\n --tabs--label-background--hover: transparent\n --tabs--label-background--active: transparent\n --tabs--label-background--active--hover: transparent\n --tabs--padding-x: 0.25em\n --tabs--margin-x: 1em\n --tabs--border: var(--color-background-border)\n --tabs--label-border: transparent\n --tabs--label-border--hover: var(--color-foreground-muted)\n --tabs--label-border--active: var(--color-brand-content)\n --tabs--label-border--active--hover: var(--color-brand-content)\n","// This file contains styles to tweak sphinx-panels to work well with Furo.\n\n// sphinx-panels includes Bootstrap 4, which uses .container which can conflict\n// with docutils' `.. container::` directive.\n[role=\"main\"] .container\n max-width: initial\n padding-left: initial\n padding-right: initial\n\n// Make the panels look nicer!\n.shadow.docutils\n border: none\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n// Make panel colors respond to dark mode\n.sphinx-bs .card\n background-color: var(--color-background-secondary)\n color: var(--color-foreground)\n"],"names":[],"sourceRoot":""} \ No newline at end of file diff --git a/_static/styles/furo.css b/_static/styles/furo.css new file mode 100644 index 00000000..05a56b17 --- /dev/null +++ b/_static/styles/furo.css @@ -0,0 +1,2 @@ +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}[hidden],template{display:none}@media print{.content-icon-container,.headerlink,.mobile-header,.related-pages{display:none!important}.highlight{border:.1pt solid var(--color-foreground-border)}a,blockquote,dl,ol,p,pre,table,ul{page-break-inside:avoid}caption,figure,h1,h2,h3,h4,h5,h6,img{page-break-after:avoid;page-break-inside:avoid}dl,ol,ul{page-break-before:avoid}}.visually-hidden{height:1px!important;margin:-1px!important;overflow:hidden!important;padding:0!important;position:absolute!important;width:1px!important;clip:rect(0,0,0,0)!important;background:var(--color-background-primary);border:0!important;color:var(--color-foreground-primary);white-space:nowrap!important}:-moz-focusring{outline:auto}body{--font-stack:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;--font-stack--monospace:"SFMono-Regular",Menlo,Consolas,Monaco,Liberation Mono,Lucida Console,monospace;--font-stack--headings:var(--font-stack);--font-size--normal:100%;--font-size--small:87.5%;--font-size--small--2:81.25%;--font-size--small--3:75%;--font-size--small--4:62.5%;--sidebar-caption-font-size:var(--font-size--small--2);--sidebar-item-font-size:var(--font-size--small);--sidebar-search-input-font-size:var(--font-size--small);--toc-font-size:var(--font-size--small--3);--toc-font-size--mobile:var(--font-size--normal);--toc-title-font-size:var(--font-size--small--4);--admonition-font-size:0.8125rem;--admonition-title-font-size:0.8125rem;--code-font-size:var(--font-size--small--2);--api-font-size:var(--font-size--small);--header-height:calc(var(--sidebar-item-line-height) + var(--sidebar-item-spacing-vertical)*4);--header-padding:0.5rem;--sidebar-tree-space-above:1.5rem;--sidebar-caption-space-above:1rem;--sidebar-item-line-height:1rem;--sidebar-item-spacing-vertical:0.5rem;--sidebar-item-spacing-horizontal:1rem;--sidebar-item-height:calc(var(--sidebar-item-line-height) + var(--sidebar-item-spacing-vertical)*2);--sidebar-expander-width:var(--sidebar-item-height);--sidebar-search-space-above:0.5rem;--sidebar-search-input-spacing-vertical:0.5rem;--sidebar-search-input-spacing-horizontal:0.5rem;--sidebar-search-input-height:1rem;--sidebar-search-icon-size:var(--sidebar-search-input-height);--toc-title-padding:0.25rem 0;--toc-spacing-vertical:1.5rem;--toc-spacing-horizontal:1.5rem;--toc-item-spacing-vertical:0.4rem;--toc-item-spacing-horizontal:1rem;--icon-search:url('data:image/svg+xml;charset=utf-8,');--icon-pencil:url('data:image/svg+xml;charset=utf-8,');--icon-abstract:url('data:image/svg+xml;charset=utf-8,');--icon-info:url('data:image/svg+xml;charset=utf-8,');--icon-flame:url('data:image/svg+xml;charset=utf-8,');--icon-question:url('data:image/svg+xml;charset=utf-8,');--icon-warning:url('data:image/svg+xml;charset=utf-8,');--icon-failure:url('data:image/svg+xml;charset=utf-8,');--icon-spark:url('data:image/svg+xml;charset=utf-8,');--color-admonition-title--caution:#ff9100;--color-admonition-title-background--caution:rgba(255,145,0,.2);--color-admonition-title--warning:#ff9100;--color-admonition-title-background--warning:rgba(255,145,0,.2);--color-admonition-title--danger:#ff5252;--color-admonition-title-background--danger:rgba(255,82,82,.2);--color-admonition-title--attention:#ff5252;--color-admonition-title-background--attention:rgba(255,82,82,.2);--color-admonition-title--error:#ff5252;--color-admonition-title-background--error:rgba(255,82,82,.2);--color-admonition-title--hint:#00c852;--color-admonition-title-background--hint:rgba(0,200,82,.2);--color-admonition-title--tip:#00c852;--color-admonition-title-background--tip:rgba(0,200,82,.2);--color-admonition-title--important:#00bfa5;--color-admonition-title-background--important:rgba(0,191,165,.2);--color-admonition-title--note:#00b0ff;--color-admonition-title-background--note:rgba(0,176,255,.2);--color-admonition-title--seealso:#448aff;--color-admonition-title-background--seealso:rgba(68,138,255,.2);--color-admonition-title--admonition-todo:grey;--color-admonition-title-background--admonition-todo:hsla(0,0%,50%,.2);--color-admonition-title:#651fff;--color-admonition-title-background:rgba(101,31,255,.2);--icon-admonition-default:var(--icon-abstract);--color-topic-title:#14b8a6;--color-topic-title-background:rgba(20,184,166,.2);--icon-topic-default:var(--icon-pencil);--color-problematic:#b30000;--color-foreground-primary:#000;--color-foreground-secondary:#5a5c63;--color-foreground-muted:#6b6f76;--color-foreground-border:#878787;--color-background-primary:#fff;--color-background-secondary:#f8f9fb;--color-background-hover:#efeff4;--color-background-hover--transparent:#efeff400;--color-background-border:#eeebee;--color-background-item:#ccc;--color-announcement-background:#000000dd;--color-announcement-text:#eeebee;--color-brand-primary:#0a4bff;--color-brand-content:#2757dd;--color-brand-visited:#872ee0;--color-api-background:var(--color-background-hover--transparent);--color-api-background-hover:var(--color-background-hover);--color-api-overall:var(--color-foreground-secondary);--color-api-name:var(--color-problematic);--color-api-pre-name:var(--color-problematic);--color-api-paren:var(--color-foreground-secondary);--color-api-keyword:var(--color-foreground-primary);--color-api-added:#21632c;--color-api-added-border:#38a84d;--color-api-changed:#046172;--color-api-changed-border:#06a1bc;--color-api-deprecated:#605706;--color-api-deprecated-border:#f0d90f;--color-api-removed:#b30000;--color-api-removed-border:#ff5c5c;--color-highlight-on-target:#ffc;--color-inline-code-background:var(--color-background-secondary);--color-highlighted-background:#def;--color-highlighted-text:var(--color-foreground-primary);--color-guilabel-background:#ddeeff80;--color-guilabel-border:#bedaf580;--color-guilabel-text:var(--color-foreground-primary);--color-admonition-background:transparent;--color-table-header-background:var(--color-background-secondary);--color-table-border:var(--color-background-border);--color-card-border:var(--color-background-secondary);--color-card-background:transparent;--color-card-marginals-background:var(--color-background-secondary);--color-header-background:var(--color-background-primary);--color-header-border:var(--color-background-border);--color-header-text:var(--color-foreground-primary);--color-sidebar-background:var(--color-background-secondary);--color-sidebar-background-border:var(--color-background-border);--color-sidebar-brand-text:var(--color-foreground-primary);--color-sidebar-caption-text:var(--color-foreground-muted);--color-sidebar-link-text:var(--color-foreground-secondary);--color-sidebar-link-text--top-level:var(--color-brand-primary);--color-sidebar-item-background:var(--color-sidebar-background);--color-sidebar-item-background--current:var( --color-sidebar-item-background );--color-sidebar-item-background--hover:linear-gradient(90deg,var(--color-background-hover--transparent) 0%,var(--color-background-hover) var(--sidebar-item-spacing-horizontal),var(--color-background-hover) 100%);--color-sidebar-item-expander-background:transparent;--color-sidebar-item-expander-background--hover:var( --color-background-hover );--color-sidebar-search-text:var(--color-foreground-primary);--color-sidebar-search-background:var(--color-background-secondary);--color-sidebar-search-background--focus:var(--color-background-primary);--color-sidebar-search-border:var(--color-background-border);--color-sidebar-search-icon:var(--color-foreground-muted);--color-toc-background:var(--color-background-primary);--color-toc-title-text:var(--color-foreground-muted);--color-toc-item-text:var(--color-foreground-secondary);--color-toc-item-text--hover:var(--color-foreground-primary);--color-toc-item-text--active:var(--color-brand-primary);--color-content-foreground:var(--color-foreground-primary);--color-content-background:transparent;--color-link:var(--color-brand-content);--color-link-underline:var(--color-background-border);--color-link--hover:var(--color-brand-content);--color-link-underline--hover:var(--color-foreground-border);--color-link--visited:var(--color-brand-visited);--color-link-underline--visited:var(--color-background-border);--color-link--visited--hover:var(--color-brand-visited);--color-link-underline--visited--hover:var(--color-foreground-border)}.only-light{display:block!important}html body .only-dark{display:none!important}@media not print{body[data-theme=dark]{--color-problematic:#ee5151;--color-foreground-primary:#cfd0d0;--color-foreground-secondary:#9ca0a5;--color-foreground-muted:#81868d;--color-foreground-border:#666;--color-background-primary:#131416;--color-background-secondary:#1a1c1e;--color-background-hover:#1e2124;--color-background-hover--transparent:#1e212400;--color-background-border:#303335;--color-background-item:#444;--color-announcement-background:#000000dd;--color-announcement-text:#eeebee;--color-brand-primary:#3d94ff;--color-brand-content:#5ca5ff;--color-brand-visited:#b27aeb;--color-highlighted-background:#083563;--color-guilabel-background:#08356380;--color-guilabel-border:#13395f80;--color-api-keyword:var(--color-foreground-secondary);--color-highlight-on-target:#330;--color-api-added:#3db854;--color-api-added-border:#267334;--color-api-changed:#09b0ce;--color-api-changed-border:#056d80;--color-api-deprecated:#b1a10b;--color-api-deprecated-border:#6e6407;--color-api-removed:#ff7575;--color-api-removed-border:#b03b3b;--color-admonition-background:#18181a;--color-card-border:var(--color-background-secondary);--color-card-background:#18181a;--color-card-marginals-background:var(--color-background-hover)}html body[data-theme=dark] .only-light{display:none!important}body[data-theme=dark] .only-dark{display:block!important}@media(prefers-color-scheme:dark){body:not([data-theme=light]){--color-problematic:#ee5151;--color-foreground-primary:#cfd0d0;--color-foreground-secondary:#9ca0a5;--color-foreground-muted:#81868d;--color-foreground-border:#666;--color-background-primary:#131416;--color-background-secondary:#1a1c1e;--color-background-hover:#1e2124;--color-background-hover--transparent:#1e212400;--color-background-border:#303335;--color-background-item:#444;--color-announcement-background:#000000dd;--color-announcement-text:#eeebee;--color-brand-primary:#3d94ff;--color-brand-content:#5ca5ff;--color-brand-visited:#b27aeb;--color-highlighted-background:#083563;--color-guilabel-background:#08356380;--color-guilabel-border:#13395f80;--color-api-keyword:var(--color-foreground-secondary);--color-highlight-on-target:#330;--color-api-added:#3db854;--color-api-added-border:#267334;--color-api-changed:#09b0ce;--color-api-changed-border:#056d80;--color-api-deprecated:#b1a10b;--color-api-deprecated-border:#6e6407;--color-api-removed:#ff7575;--color-api-removed-border:#b03b3b;--color-admonition-background:#18181a;--color-card-border:var(--color-background-secondary);--color-card-background:#18181a;--color-card-marginals-background:var(--color-background-hover)}html body:not([data-theme=light]) .only-light{display:none!important}body:not([data-theme=light]) .only-dark{display:block!important}}}body[data-theme=auto] .theme-toggle svg.theme-icon-when-auto-light{display:block}@media(prefers-color-scheme:dark){body[data-theme=auto] .theme-toggle svg.theme-icon-when-auto-dark{display:block}body[data-theme=auto] .theme-toggle svg.theme-icon-when-auto-light{display:none}}body[data-theme=dark] .theme-toggle svg.theme-icon-when-dark,body[data-theme=light] .theme-toggle svg.theme-icon-when-light{display:block}body{font-family:var(--font-stack)}code,kbd,pre,samp{font-family:var(--font-stack--monospace)}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}article{line-height:1.5}h1,h2,h3,h4,h5,h6{border-radius:.5rem;font-family:var(--font-stack--headings);font-weight:700;line-height:1.25;margin:.5rem -.5rem;padding-left:.5rem;padding-right:.5rem}h1+p,h2+p,h3+p,h4+p,h5+p,h6+p{margin-top:0}h1{font-size:2.5em;margin-bottom:1rem}h1,h2{margin-top:1.75rem}h2{font-size:2em}h3{font-size:1.5em}h4{font-size:1.25em}h5{font-size:1.125em}h6{font-size:1em}small{font-size:80%;opacity:75%}p{margin-bottom:.75rem;margin-top:.5rem}hr.docutils{background-color:var(--color-background-border);border:0;height:1px;margin:2rem 0;padding:0}.centered{text-align:center}a{color:var(--color-link);text-decoration:underline;text-decoration-color:var(--color-link-underline)}a:visited{color:var(--color-link--visited);text-decoration-color:var(--color-link-underline--visited)}a:visited:hover{color:var(--color-link--visited--hover);text-decoration-color:var(--color-link-underline--visited--hover)}a:hover{color:var(--color-link--hover);text-decoration-color:var(--color-link-underline--hover)}a.muted-link{color:inherit}a.muted-link:hover{color:var(--color-link--hover);text-decoration-color:var(--color-link-underline--hover)}a.muted-link:hover:visited{color:var(--color-link--visited--hover);text-decoration-color:var(--color-link-underline--visited--hover)}html{overflow-x:hidden;overflow-y:scroll;scroll-behavior:smooth}.sidebar-scroll,.toc-scroll,article[role=main] *{scrollbar-color:var(--color-foreground-border) transparent;scrollbar-width:thin}.sidebar-scroll::-webkit-scrollbar,.toc-scroll::-webkit-scrollbar,article[role=main] ::-webkit-scrollbar{height:.25rem;width:.25rem}.sidebar-scroll::-webkit-scrollbar-thumb,.toc-scroll::-webkit-scrollbar-thumb,article[role=main] ::-webkit-scrollbar-thumb{background-color:var(--color-foreground-border);border-radius:.125rem}body,html{height:100%}.skip-to-content,body,html{background:var(--color-background-primary);color:var(--color-foreground-primary)}.skip-to-content{border-radius:1rem;left:.25rem;padding:1rem;position:fixed;top:.25rem;transform:translateY(-200%);transition:transform .3s ease-in-out;z-index:40}.skip-to-content:focus-within{transform:translateY(0)}article{background:var(--color-content-background);color:var(--color-content-foreground);overflow-wrap:break-word}.page{display:flex;min-height:100%}.mobile-header{background-color:var(--color-header-background);border-bottom:1px solid var(--color-header-border);color:var(--color-header-text);display:none;height:var(--header-height);width:100%;z-index:10}.mobile-header.scrolled{border-bottom:none;box-shadow:0 0 .2rem rgba(0,0,0,.1),0 .2rem .4rem rgba(0,0,0,.2)}.mobile-header .header-center a{color:var(--color-header-text);text-decoration:none}.main{display:flex;flex:1}.sidebar-drawer{background:var(--color-sidebar-background);border-right:1px solid var(--color-sidebar-background-border);box-sizing:border-box;display:flex;justify-content:flex-end;min-width:15em;width:calc(50% - 26em)}.sidebar-container,.toc-drawer{box-sizing:border-box;width:15em}.toc-drawer{background:var(--color-toc-background);padding-right:1rem}.sidebar-sticky,.toc-sticky{display:flex;flex-direction:column;height:min(100%,100vh);height:100vh;position:sticky;top:0}.sidebar-scroll,.toc-scroll{flex-grow:1;flex-shrink:1;overflow:auto;scroll-behavior:smooth}.content{display:flex;flex-direction:column;justify-content:space-between;padding:0 3em;width:46em}.icon{display:inline-block;height:1rem;width:1rem}.icon svg{height:100%;width:100%}.announcement{align-items:center;background-color:var(--color-announcement-background);color:var(--color-announcement-text);display:flex;height:var(--header-height);overflow-x:auto}.announcement+.page{min-height:calc(100% - var(--header-height))}.announcement-content{box-sizing:border-box;min-width:100%;padding:.5rem;text-align:center;white-space:nowrap}.announcement-content a{color:var(--color-announcement-text);text-decoration-color:var(--color-announcement-text)}.announcement-content a:hover{color:var(--color-announcement-text);text-decoration-color:var(--color-link--hover)}.no-js .theme-toggle-container{display:none}.theme-toggle-container{display:flex}.theme-toggle{background:transparent;border:none;cursor:pointer;display:flex;padding:0}.theme-toggle svg{color:var(--color-foreground-primary);display:none;height:1.25rem;width:1.25rem}.theme-toggle-header{align-items:center;display:flex;justify-content:center}.nav-overlay-icon,.toc-overlay-icon{cursor:pointer;display:none}.nav-overlay-icon .icon,.toc-overlay-icon .icon{color:var(--color-foreground-secondary);height:1.5rem;width:1.5rem}.nav-overlay-icon,.toc-header-icon{align-items:center;justify-content:center}.toc-content-icon{height:1.5rem;width:1.5rem}.content-icon-container{display:flex;float:right;gap:.5rem;margin-bottom:1rem;margin-left:1rem;margin-top:1.5rem}.content-icon-container .edit-this-page svg,.content-icon-container .view-this-page svg{color:inherit;height:1.25rem;width:1.25rem}.sidebar-toggle{display:none;position:absolute}.sidebar-toggle[name=__toc]{left:20px}.sidebar-toggle:checked{left:40px}.overlay{background-color:rgba(0,0,0,.54);height:0;opacity:0;position:fixed;top:0;transition:width 0ms,height 0ms,opacity .25s ease-out;width:0}.sidebar-overlay{z-index:20}.toc-overlay{z-index:40}.sidebar-drawer{transition:left .25s ease-in-out;z-index:30}.toc-drawer{transition:right .25s ease-in-out;z-index:50}#__navigation:checked~.sidebar-overlay{height:100%;opacity:1;width:100%}#__navigation:checked~.page .sidebar-drawer{left:0;top:0}#__toc:checked~.toc-overlay{height:100%;opacity:1;width:100%}#__toc:checked~.page .toc-drawer{right:0;top:0}.back-to-top{background:var(--color-background-primary);border-radius:1rem;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 1px 0 hsla(220,9%,46%,.502);display:none;font-size:.8125rem;left:0;margin-left:50%;padding:.5rem .75rem .5rem .5rem;position:fixed;text-decoration:none;top:1rem;transform:translateX(-50%);z-index:10}.back-to-top svg{height:1rem;width:1rem;fill:currentColor;display:inline-block}.back-to-top span{margin-left:.25rem}.show-back-to-top .back-to-top{align-items:center;display:flex}@media(min-width:97em){html{font-size:110%}}@media(max-width:82em){.toc-content-icon{display:flex}.toc-drawer{border-left:1px solid var(--color-background-muted);height:100vh;position:fixed;right:-15em;top:0}.toc-tree{border-left:none;font-size:var(--toc-font-size--mobile)}.sidebar-drawer{width:calc(50% - 18.5em)}}@media(max-width:67em){.content{margin-left:auto;margin-right:auto;padding:0 1em}}@media(max-width:63em){.nav-overlay-icon{display:flex}.sidebar-drawer{height:100vh;left:-15em;position:fixed;top:0;width:15em}.theme-toggle-header,.toc-header-icon{display:flex}.theme-toggle-content,.toc-content-icon{display:none}.mobile-header{align-items:center;display:flex;justify-content:space-between;position:sticky;top:0}.mobile-header .header-left,.mobile-header .header-right{display:flex;height:var(--header-height);padding:0 var(--header-padding)}.mobile-header .header-left label,.mobile-header .header-right label{height:100%;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:100%}.nav-overlay-icon .icon,.theme-toggle svg{height:1.5rem;width:1.5rem}:target{scroll-margin-top:calc(var(--header-height) + 2.5rem)}.back-to-top{top:calc(var(--header-height) + .5rem)}.page{flex-direction:column;justify-content:center}}@media(max-width:48em){.content{overflow-x:auto;width:100%}}@media(max-width:46em){article[role=main] aside.sidebar{float:none;margin:1rem 0;width:100%}}.admonition,.topic{background:var(--color-admonition-background);border-radius:.2rem;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 .0625rem rgba(0,0,0,.1);font-size:var(--admonition-font-size);margin:1rem auto;overflow:hidden;padding:0 .5rem .5rem;page-break-inside:avoid}.admonition>:nth-child(2),.topic>:nth-child(2){margin-top:0}.admonition>:last-child,.topic>:last-child{margin-bottom:0}.admonition p.admonition-title,p.topic-title{font-size:var(--admonition-title-font-size);font-weight:500;line-height:1.3;margin:0 -.5rem .5rem;padding:.4rem .5rem .4rem 2rem;position:relative}.admonition p.admonition-title:before,p.topic-title:before{content:"";height:1rem;left:.5rem;position:absolute;width:1rem}p.admonition-title{background-color:var(--color-admonition-title-background)}p.admonition-title:before{background-color:var(--color-admonition-title);-webkit-mask-image:var(--icon-admonition-default);mask-image:var(--icon-admonition-default);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}p.topic-title{background-color:var(--color-topic-title-background)}p.topic-title:before{background-color:var(--color-topic-title);-webkit-mask-image:var(--icon-topic-default);mask-image:var(--icon-topic-default);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}.admonition{border-left:.2rem solid var(--color-admonition-title)}.admonition.caution{border-left-color:var(--color-admonition-title--caution)}.admonition.caution>.admonition-title{background-color:var(--color-admonition-title-background--caution)}.admonition.caution>.admonition-title:before{background-color:var(--color-admonition-title--caution);-webkit-mask-image:var(--icon-spark);mask-image:var(--icon-spark)}.admonition.warning{border-left-color:var(--color-admonition-title--warning)}.admonition.warning>.admonition-title{background-color:var(--color-admonition-title-background--warning)}.admonition.warning>.admonition-title:before{background-color:var(--color-admonition-title--warning);-webkit-mask-image:var(--icon-warning);mask-image:var(--icon-warning)}.admonition.danger{border-left-color:var(--color-admonition-title--danger)}.admonition.danger>.admonition-title{background-color:var(--color-admonition-title-background--danger)}.admonition.danger>.admonition-title:before{background-color:var(--color-admonition-title--danger);-webkit-mask-image:var(--icon-spark);mask-image:var(--icon-spark)}.admonition.attention{border-left-color:var(--color-admonition-title--attention)}.admonition.attention>.admonition-title{background-color:var(--color-admonition-title-background--attention)}.admonition.attention>.admonition-title:before{background-color:var(--color-admonition-title--attention);-webkit-mask-image:var(--icon-warning);mask-image:var(--icon-warning)}.admonition.error{border-left-color:var(--color-admonition-title--error)}.admonition.error>.admonition-title{background-color:var(--color-admonition-title-background--error)}.admonition.error>.admonition-title:before{background-color:var(--color-admonition-title--error);-webkit-mask-image:var(--icon-failure);mask-image:var(--icon-failure)}.admonition.hint{border-left-color:var(--color-admonition-title--hint)}.admonition.hint>.admonition-title{background-color:var(--color-admonition-title-background--hint)}.admonition.hint>.admonition-title:before{background-color:var(--color-admonition-title--hint);-webkit-mask-image:var(--icon-question);mask-image:var(--icon-question)}.admonition.tip{border-left-color:var(--color-admonition-title--tip)}.admonition.tip>.admonition-title{background-color:var(--color-admonition-title-background--tip)}.admonition.tip>.admonition-title:before{background-color:var(--color-admonition-title--tip);-webkit-mask-image:var(--icon-info);mask-image:var(--icon-info)}.admonition.important{border-left-color:var(--color-admonition-title--important)}.admonition.important>.admonition-title{background-color:var(--color-admonition-title-background--important)}.admonition.important>.admonition-title:before{background-color:var(--color-admonition-title--important);-webkit-mask-image:var(--icon-flame);mask-image:var(--icon-flame)}.admonition.note{border-left-color:var(--color-admonition-title--note)}.admonition.note>.admonition-title{background-color:var(--color-admonition-title-background--note)}.admonition.note>.admonition-title:before{background-color:var(--color-admonition-title--note);-webkit-mask-image:var(--icon-pencil);mask-image:var(--icon-pencil)}.admonition.seealso{border-left-color:var(--color-admonition-title--seealso)}.admonition.seealso>.admonition-title{background-color:var(--color-admonition-title-background--seealso)}.admonition.seealso>.admonition-title:before{background-color:var(--color-admonition-title--seealso);-webkit-mask-image:var(--icon-info);mask-image:var(--icon-info)}.admonition.admonition-todo{border-left-color:var(--color-admonition-title--admonition-todo)}.admonition.admonition-todo>.admonition-title{background-color:var(--color-admonition-title-background--admonition-todo)}.admonition.admonition-todo>.admonition-title:before{background-color:var(--color-admonition-title--admonition-todo);-webkit-mask-image:var(--icon-pencil);mask-image:var(--icon-pencil)}.admonition-todo>.admonition-title{text-transform:uppercase}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd{margin-left:2rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd>:first-child{margin-top:.125rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list,dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd>:last-child{margin-bottom:.75rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list>dt{font-size:var(--font-size--small);text-transform:uppercase}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd:empty{margin-bottom:.5rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd>ul{margin-left:-1.2rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd>ul>li>p:nth-child(2){margin-top:0}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd>ul>li>p+p:last-child:empty{margin-bottom:0;margin-top:0}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt{color:var(--color-api-overall)}.sig:not(.sig-inline){background:var(--color-api-background);border-radius:.25rem;font-family:var(--font-stack--monospace);font-size:var(--api-font-size);font-weight:700;margin-left:-.25rem;margin-right:-.25rem;padding:.25rem .5rem .25rem 3em;text-indent:-2.5em;transition:background .1s ease-out}.sig:not(.sig-inline):hover{background:var(--color-api-background-hover)}.sig:not(.sig-inline) a.reference .viewcode-link{font-weight:400;width:4.25rem}em.property{font-style:normal}em.property:first-child{color:var(--color-api-keyword)}.sig-name{color:var(--color-api-name)}.sig-prename{color:var(--color-api-pre-name);font-weight:400}.sig-paren{color:var(--color-api-paren)}.sig-param{font-style:normal}div.deprecated,div.versionadded,div.versionchanged,div.versionremoved{border-left:.1875rem solid;border-radius:.125rem;padding-left:.75rem}div.deprecated p,div.versionadded p,div.versionchanged p,div.versionremoved p{margin-bottom:.125rem;margin-top:.125rem}div.versionadded{border-color:var(--color-api-added-border)}div.versionadded .versionmodified{color:var(--color-api-added)}div.versionchanged{border-color:var(--color-api-changed-border)}div.versionchanged .versionmodified{color:var(--color-api-changed)}div.deprecated{border-color:var(--color-api-deprecated-border)}div.deprecated .versionmodified{color:var(--color-api-deprecated)}div.versionremoved{border-color:var(--color-api-removed-border)}div.versionremoved .versionmodified{color:var(--color-api-removed)}.viewcode-back,.viewcode-link{float:right;text-align:right}.line-block{margin-bottom:.75rem;margin-top:.5rem}.line-block .line-block{margin-bottom:0;margin-top:0;padding-left:1rem}.code-block-caption,article p.caption,table>caption{font-size:var(--font-size--small);text-align:center}.toctree-wrapper.compound .caption,.toctree-wrapper.compound :not(.caption)>.caption-text{font-size:var(--font-size--small);margin-bottom:0;text-align:initial;text-transform:uppercase}.toctree-wrapper.compound>ul{margin-bottom:0;margin-top:0}.sig-inline,code.literal{background:var(--color-inline-code-background);border-radius:.2em;font-size:var(--font-size--small--2);padding:.1em .2em}pre.literal-block .sig-inline,pre.literal-block code.literal{font-size:inherit;padding:0}p .sig-inline,p code.literal{border:1px solid var(--color-background-border)}.sig-inline{font-family:var(--font-stack--monospace)}div[class*=" highlight-"],div[class^=highlight-]{display:flex;margin:1em 0}div[class*=" highlight-"] .table-wrapper,div[class^=highlight-] .table-wrapper,pre{margin:0;padding:0}pre{overflow:auto}article[role=main] .highlight pre{line-height:1.5}.highlight pre,pre.literal-block{font-size:var(--code-font-size);padding:.625rem .875rem}pre.literal-block{background-color:var(--color-code-background);border-radius:.2rem;color:var(--color-code-foreground);margin-bottom:1rem;margin-top:1rem}.highlight{border-radius:.2rem;width:100%}.highlight .gp,.highlight span.linenos{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.highlight .hll{display:block;margin-left:-.875rem;margin-right:-.875rem;padding-left:.875rem;padding-right:.875rem}.code-block-caption{background-color:var(--color-code-background);border-bottom:1px solid;border-radius:.25rem;border-bottom-left-radius:0;border-bottom-right-radius:0;border-color:var(--color-background-border);color:var(--color-code-foreground);display:flex;font-weight:300;padding:.625rem .875rem}.code-block-caption+div[class]{margin-top:0}.code-block-caption+div[class] pre{border-top-left-radius:0;border-top-right-radius:0}.highlighttable{display:block;width:100%}.highlighttable tbody{display:block}.highlighttable tr{display:flex}.highlighttable td.linenos{background-color:var(--color-code-background);border-bottom-left-radius:.2rem;border-top-left-radius:.2rem;color:var(--color-code-foreground);padding:.625rem 0 .625rem .875rem}.highlighttable .linenodiv{box-shadow:-.0625rem 0 var(--color-foreground-border) inset;font-size:var(--code-font-size);padding-right:.875rem}.highlighttable td.code{display:block;flex:1;overflow:hidden;padding:0}.highlighttable td.code .highlight{border-bottom-left-radius:0;border-top-left-radius:0}.highlight span.linenos{box-shadow:-.0625rem 0 var(--color-foreground-border) inset;display:inline-block;margin-right:.875rem;padding-left:0;padding-right:.875rem}.footnote-reference{font-size:var(--font-size--small--4);vertical-align:super}dl.footnote.brackets{color:var(--color-foreground-secondary);display:grid;font-size:var(--font-size--small);grid-template-columns:max-content auto}dl.footnote.brackets dt{margin:0}dl.footnote.brackets dt>.fn-backref{margin-left:.25rem}dl.footnote.brackets dt:after{content:":"}dl.footnote.brackets dt .brackets:before{content:"["}dl.footnote.brackets dt .brackets:after{content:"]"}dl.footnote.brackets dd{margin:0;padding:0 1rem}aside.footnote{color:var(--color-foreground-secondary);font-size:var(--font-size--small)}aside.footnote>span,div.citation>span{float:left;font-weight:500;padding-right:.25rem}aside.footnote>:not(span),div.citation>p{margin-left:2rem}img{box-sizing:border-box;height:auto;max-width:100%}article .figure,article figure{border-radius:.2rem;margin:0}article .figure :last-child,article figure :last-child{margin-bottom:0}article .align-left{clear:left;float:left;margin:0 1rem 1rem}article .align-right{clear:right;float:right;margin:0 1rem 1rem}article .align-center,article .align-default{display:block;margin-left:auto;margin-right:auto;text-align:center}article table.align-default{display:table;text-align:initial}.domainindex-jumpbox,.genindex-jumpbox{border-bottom:1px solid var(--color-background-border);border-top:1px solid var(--color-background-border);padding:.25rem}.domainindex-section h2,.genindex-section h2{margin-bottom:.5rem;margin-top:.75rem}.domainindex-section ul,.genindex-section ul{margin-bottom:0;margin-top:0}ol,ul{margin-bottom:1rem;margin-top:1rem;padding-left:1.2rem}ol li>p:first-child,ul li>p:first-child{margin-bottom:.25rem;margin-top:.25rem}ol li>p:last-child,ul li>p:last-child{margin-top:.25rem}ol li>ol,ol li>ul,ul li>ol,ul li>ul{margin-bottom:.5rem;margin-top:.5rem}ol.arabic{list-style:decimal}ol.loweralpha{list-style:lower-alpha}ol.upperalpha{list-style:upper-alpha}ol.lowerroman{list-style:lower-roman}ol.upperroman{list-style:upper-roman}.simple li>ol,.simple li>ul,.toctree-wrapper li>ol,.toctree-wrapper li>ul{margin-bottom:0;margin-top:0}.field-list dt,.option-list dt,dl.footnote dt,dl.glossary dt,dl.simple dt,dl:not([class]) dt{font-weight:500;margin-top:.25rem}.field-list dt+dt,.option-list dt+dt,dl.footnote dt+dt,dl.glossary dt+dt,dl.simple dt+dt,dl:not([class]) dt+dt{margin-top:0}.field-list dt .classifier:before,.option-list dt .classifier:before,dl.footnote dt .classifier:before,dl.glossary dt .classifier:before,dl.simple dt .classifier:before,dl:not([class]) dt .classifier:before{content:":";margin-left:.2rem;margin-right:.2rem}.field-list dd ul,.field-list dd>p:first-child,.option-list dd ul,.option-list dd>p:first-child,dl.footnote dd ul,dl.footnote dd>p:first-child,dl.glossary dd ul,dl.glossary dd>p:first-child,dl.simple dd ul,dl.simple dd>p:first-child,dl:not([class]) dd ul,dl:not([class]) dd>p:first-child{margin-top:.125rem}.field-list dd ul,.option-list dd ul,dl.footnote dd ul,dl.glossary dd ul,dl.simple dd ul,dl:not([class]) dd ul{margin-bottom:.125rem}.math-wrapper{overflow-x:auto;width:100%}div.math{position:relative;text-align:center}div.math .headerlink,div.math:focus .headerlink{display:none}div.math:hover .headerlink{display:inline-block}div.math span.eqno{position:absolute;right:.5rem;top:50%;transform:translateY(-50%);z-index:1}abbr[title]{cursor:help}.problematic{color:var(--color-problematic)}kbd:not(.compound){background-color:var(--color-background-secondary);border:1px solid var(--color-foreground-border);border-radius:.2rem;box-shadow:0 .0625rem 0 rgba(0,0,0,.2),inset 0 0 0 .125rem var(--color-background-primary);color:var(--color-foreground-primary);display:inline-block;font-size:var(--font-size--small--3);margin:0 .2rem;padding:0 .2rem;vertical-align:text-bottom}blockquote{background:var(--color-background-secondary);border-left:4px solid var(--color-background-border);margin-left:0;margin-right:0;padding:.5rem 1rem}blockquote .attribution{font-weight:600;text-align:right}blockquote.highlights,blockquote.pull-quote{font-size:1.25em}blockquote.epigraph,blockquote.pull-quote{border-left-width:0;border-radius:.5rem}blockquote.highlights{background:transparent;border-left-width:0}p .reference img{vertical-align:middle}p.rubric{font-size:1.125em;font-weight:700;line-height:1.25}dd p.rubric{font-size:var(--font-size--small);font-weight:inherit;line-height:inherit;text-transform:uppercase}article .sidebar{background-color:var(--color-background-secondary);border:1px solid var(--color-background-border);border-radius:.2rem;clear:right;float:right;margin-left:1rem;margin-right:0;width:30%}article .sidebar>*{padding-left:1rem;padding-right:1rem}article .sidebar>ol,article .sidebar>ul{padding-left:2.2rem}article .sidebar .sidebar-title{border-bottom:1px solid var(--color-background-border);font-weight:500;margin:0;padding:.5rem 1rem}[role=main] .table-wrapper.container{margin-bottom:.5rem;margin-top:1rem;overflow-x:auto;padding:.2rem .2rem .75rem;width:100%}table.docutils{border-collapse:collapse;border-radius:.2rem;border-spacing:0;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 .0625rem rgba(0,0,0,.1)}table.docutils th{background:var(--color-table-header-background)}table.docutils td,table.docutils th{border-bottom:1px solid var(--color-table-border);border-left:1px solid var(--color-table-border);border-right:1px solid var(--color-table-border);padding:0 .25rem}table.docutils td p,table.docutils th p{margin:.25rem}table.docutils td:first-child,table.docutils th:first-child{border-left:none}table.docutils td:last-child,table.docutils th:last-child{border-right:none}table.docutils td.text-left,table.docutils th.text-left{text-align:left}table.docutils td.text-right,table.docutils th.text-right{text-align:right}table.docutils td.text-center,table.docutils th.text-center{text-align:center}:target{scroll-margin-top:2.5rem}@media(max-width:67em){:target{scroll-margin-top:calc(2.5rem + var(--header-height))}section>span:target{scroll-margin-top:calc(2.8rem + var(--header-height))}}.headerlink{font-weight:100;-webkit-user-select:none;-moz-user-select:none;user-select:none}.code-block-caption>.headerlink,dl dt>.headerlink,figcaption p>.headerlink,h1>.headerlink,h2>.headerlink,h3>.headerlink,h4>.headerlink,h5>.headerlink,h6>.headerlink,p.caption>.headerlink,table>caption>.headerlink{margin-left:.5rem;visibility:hidden}.code-block-caption:hover>.headerlink,dl dt:hover>.headerlink,figcaption p:hover>.headerlink,h1:hover>.headerlink,h2:hover>.headerlink,h3:hover>.headerlink,h4:hover>.headerlink,h5:hover>.headerlink,h6:hover>.headerlink,p.caption:hover>.headerlink,table>caption:hover>.headerlink{visibility:visible}.code-block-caption>.toc-backref,dl dt>.toc-backref,figcaption p>.toc-backref,h1>.toc-backref,h2>.toc-backref,h3>.toc-backref,h4>.toc-backref,h5>.toc-backref,h6>.toc-backref,p.caption>.toc-backref,table>caption>.toc-backref{color:inherit;text-decoration-line:none}figure:hover>figcaption>p>.headerlink,table:hover>caption>.headerlink{visibility:visible}:target>h1:first-of-type,:target>h2:first-of-type,:target>h3:first-of-type,:target>h4:first-of-type,:target>h5:first-of-type,:target>h6:first-of-type,span:target~h1:first-of-type,span:target~h2:first-of-type,span:target~h3:first-of-type,span:target~h4:first-of-type,span:target~h5:first-of-type,span:target~h6:first-of-type{background-color:var(--color-highlight-on-target)}:target>h1:first-of-type code.literal,:target>h2:first-of-type code.literal,:target>h3:first-of-type code.literal,:target>h4:first-of-type code.literal,:target>h5:first-of-type code.literal,:target>h6:first-of-type code.literal,span:target~h1:first-of-type code.literal,span:target~h2:first-of-type code.literal,span:target~h3:first-of-type code.literal,span:target~h4:first-of-type code.literal,span:target~h5:first-of-type code.literal,span:target~h6:first-of-type code.literal{background-color:transparent}.literal-block-wrapper:target .code-block-caption,.this-will-duplicate-information-and-it-is-still-useful-here li :target,figure:target,table:target>caption{background-color:var(--color-highlight-on-target)}dt:target{background-color:var(--color-highlight-on-target)!important}.footnote-reference:target,.footnote>dt:target+dd{background-color:var(--color-highlight-on-target)}.guilabel{background-color:var(--color-guilabel-background);border:1px solid var(--color-guilabel-border);border-radius:.5em;color:var(--color-guilabel-text);font-size:.9em;padding:0 .3em}footer{display:flex;flex-direction:column;font-size:var(--font-size--small);margin-top:2rem}.bottom-of-page{align-items:center;border-top:1px solid var(--color-background-border);color:var(--color-foreground-secondary);display:flex;justify-content:space-between;line-height:1.5;margin-top:1rem;padding-bottom:1rem;padding-top:1rem}@media(max-width:46em){.bottom-of-page{flex-direction:column-reverse;gap:.25rem;text-align:center}}.bottom-of-page .left-details{font-size:var(--font-size--small)}.bottom-of-page .right-details{display:flex;flex-direction:column;gap:.25rem;text-align:right}.bottom-of-page .icons{display:flex;font-size:1rem;gap:.25rem;justify-content:flex-end}.bottom-of-page .icons a{text-decoration:none}.bottom-of-page .icons img,.bottom-of-page .icons svg{font-size:1.125rem;height:1em;width:1em}.related-pages a{align-items:center;display:flex;text-decoration:none}.related-pages a:hover .page-info .title{color:var(--color-link);text-decoration:underline;text-decoration-color:var(--color-link-underline)}.related-pages a svg.furo-related-icon,.related-pages a svg.furo-related-icon>use{color:var(--color-foreground-border);flex-shrink:0;height:.75rem;margin:0 .5rem;width:.75rem}.related-pages a.next-page{clear:right;float:right;max-width:50%;text-align:right}.related-pages a.prev-page{clear:left;float:left;max-width:50%}.related-pages a.prev-page svg{transform:rotate(180deg)}.page-info{display:flex;flex-direction:column;overflow-wrap:anywhere}.next-page .page-info{align-items:flex-end}.page-info .context{align-items:center;color:var(--color-foreground-muted);display:flex;font-size:var(--font-size--small);padding-bottom:.1rem;text-decoration:none}ul.search{list-style:none;padding-left:0}ul.search li{border-bottom:1px solid var(--color-background-border);padding:1rem 0}[role=main] .highlighted{background-color:var(--color-highlighted-background);color:var(--color-highlighted-text)}.sidebar-brand{display:flex;flex-direction:column;flex-shrink:0;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal);text-decoration:none}.sidebar-brand-text{color:var(--color-sidebar-brand-text);font-size:1.5rem;overflow-wrap:break-word}.sidebar-brand-text,.sidebar-logo-container{margin:var(--sidebar-item-spacing-vertical) 0}.sidebar-logo{display:block;margin:0 auto;max-width:100%}.sidebar-search-container{align-items:center;background:var(--color-sidebar-search-background);display:flex;margin-top:var(--sidebar-search-space-above);position:relative}.sidebar-search-container:focus-within,.sidebar-search-container:hover{background:var(--color-sidebar-search-background--focus)}.sidebar-search-container:before{background-color:var(--color-sidebar-search-icon);content:"";height:var(--sidebar-search-icon-size);left:var(--sidebar-item-spacing-horizontal);-webkit-mask-image:var(--icon-search);mask-image:var(--icon-search);position:absolute;width:var(--sidebar-search-icon-size)}.sidebar-search{background:transparent;border:none;border-bottom:1px solid var(--color-sidebar-search-border);border-top:1px solid var(--color-sidebar-search-border);box-sizing:border-box;color:var(--color-sidebar-search-foreground);padding:var(--sidebar-search-input-spacing-vertical) var(--sidebar-search-input-spacing-horizontal) var(--sidebar-search-input-spacing-vertical) calc(var(--sidebar-item-spacing-horizontal) + var(--sidebar-search-input-spacing-horizontal) + var(--sidebar-search-icon-size));width:100%;z-index:10}.sidebar-search:focus{outline:none}.sidebar-search::-moz-placeholder{font-size:var(--sidebar-search-input-font-size)}.sidebar-search::placeholder{font-size:var(--sidebar-search-input-font-size)}#searchbox .highlight-link{margin:0;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal) 0;text-align:center}#searchbox .highlight-link a{color:var(--color-sidebar-search-icon);font-size:var(--font-size--small--2)}.sidebar-tree{font-size:var(--sidebar-item-font-size);margin-bottom:var(--sidebar-item-spacing-vertical);margin-top:var(--sidebar-tree-space-above)}.sidebar-tree ul{display:flex;flex-direction:column;list-style:none;margin-bottom:0;margin-top:0;padding:0}.sidebar-tree li{margin:0;position:relative}.sidebar-tree li>ul{margin-left:var(--sidebar-item-spacing-horizontal)}.sidebar-tree .icon,.sidebar-tree .reference{color:var(--color-sidebar-link-text)}.sidebar-tree .reference{box-sizing:border-box;display:inline-block;height:100%;line-height:var(--sidebar-item-line-height);overflow-wrap:anywhere;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal);text-decoration:none;width:100%}.sidebar-tree .reference:hover{background:var(--color-sidebar-item-background--hover);color:var(--color-sidebar-link-text)}.sidebar-tree .reference.external:after{color:var(--color-sidebar-link-text);content:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23607D8B' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' viewBox='0 0 24 24'%3E%3Cpath stroke='none' d='M0 0h24v24H0z'/%3E%3Cpath d='M11 7H6a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2v-5M10 14 20 4M15 4h5v5'/%3E%3C/svg%3E");margin:0 .25rem;vertical-align:middle}.sidebar-tree .current-page>.reference{font-weight:700}.sidebar-tree label{align-items:center;cursor:pointer;display:flex;height:var(--sidebar-item-height);justify-content:center;position:absolute;right:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:var(--sidebar-expander-width)}.sidebar-tree .caption,.sidebar-tree :not(.caption)>.caption-text{color:var(--color-sidebar-caption-text);font-size:var(--sidebar-caption-font-size);font-weight:700;margin:var(--sidebar-caption-space-above) 0 0 0;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal);text-transform:uppercase}.sidebar-tree li.has-children>.reference{padding-right:var(--sidebar-expander-width)}.sidebar-tree .toctree-l1>.reference,.sidebar-tree .toctree-l1>label .icon{color:var(--color-sidebar-link-text--top-level)}.sidebar-tree label{background:var(--color-sidebar-item-expander-background)}.sidebar-tree label:hover{background:var(--color-sidebar-item-expander-background--hover)}.sidebar-tree .current>.reference{background:var(--color-sidebar-item-background--current)}.sidebar-tree .current>.reference:hover{background:var(--color-sidebar-item-background--hover)}.toctree-checkbox{display:none;position:absolute}.toctree-checkbox~ul{display:none}.toctree-checkbox~label .icon svg{transform:rotate(90deg)}.toctree-checkbox:checked~ul{display:block}.toctree-checkbox:checked~label .icon svg{transform:rotate(-90deg)}.toc-title-container{padding:var(--toc-title-padding);padding-top:var(--toc-spacing-vertical)}.toc-title{color:var(--color-toc-title-text);font-size:var(--toc-title-font-size);padding-left:var(--toc-spacing-horizontal);text-transform:uppercase}.no-toc{display:none}.toc-tree-container{padding-bottom:var(--toc-spacing-vertical)}.toc-tree{border-left:1px solid var(--color-background-border);font-size:var(--toc-font-size);line-height:1.3;padding-left:calc(var(--toc-spacing-horizontal) - var(--toc-item-spacing-horizontal))}.toc-tree>ul>li:first-child{padding-top:0}.toc-tree>ul>li:first-child>ul{padding-left:0}.toc-tree>ul>li:first-child>a{display:none}.toc-tree ul{list-style-type:none;margin-bottom:0;margin-top:0;padding-left:var(--toc-item-spacing-horizontal)}.toc-tree li{padding-top:var(--toc-item-spacing-vertical)}.toc-tree li.scroll-current>.reference{color:var(--color-toc-item-text--active);font-weight:700}.toc-tree a.reference{color:var(--color-toc-item-text);overflow-wrap:anywhere;text-decoration:none}.toc-scroll{max-height:100vh;overflow-y:scroll}.contents:not(.this-will-duplicate-information-and-it-is-still-useful-here){background:rgba(255,0,0,.25);color:var(--color-problematic)}.contents:not(.this-will-duplicate-information-and-it-is-still-useful-here):before{content:"ERROR: Adding a table of contents in Furo-based documentation is unnecessary, and does not work well with existing styling. Add a 'this-will-duplicate-information-and-it-is-still-useful-here' class, if you want an escape hatch."}.text-align\:left>p{text-align:left}.text-align\:center>p{text-align:center}.text-align\:right>p{text-align:right} +/*# sourceMappingURL=furo.css.map*/ \ No newline at end of file diff --git a/_static/styles/furo.css.map b/_static/styles/furo.css.map new file mode 100644 index 00000000..3ecc3715 --- /dev/null +++ b/_static/styles/furo.css.map @@ -0,0 +1 @@ +{"version":3,"file":"styles/furo.css","mappings":"AAAA,2EAA2E,CAU3E,KACE,gBAAiB,CACjB,6BACF,CASA,KACE,QACF,CAMA,KACE,aACF,CAOA,GACE,aAAc,CACd,cACF,CAUA,GACE,sBAAuB,CACvB,QAAS,CACT,gBACF,CAOA,IACE,+BAAiC,CACjC,aACF,CASA,EACE,4BACF,CAOA,YACE,kBAAmB,CACnB,yBAA0B,CAC1B,gCACF,CAMA,SAEE,kBACF,CAOA,cAGE,+BAAiC,CACjC,aACF,CAeA,QAEE,aAAc,CACd,aAAc,CACd,iBAAkB,CAClB,uBACF,CAEA,IACE,aACF,CAEA,IACE,SACF,CASA,IACE,iBACF,CAUA,sCAKE,mBAAoB,CACpB,cAAe,CACf,gBAAiB,CACjB,QACF,CAOA,aAEE,gBACF,CAOA,cAEE,mBACF,CAMA,gDAIE,yBACF,CAMA,wHAIE,iBAAkB,CAClB,SACF,CAMA,4GAIE,6BACF,CAMA,SACE,0BACF,CASA,OACE,qBAAsB,CACtB,aAAc,CACd,aAAc,CACd,cAAe,CACf,SAAU,CACV,kBACF,CAMA,SACE,uBACF,CAMA,SACE,aACF,CAOA,6BAEE,qBAAsB,CACtB,SACF,CAMA,kFAEE,WACF,CAOA,cACE,4BAA6B,CAC7B,mBACF,CAMA,yCACE,uBACF,CAOA,6BACE,yBAA0B,CAC1B,YACF,CASA,QACE,aACF,CAMA,QACE,iBACF,CAiBA,kBACE,YACF,CCvVA,aAcE,kEACE,uBAOF,WACE,iDAMF,kCACE,wBAEF,qCAEE,uBADA,uBACA,CAEF,SACE,wBAtBA,CCpBJ,iBAGE,qBAEA,sBACA,0BAFA,oBAHA,4BACA,oBAKA,6BAIA,2CAFA,mBACA,sCAFA,4BAGA,CAEF,gBACE,aCTF,KCGE,mHAEA,wGAEA,wCAAyC,CAEzC,wBAAyB,CACzB,wBAAyB,CACzB,4BAA6B,CAC7B,yBAA0B,CAC1B,2BAA4B,CAG5B,sDAAuD,CACvD,gDAAiD,CACjD,wDAAyD,CAGzD,0CAA2C,CAC3C,gDAAiD,CACjD,gDAAiD,CAKjD,gCAAiC,CACjC,sCAAuC,CAGvC,2CAA4C,CAG5C,uCAAwC,CCjCxC,+FAGA,uBAAwB,CAGxB,iCAAkC,CAClC,kCAAmC,CAEnC,+BAAgC,CAChC,sCAAuC,CACvC,sCAAuC,CACvC,qGAIA,mDAAoD,CAEpD,mCAAoC,CACpC,8CAA+C,CAC/C,gDAAiD,CACjD,kCAAmC,CACnC,6DAA8D,CAG9D,6BAA8B,CAC9B,6BAA8B,CAC9B,+BAAgC,CAChC,kCAAmC,CACnC,kCAAmC,CCPjC,+jBCYA,iqCAZF,iaCVA,8KAOA,4SAWA,4SAUA,0CACA,gEAGA,0CAGA,gEAGA,yCACA,+DAIA,4CACA,kEAGA,wCAUA,8DACA,uCAGA,4DACA,sCACA,2DAGA,4CACA,kEACA,uCAGA,6DACA,2GAGA,sHAEA,yFAEA,+CACA,+EAGA,4MAOA,gCACA,sHAIA,kCACA,uEACA,gEACA,4DACA,kEAGA,2DACA,sDACA,0CACA,8CACA,wGAGA,0BACA,iCAGA,+DACA,+BACA,sCACA,+DAEA,kGACA,oCACA,yDACA,sCL7HF,kCAEA,sDAIA,0CK2HE,kEAIA,oDACA,sDAGA,oCACA,oEAEA,0DACA,qDAIA,oDACA,6DAIA,iEAIA,2DAIA,2DAGA,4DACA,gEAIA,gEAEA,gFAEA,oNASA,qDLxKE,gFAGE,4DAIF,oEKkHF,yEAEA,6DAGA,0DAEA,uDACA,qDACA,wDAIA,6DAIA,yDACA,2DAIA,uCAGA,wCACA,sDAGA,+CAGA,6DAEA,iDACA,+DAEA,wDAEA,sEAMA,0DACA,sBACA,mEL9JI,wEAEA,iCACE,+BAMN,wEAGA,iCACE,kFAEA,uEAIF,gEACE,8BAGF,qEMvDA,sCAKA,wFAKA,iCAIA,0BAWA,iCACA,4BACA,mCAGA,+BAEA,sCACA,4BAEA,mCAEA,sCAKA,sDAIA,gCAEA,gEAQF,wCAME,sBACA,kCAKA,uBAEA,gEAIA,2BAIA,mCAEA,qCACA,iCAGE,+BACA,wEAEE,iCACA,kFAGF,6BACA,0CACF,kCAEE,8BACE,8BACA,qEAEE,sCACA,wFCnFN,iCAGF,2DAEE,4BACA,oCAGA,mIAGA,4HACE,gEAMJ,+CAGE,sBACA,yCAEF,uBAEE,sEAKA,gDACA,kEAGA,iFAGE,YAGF,EACA,4HAQF,mBACE,6BACA,mBACA,wCACA,wCACA,2CAIA,eAGA,mBAKE,mBAGA,CAJA,uCACA,iBAFF,gBACE,CAKE,mBACA,mBAGJ,oBAIF,+BAGE,kDACA,OADA,kBAGA,CAFA,gBAEA,mBACA,oBAEA,sCACA,OAGF,cAHE,WAGF,GAEE,oBACA,CAHF,gBAGE,CC9Gc,YDiHd,+CAIF,SAEE,CAPF,UACE,wBAMA,4BAEA,GAGA,uBACA,CAJA,yBAGA,CACA,iDAKA,2CAGA,2DAQA,iBACA,uCAGA,kEAKE,SAKJ,8BACE,yDACA,2BAEA,oBACA,8BAEA,yDAEE,4BAEJ,uCACE,CACA,iEAGA,CAEA,wCACE,uBACA,kDAEA,0DAEE,CAJF,oBAIE,0GAWN,aACE,CAHA,YAGA,4HASA,+CAGF,sBACE,WACA,WAQA,4BAFF,0CAEE,CARA,qCAsBA,CAdA,iBAEA,kBACE,aADF,4BACE,WAMF,2BAGF,qCAEE,CAXE,UAWF,+BAGA,uBAEA,SAEA,0CAIE,CANF,qCAEA,CAIE,2DACE,gBAIN,+CAIA,CAEA,kDAKE,CAPF,8BAEA,CAOE,YACA,CAjBI,2BAGN,CAHM,WAcJ,UAGA,CAEA,2GAIF,iCAGE,8BAIA,qBACA,oBACF,uBAOI,0CAIA,CATF,6DAKE,CALF,sBASE,qCAKF,CACE,cACA,CAFF,sBAEE,CACA,+BAEA,qBAEE,WAKN,aACE,sCAGA,mBAEA,6BAMA,kCACA,CAJA,sBACA,aAEA,CAJA,eACA,MAIA,2FAEA,UAGA,YACA,sBACE,8BAEA,CALF,aACA,WAIE,OACA,oBAEF,uBACE,WAEF,YAFE,UAEF,eAgBA,kBACE,CAhBA,qDAQF,qCAGF,CAGI,YACF,CAJF,2BAGI,CAEA,eACA,qBAGA,mEAEA,qBACA,8BAIA,kBADF,kBACE,yBAEJ,oCAGI,qDAIJ,+BAGI,oCAEA,+CAQF,4CACE,yBACF,2BAOE,sBACA,CAHA,WACA,CAFF,cACE,CAJA,YAGF,CAEE,SAEA,mBAGA,kDAEE,CAJF,cAEA,cAEE,sBAEA,mBADA,YACA,uBACA,mDACE,CADF,YACE,iDAEA,uCAEN,+DAOE,mBADF,sBACE,mBAGF,aACE,sCAIA,aADF,WACE,CAKF,SACE,CAHJ,kBAEE,CAJE,gBAEJ,CAHI,iBAMA,yFAKA,aACA,eACA,cElbJ,iBAEE,aADA,iBACA,6BAEA,kCAEA,SACA,UAIA,gCACA,CALA,SAEA,SAEA,CAJA,0EAEA,CAFA,OAKA,CAGA,mDACE,iBAGF,gCACE,CADF,UACE,aAEJ,iCAEE,CAFF,UAEE,wCAEA,WACA,WADA,UACA,CACA,4CAGA,MACA,CADA,KACA,wCACA,UAGA,CAJA,UAIA,6DAUA,0CACE,CAFF,mBAEE,wEACA,CAVA,YACA,CAMF,mBAJE,OAOA,gBAJJ,gCACE,CANE,cACA,CAHA,oBACA,CAGA,QAGJ,CAII,0BACA,CADA,UACA,wCAEJ,kBACE,0DACA,gCACE,kBACA,CADA,YACA,oEACA,2CAMF,mDAII,CALN,YACE,CANE,cAKJ,CACE,iBAII,kEACA,yCACE,kDACA,yDACE,+CACA,uBANN,CAMM,+BANN,uCACE,qDACA,4BAEE,mBADA,0CACA,CADA,qBACA,0DACE,wCACA,sGALJ,oCACA,sBACE,kBAFF,UAEE,2CACA,wFACE,cACA,kEANN,uBACE,iDACA,CADA,UACA,0DACE,wDAEE,iEACA,qEANN,sCACE,CAGE,iBAHF,gBAGE,qBACE,CAJJ,uBACA,gDACE,wDACA,6DAHF,2CACA,CADA,gBACA,eACE,CAGE,sBANN,8BACE,CAII,iBAFF,4DACA,WACE,YADF,uCACE,6EACA,2BANN,8CACE,kDACA,0CACE,8BACA,yFACE,sBACA,sFALJ,mEACA,sBACE,kEACA,6EACE,uCACA,kEALJ,qGAEE,kEACA,6EACE,uCACA,kEALJ,8CACA,uDACE,sEACA,2EACE,sCACA,iEALJ,mGACA,qCACE,oDACA,0DACE,6GACA,gDAGR,yDCrEA,sEACE,CACA,6GACE,gEACF,iGAIF,wFACE,qDAGA,mGAEE,2CAEF,4FACE,gCACF,wGACE,8DAEE,6FAIA,iJAKN,6GACE,gDAKF,yDACA,qCAGA,6BACA,kBACA,qDAKA,oCAEA,+DAGA,2CAGE,oDAIA,oEAEE,qBAGJ,wDAEE,uCAEF,kEAGA,8CAEA,uDAIF,gEAIE,6BACA,gEAIA,+CACE,0EAIF,sDAEE,+DAGF,sCACA,8BACE,oCAEJ,wBACE,4FAEE,gBAEJ,yGAGI,kBAGJ,CCnHE,2MCFF,oBAGE,wGAKA,iCACE,CADF,wBACE,8GAQA,mBCjBJ,2GAIE,mBACA,6HAMA,YACE,mIAYF,eACA,CAHF,YAGE,4FAGE,8BAKF,uBAkBE,sCACA,CADA,qBAbA,wCAIA,CALF,8BACE,CADF,gBAKE,wCACA,CAOA,kDACA,CACA,kCAKF,6BAGA,4CACE,kDACA,eAGF,cACE,aACA,iBACA,yBACA,8BACA,WAGJ,2BACE,cAGA,+BACA,CAHA,eAGA,wCACA,YACA,iBACA,uEAGA,0BACA,2CAEA,8EAGI,qBACA,CAFF,kBAEE,kBAGN,0CAGE,mCAGA,4BAIA,gEACE,qCACA,8BAEA,gBACA,+CACA,iCAEF,iCAEE,gEACA,qCAGF,8BAEE,+BAIA,yCAEE,qBADA,gBACA,yBAKF,eACA,CAFF,YACE,CACA,iBACA,qDAEA,mDCvIJ,2FAOE,iCACA,CAEA,eACA,CAHA,kBAEA,CAFA,wBAGA,8BACA,eACE,CAFF,YAEE,0BACA,8CAGA,oBACE,oCAGA,kBACE,8DAEA,iBAEN,UACE,8BAIJ,+CAEE,qDAEF,kDAIE,YAEF,CAFE,YAEF,CCpCE,mFADA,kBAKE,CAJF,IAGA,aACE,mCAGA,iDACE,+BAEJ,wBAEE,mBAMA,6CAEF,CAJE,mBAEA,CAEF,kCAGE,CARF,kBACE,CAHA,eAUA,YACA,mBACA,CADA,UACA,wCC9BF,oBDkCE,wBCnCJ,uCACE,+BACA,+DACA,sBAGA,qBCDA,6CAIE,CAPF,uBAGA,CDGE,oBACF,yDAEE,CCDE,2CAGF,CAJA,kCACE,CDJJ,YACE,CAIA,eCTF,CDKE,uBCMA,gCACE,YAEF,oCAEE,wBACA,0BAIF,iBAEA,cADF,UACE,uBAEA,iCAEA,wCAEA,6CAMA,CAYF,gCATI,4BASJ,CAZE,mCAEE,iCAUJ,4BAGE,4DADA,+BACA,CAHF,qBAGE,sCACE,OAEF,iBAHA,SAGA,iHACE,2DAKF,CANA,8EAMA,uSAEE,kBAEF,+FACE,yCCjEJ,WACA,yBAGA,uBACA,gBAEA,uCAIA,CAJA,iCAIA,uCAGA,UACE,gBACA,qBAEA,0CClBJ,gBACE,KAGF,qBACE,YAGF,CAHE,cAGF,gCAEE,mBACA,iEAEA,oCACA,wCAEA,sBACA,WAEA,CAFA,YAEA,8EAEA,mCAFA,iBAEA,6BAIA,wEAKA,sDAIE,CARF,mDAIA,CAIE,cAEF,8CAIA,oBAFE,iBAEF,8CAGE,eAEF,CAFE,YAEF,OAEE,kBAGJ,CAJI,eACA,CAFF,mBAKF,yCCjDE,oBACA,CAFA,iBAEA,uCAKE,iBACA,qCAGA,mBCZJ,CDWI,gBCXJ,6BAEE,eACA,sBAGA,eAEA,sBACA,oDACA,iGAMA,gBAFE,YAEF,8FAME,iJCnBF,YACA,gNAWE,gDAEF,iSAaE,kBACE,gHAKF,oCACE,eACF,CADE,UACF,8CACE,gDACF,wCACE,oBCxCJ,oBAEF,6BACE,QACE,kDAGF,yBACE,kDAmBA,kDAEF,CAhBA,+CAaA,CAbA,oBAaA,0FACE,CADF,gGAfF,cACE,gBACA,CAaA,0BAGA,mQACE,gBAGF,oMACE,iBACA,CAFF,eACE,CADF,gBAEE,aAGJ,iCAEE,CAFF,wCAEE,wBAUE,+VAIE,uEAHA,2BAGA,wXAKJ,iDAGF,CARM,+CACE,iDAIN,CALI,gBAQN,mHACE,gBAGF,2DACE,0EAOA,0EAGF,gBAEE,6DC/EA,kDACA,gCACA,qDAGA,qBACA,qDCFA,cACA,eAEA,yBAGF,sBAEE,iBACA,sNAWA,iBACE,kBACA,wRAgBA,kBAEA,iOAgBA,uCACE,uEAEA,kBAEF,qUAuBE,iDAIJ,CACA,geCxFF,4BAEE,CAQA,6JACA,iDAIA,sEAGA,mDAOF,iDAGE,4DAIA,8CACA,qDAEE,eAFF,cAEE,oBAEF,uBAFE,kCAGA,eACA,iBACA,mBAIA,mDACA,CAHA,uCAEA,CAJA,0CACA,CAIA,gBAJA,gBACA,oBADA,gBAIA,wBAEJ,gBAGE,6BACA,YAHA,iBAGA,gCACA,iEAEA,6CACA,sDACA,0BADA,wBACA,0BACA,oIAIA,mBAFA,YAEA,qBACA,0CAIE,uBAEF,CAHA,yBACE,CAEF,iDACE,mFAKJ,oCACE,CANE,aAKJ,CACE,qEAIA,YAFA,WAEA,CAHA,aACA,CAEA,gBACE,4BACA,sBADA,aACA,gCAMF,oCACA,yDACA,2CAEA,qBAGE,kBAEA,CACA,mCAIF,CARE,YACA,CAOF,iCAEE,CAPA,oBACA,CAQA,oBACE,uDAEJ,sDAGA,CAHA,cAGA,0BACE,oDAIA,oCACA,4BACA,sBAGA,cAEA,oFAGA,sBAEA,yDACE,CAIF,iBAJE,wBAIF,6CAHE,6CAKA,eACA,aACA,CADA,cACA,yCAGJ,kBACE,CAKA,iDAEA,CARF,aACE,4CAGA,kBAIA,wEAGA,wDAGA,kCAOA,iDAGA,CAPF,WAEE,sCAEA,CAJF,2CACE,CAMA,qCACA,+BARF,kBACE,qCAOA,iBAsBA,sBACE,CAvBF,WAKA,CACE,0DAIF,CALA,uDACE,CANF,sBAqBA,4CACA,CALA,gRAIA,YAEE,6CAEN,mCAEE,+CASA,6EAIA,4BChNA,SDmNA,qFCnNA,gDACA,sCAGA,qCACA,sDACA,CAKA,kDAGA,CARA,0CAQA,kBAGA,YACA,sBACA,iBAFA,gBADF,YACE,CAHA,SAKA,kBAEA,SAFA,iBAEA,uEAGA,CAEE,6CAFF,oCAgBI,CAdF,yBACE,qBACF,CAGF,oBACE,CAIF,WACE,CALA,2CAGA,uBACF,CACE,mFAGE,CALF,qBAEA,UAGE,gCAIF,sDAEA,CALE,oCAKF,yCC7CJ,oCACE,CD+CA,yXAQE,sCCrDJ,wCAGA,oCACE","sources":["webpack:///./node_modules/normalize.css/normalize.css","webpack:///./src/furo/assets/styles/base/_print.sass","webpack:///./src/furo/assets/styles/base/_screen-readers.sass","webpack:///./src/furo/assets/styles/base/_theme.sass","webpack:///./src/furo/assets/styles/variables/_fonts.scss","webpack:///./src/furo/assets/styles/variables/_spacing.scss","webpack:///./src/furo/assets/styles/variables/_icons.scss","webpack:///./src/furo/assets/styles/variables/_admonitions.scss","webpack:///./src/furo/assets/styles/variables/_colors.scss","webpack:///./src/furo/assets/styles/base/_typography.sass","webpack:///./src/furo/assets/styles/_scaffold.sass","webpack:///./src/furo/assets/styles/variables/_layout.scss","webpack:///./src/furo/assets/styles/content/_admonitions.sass","webpack:///./src/furo/assets/styles/content/_api.sass","webpack:///./src/furo/assets/styles/content/_blocks.sass","webpack:///./src/furo/assets/styles/content/_captions.sass","webpack:///./src/furo/assets/styles/content/_code.sass","webpack:///./src/furo/assets/styles/content/_footnotes.sass","webpack:///./src/furo/assets/styles/content/_images.sass","webpack:///./src/furo/assets/styles/content/_indexes.sass","webpack:///./src/furo/assets/styles/content/_lists.sass","webpack:///./src/furo/assets/styles/content/_math.sass","webpack:///./src/furo/assets/styles/content/_misc.sass","webpack:///./src/furo/assets/styles/content/_rubrics.sass","webpack:///./src/furo/assets/styles/content/_sidebar.sass","webpack:///./src/furo/assets/styles/content/_tables.sass","webpack:///./src/furo/assets/styles/content/_target.sass","webpack:///./src/furo/assets/styles/content/_gui-labels.sass","webpack:///./src/furo/assets/styles/components/_footer.sass","webpack:///./src/furo/assets/styles/components/_sidebar.sass","webpack:///./src/furo/assets/styles/components/_table_of_contents.sass","webpack:///./src/furo/assets/styles/_shame.sass"],"sourcesContent":["/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */\n\n/* Document\n ========================================================================== */\n\n/**\n * 1. Correct the line height in all browsers.\n * 2. Prevent adjustments of font size after orientation changes in iOS.\n */\n\nhtml {\n line-height: 1.15; /* 1 */\n -webkit-text-size-adjust: 100%; /* 2 */\n}\n\n/* Sections\n ========================================================================== */\n\n/**\n * Remove the margin in all browsers.\n */\n\nbody {\n margin: 0;\n}\n\n/**\n * Render the `main` element consistently in IE.\n */\n\nmain {\n display: block;\n}\n\n/**\n * Correct the font size and margin on `h1` elements within `section` and\n * `article` contexts in Chrome, Firefox, and Safari.\n */\n\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\n\n/* Grouping content\n ========================================================================== */\n\n/**\n * 1. Add the correct box sizing in Firefox.\n * 2. Show the overflow in Edge and IE.\n */\n\nhr {\n box-sizing: content-box; /* 1 */\n height: 0; /* 1 */\n overflow: visible; /* 2 */\n}\n\n/**\n * 1. Correct the inheritance and scaling of font size in all browsers.\n * 2. Correct the odd `em` font sizing in all browsers.\n */\n\npre {\n font-family: monospace, monospace; /* 1 */\n font-size: 1em; /* 2 */\n}\n\n/* Text-level semantics\n ========================================================================== */\n\n/**\n * Remove the gray background on active links in IE 10.\n */\n\na {\n background-color: transparent;\n}\n\n/**\n * 1. Remove the bottom border in Chrome 57-\n * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.\n */\n\nabbr[title] {\n border-bottom: none; /* 1 */\n text-decoration: underline; /* 2 */\n text-decoration: underline dotted; /* 2 */\n}\n\n/**\n * Add the correct font weight in Chrome, Edge, and Safari.\n */\n\nb,\nstrong {\n font-weight: bolder;\n}\n\n/**\n * 1. Correct the inheritance and scaling of font size in all browsers.\n * 2. Correct the odd `em` font sizing in all browsers.\n */\n\ncode,\nkbd,\nsamp {\n font-family: monospace, monospace; /* 1 */\n font-size: 1em; /* 2 */\n}\n\n/**\n * Add the correct font size in all browsers.\n */\n\nsmall {\n font-size: 80%;\n}\n\n/**\n * Prevent `sub` and `sup` elements from affecting the line height in\n * all browsers.\n */\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -0.25em;\n}\n\nsup {\n top: -0.5em;\n}\n\n/* Embedded content\n ========================================================================== */\n\n/**\n * Remove the border on images inside links in IE 10.\n */\n\nimg {\n border-style: none;\n}\n\n/* Forms\n ========================================================================== */\n\n/**\n * 1. Change the font styles in all browsers.\n * 2. Remove the margin in Firefox and Safari.\n */\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n font-family: inherit; /* 1 */\n font-size: 100%; /* 1 */\n line-height: 1.15; /* 1 */\n margin: 0; /* 2 */\n}\n\n/**\n * Show the overflow in IE.\n * 1. Show the overflow in Edge.\n */\n\nbutton,\ninput { /* 1 */\n overflow: visible;\n}\n\n/**\n * Remove the inheritance of text transform in Edge, Firefox, and IE.\n * 1. Remove the inheritance of text transform in Firefox.\n */\n\nbutton,\nselect { /* 1 */\n text-transform: none;\n}\n\n/**\n * Correct the inability to style clickable types in iOS and Safari.\n */\n\nbutton,\n[type=\"button\"],\n[type=\"reset\"],\n[type=\"submit\"] {\n -webkit-appearance: button;\n}\n\n/**\n * Remove the inner border and padding in Firefox.\n */\n\nbutton::-moz-focus-inner,\n[type=\"button\"]::-moz-focus-inner,\n[type=\"reset\"]::-moz-focus-inner,\n[type=\"submit\"]::-moz-focus-inner {\n border-style: none;\n padding: 0;\n}\n\n/**\n * Restore the focus styles unset by the previous rule.\n */\n\nbutton:-moz-focusring,\n[type=\"button\"]:-moz-focusring,\n[type=\"reset\"]:-moz-focusring,\n[type=\"submit\"]:-moz-focusring {\n outline: 1px dotted ButtonText;\n}\n\n/**\n * Correct the padding in Firefox.\n */\n\nfieldset {\n padding: 0.35em 0.75em 0.625em;\n}\n\n/**\n * 1. Correct the text wrapping in Edge and IE.\n * 2. Correct the color inheritance from `fieldset` elements in IE.\n * 3. Remove the padding so developers are not caught out when they zero out\n * `fieldset` elements in all browsers.\n */\n\nlegend {\n box-sizing: border-box; /* 1 */\n color: inherit; /* 2 */\n display: table; /* 1 */\n max-width: 100%; /* 1 */\n padding: 0; /* 3 */\n white-space: normal; /* 1 */\n}\n\n/**\n * Add the correct vertical alignment in Chrome, Firefox, and Opera.\n */\n\nprogress {\n vertical-align: baseline;\n}\n\n/**\n * Remove the default vertical scrollbar in IE 10+.\n */\n\ntextarea {\n overflow: auto;\n}\n\n/**\n * 1. Add the correct box sizing in IE 10.\n * 2. Remove the padding in IE 10.\n */\n\n[type=\"checkbox\"],\n[type=\"radio\"] {\n box-sizing: border-box; /* 1 */\n padding: 0; /* 2 */\n}\n\n/**\n * Correct the cursor style of increment and decrement buttons in Chrome.\n */\n\n[type=\"number\"]::-webkit-inner-spin-button,\n[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n/**\n * 1. Correct the odd appearance in Chrome and Safari.\n * 2. Correct the outline style in Safari.\n */\n\n[type=\"search\"] {\n -webkit-appearance: textfield; /* 1 */\n outline-offset: -2px; /* 2 */\n}\n\n/**\n * Remove the inner padding in Chrome and Safari on macOS.\n */\n\n[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n/**\n * 1. Correct the inability to style clickable types in iOS and Safari.\n * 2. Change font properties to `inherit` in Safari.\n */\n\n::-webkit-file-upload-button {\n -webkit-appearance: button; /* 1 */\n font: inherit; /* 2 */\n}\n\n/* Interactive\n ========================================================================== */\n\n/*\n * Add the correct display in Edge, IE 10+, and Firefox.\n */\n\ndetails {\n display: block;\n}\n\n/*\n * Add the correct display in all browsers.\n */\n\nsummary {\n display: list-item;\n}\n\n/* Misc\n ========================================================================== */\n\n/**\n * Add the correct display in IE 10+.\n */\n\ntemplate {\n display: none;\n}\n\n/**\n * Add the correct display in IE 10.\n */\n\n[hidden] {\n display: none;\n}\n","// This file contains styles for managing print media.\n\n////////////////////////////////////////////////////////////////////////////////\n// Hide elements not relevant to print media.\n////////////////////////////////////////////////////////////////////////////////\n@media print\n // Hide icon container.\n .content-icon-container\n display: none !important\n\n // Hide showing header links if hovering over when printing.\n .headerlink\n display: none !important\n\n // Hide mobile header.\n .mobile-header\n display: none !important\n\n // Hide navigation links.\n .related-pages\n display: none !important\n\n////////////////////////////////////////////////////////////////////////////////\n// Tweaks related to decolorization.\n////////////////////////////////////////////////////////////////////////////////\n@media print\n // Apply a border around code which no longer have a color background.\n .highlight\n border: 0.1pt solid var(--color-foreground-border)\n\n////////////////////////////////////////////////////////////////////////////////\n// Avoid page break in some relevant cases.\n////////////////////////////////////////////////////////////////////////////////\n@media print\n ul, ol, dl, a, table, pre, blockquote, p\n page-break-inside: avoid\n\n h1, h2, h3, h4, h5, h6, img, figure, caption\n page-break-inside: avoid\n page-break-after: avoid\n\n ul, ol, dl\n page-break-before: avoid\n",".visually-hidden\n position: absolute !important\n width: 1px !important\n height: 1px !important\n padding: 0 !important\n margin: -1px !important\n overflow: hidden !important\n clip: rect(0,0,0,0) !important\n white-space: nowrap !important\n border: 0 !important\n color: var(--color-foreground-primary)\n background: var(--color-background-primary)\n\n:-moz-focusring\n outline: auto\n","// This file serves as the \"skeleton\" of the theming logic.\n//\n// This contains the bulk of the logic for handling dark mode, color scheme\n// toggling and the handling of color-scheme-specific hiding of elements.\n\nbody\n @include fonts\n @include spacing\n @include icons\n @include admonitions\n @include default-admonition(#651fff, \"abstract\")\n @include default-topic(#14B8A6, \"pencil\")\n\n @include colors\n\n.only-light\n display: block !important\nhtml body .only-dark\n display: none !important\n\n// Ignore dark-mode hints if print media.\n@media not print\n // Enable dark-mode, if requested.\n body[data-theme=\"dark\"]\n @include colors-dark\n\n html & .only-light\n display: none !important\n .only-dark\n display: block !important\n\n // Enable dark mode, unless explicitly told to avoid.\n @media (prefers-color-scheme: dark)\n body:not([data-theme=\"light\"])\n @include colors-dark\n\n html & .only-light\n display: none !important\n .only-dark\n display: block !important\n\n//\n// Theme toggle presentation\n//\nbody[data-theme=\"auto\"]\n .theme-toggle svg.theme-icon-when-auto-light\n display: block\n\n @media (prefers-color-scheme: dark)\n .theme-toggle svg.theme-icon-when-auto-dark\n display: block\n .theme-toggle svg.theme-icon-when-auto-light\n display: none\n\nbody[data-theme=\"dark\"]\n .theme-toggle svg.theme-icon-when-dark\n display: block\n\nbody[data-theme=\"light\"]\n .theme-toggle svg.theme-icon-when-light\n display: block\n","// Fonts used by this theme.\n//\n// There are basically two things here -- using the system font stack and\n// defining sizes for various elements in %ages. We could have also used `em`\n// but %age is easier to reason about for me.\n\n@mixin fonts {\n // These are adapted from https://systemfontstack.com/\n --font-stack: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,\n sans-serif, Apple Color Emoji, Segoe UI Emoji;\n --font-stack--monospace: \"SFMono-Regular\", Menlo, Consolas, Monaco,\n Liberation Mono, Lucida Console, monospace;\n --font-stack--headings: var(--font-stack);\n\n --font-size--normal: 100%;\n --font-size--small: 87.5%;\n --font-size--small--2: 81.25%;\n --font-size--small--3: 75%;\n --font-size--small--4: 62.5%;\n\n // Sidebar\n --sidebar-caption-font-size: var(--font-size--small--2);\n --sidebar-item-font-size: var(--font-size--small);\n --sidebar-search-input-font-size: var(--font-size--small);\n\n // Table of Contents\n --toc-font-size: var(--font-size--small--3);\n --toc-font-size--mobile: var(--font-size--normal);\n --toc-title-font-size: var(--font-size--small--4);\n\n // Admonitions\n //\n // These aren't defined in terms of %ages, since nesting these is permitted.\n --admonition-font-size: 0.8125rem;\n --admonition-title-font-size: 0.8125rem;\n\n // Code\n --code-font-size: var(--font-size--small--2);\n\n // API\n --api-font-size: var(--font-size--small);\n}\n","// Spacing for various elements on the page\n//\n// If the user wants to tweak things in a certain way, they are permitted to.\n// They also have to deal with the consequences though!\n\n@mixin spacing {\n // Header!\n --header-height: calc(\n var(--sidebar-item-line-height) + 4 * #{var(--sidebar-item-spacing-vertical)}\n );\n --header-padding: 0.5rem;\n\n // Sidebar\n --sidebar-tree-space-above: 1.5rem;\n --sidebar-caption-space-above: 1rem;\n\n --sidebar-item-line-height: 1rem;\n --sidebar-item-spacing-vertical: 0.5rem;\n --sidebar-item-spacing-horizontal: 1rem;\n --sidebar-item-height: calc(\n var(--sidebar-item-line-height) + 2 *#{var(--sidebar-item-spacing-vertical)}\n );\n\n --sidebar-expander-width: var(--sidebar-item-height); // be square\n\n --sidebar-search-space-above: 0.5rem;\n --sidebar-search-input-spacing-vertical: 0.5rem;\n --sidebar-search-input-spacing-horizontal: 0.5rem;\n --sidebar-search-input-height: 1rem;\n --sidebar-search-icon-size: var(--sidebar-search-input-height);\n\n // Table of Contents\n --toc-title-padding: 0.25rem 0;\n --toc-spacing-vertical: 1.5rem;\n --toc-spacing-horizontal: 1.5rem;\n --toc-item-spacing-vertical: 0.4rem;\n --toc-item-spacing-horizontal: 1rem;\n}\n","// Expose theme icons as CSS variables.\n\n$icons: (\n // Adapted from tabler-icons\n // url: https://tablericons.com/\n \"search\":\n url('data:image/svg+xml;charset=utf-8,'),\n // Factored out from mkdocs-material on 24-Aug-2020.\n // url: https://squidfunk.github.io/mkdocs-material/reference/admonitions/\n \"pencil\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"abstract\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"info\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"flame\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"question\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"warning\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"failure\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"spark\":\n url('data:image/svg+xml;charset=utf-8,')\n);\n\n@mixin icons {\n @each $name, $glyph in $icons {\n --icon-#{$name}: #{$glyph};\n }\n}\n","// Admonitions\n\n// Structure of these is:\n// admonition-class: color \"icon-name\";\n//\n// The colors are translated into CSS variables below. The icons are\n// used directly in the main declarations to set the `mask-image` in\n// the title.\n\n// prettier-ignore\n$admonitions: (\n // Each of these has an reST directives for it.\n \"caution\": #ff9100 \"spark\",\n \"warning\": #ff9100 \"warning\",\n \"danger\": #ff5252 \"spark\",\n \"attention\": #ff5252 \"warning\",\n \"error\": #ff5252 \"failure\",\n \"hint\": #00c852 \"question\",\n \"tip\": #00c852 \"info\",\n \"important\": #00bfa5 \"flame\",\n \"note\": #00b0ff \"pencil\",\n \"seealso\": #448aff \"info\",\n \"admonition-todo\": #808080 \"pencil\"\n);\n\n@mixin default-admonition($color, $icon-name) {\n --color-admonition-title: #{$color};\n --color-admonition-title-background: #{rgba($color, 0.2)};\n\n --icon-admonition-default: var(--icon-#{$icon-name});\n}\n\n@mixin default-topic($color, $icon-name) {\n --color-topic-title: #{$color};\n --color-topic-title-background: #{rgba($color, 0.2)};\n\n --icon-topic-default: var(--icon-#{$icon-name});\n}\n\n@mixin admonitions {\n @each $name, $values in $admonitions {\n --color-admonition-title--#{$name}: #{nth($values, 1)};\n --color-admonition-title-background--#{$name}: #{rgba(\n nth($values, 1),\n 0.2\n )};\n }\n}\n","// Colors used throughout this theme.\n//\n// The aim is to give the user more control. Thus, instead of hard-coding colors\n// in various parts of the stylesheet, the approach taken is to define all\n// colors as CSS variables and reusing them in all the places.\n//\n// `colors-dark` depends on `colors` being included at a lower specificity.\n\n@mixin colors {\n --color-problematic: #b30000;\n\n // Base Colors\n --color-foreground-primary: black; // for main text and headings\n --color-foreground-secondary: #5a5c63; // for secondary text\n --color-foreground-muted: #6b6f76; // for muted text\n --color-foreground-border: #878787; // for content borders\n\n --color-background-primary: white; // for content\n --color-background-secondary: #f8f9fb; // for navigation + ToC\n --color-background-hover: #efeff4ff; // for navigation-item hover\n --color-background-hover--transparent: #efeff400;\n --color-background-border: #eeebee; // for UI borders\n --color-background-item: #ccc; // for \"background\" items (eg: copybutton)\n\n // Announcements\n --color-announcement-background: #000000dd;\n --color-announcement-text: #eeebee;\n\n // Brand colors\n --color-brand-primary: #0a4bff;\n --color-brand-content: #2757dd;\n --color-brand-visited: #872ee0;\n\n // API documentation\n --color-api-background: var(--color-background-hover--transparent);\n --color-api-background-hover: var(--color-background-hover);\n --color-api-overall: var(--color-foreground-secondary);\n --color-api-name: var(--color-problematic);\n --color-api-pre-name: var(--color-problematic);\n --color-api-paren: var(--color-foreground-secondary);\n --color-api-keyword: var(--color-foreground-primary);\n\n --color-api-added: #21632c;\n --color-api-added-border: #38a84d;\n --color-api-changed: #046172;\n --color-api-changed-border: #06a1bc;\n --color-api-deprecated: #605706;\n --color-api-deprecated-border: #f0d90f;\n --color-api-removed: #b30000;\n --color-api-removed-border: #ff5c5c;\n\n --color-highlight-on-target: #ffffcc;\n\n // Inline code background\n --color-inline-code-background: var(--color-background-secondary);\n\n // Highlighted text (search)\n --color-highlighted-background: #ddeeff;\n --color-highlighted-text: var(--color-foreground-primary);\n\n // GUI Labels\n --color-guilabel-background: #ddeeff80;\n --color-guilabel-border: #bedaf580;\n --color-guilabel-text: var(--color-foreground-primary);\n\n // Admonitions!\n --color-admonition-background: transparent;\n\n //////////////////////////////////////////////////////////////////////////////\n // Everything below this should be one of:\n // - var(...)\n // - *-gradient(...)\n // - special literal values (eg: transparent, none)\n //////////////////////////////////////////////////////////////////////////////\n\n // Tables\n --color-table-header-background: var(--color-background-secondary);\n --color-table-border: var(--color-background-border);\n\n // Cards\n --color-card-border: var(--color-background-secondary);\n --color-card-background: transparent;\n --color-card-marginals-background: var(--color-background-secondary);\n\n // Header\n --color-header-background: var(--color-background-primary);\n --color-header-border: var(--color-background-border);\n --color-header-text: var(--color-foreground-primary);\n\n // Sidebar (left)\n --color-sidebar-background: var(--color-background-secondary);\n --color-sidebar-background-border: var(--color-background-border);\n\n --color-sidebar-brand-text: var(--color-foreground-primary);\n --color-sidebar-caption-text: var(--color-foreground-muted);\n --color-sidebar-link-text: var(--color-foreground-secondary);\n --color-sidebar-link-text--top-level: var(--color-brand-primary);\n\n --color-sidebar-item-background: var(--color-sidebar-background);\n --color-sidebar-item-background--current: var(\n --color-sidebar-item-background\n );\n --color-sidebar-item-background--hover: linear-gradient(\n 90deg,\n var(--color-background-hover--transparent) 0%,\n var(--color-background-hover) var(--sidebar-item-spacing-horizontal),\n var(--color-background-hover) 100%\n );\n\n --color-sidebar-item-expander-background: transparent;\n --color-sidebar-item-expander-background--hover: var(\n --color-background-hover\n );\n\n --color-sidebar-search-text: var(--color-foreground-primary);\n --color-sidebar-search-background: var(--color-background-secondary);\n --color-sidebar-search-background--focus: var(--color-background-primary);\n --color-sidebar-search-border: var(--color-background-border);\n --color-sidebar-search-icon: var(--color-foreground-muted);\n\n // Table of Contents (right)\n --color-toc-background: var(--color-background-primary);\n --color-toc-title-text: var(--color-foreground-muted);\n --color-toc-item-text: var(--color-foreground-secondary);\n --color-toc-item-text--hover: var(--color-foreground-primary);\n --color-toc-item-text--active: var(--color-brand-primary);\n\n // Actual page contents\n --color-content-foreground: var(--color-foreground-primary);\n --color-content-background: transparent;\n\n // Links\n --color-link: var(--color-brand-content);\n --color-link-underline: var(--color-background-border);\n --color-link--hover: var(--color-brand-content);\n --color-link-underline--hover: var(--color-foreground-border);\n\n --color-link--visited: var(--color-brand-visited);\n --color-link-underline--visited: var(--color-background-border);\n --color-link--visited--hover: var(--color-brand-visited);\n --color-link-underline--visited--hover: var(--color-foreground-border);\n}\n\n@mixin colors-dark {\n --color-problematic: #ee5151;\n\n // Base Colors\n --color-foreground-primary: #cfd0d0; // for main text and headings\n --color-foreground-secondary: #9ca0a5; // for secondary text\n --color-foreground-muted: #81868d; // for muted text\n --color-foreground-border: #666666; // for content borders\n\n --color-background-primary: #131416; // for content\n --color-background-secondary: #1a1c1e; // for navigation + ToC\n --color-background-hover: #1e2124ff; // for navigation-item hover\n --color-background-hover--transparent: #1e212400;\n --color-background-border: #303335; // for UI borders\n --color-background-item: #444; // for \"background\" items (eg: copybutton)\n\n // Announcements\n --color-announcement-background: #000000dd;\n --color-announcement-text: #eeebee;\n\n // Brand colors\n --color-brand-primary: #3d94ff;\n --color-brand-content: #5ca5ff;\n --color-brand-visited: #b27aeb;\n\n // Highlighted text (search)\n --color-highlighted-background: #083563;\n\n // GUI Labels\n --color-guilabel-background: #08356380;\n --color-guilabel-border: #13395f80;\n\n // API documentation\n --color-api-keyword: var(--color-foreground-secondary);\n --color-highlight-on-target: #333300;\n\n --color-api-added: #3db854;\n --color-api-added-border: #267334;\n --color-api-changed: #09b0ce;\n --color-api-changed-border: #056d80;\n --color-api-deprecated: #b1a10b;\n --color-api-deprecated-border: #6e6407;\n --color-api-removed: #ff7575;\n --color-api-removed-border: #b03b3b;\n\n // Admonitions\n --color-admonition-background: #18181a;\n\n // Cards\n --color-card-border: var(--color-background-secondary);\n --color-card-background: #18181a;\n --color-card-marginals-background: var(--color-background-hover);\n}\n","// This file contains the styling for making the content throughout the page,\n// including fonts, paragraphs, headings and spacing among these elements.\n\nbody\n font-family: var(--font-stack)\npre,\ncode,\nkbd,\nsamp\n font-family: var(--font-stack--monospace)\n\n// Make fonts look slightly nicer.\nbody\n -webkit-font-smoothing: antialiased\n -moz-osx-font-smoothing: grayscale\n\n// Line height from Bootstrap 4.1\narticle\n line-height: 1.5\n\n//\n// Headings\n//\nh1,\nh2,\nh3,\nh4,\nh5,\nh6\n line-height: 1.25\n font-family: var(--font-stack--headings)\n font-weight: bold\n\n border-radius: 0.5rem\n margin-top: 0.5rem\n margin-bottom: 0.5rem\n margin-left: -0.5rem\n margin-right: -0.5rem\n padding-left: 0.5rem\n padding-right: 0.5rem\n\n + p\n margin-top: 0\n\nh1\n font-size: 2.5em\n margin-top: 1.75rem\n margin-bottom: 1rem\nh2\n font-size: 2em\n margin-top: 1.75rem\nh3\n font-size: 1.5em\nh4\n font-size: 1.25em\nh5\n font-size: 1.125em\nh6\n font-size: 1em\n\nsmall\n opacity: 75%\n font-size: 80%\n\n// Paragraph\np\n margin-top: 0.5rem\n margin-bottom: 0.75rem\n\n// Horizontal rules\nhr.docutils\n height: 1px\n padding: 0\n margin: 2rem 0\n background-color: var(--color-background-border)\n border: 0\n\n.centered\n text-align: center\n\n// Links\na\n text-decoration: underline\n\n color: var(--color-link)\n text-decoration-color: var(--color-link-underline)\n\n &:visited\n color: var(--color-link--visited)\n text-decoration-color: var(--color-link-underline--visited)\n &:hover\n color: var(--color-link--visited--hover)\n text-decoration-color: var(--color-link-underline--visited--hover)\n\n &:hover\n color: var(--color-link--hover)\n text-decoration-color: var(--color-link-underline--hover)\n &.muted-link\n color: inherit\n &:hover\n color: var(--color-link--hover)\n text-decoration-color: var(--color-link-underline--hover)\n &:visited\n color: var(--color-link--visited--hover)\n text-decoration-color: var(--color-link-underline--visited--hover)\n","// This file contains the styles for the overall layouting of the documentation\n// skeleton, including the responsive changes as well as sidebar toggles.\n//\n// This is implemented as a mobile-last design, which isn't ideal, but it is\n// reasonably good-enough and I got pretty tired by the time I'd finished this\n// to move the rules around to fix this. Shouldn't take more than 3-4 hours,\n// if you know what you're doing tho.\n\n// HACK: Not all browsers account for the scrollbar width in media queries.\n// This results in horizontal scrollbars in the breakpoint where we go\n// from displaying everything to hiding the ToC. We accomodate for this by\n// adding a bit of padding to the TOC drawer, disabling the horizontal\n// scrollbar and allowing the scrollbars to cover the padding.\n// https://www.456bereastreet.com/archive/201301/media_query_width_and_vertical_scrollbars/\n\n// HACK: Always having the scrollbar visible, prevents certain browsers from\n// causing the content to stutter horizontally between taller-than-viewport and\n// not-taller-than-viewport pages.\n\nhtml\n overflow-x: hidden\n overflow-y: scroll\n scroll-behavior: smooth\n\n.sidebar-scroll, .toc-scroll, article[role=main] *\n // Override Firefox scrollbar style\n scrollbar-width: thin\n scrollbar-color: var(--color-foreground-border) transparent\n\n // Override Chrome scrollbar styles\n &::-webkit-scrollbar\n width: 0.25rem\n height: 0.25rem\n &::-webkit-scrollbar-thumb\n background-color: var(--color-foreground-border)\n border-radius: 0.125rem\n\n//\n// Overalls\n//\nhtml,\nbody\n height: 100%\n color: var(--color-foreground-primary)\n background: var(--color-background-primary)\n\n.skip-to-content\n position: fixed\n padding: 1rem\n border-radius: 1rem\n left: 0.25rem\n top: 0.25rem\n z-index: 40\n background: var(--color-background-primary)\n color: var(--color-foreground-primary)\n\n transform: translateY(-200%)\n transition: transform 300ms ease-in-out\n\n &:focus-within\n transform: translateY(0%)\n\narticle\n color: var(--color-content-foreground)\n background: var(--color-content-background)\n overflow-wrap: break-word\n\n.page\n display: flex\n // fill the viewport for pages with little content.\n min-height: 100%\n\n.mobile-header\n width: 100%\n height: var(--header-height)\n background-color: var(--color-header-background)\n color: var(--color-header-text)\n border-bottom: 1px solid var(--color-header-border)\n\n // Looks like sub-script/super-script have this, and we need this to\n // be \"on top\" of those.\n z-index: 10\n\n // We don't show the header on large screens.\n display: none\n\n // Add shadow when scrolled\n &.scrolled\n border-bottom: none\n box-shadow: 0 0 0.2rem rgba(0, 0, 0, 0.1), 0 0.2rem 0.4rem rgba(0, 0, 0, 0.2)\n\n .header-center\n a\n color: var(--color-header-text)\n text-decoration: none\n\n.main\n display: flex\n flex: 1\n\n// Sidebar (left) also covers the entire left portion of screen.\n.sidebar-drawer\n box-sizing: border-box\n\n border-right: 1px solid var(--color-sidebar-background-border)\n background: var(--color-sidebar-background)\n\n display: flex\n justify-content: flex-end\n // These next two lines took me two days to figure out.\n width: calc((100% - #{$full-width}) / 2 + #{$sidebar-width})\n min-width: $sidebar-width\n\n// Scroll-along sidebars\n.sidebar-container,\n.toc-drawer\n box-sizing: border-box\n width: $sidebar-width\n\n.toc-drawer\n background: var(--color-toc-background)\n // See HACK described on top of this document\n padding-right: 1rem\n\n.sidebar-sticky,\n.toc-sticky\n position: sticky\n top: 0\n height: min(100%, 100vh)\n height: 100vh\n\n display: flex\n flex-direction: column\n\n.sidebar-scroll,\n.toc-scroll\n flex-grow: 1\n flex-shrink: 1\n\n overflow: auto\n scroll-behavior: smooth\n\n// Central items.\n.content\n padding: 0 $content-padding\n width: $content-width\n\n display: flex\n flex-direction: column\n justify-content: space-between\n\n.icon\n display: inline-block\n height: 1rem\n width: 1rem\n svg\n width: 100%\n height: 100%\n\n//\n// Accommodate announcement banner\n//\n.announcement\n background-color: var(--color-announcement-background)\n color: var(--color-announcement-text)\n\n height: var(--header-height)\n display: flex\n align-items: center\n overflow-x: auto\n & + .page\n min-height: calc(100% - var(--header-height))\n\n.announcement-content\n box-sizing: border-box\n padding: 0.5rem\n min-width: 100%\n white-space: nowrap\n text-align: center\n\n a\n color: var(--color-announcement-text)\n text-decoration-color: var(--color-announcement-text)\n\n &:hover\n color: var(--color-announcement-text)\n text-decoration-color: var(--color-link--hover)\n\n////////////////////////////////////////////////////////////////////////////////\n// Toggles for theme\n////////////////////////////////////////////////////////////////////////////////\n.no-js .theme-toggle-container // don't show theme toggle if there's no JS\n display: none\n\n.theme-toggle-container\n display: flex\n\n.theme-toggle\n display: flex\n cursor: pointer\n border: none\n padding: 0\n background: transparent\n\n.theme-toggle svg\n height: 1.25rem\n width: 1.25rem\n color: var(--color-foreground-primary)\n display: none\n\n.theme-toggle-header\n display: flex\n align-items: center\n justify-content: center\n\n////////////////////////////////////////////////////////////////////////////////\n// Toggles for elements\n////////////////////////////////////////////////////////////////////////////////\n.toc-overlay-icon, .nav-overlay-icon\n display: none\n cursor: pointer\n\n .icon\n color: var(--color-foreground-secondary)\n height: 1.5rem\n width: 1.5rem\n\n.toc-header-icon, .nav-overlay-icon\n // for when we set display: flex\n justify-content: center\n align-items: center\n\n.toc-content-icon\n height: 1.5rem\n width: 1.5rem\n\n.content-icon-container\n float: right\n display: flex\n margin-top: 1.5rem\n margin-left: 1rem\n margin-bottom: 1rem\n gap: 0.5rem\n\n .edit-this-page, .view-this-page\n svg\n color: inherit\n height: 1.25rem\n width: 1.25rem\n\n.sidebar-toggle\n position: absolute\n display: none\n// \n.sidebar-toggle[name=\"__toc\"]\n left: 20px\n.sidebar-toggle:checked\n left: 40px\n// \n\n.overlay\n position: fixed\n top: 0\n width: 0\n height: 0\n\n transition: width 0ms, height 0ms, opacity 250ms ease-out\n\n opacity: 0\n background-color: rgba(0, 0, 0, 0.54)\n.sidebar-overlay\n z-index: 20\n.toc-overlay\n z-index: 40\n\n// Keep things on top and smooth.\n.sidebar-drawer\n z-index: 30\n transition: left 250ms ease-in-out\n.toc-drawer\n z-index: 50\n transition: right 250ms ease-in-out\n\n// Show the Sidebar\n#__navigation:checked\n & ~ .sidebar-overlay\n width: 100%\n height: 100%\n opacity: 1\n & ~ .page\n .sidebar-drawer\n top: 0\n left: 0\n // Show the toc sidebar\n#__toc:checked\n & ~ .toc-overlay\n width: 100%\n height: 100%\n opacity: 1\n & ~ .page\n .toc-drawer\n top: 0\n right: 0\n\n////////////////////////////////////////////////////////////////////////////////\n// Back to top\n////////////////////////////////////////////////////////////////////////////////\n.back-to-top\n text-decoration: none\n\n display: none\n position: fixed\n left: 0\n top: 1rem\n padding: 0.5rem\n padding-right: 0.75rem\n border-radius: 1rem\n font-size: 0.8125rem\n\n background: var(--color-background-primary)\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), #6b728080 0px 0px 1px 0px\n\n z-index: 10\n\n margin-left: 50%\n transform: translateX(-50%)\n svg\n height: 1rem\n width: 1rem\n fill: currentColor\n display: inline-block\n\n span\n margin-left: 0.25rem\n\n .show-back-to-top &\n display: flex\n align-items: center\n\n////////////////////////////////////////////////////////////////////////////////\n// Responsive layouting\n////////////////////////////////////////////////////////////////////////////////\n// Make things a bit bigger on bigger screens.\n@media (min-width: $full-width + $sidebar-width)\n html\n font-size: 110%\n\n@media (max-width: $full-width)\n // Collapse \"toc\" into the icon.\n .toc-content-icon\n display: flex\n .toc-drawer\n position: fixed\n height: 100vh\n top: 0\n right: -$sidebar-width\n border-left: 1px solid var(--color-background-muted)\n .toc-tree\n border-left: none\n font-size: var(--toc-font-size--mobile)\n\n // Accomodate for a changed content width.\n .sidebar-drawer\n width: calc((100% - #{$full-width - $sidebar-width}) / 2 + #{$sidebar-width})\n\n@media (max-width: $content-padded-width + $sidebar-width)\n // Center the page\n .content\n margin-left: auto\n margin-right: auto\n padding: 0 $content-padding--small\n\n@media (max-width: $content-padded-width--small + $sidebar-width)\n // Collapse \"navigation\".\n .nav-overlay-icon\n display: flex\n .sidebar-drawer\n position: fixed\n height: 100vh\n width: $sidebar-width\n\n top: 0\n left: -$sidebar-width\n\n // Swap which icon is visible.\n .toc-header-icon, .theme-toggle-header\n display: flex\n .toc-content-icon, .theme-toggle-content\n display: none\n\n // Show the header.\n .mobile-header\n position: sticky\n top: 0\n display: flex\n justify-content: space-between\n align-items: center\n\n .header-left,\n .header-right\n display: flex\n height: var(--header-height)\n padding: 0 var(--header-padding)\n label\n height: 100%\n width: 100%\n user-select: none\n\n .nav-overlay-icon .icon,\n .theme-toggle svg\n height: 1.5rem\n width: 1.5rem\n\n // Add a scroll margin for the content\n :target\n scroll-margin-top: calc(var(--header-height) + 2.5rem)\n\n // Show back-to-top below the header\n .back-to-top\n top: calc(var(--header-height) + 0.5rem)\n\n // Accommodate for the header.\n .page\n flex-direction: column\n justify-content: center\n\n@media (max-width: $content-width + 2* $content-padding--small)\n // Content should respect window limits.\n .content\n width: 100%\n overflow-x: auto\n\n@media (max-width: $content-width)\n article[role=main] aside.sidebar\n float: none\n width: 100%\n margin: 1rem 0\n","// Overall Layout Variables\n//\n// Because CSS variables can't be used in media queries. The fact that this\n// makes the layout non-user-configurable is a good thing.\n$content-padding: 3em;\n$content-padding--small: 1em;\n$content-width: 46em;\n$sidebar-width: 15em;\n$content-padded-width: $content-width + 2 * $content-padding;\n$content-padded-width--small: $content-width + 2 * $content-padding--small;\n$full-width: $content-padded-width + 2 * $sidebar-width;\n","//\n// The design here is strongly inspired by mkdocs-material.\n.admonition, .topic\n margin: 1rem auto\n padding: 0 0.5rem 0.5rem 0.5rem\n\n background: var(--color-admonition-background)\n\n border-radius: 0.2rem\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0 0.0625rem rgba(0, 0, 0, 0.1)\n\n font-size: var(--admonition-font-size)\n\n overflow: hidden\n page-break-inside: avoid\n\n // First element should have no margin, since the title has it.\n > :nth-child(2)\n margin-top: 0\n\n // Last item should have no margin, since we'll control that w/ padding\n > :last-child\n margin-bottom: 0\n\n.admonition p.admonition-title,\np.topic-title\n position: relative\n margin: 0 -0.5rem 0.5rem\n padding-left: 2rem\n padding-right: .5rem\n padding-top: .4rem\n padding-bottom: .4rem\n\n font-weight: 500\n font-size: var(--admonition-title-font-size)\n line-height: 1.3\n\n // Our fancy icon\n &::before\n content: \"\"\n position: absolute\n left: 0.5rem\n width: 1rem\n height: 1rem\n\n// Default styles\np.admonition-title\n background-color: var(--color-admonition-title-background)\n &::before\n background-color: var(--color-admonition-title)\n mask-image: var(--icon-admonition-default)\n mask-repeat: no-repeat\n\np.topic-title\n background-color: var(--color-topic-title-background)\n &::before\n background-color: var(--color-topic-title)\n mask-image: var(--icon-topic-default)\n mask-repeat: no-repeat\n\n//\n// Variants\n//\n.admonition\n border-left: 0.2rem solid var(--color-admonition-title)\n\n @each $type, $value in $admonitions\n &.#{$type}\n border-left-color: var(--color-admonition-title--#{$type})\n > .admonition-title\n background-color: var(--color-admonition-title-background--#{$type})\n &::before\n background-color: var(--color-admonition-title--#{$type})\n mask-image: var(--icon-#{nth($value, 2)})\n\n.admonition-todo > .admonition-title\n text-transform: uppercase\n","// This file stylizes the API documentation (stuff generated by autodoc). It's\n// deeply nested due to how autodoc structures the HTML without enough classes\n// to select the relevant items.\n\n// API docs!\ndl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)\n // Tweak the spacing of all the things!\n dd\n margin-left: 2rem\n > :first-child\n margin-top: 0.125rem\n > :last-child\n margin-bottom: 0.75rem\n\n // This is used for the arguments\n .field-list\n margin-bottom: 0.75rem\n\n // \"Headings\" (like \"Parameters\" and \"Return\")\n > dt\n text-transform: uppercase\n font-size: var(--font-size--small)\n\n dd:empty\n margin-bottom: 0.5rem\n dd > ul\n margin-left: -1.2rem\n > li\n > p:nth-child(2)\n margin-top: 0\n // When the last-empty-paragraph follows a paragraph, it doesn't need\n // to augument the existing spacing.\n > p + p:last-child:empty\n margin-top: 0\n margin-bottom: 0\n\n // Colorize the elements\n > dt\n color: var(--color-api-overall)\n\n.sig:not(.sig-inline)\n font-weight: bold\n\n font-size: var(--api-font-size)\n font-family: var(--font-stack--monospace)\n\n margin-left: -0.25rem\n margin-right: -0.25rem\n padding-top: 0.25rem\n padding-bottom: 0.25rem\n padding-right: 0.5rem\n\n // These are intentionally em, to properly match the font size.\n padding-left: 3em\n text-indent: -2.5em\n\n border-radius: 0.25rem\n\n background: var(--color-api-background)\n transition: background 100ms ease-out\n\n &:hover\n background: var(--color-api-background-hover)\n\n // adjust the size of the [source] link on the right.\n a.reference\n .viewcode-link\n font-weight: normal\n width: 4.25rem\n\nem.property\n font-style: normal\n &:first-child\n color: var(--color-api-keyword)\n.sig-name\n color: var(--color-api-name)\n.sig-prename\n font-weight: normal\n color: var(--color-api-pre-name)\n.sig-paren\n color: var(--color-api-paren)\n.sig-param\n font-style: normal\n\ndiv.versionadded,\ndiv.versionchanged,\ndiv.deprecated,\ndiv.versionremoved\n border-left: 0.1875rem solid\n border-radius: 0.125rem\n\n padding-left: 0.75rem\n\n p\n margin-top: 0.125rem\n margin-bottom: 0.125rem\n\ndiv.versionadded\n border-color: var(--color-api-added-border)\n .versionmodified\n color: var(--color-api-added)\n\ndiv.versionchanged\n border-color: var(--color-api-changed-border)\n .versionmodified\n color: var(--color-api-changed)\n\ndiv.deprecated\n border-color: var(--color-api-deprecated-border)\n .versionmodified\n color: var(--color-api-deprecated)\n\ndiv.versionremoved\n border-color: var(--color-api-removed-border)\n .versionmodified\n color: var(--color-api-removed)\n\n// Align the [docs] and [source] to the right.\n.viewcode-link, .viewcode-back\n float: right\n text-align: right\n",".line-block\n margin-top: 0.5rem\n margin-bottom: 0.75rem\n .line-block\n margin-top: 0rem\n margin-bottom: 0rem\n padding-left: 1rem\n","// Captions\narticle p.caption,\ntable > caption,\n.code-block-caption\n font-size: var(--font-size--small)\n text-align: center\n\n// Caption above a TOCTree\n.toctree-wrapper.compound\n .caption, :not(.caption) > .caption-text\n font-size: var(--font-size--small)\n text-transform: uppercase\n\n text-align: initial\n margin-bottom: 0\n\n > ul\n margin-top: 0\n margin-bottom: 0\n","// Inline code\ncode.literal, .sig-inline\n background: var(--color-inline-code-background)\n border-radius: 0.2em\n // Make the font smaller, and use padding to recover.\n font-size: var(--font-size--small--2)\n padding: 0.1em 0.2em\n\n pre.literal-block &\n font-size: inherit\n padding: 0\n\n p &\n border: 1px solid var(--color-background-border)\n\n.sig-inline\n font-family: var(--font-stack--monospace)\n\n// Code and Literal Blocks\n$code-spacing-vertical: 0.625rem\n$code-spacing-horizontal: 0.875rem\n\n// Wraps every literal block + line numbers.\ndiv[class*=\" highlight-\"],\ndiv[class^=\"highlight-\"]\n margin: 1em 0\n display: flex\n\n .table-wrapper\n margin: 0\n padding: 0\n\npre\n margin: 0\n padding: 0\n overflow: auto\n\n // Needed to have more specificity than pygments' \"pre\" selector. :(\n article[role=\"main\"] .highlight &\n line-height: 1.5\n\n &.literal-block,\n .highlight &\n font-size: var(--code-font-size)\n padding: $code-spacing-vertical $code-spacing-horizontal\n\n // Make it look like all the other blocks.\n &.literal-block\n margin-top: 1rem\n margin-bottom: 1rem\n\n border-radius: 0.2rem\n background-color: var(--color-code-background)\n color: var(--color-code-foreground)\n\n// All code is always contained in this.\n.highlight\n width: 100%\n border-radius: 0.2rem\n\n // Make line numbers and prompts un-selectable.\n .gp, span.linenos\n user-select: none\n pointer-events: none\n\n // Expand the line-highlighting.\n .hll\n display: block\n margin-left: -$code-spacing-horizontal\n margin-right: -$code-spacing-horizontal\n padding-left: $code-spacing-horizontal\n padding-right: $code-spacing-horizontal\n\n/* Make code block captions be nicely integrated */\n.code-block-caption\n display: flex\n padding: $code-spacing-vertical $code-spacing-horizontal\n\n border-radius: 0.25rem\n border-bottom-left-radius: 0\n border-bottom-right-radius: 0\n font-weight: 300\n border-bottom: 1px solid\n\n background-color: var(--color-code-background)\n color: var(--color-code-foreground)\n border-color: var(--color-background-border)\n\n + div[class]\n margin-top: 0\n pre\n border-top-left-radius: 0\n border-top-right-radius: 0\n\n// When `html_codeblock_linenos_style` is table.\n.highlighttable\n width: 100%\n display: block\n tbody\n display: block\n\n tr\n display: flex\n\n // Line numbers\n td.linenos\n background-color: var(--color-code-background)\n color: var(--color-code-foreground)\n padding: $code-spacing-vertical $code-spacing-horizontal\n padding-right: 0\n border-top-left-radius: 0.2rem\n border-bottom-left-radius: 0.2rem\n\n .linenodiv\n padding-right: $code-spacing-horizontal\n font-size: var(--code-font-size)\n box-shadow: -0.0625rem 0 var(--color-foreground-border) inset\n\n // Actual code\n td.code\n padding: 0\n display: block\n flex: 1\n overflow: hidden\n\n .highlight\n border-top-left-radius: 0\n border-bottom-left-radius: 0\n\n// When `html_codeblock_linenos_style` is inline.\n.highlight\n span.linenos\n display: inline-block\n padding-left: 0\n padding-right: $code-spacing-horizontal\n margin-right: $code-spacing-horizontal\n box-shadow: -0.0625rem 0 var(--color-foreground-border) inset\n","// Inline Footnote Reference\n.footnote-reference\n font-size: var(--font-size--small--4)\n vertical-align: super\n\n// Definition list, listing the content of each note.\n// docutils <= 0.17\ndl.footnote.brackets\n font-size: var(--font-size--small)\n color: var(--color-foreground-secondary)\n\n display: grid\n grid-template-columns: max-content auto\n dt\n margin: 0\n > .fn-backref\n margin-left: 0.25rem\n\n &:after\n content: \":\"\n\n .brackets\n &:before\n content: \"[\"\n &:after\n content: \"]\"\n\n dd\n margin: 0\n padding: 0 1rem\n\n// docutils >= 0.18\naside.footnote\n font-size: var(--font-size--small)\n color: var(--color-foreground-secondary)\n\naside.footnote > span,\ndiv.citation > span\n float: left\n font-weight: 500\n padding-right: 0.25rem\n\naside.footnote > *:not(span),\ndiv.citation > p\n margin-left: 2rem\n","//\n// Figures\n//\nimg\n box-sizing: border-box\n max-width: 100%\n height: auto\n\narticle\n figure, .figure\n border-radius: 0.2rem\n\n margin: 0\n :last-child\n margin-bottom: 0\n\n .align-left\n float: left\n clear: left\n margin: 0 1rem 1rem\n\n .align-right\n float: right\n clear: right\n margin: 0 1rem 1rem\n\n .align-default,\n .align-center\n display: block\n text-align: center\n margin-left: auto\n margin-right: auto\n\n // WELL, table needs to be stylised like a table.\n table.align-default\n display: table\n text-align: initial\n",".genindex-jumpbox, .domainindex-jumpbox\n border-top: 1px solid var(--color-background-border)\n border-bottom: 1px solid var(--color-background-border)\n padding: 0.25rem\n\n.genindex-section, .domainindex-section\n h2\n margin-top: 0.75rem\n margin-bottom: 0.5rem\n ul\n margin-top: 0\n margin-bottom: 0\n","ul,\nol\n padding-left: 1.2rem\n\n // Space lists out like paragraphs\n margin-top: 1rem\n margin-bottom: 1rem\n // reduce margins within li.\n li\n > p:first-child\n margin-top: 0.25rem\n margin-bottom: 0.25rem\n\n > p:last-child\n margin-top: 0.25rem\n\n > ul,\n > ol\n margin-top: 0.5rem\n margin-bottom: 0.5rem\n\nol\n &.arabic\n list-style: decimal\n &.loweralpha\n list-style: lower-alpha\n &.upperalpha\n list-style: upper-alpha\n &.lowerroman\n list-style: lower-roman\n &.upperroman\n list-style: upper-roman\n\n// Don't space lists out when they're \"simple\" or in a `.. toctree::`\n.simple,\n.toctree-wrapper\n li\n > ul,\n > ol\n margin-top: 0\n margin-bottom: 0\n\n// Definition Lists\n.field-list,\n.option-list,\ndl:not([class]),\ndl.simple,\ndl.footnote,\ndl.glossary\n dt\n font-weight: 500\n margin-top: 0.25rem\n + dt\n margin-top: 0\n\n .classifier::before\n content: \":\"\n margin-left: 0.2rem\n margin-right: 0.2rem\n\n dd\n > p:first-child,\n ul\n margin-top: 0.125rem\n\n ul\n margin-bottom: 0.125rem\n",".math-wrapper\n width: 100%\n overflow-x: auto\n\ndiv.math\n position: relative\n text-align: center\n\n .headerlink,\n &:focus .headerlink\n display: none\n\n &:hover .headerlink\n display: inline-block\n\n span.eqno\n position: absolute\n right: 0.5rem\n top: 50%\n transform: translate(0, -50%)\n z-index: 1\n","// Abbreviations\nabbr[title]\n cursor: help\n\n// \"Problematic\" content, as identified by Sphinx\n.problematic\n color: var(--color-problematic)\n\n// Keyboard / Mouse \"instructions\"\nkbd:not(.compound)\n margin: 0 0.2rem\n padding: 0 0.2rem\n border-radius: 0.2rem\n border: 1px solid var(--color-foreground-border)\n color: var(--color-foreground-primary)\n vertical-align: text-bottom\n\n font-size: var(--font-size--small--3)\n display: inline-block\n\n box-shadow: 0 0.0625rem 0 rgba(0, 0, 0, 0.2), inset 0 0 0 0.125rem var(--color-background-primary)\n\n background-color: var(--color-background-secondary)\n\n// Blockquote\nblockquote\n border-left: 4px solid var(--color-background-border)\n background: var(--color-background-secondary)\n\n margin-left: 0\n margin-right: 0\n padding: 0.5rem 1rem\n\n .attribution\n font-weight: 600\n text-align: right\n\n &.pull-quote,\n &.highlights\n font-size: 1.25em\n\n &.epigraph,\n &.pull-quote\n border-left-width: 0\n border-radius: 0.5rem\n\n &.highlights\n border-left-width: 0\n background: transparent\n\n// Center align embedded-in-text images\np .reference img\n vertical-align: middle\n","p.rubric\n line-height: 1.25\n font-weight: bold\n font-size: 1.125em\n\n // For Numpy-style documentation that's got rubrics within it.\n // https://github.com/pradyunsg/furo/discussions/505\n dd &\n line-height: inherit\n font-weight: inherit\n\n font-size: var(--font-size--small)\n text-transform: uppercase\n","article .sidebar\n float: right\n clear: right\n width: 30%\n\n margin-left: 1rem\n margin-right: 0\n\n border-radius: 0.2rem\n background-color: var(--color-background-secondary)\n border: var(--color-background-border) 1px solid\n\n > *\n padding-left: 1rem\n padding-right: 1rem\n\n > ul, > ol // lists need additional padding, because bullets.\n padding-left: 2.2rem\n\n .sidebar-title\n margin: 0\n padding: 0.5rem 1rem\n border-bottom: var(--color-background-border) 1px solid\n\n font-weight: 500\n\n// TODO: subtitle\n// TODO: dedicated variables?\n","[role=main] .table-wrapper.container\n width: 100%\n overflow-x: auto\n margin-top: 1rem\n margin-bottom: 0.5rem\n padding: 0.2rem 0.2rem 0.75rem\n\ntable.docutils\n border-radius: 0.2rem\n border-spacing: 0\n border-collapse: collapse\n\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0 0.0625rem rgba(0, 0, 0, 0.1)\n\n th\n background: var(--color-table-header-background)\n\n td,\n th\n // Space things out properly\n padding: 0 0.25rem\n\n // Get the borders looking just-right.\n border-left: 1px solid var(--color-table-border)\n border-right: 1px solid var(--color-table-border)\n border-bottom: 1px solid var(--color-table-border)\n\n p\n margin: 0.25rem\n\n &:first-child\n border-left: none\n &:last-child\n border-right: none\n\n // MyST-parser tables set these classes for control of column alignment\n &.text-left\n text-align: left\n &.text-right\n text-align: right\n &.text-center\n text-align: center\n",":target\n scroll-margin-top: 2.5rem\n\n@media (max-width: $full-width - $sidebar-width)\n :target\n scroll-margin-top: calc(2.5rem + var(--header-height))\n\n // When a heading is selected\n section > span:target\n scroll-margin-top: calc(2.8rem + var(--header-height))\n\n// Permalinks\n.headerlink\n font-weight: 100\n user-select: none\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\ndl dt,\np.caption,\nfigcaption p,\ntable > caption,\n.code-block-caption\n > .headerlink\n margin-left: 0.5rem\n visibility: hidden\n &:hover > .headerlink\n visibility: visible\n\n // Don't change to link-like, if someone adds the contents directive.\n > .toc-backref\n color: inherit\n text-decoration-line: none\n\n// Figure and table captions are special.\nfigure:hover > figcaption > p > .headerlink,\ntable:hover > caption > .headerlink\n visibility: visible\n\n:target >, // Regular section[id] style anchors\nspan:target ~ // Non-regular span[id] style \"extra\" anchors\n h1,\n h2,\n h3,\n h4,\n h5,\n h6\n &:nth-of-type(1)\n background-color: var(--color-highlight-on-target)\n // .headerlink\n // visibility: visible\n code.literal\n background-color: transparent\n\ntable:target > caption,\nfigure:target\n background-color: var(--color-highlight-on-target)\n\n// Inline page contents\n.this-will-duplicate-information-and-it-is-still-useful-here li :target\n background-color: var(--color-highlight-on-target)\n\n// Code block permalinks\n.literal-block-wrapper:target .code-block-caption\n background-color: var(--color-highlight-on-target)\n\n// When a definition list item is selected\n//\n// There isn't really an alternative to !important here, due to the\n// high-specificity of API documentation's selector.\ndt:target\n background-color: var(--color-highlight-on-target) !important\n\n// When a footnote reference is selected\n.footnote > dt:target + dd,\n.footnote-reference:target\n background-color: var(--color-highlight-on-target)\n",".guilabel\n background-color: var(--color-guilabel-background)\n border: 1px solid var(--color-guilabel-border)\n color: var(--color-guilabel-text)\n\n padding: 0 0.3em\n border-radius: 0.5em\n font-size: 0.9em\n","// This file contains the styles used for stylizing the footer that's shown\n// below the content.\n\nfooter\n font-size: var(--font-size--small)\n display: flex\n flex-direction: column\n\n margin-top: 2rem\n\n// Bottom of page information\n.bottom-of-page\n display: flex\n align-items: center\n justify-content: space-between\n\n margin-top: 1rem\n padding-top: 1rem\n padding-bottom: 1rem\n\n color: var(--color-foreground-secondary)\n border-top: 1px solid var(--color-background-border)\n\n line-height: 1.5\n\n @media (max-width: $content-width)\n text-align: center\n flex-direction: column-reverse\n gap: 0.25rem\n\n .left-details\n font-size: var(--font-size--small)\n\n .right-details\n display: flex\n flex-direction: column\n gap: 0.25rem\n text-align: right\n\n .icons\n display: flex\n justify-content: flex-end\n gap: 0.25rem\n font-size: 1rem\n\n a\n text-decoration: none\n\n svg,\n img\n font-size: 1.125rem\n height: 1em\n width: 1em\n\n// Next/Prev page information\n.related-pages\n a\n display: flex\n align-items: center\n\n text-decoration: none\n &:hover .page-info .title\n text-decoration: underline\n color: var(--color-link)\n text-decoration-color: var(--color-link-underline)\n\n svg.furo-related-icon,\n svg.furo-related-icon > use\n flex-shrink: 0\n\n color: var(--color-foreground-border)\n\n width: 0.75rem\n height: 0.75rem\n margin: 0 0.5rem\n\n &.next-page\n max-width: 50%\n\n float: right\n clear: right\n text-align: right\n\n &.prev-page\n max-width: 50%\n\n float: left\n clear: left\n\n svg\n transform: rotate(180deg)\n\n.page-info\n display: flex\n flex-direction: column\n overflow-wrap: anywhere\n\n .next-page &\n align-items: flex-end\n\n .context\n display: flex\n align-items: center\n\n padding-bottom: 0.1rem\n\n color: var(--color-foreground-muted)\n font-size: var(--font-size--small)\n text-decoration: none\n","// This file contains the styles for the contents of the left sidebar, which\n// contains the navigation tree, logo, search etc.\n\n////////////////////////////////////////////////////////////////////////////////\n// Brand on top of the scrollable tree.\n////////////////////////////////////////////////////////////////////////////////\n.sidebar-brand\n display: flex\n flex-direction: column\n flex-shrink: 0\n\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n text-decoration: none\n\n.sidebar-brand-text\n color: var(--color-sidebar-brand-text)\n overflow-wrap: break-word\n margin: var(--sidebar-item-spacing-vertical) 0\n font-size: 1.5rem\n\n.sidebar-logo-container\n margin: var(--sidebar-item-spacing-vertical) 0\n\n.sidebar-logo\n margin: 0 auto\n display: block\n max-width: 100%\n\n////////////////////////////////////////////////////////////////////////////////\n// Search\n////////////////////////////////////////////////////////////////////////////////\n.sidebar-search-container\n display: flex\n align-items: center\n margin-top: var(--sidebar-search-space-above)\n\n position: relative\n\n background: var(--color-sidebar-search-background)\n &:hover,\n &:focus-within\n background: var(--color-sidebar-search-background--focus)\n\n &::before\n content: \"\"\n position: absolute\n left: var(--sidebar-item-spacing-horizontal)\n width: var(--sidebar-search-icon-size)\n height: var(--sidebar-search-icon-size)\n\n background-color: var(--color-sidebar-search-icon)\n mask-image: var(--icon-search)\n\n.sidebar-search\n box-sizing: border-box\n\n border: none\n border-top: 1px solid var(--color-sidebar-search-border)\n border-bottom: 1px solid var(--color-sidebar-search-border)\n\n padding-top: var(--sidebar-search-input-spacing-vertical)\n padding-bottom: var(--sidebar-search-input-spacing-vertical)\n padding-right: var(--sidebar-search-input-spacing-horizontal)\n padding-left: calc(var(--sidebar-item-spacing-horizontal) + var(--sidebar-search-input-spacing-horizontal) + var(--sidebar-search-icon-size))\n\n width: 100%\n\n color: var(--color-sidebar-search-foreground)\n background: transparent\n z-index: 10\n\n &:focus\n outline: none\n\n &::placeholder\n font-size: var(--sidebar-search-input-font-size)\n\n//\n// Hide Search Matches link\n//\n#searchbox .highlight-link\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal) 0\n margin: 0\n text-align: center\n\n a\n color: var(--color-sidebar-search-icon)\n font-size: var(--font-size--small--2)\n\n////////////////////////////////////////////////////////////////////////////////\n// Structure/Skeleton of the navigation tree (left)\n////////////////////////////////////////////////////////////////////////////////\n.sidebar-tree\n font-size: var(--sidebar-item-font-size)\n margin-top: var(--sidebar-tree-space-above)\n margin-bottom: var(--sidebar-item-spacing-vertical)\n\n ul\n padding: 0\n margin-top: 0\n margin-bottom: 0\n\n display: flex\n flex-direction: column\n\n list-style: none\n\n li\n position: relative\n margin: 0\n\n > ul\n margin-left: var(--sidebar-item-spacing-horizontal)\n\n .icon\n color: var(--color-sidebar-link-text)\n\n .reference\n box-sizing: border-box\n color: var(--color-sidebar-link-text)\n\n // Fill the parent.\n display: inline-block\n line-height: var(--sidebar-item-line-height)\n text-decoration: none\n\n // Don't allow long words to cause wrapping.\n overflow-wrap: anywhere\n\n height: 100%\n width: 100%\n\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n\n &:hover\n color: var(--color-sidebar-link-text)\n background: var(--color-sidebar-item-background--hover)\n\n // Add a nice little \"external-link\" arrow here.\n &.external::after\n content: url('data:image/svg+xml,')\n margin: 0 0.25rem\n vertical-align: middle\n color: var(--color-sidebar-link-text)\n\n // Make the current page reference bold.\n .current-page > .reference\n font-weight: bold\n\n label\n position: absolute\n top: 0\n right: 0\n height: var(--sidebar-item-height)\n width: var(--sidebar-expander-width)\n\n cursor: pointer\n user-select: none\n\n display: flex\n justify-content: center\n align-items: center\n\n .caption, :not(.caption) > .caption-text\n font-size: var(--sidebar-caption-font-size)\n color: var(--color-sidebar-caption-text)\n\n font-weight: bold\n text-transform: uppercase\n\n margin: var(--sidebar-caption-space-above) 0 0 0\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n\n // If it has children, add a bit more padding to wrap the content to avoid\n // overlapping with the