diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 0000000..9f0acc7 --- /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: fd8ea45cda0bf6a8165e8a72a61a1875 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.github/scripts/yamlheader.html b/.github/scripts/yamlheader.html new file mode 100644 index 0000000..55e553b --- /dev/null +++ b/.github/scripts/yamlheader.html @@ -0,0 +1,121 @@ + + + + + + + <no title> — Key4hep documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ + + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/CONDUCT.html b/CONDUCT.html new file mode 100644 index 0000000..01a85cd --- /dev/null +++ b/CONDUCT.html @@ -0,0 +1,143 @@ + + + + + + + Contributor Code of Conduct — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Contributor Code of Conduct

+

As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.

+

We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.

+

Examples of unacceptable behaviour by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.

+

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.

+

Instances of abusive, harassing, or otherwise unacceptable behaviour may be reported by opening an issue or contacting one or more of the project maintainers.

+

This Code of Conduct is adapted from the Contributor Covenant, version 1.0.0, available at https://contributor-covenant.org/version/1/0/0/.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/CONTRIBUTING.html b/CONTRIBUTING.html new file mode 100644 index 0000000..21cf6b7 --- /dev/null +++ b/CONTRIBUTING.html @@ -0,0 +1,162 @@ + + + + + + + Contributing — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Contributing

+

Key4hep is an open source project, and we welcome contributions of all kinds:

+
    +
  • New lessons

  • +
  • Fixes to existing material

  • +
  • Bug reports

  • +
  • Reviews of proposed changes

  • +
+

By contributing, you are agreeing that we may redistribute your work under +these licenses. You also agree to abide by our contributor code of +conduct.

+
+

Getting Started

+
    +
  1. We use the fork and pull model to manage changes. +More information about forking a repository and making a Pull Request.

  2. +
  3. You should branch from and submit pull requests against the main branch +(in some repositories it may still be master but this will change in the +future to main).

  4. +
  5. If you’re looking for things to work on, feel free to get in touch with the +Key4hep team at key4hep dash sw @ cern dot ch. You can also have a look at +the the list of issues for this repository. Comments on issues and +reviews of pull requests are equally welcome.

  6. +
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/LICENSE.html b/LICENSE.html new file mode 100644 index 0000000..469c1d3 --- /dev/null +++ b/LICENSE.html @@ -0,0 +1,138 @@ + + + + + + + Software — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Software

+

Except where otherwise noted, the example programs and other software provided +by Software Carpentry are made available under the OSI-approved Apache +2.0.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_images/doxygen_class_list.png b/_images/doxygen_class_list.png new file mode 100644 index 0000000..6b9a2c6 Binary files /dev/null and b/_images/doxygen_class_list.png differ diff --git a/_images/doxygen_reco_particle.png b/_images/doxygen_reco_particle.png new file mode 100644 index 0000000..763e9ad Binary files /dev/null and b/_images/doxygen_reco_particle.png differ diff --git a/_images/doxygen_type_table.png b/_images/doxygen_type_table.png new file mode 100644 index 0000000..f61e85a Binary files /dev/null and b/_images/doxygen_type_table.png differ diff --git a/_images/edm4hep_branches_1.png b/_images/edm4hep_branches_1.png new file mode 100644 index 0000000..703d505 Binary files /dev/null and b/_images/edm4hep_branches_1.png differ diff --git a/_images/edm4hep_browse_relations_1.png b/_images/edm4hep_browse_relations_1.png new file mode 100644 index 0000000..747cbe7 Binary files /dev/null and b/_images/edm4hep_browse_relations_1.png differ diff --git a/_images/edm4hep_doxygen.png b/_images/edm4hep_doxygen.png new file mode 100644 index 0000000..ab17647 Binary files /dev/null and b/_images/edm4hep_doxygen.png differ diff --git a/_images/key4hep_logo1.svg b/_images/key4hep_logo1.svg new file mode 100644 index 0000000..52093c9 --- /dev/null +++ b/_images/key4hep_logo1.svg @@ -0,0 +1,167 @@ + + + + + + + + + + image/svg+xml + + + + + + + K + + + + + Y + E + HEP + 4 + + + + diff --git a/_images/key4hep_logo2.svg b/_images/key4hep_logo2.svg new file mode 100644 index 0000000..956c304 --- /dev/null +++ b/_images/key4hep_logo2.svg @@ -0,0 +1,607 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + Key4HEP + + + + diff --git a/_images/key4hep_logo3.png b/_images/key4hep_logo3.png new file mode 100644 index 0000000..3194eb6 Binary files /dev/null and b/_images/key4hep_logo3.png differ diff --git a/_images/key4hep_logo6.svg b/_images/key4hep_logo6.svg new file mode 100644 index 0000000..819f427 --- /dev/null +++ b/_images/key4hep_logo6.svg @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4hep + Key + + diff --git a/_images/key4hep_logo6p1.svg b/_images/key4hep_logo6p1.svg new file mode 100644 index 0000000..95fd45c --- /dev/null +++ b/_images/key4hep_logo6p1.svg @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + Key + + + + + + + + + + + + + + + + 4hep + + + + + + + + + + + + + diff --git a/_images/key4hep_logo7.svg b/_images/key4hep_logo7.svg new file mode 100644 index 0000000..9aaff22 --- /dev/null +++ b/_images/key4hep_logo7.svg @@ -0,0 +1,23 @@ + + + key4hep_v0 + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_images/key4hep_logo7p1.svg b/_images/key4hep_logo7p1.svg new file mode 100644 index 0000000..77a799c --- /dev/null +++ b/_images/key4hep_logo7p1.svg @@ -0,0 +1,23 @@ + + + key4hep_v1 + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_images/marlin_wrapper_tools.png b/_images/marlin_wrapper_tools.png new file mode 100644 index 0000000..1312b0f Binary files /dev/null and b/_images/marlin_wrapper_tools.png differ diff --git a/_sources/.github/scripts/yamlheader.md.txt b/_sources/.github/scripts/yamlheader.md.txt new file mode 100644 index 0000000..a37817e --- /dev/null +++ b/_sources/.github/scripts/yamlheader.md.txt @@ -0,0 +1,8 @@ +--- +jupyter: + kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + diff --git a/_sources/CONDUCT.md.txt b/_sources/CONDUCT.md.txt new file mode 100644 index 0000000..922ba82 --- /dev/null +++ b/_sources/CONDUCT.md.txt @@ -0,0 +1,13 @@ +# Contributor Code of Conduct + +As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. + +We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion. + +Examples of unacceptable behaviour by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team. + +Instances of abusive, harassing, or otherwise unacceptable behaviour may be reported by opening an issue or contacting one or more of the project maintainers. + +This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/), version 1.0.0, available at [https://contributor-covenant.org/version/1/0/0/](https://www.contributor-covenant.org/version/1/0/0/). diff --git a/_sources/CONTRIBUTING.md.txt b/_sources/CONTRIBUTING.md.txt new file mode 100644 index 0000000..9fa668e --- /dev/null +++ b/_sources/CONTRIBUTING.md.txt @@ -0,0 +1,43 @@ +# Contributing + +Key4hep is an open source project, and we welcome contributions of all kinds: + +* New lessons +* Fixes to existing material +* Bug reports +* Reviews of proposed changes + +By contributing, you are agreeing that we may redistribute your work under +[these licenses][license]. You also agree to abide by our [contributor code of +conduct][conduct]. + +## Getting Started + +1. We use the [fork and pull][gh-fork-pull] model to manage changes. + More information about [forking a repository][gh-fork] and [making a Pull Request][gh-pull]. + +2. You should branch from and submit pull requests against the `main` branch + (in some repositories it may still be `master` but this will change in the + future to `main`). + +3. If you're looking for things to work on, feel free to get in touch with the + Key4hep team at key4hep dash sw @ cern dot ch. You can also have a look at + the [the list of issues for this repository][issues]. Comments on issues and + reviews of pull requests are equally welcome. + +[conduct]: CONDUCT.md +[issues]: https://github.com/search?o=desc&q=org%3Akey4hep&s=created&type=Issues +[license]: LICENSE.md +[pro-git-chapter]: http://git-scm.com/book/en/v2/GitHub-Contributing-to-a-Project +[gh-fork]: https://help.github.com/en/articles/fork-a-repo +[gh-pull]: https://help.github.com/en/articles/about-pull-requests +[gh-fork-pull]: https://reflectoring.io/github-fork-and-pull/ + + +```{eval-rst} +.. toctree:: + :hidden: + + CONDUCT.md + LICENSE.md +``` diff --git a/_sources/LICENSE.md.txt b/_sources/LICENSE.md.txt new file mode 100644 index 0000000..fa5ecc4 --- /dev/null +++ b/_sources/LICENSE.md.txt @@ -0,0 +1,8 @@ +# Software + +Except where otherwise noted, the example programs and other software provided +by Software Carpentry are made available under the [OSI][osi]-approved [Apache +2.0][license]. + +[license]: https://opensource.org/license/apache-2-0/ +[osi]: https://opensource.org diff --git a/_sources/call-for-logos/README.md.txt b/_sources/call-for-logos/README.md.txt new file mode 100644 index 0000000..c1e3e72 --- /dev/null +++ b/_sources/call-for-logos/README.md.txt @@ -0,0 +1,31 @@ +# Call for logos + +Logo 1 + +![](key4hep_logo1.svg) + +Logo 2 + +![](key4hep_logo2.svg) + +Logo 3 + +![](key4hep_logo3.png) + +Logo 4 + + + +Logo 5 + + + +Logo 6 + +![](key4hep_logo6.svg) +![](key4hep_logo6p1.svg) + +Logo 7 + +![](key4hep_logo7.svg) +![](key4hep_logo7p1.svg) diff --git a/_sources/developing-key4hep-software/CMakeBuild.md.txt b/_sources/developing-key4hep-software/CMakeBuild.md.txt new file mode 100644 index 0000000..c2a2993 --- /dev/null +++ b/_sources/developing-key4hep-software/CMakeBuild.md.txt @@ -0,0 +1,97 @@ +# Building Key4hep using CMake: For Developers + +A common problem when developing is needing to build multiple packages on top of +the stack to test changes in several repositories. One way of doing this is +using Spack but there is an experimental way using cmake. + +First, source the releases or the nightlies as usual. Then, run the following +command: + +``` +/cvmfs/sw-nightlies.hsf.org/key4hep/experimental/setup.py pkg1 pkg2 +``` + +Where `pkg1` and `pkg2` are the packages that will be cloned (can be empty). On +top of that, `setup.py` checks for folders (or symbolic links) in the current +directory that contain `CMakeLists.txt`. This can be useful if we want to use a +local version and don't need to clone some repositories. After running the +command, a CMakeLists.txt file will appear. We may have to edit it manually if +we are using packages that are not recognized or are in a different organization +than the predefined ones. The information that we'll need to edit is most likely +one of the first lines at the top: + +``` +set(pkgs EDM4hep k4FWCore) +``` +that sets the packages that will be built in their right build order. +and the individual `FetchContent_Declare` entries for each package. + +After we are happy with the CMakeLists.txt file, it's important that we set the +new environment variables: + +``` bash +mkdir install +cd install +export PATH=$PWD/bin:$PATH +export LD_LIBRARY_PATH=$PWD/lib:$PWD/lib64:$LD_LIBRARY_PATH +export ROOT_INCLUDE_PATH=$PWD/include:$ROOT_INCLUDE_PATH +export PYTHONPATH=$PWD/python:$PYTHONPATH +export CMAKE_PREFIX_PATH=$PWD:$CMAKE_PREFIX_PATH +cd .. +``` + +Then, we can run the usual commands for building: + +``` +mkdir build +cd build +cmake .. -DCMAKE_INSTALL_PREFIX=../install +make -j N install +``` + +and it will build all the packages at the same time, so it may take some time. Symbolic links are +created in the build directory for each package that allow us to run `ctest` like: + +``` bash +cd k4FWCore +ctest -j 2 +``` + +in case we are building k4FWCore. + +For the cloned directories, in case we want to clone a different commit or +branch from the master/main branch, this can be done by editing the +CMakeLists.txt + + +## Possible issues + +Not everything has been tested so it's likely some things won't work. For +many packages there are recent changes that enable these builds so using older +versions probably won't work. + +## Packages that have been tested + +The following packages have been built together successfully so it should be +possible to build any combination of them: +- podio +- EDM4hep +- k4FWCore +- LCIO +- ILCUTIL +- LCCD +- GEAR +- Marlin +- k4EDM4hep2LcioConv +- k4MarlinWrapper + +## Changing to a different commit or branch + +If we don't want to build the master or main branch of the repositories we are +cloning, we have two options: + +- Set the commit or branch we want in the `CMakeLists.txt` in the corresponding + `FetchContent_Declare` entry by changing `GIT_TAG` to whatever commit or branch + we want to checkout. +- Go to the source directory, which can be found in the build directory under + `_deps/-src` and checkout manually whatever commit or branch you want. diff --git a/_sources/developing-key4hep-software/Key4hepCMakeGuide.md.txt b/_sources/developing-key4hep-software/Key4hepCMakeGuide.md.txt new file mode 100644 index 0000000..bbfdb70 --- /dev/null +++ b/_sources/developing-key4hep-software/Key4hepCMakeGuide.md.txt @@ -0,0 +1,131 @@ +# CMake guide for Key4hep software + +## Overview + +CMake is a tool for building software, which has become the de-facto +standard outside HEP. In HEP, it is for example used by the ILC/CLIC +communities and by the LHCb collaboration. For CMS people, CMake is the +equivalent of scram. + +## Quick start into building Key4hep Software + +### Set up the environment + +The first step is adding all dependencies to the bash environment. +In case you are unsure, it is best to use the default init script, provided on CVMFS for Centos7: + +``` +source /cvmfs/sw.hsf.org/key4hep/setup.sh +``` + +Note that mixing setup scripts (from another package, for example) may or may not work as intended - more likely not. +For any requests to changes in the environment, feel free to contact the software team on the mailing list or any other channels. +Developers may also look into `spack` to have more fine-grained control over the build dependencies. + + +### Running CMake + +* Create a build directory: `mkdir build; cd build` +* Run CMake in the build directory: `cmake .. ` +* Change any cmake options by rerunning cmake.\ + For example: `cmake .. -DCMAKE_INSTALL_PREFIX=../install -DCMAKE_BUILD_TYPE=Debug`.\ + Tools like ccmake may also be useful: `ccmake ..` +* Compile the software, using all the cpus available: ```make -j `getconf _NPROCESSORS_ONLN` ``` +* Install by running `make install` +* In case any dependency is changed, most likely you need to remove all the contents of the build folder and rerun cmake and the compilation. + +### Using your local installation + +In order to run the code you just installed, there are a few environment variables to set up (assuming the installation directory is the working directory): + +``` +mkdir build; cd build +cmake .. -DCMAKE_INSTALL_PREFIX=../InstallArea +make install +cd ../InstallArea +``` + +* `export CMAKE_PREFIX_PATH=$PWD/:$CMAKE_PREFIX_PATH` + - in order to use this installation as a dependency for other packages +* `export PATH=$PWD/bin/:$PATH` + - in order to make any executables available on the command line +* `export LD_LIBRARY_PATH=$PWD/lib:$PWD/lib64:$LD_LIBRARY_PATH` + - in order to make libraries available for linking and for the plugin systems in Gaudi/DD4hep +* `export PYTHONPATH=$PWD/python:$PYTHONPATH` + - in order to make libraries available for linking and for the plugin systems in Gaudi/DD4hep +* `export ROOT_INCLUDE_PATH=$PWD/include:$ROOT_INCLUDE_PATH` + - in case the package builds ROOT dictionaries +* `export =$PWD/share/` + - some packages distribute data files that are found with a special environment variable, usually this is the package name in all caps. + - e.g. `export K4SIMDELPHES=$PWD/share/k4SimDelphes/` + +## CMake example packages + +Colin provides [a few simple CMake +examples](https://github.com/cbernet/cmake-examples). They are helpful to understand the basics of +CMake. + +Get these packages: + + git clone https://github.com/cbernet/cmake-examples.git + cd cmake-examples + +Follow the instructions in +[README.md](https://github.com/cbernet/cmake-examples/blob/master/README.md). + +## Changing the CMake Configuration + + +When adding new source files to a package, the CMake build system needs +to be made aware of them. Usually `CMakeLists.txt` contains a wildcard +expression that adds all implementation files in a subfolder, e.g. +`src/*.cpp` , so there is no need to explicitly add the names of the +new files. To update the list of files, it is fastest to run +`make configure` . + +Note that when changing the name of a property of an algorithm or a +tool, `make` (and not only `make packagename` ) needs to be run for +Gaudi to be aware of the change. + + +### Runtime Environment + +Key4hep packages, in particular the gaudi framework components, consist of executables, headers, scripts, dynamic libraries, xmls and special files describing gaudi components. +In order to use these, some environment variables need to be set. + +Gaudi also offers the possibility to set up the environment via the `xenv` command. This is done by simply prefixing the command you want to run with the `run` script in the top level directory of FCCSW, or directly in the build directory. + +```bash +./build/run key4run Examples/options/pythia.py +``` + +Sometimes it is convenient to run FCCSW directly from the binaries in the build directory without installing them. +This can be done by using the `run` script in the build directory, or setting the environment variables as in `setup.sh` for the build folder. +Note that the directories in the build folder differ a bit. Mostly it is important the the LD_LIBRARY_PATH is pre-fixed with the library directories. The fccrun command should pick up the components from the build folder then. + + + +## CTest in Key4hep + +Key4hep also uses CMake for integration tests. +They are added with `add_test()` and can be run with `make test` in the build folder. For Gaudi packages, the environment should be set so they can be run also in a build environments, see https://github.com/HEP-FCC/k4Gen/blob/main/k4Gen/CMakeLists.txt + + + +### Customizing how CMake is run + +An environment variable is used to forward command line arguments to the cmake command, for example to run cmake with the `trace` option: + +``` +CMAKEFLAGS='--trace' make +``` + +{% callout "How do I check compilation flags?" %} + +Instead of running ` make` , run: + + ```bash + make VERBOSE=1 + ``` + +{% endcallout %} diff --git a/_sources/developing-key4hep-software/Key4hepSoftwareGit.md.txt b/_sources/developing-key4hep-software/Key4hepSoftwareGit.md.txt new file mode 100644 index 0000000..db9baae --- /dev/null +++ b/_sources/developing-key4hep-software/Key4hepSoftwareGit.md.txt @@ -0,0 +1,193 @@ +# Github workflow and contribution guide + +## Overview + +This page should allow users that are new to Git to get started with Key4hep software, and describes the workflow for accessing and contributing code. + +For a general introduction to git, have a look at these tutorials: + +- [Atlassian tutorial](https://www.atlassian.com/git/tutorials/) +- [Interactive tutorial](http://pcottle.github.io/learnGitBranching/) +- [The git book](https://git-scm.com/book/en/v2) + +## First time setup of git + +Please refer to [this tutorial](https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup) and the [GitHub help](https://help.github.com/articles/set-up-git/). + +## Generate and set up ssh keys for github + +We recommend to clone github repositories via SSH, especially if you want to +contribute code. For this to work, you need to generate ssh keys for +authentication. See the corresponding github +[help-page](https://help.github.com/articles/generating-an-ssh-key/). + +{% callout "Generate and set up ssh keys for github" %} + + If you only want to use the software it may be easier to use https. In that case you don't need to generate the keys but have to replace `git@github:` with `https://github.com/` in all the instructions. Note that you'll not be able to push to your repository when you are on lxplus. You can also start using https for now and later re-add your repository with ssh authentication, see the [trouble shooting section](#trouble-shooting). + +{% endcallout %} + + +## Improving your git experience + +It may be useful to install [Git integration tools](https://github.com/git/git/tree/master/contrib/completion) for your shell that allow tab-completion of most git commands and also can show you in your prompt on which branch you currently are, what changes you have pending, etc. + +## Development workflow + +For any key4hep repository (taking `k4SimDelphes` as an example), you will be using (at least) 3 sources: + +1. The official [Key4hep repository on github](https://github.com/key4hep/k4SimDelphes) +2. Your fork of the repository (see [github help](https://help.github.com/articles/fork-a-repo/) on what that means) +3. Your local repository in your work area (e.g. on AFS) + +The repositories 1 and 2 are added as remote to the repository 3: + +```bash +git clone git@github.com:[YOUR_GITHUB_USER]/k4SimDelphes.git # create a local copy (3) of your fork (2) +cd k4SimDelphes +git remote add upstream git@github.com:key4hep/k4SimDelphes.git # add official repo (1) as additional remote +``` + +### Keeping your local repository up to date + +- fetch all changes from the official repository (1) + + ```bash + git fetch --all --prune + ``` + +- rebase your development area to the master branch from the official repository (1), **please read [this](https://www.atlassian.com/git/tutorials/rewriting-history) to avoid loss of work** + + ```bash + git rebase -i upstream/main + ``` + + in this process you can also fix any commits that need touching up, **be aware that deleting commits in the list will result also in the deletion of the corresponding changes** (more info in the [GitHub help](https://help.github.com/articles/about-git-rebase/) and the [Atlassian tutorial](https://www.atlassian.com/git/tutorials/rewriting-history)) + +- push your local changes to your fork (2), see [below](#contributing-code) how to create a local branch + + ``` + git push origin [NAME_OF_LOCAL_BRANCH] + ``` + +### Contributing code + +- if you are fixing a bug, first create an issue in the github issue tracker. +- develop your feature in your local copy (3) on a local branch of your choice, to create a branch do: + + ``` + git branch -b [NAME_OF_LOCAL_BRANCH] + ``` + +- refer to [this tutorial](https://www.atlassian.com/git/tutorials/saving-changes) to see how to commit changes +- occasionally, get new code from the official repository (1) as explained above and merge it in this branch +- test: + - that the code compiles and all tests succeed (`make && make test`) + - that your code runs (even better: [add an automatic test] + - that it produces the expected results +- push your local branch to your fork (2) (see [above](#keeping-your-local-repository-up-to-date)) +- create a pull request from your fork (2) to the offical repository's (1) master branch (see github [help-page](https://help.github.com/articles/creating-a-pull-request/)) + - also see the [recommendations for pull requests](#pull-requests) + +## Recommendations + +Please always follow the recommendations below. + +### General recommendations + +- if you're working on a given topic, always create a branch for + it, e.g. `pythia_interface`. You may commit many times to this branch + in your local repository. When you have something solid create a + pull request to the official repository. + +### Commit comments + +- feel free to commit often to your local repository, make a pull request once the topic you are working on is finished + - if the feature you are working on is large, consider making a work in progress-pull request (see [below](#pull-requests)) + - git commits represent a snapshot of the software as a whole, and not only the difference to a previous commit (although that as well, in practice). It is recommended that each commit compiles and passes the tests. Take a look at the [commit history of a key4hep repository](https://github.com/key4hep/k4simdelphes/commits/main) and the histories of some individual files to find both good and bad examples. + +- always provide a meaningful comment for each commit + - if you are working on an issue, refer to that issue by adding "refs. #[issue id]", see also + [GitHub help](https://help.github.com/articles/closing-issues-via-commit-messages/) +- commit comments should look like the one below, so that they show up + correctly in git printouts. + + ``` + first version of a pythia interface # this line should be a short 1 liner + + Here, you may write a few more lines if needed + ``` + +### Cleaning history + +- before opening a pull request it may be a good idea to check that your history makes sense (commit messages explain what you did, no unnecessary commits, etc.), check with: + + ``` + git log + ``` +- if you see commits that you'd like to change, there are several ways of doing that, the most commonly used is `git rebase`: + - with the interactive version you can rebase your development branch to the official master and fix the history at the same time + + ``` + git fetch upstream # get changes from the official repo + git rebase -i upstream/main # do the actual rebase + ``` + + - git will guide you through the steps, where you can delete entire commits (and the corresponding changes), merge commits and change commit messages + - more information can be found in [this tutorial](https://www.atlassian.com/git/tutorials/rewriting-history#git-rebase-i) + +### Pull requests + +- Give a meaningful title that appropriately describes what you did (e.g. Add new calorimeter clustering) + - Pull requests of work in progress (to make people aware that you are working on a feature) create a PR starting with "[WIP]" +- In the description, give a short bullet-point list of what was done +- If your pull request fixes issues tracked in the issue tracker: + - Make sure you added a test that shows they are actually fixed + - In the description mention that you fixed it by referring to the issue: "fixes #" (this will automatically close the issue, see also [GitHub help](https://help.github.com/articles/closing-issues-via-commit-messages/)) + +## Trouble-shooting + +### When I try to push to the repository, I get an authentication error + +Check with `git remote -v` which remote repositories you have added to your local copy. You should see something like: + +``` +upstream git@github.com:key4hep/k4SimDelphes.git (fetch) +upstream git@github.com:key4hep/k4SimDelphes.git (push) +origin git@github.com:[your git user name]/k4SimDelphes.git (fetch) +origin git@github.com:[your git user name]/k4SimDelphes.git (push) +``` + +If you see something similar but all the addresses start with `https`, see [below](#i-have-cloned-with-https-and-now-i-cant-push-my-changes-what-do-i-do). + +If you only see `origin git@github.com:key4hep/k4SimDelphes.git`, you need to add your own repository, push to that one and do a pull request, as described above. To add your own repository do: + +``` +git remote rename origin hep-fcc +git remote add myfccsw git@github.com:[your git user name]/FCCSW.git +``` + + +### I have cloned with https and now I can't push my changes, what do I do? + +You only need to change the URL of your remote pointing to your repository to one that uses SSH instead: + +``` +git remote set-url [the remote name] git@github.com:[your git user name]/k4SimDelphes.git +``` + +Now you can push to that remote with: + +``` +git push [the remote name] [the branch you want to push] +``` + +--- + +## Need help? + +In case you have any questions on this guide, or need help to sort out +an issue with a repository, feel free to drop a mail to +key4hep-sw at CERN, and we'll be happy to help you. +Alternatively create an issue in the [bug tracker](https://github.com/key4hep) +![smile](https://twiki.cern.ch/twiki/pub/TWiki/SmiliesPlugin/smile.gif "smile"). diff --git a/_sources/developing-key4hep-software/README.md.txt b/_sources/developing-key4hep-software/README.md.txt new file mode 100644 index 0000000..9955c43 --- /dev/null +++ b/_sources/developing-key4hep-software/README.md.txt @@ -0,0 +1,19 @@ +# Developing Key4hep + +Sooner rather than later you will find it necessary write code for Key4hep. These pages cover some software development topics to remove any friction. + + + +```{eval-rst} +.. toctree:: + :caption: Contents: + + Key4hepSoftwareGit.md + Key4hepCMakeGuide.md + SinglePackage.md + SpackForDevelopers.md + WritingAlgorithms.md + +CMakeBuild.md + +``` diff --git a/_sources/developing-key4hep-software/SinglePackage.md.txt b/_sources/developing-key4hep-software/SinglePackage.md.txt new file mode 100644 index 0000000..37398c0 --- /dev/null +++ b/_sources/developing-key4hep-software/SinglePackage.md.txt @@ -0,0 +1,26 @@ +# Developing a single package + +For quick changes of, for example, a single package, it's possible to compile +the package using cmake (after having sourced the release or nightlies) and then +export some environment variables manually so that our local version will be +picked up instead of the one in cvmfs: + +``` bash +export PATH=/path/to/install/bin:$PATH +export LD_LIBRARY_PATH=/path/to/install/lib:/path/to/install/lib64:$LD_LIBRARY_PATH +export ROOT_INCLUDE_PATH=/path/to/install/include:$ROOT_INCLUDE_PATH +export PYTHONPATH=/path/to/install/python:$PYTHONPATH +``` + +where the path to the installation is the one we gave cmake with +`-DCMAKE_INSTALL_PREFIX` when configuring. It's possible more environment +variables need to be set depending on which package we are installing but the +previous ones are the main ones for many of the packages of the key4hep stack. + +While this approach works and any number of packages can be built this way, it +is cumbersome to do so for many packages, as one has to repeat the cycle of +configuring, building and installing and then exporting the environment +variables as many times as packages are installed. It is possible to miss +packages and then the cvmfs version will be used instead of the local one +without notice and it's also cumbersome to reproduce the environment at a later +time. diff --git a/_sources/developing-key4hep-software/SpackForDevelopers.md.txt b/_sources/developing-key4hep-software/SpackForDevelopers.md.txt new file mode 100644 index 0000000..04a0301 --- /dev/null +++ b/_sources/developing-key4hep-software/SpackForDevelopers.md.txt @@ -0,0 +1,314 @@ +# Building Key4hep using Spack: For Developers + +Using spack to develop software is somewhat pushing its intended usage to its +limits. However, it is not impossible and this is an area of spack that is +currently under active development. Unfortunately, this also means that the +spack documentation might not be fully up-to-date on these topics. Hence, this +page tries to collect some of the experiences the Key4hep developers have made. + +```{tip} +To obtain and setup `spack` take a look at {doc}`/spack-build-instructions-for-librarians/spack-setup`. +``` + +## Spack set up + +For a standalone spack installation where we are happy to install all the +dependencies the link above will suffice. However, it is possible to use the +key4hep stack from cvmfs that has all the dependencies installed and only +install the packages that we want to work on. For that, it is important to +reproduce the environment that was used for building whatever release we are +going to use. Otherwise spack will see that we have different versions of +packages and will try to compile and install more than what we need. As +explained here, there are three files that are provided with each release or +nightly, that we need to use. Let's say we want to use the nigthly for +2023-07-18. Then the first thing we do is source the nightly: + +``` bash +source /cvmfs/sw-nightlies.hsf.org/key4hep/releases/2023-07-18/x86_64-almalinux9-gcc11.3.1-opt/key4hep-stack/2023-07-18-kzukii/setup.sh +``` + +And then we clone spack and key4hep-spack, set up the environment and the +upstream installation, and the latest build from scratch (that we have to find +manually for now using, for example, `find -iname .scratch`), in this case it +happens to be 2023-06-24): + +``` bash +rel=/cvmfs/sw-nightlies.hsf.org/key4hep/releases/2023-07-18/x86_64-almalinux9-gcc11.3.1-opt +latest_scratch=/cvmfs/sw-nightlies.hsf.org/key4hep/releases/2023-06-24/x86_64-almalinux9-gcc11.3.1-opt +git clone https://github.com/key4hep/key4hep-spack --depth 1 +git clone https://github.com/spack/spack +cd key4hep-spack +git checkout $(cat $rel/.key4hep-spack-commit) +cd .. +cd spack +git checkout $(cat $rel/.spack-commit) +source $rel/.cherry-pick +cd .. +source spack/share/spack/setup-env.sh +spack env activate key4hep-spack/environments/key4hep-nightly +spack config add "upstreams:nightly:install_tree: $rel" +spack config add "upstreams:nightly-scratch:install_tree: $latest_scratch" +``` + +And now we should have exactly the same version of spack and key4hep-spack that +was used to make the build, so the number of dependencies that spack tries to +install should be the minimum: it should find all the dependencies (in practice +this may not be the case but it should find most of them). + +## Developing a single package + +When only developing on a single package it is possible to use the [`dev-build`](https://spack.readthedocs.io/en/latest/command_index.html#spack-dev-build) command of spack. +A brief tutorial can be found in [the spack documentation](https://spack-tutorial.readthedocs.io/en/latest/tutorial_developer_workflows.html). +There is also a dedicated channel on slack [spackpm.slack.com](https://spackpm.slack.com) (to get an invitation, visit [slack.spack.io](https://slack.spack.io)) where questions regarding the development workflow can be discussed. +It allows to build a given package directly from local sources in the same way as spack does it, and even makes this package available to other packages in the same way it does packages that have been installed by spack directly. +Here we will use [LCIO](https://github.com/iLCSoft/LCIO) as an example since it can be installed without (or with only one) dependency. + +As a first step let's have a look at what installing `lcio` with spack would entail. +Note that we explicitly disable the ROOT dictionaries in order to limit the number of dependencies +```bash +spack spec -Il lcio ~rootdict +``` +``` +Input spec +-------------------------------- + - lcio~rootdict + +Concretized +-------------------------------- + + - vdwx2aq lcio@2.16%gcc@9.3.0~examples~ipo~jar~rootdict build_type=RelWithDebInfo cxxstd=17 arch=linux-ubuntu20.04-skylake +[+] utzbuq7 ^cmake@3.16.3%gcc@9.3.0~doc+ncurses+openssl+ownlibs~qt patches=1c540040c7e203dd8e27aa20345ecb07fe06570d56410a24a266ae570b1c4c39,bf695e3febb222da2ed94b3beea600650e4318975da90e4a71d6f31a6d5d8c3d arch=linux-ubuntu20.04-skylake +[+] pljbs5a ^sio@0.0.4%gcc@9.3.0+builtin_zlib~ipo build_type=RelWithDebInfo cxxstd=17 arch=linux-ubuntu20.04-skylake + +``` + +In this configuration `lcio` has only two dependencies, `sio` and `cmake`, which +are both already installed in this case. If these dependencies are not yet +installed, spack will automatically install them for you when using the +`dev-build` command. + +### Installing a local version with `dev-build` + +In order to install a local version of LCIO with spack, first we have to clone it into a local directory +```bash +git clone https://github.com/iLCSoft/LCIO +``` + +Now we can install this local version via +```bash +cd LCIO +spack dev-build lcio@master ~rootdict +``` +This should install `lcio` and all dependencies that are not yet fulfilled, giving you the full output of all the build stages ending on something like the following +``` +... +==> lcio: Successfully installed lcio-master-7dovpqn3kscbg672ham5wcqro7lg45gh + Fetch: 0.00s. Build: 1.62s. Total: 1.62s. +[+] /home/tmadlener/work/spack/opt/spack/linux-ubuntu20.04-skylake/gcc-9.3.0/lcio-master-7dovpqn3kscbg672ham5wcqro7lg45gh +``` + +Note, that it is necessary to specify a single concrete version here for `lcio`. We use `@master`. +This version has to be one that is already available for the package (use `spack info` to find out which ones are available) and cannot be an arbitrary version. +It also does not necessarily have to correspond to the actual version of the source code you are currently installing. +However, it is of course encouraged to use a meaningful version specifier, since this package should also be useable as desired by dependent packages. + +### Using the local version as dependency + +Now that the local version has been installed, it would of course be nice to be able to use it in downstream packages as well. +As far as spack is concerned, a package that has been built from local sources is not really different from one that has been built from automatically downloaded sources. +The main difference is that the fact that it has been built from local sources manifests in the spec +```bash +spack find -lv lcio +``` +will yield something like +``` +==> 1 installed package +-- linux-ubuntu20.04-skylake / gcc@9.3.0 ------------------------ +7dovpqn lcio@master~examples~ipo~jar~rootdict build_type=RelWithDebInfo cxxstd=17 dev_path=/home/tmadlener/work/ILCSoft/LCIO +``` +As you can see the local path from which this version was installed has become part of the spec for the installed package (the `dev_path=...` part of the spec above). +Hence, also the hash is affected by the fact that it has been built from a local source. + +To use this specific version as a dependency the usual spack syntax can be used, e.g. +```bash +spack install marlin ^lcio/7dovpqn +``` +will install `marlin` but use the version of `lcio` that we have just built locally. + +### More advanced usage +Note: If you have installed lcio following the description above you might have to uninstall it again first to follow these instructions, because spack will not overwrite an already installed package. + +The above instructions only dealt with installing a package from a local source, but not how to easily get a development environment allowing for a quick edit, compile cycle. +This can be achieved by using the `--drop-in` and the `--before`/`--until` arguments of the `dev-build` command: + +```bash +spack dev-build --drop-in bash --until cmake lcio@master ~rootdict +``` + +This command will first install all necessary dependencies, then run the install process for `lcio` until **after** the `cmake` stage and then drop you into a new bash shell with the proper build environment setup. +It will also setup a build folder, which follows the naming scheme `spack-build-${hash}`, in this case: `spack-build-7dovpqn`. +To compile `lcio` simply go into this directory and run `make` in there +```bash +cd spack-build-7dovpqn +make -j4 +``` +You are now in an environment where you can easily edit the local source code and re-compile afterwards. + +Once all the development is done, it is still necessary to install everything to the appropriate location. +This installation has to be registered in the spack database as well. Hence, simply calling `make install` in the build directory will not do the trick. +Another call to `dev-build` is necessary. +```bash +cd .. # go back to the source directory where you started +spack dev-build lcio@master ~rootdict +``` +This will run the whole chain again, but it will not overwrite the build directory. +Hence, it will not recompile everything again, but simply install all the build artifacts to the appropriate location. +`spack find -lv lcio` can be used to check if the installation was successful. + +**NOTE: You are probably still in the build environment at this stage. To return back to you original shell simply type `exit`.** + +## Developing multiple packages or dependencies of other packages + +Developing on many packages simultaneously using the `dev-build` command can become cumbersome and doesn't really scale. + +### Using an environment to setup all dependencies +One way to develop on multiple packages simultaneously can be to setup an [environment](https://spack.readthedocs.io/en/latest/environments.html) that contains the dependencies of all packages. + +As an example the following definition of an environment has been used to develop on +[`podio`](https://github.com/AIDASoft/podio), [`EDM4HEP`](https://github.com/key4hep/EDM4HEP) and some other packages. +```yaml +spack: + specs: + - python + - root@6.20.04 +davix+gsl+math~memstat+minuit+mlp~mysql+opengl~postgres~pythia6+pythia8+python~qt4+r+root7+rootfit+rpath~shadow+sqlite+ssl~table+tbb+threads+tmva+unuran+vc+vdt+vmc+x+xml+xrootd build_type=RelWithDebInfo cxxstd=17 patches=22af3471f3fd87c0fe8917bf9c811c6d806de6c8b9867d30a1e3d383a1b929d7 + - dd4hep +geant4 + - geant4 + - heppdt + - hepmc@2.06.10 + - tricktrack + - py-pyyaml + - py-jinja2 + - cmake + - pythia8 + - evtgen + concretization: together + view: true + packages: + all: + compiler: [gcc@9.3.0] + variants: cxxstd=17 +``` + +Assuming this is the content of `edm4hep_devel.yaml` an environment can be created, activated, concretized and installed with the following commands: +```bash +spack env create edm4hep-devel edm4hep_devel.yaml +spack env activate -p edm4hep-devel +spack concretize +spack install +``` + +After an environment has been installed, it can easily be activated via +```bash +spack env activate -p edm4hep-devel +``` +which immediately drops you in an environment with all the packages stated in the environment file above available and properly set up. +Developing packages that depend on these should then be straight forward, especially for properly setup CMake based projects that can automatically find and configure their dependencies. + +The disadvantage of this approach is that the packages you want to develop on have to be on the top of the stack and if they depend on each other, you still have to properly handle these dependencies on your own. + +### Environments and a development workflow + +Recently spack gained the ability to setup environments and specify multiple packages that you would like to develop on (See [spack/spack#256](https://github.com/spack/spack/pull/15256)). +It is not yet really documented and it is not yet fully optimized, but it allows for a decent development experience if your package is not too deep down in the stack. +It is not impossible to develop on packages deep down the software stack, but this can imply frequently recompiling large parts of the software stack, since spack does not yet handle this in the best way, but instead builds all packages that you are not developing on from scratch. Hence, even if a simple relinking would have done the trick, spack will still build a lot of packages again. +Nevertheless, the feature is in a usable state and this section briefly describes how to use it. +Especially if you mainly develop on one package but sometimes want to check whether the rest of the stack, that depends on this package still compiles with the latest version, this can be a very useful workflow. + +As an example we will be using the `k4simdelphes` package that depends on `edm4hep`, which in turn depens again on `podio`. +Suppose we want to change `podio` and `edm4hep` and see if `k4simdelphes` still compiles and works. +We would then use an environment definition file similar to the usual environments. For this example it has the following content +```yaml +spack: + spec: + - k4simdelphes + concretization: together + view: false + packages: + all: + compiler: [gcc@9.3.0] + variants: cxxstd=17 + develop: + podio: + spec: podio@master +sio + path: ../../../../../podio + edm4hep: + spec: edm4hep@master + path: ../../../../../EDM4hep +``` + +The first part is the same as previously, but a new `develop` section containing information about the packages that should be developed on has been added. +For each package there is a `spec` and a `path` field. The `spec` field tells spack which spec to build, while the `path` field tells spack where the source files are located. +**The path is relative to the `$(prefix)/var/spack/environments/${environment-name}` directory or an absolute path.** + +Assuming that you are currently in the directory that contains local `spack` installation, the following steps are necessary to create the development environment +```bash +git clone https://github.com/AIDASoft/podio +git clone https://github.com/key4hep/EDM4hep +spack env create my-development-env development_env_packages.yaml +``` +where `development_env_packages.yaml` is the yaml file with the contents just described above. + +It is now possible to activate this environment via +```bash +spack env activate -p my-development-env +``` + +To install all the packages, including the local versions of `podio` and `edm4hep` it is now enough to simply do `spack install`**in the activated environment**. +This will build your local copies of `podio` and `edm4hep` and use these versions as dependencies for the `k4simdelphes` package. +Changes can also be made to either of the two packages. +To compile only one package without installing it yet, it is easiest to simply go to the directory where the sources are. +There should now be a few spack related files and a spack build folder among the other source files +``` +[...] +spack-configure-args.txt +spack-build-env.txt +spack-build-out.txt +spack-build-${hash} +``` +Here `${hash}` is the same that you get from `spack find -l package`. +After you have done all the necessary changes you can simply change into this build directory and run `make` to compile the package again. +Once all your development is done and you want to install the package `spack install` will run the whole build chain again. +This means that all the (local) development packages in your environment will only be recompiled as far as necessary, while all other packages that depend on the development packages will be re-built from scratch. + +Once you are done developing, this environment can be used like any other environment simply by running `spack env activate my-development-env` to activate it. + +#### Adding another package to develop +If you now realize that your changes to `podio` or `edm4hep` broke `k4simdelphes` and you need to also implement some changes there, you do not have to define a new environment. +Instead it is possible to add `k4simdelphes` to the `develop` section via `spack develop` (assuming you are still in the activated environment and in the same directory where also the `podio` and `edm4hep` sources live) +```bash +git clone https://github.com/key4hep/k4SimDelphes +spack develop --no-clone --path ../../../../../k4SimDelphes k4simdelphes@main +``` +Here, the `--path` is again either relative to the environment directory inside spack. It could also be an absolute path. +You now have to concretize the environment again before you can install the packages. +```bash +spack concretize -f +spack install +``` + +Now you can work on `k4simdelphes` in the same way as you can for `podio` or `edm4hep`. +You can also check that the environment now indeed uses your local version of `k4simdelphes` via +``` +spack find -lv k4simdelphes +``` +which should now yield something along the lines of +``` +==> In environment my-development-env +==> Root specs +------- k4simdelphes@main + +==> 1 installed package +-- linux-ubuntu20.04-broadwell / gcc@9.3.0 ---------------------- +m5khm2w k4simdelphes@main~ipo build_type=RelWithDebInfo dev_path=/home/tmadlener/work/spack/var/spack/environments/test-devel-env/../../../../../k4SimDelphes +``` +where the path to the local source files has now again become part of the spec as can be seen by the `dev_path=...` part of the spec. diff --git a/_sources/developing-key4hep-software/WritingAlgorithms.md.txt b/_sources/developing-key4hep-software/WritingAlgorithms.md.txt new file mode 100644 index 0000000..fb46e90 --- /dev/null +++ b/_sources/developing-key4hep-software/WritingAlgorithms.md.txt @@ -0,0 +1,310 @@ +# Writing Gaudi Algorithms + +## Gaudi + +Gaudi is an event-processing framework. Algorithms can be defined by users and +Gaudi will take care of running them for each event. In addition, Gaudi has a +set of services and tools like logging and support for running in a +multithreaded environment. + +The relationship between Gaudi with key4hep happens through +[k4FWCore](https://github.com/key4hep/k4FWCore). k4FWCore has tools and +utilities needed to be able to use (almost) seamlessly EDM4hep collections in +Gaudi algorithms. We recommend checking out the +[tests](https://github.com/key4hep/k4FWCore/tree/main/test/k4FWCoreTest) in this +repository since they contain examples of algorithms (in particular of +algorithms using `Gaudi::Functional`). + +# Gaudi::Functional +Using `Gaudi::Functional` is the recommended way of creating algorithms. The +design is simple and at the same time enforces several constraints at +compile-time, allowing for a quicker development cycle. In particular, we will +see that our algorithms won't have an internal state and we obtain the benefit +of being able to run in a multithreaded environment (almost) trivially[^1]. + +[^1]: It's possible to find algorithms written based on GaudiAlg which is going to be removed from future versions of Gaudi. GaudiAlg was substituted by Gaudi::Algorithm, although the recommended way is to use Gaudi::Functional. + +## Setup +We will need Gaudi, k4FWCore and all their dependencies. Installing these by +ourselves is not easy but there are software stacks on cvmfs, see the +{doc}`/setup-and-getting-started/README.md` to set up the key4hep stack. + +The easiest way of having a working repository is to copy the template +repository that we provide in key4hep: + +``` bash +git clone https://github.com/key4hep/k4-project-template +``` + +or ideally with ssh + +``` bash +git clone git@github.com:key4hep/k4-project-template +``` + +This template repository already has the cmake code that will make our +algorithms know where Gaudi and k4FWCore and to properly link to them. In +addition there are a few examples that combined with the tests in k4FWCore +provide an overview of what's possible to do. The `k4-project-template` +repository contains a CMake configuration (as described in more detail in the +previous tutorial) so it can be built with: + +```bash +cd k4-project-template +mkdir build install +cd build +cmake .. -DCMAKE_INSTALL_PREFIX=../install +make -j 4 install +``` + +To run the algorithms contained in this repository you can use `k4run`, like: + +```bash +k4run ../K4TestFWCore/options/createExampleEventData.py + +``` + +## Walkthrough of Functional Algorithms + +Functional algorithms in Gaudi are relatively straightforward to write. For each +algorithm we want, we have to create a class that will inherit from one of the +`Gaudi::Functional` classes. The most important function member will be +`operator()` which is what will run over our events (or over none in case we are +generating). There are several base classes in Gaudi (see a more complete list +in https://lhcb.github.io/DevelopKit/03a-gaudi/): +- Consumer, one or more inputs, no outputs +- Producer, one or more outputs, no inputs +- Transformer (and MultiTransformer), one or more inputs, one or more outputs + +The structure of our class (more precisely structs) will then be, in the general +case of the transformer: + +``` cpp +#include "GaudiAlg/Transformer.h" +// Define BaseClass_t +#include "k4FWCore/BaseClass.h" + +struct ExampleTransformer final + : Gaudi::Functional::Transformer { + + ExampleTransformer(const std::string& name, ISvcLocator* svcLoc); + colltype_out operator()(const colltype_in& input) const override; +}; +``` + +Some key points: +- The magic to make our algorithm work with EDM4hep collections happens by + including `BaseClass.h` and passing `BaseClass_t` it as one of the template + arguments to the Gaudi class we are inheriting from. +- `operator()` is const, which means that it can't modify class members. This is + intended and helps with multithreading by not having an internal state. + +Let's start with the first template argument. It's the signature of a function +that returns one or more outputs and takes as input one or more inputs. +One possible example would be to have these two lines before the class definition: + +``` cpp +using colltype_in = edm4hep::MCParticleCollection; +using colltype_out = edm4hep::MCParticleCollection; +``` + +and then we have a transformer that will take one `MCParticleCollection` as +input and return another one. If we have multiple inputs we keep adding +arguments to the function arguments and if we don't have any we can leave that +empty. For the output this is slightly more complicated because if there are +more than one output we have to return an `std::tuple`; if there aren't any outputs we can simply return `void`. + +Then we reach the constructor. We'll always initialize from the constructor of the +class we're inheriting (in this example a `Transformer`) and then we'll +initialize a set of `KeyValues`. These `KeyValues` will be how we define the +names of our inputs and outputs so they can be found by other algorithms, read +from a file or saved to a file. + +``` cpp + ExampleTransformer(const std::string& name, ISvcLocator* svcLoc) + : Transformer(name, svcLoc, + KeyValue("InputCollection", "MCParticles"), + KeyValue("OutputCollection", "NewMCParticles")) { + // possibly do something + } +``` + +Here we are defining how we will name our input collection in the steering value +(`InputCollection`) and giving it a default value. We're doing the same with the +output collection. The order is important here: first inputs and then outputs +and they are ordered. When we have more inputs we just add another line, like +the one above for the input collection. For outputs, since they are bundled +together in a `std::tuple` when there are several, we have to enclose the list +of `KeyValue` with brackets, like + +``` cpp + ExampleMultiTransformer(const std::string& name, ISvcLocator* svcLoc) + : MultiTransformer(name, svcLoc, + KeyValue("InputCollection", "MCParticles"), + { + KeyValue("OutputCollection1", "NewMCParticles"), + KeyValue("OutputCollection2", "SimTrackerHits"), + KeyValue("OutputCollection3", "UsefulCollection"), + } + ) { + // possibly do something + } +``` + +Then in the `operator()` we can do whatever we want to do with our collections +``` cpp + colltype_out operator()(const colltype_in& input) const override { + auto coll_out = edm4hep::MCParticleCollection(); + for (const auto& particle : input) { + auto new_particle = edm4hep::MutableMCParticle(); + new_particle.setPDG(particle.getPDG() + 10); + new_particle.setGeneratorStatus(particle.getGeneratorStatus() + 10); + new_particle.setSimulatorStatus(particle.getSimulatorStatus() + 10); + new_particle.setCharge(particle.getCharge() + 10); + new_particle.setTime(particle.getTime() + 10); + new_particle.setMass(particle.getMass() + 10); + coll_out->push_back(new_particle); + } + return coll_out; +``` + +When we return several collections we can bundle them in an `std::tuple` like this: + +``` cpp + return std::make_tuple(std::move(collection1), std::move(collection2)); +``` + +The complete example for reference can be found in the tests of k4FWCore: +https://github.com/key4hep/k4FWCore/blob/main/test/k4FWCoreTest/src/components/ExampleFunctionalTransformer.cpp + +## The steering file + +The steering file is the file where we define which algorithms will run, what +parameters they will use and how they will do it; what level of logging, if +using multithreading, etc. + +We start with some imports + +``` python +from Gaudi.Configuration import INFO +from Configurables import ExampleFunctionalTransformer +from Configurables import ApplicationMgr +from Configurables import k4DataSvc +from Configurables import PodioOutput +from Configurables import PodioInput +``` + +it's also possible to import everything from `Configurables` but it's better not +to so that if we are using IDE or an editor with some kind of analysis it can +tell us if we are using an undefined variable, for example. + +Then, the input: + +``` python +podioevent = k4DataSvc("EventDataSvc") +podioevent.input = "output_k4test_exampledata_producer.root" + +inp = PodioInput() +inp.collections = [ + "MCParticles", +] +``` + +We select the name of the input file and which collections we'll make available +for the rest of the algorithms. + +For the output: + +``` python +out = PodioOutput("out") +out.filename = "output_k4test_exampledata_transformer.root" +# The collections that we don't drop will also be present in the output file +out.outputCommands = ["drop MCParticles"] +``` + +we can select which collections we keep in the output file. By default the +collections in the output file will be the same as in the input file. Check the +[relevant +documentation](https://github.com/key4hep/k4FWCore/blob/main/doc/PodioInputOutput.md) +to learn more about `PodioInput` and `PodioOutput`. + +Our algorithm will look like this: + +``` python +transformer = ExampleFunctionalTransformer("ExampleFunctionalTransformer", + InputCollection="MCParticles", + OutputCollection="NewMCParticles") +``` + +If we have defined `Gaudi::Property`s for our algorithm it is also possible to +change them by doing `transformer.property = value`; however with the names of +the collections, if they are provided, they are set when creating the python +object with our algorithm. + +Finally we define what to run: + +``` python +ApplicationMgr(TopAlg=[inp, transformer, out], + EvtSel="NONE", + EvtMax=10, + ExtSvc=[k4DataSvc("EventDataSvc")], + OutputLevel=INFO, + ) +``` + +We pass a list of the algorithms in `TopAlg`. `PodioInput` will be the first one +and `PodioOutput` will be the last one when used. In `EvtMax` we set what is the +maximum number of event that we are processing. Use -1 not to limit it. That +means if we are processing a file, then read all the events in the file. We pass +extra services to `ExtSvc` and set an `OutputLevel` that could be `DEBUG`, +`WARNING` or `INFO` most of the time. + +## Initialize and finalize +There are some occasions where we may want to run some code between the +constructor and the `operator()`; that is the place for `initialize()`. There is +also a way of doing something similar after processing with `finalize()`. For that, we +can add to our classes those functions (we can also add only one of these): + +``` cpp + StatusCode initialize() override; + StatusCode finalize() override; +``` + +and then we can implement them. + +Make sure to remember to return the corresponding status code, otherwise +Gaudi will crash. For example: + +``` cpp +StatusCode MyAlgorithm::initialize() { + // do something + return StatusCode::SUCCESS; +} +``` + +## Debugging: How to use GDB + +[The GNU Project Debugger](https://www.sourceware.org/gdb/) is supported by +Gaudi and can be invoked by passing additional `--gdb` parameter to the `k4run`. +For example: +```bash +k4run ../K4TestFWCore/options/createExampleEventData.py --gdb +``` +This will start the GDB and attaches it to the Gaudi steering. After initial +loading, user can start running of the steering by typing `continue` into the +GDB console. To interrupt running of the Gaudi steering use `CTRL+C`. + +More details how to run GDB with Gaudi can be found in +[LHCb Code Analysis Tools](https://twiki.cern.ch/twiki/bin/view/LHCb/CodeAnalysisTools#Debugging_gaudirun_py_on_Linux_w) (requires a CERN account to view). + +## Avoiding const in `operator()` +There is a way of working around `operator()` being const and that is by adding +the keyword `mutable` to our data member. This will allow us to change our data +member inside `operator()` and will cause code that wasn't compiling because of +this to compile. Of course, this is not a good idea because unless the member of +our class is thread-safe, that means that our algorithm is no longer thread-safe +and running with multiple threads can cause different results. Even worse than +that, it's very possible that there are not any errors or crashes but the +results are simply wrong from having several threads changing a member at the +same time, for example. diff --git a/_sources/how-tos/README.md.txt b/_sources/how-tos/README.md.txt new file mode 100644 index 0000000..73e3213 --- /dev/null +++ b/_sources/how-tos/README.md.txt @@ -0,0 +1,29 @@ +# Key4hep How-Tos and Instructions + +This page contains a few brief How-Tos and Instructions on how to achieve +certain things within the Key4hep software stack. They are mainly aimed at +Key4hep users and are mostly designed to be reference material, rather than +[tutorials](https://key4hep.github.io/key4hep-doc/tutorials/README.html). + +```{eval-rst} +.. toctree:: + :caption: Contents + :maxdepth: 1 + + key4hep-tutorials/edm4hep_analysis/edm4hep_api_intro.md + k4fwcore/doc/PodioInputOutput.md + k4fwcore/doc/k4run-args.md + k4marlinwrapper/doc/MarlinWrapperIntroduction.md + k4edm4hep2lcioconv/doc/LCIO2EDM4hep.md +``` + + diff --git a/_sources/how-tos/k4edm4hep2lcioconv/doc/LCIO2EDM4hep.md.txt b/_sources/how-tos/k4edm4hep2lcioconv/doc/LCIO2EDM4hep.md.txt new file mode 100644 index 0000000..8efca02 --- /dev/null +++ b/_sources/how-tos/k4edm4hep2lcioconv/doc/LCIO2EDM4hep.md.txt @@ -0,0 +1,150 @@ +# Standalone conversion from LCIO to EDM4hep +The `lcio2edm4hep` executable reads LCIO (`.slcio`) files and converts its +contents into EDM4hep. Each `LCEvent` of the input file will be put into a +`podio::Frame` in the output file (under the `events` category). The most basic +usage is simply + +```bash +lcio2edm4hep +``` + +## Patching missing collections on the fly +A major difference between LCIO and EDM4hep is that in LCIO an `LCEvent` can +effectively have arbitrary contents, whereas in EDM4hep the assumption is that +each event consists of the same collections (even if some of them are empty). +Hence, it is necessary to either ensure that all events in the LCIO file have +the same contents or or to give `lcio2edm4hep` some additional information such +that it can patch in potentially missing collections on the fly. This additional +information comes in the form of a third argument to `lcio2edm4hep` and is +effectively a list of collection names and their types that comprise the +superset of all collections appearing in at least one event in the input LCIO +file. The format looks like this + +``` +name[:output-name] type-name +``` + +Each collection is a single line containing the name first (including an +optional output name [see below](#renaming-collections-on-the-fly)) and than its +type. The simplest form looks like this: + +``` +SETSpacePoints TrackerHit +RecoMCTruthLink LCRelation[ReconstructedParticle,MCParticle] +``` + +The easiest way to obtain such a file is to use the `check_missing_cols` +executable that comes with LCIO using the `--minimal` flag. The output of this +can be directly consumed by `lcio2edm4hep` + +#### Example: +1. Get the patch file +```bash +check_missing_cols --minimal \ + /pnfs/desy.de/ilc/prod/ilc/mc-2020/ild/rec/250-SetA/higgs/ILD_l5_o2_v02/v02-02-01/00015671/000/rv02-02-01.sv02-02-01.mILD_l5_o2_v02.E250-SetA.I402005.Pe3e3h.eL.pR.n000_002.d_rec_00015671_493.slcio \ + > patch.txt +``` +2. Pass it to `lcio2edm4hep` +```bash +lcio2edm4hep \ + /pnfs/desy.de/ilc/prod/ilc/mc-2020/ild/rec/250-SetA/higgs/ILD_l5_o2_v02/v02-02-01/00015671/000/rv02-02-01.sv02-02-01.mILD_l5_o2_v02.E250-SetA.I402005.Pe3e3h.eL.pR.n000_002.d_rec_00015671_493.slcio \ + Output.root \ + patch.txt +``` + +### Converting `LCRelation` collections +For collections of `LCRelation` type it is necessary to define the `FromType` and +`ToType` as well, as otherwise the converter will not be able to create the +correct edm4hep file. The `check_missing_cols` executable will try to determine +these types from the collection parameters and will warn if it cannot do it for +certain collections. In this case it is the **users responsibility to provide +the missing types** as otherwise the conversion will simply skip these +collections, or potentially even crash. + +## Converting only a subset of collections +Using the same mechanism as for patching collections it is also possible to only +convert a subset of all available collections. `lcio2edm4hep` uses the contents +of the `colltypefile` to determine the contents of the output. If that contains +only a subset of all collections, only that subset will be converted. Missing +collections will still be patched in, in this case. + +## Renaming collections on the fly +The optional `[:output-name]` part of each collection can be used to remap the +names of the collections in the input LCIO file to a different name in the +output EDM4hep file, e.g. + +``` +MCParticle:MCParticles MCParticle +``` + +will read the `MCParticle` collection from the input file but store it as +`MCParticles` in the output file. + +# Library usage of the conversion functions +The conversion functions are designed to also be usable as a library. The overall design is to make the conversion a two step process. Step one is converting the data and step two being the resolving of the relations and filling of subset collection. + +## Converting collection (data) +The main entry point is `convertCollection` which will automatically dispatch to +the correct conversion function depending on the type information that is stored +in the input `LCCollection`. It is also possible to access the individual +conversion functions for each type. All of the conversion functions take a map +of LCIO to EDM4hep objects of their specific type that will be filled during the +conversion. for convenience all necessary maps are bundled in the +`LcioEdmTypeMapping` struct. + +## Handling relations +**Once all necessary collections have been converted, it is necessary to resolve +the relations between the objects.** This is done using the `resolveRelations` +function. This will again dispatch to the correct relation resolving function +for the corresponding types, which can obviously also be invoked directly. + +## Handling of subset collections +Subset collections are handled similar to relations using the function +`fillSubset`. Internally this simply forwards to `handleSubsetColl` which +handles all the type details and can obviously also be used directly. + +## Handling of `LCRelation`s +`LCRelation` only exist in LCIO and their conversion is limited to what is +available in EDM4hep. They use the `"FromType"` and `"ToType"` collection +parameters to get the necessary type information. + +The AssociationCollections in EDM4hep are then created using `createAssociations`. + +## Converting entire events +Converting an entire event can be done calling the `convertEvent`. This can also +be used as an example to guide the implementation of custom conversions using +the available functionality. + +## Converting Event parameters +This can be done by calling `convertObjectParameters` that will put all the event parameters into the passed `podio::Frame`. + +## Subtle differences between LCIO and EDM4hep +There are a few small differences between LCIO and EDM4hep that shine through in the conversion, these are: + +- `CaloHitContributions` are part of the SimCalorimeterHits in LCIO while being their own data type in EDM4hep. They are created by [`createCaloHitContributions`](../k4EDM4hep2LcioConv/include/k4EDM4hep2LcioConv/k4Lcio2EDM4hepConv.h). +- The event information like an event number is part of the `LCEvent` in LCIO. In EDM4hep there is a separate EventHeader Collection. It can be created using [`EventHeaderCollection`](../k4EDM4hep2LcioConv/include/k4EDM4hep2LcioConv/k4Lcio2EDM4hepConv.h) which is stored under the name `"EventHeader"`. +- Particle IDs are converted during the conversion of the the reconstructed Particle collection. + +## Example for a ReconstructedParticle Collection +```cpp +#include "k4EDM4hep2LcioConv/k4Lcio2EDM4hepConv.h" + +// the struct defined in the header file is used for the maps linking Lcio particles +// to their EDM counterparts. + +auto typeMapping = LcioEdmTypeMapping{}; + +// We assume that this is a collection of ReconstructedParticles! +LCEVENT::LCCollection* lcCollection; + +// Convert the data +auto edmCollections = convertReconstructedParticle("name", + lcCollection, + typeMapping.recoParticles, + typeMapping.particleIDs); + +// Resolve relations (only converted objects will be available) +// This has to be called at the very end, after all collection data has been +// converted +resolveRelations(typeMapping); +``` diff --git a/_sources/how-tos/k4fwcore/doc/PodioInputOutput.md.txt b/_sources/how-tos/k4fwcore/doc/PodioInputOutput.md.txt new file mode 100644 index 0000000..600327f --- /dev/null +++ b/_sources/how-tos/k4fwcore/doc/PodioInputOutput.md.txt @@ -0,0 +1,132 @@ + +# Reading and writing EDM4hep files in Gaudi + +The facilities to read and write EDM4hep (or in general event data models based +on podio) are provided by [`k4FWCore`](https://github.com/key4hep/k4FWCore). +This page will describe their usage, but not go into too much details of their +internals. This page also assumes a certain familiarity with Gaudi, i.e. most of +the snippets just show a minimal configuration part, and not a complete runnable +example. + +## The `k4DataSvc` + +Whenever you want to work with EDM4hep in the Gaudi based framework of Key4hep, +you will need to use the `k4DataSvc` as *EventDataSvc*. You can instantiate and +configure this service like the following + +```python +from Gaudi.Configuration import * +from Configurables import k4DataSvc + +evtSvc = k4DataSvc("EventDataSvc") +``` + +**It is important that the name is `EventDataSvc` in this case, as otherwise +this is an assumption from Gaudi.** Once you have the `k4DataSvc` instantiated, +you still have to make the `ApplicationMgr` aware of it, by making sure that the +`evtSvc` is in the list of the *external services* (`ExtSvc`): + +```python +from Configurables import ApplicationMgr +ApplicationMgr( + # other args + ExtSvc = [evtSvc] +) +``` + +## Reading events + +To read events you will need to use the `PodioInput` algorithm in addition to +the [`k4DataSvc`](#the-k4datasvc). Currently, you will need to pass the input +file to the `k4DataSvc` via the `input` option but pass the collections that you +want to read to the `PodioInput`. We are working on making this (discussion +happens in this [issue](https://github.com/key4hep/k4FWCore/issues/105)). The +parts of your options file related to reading EDM4hep files will look something +like this + +```python +from Configurables import PodioInput, k4DataSvc + +evtSvc = k4DataSvc("EventDataSvc") +evtSvc.input = "/path/to/your/input-file.root" + +podioInput = PodioInput() +``` + +It is possible to change the input file from the command line via +```bash +k4run --EventDataSvc.input= +``` + +By default the `PodioInput` will read all collections that are available from +the input file. It is possible to limit the collections that should become +available via the `collections` option + +```python +podioInput.collections = [ + # List of collection names that should be made available +] +``` + +## Writing events + +To write events you will need to use the `PodioOutput` algorithm in addition to +the [`k4DataSvc`](#the-k4datasvc): + +```python +from Configurables import PodioOutput + +podioOutput = PodioOutput("PodioOutput", filename="my_output.root") +``` + +By default this will write the complete event contents to the output file. + +### Writing only a subset of collections + +Sometimes it is desirable to limit the collections to a subset of all available +collections from the EventStore. The `PodioOutput` allows to do this via the +`outputCommands` option that takes a list of `keep` or `drop` commands. Each +command must consist of the `keep`/`drop` command and a target. The target is a +collection name that may include the `?` or `*` wildcard patterns. This might +look like the following + +```python +podioOutput.outputCommands = ["keep *"] +``` + +which will keep everything (the default), while + +```python +podioOutput.outputCommands = ["drop *"] +``` + +will simply drop all collections and effectively write an empty file (apart from +some metadata). A common pattern is to `"drop *"` and then selectively adding +`keep` collections to keep, e.g. to only keep the highest level MC and reco +information: + +```python +podioOutput.outputCommands = [ + "drop *", + "keep MCParticlesSkimmed", + "keep PandoraPFOs", + "keep RecoMCTruthLink", +] +``` diff --git a/_sources/how-tos/k4fwcore/doc/k4run-args.md.txt b/_sources/how-tos/k4fwcore/doc/k4run-args.md.txt new file mode 100644 index 0000000..f05454e --- /dev/null +++ b/_sources/how-tos/k4fwcore/doc/k4run-args.md.txt @@ -0,0 +1,35 @@ + +# Adding custom arguments to `k4run` + +It is possible to extend `k4run` with custom arguments from a steering file using `k4FWCore.parseArgs`. + +Example: + +```python +from k4FWCore.parseArgs import parser +parser.add_argument("--trackingOnly", action="store_true", help="Run only track reconstruction", default=False) +my_opts = parser.parse_known_args()[0] + +# later +if my_opts.trackingOnly: + # only run track reconstruction +``` + +Behind the scenes parser is just a normal instance of pythons [`argparse.ArgumentParser`](https://docs.python.org/3/library/argparse.html), please refer to its documentation for usage details. The only important thing to keep in mind is to always use `parse_known_args()` instead of `parse_args()` so that the normal `k4run` arguments keep working. diff --git a/_sources/how-tos/k4marlinwrapper/doc/MarlinWrapperIntroduction.md.txt b/_sources/how-tos/k4marlinwrapper/doc/MarlinWrapperIntroduction.md.txt new file mode 100644 index 0000000..f0d7a3e --- /dev/null +++ b/_sources/how-tos/k4marlinwrapper/doc/MarlinWrapperIntroduction.md.txt @@ -0,0 +1,222 @@ + +# Wrapping Marlin processors in Gaudi + +This page describes how to run existing Marlin processors within the Gaudi +framework. `Marlin` and `Gaudi` are two event processing frameworks available in +the Key4hep software stack. The former was originally developed by the linear +collider communities in iLCSoft, while the latter originally comes from LHCb. It +is also the event processing framework for future developments within Key4hep. +To enable using the existing functionality that has been developed for the +linear collider studies and also to allow for a gradual migration the +`MarlinProcessorWrapper` has been developed. It allows to run Marlin processors +within the Gaudi framework and it's usage is described +[below](#the-marlinprocessorwrapper-gaudi-algorithm) + +One of the major differences between Marlin processors and (Key4hep) Gaudi +algorithms is the event data model (EDM) that they use. While Marlin uses LCIO, +Gaudi in Key4hep uses [EDM4hep](https://edm4hep.web.cern.ch). Since EDM4hep is +based on LCIO the differences are limited and it is possible to convert between +the two EDMs as necessary. We will also show how to do this +[below](#using-the-edm-converters). + +The following descriptions assume that you are somewhat familiar with how to +configure and run Gaudi via `k4run`, i.e. most of the snippets will just show +the bare minimum of configuration, but will usually not work without +modifications (e.g. in most cases the `ApplicationMgr` as well as putting all +the configured algorithms into the list of algorithms to run is missing +entirely). + +## The `MarlinProcessorWrapper` Gaudi algorithm + +The `MarlinProcessorWrapper` is a standard Gaudi algorithm and can be used just +like all others, i.e. in a Gaudi options file we simply have to import it via +```python +from Gaudi.Configuration import * +from Configurables import MarlinProcessorWrapper +``` + +It can then be configured just like any other algorithm by instantiating it and +passing the necessary parameters to it. Each Marlin processor that you want to +wrap needs its own instance. The main configuration parameters for the +`MarlinProcessorWrapper` are +- `ProcessorType` - a string with the **Marlin processor type**. The type is + usually the class name of the Marlin processor, and corresponds to the `type` + attribute in a Marlin XML configuration for a processor. +- `Parameters` - a dictionary of string keys and **list of string** values. Each + parameter of the Marlin processor needs its own entry in this dictionary and + all parameter values have to be strings as the parsing is done internally. + +As a very brief example; The following snippet of a Marlin XML steering file +```xml + + 1 + +``` + +could be converted to the following snippet of a Gaudi options file + +```python +StatMonitorAlg = MarlinProcessorWrapper("StatMonitorAlg") +StatMonitorAlg.ProcessorType = "StatusMonitor" +StatMonitorAlg.Parameters = {"HowOften": ["1"]} +``` + +**Note that wrapped Marlin processors still expect their inputs in LCIO +format!** You can either read in the data in that format directly, or use +[converters](#using-the-edm-converters) to convert from EDM4hep to LCIO first. + +## Reading and writing LCIO events with Gaudi + +In order to read in event data in LCIO format into the Gaudi world it is +necessary to use the `LcioEvent` Gaudi algorithm. It is configured in the same +way as normal Gaudi algorithms, i.e. in a minimal standalone form + +```python +from Gaudi.Configurables import * +from Configurables import LcioEvent + +read = LcioEvent() +read.Files = ["inputfile1.slcio", "inputfile2.slcio"] +``` + +For writing LCIO events from Gaudi, simply use a `MarlinProcessorWrapper` to +wrap a `LCIOOutputProcessor`, e.g. + +```python +from Configurables import MarlinProcessorWrapper + +Output_DST = MarlinProcessorWrapper("Output_DST") +Output_DST.ProcessorType = "LCIOOutputProcessor" +Output_DST.Parameters = { + "DropCollectionNames": [], + "DropCollectionTypes": ["MCParticle", "LCRelation", "SimCalorimeterHit"], + } +``` + +## Automatic conversion of Marlin XML steering files + +We provide the `convertMarlinSteeringToGaudi.py` converter script to +automatically convert Marlin steering files in XML format to Gaudi options +python files. Usage is as simple as + +```bash +convertMarlinSteeringToGaudi.py +``` + +### Limitations +This converter script handles almost everything, but there are a few +short-comings which it cannot yet handle: +- Marlin XML steering files can have `include` statements, e.g. ``. These cannot be resolved by the converter + script, and it will issue a warning. The easiest way to fix this is to simply + run `Marlin -n` to resolve all these statements and then run the converter + script again on the output file which will be named + `Parsed.xml`. +- Marlin has a mechanism to resolve constants that are defined in the + `constants` section and used like `${someFancyConstant}` in the following. The + converter script and the converted Gaudi options file handle these in general. + However, it might be necessary to change the values of the constants inside + the `CONSTANTS` dictionary that can be found at the beginning of the created + options file. Alternatively one can use `Marlin -n` with e.g. + `--constant.someFancyConstant=` to set the values in the Marlin + steering file first and again parse the converted output. +- Marlin supports conditional execution of processors via the `condition` tag. + These conditions can be configured via constant values from the `constants` + section in the steering file, but in principle these can also be runtime + values that are set, e.g. by a previously run processor. At the moment dynamic + conditions (where the value might change on an event by event basis) are not + supported by Gaudi. Additionally static conditions are only partially handled + by the converter script. While it converts the necessary configuration, it + will by default not put the converted algorithm into the `algList` list of + algorithms to run and you might have to comment / uncomment the algorithms you + actually want to run. +- If the value of the `LCIOInputFiles` is empty in the input XML file, the + converter script will put a value of `"None"` into the `read.Files` parameter. + You will have to change this either in the steering file or them in via + `--LcioEvent.Files`. +- Marlin is in some cases able to replace `constant`s with the values stored in + environment variables of the same name. In Gaudi these have to be retrieved + from the environment explicitly via `os.environ`. + +## Using the EDM converters + +The converters between EDM4hep and LCIO are implemented as so called +`GaudiTool`s. They can be attached to any `MarlinProcessorWrapper` algorithm +that is configured in the Gaudi options file. The tools are called +`Lcio2EDM4hepTool` and `EDM4hep2LcioTool` respectively. Each wrapped processor +can be equipped with both tools, so that it is possible to e.g. convert input +from EDM4hep to LCIO and output from LCIO to EDM4hep again: + +![](marlin_wrapper_tools.png) + +The (very) basic usage of the converter tools looks like the following +- Instantiate the necessary tools (and configure them as desired) +- Attach the tools to a wrapped marlin processor via the `Lcio2EDM4hepTool` + and/or `EDM4hep2LcioTool` options + +```python +from Configurables import EDM4hep2LcioTool, Lcio2EDM4hepTool + +edm4hep2LcioConv = EDM4hep2LcioTool("EDM4hep2Lcio") +lcio2edm4hepConv = Lcio2EDM4hepTool("Lcio2EDM4hep") + +wrappedProcAlg = MarlinProcessorWrapper("ProcessorToWrap") +wrappedProcAlg.Lcio2EDM4hepTool = lcio2edm4hepConv +wrappedProcAlg.EDM4hep2LcioTool = edm4hep2LcioConv +``` + +An arbitrary number of converter tools can be instantiated and attached to Gaudi +algorithms (taking into account that each algorithm can at most have one +converter for each direction attached). If you have multiple tools make sure to +give them meaningful names in order to avoid any confusion. + +### Configuration options + +By default each converter tool will try to convert the complete event content +that is currently available in the transient event store for the corresponding +source format. **It will skip the conversion of a collection if the same +collection already exists in the other format. This check is done by collection +name.** However, it is possible to control the conversion process with a +slightly higher granularity with two options that can be configured +- `collNameMapping` - this is a dictionary of collection names, where a *source* + collection name is mapped to a *target* collection name during the conversion. + This makes it possible to rename collections on the fly. In combination with + the `convertAll` option this also allows to select the collections that should + be converted. In that case if you want to keep the original collection name + you can simply repeat it. +- `convertAll` - set this to `False` if you do not want to convert all + collections, but rather would like to select a subset to convert. + +As an example, if you only want to convert the `MCParticles` collection, you +would configure the tool like this +```python +edm4hep2LcioConv = EDM4hep2LcioTool("EDM4hep2Lcio") +edm4hep2LcioConv.convertAll = False +edm4hep2LcioConv.collNameMapping = {"MCParticles": "MCParticles"} +``` + +On the other hand if you want to convert all collections, but rename the +`MCParticle` (LCIO) input collection to the `MCParticles` (EDM4hep) output +collection in the process, you would configure the tool like so + +```python +lcio2edm4hepConv = Lcio2EDM4hepTool("Lcio2EDM4hep") +lcio2edm4hepConv.collNameMapping = {"MCParticle": "MCParticles"} +``` diff --git a/_sources/how-tos/key4hep-tutorials/edm4hep_analysis/edm4hep_api_intro.md.txt b/_sources/how-tos/key4hep-tutorials/edm4hep_analysis/edm4hep_api_intro.md.txt new file mode 100644 index 0000000..b846fab --- /dev/null +++ b/_sources/how-tos/key4hep-tutorials/edm4hep_analysis/edm4hep_api_intro.md.txt @@ -0,0 +1,542 @@ +# EDM4hep - The common event data model + +EDM4hep is the common and shared Event Data Model (EDM) of the Key4hep project. +Here we will give a brief introduction to EDM4hep as well as some of the +technicalities behind it. We will also guide you towards documentation and try +to give you the knowledge to make sense of it. + +## Important resources + +- EDM4hep doxygen API reference page: [edm4hep.web.cern.ch](https://edm4hep.web.cern.ch) +- EDM4hep github repository: [github.com/key4hep/EDM4hep](https://github.com/key4hep/EDM4hep) +- podio documentation page (including API reference): [key4hep.web.cern.ch/podio](https://key4hep.web.cern.ch/podio) +- podio github repository: [github.com/AIDASoft/podio](https://github.com/AIDASoft/podio) + +## Doxygen API documentation + +We start with having a look at the [EDM4hep doxygen API reference +page](https://edm4hep.web.cern.ch): + +### The overview diagram +![](images/edm4hep_doxygen.png) + +You see a diagrammatic overview of EDM4hep with all the available data types, +broadly organized into different categories. The arrows depict two ways data +types can be related / associated with each other + +- ["Relations"](#relations) (black arrows) +- ["Associations"](#associations) (purple-ish arrows) + +#### Relations +These are relations defined within the data types, and which are directly +accessible from the data types. They come in two flavors, depending on the +multiplicity of the relation + +- `OneToOneRelations` +- `OneToManyRelations` + +Data types can relate to other instances of the same type (e.g. `MCParticle`s +usually form a hierarchy of mothers/daughters). Relations are directed, i.e. it +is possible to go from one object to a related object, but vice versa this does +usually not hold. For example, a `ReconstructedParticle` can point to multiple +`Tracks` or `Clusters`, but those do not point to a `ReconstructedParticle`. + +#### Associations +These are relations that are in a sense "external" to the data model definition. +They are currently mainly used to connect MC and RECO information, as a direct +link via a relation is not desirable as it would mix the two worlds. In contrast +to relations, associations are not directed, i.e. it is possible to access both +involved objects from the association. + +### The table of available types +Just below the diagram is an overview table of all the types that are defined in +EDM4hep. Here they are organized into + +- `Components` - very simple types, that are used throughout the +- `Datatypes` - The data types that are defined in EDM4hep +- `Association` - The available associations between different data types + +![](images/doxygen_type_table.png) + +Clicking on any of these links will take you to the +[`edm4hep.yaml`](https://github.com/key4hep/EDM4hep/blob/master/edm4hep.yaml) +definition file of EDM4hep, jumping directly to the definition of the respective +datatype or component. For more information on this file check out the section +about [podio](#podio-the-technical-infrastructure-on-which-things-run). In +principle it is possible to have *very educated guesses* on how the interface of +the classes will look like from this. + +### Navigating the doxygen reference page +To see all the available classes simply click on [`Classes -> Class +Index`](https://edm4hep.web.cern.ch/classes.html) or on [`Classes -> Class +List`](https://edm4hep.web.cern.ch/annotated.html). Doing the latter and +expanding the `edm4hep` namespace gives you something like this + +![](images/doxygen_class_list.png) + +Clicking on any of the links in this list will take you to the reference page +for that class, e.g. for the [`ReconstructedParticle`](https://edm4hep.web.cern.ch/classedm4hep_1_1_reconstructed_particle.html) + +![](images/doxygen_reco_particle.png) + +#### Why are there so many classes and do I need all of them? +If you look at the list you will realize there are many classes that are all +named very similar, e.g. + +- **`CaloHitContribution`** +- **`CaloHitContributionCollection`** +- `CaloHitContributionCollectionData` +- `CaloHitContributionCollectionIterator` +- `CaloHitContributionData` +- `CaloHitContributionMutableCollectionIterator` +- `CaloHitContributionObj` +- `CaloHitContributionSIOBlock` +- **`MutableCaloHitContribution`** + +From all of these classes **only the ones marked bold are truly "visible" and +intended for use**. The others are internal classes or simple helper types that +you will most likely only ever see in compiler errors, especially if you follow +the *Almost Always Auto* style of writing c++ code (see [Herb Sutter's original +blog +post](https://herbsutter.com/2013/08/12/gotw-94-solution-aaa-style-almost-always-auto/) +or [a slightly easier to digest +summary](http://cginternals.github.io/guidelines/articles/almost-always-auto/)). +To understand why these classes exist and what their purpose is, we have to make +a slight detour to +[podio](#podio-the-technical-infrastructure-on-which-things-run). + + +### Some utility functionality +EDM4hep also brings a bit of utility functionality. You can find it in the +[`edm4hep::utils` +namespace](https://edm4hep.web.cern.ch/namespaceedm4hep_1_1utils.html) (click on +`Namespaces -> Namespace List`, then expand the `edm4hep` namespace and then +click on `utils` to arrive at this link). + +# podio - The technical infrastructure on which things run +podio is an EDM toolkit that is used by and developed further in the Key4hep +context. The main purpose is to have an efficiently implemented, thread safe EDM +starting from a high level description. For more (gory) details have a look at +the [github repository](https://github.com/AIDASoft/podio). + +Here we will describe the code generation, and its implications for EDM4hep. A +[bit further down](#the-podioframe-container) we will describe how to read and +write podio (root) files and the [`podio-dump`](#podio-dump) tool to inspect +files without having to open them. + +## podio code generation +The podio code generator is a python script that reads in the EDM definition in +**yaml** format, does a few basic validation checks on the definition, and then +generates all the necessary code via the Jinja2 template engine. + + ![]() + +The generated code should (among other things) + +- be efficient, +- offer an easy to use interface, +- offer performant I/O. + +Having automated code generation has a few advantages: + +- Freeing the user from the repetitive task of implementing all the types + themselves +- Freeing the user from having to deal with all the details of how to do things + efficiently +- Making it very easy to roll out improved implementations (or bug fixes) via + simply regenerating the code + +### The three layers of podio +To achieve the goals stated above podio favors composition over inheritance and +uses **plain-old-data (POD)** types wherever possible. To achieve this podio +employs a layered design, which makes it possible to have an efficient memory +layout and performant I/O implementation, while still offering an easy to use +interface + +![]() + +- The *User Layer* is the top most layer and it **offers the full + functionality** and is the **only layer with which users interact directly**. + It consists mainly of the collections and lightweight handle classes, i.e. + - `XYZCollection` + - `XYZ` + - `MutableXYZ` +- The *Object Layer* consists of the `XYZObj` classes, that take care of all + resource management and which also enable the relations between different + objects. +- The *POD Layer* at the very bottom is where all the actual data lives in + simple `XYZData` POD structs. These are the things that are actually stored + in, e.g. root files that are written by podio. + +### Basics of generated code - value semantics +The generated c++ code offers so called *value semantics*. The exact details of +what this actually means are not very important, the main point **is that you +can treat all objects as values and you don't have to worry about inefficient +copies or managing resources:** + +```cpp +auto recos = edm4hep::ReconstructedParticleCollection(); + +// ... fill, e.g. via +auto p = recos.create(); +// or via +auto p2 = edm4hep::ReconstructedParticle(); +recos.push_back(p2); + +// Loop over a collection +for (auto reco : recos) { + auto vtx = reco.getStartVertex(); + // do something with the vertex + + // loop over related tracks + for (auto track : reco.getTracks()) { + // do something with this track + } +} +``` + +This looks very similar to the equivalent python code (if you squint a bit, and ignore the `auto`s, `;` and `{}` ;) ) + +```python +recos = edm4hep.ReconstructedParticleCollection() + +# ... fill, e.g. via +p = recos.create() +# or via +p2 = edm4hep.ReconstructedParticle() +recos.push_back(p2) + +# Loop over a collection +for reco in recos: + vtx = reco.getStartVertex() + # do something with the vertex + + # loop over related tracks + for track in reco.getTracks(): + # do something with the tracks +``` + +The python interface is functionally equivalent to the one c++ interface, since +that is implemented via PyROOT. There are some additions that make the python +interface more *pythonic*, e.g. `len(recos)` is equivalent to `recos.size()`. +Nevertheless, the doxygen reference is valid for both interfaces. + +### Guessing the interface from the yaml definition +Since all code is generated, it is usually pretty straight forward to guess how +the interface will look like just from looking at the definition in the yaml +file. For EDM4hep the general rule is to get a `Member` variable, a +`OneToOneRelation`, a `OneToManyRelation` or a `VectorMember` is to **simply +stick a `get` in front of the name in the yaml file and to capitalize the first +letter.**, e.g. + +```yaml +Members: + - edm4hep::Vector3f momentum // the momentum in [GeV] +``` +will turn into something like +```cpp +const edm4hep::Vector3f& getMomentum() const; +``` + +Similar, but in slightly more nuanced rules apply for the methods that are +generated for setting a value. For `Member` variables and `OneToOneRelation`s +the general rule is to **stick a `set` in front of the name in the yaml file and +to capitalize the first letter**, e.g. (continuing from above) + +```cpp +void setMomentum(edm4hep::Vector3f value); +``` + +For the `OneToManyRelation`s and `VectorMember`s the rule is to **stick a +`addTo` in front of the name in the yaml file and to capitalize the first +letter**, e.g. + +```yaml +OneToManyRelation: + - MCParticle daughters // the daughters of this particle +``` + +will be generated to + +```cpp +void addToDaughters(MCParticle daughter); +``` + +### Why is there a `XYZ` and a `MutableXYX`? + +The underlying technical reasons are rather complex, dive quite deepish into c++ +nuances, and definitely far beyond the scope of this tutorial. In short: We need +two different handle classes in order to control whether users are allowed to +modify things or not. As one of the main goals of podio generated EDMs is to be +thread safe the default generated class for each data type allows only for +immutable read access, i.e. it provides only the `get` methods. Only the +`Mutable` classes actually have the `set` methods, and can hence be used to +actually modify objects. The most important implication of this is the +following: **Everything that you read from file, or that you get from the Gaudi +TES (in [gaudi](../gaudi/README.md#accessing-data-within-an-algorithm), or that +you get from a [`Frame`](#the-podioframe-container)) is immutable.** I.e. there +is no way for you to change or update the values that you read. The only way to +"update" values (or collections) is to actually copy the contents and then store +the updated values back. Independent copies of objects can be obtained with the +`clone` method. + +### Writing function interfaces +The `Mutable` objects implicitly convert to an instance of a default class. +Hence, **always use the default classes when specifying function interfaces** +(obviously this only works if you only need read access in the function. **There +is no implicit conversion from the default, immutable objects to the `Mutable` +objects!** + +As an example +```cpp +void printE(edm4hep::MCParticle particle) { + std::cout << particle.getEnergy() << '\n'; +} + +void printEMutable(edm4hep::MutableMCParticle particle) { + std::cout << particle.getEnergy() << '\n'; +} + +int main() { + auto mutP = edm4hep::MutableMCParticle(); + p.setEnergy(3.14); + + printE(mutP); // Works due to implicit conversion + printEMutable(mutP); // Obviously also works + + // Now we create an immutable object + auto P = edm4hep::MCParticle(); + + printE(P); // Obviously works + printEMutable(P); // BREAKS: No conversion from default to Mutable + + return 0; +} +``` + +### Subset collections +Similar to LCIO, podio generated EDMs offer a *subset collection functionality*. +This allows to create collections of objects, that are actually part of another +collection, e.g. to simply collect all the muons that are present in a larger +collection of reconstructed particles: + +![]() + +To create a subset collection, simply do +```cpp +auto muons = edm4hep::ReconstructedParticleCollection(); +muons.setSubsetCollection(); + +// You can now add objects that are part +// of another collection to this one via push_back +muons.push_back(recos[0]); +``` + +Reading a subset collection works exactly the same as reading a normal +collection. This is handled in a transparent way, such that you usually don't +even realize that you are operating on a subset collection. + +## The `podio::Frame` container + +The `podio::Frame` is a *generalized event*. It is a container that aggregates +all relevant data (and some meta data). It also defines an implicit *interval of +validity* (but that is less relevant for this tutorial). It provides a thread +safe interface for data access +- Immutable read access only for collections that are stored inside the a + `Frame` +- All data that is inside a `Frame` is owned by it, and this is also reflected + in its interface. + +![]() + +Here we will just briefly introduce the main functionality, for more details see +the [documentation in +podio](https://github.com/AIDASoft/podio/blob/master/doc/frame.md). + +### Getting collections from a `Frame` +Assuming that `event` is a `podio::Frame` in the following code examples, +getting a collection can be done via (c++) + +```cpp +auto& mcParticles = event.get("MCParticles"); +``` + +or (python) + +```python +mcParticles = event.get("MCParticles") +``` + +This retrieves the collection that is stored under the name `MCParticles` with +type `edm4hep::MCParticleCollection`. If no such collection exists, it will +simply return an empty collection of the desired type. As you can see, the type +is automatically inferred in python. **Note that `get` returns a const&, so it +is required to actually put the `&` behind `auto` in c++**, otherwise there will +be a compilation error complaining about a copy-constructor being marked +`delete`. + +### Putting a collection into a `Frame` +When putting a collection into a `Frame` you give up ownership of this +collection. To signal this to the users, it is necessary to *move* the +collection into a `Frame`. Again assuming `event` is a `podio::Frame` in the +following examples, this looks like this + +```cpp +auto recos = edm4hep::ReconstructedParticleCollection(); +event.put(std::move(recos), "ReconstructedParticles"); +``` + +Note the requirement to explicitly use `std::move` in this case. At this point +`recos` is *moved* into the `event`, and you are left with an object [*in a +valid but unspecified state*](https://stackoverflow.com/a/12095473) that you +should under normal circumstances no longer use after this point. (Technically +we do enough that you still can use this, but don't expect the results to match +your expectations). + +## Reading EDM4hep files +EDM4hep files are read with tools provided by podio. As podio supports multiple +different backends there are several, *low level* readers that support all the +necessary functionality. You can obviously use these readers directly, but we +recommend to use the `Reader` class and the `makeReader` function that will +dispatch to the correct low level reader automatically. + +```cpp +#include + +#include + +int main() { + auto reader = podio::makeReader("some_file_containing_edm4hep.data.root"); + + // Loop over all events + for (size_t i = 0; i < reader.getEvents(); ++i) { + auto event = reader.readNextEvent()); + auto& mcParticles = event.get("MCParticles"); + + // do more stuff with this event + } + + return 0; +} +``` + +### The available low level readers + +- `ROOTReader` - The default reader for TTree based files +- `ROOTLegacyReader` - The reader for an old podio format based on TTrees +- `RNTupleReader` - A reader for RNTuple based files +- `SIOReader` - The reader for reading files using the SIO backend +- `SIOLegacyReader` - The reader for the SIO backend with an old podio format + +The `Legacy` readers are stated here mainly for completeness, in case you need +to read a rather old file that still used the `EventStore` which has been +removed from podio some time ago. See +[here](#how-do-i-figure-out-if-a-file-is-legacy) for more information on how to +figure out whether the file you are interested in is a legacy file or not. +As podio is a rather low level tool, also the interface of these readers feel +somewhat low level. This is mostly visible in the fact, that you have to provide +a `category` (name) when getting the number of entries, or when reading the next +entry. This is because in principle podio can handle multiple different +categories of Frames in one file. **For the purpose of this tutorial and also +for the majority of use cases, simply use `"events"` as category name.** Readers +in podio do not return a `podio::Frame` directly, rather they just return some +*frame data* from which a `podio::Frame` can be constructed. Putting all of +these things together, a simple event loop looks like this in c++: + +```cpp +#include "podio/ROOTReader.h" +#include "podio/Frame.h" + +#include "edm4hep/MCParticleCollection.h" + +int main() { + auto reader = podio::ROOTReader(); + reader.openFile("some_file_containing_edm4hep_data.root"); + + // Loop over all events + for (size_t i = 0; i < reader.getEntries("events"); ++i) { + auto event = podio::Frame(reader.readNextEntry("events")); + auto& mcParticles = event.get("MCParticles"); + + // do more stuff with this event + } + + return 0; +} +``` + +The equivalent python code looks like this + +```python +from podio import root_io + +reader = root_io.Reader("some_file_containing_edm4hep_data.root") +# if you want to read legacy files use root_io.LegacyReader + +for event in reader.get("events"): + mcParticles = event.get("MCParticles") + # do more stuff with this event +``` + +## ROOT file layout of podio generated EDMs +podio generated EDMs, i.e. also EDM4hep, use ROOT as their default I/O backend. +Since everything is based on PODs, the produced root files are pretty straight +forward to read and interpret (with some caveats). They are already almost flat +ntuples. + +![](images/edm4hep_branches_1.png) + + +![](images/edm4hep_browse_relations_1.png) + +### How do I figure out if a file is legacy? + +1. Use [`podio-dump`](#podio-dump) and it will tell you +```console +$podio-dump /home/workarea/data/rv02-02.sv02-02.mILD_l5_o1_v02.E250-SetA.I402003.Pe2e2h.eL.pR.n000.d_dstm_15089_0_edm4hep.root +input file: /home/workarea/data/rv02-02.sv02-02.mILD_l5_o1_v02.E250-SetA.I402003.Pe2e2h.eL.pR.n000.d_dstm_15089_0_edm4hep.root + +Frame categories in this file (this is a legacy file!): +[...] +``` + +2. Peek inside the root file and look at the contents + +![]() ![]() + + +## `podio-dump` +The `podio-dump` utility allows to inspect EDM4hep files from the command line. +The synopsis looks like this + +``` console +$podio-dump --help +usage: podio-dump [-h] [-c CATEGORY] [-e ENTRIES] [-d] [--dump-edm DUMP_EDM] [--version] inputfile + +Dump contents of a podio file to stdout + +positional arguments: + inputfile Name of the file to dump content from + +options: + -h, --help show this help message and exit + -c CATEGORY, --category CATEGORY + Which Frame category to dump + -e ENTRIES, --entries ENTRIES + Which entries to print. A single number, comma separated list of numbers or "first:last" for an inclusive range of entries. Defaults to the first entry. + -d, --detailed Dump the full contents not just the collection info + --dump-edm DUMP_EDM Dump the specified EDM definition from the file in yaml format + --version show program's version number and exit +``` + +By default it prints how many events are present in the file and also a summary +of the contents of the first event. This overview consists of the names, data +types and number of elements of the collections that are stored in this event. +Using the `--detailed` flag, `podio-dump` will print the complete contents of +all collections in ASCII format. This can be quite a bit of information. Using +the `--entries` flag it is possible to choose which events to look at. The +`--categories` flag is an advanced feature and not necessary for this tutorial. + +`podio-dump` will also tell you whether the file that is passed to it is a +*legacy file* in which case you will need the `ROOTLegacyReader` or the +`SIOLegacyReader` to read it. diff --git a/_sources/index.md.txt b/_sources/index.md.txt new file mode 100644 index 0000000..ace4cbe --- /dev/null +++ b/_sources/index.md.txt @@ -0,0 +1,30 @@ +# Key4hep + + +```{eval-rst} +.. toctree:: + :maxdepth: 3 + :includehidden: + :caption: Contents: + + setup-and-getting-started/README.md + how-tos/README.md + tutorials/README.md + developing-key4hep-software/README.md + spack-build-instructions-for-librarians/README.md + talks-and-presentations/README.md + call-for-logos/README.md + CONTRIBUTING.md + +.. toctree:: + :maxdepth: 2 + :includehidden: + :caption: External links: + + FCC software + CLIC software + ILC software + CEPC software + Muon Collider software +``` + diff --git a/_sources/setup-and-getting-started/README.md.txt b/_sources/setup-and-getting-started/README.md.txt new file mode 100644 index 0000000..34ced1a --- /dev/null +++ b/_sources/setup-and-getting-started/README.md.txt @@ -0,0 +1,29 @@ +# Getting started with Key4hep software + +## Setting up the Key4hep Software Stack + +### Using a central installation on cvmfs + +Two builds with the key4hep stack are distributed on cvmfs. The releases happen +every few months on demand (for example, if there is a new important feature or +a breaking change) and at the moment Ubuntu22.04 and AlmaLinux9 (EL9, +RockyLinux9) are supported. We also have older releases for CentOS7 but are not +making any new builds for that. + +```bash +source /cvmfs/sw.hsf.org/key4hep/setup.sh +``` + +In addition, nightly builds for AlmaLinux 9 and Ubuntu 22.04 with the latest +version of most of the packages are available: + +```bash +source /cvmfs/sw-nightlies.hsf.org/key4hep/setup.sh +``` + +The `setup.sh` script always points to the latest build and it will change +without warning. However, after sourcing the script some information will be +displayed with instructions on how to reproduce the current environment. +**Nightly builds are intended for development and testing and they will be +deleted after some time from `/cvmfs`. They will also introduce new features +unannounced, so don't use these for anything else than development!** diff --git a/_sources/spack-build-instructions-for-librarians/README.md.txt b/_sources/spack-build-instructions-for-librarians/README.md.txt new file mode 100644 index 0000000..8442280 --- /dev/null +++ b/_sources/spack-build-instructions-for-librarians/README.md.txt @@ -0,0 +1,21 @@ +# Building Key4hep: For Librarians + +Key4hep comprises a fairly large number of software and depends on even more externals, so some tooling is needed to efficiently build the whole software stack. The [spack](https://spack.io) package manager can be used to build scientific software at scale, and is part of the Key4hep software R&D program. + + +A spack install of Key4hep is regularly deployed to `/cvmfs/sw.hsf.org/`, and can be used on lxplus/centos7 just by sourcing the following setup script: + +```bash +source /cvmfs/sw.hsf.org/key4hep/setup.sh +``` + +In this page, the workflow to create this installation is documented. + +```{eval-rst} +.. toctree:: + :caption: Contents: + + spack-setup.md +``` + + diff --git a/_sources/spack-build-instructions-for-librarians/spack-advanced.md.txt b/_sources/spack-build-instructions-for-librarians/spack-advanced.md.txt new file mode 100644 index 0000000..135bf3c --- /dev/null +++ b/_sources/spack-build-instructions-for-librarians/spack-advanced.md.txt @@ -0,0 +1,168 @@ + +# Spack Usage and Further Technical Topics + +This page collects a few known workarounds for issues and areas of development in spack. +Check also the issues in [key4hep-spack](https://github.com/key4hep/key4hep-spack/issues) for up-to-date information. +Additionally, we also provide a few more advanced invocations of `spack` commands that allow a certain degree of debugging of the decisions spack has made when installing a given package and its dependencies. + +## Checking which packages will be newly installed + +When installing a package it might be interesting to estimate how long it will take to do so. +An important proxy for this is how many and which dependencies spack will install in order to build a package. +This can be done with the `spack solve` command, which invokes the concretizer and then spits out the solution that would be installed if the same arguments were passed to `spack install`, e.g. + +```bash +spack solve -I +``` +```console +==> Best of 12 considered solutions. +==> Optimization Criteria: + Priority Criterion Installed ToBuild + 1 number of input specs not concretized - 0 + 2 number of packages to build (vs. reuse) - 4 + 3 requirement weight 0 0 + 4 deprecated versions used 1 0 + 5 version weight 0 0 + 6 number of non-default variants (roots) 0 0 + 7 preferred providers for roots 0 0 + 8 default values of variants not being used (roots) 0 0 + 9 number of non-default variants (non-roots) 3 0 + 10 preferred providers (non-roots) 0 0 + 11 compiler mismatches 0 0 + 12 OS mismatches 0 0 + 13 non-preferred OS's 0 0 + 14 version badness 156 0 + 15 default values of variants not being used (non-roots) 1 0 + 16 non-preferred compilers 0 0 + 17 target mismatches 0 0 + 18 non-preferred targets 165 44 + + - whizard@3.0.3%gcc@10.3.0~fastjet~latex~lcio~lhapdf~openloops~openmp+pythia8 hepmc=3 arch=linux-ubuntu20.04-x86_64 +[+] ^hepmc3@3.2.4%gcc@10.3.0~interfaces~ipo~python~rootio build_type=RelWithDebInfo arch=linux-ubuntu20.04-x86_64 +[+] ^cmake@3.16.3%gcc@10.3.0~doc+ncurses+ownlibs~qt build_type=RelWithDebInfo patches=1c54004,bf695e3 arch=linux-ubuntu20.04-x86_64 + - ^libtirpc@1.2.6%gcc@10.3.0 arch=linux-ubuntu20.04-x86_64 + - ^krb5@1.19.3%gcc@10.3.0+shared arch=linux-ubuntu20.04-x86_64 +[+] ^bison@3.8.2%gcc@10.3.0 arch=linux-ubuntu20.04-x86_64 +[+] ^diffutils@3.8%gcc@10.3.0 arch=linux-ubuntu20.04-x86_64 +[+] ^libiconv@1.16%gcc@10.3.0 libs=shared,static arch=linux-ubuntu20.04-x86_64 +[+] ^m4@1.4.18%gcc@10.3.0+sigsegv patches=3877ab5,fc9b616 arch=linux-ubuntu20.04-x86_64 +[+] ^perl@5.30.0%gcc@10.3.0~cpanm+shared+threads arch=linux-ubuntu20.04-x86_64 +[+] ^gettext@0.21%gcc@10.3.0+bzip2+curses+git~libunistring+libxml2+tar+xz arch=linux-ubuntu20.04-x86_64 +[+] ^bzip2@1.0.8%gcc@10.3.0~debug~pic+shared arch=linux-ubuntu20.04-x86_64 +[+] ^libxml2@2.9.13%gcc@10.3.0~python arch=linux-ubuntu20.04-x86_64 +[+] ^pkgconf@1.8.0%gcc@10.3.0 arch=linux-ubuntu20.04-x86_64 +[+] ^xz@5.2.5%gcc@10.3.0~pic libs=shared,static arch=linux-ubuntu20.04-x86_64 +[+] ^zlib@1.2.12%gcc@10.3.0+optimize+pic+shared patches=0d38234 arch=linux-ubuntu20.04-x86_64 +[+] ^ncurses@6.2%gcc@10.3.0~symlinks+termlib abi=none arch=linux-ubuntu20.04-x86_64 +[+] ^tar@1.30%gcc@10.3.0 zip=pigz arch=linux-ubuntu20.04-x86_64 +[+] ^openssl@1.1.1f%gcc@10.3.0~docs~shared certs=mozilla arch=linux-ubuntu20.04-x86_64 + - ^ocaml@4.13.1%gcc@10.3.0+force-safe-string arch=linux-ubuntu20.04-x86_64 +[+] ^pythia8@8.306%gcc@10.3.0~evtgen~fastjet~hdf5+hepmc+hepmc3~lhapdf~madgraph5amc~mpich~openmpi~python~rivet~root+shared arch=linux-ubuntu20.04-x86_64 +[+] ^hepmc@2.06.11%gcc@10.3.0~ipo build_type=RelWithDebInfo length=MM momentum=GEV arch=linux-ubuntu20.04-x86_64 +[+] ^rsync@3.1.3%gcc@10.3.0 arch=linux-ubuntu20.04-x86_64 +``` + +The `-I` flag shows which packages are alrady installed. +`spack solve` also shows some information about all the things that were considered during concretization. It can also be used to dump more information on the concretization process. +Unfortunately, this information is rather hard to parse, and still a work in progress from the spack developers. + + +## Requiring certain variants globally + +spack can be configured using some [configuration +files](https://spack.readthedocs.io/en/latest/configuration.html). Specifically +using `packages.yaml` which is read from the user directory, i.e. `~/.spack` (or +`/.spack/linux`) can be used to enforce the value of certain default variants +globally. To solve the above problem it is enough to put the following into +`packages.yaml`: + +```yaml +packages: + all: + variants: cxxstd=17 + ``` + +It is still possible to override this for certain packages either by +individually configuring them in `packages.yaml` or via the command line which +take precedence over all configuration files. + +In the Key4hep software stack build recipes for releases, we use the same mechanism, as this configuration is also available from spack environments. + + +## System Dependencies + +Some spack packages have *external find* support. For these packages it is possible to let spack detect the variants and versions for system (or otherwise) installed packages. +For such cases use the `spack external find` command. It has to be noted that detecting external packages and using them does not always work perfectly. + + +## Target Architectures + +Since HEP software is usually deployed on a variety of machines via cvmfs, installations need to pick a target architecture. `broadwell` is for now the default choice, and can be set with: + +``` +packages: + all: + target: [broadwell] +``` + +in `$HOME/.spack/linux/packages.yaml` + + + + +## Bundle Packages and Environments + +Right now, key4hep is installed via a `BundlePackage`, that depends on all other relevant packages. +An alternative would be to use [spack environments](https://spack-tutorial.readthedocs.io/en/latest/tutorial_environments.html). This alternative is still under investigation. + + +## Setting Up Runtime Environments + +The simplest way to set the environment to use spack installed packages is to use the `spack load` command. +In order for users not to have to set up spack when it is not needed, the `key4hep-stack` bundle package includes a script that will automatically generate a bash setup script and install it into its prefix. + +Spack can also create "filesystem views" of several packages, resulting in a directory structure similar what you would find in `/usr/local`. +This simplifies library and include paths, but the setup generation for views still has to be developed. + +## Compiler Dependencies and Data Packages + +Some HEP packages (like `geant4-data`) consist only of data files, and can thus be used on any platform. +Spack cannot yet handle this gracefully, but an ongoing development tries to treat compilers as dependencies, which would help with re-using data packages. + + +## Duplicating Recipes in Downstream Repositories + +Although it is possible to "patch" spack build recipes by overriding them in another repository (key4hep-spack, for example), this is discouraged. +The central repo is one of the strenghts of spack, with many contributors ensuring that packages build smoothly. +Also, packages are installed in different namespaces, so it is not possible to deprecate changed recipes and use the upstream ones without re-installing the packages. + + +## CVMFS Installation Workflow + +The distribution on cvmfs is an exact copy of the spack installation on the build machine, just copied with this rsync command on the publisher: + +``` +rsync -axv --inplace --delete --verbose -e "ssh -T -o Compression=no -o StrictHostKeyChecking=no -o GSSAPIAuthentication=yes -o GSSAPITrustDNS=yes" user@build-machine:/cvmfs/sw.hsf.org/spackages/ /cvmfs/sw.hsf.org/spackages/ +``` + +The `--delete` option can be omitted in order to preserve already installed packages, regardless of the state of the build machine. + + + +## Compiler Wrappers + +Spack uses compiler wrappers instead of exposing the actual compilers during the build. +For packages like whizard, which register the compiler path to use during runtime, this will not work, as the wrappers are not available at runtime. +For these packages, the current workaround is to force spack to use the actual compilers during build (see the build recipe of `whizard`). + + +## Spack-Installed LCG releases + +A spack installation that contains all packages in the LCG releases is work in progress, see https://gitlab.cern.ch/sft/sft-spack-repo. + +## Using Spack-installed GCC + +When installing gcc with spack, it is necessary to add a `cc` symlink to `$PATH`, in order to avoid errors with cling, see https://github.com/spack/spack/issues/17488. + + + diff --git a/_sources/spack-build-instructions-for-librarians/spack-buildcache.md.txt b/_sources/spack-build-instructions-for-librarians/spack-buildcache.md.txt new file mode 100644 index 0000000..7868606 --- /dev/null +++ b/_sources/spack-build-instructions-for-librarians/spack-buildcache.md.txt @@ -0,0 +1,49 @@ + +# Spack Buildcaches + +{% callout "Spack documentation" %} + +Buildcaches were investigated, but are no longer supported for Key4hep software, due to the difficulty of relocating some packages. + +For more information refer to the [spack documentation](https://spack.readthedocs.io/en/latest/binary_caches.html). + +{% endcallout %} + +It is possible to relocate and re-use binaries with the so-called buildcache. +Some central buildcaches are on the key4hep `eos` space under: + +``` +/eos/project/k/key4hep/www/key4hep/spack_build/mirror/spackages +``` +`spackages` is intended as the central buildcache for key4hep packages built from scratch, +but there exist other buildcaches for packages built against the LCG releases, and rolling builds that are using the branchname `master` or other moving targets. +All packages versioned `package@master` are treated by spack as the same version, even if master points to different commits, thus they must be installed to separate directories, ideally indicating the date. +A buildcache called `contrib` is intended for build tools such as compilers. +Spack automatically creates subdirectory for different platforms and compiler versions. + +For write permissions to this space, subscribe to the egroup `cernbox-project-key4hep-writers`. + +The following command can be used to put packages into the buildcache: + +```bash +# key4hep-stack was already installed with 'spack install key4hep-stack' +spack mirror add key4hep /eos/project/k/key4hep/www/key4hep/spack_build/mirror/spackages +spack buildcache create -m key4hep -u -a -f key4hep-stack +``` + +Since the packages need to be relocated as well as copied, this might take up to an hour. + + +In order to install packages from the buildcache, use: + +```bash +spack buildcache install -u -a key4hep-stack +``` + +Spack will then search all added mirrors for `key4hep-stack`. +For read-only access on machines without `eos`, these files are served also over http: + + +```bash +spack mirror add key4hep-web http://key4hep.web.cern.ch/key4hep/spack_build/mirror/spackages/ +``` diff --git a/_sources/spack-build-instructions-for-librarians/spack-nightlies.md.txt b/_sources/spack-build-instructions-for-librarians/spack-nightlies.md.txt new file mode 100644 index 0000000..46b1d0a --- /dev/null +++ b/_sources/spack-build-instructions-for-librarians/spack-nightlies.md.txt @@ -0,0 +1,21 @@ +# Nightly Builds with Spack + + +## Usage of the nightly builds on CVMFS + +For Centos7, the latest nightly build can be set up by running: + +``` +source /cvmfs/sw-nightlies.hsf.org/key4hep/setup.sh +``` + +Spack can also be configured to use `/cvmfs/sw-nightlies.hsf.org/spackages` as an upstream installation. + +## Technical Information + +Nightly builds can be a very useful tool, both to test code correctness and to quickly and automatically deploy the latest developments. +In contrast to the release builds, which use the latest stable version of the individual packages, nightly builds typically use the HEAD of the main development branch. + +It is not very efficient to completely rebuild the stack every day, as some packages change fairly infrequently. +The key4hep-spack repository includes some scripts in order to use commit hashes as versions. + diff --git a/_sources/spack-build-instructions-for-librarians/spack-setup.md.txt b/_sources/spack-build-instructions-for-librarians/spack-setup.md.txt new file mode 100644 index 0000000..f27e5e0 --- /dev/null +++ b/_sources/spack-build-instructions-for-librarians/spack-setup.md.txt @@ -0,0 +1,110 @@ + +## Setting up Spack + + +### Downloading a spack instance + +Spack is easy to set up: simply clone the key4hep fork, and use one of the provided spack "environments", that is spack configuration that is created automatically from the current key4hep/key4hep-spack repository. + +```bash +git clone https://github.com/spack/spack +git clone https://github.com/key4hep/key4hep-spack +source spack/share/spack/setup-env.sh +source key4hep-spack/environments/key4hep-release-user/setup_clingo_centos7.sh # NOTE: only needed on centos7 +spack env activate key4hep-spack/environments/key4hep-release-user # or other environment, see below +``` + +These instructions assume that a Centos7 machine with a running CVMFS client is used (for other OSs see below). Since Spack cannot bootstrap with the system compiler on Centos7, a setup script for Clingo ( a spack dependency ) is provided. + +### Using Spack Environments + +The [spack environments](https://spack.readthedocs.io/en/latest/environments.html) available in `key4hep-spack/environments` bundle the spack configuration, setting up a suitable compiler from cvmfs, the key4hep package recipes, whether to create a view, etc. It is recommended to always use spack in an environment. New environments can be easily created by copying and modifying existing ones, but some use relative links to common configuration files in `key4hep-spack/environments/key4hep-common`, so they should be kept in the `key4hep/environments` directory. + +The basic environment is `key4hep-release`, which is used for the central installations and therefore uses `/cvmfs` as install area. `key4hep-debug` is a variation for debug builds. The default compiler is gcc, but an environment that uses clang is provided under `key4hep-release-clang`. + For local builds that use cvmfs read-only, `key4hep-release-user` can be used. + +### Using the key4hep-release-user environment + +The key4hep user environment has the `key4hep-stack` bundle package in its spec list. By concretizing it, spack selects the latest compatible versions, re-using installations from cvmfs + +```bash +spack concretize -f +spack find # lists the available concretized packages +``` + +The environment can be installed as is, although this will just install the bundle packages. However, this will create a setup script that can be used to load the software. + +``` +spack install +``` + +Custom builds can now be realized, by adding specs to the environment and concretizing together. For example, to build the stack with a local version of EDM4hep: + +``` +spack add edm4hep@master +git clone https://github.com/key4hep/edm4hep +# make some local changes to edm4hep +spack develop -p $PWD/edm4hep edm4hep@master +spack concretize -f +spack install + +``` + + +### Configuring Spack + +Alternatively, and for other platforms, spack can be configured in a few steps. These steps are essentially what is used to create the pre-configured spack instance in this script: https://github.com/key4hep/key4hep-spack/blob/master/scripts/ci_setup_spack.sh + +While this still puts the configuration files in the global scope of spack, it is recommended to use them in an environment, as provided by key4hep-spack. + +#### Installing Spack +Spack itself is very easy to install - simply clone the repository with git. + +```bash +git clone https://github.com/spack/spack.git +source spack/share/spack/setup-env.sh +``` + +#### Installing the key4hep package recipes + + The spack repository for key4hep packages is installed the same way: + +``` +git clone https://github.com/key4hep/key4hep-spack.git +spack repo add key4hep-spack +``` + +### Configuring `packages.yaml` + +In order to choose the right package versions and build options, spack sometimes needs a few [hints and nudges](https://spack.readthedocs.io/en/latest/build_settings.html). With the new concretizer (default as of spack version 0.17) this should be mostly obsolete. +key4hep-spack ships a spack config file that should give a good build customization out of the box, but can also be customized further. It just needs to be copied to the configuration where spack searches for configurations: + +``` +cp key4hep-spack/environments/key4hep-common/packages.yaml spack/etc/spack/ +``` + + + +#### Configuring `upstreams.yaml` + +The cvmfs installation can be used as an "upstream installation", by adding the following configuration: + +```bash +cat <> spack/etc/spack/upstreams.yaml +upstreams: + spack-instance-1: + install_tree: /cvmfs/sw.hsf.org/spackages6/ +EOT +``` + + +#### Setting up additional compilers + +Often it is practical to use a compiler already installed upstream. Spack provides the `spack compiler find` command for this, but the compiler needs to be loaded into the PATH: + +```bash +# loading the compiler from upstream +source /cvmfs/sft.cern.ch/lcg/contrib/gcc/11.2.0/x86_64-centos7/setup.sh +spack compiler find --scope site +``` + diff --git a/_sources/talks-and-presentations/README.md.txt b/_sources/talks-and-presentations/README.md.txt new file mode 100644 index 0000000..c2ec9a6 --- /dev/null +++ b/_sources/talks-and-presentations/README.md.txt @@ -0,0 +1,43 @@ +# Talks and Presentations + +A Zotero group with the items listed below can be found [here](https://www.zotero.org/groups/2447672/key4hep-talksandpublications). + +* *Carceller, Juan Miguel*, **Spack in Key4hep** presented at the HSF Software + Developer Tools & Packaging Working Group July 11, 20 + + +* *Carceller, Juan Miguel*, **key4hep Update** presented at the CERN EP R&D: Software meeting, June + 21, 2023, + + +* *Volkl, Valentin*, **Status of the key4hep Software Development** presented at + IAS Program on High Energy Physics (HEP 2021), January 20, 2021, + + +* *Madlener, Thomas*. **Key4HEP - Turnkey Software for Future Colliders** + presented at the XXVII Cracow EPIPHANY Conference on Future of particle + physics, January 10, 2021. + + +* *Helsens, Clement*, **FCC software for physics and detector studies** + presented at the XXVII Cracow EPIPHANY Conference on Future of particle + physics, January 10, 2021. + + +* *Ganis, Gerardo*. **“The Turnkey Software Stack: Where Are We and Where We + Want to Go.”** presented at the IAS HEP 2020, January 17, 2020. + . + +* *Sailer, André*. **“Key4HEP: Turnkey Software for Future Collider + Experiments.”** presented at the Joint Workshop on Future Charm–Tau Factory, + September 24, 2019. + . + +* *Sailer, André*. **“Towards a Turnkey Software Stack for HEP Experiments.”** + presented at the International Conference on Computing in High Energy & + Nuclear Physics 2019, September 5, 2019. + . + +* *Mato, Pere*. **“Key4HEP: The Common Turnkey Software Stack.”** presented at + the CLICdp Collaboration Meeting, August 28, 2019. + . diff --git a/_sources/tutorials/README.md.txt b/_sources/tutorials/README.md.txt new file mode 100644 index 0000000..d6fd51e --- /dev/null +++ b/_sources/tutorials/README.md.txt @@ -0,0 +1,25 @@ +# Key4hep Tutorials + +This page contains several tutorials for working in a Key4hep software stack. We +try to design and set them up in a way that they can be done at any time but we +present them at hands-on tutorial sessions as well. This is an incomplete list +of all available tutorials, which you can find in the +[key4hep-tutorials](https://github.com/key4hep/key4hep-tutorials) repository. + +**If you are following these tutorials and run into an issue please let us know +by [opening an issue](https://github.com/key4hep/key4hep-doc/issues/new/choose) +on the [`key4hep-doc`](https://github.com/key4hep/key4hep-doc) repository.** If +you have the feeling that something is missing, we are also very happy to accept +new tutorial suggestions. If you have a tutorial that you would like to add +here. + +```{eval-rst} +.. toctree:: + :caption: Exercises + + k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/Readme.md + key4hep-tutorials/gaudi_ild_reco/README.md + k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/howtoMultithread.md + k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/CEDViaWrapper.md + k4simdelphes/doc/starterkit/k4SimDelphes/Readme.md +``` diff --git a/_sources/tutorials/k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/CEDViaWrapper.md.txt b/_sources/tutorials/k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/CEDViaWrapper.md.txt new file mode 100644 index 0000000..7640344 --- /dev/null +++ b/_sources/tutorials/k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/CEDViaWrapper.md.txt @@ -0,0 +1,88 @@ + +# Running an Event Display with EDM4hep or LCIO input + +It is possible to run the [C Event Display (CED)](https://github.com/iLCSoft/CED) via a wrapped [CEDViewer](https://github.com/iLCSoft/CEDViewer) Marlin Processor. This makes it possible to run the Event Display with EDM4hep input files using an on the fly conversion to LCIO for CED. This introduction shows the basic concepts and also provides a options file that should work for most use cases. This example will be using the CLIC detector but should also work for other DD4hep detector models. The example is fully self contained, if you already have everything set up you can jump directly to [running the event display](#running-the-event-display). + +## Setting up an environment + +The following steps have been tested with the Key4hep nightly builds release which can be setup using +```bash +source /cvmfs/sw-nightlies.hsf.org/key4hep/setup.sh +``` + +To get the CLIC detector description we clone the `CLICPerformance` repository +```bash +git clone https://github.com/iLCSoft/CLICPerformance +``` + +All the following steps assume that the environment is setup like above and that the detector description is in the `CLICPerformance` directory. All commands start from the directory from which `git clone` has been executed. + +## Creating an input file + +To create an input file for the event display we run a simple detector simulation using `ddsim` and a particle gun that shoots photons. The input file that we create here for illustration purposes has only 10 events, which also means that the creation should only take a few minutes. The steps to create this file are the following + +```bash +ddsim --steeringFile CLICPerformance/clicConfig/clic_steer.py \ + --compactFile $K4GEO/CLIC/compact/CLIC_o3_v14/CLIC_o3_v14.xml \ + --enableGun \ + --gun.distribution uniform \ + --gun.particle gamma \ + --gun.energy 10*GeV \ + --outputFile gamma_10GeV_edm4hep.root \ + --numberOfEvents 10 +``` + +You should now have a `gamma_10GeV_edm4hep.root` file containing 10 events. + +## Running the event display + +In order to run the event display via the `DDCEDViewer` we use the Marlin wrapper. Here we simply present the most important steps, but do not go over all details of the `DDCEDViewer` configuration, for that it is probably best to directly look at the [CEDViewer repository](https://github.com/iLCSoft/CEDViewer) directly. The complete Gaudi configuration can be found in [`k4MarlinWrapper/examples/event_display.py`](https://github.com/key4hep/k4MarlinWrapper/blob/master/k4MarlinWrapper/examples/event_display.py) which is also installed at `$K4MARLINWRAPPER/examples/event_display.py` + +In order to run the event display we first have to start the `glced` server program to which the wrapped `CEDViewer` processor will then connect. Starting the server and running the wrapped processor can be done via +```bash +glced & + +k4run $K4MARLINWRAPPER/examples/event_display.py --inputFiles=gamma_10GeV_edm4hep.root +``` + +If you want to run the event display for a different geometry you can do so with the `--compactFile` argument. However, depending on your detector model you might also need to change some of the `DDCEDViewer` parameters. The default compact file is `"CLICPerformance/Visualisation/CLIC_o3_v06_CED/CLIC_o3_v06_CED.xml"`. + + +## Details + +The main work is done by the `DDCEDViewer`, which we use via the `MarlinProcessorWrapper`. It is the following part of example `event_display.py`. + +```python +from Configurables import MarlinProcessorWrapper + +MyCEDViewer = MarlinProcessorWrapper("MyCEDViewer") +MyCEDViewer.ProcessorType = "DDCEDViewer" +MyCEDViewer.Parameters = { + # ... lots of CEDViewer configuration ... + } +``` +Some of the more commonly used parameters have self explanatory names. + +## Troubleshooting / Using other detectors + +When running this for a detector different than CLD, CLIC or ILD (or a derivative of one of them) you might not see anything in the event display. + +If you are not seeing the detector make sure that it has the proper visualisation attributes, e.g. by comparing it to the compact file used above. +If you are not seeing any hits, tracks etc. from your event, make sure to add their collection names to the `DrawInLayer` list in the `DDCEDViewer` parameters. diff --git a/_sources/tutorials/k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/Readme.md.txt b/_sources/tutorials/k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/Readme.md.txt new file mode 100644 index 0000000..e30111c --- /dev/null +++ b/_sources/tutorials/k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/Readme.md.txt @@ -0,0 +1,208 @@ + +# Using the Key4hep-Stack for CLIC Simulation and Reconstruction + + +This assumes that you have access to an installation of the Key4hep-stack, either via ``CVMFS`` or ``spack install``. +To setup the installation on cvmfs, do: + +```bash +source /cvmfs/sw.hsf.org/key4hep/setup.sh +``` + +These commands will explain how one can run the CLIC detector simulation and reconstruction using the Key4hep-Stack. +First we will obtain all the necessary steering and input files for CLIC, simulate a few events and run the +reconstruction both with ``Marlin`` and ``k4run``. These steps can be adapted to simulate or run other ``Marlin`` +processors as well. + +The ``CLICPerformance`` repository contains the steering and input files. + +```bash +git clone https://github.com/iLCSoft/CLICPerformance +``` + +## Simulation + +Simulating a few events with `ddsim` can produce output in EDM4hep or LCIO format. + +- To produce events in **EDM4hep** format one can run indicating `--outputFile _edm4hep.root` to produce the +output in such format: + + +```bash +cd CLICPerformance/clicConfig + +ddsim --compactFile $K4GEO/CLIC/compact/CLIC_o3_v14/CLIC_o3_v14.xml \ + --outputFile ttbar_edm4hep.root \ + --steeringFile clic_steer.py \ + --inputFiles ../Tests/yyxyev_000.stdhep \ + --numberOfEvents 3 +``` + +- To produce events in **LCIO** format one can run indicating `--outputFile .slcio` to produce the output file +in such format: + +```bash +cd CLICPerformance/clicConfig + +ddsim --compactFile $K4GEO/CLIC/compact/CLIC_o3_v14/CLIC_o3_v14.xml \ + --outputFile ttbar.slcio \ + --steeringFile clic_steer.py \ + --inputFiles ../Tests/yyxyev_000.stdhep \ + --numberOfEvents 3 +``` + + +## Reconstruction + +### Reconstruction with Marlin + +To run the reconstruction with ``Marlin``: + +```bash +cd CLICPerformance/clicConfig + +Marlin clicReconstruction.xml \ + --InitDD4hep.DD4hepXMLFile=$K4GEO/CLIC/compact/CLIC_o3_v14/CLIC_o3_v14.xml \ + --global.LCIOInputFiles=ttbar.slcio \ + --global.MaxRecordNumber=3 +``` + +### Reconstruction with Gaudi through k4MarlinWrapper + +We can convert the ``xml`` steering file to a Gaudi steering file (python): + +```bash +cd CLICPerformance/clicConfig + +convertMarlinSteeringToGaudi.py clicReconstruction.xml clicReconstruction.py +``` + +Reconstruction can be performed with LCIO or EDM4hep input, depending on the output format of the events produced +during [Simulation](#simulation). + +#### Reconstruction with LCIO input + +- When using **LCIO** format for the input events to be used in reconstruction: + + Modify the ``clicReconstruction.py`` file to point to the ``ttbar.slcio`` input file, and change the + ``DD4hepXMLFile`` parameter for the ``InitDD4hep`` algorithm. In addition the two processors with the comment ``# + Config.OverlayFalse`` and ``# Config.TrackingConformal`` should be enabled by uncommenting their line in the ``algList`` + at the end of the file. + +```bash +cd CLICPerformance/clicConfig + +sed -i '1s/^/import os\n/' clicReconstruction.py +sed -i 's;read.Files = \[".*"\];read.Files = \["ttbar.slcio"\];' clicReconstruction.py +sed -i 's;EvtMax = 10,;EvtMax = 3,;' clicReconstruction.py +sed -i 's;"MaxRecordNumber": ["10"],;"MaxRecordNumber": ["3"],;' clicReconstruction.py +sed -i 's;# algList.append(OverlayFalse);algList.append(OverlayFalse);' clicReconstruction.py +sed -i 's;# algList.append(MyConformalTracking);algList.append(MyConformalTracking);' clicReconstruction.py +sed -i 's;# algList.append(ClonesAndSplitTracksFinder);algList.append(ClonesAndSplitTracksFinder);' clicReconstruction.py +sed -i 's;# algList.append(RenameCollection);algList.append(RenameCollection);' clicReconstruction.py +sed -i 's;"DD4hepXMLFile": \[".*"\],; "DD4hepXMLFile": \[os.environ["LCGEO"]+"/CLIC/compact/CLIC_o3_v14/CLIC_o3_v14.xml"\],;' clicReconstruction.py + +``` + +Then the reconstruction using the k4MarlinWrapper can be run with + +```bash +cd CLICPerformance/clicConfig + +k4run clicReconstruction.py +``` + + +#### Reconstruction with EDM4hep input + +- When using **EDM4hep** format for the input events to be used in reconstruction, refer to the [**EDM converters**](https://github.com/key4hep/k4MarlinWrapper/blob/master/doc/MarlinWrapperIntroduction.md) +included with k4MarlinWrapper. Note that: + + *MarlinProcessorWrappers* need input in LCIO format: EDM4hep collections need to be converted to LCIO + + The output collections of *MarlinProcessorWrappers* may be used later by other algorithms: + * Output collections of *MarlinProcessorWrappers* will be in LCIO format unless these are explicitly converted + * Some *MarlinProcessorWrappers* may modify collections instead of producing new ones: the original EDM4hep collection wont be updated in this case and would need conversion from LCIO to EDM4hep. + +- To run *clicReconstruction* with EDM4hep format, use the steering file found in the `examples` folder of k4MarlinWrapper: +`k4MarlinWrapper/examples/clicRec_e4h_input.py` (this also gets installed to `$K4MARLINWRAPPER/examples` in Key4hep releases) + + Change the line where `evtsvc.input` is defined to point to the location of your input file. + + At the bottom of the file, in the `ApplicationMgr` parameters, change `EvtMax = 3,` to the number of events to run. + +This can be run in the following way. +```bash +cd CLICPerformance/clicConfig + +cp $K4MARLINWRAPPER/examples/clicRec_e4h_input.py . + +k4run clicRec_e4h_input.py --EventDataSvc.input ttbar_edm4hep.root +``` + +### DD4hep Geometry Information + +The ``MarlinDD4hep::InitializeDD4hep`` processor can be replaced by the ``k4SimGeant4::GeoSvc`` and the +``TrackingCellIDEncodingSvc`` the latter of which is part of the k4MarlinWrapper repository. +This requires removing the wrapped `InitDD4hep` processor from the `algList` and the two new processed be appended to the `ExtSvc` argument in the `ApplicationMgr`. + +We will create another list, `svcList` for this. +In the space following + +```python +import os +from Configurables import k4DataSvc, PodioInput +evtsvc = k4DataSvc('EventDataSvc') +evtsvc.input = os.path.join('$TEST_DIR/inputFiles/', os.environ.get("INPUTFILE", "ttbar_edm4hep.root")) +``` + +we can start the `svcList` list and add the `GeoSvc` and `TrackingCellIDEncodingSvc` with; + +```python +svcList = [] +svcList.append(evtsvc) + + +import os +from Gaudi.Configuration import INFO +from Configurables import GeoSvc, TrackingCellIDEncodingSvc + +geoservice = GeoSvc("GeoSvc") +geoservice.detectors = [os.environ["K4GEO"]+"/CLIC/compact/CLIC_o3_v15/CLIC_o3_v15.xml"] +geoservice.OutputLevel = INFO +geoservice.EnableGeant4Geo = False +svcList.append(geoservice) + + +cellIDSvc = TrackingCellIDEncodingSvc("CellIDSvc") +cellIDSvc.EncodingStringParameterName = "GlobalTrackerReadoutID" +cellIDSvc.GeoSvcName = geoservice.name() +cellIDSvc.OutputLevel = INFO +svcList.append(cellIDSvc) +``` + + +Then all that is left is to pass that to the `ExtSvc` argument. +At the bottom of the file: + +```diff +ApplicationMgr( TopAlg = algList, + EvtSel = 'NONE', + EvtMax = 3, +- ExtSvc = [evtsvc], ++ ExtSvc = svcList, + OutputLevel=WARNING + ) +``` diff --git a/_sources/tutorials/k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/howtoMultithread.md.txt b/_sources/tutorials/k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/howtoMultithread.md.txt new file mode 100644 index 0000000..fa12350 --- /dev/null +++ b/_sources/tutorials/k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/howtoMultithread.md.txt @@ -0,0 +1,142 @@ + +# How to run multithreading with k4MarlinWrapper (Gaudi) + +**Supported** +- Reading LCIO events with `LcioEvent()` +- Writing LCIO events with `LcioEventOutput()` +- Running `MarlinProcessorWrapper`s with **no** converters +- Using `whiteboard` as `ExtSvc` (no k4DataSvc or EventDataSvc) + +**Not supported** +- Using EDM converters `EDM4hep2LcioTool` and `Lcio2EDM4hepTool()` +- Reading EDM4hep events with `PodioInput()` +- Writing EDM4hep events with `PodioOutput()` +- Writing EDM4hep events with `MarlinProcessorWrapper` of type `LCIOOutputProcessor` +- Running non-thread algorithms/processors in parallel +- Running wrapped Marlin processors that make use of the `isFirstEvent` method in their `processEvent` method to do some setup only in the first event. There is no way to make this thread safe. If you want your processor to be usable on in a multi threaded environment, you have to move this setup to `init`. + +## Running Gaudi with multithreading support + +Gaudi uses [Intel TBB](https://oneapi-src.github.io/oneTBB/) under the hood for multithreading. + +Gaudi exposes two main levels of parallelism: +- Inter-event parallelism: running multiple events in parallel +- Intra-event parallelism: running multiple algorithms in parallel, within an event + +The two levels of parallelism can be combined: events can run in parallel, and algorithms within the events can run in parallel. + +### How to run with inter-event parallelism + +The following components are used to achieve parallelism: + +```python +from Configurables import (HiveWhiteBoard, HiveSlimEventLoopMgr, AvalancheSchedulerSvc) +``` + +These 3 components need to be configured to adapt the level of parallelism to the sequence, algorithms and hardware to be used. + +- Event Data Service: `HiveWhiteBoard` + + *EventSlots*: Number of events that may run in parallel, each with its own EventStore + + This is the Event Data Service, which needs the number of EventSlots +- Event Loop Manager: `HiveSlimEventLoopMgr` + + Event Loop Manager with parallelism support +- Thread Scheduling config: `AvalancheSchedulerSvc` + + Scheduler to indicate the number of threads to use + + In needs the total number of threads to use: this determines how many events and algorithms can be in flight (run in parallel) + + Default value is `-1` which indicate TBB to take over the machine with what it decides to be the optimal configuration + + +All these components can be set as follows in the options file: + +```python +evtslots = 4 +threads = 4 + +whiteboard = HiveWhiteBoard("EventDataSvc", EventSlots=evtslots) +slimeventloopmgr = HiveSlimEventLoopMgr(SchedulerName="AvalancheSchedulerSvc", OutputLevel=DEBUG) +scheduler = AvalancheSchedulerSvc(ThreadPoolSize=threads, OutputLevel=WARNING) + +from Configurables import ApplicationMgr +ApplicationMgr( TopAlg = [seq], + EvtSel = 'NONE', + EvtMax = 10, + ExtSvc = [whiteboard], + EventLoop=slimeventloopmgr, + MessageSvcType="InertMessageSvc" + ) +``` + +To only run events in parallel, with no parallelism between the algorithms within each event, the cardinality of the algorithms must be set: + +- Given a list of algorithms, set the cardinality of all to be 1 +- Create a `GaudiSequencer` with all the algorithms as `Members` +- Set the `GaudiSequencer` sequential property to true +- Pass the created `GaudiSequencer` to the Application Manager in the `TopAlg`: `TopAlg = [seq]` + +```python +from Configurables import MarlinProcessorWrapper +from Configurables import (GaudiSequencer) + +cardinality = 1 + +alg1 = MarlinProcessorWrapper("alg1") +alg2 = MarlinProcessorWrapper("alg2") +alg3 = MarlinProcessorWrapper("alg3") +alg4 = MarlinProcessorWrapper("alg4") + +algList = [] + +algList.append(alg1) +algList.append(alg2) +algList.append(alg3) +algList.append(alg4) + +for algo in algList: + algo.Cardinality = cardinality + algo.OutputLevel = DEBUG + +seq = GaudiSequencer( + "createViewSeq", + Members=algList, + Sequential=True, + OutputLevel=VERBOSE) + +from Configurables import ApplicationMgr +ApplicationMgr( TopAlg = [seq], + EvtSel = 'NONE', + EvtMax = 10, + ExtSvc = [whiteboard], + EventLoop=slimeventloopmgr, + MessageSvcType="InertMessageSvc" + ) +``` + +## Running example + +A multi-threaded CLIC Reconstruction can be run in multi-threaded mode, for LCIO input and output. +After successful compilation, from the build location: + +```sh +# Check available tests +ctest -N + +# Run multi-threaded clicReconstruction test +ctest -R clicRec_lcio_mt +``` diff --git a/_sources/tutorials/k4simdelphes/doc/starterkit/k4SimDelphes/Readme.md.txt b/_sources/tutorials/k4simdelphes/doc/starterkit/k4SimDelphes/Readme.md.txt new file mode 100644 index 0000000..2e5c8e8 --- /dev/null +++ b/_sources/tutorials/k4simdelphes/doc/starterkit/k4SimDelphes/Readme.md.txt @@ -0,0 +1,64 @@ +# Running Delphes fast simulation with EDM4hep output + +The [`k4SimDelphes`](https://github.com/key4hep/k4SimDelphes) package provides utilities to convert output from the [Delphes fast simulation framework](https://cp3.irmp.ucl.ac.be/projects/delphes) into the [EDM4hep](https://github.com/key4hep/EDM4hep) format. It offers standalone executables, similar to the ones Delphes offers, as well as integration into the Key4hep framework. Here we will provide examples of how to run the standalone executables as well as the usage in the Key4hep framework. + +## Setup and prerequisites +The following examples assume that you have access to an existing installation of the Key4hep software stack. The easiest way to achieve this to use an existing installation on `cvmfs` +```bash +source /cvmfs/sw.hsf.org/key4hep/setup.sh +``` +Alternatively it is possible to build the complete stack via `spack`, see the [instructions](https://key4hep.github.io/key4hep-doc/spack-build-instructions-for-librarians/README.html) for how to do this. + +In order to run the examples below it is necessary to get some inputs that are used for the generation of the physics events. In the following we will be using pythia generator files that are also used by the FCCee. In particular we will be generating the following process + +e+e- -> ZH -> mu+mu- X (i.e. the Z decays into a pair of oppositely charged muons and the H to anything) + +To start we download the pythia cards for this process +```bash +wget https://raw.githubusercontent.com/HEP-FCC/FCC-config/spring2021/FCCee/Generator/Pythia8/p8_noBES_ee_ZH_ecm240.cmd +``` + +All the other resources are available from within a Key4hep release. + +## Standalone executables + +For this example we will be using the `DelphesPythia8_EDM4HEP` standalone executable, which is essentially the same as the `DelphesPythia8` executable that is provided by Delphes. Contrary to the Delphes executable the one provided by k4SimDelphes will produce output in the EDM4hep format. + +To run the generation and fast detector simulation in one go run +```bash +DelphesPythia8_EDM4HEP ${DELPHES_DIR}/cards/delphes_card_IDEA.tcl \ + ${K4SIMDELPHES}/edm4hep_output_config.tcl \ + p8_noBES_ee_ZH_ecm240.cmd \ + delphes_events_edm4hep.root +``` + +The arguments in this case are (in the order they are passed) +- The delphes card that describes the (parameterized) detector. In this case we use one that is shipped with the Delphes installation +- The output configuration for the Delphes to EDM4hep converter. Here we use the defaults that are provided by `k4SimDelphes`, which should cover the majority of use cases. It is however possible to [configure these to your needs](https://github.com/key4hep/k4SimDelphes/blob/main/doc/output_config.md) if necessary. +- The pythia card that describes the physics process [as described above](#setup-and-prerequisites) +- The name of the output file that will be created and that will contain the generated and simulated events in EDM4hep format + +### Other standalone executables +k4SimDelphes provides other standalone executables that can read different inputs. They offer the same functionality as the ones available from Delphes: +- `DelphesSTDHEP_EDM4HEP` - for reading STDHEP inputs +- `DelphesROOT_EDM4HEP` - for reading ROOT files in the Delphes format +- `DelphesPythia8_EDM4HEP` - for running Pythia8 as part of the simulation + +For all executables it is possible to at least get the order of the input arguments via `--help` or `-h`, e.g. +```bash +DelphesSTDHEP_EDM4HEP --help +``` +will print +```console +Usage: DelphesHepMC config_file output_config_file output_file [input_file(s)] +config_file - configuration file in Tcl format, +output_config_file - configuration file steering the content of the edm4hep output in Tcl format, +output_file - output file in ROOT format, +input_file(s) - input file(s) in STDHEP format, +with no input_file, or when input_file is -, read standard input. + +``` + +## Usage in the Key4hep framework + +- [ ] TODO diff --git a/_sources/tutorials/key4hep-tutorials/gaudi_ild_reco/README.md.txt b/_sources/tutorials/key4hep-tutorials/gaudi_ild_reco/README.md.txt new file mode 100644 index 0000000..8cb1c51 --- /dev/null +++ b/_sources/tutorials/key4hep-tutorials/gaudi_ild_reco/README.md.txt @@ -0,0 +1,393 @@ +# Running ILD simulation and reconstruction + +This exercise aims at showing you how to run full simulation as well as +reconstruction using `ddsim` and the Gaudi based Key4hep framework respectively. +You will +- Run `ddsim` to produce SIM level input files for the reconstruction in EDM4hep + format +- Learn how to use the tools provided by + [`k4MarlinWrapper`](https://github.com/key4hep/k4MarlinWrapper) that allows to + run workflows that were originally developed for the `Marlin` in the Gaudi + based framework of Key4hep. This includes + - Converting a Marlin steering file to a Gaudi options file, + - Adapting the options file to be able to read and write EDM4hep output + - Running this Gaudi options file via `k4run` + +In this particular case we are using the ILD configuration to do this but the +conceptual steps are very similar for other detector concepts that used Marlin +originally. + +## Setup +If you haven't done it yet, source a Key4hep software environment via + +```bash +source /cvmfs/sw.hsf.org/key4hep/setup.sh +``` + +For the remainder of the tutorial we will assume that you are working within the +`key4hep_tut_ild_reco` directory, i.e. + +```bash +mkdir key4hep_tut_ild_reco +cd key4hep_tut_ild_reco +``` + +However, this is a minor detail and you can choose whatever directory you want. +We do suggest a clean directory though. + +Next we will be using the standard simulation and reconstruction +configuration for ILD which we can get via + +```bash +git clone https://github.com/iLCSoft/ILDConfig +``` + +For the rest of this tutorial we will be working in the +`ILDConfig/StandardConfig/production` folder + +```bash +cd ILDConfig/StandardConfig/production +``` + +## Running the simulation + +We will use the output file of [*the whizard +tutorial*](https://github.com/key4hep/key4hep-tutorials/blob/main/whizard_gen/README.md) +as generator level input. In case you have not done that exercise you can get +one via + +```bash +wget https://raw.githubusercontent.com/key4hep/key4hep-tutorials/main/gaudi_ild_reco/input_files/zh_mumu.slcio +``` + +Simulating a few events with `ddsim` is straight forward. `ddsim` can produce +EDM4hep and LCIO format output files, and it decides which format to used based +on the name of the output file: +- Names ending on `.slcio` will result in LCIO output files +- Names ending in `edm4hep.root` will result in in EDM4hep output files + +In the course of this exercise we will only need the EDM4hep format, we simply +provide both options for convenience here. + +::::{tab-set} +:::{tab-item} EDM4hep +:sync: edm4hep + +To run the simulation with EDM4hep output you can use the following command +```bash +ddsim --compactFile $k4geo_DIR/ILD/compact/ILD_l5_v02/ILD_l5_v02.xml \ + --steeringFile ddsim_steer.py \ + --inputFiles zh_mumu.slcio \ + --outputFile zh_mumu_SIM.edm4hep.root +``` + +::: +:::{tab-item} LCIO +:sync: lcio + +To run the simulation with LCIO output you can use the following command +``` bash +ddsim --compactFile $k4geo_DIR/ILD/compact/ILD_l5_v02/ILD_l5_v02.xml \ + --steeringFile ddsim_steer.py \ + --inputFiles zh_mumu.slcio \ + --outputFile zh_mumu_SIM.slcio +``` + +::: +:::: + +Depending on the machine where you are running this, this will take up to a few +minutes to complete. You can start this and read on in the meantime. + +## Reconstruction + +To run the reconstruction we will use the Gaudi based Key4hep framework. Note +that we can run the reconstruction just the same as within iLCSoft via `Marlin`. +However, we will not show that in this tutorial. + +### Using `ILDReconstruction.py` from ILDConfig + +In order to run the *standard reconstruction* simply run the following command + +```bash +k4run ILDReconstruction.py \ + --detectorModel=ILD_l5_o1_v02 \ + --inputFiles=zh_mumu_SIM.edm4hep.root \ + --outputFileBase=zh_mumu +``` + +The `ILDReconstruction.py` configuration can handle several different ILD +detector configurations, so we have to choose one via the `--detectorModel` +argument. Make sure that this is compatible to the one that has been used for +simulation. + +This will produce several new output files + +- `zh_mumu_REC.edm4hep.root` - The output of the reconstruction in EDM4hep + format +- `zh_mumu_AIDA.root` - The histograms that were produce by wrapped processors + using the AIDA interface +- `zh_mumu_PfoAnalysis.root` - The output file of the Pandora PFO analysis + processor + +`ILDReconstruction.py` also supports reading LCIO inputs and will detect this +automatically from the input file name. It also supports producing LCIO output +files via the `--lcioOutput` flag, which can either be `off` (default), `on` or +`only` (for not producing any EMD4hep output). + +Check [the introduction to EDM4hep / +podio](https://key4hep.github.io/key4hep-doc/how-tos/key4hep-tutorials/edm4hep_analysis/edm4hep_api_intro.html) +for more details on how to read and analyse this file. + +### Creating a Gaudi options file + +```{warning} +These instructions show you how to convert an existing Marlin steering file to a +Gaudi options file using the full ILD reconstruction as an example since it +exhibits a few of the potential issues that you might run into along the way. +However, we **strongly recommend using the existing reconstruction configuration +that is available from +[ILDConfig](https://github.com/iLCSoft/ILDConfig/tree/master/StandardConfig/production) +for actually running the reconstruction.** It has more features and also +supports running with different detector models, something that the following +steps will not achieve!. +``` + +The bulk of the work for creating such an options file from an existing Marlin +steering file in XML format can be done with the +`convertMarlinSteeringToGaudi.py` converter script. We will start by converting +the `MarlinStdReco.xml` steering file and then do some minor adjustments to the +converted options file. The main thing to consider for the ILD configuration is +that `MarlinStdReco.xml` makes use of several include statements to pull in more +configuration. Hence, we first have to create a Marlin steering file with these +includes resolved. We also have to provide a `DetectorModel` constant here, +since some of the includes depend on this. + +```bash +Marlin -n MarlinStdReco.xml --constant.DetectorModel=ILD_l5_o1_v02 +``` + +You should now have a `MarlinStdRecoParsed.xml` file. This is the one that we +will convert using the converter script via + +```bash +convertMarlinSteeringToGaudi.py MarlinStdRecoParsed.xml MarlinStdReco.py +``` + +Since some parts of the Marlin steering file conversion can not be handled +automatically we have to make a few adjustments to `MarlinStdReco.py`. We +recommend to simply edit the file directly, but you can also use the `sed` +commands below to do these adjustments. The adjustments are: +- Give the `lcgeo_DIR` constant (first entry in the `CONSTANTS` dict) a + meaningful value. The easiest way to do this is to simply get the value of the + corresponding environment variable via `os.environ["lcgeo_DIR"]` (don't forget + to `import os` at the top) +- Exclude the `BgOverlayWW`, `BgOverlayBB`, `BgOverlayBW`, `BgOverlayWB` and `PairBgOverlay` + algorithms from being run, by simply commenting out the lines where these are + appended to the `algList` (this list is populated at almost the end of the + file). + +:::{dropdown} `sed` commands for adjustments + +``` bash +sed -i '1s/^/import os\n/' MarlinStdReco.py +sed -i 's/\( *.lcgeo_DIR.:\).*/\1 os.environ["lcgeo_DIR"],'/ MarlinStdReco.py +sed -i 's/algList.append(BgOverlayWW)/# algList.append(BgOverlayWW)/' MarlinStdReco.py +sed -i 's/algList.append(BgOverlayWB)/# algList.append(BgOverlayWB)/' MarlinStdReco.py +sed -i 's/algList.append(BgOverlayBW)/# algList.append(BgOverlayBW)/' MarlinStdReco.py +sed -i 's/algList.append(BgOverlayBB)/# algList.append(BgOverlayBB)/' MarlinStdReco.py +sed -i 's/algList.append(PairBgOverlay)/# algList.append(PairBgOverlay)/' MarlinStdReco.py +``` + +::: + +With the state the options file is in now, you would be able to run it with LCIO +input. + +:::{dropdown} Running the reconstruction with LCIO +To run the reconstruction with LCIO inputs and outputs we now simply need to +pass in the input file that we have created at the simulation step + +```bash +k4run MarlinStdReco.py --LcioEvent.Files=zh_mumu_SIM.slcio +``` + +This should take somewhere between 20 seconds up to roughly a minute to run. If +you haven't changed anything else you should now have a few output files: + +```bash +ls StandardReco_*.* +``` + +should now show a `REC` and `DST` file, as well as a `PfoAnalysis` and an `AIDA` +file. You can change the names of these files by adjusting the `OutputBaseName`, +resp. The corresponding filename constants values in `CONSTANTS`. + +::: + +### Adapting the options file for EDM4hep + +It is necessary to adapt the Gaudi options file a bit further: +- Replace the `LcioEvent` algorithm with the `PodioInput` algorithm + - Make sure to replace the `Files` option with the `collections` option and to + populate this option with the list of collections you want to read (see + below) +- Replace the `EventDataSvc` with the `k4DataSvc` (remember to instantiate it + with `"EventDataSvc"` as name) +- Add a `PodioOutput` algorithm to write EDM4hep output (don't forget to add it + to the `algList` at the very end) + - (For the sake of this exercise) configure this to only write the + `MCParticlesSkimmed`, `PandoraPFOs` and the `RecoMCTruthLink` collections +- Attach the necessary in-memory on-the-fly converters between EDM4hep and LCIO + (and vice versa) + - For the conversion of the EDM4hep inputs to LCIO instantiate a + `EDM4hep2LcioTool` and attach it to the first wrapped processor that is run + (`MyAIDAProcessor`). See detailed description below. + - For the conversion of the LCIO outputs to EDM4hep instantiate a + `Lcio2EDM4hepTool` and attach it to the last wrapped processor that is run + before the `PodioOutput` algorithm that you just added (`MyPfoAnalysis`). + Also see below. + +**For all of these steps make sure that you `import` all the necessary tools and +algorithms from `Configurables`!** + +The top of your file should now look something like this + +```python +from Configurables import ( + PodioInput, PodioOutput, k4DataSvc, MarlinProcessorWrapper, + EDM4hep2LcioTool, Lcio2EDM4hepTool + ) +from k4MarlinWrapper.parseConstants import * +algList = [] +evtsvc = k4DataSvc("EventDataSvc") +``` + +while the configuration for the input reader and the `EDM4hep2LcioTool` should +look like this + +```python +read = PodioInput() +read.OutputLevel = INFO +read.collections = [ + # ... list of collection names +] +algList.append(read) + +edm4hep2LcioConv = EDM4hep2LcioTool() +edm4hep2LcioConv.collNameMapping = { + "MCParticles": "MCParticle" +} + +# ... Unchanged config of MyAIDAProcessor + +MyAIDAProcessor.EDM4hep2LcioTool = edm4hep2LcioConv +``` + +:::{dropdown} list of collection names + +The list of collections that is populated by standard configuration of ILD for +simulation looks like this. You can simply copy this into the options file + +```python +read.collections = [ + "BeamCalCollection", + "BeamCalCollectionContributions", + "ECalBarrelScHitsEven", + "ECalBarrelScHitsEvenContributions", + "ECalBarrelScHitsOdd", + "ECalBarrelScHitsOddContributions", + "ECalBarrelSiHitsEven", + "ECalBarrelSiHitsEvenContributions", + "ECalBarrelSiHitsOdd", + "ECalBarrelSiHitsOddContributions", + "EcalEndcapRingCollection", + "EcalEndcapRingCollectionContributions", + "ECalEndcapScHitsEven", + "ECalEndcapScHitsEvenContributions", + "ECalEndcapScHitsOdd", + "ECalEndcapScHitsOddContributions", + "ECalEndcapSiHitsEven", + "ECalEndcapSiHitsEvenContributions", + "ECalEndcapSiHitsOdd", + "ECalEndcapSiHitsOddContributions", + "EventHeader", + "FTDCollection", + "HcalBarrelRegCollection", + "HcalBarrelRegCollectionContributions", + "HCalBarrelRPCHits", + "HCalBarrelRPCHitsContributions", + "HCalECRingRPCHits", + "HCalECRingRPCHitsContributions", + "HcalEndcapRingCollection", + "HcalEndcapRingCollectionContributions", + "HCalEndcapRPCHits", + "HCalEndcapRPCHitsContributions", + "HcalEndcapsCollection", + "HcalEndcapsCollectionContributions", + "LHCalCollection", + "LHCalCollectionContributions", + "LumiCalCollection", + "LumiCalCollectionContributions", + "MCParticles", + "SETCollection", + "SITCollection", + "TPCCollection", + "TPCLowPtCollection", + "TPCSpacePointCollection", + "VXDCollection", + "YokeBarrelCollection", + "YokeBarrelCollectionContributions", + "YokeEndcapsCollection", + "YokeEndcapsCollectionContributions", +] +``` + +::: + +Finally, the `PodioOutput` algorithm and the `Lcio2EDM4hepTool` can be +configuration should look something like this + +```python +# ... MyPfoAnalysis configuration unchanged + +lcio2edm4hepConv = Lcio2EDM4hepTool() +lcio2edm4hepConv.collNameMapping = { + "MCParticle": "MCParticles" +} +MyPfoAnalysis.Lcio2EDM4hepTool = lcio2edm4hepConv + +edm4hepOutput = PodioOutput() +edm4hepOutput.filename = "zh_mumu_reco.edm4hep.root" +edm4hepOutput.outputCommands = [ + "drop *", + "keep MCParticlesSkimmed", + "keep PandoraPFOs", + "keep RecoMCTruthLink", +] + +# ... the complete algList +algList.append(edm4hepOutput) + +# ... ApplicationMgr config +``` + +### Running the reconstruction with `k4run` + +After all these adaptions it is now possible to run the full reconstruction +chain on the previously simulated input with `k4run` + +```bash +k4run MarlinStdReco.py --num-events=3 --EventDataSvc.input=zh_mumu_SIM.edm4hep.root +``` + +Here we are again using the command line to specify the input file, we could +have just as well used the `input` option of the `evtsvc` in the options file. +Note also that we explicitly pass in the number of events, this is a workaround +for [this issue](https://github.com/key4hep/k4MarlinWrapper/issues/94). + +You should now have a `zh_mumu_reco.edm4hep.root` file that contains the +complete events in all their glory. For a more practical output you can tweak +the `edm4hepOutput.outputCommands` option in order to keep only "interesting" +collections. Also note that the REC and DST LCIO output files are still +produced. Can you reproduce these data tiers for EDM4hep? diff --git a/_sphinx_design_static/design-style.1e8bd061cd6da7fc9cf755528e8ffc24.min.css b/_sphinx_design_static/design-style.1e8bd061cd6da7fc9cf755528e8ffc24.min.css new file mode 100644 index 0000000..eb19f69 --- /dev/null +++ b/_sphinx_design_static/design-style.1e8bd061cd6da7fc9cf755528e8ffc24.min.css @@ -0,0 +1 @@ +.sd-bg-primary{background-color:var(--sd-color-primary) !important}.sd-bg-text-primary{color:var(--sd-color-primary-text) !important}button.sd-bg-primary:focus,button.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}a.sd-bg-primary:focus,a.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}.sd-bg-secondary{background-color:var(--sd-color-secondary) !important}.sd-bg-text-secondary{color:var(--sd-color-secondary-text) !important}button.sd-bg-secondary:focus,button.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}a.sd-bg-secondary:focus,a.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}.sd-bg-success{background-color:var(--sd-color-success) !important}.sd-bg-text-success{color:var(--sd-color-success-text) !important}button.sd-bg-success:focus,button.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}a.sd-bg-success:focus,a.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}.sd-bg-info{background-color:var(--sd-color-info) !important}.sd-bg-text-info{color:var(--sd-color-info-text) !important}button.sd-bg-info:focus,button.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}a.sd-bg-info:focus,a.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}.sd-bg-warning{background-color:var(--sd-color-warning) !important}.sd-bg-text-warning{color:var(--sd-color-warning-text) !important}button.sd-bg-warning:focus,button.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}a.sd-bg-warning:focus,a.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}.sd-bg-danger{background-color:var(--sd-color-danger) !important}.sd-bg-text-danger{color:var(--sd-color-danger-text) !important}button.sd-bg-danger:focus,button.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}a.sd-bg-danger:focus,a.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}.sd-bg-light{background-color:var(--sd-color-light) !important}.sd-bg-text-light{color:var(--sd-color-light-text) !important}button.sd-bg-light:focus,button.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}a.sd-bg-light:focus,a.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}.sd-bg-muted{background-color:var(--sd-color-muted) !important}.sd-bg-text-muted{color:var(--sd-color-muted-text) !important}button.sd-bg-muted:focus,button.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}a.sd-bg-muted:focus,a.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}.sd-bg-dark{background-color:var(--sd-color-dark) !important}.sd-bg-text-dark{color:var(--sd-color-dark-text) !important}button.sd-bg-dark:focus,button.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}a.sd-bg-dark:focus,a.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}.sd-bg-black{background-color:var(--sd-color-black) !important}.sd-bg-text-black{color:var(--sd-color-black-text) !important}button.sd-bg-black:focus,button.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}a.sd-bg-black:focus,a.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}.sd-bg-white{background-color:var(--sd-color-white) !important}.sd-bg-text-white{color:var(--sd-color-white-text) !important}button.sd-bg-white:focus,button.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}a.sd-bg-white:focus,a.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}.sd-text-primary,.sd-text-primary>p{color:var(--sd-color-primary) !important}a.sd-text-primary:focus,a.sd-text-primary:hover{color:var(--sd-color-primary-highlight) !important}.sd-text-secondary,.sd-text-secondary>p{color:var(--sd-color-secondary) !important}a.sd-text-secondary:focus,a.sd-text-secondary:hover{color:var(--sd-color-secondary-highlight) !important}.sd-text-success,.sd-text-success>p{color:var(--sd-color-success) !important}a.sd-text-success:focus,a.sd-text-success:hover{color:var(--sd-color-success-highlight) !important}.sd-text-info,.sd-text-info>p{color:var(--sd-color-info) !important}a.sd-text-info:focus,a.sd-text-info:hover{color:var(--sd-color-info-highlight) !important}.sd-text-warning,.sd-text-warning>p{color:var(--sd-color-warning) !important}a.sd-text-warning:focus,a.sd-text-warning:hover{color:var(--sd-color-warning-highlight) !important}.sd-text-danger,.sd-text-danger>p{color:var(--sd-color-danger) !important}a.sd-text-danger:focus,a.sd-text-danger:hover{color:var(--sd-color-danger-highlight) !important}.sd-text-light,.sd-text-light>p{color:var(--sd-color-light) !important}a.sd-text-light:focus,a.sd-text-light:hover{color:var(--sd-color-light-highlight) !important}.sd-text-muted,.sd-text-muted>p{color:var(--sd-color-muted) !important}a.sd-text-muted:focus,a.sd-text-muted:hover{color:var(--sd-color-muted-highlight) !important}.sd-text-dark,.sd-text-dark>p{color:var(--sd-color-dark) !important}a.sd-text-dark:focus,a.sd-text-dark:hover{color:var(--sd-color-dark-highlight) !important}.sd-text-black,.sd-text-black>p{color:var(--sd-color-black) !important}a.sd-text-black:focus,a.sd-text-black:hover{color:var(--sd-color-black-highlight) !important}.sd-text-white,.sd-text-white>p{color:var(--sd-color-white) !important}a.sd-text-white:focus,a.sd-text-white:hover{color:var(--sd-color-white-highlight) !important}.sd-outline-primary{border-color:var(--sd-color-primary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-primary:focus,a.sd-outline-primary:hover{border-color:var(--sd-color-primary-highlight) !important}.sd-outline-secondary{border-color:var(--sd-color-secondary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-secondary:focus,a.sd-outline-secondary:hover{border-color:var(--sd-color-secondary-highlight) !important}.sd-outline-success{border-color:var(--sd-color-success) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-success:focus,a.sd-outline-success:hover{border-color:var(--sd-color-success-highlight) !important}.sd-outline-info{border-color:var(--sd-color-info) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-info:focus,a.sd-outline-info:hover{border-color:var(--sd-color-info-highlight) !important}.sd-outline-warning{border-color:var(--sd-color-warning) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-warning:focus,a.sd-outline-warning:hover{border-color:var(--sd-color-warning-highlight) !important}.sd-outline-danger{border-color:var(--sd-color-danger) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-danger:focus,a.sd-outline-danger:hover{border-color:var(--sd-color-danger-highlight) !important}.sd-outline-light{border-color:var(--sd-color-light) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-light:focus,a.sd-outline-light:hover{border-color:var(--sd-color-light-highlight) !important}.sd-outline-muted{border-color:var(--sd-color-muted) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-muted:focus,a.sd-outline-muted:hover{border-color:var(--sd-color-muted-highlight) !important}.sd-outline-dark{border-color:var(--sd-color-dark) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-dark:focus,a.sd-outline-dark:hover{border-color:var(--sd-color-dark-highlight) !important}.sd-outline-black{border-color:var(--sd-color-black) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-black:focus,a.sd-outline-black:hover{border-color:var(--sd-color-black-highlight) !important}.sd-outline-white{border-color:var(--sd-color-white) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-white:focus,a.sd-outline-white:hover{border-color:var(--sd-color-white-highlight) !important}.sd-bg-transparent{background-color:transparent !important}.sd-outline-transparent{border-color:transparent !important}.sd-text-transparent{color:transparent !important}.sd-p-0{padding:0 !important}.sd-pt-0,.sd-py-0{padding-top:0 !important}.sd-pr-0,.sd-px-0{padding-right:0 !important}.sd-pb-0,.sd-py-0{padding-bottom:0 !important}.sd-pl-0,.sd-px-0{padding-left:0 !important}.sd-p-1{padding:.25rem !important}.sd-pt-1,.sd-py-1{padding-top:.25rem !important}.sd-pr-1,.sd-px-1{padding-right:.25rem !important}.sd-pb-1,.sd-py-1{padding-bottom:.25rem !important}.sd-pl-1,.sd-px-1{padding-left:.25rem !important}.sd-p-2{padding:.5rem !important}.sd-pt-2,.sd-py-2{padding-top:.5rem !important}.sd-pr-2,.sd-px-2{padding-right:.5rem !important}.sd-pb-2,.sd-py-2{padding-bottom:.5rem !important}.sd-pl-2,.sd-px-2{padding-left:.5rem !important}.sd-p-3{padding:1rem !important}.sd-pt-3,.sd-py-3{padding-top:1rem !important}.sd-pr-3,.sd-px-3{padding-right:1rem !important}.sd-pb-3,.sd-py-3{padding-bottom:1rem !important}.sd-pl-3,.sd-px-3{padding-left:1rem !important}.sd-p-4{padding:1.5rem !important}.sd-pt-4,.sd-py-4{padding-top:1.5rem !important}.sd-pr-4,.sd-px-4{padding-right:1.5rem !important}.sd-pb-4,.sd-py-4{padding-bottom:1.5rem !important}.sd-pl-4,.sd-px-4{padding-left:1.5rem !important}.sd-p-5{padding:3rem !important}.sd-pt-5,.sd-py-5{padding-top:3rem !important}.sd-pr-5,.sd-px-5{padding-right:3rem !important}.sd-pb-5,.sd-py-5{padding-bottom:3rem !important}.sd-pl-5,.sd-px-5{padding-left:3rem !important}.sd-m-auto{margin:auto !important}.sd-mt-auto,.sd-my-auto{margin-top:auto !important}.sd-mr-auto,.sd-mx-auto{margin-right:auto !important}.sd-mb-auto,.sd-my-auto{margin-bottom:auto !important}.sd-ml-auto,.sd-mx-auto{margin-left:auto !important}.sd-m-0{margin:0 !important}.sd-mt-0,.sd-my-0{margin-top:0 !important}.sd-mr-0,.sd-mx-0{margin-right:0 !important}.sd-mb-0,.sd-my-0{margin-bottom:0 !important}.sd-ml-0,.sd-mx-0{margin-left:0 !important}.sd-m-1{margin:.25rem !important}.sd-mt-1,.sd-my-1{margin-top:.25rem !important}.sd-mr-1,.sd-mx-1{margin-right:.25rem !important}.sd-mb-1,.sd-my-1{margin-bottom:.25rem !important}.sd-ml-1,.sd-mx-1{margin-left:.25rem !important}.sd-m-2{margin:.5rem !important}.sd-mt-2,.sd-my-2{margin-top:.5rem !important}.sd-mr-2,.sd-mx-2{margin-right:.5rem !important}.sd-mb-2,.sd-my-2{margin-bottom:.5rem !important}.sd-ml-2,.sd-mx-2{margin-left:.5rem !important}.sd-m-3{margin:1rem !important}.sd-mt-3,.sd-my-3{margin-top:1rem !important}.sd-mr-3,.sd-mx-3{margin-right:1rem !important}.sd-mb-3,.sd-my-3{margin-bottom:1rem !important}.sd-ml-3,.sd-mx-3{margin-left:1rem !important}.sd-m-4{margin:1.5rem !important}.sd-mt-4,.sd-my-4{margin-top:1.5rem !important}.sd-mr-4,.sd-mx-4{margin-right:1.5rem !important}.sd-mb-4,.sd-my-4{margin-bottom:1.5rem !important}.sd-ml-4,.sd-mx-4{margin-left:1.5rem !important}.sd-m-5{margin:3rem !important}.sd-mt-5,.sd-my-5{margin-top:3rem !important}.sd-mr-5,.sd-mx-5{margin-right:3rem !important}.sd-mb-5,.sd-my-5{margin-bottom:3rem !important}.sd-ml-5,.sd-mx-5{margin-left:3rem !important}.sd-w-25{width:25% !important}.sd-w-50{width:50% !important}.sd-w-75{width:75% !important}.sd-w-100{width:100% !important}.sd-w-auto{width:auto !important}.sd-h-25{height:25% !important}.sd-h-50{height:50% !important}.sd-h-75{height:75% !important}.sd-h-100{height:100% !important}.sd-h-auto{height:auto !important}.sd-d-none{display:none !important}.sd-d-inline{display:inline !important}.sd-d-inline-block{display:inline-block !important}.sd-d-block{display:block !important}.sd-d-grid{display:grid !important}.sd-d-flex-row{display:-ms-flexbox !important;display:flex !important;flex-direction:row !important}.sd-d-flex-column{display:-ms-flexbox !important;display:flex !important;flex-direction:column !important}.sd-d-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}@media(min-width: 576px){.sd-d-sm-none{display:none !important}.sd-d-sm-inline{display:inline !important}.sd-d-sm-inline-block{display:inline-block !important}.sd-d-sm-block{display:block !important}.sd-d-sm-grid{display:grid !important}.sd-d-sm-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-sm-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 768px){.sd-d-md-none{display:none !important}.sd-d-md-inline{display:inline !important}.sd-d-md-inline-block{display:inline-block !important}.sd-d-md-block{display:block !important}.sd-d-md-grid{display:grid !important}.sd-d-md-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-md-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 992px){.sd-d-lg-none{display:none !important}.sd-d-lg-inline{display:inline !important}.sd-d-lg-inline-block{display:inline-block !important}.sd-d-lg-block{display:block !important}.sd-d-lg-grid{display:grid !important}.sd-d-lg-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-lg-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 1200px){.sd-d-xl-none{display:none !important}.sd-d-xl-inline{display:inline !important}.sd-d-xl-inline-block{display:inline-block !important}.sd-d-xl-block{display:block !important}.sd-d-xl-grid{display:grid !important}.sd-d-xl-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-xl-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}.sd-align-major-start{justify-content:flex-start !important}.sd-align-major-end{justify-content:flex-end !important}.sd-align-major-center{justify-content:center !important}.sd-align-major-justify{justify-content:space-between !important}.sd-align-major-spaced{justify-content:space-evenly !important}.sd-align-minor-start{align-items:flex-start !important}.sd-align-minor-end{align-items:flex-end !important}.sd-align-minor-center{align-items:center !important}.sd-align-minor-stretch{align-items:stretch !important}.sd-text-justify{text-align:justify !important}.sd-text-left{text-align:left !important}.sd-text-right{text-align:right !important}.sd-text-center{text-align:center !important}.sd-font-weight-light{font-weight:300 !important}.sd-font-weight-lighter{font-weight:lighter !important}.sd-font-weight-normal{font-weight:400 !important}.sd-font-weight-bold{font-weight:700 !important}.sd-font-weight-bolder{font-weight:bolder !important}.sd-font-italic{font-style:italic !important}.sd-text-decoration-none{text-decoration:none !important}.sd-text-lowercase{text-transform:lowercase !important}.sd-text-uppercase{text-transform:uppercase !important}.sd-text-capitalize{text-transform:capitalize !important}.sd-text-wrap{white-space:normal !important}.sd-text-nowrap{white-space:nowrap !important}.sd-text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sd-fs-1,.sd-fs-1>p{font-size:calc(1.375rem + 1.5vw) !important;line-height:unset !important}.sd-fs-2,.sd-fs-2>p{font-size:calc(1.325rem + 0.9vw) !important;line-height:unset !important}.sd-fs-3,.sd-fs-3>p{font-size:calc(1.3rem + 0.6vw) !important;line-height:unset !important}.sd-fs-4,.sd-fs-4>p{font-size:calc(1.275rem + 0.3vw) !important;line-height:unset !important}.sd-fs-5,.sd-fs-5>p{font-size:1.25rem !important;line-height:unset !important}.sd-fs-6,.sd-fs-6>p{font-size:1rem !important;line-height:unset !important}.sd-border-0{border:0 solid !important}.sd-border-top-0{border-top:0 solid !important}.sd-border-bottom-0{border-bottom:0 solid !important}.sd-border-right-0{border-right:0 solid !important}.sd-border-left-0{border-left:0 solid !important}.sd-border-1{border:1px solid !important}.sd-border-top-1{border-top:1px solid !important}.sd-border-bottom-1{border-bottom:1px solid !important}.sd-border-right-1{border-right:1px solid !important}.sd-border-left-1{border-left:1px solid !important}.sd-border-2{border:2px solid !important}.sd-border-top-2{border-top:2px solid !important}.sd-border-bottom-2{border-bottom:2px solid !important}.sd-border-right-2{border-right:2px solid !important}.sd-border-left-2{border-left:2px solid !important}.sd-border-3{border:3px solid !important}.sd-border-top-3{border-top:3px solid !important}.sd-border-bottom-3{border-bottom:3px solid !important}.sd-border-right-3{border-right:3px solid !important}.sd-border-left-3{border-left:3px solid !important}.sd-border-4{border:4px solid !important}.sd-border-top-4{border-top:4px solid !important}.sd-border-bottom-4{border-bottom:4px solid !important}.sd-border-right-4{border-right:4px solid !important}.sd-border-left-4{border-left:4px solid !important}.sd-border-5{border:5px solid !important}.sd-border-top-5{border-top:5px solid !important}.sd-border-bottom-5{border-bottom:5px solid !important}.sd-border-right-5{border-right:5px solid !important}.sd-border-left-5{border-left:5px solid !important}.sd-rounded-0{border-radius:0 !important}.sd-rounded-1{border-radius:.2rem !important}.sd-rounded-2{border-radius:.3rem !important}.sd-rounded-3{border-radius:.5rem !important}.sd-rounded-pill{border-radius:50rem !important}.sd-rounded-circle{border-radius:50% !important}.shadow-none{box-shadow:none !important}.sd-shadow-sm{box-shadow:0 .125rem .25rem var(--sd-color-shadow) !important}.sd-shadow-md{box-shadow:0 .5rem 1rem var(--sd-color-shadow) !important}.sd-shadow-lg{box-shadow:0 1rem 3rem var(--sd-color-shadow) !important}@keyframes sd-slide-from-left{0%{transform:translateX(-100%)}100%{transform:translateX(0)}}@keyframes sd-slide-from-right{0%{transform:translateX(200%)}100%{transform:translateX(0)}}@keyframes sd-grow100{0%{transform:scale(0);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50{0%{transform:scale(0.5);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50-rot20{0%{transform:scale(0.5) rotateZ(-20deg);opacity:.5}75%{transform:scale(1) rotateZ(5deg);opacity:1}95%{transform:scale(1) rotateZ(-1deg);opacity:1}100%{transform:scale(1) rotateZ(0);opacity:1}}.sd-animate-slide-from-left{animation:1s ease-out 0s 1 normal none running sd-slide-from-left}.sd-animate-slide-from-right{animation:1s ease-out 0s 1 normal none running sd-slide-from-right}.sd-animate-grow100{animation:1s ease-out 0s 1 normal none running sd-grow100}.sd-animate-grow50{animation:1s ease-out 0s 1 normal none running sd-grow50}.sd-animate-grow50-rot20{animation:1s ease-out 0s 1 normal none running sd-grow50-rot20}.sd-badge{display:inline-block;padding:.35em .65em;font-size:.75em;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.sd-badge:empty{display:none}a.sd-badge{text-decoration:none}.sd-btn .sd-badge{position:relative;top:-1px}.sd-btn{background-color:transparent;border:1px solid transparent;border-radius:.25rem;cursor:pointer;display:inline-block;font-weight:400;font-size:1rem;line-height:1.5;padding:.375rem .75rem;text-align:center;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;vertical-align:middle;user-select:none;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none}.sd-btn:hover{text-decoration:none}@media(prefers-reduced-motion: reduce){.sd-btn{transition:none}}.sd-btn-primary,.sd-btn-outline-primary:hover,.sd-btn-outline-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-primary:hover,.sd-btn-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary-highlight) !important;border-color:var(--sd-color-primary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-primary{color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary,.sd-btn-outline-secondary:hover,.sd-btn-outline-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary:hover,.sd-btn-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary-highlight) !important;border-color:var(--sd-color-secondary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-secondary{color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success,.sd-btn-outline-success:hover,.sd-btn-outline-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success:hover,.sd-btn-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success-highlight) !important;border-color:var(--sd-color-success-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-success{color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info,.sd-btn-outline-info:hover,.sd-btn-outline-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info:hover,.sd-btn-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info-highlight) !important;border-color:var(--sd-color-info-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-info{color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning,.sd-btn-outline-warning:hover,.sd-btn-outline-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning:hover,.sd-btn-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning-highlight) !important;border-color:var(--sd-color-warning-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-warning{color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger,.sd-btn-outline-danger:hover,.sd-btn-outline-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger:hover,.sd-btn-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger-highlight) !important;border-color:var(--sd-color-danger-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-danger{color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light,.sd-btn-outline-light:hover,.sd-btn-outline-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light:hover,.sd-btn-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light-highlight) !important;border-color:var(--sd-color-light-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-light{color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted,.sd-btn-outline-muted:hover,.sd-btn-outline-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted:hover,.sd-btn-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted-highlight) !important;border-color:var(--sd-color-muted-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-muted{color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark,.sd-btn-outline-dark:hover,.sd-btn-outline-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark:hover,.sd-btn-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark-highlight) !important;border-color:var(--sd-color-dark-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-dark{color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black,.sd-btn-outline-black:hover,.sd-btn-outline-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black:hover,.sd-btn-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black-highlight) !important;border-color:var(--sd-color-black-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-black{color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white,.sd-btn-outline-white:hover,.sd-btn-outline-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white:hover,.sd-btn-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white-highlight) !important;border-color:var(--sd-color-white-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-white{color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.sd-hide-link-text{font-size:0}.sd-octicon,.sd-material-icon{display:inline-block;fill:currentColor;vertical-align:middle}.sd-avatar-xs{border-radius:50%;object-fit:cover;object-position:center;width:1rem;height:1rem}.sd-avatar-sm{border-radius:50%;object-fit:cover;object-position:center;width:3rem;height:3rem}.sd-avatar-md{border-radius:50%;object-fit:cover;object-position:center;width:5rem;height:5rem}.sd-avatar-lg{border-radius:50%;object-fit:cover;object-position:center;width:7rem;height:7rem}.sd-avatar-xl{border-radius:50%;object-fit:cover;object-position:center;width:10rem;height:10rem}.sd-avatar-inherit{border-radius:50%;object-fit:cover;object-position:center;width:inherit;height:inherit}.sd-avatar-initial{border-radius:50%;object-fit:cover;object-position:center;width:initial;height:initial}.sd-card{background-clip:border-box;background-color:var(--sd-color-card-background);border:1px solid var(--sd-color-card-border);border-radius:.25rem;color:var(--sd-color-card-text);display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;position:relative;word-wrap:break-word}.sd-card>hr{margin-left:0;margin-right:0}.sd-card-hover:hover{border-color:var(--sd-color-card-border-hover);transform:scale(1.01)}.sd-card-body{-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem 1rem}.sd-card-title{margin-bottom:.5rem}.sd-card-subtitle{margin-top:-0.25rem;margin-bottom:0}.sd-card-text:last-child{margin-bottom:0}.sd-card-link:hover{text-decoration:none}.sd-card-link+.card-link{margin-left:1rem}.sd-card-header{padding:.5rem 1rem;margin-bottom:0;background-color:var(--sd-color-card-header);border-bottom:1px solid var(--sd-color-card-border)}.sd-card-header:first-child{border-radius:calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0}.sd-card-footer{padding:.5rem 1rem;background-color:var(--sd-color-card-footer);border-top:1px solid var(--sd-color-card-border)}.sd-card-footer:last-child{border-radius:0 0 calc(0.25rem - 1px) calc(0.25rem - 1px)}.sd-card-header-tabs{margin-right:-0.5rem;margin-bottom:-0.5rem;margin-left:-0.5rem;border-bottom:0}.sd-card-header-pills{margin-right:-0.5rem;margin-left:-0.5rem}.sd-card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom,.sd-card-img-top{width:100%}.sd-card-img,.sd-card-img-top{border-top-left-radius:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom{border-bottom-left-radius:calc(0.25rem - 1px);border-bottom-right-radius:calc(0.25rem - 1px)}.sd-cards-carousel{width:100%;display:flex;flex-wrap:nowrap;-ms-flex-direction:row;flex-direction:row;overflow-x:hidden;scroll-snap-type:x mandatory}.sd-cards-carousel.sd-show-scrollbar{overflow-x:auto}.sd-cards-carousel:hover,.sd-cards-carousel:focus{overflow-x:auto}.sd-cards-carousel>.sd-card{flex-shrink:0;scroll-snap-align:start}.sd-cards-carousel>.sd-card:not(:last-child){margin-right:3px}.sd-card-cols-1>.sd-card{width:90%}.sd-card-cols-2>.sd-card{width:45%}.sd-card-cols-3>.sd-card{width:30%}.sd-card-cols-4>.sd-card{width:22.5%}.sd-card-cols-5>.sd-card{width:18%}.sd-card-cols-6>.sd-card{width:15%}.sd-card-cols-7>.sd-card{width:12.8571428571%}.sd-card-cols-8>.sd-card{width:11.25%}.sd-card-cols-9>.sd-card{width:10%}.sd-card-cols-10>.sd-card{width:9%}.sd-card-cols-11>.sd-card{width:8.1818181818%}.sd-card-cols-12>.sd-card{width:7.5%}.sd-container,.sd-container-fluid,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container-xl{margin-left:auto;margin-right:auto;padding-left:var(--sd-gutter-x, 0.75rem);padding-right:var(--sd-gutter-x, 0.75rem);width:100%}@media(min-width: 576px){.sd-container-sm,.sd-container{max-width:540px}}@media(min-width: 768px){.sd-container-md,.sd-container-sm,.sd-container{max-width:720px}}@media(min-width: 992px){.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:960px}}@media(min-width: 1200px){.sd-container-xl,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:1140px}}.sd-row{--sd-gutter-x: 1.5rem;--sd-gutter-y: 0;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-top:calc(var(--sd-gutter-y) * -1);margin-right:calc(var(--sd-gutter-x) * -0.5);margin-left:calc(var(--sd-gutter-x) * -0.5)}.sd-row>*{box-sizing:border-box;flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--sd-gutter-x) * 0.5);padding-left:calc(var(--sd-gutter-x) * 0.5);margin-top:var(--sd-gutter-y)}.sd-col{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-auto>*{flex:0 0 auto;width:auto}.sd-row-cols-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}@media(min-width: 576px){.sd-col-sm{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-sm-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-sm-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-sm-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-sm-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-sm-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-sm-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-sm-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-sm-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-sm-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-sm-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-sm-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-sm-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-sm-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 768px){.sd-col-md{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-md-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-md-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-md-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-md-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-md-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-md-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-md-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-md-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-md-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-md-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-md-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-md-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-md-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 992px){.sd-col-lg{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-lg-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-lg-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-lg-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-lg-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-lg-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-lg-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-lg-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-lg-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-lg-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-lg-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-lg-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-lg-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-lg-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 1200px){.sd-col-xl{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-xl-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-xl-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-xl-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-xl-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-xl-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-xl-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-xl-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-xl-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-xl-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-xl-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-xl-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-xl-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-xl-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}.sd-col-auto{flex:0 0 auto;-ms-flex:0 0 auto;width:auto}.sd-col-1{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}.sd-col-2{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-col-3{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-col-4{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-col-5{flex:0 0 auto;-ms-flex:0 0 auto;width:41.6666666667%}.sd-col-6{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-col-7{flex:0 0 auto;-ms-flex:0 0 auto;width:58.3333333333%}.sd-col-8{flex:0 0 auto;-ms-flex:0 0 auto;width:66.6666666667%}.sd-col-9{flex:0 0 auto;-ms-flex:0 0 auto;width:75%}.sd-col-10{flex:0 0 auto;-ms-flex:0 0 auto;width:83.3333333333%}.sd-col-11{flex:0 0 auto;-ms-flex:0 0 auto;width:91.6666666667%}.sd-col-12{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-g-0,.sd-gy-0{--sd-gutter-y: 0}.sd-g-0,.sd-gx-0{--sd-gutter-x: 0}.sd-g-1,.sd-gy-1{--sd-gutter-y: 0.25rem}.sd-g-1,.sd-gx-1{--sd-gutter-x: 0.25rem}.sd-g-2,.sd-gy-2{--sd-gutter-y: 0.5rem}.sd-g-2,.sd-gx-2{--sd-gutter-x: 0.5rem}.sd-g-3,.sd-gy-3{--sd-gutter-y: 1rem}.sd-g-3,.sd-gx-3{--sd-gutter-x: 1rem}.sd-g-4,.sd-gy-4{--sd-gutter-y: 1.5rem}.sd-g-4,.sd-gx-4{--sd-gutter-x: 1.5rem}.sd-g-5,.sd-gy-5{--sd-gutter-y: 3rem}.sd-g-5,.sd-gx-5{--sd-gutter-x: 3rem}@media(min-width: 576px){.sd-col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-sm-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-sm-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-sm-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-sm-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-sm-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-sm-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-sm-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-sm-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-sm-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-sm-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-sm-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-sm-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-sm-0,.sd-gy-sm-0{--sd-gutter-y: 0}.sd-g-sm-0,.sd-gx-sm-0{--sd-gutter-x: 0}.sd-g-sm-1,.sd-gy-sm-1{--sd-gutter-y: 0.25rem}.sd-g-sm-1,.sd-gx-sm-1{--sd-gutter-x: 0.25rem}.sd-g-sm-2,.sd-gy-sm-2{--sd-gutter-y: 0.5rem}.sd-g-sm-2,.sd-gx-sm-2{--sd-gutter-x: 0.5rem}.sd-g-sm-3,.sd-gy-sm-3{--sd-gutter-y: 1rem}.sd-g-sm-3,.sd-gx-sm-3{--sd-gutter-x: 1rem}.sd-g-sm-4,.sd-gy-sm-4{--sd-gutter-y: 1.5rem}.sd-g-sm-4,.sd-gx-sm-4{--sd-gutter-x: 1.5rem}.sd-g-sm-5,.sd-gy-sm-5{--sd-gutter-y: 3rem}.sd-g-sm-5,.sd-gx-sm-5{--sd-gutter-x: 3rem}}@media(min-width: 768px){.sd-col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-md-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-md-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-md-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-md-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-md-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-md-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-md-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-md-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-md-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-md-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-md-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-md-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-md-0,.sd-gy-md-0{--sd-gutter-y: 0}.sd-g-md-0,.sd-gx-md-0{--sd-gutter-x: 0}.sd-g-md-1,.sd-gy-md-1{--sd-gutter-y: 0.25rem}.sd-g-md-1,.sd-gx-md-1{--sd-gutter-x: 0.25rem}.sd-g-md-2,.sd-gy-md-2{--sd-gutter-y: 0.5rem}.sd-g-md-2,.sd-gx-md-2{--sd-gutter-x: 0.5rem}.sd-g-md-3,.sd-gy-md-3{--sd-gutter-y: 1rem}.sd-g-md-3,.sd-gx-md-3{--sd-gutter-x: 1rem}.sd-g-md-4,.sd-gy-md-4{--sd-gutter-y: 1.5rem}.sd-g-md-4,.sd-gx-md-4{--sd-gutter-x: 1.5rem}.sd-g-md-5,.sd-gy-md-5{--sd-gutter-y: 3rem}.sd-g-md-5,.sd-gx-md-5{--sd-gutter-x: 3rem}}@media(min-width: 992px){.sd-col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-lg-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-lg-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-lg-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-lg-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-lg-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-lg-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-lg-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-lg-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-lg-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-lg-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-lg-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-lg-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-lg-0,.sd-gy-lg-0{--sd-gutter-y: 0}.sd-g-lg-0,.sd-gx-lg-0{--sd-gutter-x: 0}.sd-g-lg-1,.sd-gy-lg-1{--sd-gutter-y: 0.25rem}.sd-g-lg-1,.sd-gx-lg-1{--sd-gutter-x: 0.25rem}.sd-g-lg-2,.sd-gy-lg-2{--sd-gutter-y: 0.5rem}.sd-g-lg-2,.sd-gx-lg-2{--sd-gutter-x: 0.5rem}.sd-g-lg-3,.sd-gy-lg-3{--sd-gutter-y: 1rem}.sd-g-lg-3,.sd-gx-lg-3{--sd-gutter-x: 1rem}.sd-g-lg-4,.sd-gy-lg-4{--sd-gutter-y: 1.5rem}.sd-g-lg-4,.sd-gx-lg-4{--sd-gutter-x: 1.5rem}.sd-g-lg-5,.sd-gy-lg-5{--sd-gutter-y: 3rem}.sd-g-lg-5,.sd-gx-lg-5{--sd-gutter-x: 3rem}}@media(min-width: 1200px){.sd-col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-xl-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-xl-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-xl-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-xl-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-xl-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-xl-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-xl-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-xl-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-xl-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-xl-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-xl-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-xl-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-xl-0,.sd-gy-xl-0{--sd-gutter-y: 0}.sd-g-xl-0,.sd-gx-xl-0{--sd-gutter-x: 0}.sd-g-xl-1,.sd-gy-xl-1{--sd-gutter-y: 0.25rem}.sd-g-xl-1,.sd-gx-xl-1{--sd-gutter-x: 0.25rem}.sd-g-xl-2,.sd-gy-xl-2{--sd-gutter-y: 0.5rem}.sd-g-xl-2,.sd-gx-xl-2{--sd-gutter-x: 0.5rem}.sd-g-xl-3,.sd-gy-xl-3{--sd-gutter-y: 1rem}.sd-g-xl-3,.sd-gx-xl-3{--sd-gutter-x: 1rem}.sd-g-xl-4,.sd-gy-xl-4{--sd-gutter-y: 1.5rem}.sd-g-xl-4,.sd-gx-xl-4{--sd-gutter-x: 1.5rem}.sd-g-xl-5,.sd-gy-xl-5{--sd-gutter-y: 3rem}.sd-g-xl-5,.sd-gx-xl-5{--sd-gutter-x: 3rem}}.sd-flex-row-reverse{flex-direction:row-reverse !important}details.sd-dropdown{position:relative}details.sd-dropdown .sd-summary-title{font-weight:700;padding-right:3em !important;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none}details.sd-dropdown:hover{cursor:pointer}details.sd-dropdown .sd-summary-content{cursor:default}details.sd-dropdown summary{list-style:none;padding:1em}details.sd-dropdown summary .sd-octicon.no-title{vertical-align:middle}details.sd-dropdown[open] summary .sd-octicon.no-title{visibility:hidden}details.sd-dropdown summary::-webkit-details-marker{display:none}details.sd-dropdown summary:focus{outline:none}details.sd-dropdown .sd-summary-icon{margin-right:.5em}details.sd-dropdown .sd-summary-icon svg{opacity:.8}details.sd-dropdown summary:hover .sd-summary-up svg,details.sd-dropdown summary:hover .sd-summary-down svg{opacity:1;transform:scale(1.1)}details.sd-dropdown .sd-summary-up svg,details.sd-dropdown .sd-summary-down svg{display:block;opacity:.6}details.sd-dropdown .sd-summary-up,details.sd-dropdown .sd-summary-down{pointer-events:none;position:absolute;right:1em;top:1em}details.sd-dropdown[open]>.sd-summary-title .sd-summary-down{visibility:hidden}details.sd-dropdown:not([open])>.sd-summary-title .sd-summary-up{visibility:hidden}details.sd-dropdown:not([open]).sd-card{border:none}details.sd-dropdown:not([open])>.sd-card-header{border:1px solid var(--sd-color-card-border);border-radius:.25rem}details.sd-dropdown.sd-fade-in[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out;animation:sd-fade-in .5s ease-in-out}details.sd-dropdown.sd-fade-in-slide-down[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out}.sd-col>.sd-dropdown{width:100%}.sd-summary-content>.sd-tab-set:first-child{margin-top:0}@keyframes sd-fade-in{0%{opacity:0}100%{opacity:1}}@keyframes sd-slide-down{0%{transform:translate(0, -10px)}100%{transform:translate(0, 0)}}.sd-tab-set{border-radius:.125rem;display:flex;flex-wrap:wrap;margin:1em 0;position:relative}.sd-tab-set>input{opacity:0;position:absolute}.sd-tab-set>input:checked+label{border-color:var(--sd-color-tabs-underline-active);color:var(--sd-color-tabs-label-active)}.sd-tab-set>input:checked+label+.sd-tab-content{display:block}.sd-tab-set>input:not(:checked)+label:hover{color:var(--sd-color-tabs-label-hover);border-color:var(--sd-color-tabs-underline-hover)}.sd-tab-set>input:focus+label{outline-style:auto}.sd-tab-set>input:not(.focus-visible)+label{outline:none;-webkit-tap-highlight-color:transparent}.sd-tab-set>label{border-bottom:.125rem solid transparent;margin-bottom:0;color:var(--sd-color-tabs-label-inactive);border-color:var(--sd-color-tabs-underline-inactive);cursor:pointer;font-size:var(--sd-fontsize-tabs-label);font-weight:700;padding:1em 1.25em .5em;transition:color 250ms;width:auto;z-index:1}html .sd-tab-set>label:hover{color:var(--sd-color-tabs-label-active)}.sd-col>.sd-tab-set{width:100%}.sd-tab-content{box-shadow:0 -0.0625rem var(--sd-color-tabs-overline),0 .0625rem var(--sd-color-tabs-underline);display:none;order:99;padding-bottom:.75rem;padding-top:.75rem;width:100%}.sd-tab-content>:first-child{margin-top:0 !important}.sd-tab-content>:last-child{margin-bottom:0 !important}.sd-tab-content>.sd-tab-set{margin:0}.sd-sphinx-override,.sd-sphinx-override *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.sd-sphinx-override p{margin-top:0}:root{--sd-color-primary: #0071bc;--sd-color-secondary: #6c757d;--sd-color-success: #28a745;--sd-color-info: #17a2b8;--sd-color-warning: #f0b37e;--sd-color-danger: #dc3545;--sd-color-light: #f8f9fa;--sd-color-muted: #6c757d;--sd-color-dark: #212529;--sd-color-black: black;--sd-color-white: white;--sd-color-primary-highlight: #0060a0;--sd-color-secondary-highlight: #5c636a;--sd-color-success-highlight: #228e3b;--sd-color-info-highlight: #148a9c;--sd-color-warning-highlight: #cc986b;--sd-color-danger-highlight: #bb2d3b;--sd-color-light-highlight: #d3d4d5;--sd-color-muted-highlight: #5c636a;--sd-color-dark-highlight: #1c1f23;--sd-color-black-highlight: black;--sd-color-white-highlight: #d9d9d9;--sd-color-primary-text: #fff;--sd-color-secondary-text: #fff;--sd-color-success-text: #fff;--sd-color-info-text: #fff;--sd-color-warning-text: #212529;--sd-color-danger-text: #fff;--sd-color-light-text: #212529;--sd-color-muted-text: #fff;--sd-color-dark-text: #fff;--sd-color-black-text: #fff;--sd-color-white-text: #212529;--sd-color-shadow: rgba(0, 0, 0, 0.15);--sd-color-card-border: rgba(0, 0, 0, 0.125);--sd-color-card-border-hover: hsla(231, 99%, 66%, 1);--sd-color-card-background: transparent;--sd-color-card-text: inherit;--sd-color-card-header: transparent;--sd-color-card-footer: transparent;--sd-color-tabs-label-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-hover: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-inactive: hsl(0, 0%, 66%);--sd-color-tabs-underline-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-underline-hover: rgba(178, 206, 245, 0.62);--sd-color-tabs-underline-inactive: transparent;--sd-color-tabs-overline: rgb(222, 222, 222);--sd-color-tabs-underline: rgb(222, 222, 222);--sd-fontsize-tabs-label: 1rem} diff --git a/_sphinx_design_static/design-tabs.js b/_sphinx_design_static/design-tabs.js new file mode 100644 index 0000000..36b38cf --- /dev/null +++ b/_sphinx_design_static/design-tabs.js @@ -0,0 +1,27 @@ +var sd_labels_by_text = {}; + +function ready() { + const li = document.getElementsByClassName("sd-tab-label"); + for (const label of li) { + syncId = label.getAttribute("data-sync-id"); + if (syncId) { + label.onclick = onLabelClick; + if (!sd_labels_by_text[syncId]) { + sd_labels_by_text[syncId] = []; + } + sd_labels_by_text[syncId].push(label); + } + } +} + +function onLabelClick() { + // Activate other inputs with the same sync id. + syncId = this.getAttribute("data-sync-id"); + for (label of sd_labels_by_text[syncId]) { + if (label === this) continue; + label.previousElementSibling.checked = true; + } + window.localStorage.setItem("sphinx-design-last-tab", syncId); +} + +document.addEventListener("DOMContentLoaded", ready, false); diff --git a/_static/_sphinx_javascript_frameworks_compat.js b/_static/_sphinx_javascript_frameworks_compat.js new file mode 100644 index 0000000..8141580 --- /dev/null +++ b/_static/_sphinx_javascript_frameworks_compat.js @@ -0,0 +1,123 @@ +/* Compatability shim for jQuery and underscores.js. + * + * Copyright Sphinx contributors + * Released under the two clause BSD licence + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.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": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 0000000..30fee9d --- /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/check-solid.svg b/_static/check-solid.svg new file mode 100644 index 0000000..92fad4b --- /dev/null +++ b/_static/check-solid.svg @@ -0,0 +1,4 @@ + + + + diff --git a/_static/clipboard.min.js b/_static/clipboard.min.js new file mode 100644 index 0000000..54b3c46 --- /dev/null +++ b/_static/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.8 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1 + + + + diff --git a/_static/copybutton.css b/_static/copybutton.css new file mode 100644 index 0000000..f1916ec --- /dev/null +++ b/_static/copybutton.css @@ -0,0 +1,94 @@ +/* Copy buttons */ +button.copybtn { + position: absolute; + display: flex; + top: .3em; + right: .3em; + width: 1.7em; + height: 1.7em; + opacity: 0; + transition: opacity 0.3s, border .3s, background-color .3s; + user-select: none; + padding: 0; + border: none; + outline: none; + border-radius: 0.4em; + /* The colors that GitHub uses */ + border: #1b1f2426 1px solid; + background-color: #f6f8fa; + color: #57606a; +} + +button.copybtn.success { + border-color: #22863a; + color: #22863a; +} + +button.copybtn svg { + stroke: currentColor; + width: 1.5em; + height: 1.5em; + padding: 0.1em; +} + +div.highlight { + position: relative; +} + +/* Show the copybutton */ +.highlight:hover button.copybtn, button.copybtn.success { + opacity: 1; +} + +.highlight button.copybtn:hover { + background-color: rgb(235, 235, 235); +} + +.highlight button.copybtn:active { + background-color: rgb(187, 187, 187); +} + +/** + * A minimal CSS-only tooltip copied from: + * https://codepen.io/mildrenben/pen/rVBrpK + * + * To use, write HTML like the following: + * + *

Short

+ */ + .o-tooltip--left { + position: relative; + } + + .o-tooltip--left:after { + opacity: 0; + visibility: hidden; + position: absolute; + content: attr(data-tooltip); + padding: .2em; + font-size: .8em; + left: -.2em; + background: grey; + color: white; + white-space: nowrap; + z-index: 2; + border-radius: 2px; + transform: translateX(-102%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); +} + +.o-tooltip--left:hover:after { + display: block; + opacity: 1; + visibility: visible; + transform: translateX(-100%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); + transition-delay: .5s; +} + +/* By default the copy button shouldn't show up when printing a page */ +@media print { + button.copybtn { + display: none; + } +} diff --git a/_static/copybutton.js b/_static/copybutton.js new file mode 100644 index 0000000..2ea7ff3 --- /dev/null +++ b/_static/copybutton.js @@ -0,0 +1,248 @@ +// Localization support +const messages = { + 'en': { + 'copy': 'Copy', + 'copy_to_clipboard': 'Copy to clipboard', + 'copy_success': 'Copied!', + 'copy_failure': 'Failed to copy', + }, + 'es' : { + 'copy': 'Copiar', + 'copy_to_clipboard': 'Copiar al portapapeles', + 'copy_success': '¡Copiado!', + 'copy_failure': 'Error al copiar', + }, + 'de' : { + 'copy': 'Kopieren', + 'copy_to_clipboard': 'In die Zwischenablage kopieren', + 'copy_success': 'Kopiert!', + 'copy_failure': 'Fehler beim Kopieren', + }, + 'fr' : { + 'copy': 'Copier', + 'copy_to_clipboard': 'Copier dans le presse-papier', + 'copy_success': 'Copié !', + 'copy_failure': 'Échec de la copie', + }, + 'ru': { + 'copy': 'Скопировать', + 'copy_to_clipboard': 'Скопировать в буфер', + 'copy_success': 'Скопировано!', + 'copy_failure': 'Не удалось скопировать', + }, + 'zh-CN': { + 'copy': '复制', + 'copy_to_clipboard': '复制到剪贴板', + 'copy_success': '复制成功!', + 'copy_failure': '复制失败', + }, + 'it' : { + 'copy': 'Copiare', + 'copy_to_clipboard': 'Copiato negli appunti', + 'copy_success': 'Copiato!', + 'copy_failure': 'Errore durante la copia', + } +} + +let locale = 'en' +if( document.documentElement.lang !== undefined + && messages[document.documentElement.lang] !== undefined ) { + locale = document.documentElement.lang +} + +let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT; +if (doc_url_root == '#') { + doc_url_root = ''; +} + +/** + * SVG files for our copy buttons + */ +let iconCheck = ` + ${messages[locale]['copy_success']} + + +` + +// If the user specified their own SVG use that, otherwise use the default +let iconCopy = ``; +if (!iconCopy) { + iconCopy = ` + ${messages[locale]['copy_to_clipboard']} + + + +` +} + +/** + * Set up copy/paste for code blocks + */ + +const runWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} + +const codeCellId = index => `codecell${index}` + +// Clears selected text since ClipboardJS will select the text when copying +const clearSelection = () => { + if (window.getSelection) { + window.getSelection().removeAllRanges() + } else if (document.selection) { + document.selection.empty() + } +} + +// Changes tooltip text for a moment, then changes it back +// We want the timeout of our `success` class to be a bit shorter than the +// tooltip and icon change, so that we can hide the icon before changing back. +var timeoutIcon = 2000; +var timeoutSuccessClass = 1500; + +const temporarilyChangeTooltip = (el, oldText, newText) => { + el.setAttribute('data-tooltip', newText) + el.classList.add('success') + // Remove success a little bit sooner than we change the tooltip + // So that we can use CSS to hide the copybutton first + setTimeout(() => el.classList.remove('success'), timeoutSuccessClass) + setTimeout(() => el.setAttribute('data-tooltip', oldText), timeoutIcon) +} + +// Changes the copy button icon for two seconds, then changes it back +const temporarilyChangeIcon = (el) => { + el.innerHTML = iconCheck; + setTimeout(() => {el.innerHTML = iconCopy}, timeoutIcon) +} + +const addCopyButtonToCodeCells = () => { + // If ClipboardJS hasn't loaded, wait a bit and try again. This + // happens because we load ClipboardJS asynchronously. + if (window.ClipboardJS === undefined) { + setTimeout(addCopyButtonToCodeCells, 250) + return + } + + // Add copybuttons to all of our code cells + const COPYBUTTON_SELECTOR = 'div.highlight pre'; + const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR) + codeCells.forEach((codeCell, index) => { + const id = codeCellId(index) + codeCell.setAttribute('id', id) + + const clipboardButton = id => + `` + codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) + }) + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} + + +var copyTargetText = (trigger) => { + var target = document.querySelector(trigger.attributes['data-clipboard-target'].value); + + // get filtered text + let exclude = '.linenos'; + + let text = filterText(target, exclude); + return formatCopyText(text, '', false, true, true, true, '', '') +} + + // Initialize with a callback so we can modify the text before copy + const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText}) + + // Update UI with error/success messages + clipboard.on('success', event => { + clearSelection() + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success']) + temporarilyChangeIcon(event.trigger) + }) + + clipboard.on('error', event => { + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure']) + }) +} + +runWhenDOMLoaded(addCopyButtonToCodeCells) \ No newline at end of file diff --git a/_static/copybutton_funcs.js b/_static/copybutton_funcs.js new file mode 100644 index 0000000..dbe1aaa --- /dev/null +++ b/_static/copybutton_funcs.js @@ -0,0 +1,73 @@ +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +export function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} diff --git a/_static/css/badge_only.css b/_static/css/badge_only.css new file mode 100644 index 0000000..c718cee --- /dev/null +++ b/_static/css/badge_only.css @@ -0,0 +1 @@ +.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/_static/css/fonts/Roboto-Slab-Bold.woff b/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 0000000..6cb6000 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/_static/css/fonts/Roboto-Slab-Bold.woff2 b/_static/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 0000000..7059e23 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/_static/css/fonts/Roboto-Slab-Regular.woff b/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 0000000..f815f63 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/_static/css/fonts/Roboto-Slab-Regular.woff2 b/_static/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 0000000..f2c76e5 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/_static/css/fonts/fontawesome-webfont.eot b/_static/css/fonts/fontawesome-webfont.eot new file mode 100644 index 0000000..e9f60ca Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.eot differ diff --git a/_static/css/fonts/fontawesome-webfont.svg b/_static/css/fonts/fontawesome-webfont.svg new file mode 100644 index 0000000..855c845 --- /dev/null +++ b/_static/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_static/css/fonts/fontawesome-webfont.ttf b/_static/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 0000000..35acda2 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.ttf differ diff --git a/_static/css/fonts/fontawesome-webfont.woff b/_static/css/fonts/fontawesome-webfont.woff new file mode 100644 index 0000000..400014a Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.woff differ diff --git a/_static/css/fonts/fontawesome-webfont.woff2 b/_static/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 0000000..4d13fc6 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.woff2 differ diff --git a/_static/css/fonts/lato-bold-italic.woff b/_static/css/fonts/lato-bold-italic.woff new file mode 100644 index 0000000..88ad05b Binary files /dev/null and b/_static/css/fonts/lato-bold-italic.woff differ diff --git a/_static/css/fonts/lato-bold-italic.woff2 b/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 0000000..c4e3d80 Binary files /dev/null and b/_static/css/fonts/lato-bold-italic.woff2 differ diff --git a/_static/css/fonts/lato-bold.woff b/_static/css/fonts/lato-bold.woff new file mode 100644 index 0000000..c6dff51 Binary files /dev/null and b/_static/css/fonts/lato-bold.woff differ diff --git a/_static/css/fonts/lato-bold.woff2 b/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 0000000..bb19504 Binary files /dev/null and b/_static/css/fonts/lato-bold.woff2 differ diff --git a/_static/css/fonts/lato-normal-italic.woff b/_static/css/fonts/lato-normal-italic.woff new file mode 100644 index 0000000..76114bc Binary files /dev/null and b/_static/css/fonts/lato-normal-italic.woff differ diff --git a/_static/css/fonts/lato-normal-italic.woff2 b/_static/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 0000000..3404f37 Binary files /dev/null and b/_static/css/fonts/lato-normal-italic.woff2 differ diff --git a/_static/css/fonts/lato-normal.woff b/_static/css/fonts/lato-normal.woff new file mode 100644 index 0000000..ae1307f Binary files /dev/null and b/_static/css/fonts/lato-normal.woff differ diff --git a/_static/css/fonts/lato-normal.woff2 b/_static/css/fonts/lato-normal.woff2 new file mode 100644 index 0000000..3bf9843 Binary files /dev/null and b/_static/css/fonts/lato-normal.woff2 differ diff --git a/_static/css/theme.css b/_static/css/theme.css new file mode 100644 index 0000000..19a446a --- /dev/null +++ b/_static/css/theme.css @@ -0,0 +1,4 @@ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel,.rst-content .menuselection{font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .guilabel,.rst-content .menuselection{border:1px solid #7fbbe3;background:#e7f2fa}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/_static/design-style.1e8bd061cd6da7fc9cf755528e8ffc24.min.css b/_static/design-style.1e8bd061cd6da7fc9cf755528e8ffc24.min.css new file mode 100644 index 0000000..eb19f69 --- /dev/null +++ b/_static/design-style.1e8bd061cd6da7fc9cf755528e8ffc24.min.css @@ -0,0 +1 @@ +.sd-bg-primary{background-color:var(--sd-color-primary) !important}.sd-bg-text-primary{color:var(--sd-color-primary-text) !important}button.sd-bg-primary:focus,button.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}a.sd-bg-primary:focus,a.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}.sd-bg-secondary{background-color:var(--sd-color-secondary) !important}.sd-bg-text-secondary{color:var(--sd-color-secondary-text) !important}button.sd-bg-secondary:focus,button.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}a.sd-bg-secondary:focus,a.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}.sd-bg-success{background-color:var(--sd-color-success) !important}.sd-bg-text-success{color:var(--sd-color-success-text) !important}button.sd-bg-success:focus,button.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}a.sd-bg-success:focus,a.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}.sd-bg-info{background-color:var(--sd-color-info) !important}.sd-bg-text-info{color:var(--sd-color-info-text) !important}button.sd-bg-info:focus,button.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}a.sd-bg-info:focus,a.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}.sd-bg-warning{background-color:var(--sd-color-warning) !important}.sd-bg-text-warning{color:var(--sd-color-warning-text) !important}button.sd-bg-warning:focus,button.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}a.sd-bg-warning:focus,a.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}.sd-bg-danger{background-color:var(--sd-color-danger) !important}.sd-bg-text-danger{color:var(--sd-color-danger-text) !important}button.sd-bg-danger:focus,button.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}a.sd-bg-danger:focus,a.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}.sd-bg-light{background-color:var(--sd-color-light) !important}.sd-bg-text-light{color:var(--sd-color-light-text) !important}button.sd-bg-light:focus,button.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}a.sd-bg-light:focus,a.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}.sd-bg-muted{background-color:var(--sd-color-muted) !important}.sd-bg-text-muted{color:var(--sd-color-muted-text) !important}button.sd-bg-muted:focus,button.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}a.sd-bg-muted:focus,a.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}.sd-bg-dark{background-color:var(--sd-color-dark) !important}.sd-bg-text-dark{color:var(--sd-color-dark-text) !important}button.sd-bg-dark:focus,button.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}a.sd-bg-dark:focus,a.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}.sd-bg-black{background-color:var(--sd-color-black) !important}.sd-bg-text-black{color:var(--sd-color-black-text) !important}button.sd-bg-black:focus,button.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}a.sd-bg-black:focus,a.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}.sd-bg-white{background-color:var(--sd-color-white) !important}.sd-bg-text-white{color:var(--sd-color-white-text) !important}button.sd-bg-white:focus,button.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}a.sd-bg-white:focus,a.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}.sd-text-primary,.sd-text-primary>p{color:var(--sd-color-primary) !important}a.sd-text-primary:focus,a.sd-text-primary:hover{color:var(--sd-color-primary-highlight) !important}.sd-text-secondary,.sd-text-secondary>p{color:var(--sd-color-secondary) !important}a.sd-text-secondary:focus,a.sd-text-secondary:hover{color:var(--sd-color-secondary-highlight) !important}.sd-text-success,.sd-text-success>p{color:var(--sd-color-success) !important}a.sd-text-success:focus,a.sd-text-success:hover{color:var(--sd-color-success-highlight) !important}.sd-text-info,.sd-text-info>p{color:var(--sd-color-info) !important}a.sd-text-info:focus,a.sd-text-info:hover{color:var(--sd-color-info-highlight) !important}.sd-text-warning,.sd-text-warning>p{color:var(--sd-color-warning) !important}a.sd-text-warning:focus,a.sd-text-warning:hover{color:var(--sd-color-warning-highlight) !important}.sd-text-danger,.sd-text-danger>p{color:var(--sd-color-danger) !important}a.sd-text-danger:focus,a.sd-text-danger:hover{color:var(--sd-color-danger-highlight) !important}.sd-text-light,.sd-text-light>p{color:var(--sd-color-light) !important}a.sd-text-light:focus,a.sd-text-light:hover{color:var(--sd-color-light-highlight) !important}.sd-text-muted,.sd-text-muted>p{color:var(--sd-color-muted) !important}a.sd-text-muted:focus,a.sd-text-muted:hover{color:var(--sd-color-muted-highlight) !important}.sd-text-dark,.sd-text-dark>p{color:var(--sd-color-dark) !important}a.sd-text-dark:focus,a.sd-text-dark:hover{color:var(--sd-color-dark-highlight) !important}.sd-text-black,.sd-text-black>p{color:var(--sd-color-black) !important}a.sd-text-black:focus,a.sd-text-black:hover{color:var(--sd-color-black-highlight) !important}.sd-text-white,.sd-text-white>p{color:var(--sd-color-white) !important}a.sd-text-white:focus,a.sd-text-white:hover{color:var(--sd-color-white-highlight) !important}.sd-outline-primary{border-color:var(--sd-color-primary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-primary:focus,a.sd-outline-primary:hover{border-color:var(--sd-color-primary-highlight) !important}.sd-outline-secondary{border-color:var(--sd-color-secondary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-secondary:focus,a.sd-outline-secondary:hover{border-color:var(--sd-color-secondary-highlight) !important}.sd-outline-success{border-color:var(--sd-color-success) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-success:focus,a.sd-outline-success:hover{border-color:var(--sd-color-success-highlight) !important}.sd-outline-info{border-color:var(--sd-color-info) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-info:focus,a.sd-outline-info:hover{border-color:var(--sd-color-info-highlight) !important}.sd-outline-warning{border-color:var(--sd-color-warning) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-warning:focus,a.sd-outline-warning:hover{border-color:var(--sd-color-warning-highlight) !important}.sd-outline-danger{border-color:var(--sd-color-danger) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-danger:focus,a.sd-outline-danger:hover{border-color:var(--sd-color-danger-highlight) !important}.sd-outline-light{border-color:var(--sd-color-light) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-light:focus,a.sd-outline-light:hover{border-color:var(--sd-color-light-highlight) !important}.sd-outline-muted{border-color:var(--sd-color-muted) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-muted:focus,a.sd-outline-muted:hover{border-color:var(--sd-color-muted-highlight) !important}.sd-outline-dark{border-color:var(--sd-color-dark) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-dark:focus,a.sd-outline-dark:hover{border-color:var(--sd-color-dark-highlight) !important}.sd-outline-black{border-color:var(--sd-color-black) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-black:focus,a.sd-outline-black:hover{border-color:var(--sd-color-black-highlight) !important}.sd-outline-white{border-color:var(--sd-color-white) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-white:focus,a.sd-outline-white:hover{border-color:var(--sd-color-white-highlight) !important}.sd-bg-transparent{background-color:transparent !important}.sd-outline-transparent{border-color:transparent !important}.sd-text-transparent{color:transparent !important}.sd-p-0{padding:0 !important}.sd-pt-0,.sd-py-0{padding-top:0 !important}.sd-pr-0,.sd-px-0{padding-right:0 !important}.sd-pb-0,.sd-py-0{padding-bottom:0 !important}.sd-pl-0,.sd-px-0{padding-left:0 !important}.sd-p-1{padding:.25rem !important}.sd-pt-1,.sd-py-1{padding-top:.25rem !important}.sd-pr-1,.sd-px-1{padding-right:.25rem !important}.sd-pb-1,.sd-py-1{padding-bottom:.25rem !important}.sd-pl-1,.sd-px-1{padding-left:.25rem !important}.sd-p-2{padding:.5rem !important}.sd-pt-2,.sd-py-2{padding-top:.5rem !important}.sd-pr-2,.sd-px-2{padding-right:.5rem !important}.sd-pb-2,.sd-py-2{padding-bottom:.5rem !important}.sd-pl-2,.sd-px-2{padding-left:.5rem !important}.sd-p-3{padding:1rem !important}.sd-pt-3,.sd-py-3{padding-top:1rem !important}.sd-pr-3,.sd-px-3{padding-right:1rem !important}.sd-pb-3,.sd-py-3{padding-bottom:1rem !important}.sd-pl-3,.sd-px-3{padding-left:1rem !important}.sd-p-4{padding:1.5rem !important}.sd-pt-4,.sd-py-4{padding-top:1.5rem !important}.sd-pr-4,.sd-px-4{padding-right:1.5rem !important}.sd-pb-4,.sd-py-4{padding-bottom:1.5rem !important}.sd-pl-4,.sd-px-4{padding-left:1.5rem !important}.sd-p-5{padding:3rem !important}.sd-pt-5,.sd-py-5{padding-top:3rem !important}.sd-pr-5,.sd-px-5{padding-right:3rem !important}.sd-pb-5,.sd-py-5{padding-bottom:3rem !important}.sd-pl-5,.sd-px-5{padding-left:3rem !important}.sd-m-auto{margin:auto !important}.sd-mt-auto,.sd-my-auto{margin-top:auto !important}.sd-mr-auto,.sd-mx-auto{margin-right:auto !important}.sd-mb-auto,.sd-my-auto{margin-bottom:auto !important}.sd-ml-auto,.sd-mx-auto{margin-left:auto !important}.sd-m-0{margin:0 !important}.sd-mt-0,.sd-my-0{margin-top:0 !important}.sd-mr-0,.sd-mx-0{margin-right:0 !important}.sd-mb-0,.sd-my-0{margin-bottom:0 !important}.sd-ml-0,.sd-mx-0{margin-left:0 !important}.sd-m-1{margin:.25rem !important}.sd-mt-1,.sd-my-1{margin-top:.25rem !important}.sd-mr-1,.sd-mx-1{margin-right:.25rem !important}.sd-mb-1,.sd-my-1{margin-bottom:.25rem !important}.sd-ml-1,.sd-mx-1{margin-left:.25rem !important}.sd-m-2{margin:.5rem !important}.sd-mt-2,.sd-my-2{margin-top:.5rem !important}.sd-mr-2,.sd-mx-2{margin-right:.5rem !important}.sd-mb-2,.sd-my-2{margin-bottom:.5rem !important}.sd-ml-2,.sd-mx-2{margin-left:.5rem !important}.sd-m-3{margin:1rem !important}.sd-mt-3,.sd-my-3{margin-top:1rem !important}.sd-mr-3,.sd-mx-3{margin-right:1rem !important}.sd-mb-3,.sd-my-3{margin-bottom:1rem !important}.sd-ml-3,.sd-mx-3{margin-left:1rem !important}.sd-m-4{margin:1.5rem !important}.sd-mt-4,.sd-my-4{margin-top:1.5rem !important}.sd-mr-4,.sd-mx-4{margin-right:1.5rem !important}.sd-mb-4,.sd-my-4{margin-bottom:1.5rem !important}.sd-ml-4,.sd-mx-4{margin-left:1.5rem !important}.sd-m-5{margin:3rem !important}.sd-mt-5,.sd-my-5{margin-top:3rem !important}.sd-mr-5,.sd-mx-5{margin-right:3rem !important}.sd-mb-5,.sd-my-5{margin-bottom:3rem !important}.sd-ml-5,.sd-mx-5{margin-left:3rem !important}.sd-w-25{width:25% !important}.sd-w-50{width:50% !important}.sd-w-75{width:75% !important}.sd-w-100{width:100% !important}.sd-w-auto{width:auto !important}.sd-h-25{height:25% !important}.sd-h-50{height:50% !important}.sd-h-75{height:75% !important}.sd-h-100{height:100% !important}.sd-h-auto{height:auto !important}.sd-d-none{display:none !important}.sd-d-inline{display:inline !important}.sd-d-inline-block{display:inline-block !important}.sd-d-block{display:block !important}.sd-d-grid{display:grid !important}.sd-d-flex-row{display:-ms-flexbox !important;display:flex !important;flex-direction:row !important}.sd-d-flex-column{display:-ms-flexbox !important;display:flex !important;flex-direction:column !important}.sd-d-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}@media(min-width: 576px){.sd-d-sm-none{display:none !important}.sd-d-sm-inline{display:inline !important}.sd-d-sm-inline-block{display:inline-block !important}.sd-d-sm-block{display:block !important}.sd-d-sm-grid{display:grid !important}.sd-d-sm-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-sm-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 768px){.sd-d-md-none{display:none !important}.sd-d-md-inline{display:inline !important}.sd-d-md-inline-block{display:inline-block !important}.sd-d-md-block{display:block !important}.sd-d-md-grid{display:grid !important}.sd-d-md-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-md-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 992px){.sd-d-lg-none{display:none !important}.sd-d-lg-inline{display:inline !important}.sd-d-lg-inline-block{display:inline-block !important}.sd-d-lg-block{display:block !important}.sd-d-lg-grid{display:grid !important}.sd-d-lg-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-lg-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 1200px){.sd-d-xl-none{display:none !important}.sd-d-xl-inline{display:inline !important}.sd-d-xl-inline-block{display:inline-block !important}.sd-d-xl-block{display:block !important}.sd-d-xl-grid{display:grid !important}.sd-d-xl-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-xl-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}.sd-align-major-start{justify-content:flex-start !important}.sd-align-major-end{justify-content:flex-end !important}.sd-align-major-center{justify-content:center !important}.sd-align-major-justify{justify-content:space-between !important}.sd-align-major-spaced{justify-content:space-evenly !important}.sd-align-minor-start{align-items:flex-start !important}.sd-align-minor-end{align-items:flex-end !important}.sd-align-minor-center{align-items:center !important}.sd-align-minor-stretch{align-items:stretch !important}.sd-text-justify{text-align:justify !important}.sd-text-left{text-align:left !important}.sd-text-right{text-align:right !important}.sd-text-center{text-align:center !important}.sd-font-weight-light{font-weight:300 !important}.sd-font-weight-lighter{font-weight:lighter !important}.sd-font-weight-normal{font-weight:400 !important}.sd-font-weight-bold{font-weight:700 !important}.sd-font-weight-bolder{font-weight:bolder !important}.sd-font-italic{font-style:italic !important}.sd-text-decoration-none{text-decoration:none !important}.sd-text-lowercase{text-transform:lowercase !important}.sd-text-uppercase{text-transform:uppercase !important}.sd-text-capitalize{text-transform:capitalize !important}.sd-text-wrap{white-space:normal !important}.sd-text-nowrap{white-space:nowrap !important}.sd-text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sd-fs-1,.sd-fs-1>p{font-size:calc(1.375rem + 1.5vw) !important;line-height:unset !important}.sd-fs-2,.sd-fs-2>p{font-size:calc(1.325rem + 0.9vw) !important;line-height:unset !important}.sd-fs-3,.sd-fs-3>p{font-size:calc(1.3rem + 0.6vw) !important;line-height:unset !important}.sd-fs-4,.sd-fs-4>p{font-size:calc(1.275rem + 0.3vw) !important;line-height:unset !important}.sd-fs-5,.sd-fs-5>p{font-size:1.25rem !important;line-height:unset !important}.sd-fs-6,.sd-fs-6>p{font-size:1rem !important;line-height:unset !important}.sd-border-0{border:0 solid !important}.sd-border-top-0{border-top:0 solid !important}.sd-border-bottom-0{border-bottom:0 solid !important}.sd-border-right-0{border-right:0 solid !important}.sd-border-left-0{border-left:0 solid !important}.sd-border-1{border:1px solid !important}.sd-border-top-1{border-top:1px solid !important}.sd-border-bottom-1{border-bottom:1px solid !important}.sd-border-right-1{border-right:1px solid !important}.sd-border-left-1{border-left:1px solid !important}.sd-border-2{border:2px solid !important}.sd-border-top-2{border-top:2px solid !important}.sd-border-bottom-2{border-bottom:2px solid !important}.sd-border-right-2{border-right:2px solid !important}.sd-border-left-2{border-left:2px solid !important}.sd-border-3{border:3px solid !important}.sd-border-top-3{border-top:3px solid !important}.sd-border-bottom-3{border-bottom:3px solid !important}.sd-border-right-3{border-right:3px solid !important}.sd-border-left-3{border-left:3px solid !important}.sd-border-4{border:4px solid !important}.sd-border-top-4{border-top:4px solid !important}.sd-border-bottom-4{border-bottom:4px solid !important}.sd-border-right-4{border-right:4px solid !important}.sd-border-left-4{border-left:4px solid !important}.sd-border-5{border:5px solid !important}.sd-border-top-5{border-top:5px solid !important}.sd-border-bottom-5{border-bottom:5px solid !important}.sd-border-right-5{border-right:5px solid !important}.sd-border-left-5{border-left:5px solid !important}.sd-rounded-0{border-radius:0 !important}.sd-rounded-1{border-radius:.2rem !important}.sd-rounded-2{border-radius:.3rem !important}.sd-rounded-3{border-radius:.5rem !important}.sd-rounded-pill{border-radius:50rem !important}.sd-rounded-circle{border-radius:50% !important}.shadow-none{box-shadow:none !important}.sd-shadow-sm{box-shadow:0 .125rem .25rem var(--sd-color-shadow) !important}.sd-shadow-md{box-shadow:0 .5rem 1rem var(--sd-color-shadow) !important}.sd-shadow-lg{box-shadow:0 1rem 3rem var(--sd-color-shadow) !important}@keyframes sd-slide-from-left{0%{transform:translateX(-100%)}100%{transform:translateX(0)}}@keyframes sd-slide-from-right{0%{transform:translateX(200%)}100%{transform:translateX(0)}}@keyframes sd-grow100{0%{transform:scale(0);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50{0%{transform:scale(0.5);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50-rot20{0%{transform:scale(0.5) rotateZ(-20deg);opacity:.5}75%{transform:scale(1) rotateZ(5deg);opacity:1}95%{transform:scale(1) rotateZ(-1deg);opacity:1}100%{transform:scale(1) rotateZ(0);opacity:1}}.sd-animate-slide-from-left{animation:1s ease-out 0s 1 normal none running sd-slide-from-left}.sd-animate-slide-from-right{animation:1s ease-out 0s 1 normal none running sd-slide-from-right}.sd-animate-grow100{animation:1s ease-out 0s 1 normal none running sd-grow100}.sd-animate-grow50{animation:1s ease-out 0s 1 normal none running sd-grow50}.sd-animate-grow50-rot20{animation:1s ease-out 0s 1 normal none running sd-grow50-rot20}.sd-badge{display:inline-block;padding:.35em .65em;font-size:.75em;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.sd-badge:empty{display:none}a.sd-badge{text-decoration:none}.sd-btn .sd-badge{position:relative;top:-1px}.sd-btn{background-color:transparent;border:1px solid transparent;border-radius:.25rem;cursor:pointer;display:inline-block;font-weight:400;font-size:1rem;line-height:1.5;padding:.375rem .75rem;text-align:center;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;vertical-align:middle;user-select:none;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none}.sd-btn:hover{text-decoration:none}@media(prefers-reduced-motion: reduce){.sd-btn{transition:none}}.sd-btn-primary,.sd-btn-outline-primary:hover,.sd-btn-outline-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-primary:hover,.sd-btn-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary-highlight) !important;border-color:var(--sd-color-primary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-primary{color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary,.sd-btn-outline-secondary:hover,.sd-btn-outline-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary:hover,.sd-btn-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary-highlight) !important;border-color:var(--sd-color-secondary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-secondary{color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success,.sd-btn-outline-success:hover,.sd-btn-outline-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success:hover,.sd-btn-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success-highlight) !important;border-color:var(--sd-color-success-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-success{color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info,.sd-btn-outline-info:hover,.sd-btn-outline-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info:hover,.sd-btn-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info-highlight) !important;border-color:var(--sd-color-info-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-info{color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning,.sd-btn-outline-warning:hover,.sd-btn-outline-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning:hover,.sd-btn-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning-highlight) !important;border-color:var(--sd-color-warning-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-warning{color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger,.sd-btn-outline-danger:hover,.sd-btn-outline-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger:hover,.sd-btn-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger-highlight) !important;border-color:var(--sd-color-danger-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-danger{color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light,.sd-btn-outline-light:hover,.sd-btn-outline-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light:hover,.sd-btn-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light-highlight) !important;border-color:var(--sd-color-light-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-light{color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted,.sd-btn-outline-muted:hover,.sd-btn-outline-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted:hover,.sd-btn-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted-highlight) !important;border-color:var(--sd-color-muted-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-muted{color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark,.sd-btn-outline-dark:hover,.sd-btn-outline-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark:hover,.sd-btn-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark-highlight) !important;border-color:var(--sd-color-dark-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-dark{color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black,.sd-btn-outline-black:hover,.sd-btn-outline-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black:hover,.sd-btn-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black-highlight) !important;border-color:var(--sd-color-black-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-black{color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white,.sd-btn-outline-white:hover,.sd-btn-outline-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white:hover,.sd-btn-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white-highlight) !important;border-color:var(--sd-color-white-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-white{color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.sd-hide-link-text{font-size:0}.sd-octicon,.sd-material-icon{display:inline-block;fill:currentColor;vertical-align:middle}.sd-avatar-xs{border-radius:50%;object-fit:cover;object-position:center;width:1rem;height:1rem}.sd-avatar-sm{border-radius:50%;object-fit:cover;object-position:center;width:3rem;height:3rem}.sd-avatar-md{border-radius:50%;object-fit:cover;object-position:center;width:5rem;height:5rem}.sd-avatar-lg{border-radius:50%;object-fit:cover;object-position:center;width:7rem;height:7rem}.sd-avatar-xl{border-radius:50%;object-fit:cover;object-position:center;width:10rem;height:10rem}.sd-avatar-inherit{border-radius:50%;object-fit:cover;object-position:center;width:inherit;height:inherit}.sd-avatar-initial{border-radius:50%;object-fit:cover;object-position:center;width:initial;height:initial}.sd-card{background-clip:border-box;background-color:var(--sd-color-card-background);border:1px solid var(--sd-color-card-border);border-radius:.25rem;color:var(--sd-color-card-text);display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;position:relative;word-wrap:break-word}.sd-card>hr{margin-left:0;margin-right:0}.sd-card-hover:hover{border-color:var(--sd-color-card-border-hover);transform:scale(1.01)}.sd-card-body{-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem 1rem}.sd-card-title{margin-bottom:.5rem}.sd-card-subtitle{margin-top:-0.25rem;margin-bottom:0}.sd-card-text:last-child{margin-bottom:0}.sd-card-link:hover{text-decoration:none}.sd-card-link+.card-link{margin-left:1rem}.sd-card-header{padding:.5rem 1rem;margin-bottom:0;background-color:var(--sd-color-card-header);border-bottom:1px solid var(--sd-color-card-border)}.sd-card-header:first-child{border-radius:calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0}.sd-card-footer{padding:.5rem 1rem;background-color:var(--sd-color-card-footer);border-top:1px solid var(--sd-color-card-border)}.sd-card-footer:last-child{border-radius:0 0 calc(0.25rem - 1px) calc(0.25rem - 1px)}.sd-card-header-tabs{margin-right:-0.5rem;margin-bottom:-0.5rem;margin-left:-0.5rem;border-bottom:0}.sd-card-header-pills{margin-right:-0.5rem;margin-left:-0.5rem}.sd-card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom,.sd-card-img-top{width:100%}.sd-card-img,.sd-card-img-top{border-top-left-radius:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom{border-bottom-left-radius:calc(0.25rem - 1px);border-bottom-right-radius:calc(0.25rem - 1px)}.sd-cards-carousel{width:100%;display:flex;flex-wrap:nowrap;-ms-flex-direction:row;flex-direction:row;overflow-x:hidden;scroll-snap-type:x mandatory}.sd-cards-carousel.sd-show-scrollbar{overflow-x:auto}.sd-cards-carousel:hover,.sd-cards-carousel:focus{overflow-x:auto}.sd-cards-carousel>.sd-card{flex-shrink:0;scroll-snap-align:start}.sd-cards-carousel>.sd-card:not(:last-child){margin-right:3px}.sd-card-cols-1>.sd-card{width:90%}.sd-card-cols-2>.sd-card{width:45%}.sd-card-cols-3>.sd-card{width:30%}.sd-card-cols-4>.sd-card{width:22.5%}.sd-card-cols-5>.sd-card{width:18%}.sd-card-cols-6>.sd-card{width:15%}.sd-card-cols-7>.sd-card{width:12.8571428571%}.sd-card-cols-8>.sd-card{width:11.25%}.sd-card-cols-9>.sd-card{width:10%}.sd-card-cols-10>.sd-card{width:9%}.sd-card-cols-11>.sd-card{width:8.1818181818%}.sd-card-cols-12>.sd-card{width:7.5%}.sd-container,.sd-container-fluid,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container-xl{margin-left:auto;margin-right:auto;padding-left:var(--sd-gutter-x, 0.75rem);padding-right:var(--sd-gutter-x, 0.75rem);width:100%}@media(min-width: 576px){.sd-container-sm,.sd-container{max-width:540px}}@media(min-width: 768px){.sd-container-md,.sd-container-sm,.sd-container{max-width:720px}}@media(min-width: 992px){.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:960px}}@media(min-width: 1200px){.sd-container-xl,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:1140px}}.sd-row{--sd-gutter-x: 1.5rem;--sd-gutter-y: 0;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-top:calc(var(--sd-gutter-y) * -1);margin-right:calc(var(--sd-gutter-x) * -0.5);margin-left:calc(var(--sd-gutter-x) * -0.5)}.sd-row>*{box-sizing:border-box;flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--sd-gutter-x) * 0.5);padding-left:calc(var(--sd-gutter-x) * 0.5);margin-top:var(--sd-gutter-y)}.sd-col{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-auto>*{flex:0 0 auto;width:auto}.sd-row-cols-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}@media(min-width: 576px){.sd-col-sm{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-sm-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-sm-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-sm-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-sm-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-sm-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-sm-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-sm-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-sm-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-sm-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-sm-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-sm-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-sm-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-sm-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 768px){.sd-col-md{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-md-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-md-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-md-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-md-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-md-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-md-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-md-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-md-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-md-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-md-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-md-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-md-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-md-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 992px){.sd-col-lg{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-lg-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-lg-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-lg-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-lg-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-lg-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-lg-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-lg-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-lg-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-lg-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-lg-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-lg-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-lg-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-lg-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 1200px){.sd-col-xl{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-xl-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-xl-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-xl-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-xl-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-xl-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-xl-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-xl-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-xl-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-xl-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-xl-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-xl-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-xl-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-xl-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}.sd-col-auto{flex:0 0 auto;-ms-flex:0 0 auto;width:auto}.sd-col-1{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}.sd-col-2{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-col-3{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-col-4{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-col-5{flex:0 0 auto;-ms-flex:0 0 auto;width:41.6666666667%}.sd-col-6{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-col-7{flex:0 0 auto;-ms-flex:0 0 auto;width:58.3333333333%}.sd-col-8{flex:0 0 auto;-ms-flex:0 0 auto;width:66.6666666667%}.sd-col-9{flex:0 0 auto;-ms-flex:0 0 auto;width:75%}.sd-col-10{flex:0 0 auto;-ms-flex:0 0 auto;width:83.3333333333%}.sd-col-11{flex:0 0 auto;-ms-flex:0 0 auto;width:91.6666666667%}.sd-col-12{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-g-0,.sd-gy-0{--sd-gutter-y: 0}.sd-g-0,.sd-gx-0{--sd-gutter-x: 0}.sd-g-1,.sd-gy-1{--sd-gutter-y: 0.25rem}.sd-g-1,.sd-gx-1{--sd-gutter-x: 0.25rem}.sd-g-2,.sd-gy-2{--sd-gutter-y: 0.5rem}.sd-g-2,.sd-gx-2{--sd-gutter-x: 0.5rem}.sd-g-3,.sd-gy-3{--sd-gutter-y: 1rem}.sd-g-3,.sd-gx-3{--sd-gutter-x: 1rem}.sd-g-4,.sd-gy-4{--sd-gutter-y: 1.5rem}.sd-g-4,.sd-gx-4{--sd-gutter-x: 1.5rem}.sd-g-5,.sd-gy-5{--sd-gutter-y: 3rem}.sd-g-5,.sd-gx-5{--sd-gutter-x: 3rem}@media(min-width: 576px){.sd-col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-sm-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-sm-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-sm-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-sm-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-sm-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-sm-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-sm-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-sm-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-sm-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-sm-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-sm-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-sm-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-sm-0,.sd-gy-sm-0{--sd-gutter-y: 0}.sd-g-sm-0,.sd-gx-sm-0{--sd-gutter-x: 0}.sd-g-sm-1,.sd-gy-sm-1{--sd-gutter-y: 0.25rem}.sd-g-sm-1,.sd-gx-sm-1{--sd-gutter-x: 0.25rem}.sd-g-sm-2,.sd-gy-sm-2{--sd-gutter-y: 0.5rem}.sd-g-sm-2,.sd-gx-sm-2{--sd-gutter-x: 0.5rem}.sd-g-sm-3,.sd-gy-sm-3{--sd-gutter-y: 1rem}.sd-g-sm-3,.sd-gx-sm-3{--sd-gutter-x: 1rem}.sd-g-sm-4,.sd-gy-sm-4{--sd-gutter-y: 1.5rem}.sd-g-sm-4,.sd-gx-sm-4{--sd-gutter-x: 1.5rem}.sd-g-sm-5,.sd-gy-sm-5{--sd-gutter-y: 3rem}.sd-g-sm-5,.sd-gx-sm-5{--sd-gutter-x: 3rem}}@media(min-width: 768px){.sd-col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-md-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-md-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-md-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-md-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-md-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-md-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-md-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-md-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-md-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-md-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-md-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-md-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-md-0,.sd-gy-md-0{--sd-gutter-y: 0}.sd-g-md-0,.sd-gx-md-0{--sd-gutter-x: 0}.sd-g-md-1,.sd-gy-md-1{--sd-gutter-y: 0.25rem}.sd-g-md-1,.sd-gx-md-1{--sd-gutter-x: 0.25rem}.sd-g-md-2,.sd-gy-md-2{--sd-gutter-y: 0.5rem}.sd-g-md-2,.sd-gx-md-2{--sd-gutter-x: 0.5rem}.sd-g-md-3,.sd-gy-md-3{--sd-gutter-y: 1rem}.sd-g-md-3,.sd-gx-md-3{--sd-gutter-x: 1rem}.sd-g-md-4,.sd-gy-md-4{--sd-gutter-y: 1.5rem}.sd-g-md-4,.sd-gx-md-4{--sd-gutter-x: 1.5rem}.sd-g-md-5,.sd-gy-md-5{--sd-gutter-y: 3rem}.sd-g-md-5,.sd-gx-md-5{--sd-gutter-x: 3rem}}@media(min-width: 992px){.sd-col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-lg-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-lg-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-lg-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-lg-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-lg-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-lg-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-lg-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-lg-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-lg-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-lg-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-lg-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-lg-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-lg-0,.sd-gy-lg-0{--sd-gutter-y: 0}.sd-g-lg-0,.sd-gx-lg-0{--sd-gutter-x: 0}.sd-g-lg-1,.sd-gy-lg-1{--sd-gutter-y: 0.25rem}.sd-g-lg-1,.sd-gx-lg-1{--sd-gutter-x: 0.25rem}.sd-g-lg-2,.sd-gy-lg-2{--sd-gutter-y: 0.5rem}.sd-g-lg-2,.sd-gx-lg-2{--sd-gutter-x: 0.5rem}.sd-g-lg-3,.sd-gy-lg-3{--sd-gutter-y: 1rem}.sd-g-lg-3,.sd-gx-lg-3{--sd-gutter-x: 1rem}.sd-g-lg-4,.sd-gy-lg-4{--sd-gutter-y: 1.5rem}.sd-g-lg-4,.sd-gx-lg-4{--sd-gutter-x: 1.5rem}.sd-g-lg-5,.sd-gy-lg-5{--sd-gutter-y: 3rem}.sd-g-lg-5,.sd-gx-lg-5{--sd-gutter-x: 3rem}}@media(min-width: 1200px){.sd-col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-xl-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-xl-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-xl-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-xl-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-xl-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-xl-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-xl-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-xl-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-xl-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-xl-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-xl-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-xl-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-xl-0,.sd-gy-xl-0{--sd-gutter-y: 0}.sd-g-xl-0,.sd-gx-xl-0{--sd-gutter-x: 0}.sd-g-xl-1,.sd-gy-xl-1{--sd-gutter-y: 0.25rem}.sd-g-xl-1,.sd-gx-xl-1{--sd-gutter-x: 0.25rem}.sd-g-xl-2,.sd-gy-xl-2{--sd-gutter-y: 0.5rem}.sd-g-xl-2,.sd-gx-xl-2{--sd-gutter-x: 0.5rem}.sd-g-xl-3,.sd-gy-xl-3{--sd-gutter-y: 1rem}.sd-g-xl-3,.sd-gx-xl-3{--sd-gutter-x: 1rem}.sd-g-xl-4,.sd-gy-xl-4{--sd-gutter-y: 1.5rem}.sd-g-xl-4,.sd-gx-xl-4{--sd-gutter-x: 1.5rem}.sd-g-xl-5,.sd-gy-xl-5{--sd-gutter-y: 3rem}.sd-g-xl-5,.sd-gx-xl-5{--sd-gutter-x: 3rem}}.sd-flex-row-reverse{flex-direction:row-reverse !important}details.sd-dropdown{position:relative}details.sd-dropdown .sd-summary-title{font-weight:700;padding-right:3em !important;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none}details.sd-dropdown:hover{cursor:pointer}details.sd-dropdown .sd-summary-content{cursor:default}details.sd-dropdown summary{list-style:none;padding:1em}details.sd-dropdown summary .sd-octicon.no-title{vertical-align:middle}details.sd-dropdown[open] summary .sd-octicon.no-title{visibility:hidden}details.sd-dropdown summary::-webkit-details-marker{display:none}details.sd-dropdown summary:focus{outline:none}details.sd-dropdown .sd-summary-icon{margin-right:.5em}details.sd-dropdown .sd-summary-icon svg{opacity:.8}details.sd-dropdown summary:hover .sd-summary-up svg,details.sd-dropdown summary:hover .sd-summary-down svg{opacity:1;transform:scale(1.1)}details.sd-dropdown .sd-summary-up svg,details.sd-dropdown .sd-summary-down svg{display:block;opacity:.6}details.sd-dropdown .sd-summary-up,details.sd-dropdown .sd-summary-down{pointer-events:none;position:absolute;right:1em;top:1em}details.sd-dropdown[open]>.sd-summary-title .sd-summary-down{visibility:hidden}details.sd-dropdown:not([open])>.sd-summary-title .sd-summary-up{visibility:hidden}details.sd-dropdown:not([open]).sd-card{border:none}details.sd-dropdown:not([open])>.sd-card-header{border:1px solid var(--sd-color-card-border);border-radius:.25rem}details.sd-dropdown.sd-fade-in[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out;animation:sd-fade-in .5s ease-in-out}details.sd-dropdown.sd-fade-in-slide-down[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out}.sd-col>.sd-dropdown{width:100%}.sd-summary-content>.sd-tab-set:first-child{margin-top:0}@keyframes sd-fade-in{0%{opacity:0}100%{opacity:1}}@keyframes sd-slide-down{0%{transform:translate(0, -10px)}100%{transform:translate(0, 0)}}.sd-tab-set{border-radius:.125rem;display:flex;flex-wrap:wrap;margin:1em 0;position:relative}.sd-tab-set>input{opacity:0;position:absolute}.sd-tab-set>input:checked+label{border-color:var(--sd-color-tabs-underline-active);color:var(--sd-color-tabs-label-active)}.sd-tab-set>input:checked+label+.sd-tab-content{display:block}.sd-tab-set>input:not(:checked)+label:hover{color:var(--sd-color-tabs-label-hover);border-color:var(--sd-color-tabs-underline-hover)}.sd-tab-set>input:focus+label{outline-style:auto}.sd-tab-set>input:not(.focus-visible)+label{outline:none;-webkit-tap-highlight-color:transparent}.sd-tab-set>label{border-bottom:.125rem solid transparent;margin-bottom:0;color:var(--sd-color-tabs-label-inactive);border-color:var(--sd-color-tabs-underline-inactive);cursor:pointer;font-size:var(--sd-fontsize-tabs-label);font-weight:700;padding:1em 1.25em .5em;transition:color 250ms;width:auto;z-index:1}html .sd-tab-set>label:hover{color:var(--sd-color-tabs-label-active)}.sd-col>.sd-tab-set{width:100%}.sd-tab-content{box-shadow:0 -0.0625rem var(--sd-color-tabs-overline),0 .0625rem var(--sd-color-tabs-underline);display:none;order:99;padding-bottom:.75rem;padding-top:.75rem;width:100%}.sd-tab-content>:first-child{margin-top:0 !important}.sd-tab-content>:last-child{margin-bottom:0 !important}.sd-tab-content>.sd-tab-set{margin:0}.sd-sphinx-override,.sd-sphinx-override *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.sd-sphinx-override p{margin-top:0}:root{--sd-color-primary: #0071bc;--sd-color-secondary: #6c757d;--sd-color-success: #28a745;--sd-color-info: #17a2b8;--sd-color-warning: #f0b37e;--sd-color-danger: #dc3545;--sd-color-light: #f8f9fa;--sd-color-muted: #6c757d;--sd-color-dark: #212529;--sd-color-black: black;--sd-color-white: white;--sd-color-primary-highlight: #0060a0;--sd-color-secondary-highlight: #5c636a;--sd-color-success-highlight: #228e3b;--sd-color-info-highlight: #148a9c;--sd-color-warning-highlight: #cc986b;--sd-color-danger-highlight: #bb2d3b;--sd-color-light-highlight: #d3d4d5;--sd-color-muted-highlight: #5c636a;--sd-color-dark-highlight: #1c1f23;--sd-color-black-highlight: black;--sd-color-white-highlight: #d9d9d9;--sd-color-primary-text: #fff;--sd-color-secondary-text: #fff;--sd-color-success-text: #fff;--sd-color-info-text: #fff;--sd-color-warning-text: #212529;--sd-color-danger-text: #fff;--sd-color-light-text: #212529;--sd-color-muted-text: #fff;--sd-color-dark-text: #fff;--sd-color-black-text: #fff;--sd-color-white-text: #212529;--sd-color-shadow: rgba(0, 0, 0, 0.15);--sd-color-card-border: rgba(0, 0, 0, 0.125);--sd-color-card-border-hover: hsla(231, 99%, 66%, 1);--sd-color-card-background: transparent;--sd-color-card-text: inherit;--sd-color-card-header: transparent;--sd-color-card-footer: transparent;--sd-color-tabs-label-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-hover: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-inactive: hsl(0, 0%, 66%);--sd-color-tabs-underline-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-underline-hover: rgba(178, 206, 245, 0.62);--sd-color-tabs-underline-inactive: transparent;--sd-color-tabs-overline: rgb(222, 222, 222);--sd-color-tabs-underline: rgb(222, 222, 222);--sd-fontsize-tabs-label: 1rem} diff --git a/_static/design-tabs.js b/_static/design-tabs.js new file mode 100644 index 0000000..36b38cf --- /dev/null +++ b/_static/design-tabs.js @@ -0,0 +1,27 @@ +var sd_labels_by_text = {}; + +function ready() { + const li = document.getElementsByClassName("sd-tab-label"); + for (const label of li) { + syncId = label.getAttribute("data-sync-id"); + if (syncId) { + label.onclick = onLabelClick; + if (!sd_labels_by_text[syncId]) { + sd_labels_by_text[syncId] = []; + } + sd_labels_by_text[syncId].push(label); + } + } +} + +function onLabelClick() { + // Activate other inputs with the same sync id. + syncId = this.getAttribute("data-sync-id"); + for (label of sd_labels_by_text[syncId]) { + if (label === this) continue; + label.previousElementSibling.checked = true; + } + window.localStorage.setItem("sphinx-design-last-tab", syncId); +} + +document.addEventListener("DOMContentLoaded", ready, false); diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 0000000..d06a71d --- /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 0000000..7e4c114 --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '', + 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 0000000..a858a41 Binary files /dev/null and b/_static/file.png differ diff --git a/_static/jquery.js b/_static/jquery.js new file mode 100644 index 0000000..c4c6022 --- /dev/null +++ b/_static/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/_static/js/html5shiv.min.js b/_static/js/html5shiv.min.js new file mode 100644 index 0000000..cd1c674 --- /dev/null +++ b/_static/js/html5shiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/_static/js/theme.js b/_static/js/theme.js new file mode 100644 index 0000000..1fddb6e --- /dev/null +++ b/_static/js/theme.js @@ -0,0 +1 @@ +!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/_static/minus.png b/_static/minus.png new file mode 100644 index 0000000..d96755f 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 0000000..7107cec 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 0000000..84ab303 --- /dev/null +++ b/_static/pygments.css @@ -0,0 +1,75 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +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: #3D7B7B; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #008000; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #9C6500 } /* Comment.Preproc */ +.highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.highlight .gr { color: #E40000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #008400 } /* Generic.Inserted */ +.highlight .go { color: #717171 } /* Generic.Output */ +.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #008000 } /* Keyword.Pseudo */ +.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #B00040 } /* Keyword.Type */ +.highlight .m { color: #666666 } /* Literal.Number */ +.highlight .s { color: #BA2121 } /* Literal.String */ +.highlight .na { color: #687822 } /* Name.Attribute */ +.highlight .nb { color: #008000 } /* Name.Builtin */ +.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */ +.highlight .no { color: #880000 } /* Name.Constant */ +.highlight .nd { color: #AA22FF } /* Name.Decorator */ +.highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #0000FF } /* Name.Function */ +.highlight .nl { color: #767600 } /* Name.Label */ +.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #19177C } /* Name.Variable */ +.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #666666 } /* Literal.Number.Bin */ +.highlight .mf { color: #666666 } /* Literal.Number.Float */ +.highlight .mh { color: #666666 } /* Literal.Number.Hex */ +.highlight .mi { color: #666666 } /* Literal.Number.Integer */ +.highlight .mo { color: #666666 } /* Literal.Number.Oct */ +.highlight .sa { color: #BA2121 } /* Literal.String.Affix */ +.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */ +.highlight .sc { color: #BA2121 } /* Literal.String.Char */ +.highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */ +.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #BA2121 } /* Literal.String.Double */ +.highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */ +.highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ +.highlight .sx { color: #008000 } /* Literal.String.Other */ +.highlight .sr { color: #A45A77 } /* Literal.String.Regex */ +.highlight .s1 { color: #BA2121 } /* Literal.String.Single */ +.highlight .ss { color: #19177C } /* Literal.String.Symbol */ +.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #0000FF } /* Name.Function.Magic */ +.highlight .vc { color: #19177C } /* Name.Variable.Class */ +.highlight .vg { color: #19177C } /* Name.Variable.Global */ +.highlight .vi { color: #19177C } /* Name.Variable.Instance */ +.highlight .vm { color: #19177C } /* Name.Variable.Magic */ +.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/_static/searchtools.js b/_static/searchtools.js new file mode 100644 index 0000000..7918c3f --- /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/sphinx_highlight.js b/_static/sphinx_highlight.js new file mode 100644 index 0000000..8a96c69 --- /dev/null +++ b/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/call-for-logos/README.html b/call-for-logos/README.html new file mode 100644 index 0000000..3145390 --- /dev/null +++ b/call-for-logos/README.html @@ -0,0 +1,145 @@ + + + + + + + Call for logos — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Call for logos

+

Logo 1

+

+

Logo 2

+

+

Logo 3

+

+

Logo 4

+

+

Logo 5

+

+

Logo 6

+

+

+

Logo 7

+

+

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/developing-key4hep-software/CMakeBuild.html b/developing-key4hep-software/CMakeBuild.html new file mode 100644 index 0000000..eaf3bc7 --- /dev/null +++ b/developing-key4hep-software/CMakeBuild.html @@ -0,0 +1,209 @@ + + + + + + + Building Key4hep using CMake: For Developers — Key4hep documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Building Key4hep using CMake: For Developers

+

A common problem when developing is needing to build multiple packages on top of +the stack to test changes in several repositories. One way of doing this is +using Spack but there is an experimental way using cmake.

+

First, source the releases or the nightlies as usual. Then, run the following +command:

+
/cvmfs/sw-nightlies.hsf.org/key4hep/experimental/setup.py pkg1 pkg2
+
+
+

Where pkg1 and pkg2 are the packages that will be cloned (can be empty). On +top of that, setup.py checks for folders (or symbolic links) in the current +directory that contain CMakeLists.txt. This can be useful if we want to use a +local version and don’t need to clone some repositories. After running the +command, a CMakeLists.txt file will appear. We may have to edit it manually if +we are using packages that are not recognized or are in a different organization +than the predefined ones. The information that we’ll need to edit is most likely +one of the first lines at the top:

+
set(pkgs EDM4hep k4FWCore)
+
+
+

that sets the packages that will be built in their right build order. +and the individual FetchContent_Declare entries for each package.

+

After we are happy with the CMakeLists.txt file, it’s important that we set the +new environment variables:

+
mkdir install
+cd install
+export PATH=$PWD/bin:$PATH
+export LD_LIBRARY_PATH=$PWD/lib:$PWD/lib64:$LD_LIBRARY_PATH
+export ROOT_INCLUDE_PATH=$PWD/include:$ROOT_INCLUDE_PATH
+export PYTHONPATH=$PWD/python:$PYTHONPATH
+export CMAKE_PREFIX_PATH=$PWD:$CMAKE_PREFIX_PATH
+cd ..
+
+
+

Then, we can run the usual commands for building:

+
mkdir build
+cd build
+cmake .. -DCMAKE_INSTALL_PREFIX=../install
+make -j N install
+
+
+

and it will build all the packages at the same time, so it may take some time. Symbolic links are +created in the build directory for each package that allow us to run ctest like:

+
cd k4FWCore
+ctest -j 2
+
+
+

in case we are building k4FWCore.

+

For the cloned directories, in case we want to clone a different commit or +branch from the master/main branch, this can be done by editing the +CMakeLists.txt

+
+

Possible issues

+

Not everything has been tested so it’s likely some things won’t work. For +many packages there are recent changes that enable these builds so using older +versions probably won’t work.

+
+
+

Packages that have been tested

+

The following packages have been built together successfully so it should be +possible to build any combination of them:

+
    +
  • podio

  • +
  • EDM4hep

  • +
  • k4FWCore

  • +
  • LCIO

  • +
  • ILCUTIL

  • +
  • LCCD

  • +
  • GEAR

  • +
  • Marlin

  • +
  • k4EDM4hep2LcioConv

  • +
  • k4MarlinWrapper

  • +
+
+
+

Changing to a different commit or branch

+

If we don’t want to build the master or main branch of the repositories we are +cloning, we have two options:

+
    +
  • Set the commit or branch we want in the CMakeLists.txt in the corresponding +FetchContent_Declare entry by changing GIT_TAG to whatever commit or branch +we want to checkout.

  • +
  • Go to the source directory, which can be found in the build directory under +_deps/<pkg>-src and checkout manually whatever commit or branch you want.

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/developing-key4hep-software/Key4hepCMakeGuide.html b/developing-key4hep-software/Key4hepCMakeGuide.html new file mode 100644 index 0000000..afc1f50 --- /dev/null +++ b/developing-key4hep-software/Key4hepCMakeGuide.html @@ -0,0 +1,288 @@ + + + + + + + CMake guide for Key4hep software — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

CMake guide for Key4hep software

+
+

Overview

+

CMake is a tool for building software, which has become the de-facto +standard outside HEP. In HEP, it is for example used by the ILC/CLIC +communities and by the LHCb collaboration. For CMS people, CMake is the +equivalent of scram.

+
+
+

Quick start into building Key4hep Software

+
+

Set up the environment

+

The first step is adding all dependencies to the bash environment. +In case you are unsure, it is best to use the default init script, provided on CVMFS for Centos7:

+
source /cvmfs/sw.hsf.org/key4hep/setup.sh
+
+
+

Note that mixing setup scripts (from another package, for example) may or may not work as intended - more likely not. +For any requests to changes in the environment, feel free to contact the software team on the mailing list or any other channels. +Developers may also look into spack to have more fine-grained control over the build dependencies.

+
+
+

Running CMake

+
    +
  • Create a build directory: mkdir build; cd build

  • +
  • Run CMake in the build directory: cmake ..

  • +
  • Change any cmake options by rerunning cmake.
    +For example: cmake .. -DCMAKE_INSTALL_PREFIX=../install -DCMAKE_BUILD_TYPE=Debug.
    +Tools like ccmake may also be useful: ccmake ..

  • +
  • Compile the software, using all the cpus available: make -j `getconf _NPROCESSORS_ONLN`

  • +
  • Install by running make install

  • +
  • In case any dependency is changed, most likely you need to remove all the contents of the build folder and rerun cmake and the compilation.

  • +
+
+
+

Using your local installation

+

In order to run the code you just installed, there are a few environment variables to set up (assuming the installation directory is the working directory):

+
mkdir build; cd build
+cmake .. -DCMAKE_INSTALL_PREFIX=../InstallArea
+make install
+cd ../InstallArea
+
+
+
    +
  • export CMAKE_PREFIX_PATH=$PWD/:$CMAKE_PREFIX_PATH

    +
      +
    • in order to use this installation as a dependency for other packages

    • +
    +
  • +
  • export PATH=$PWD/bin/:$PATH

    +
      +
    • in order to make any executables available on the command line

    • +
    +
  • +
  • export LD_LIBRARY_PATH=$PWD/lib:$PWD/lib64:$LD_LIBRARY_PATH

    +
      +
    • in order to make libraries available for linking and for the plugin systems in Gaudi/DD4hep

    • +
    +
  • +
  • export PYTHONPATH=$PWD/python:$PYTHONPATH

    +
      +
    • in order to make libraries available for linking and for the plugin systems in Gaudi/DD4hep

    • +
    +
  • +
  • export ROOT_INCLUDE_PATH=$PWD/include:$ROOT_INCLUDE_PATH

    +
      +
    • in case the package builds ROOT dictionaries

    • +
    +
  • +
  • export <PACKAGENAME>=$PWD/share/<PackageName>

    +
      +
    • some packages distribute data files that are found with a special environment variable, usually this is the package name in all caps.

    • +
    • e.g. export K4SIMDELPHES=$PWD/share/k4SimDelphes/

    • +
    +
  • +
+
+
+
+

CMake example packages

+

Colin provides a few simple CMake +examples. They are helpful to understand the basics of +CMake.

+

Get these packages:

+
git clone https://github.com/cbernet/cmake-examples.git
+cd cmake-examples
+
+
+

Follow the instructions in +README.md.

+
+
+

Changing the CMake Configuration

+

When adding new source files to a package, the CMake build system needs +to be made aware of them. Usually CMakeLists.txt contains a wildcard +expression that adds all implementation files in a subfolder, e.g. +src/*.cpp , so there is no need to explicitly add the names of the +new files. To update the list of files, it is fastest to run +make configure .

+

Note that when changing the name of a property of an algorithm or a +tool, make (and not only make packagename ) needs to be run for +Gaudi to be aware of the change.

+
+

Runtime Environment

+

Key4hep packages, in particular the gaudi framework components, consist of executables, headers, scripts, dynamic libraries, xmls and special files describing gaudi components. +In order to use these, some environment variables need to be set.

+

Gaudi also offers the possibility to set up the environment via the xenv command. This is done by simply prefixing the command you want to run with the run script in the top level directory of FCCSW, or directly in the build directory.

+
./build/run key4run Examples/options/pythia.py
+
+
+

Sometimes it is convenient to run FCCSW directly from the binaries in the build directory without installing them. +This can be done by using the run script in the build directory, or setting the environment variables as in setup.sh for the build folder. +Note that the directories in the build folder differ a bit. Mostly it is important the the LD_LIBRARY_PATH is pre-fixed with the library directories. The fccrun command should pick up the components from the build folder then.

+
+
+
+

CTest in Key4hep

+

Key4hep also uses CMake for integration tests. +They are added with add_test() and can be run with make test in the build folder. For Gaudi packages, the environment should be set so they can be run also in a build environments, see https://github.com/HEP-FCC/k4Gen/blob/main/k4Gen/CMakeLists.txt

+
+

Customizing how CMake is run

+

An environment variable is used to forward command line arguments to the cmake command, for example to run cmake with the trace option:

+
CMAKEFLAGS='--trace' make
+
+
+

{% callout “How do I check compilation flags?” %}

+

Instead of running   make , run:

+
make VERBOSE=1 
+
+
+

{% endcallout %}

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/developing-key4hep-software/Key4hepSoftwareGit.html b/developing-key4hep-software/Key4hepSoftwareGit.html new file mode 100644 index 0000000..503335c --- /dev/null +++ b/developing-key4hep-software/Key4hepSoftwareGit.html @@ -0,0 +1,369 @@ + + + + + + + Github workflow and contribution guide — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Github workflow and contribution guide

+
+

Overview

+

This page should allow users that are new to Git to get started with Key4hep software, and describes the workflow for accessing and contributing code.

+

For a general introduction to git, have a look at these tutorials:

+ +
+
+

First time setup of git

+

Please refer to this tutorial and the GitHub help.

+
+
+

Generate and set up ssh keys for github

+

We recommend to clone github repositories via SSH, especially if you want to +contribute code. For this to work, you need to generate ssh keys for +authentication. See the corresponding github +help-page.

+

{% callout “Generate and set up ssh keys for github” %}

+

If you only want to use the software it may be easier to use https. In that case you don’t need to generate the keys but have to replace git@github: with https://github.com/ in all the instructions. Note that you’ll not be able to push to your repository when you are on lxplus. You can also start using https for now and later re-add your repository with ssh authentication, see the trouble shooting section.

+

{% endcallout %}

+
+
+

Improving your git experience

+

It may be useful to install Git integration tools for your shell that allow tab-completion of most git commands and also can show you in your prompt on which branch you currently are, what changes you have pending, etc.

+
+
+

Development workflow

+

For any key4hep repository (taking k4SimDelphes as an example), you will be using (at least) 3 sources:

+
    +
  1. The official Key4hep repository on github

  2. +
  3. Your fork of the repository (see github help on what that means)

  4. +
  5. Your local repository in your work area (e.g. on AFS)

  6. +
+

The repositories 1 and 2 are added as remote to the repository 3:

+
git clone git@github.com:[YOUR_GITHUB_USER]/k4SimDelphes.git # create a local copy (3) of your fork (2)
+cd k4SimDelphes
+git remote add upstream git@github.com:key4hep/k4SimDelphes.git # add official repo (1) as additional remote
+
+
+
+

Keeping your local repository up to date

+
    +
  • fetch all changes from the official repository (1)

    +
    git fetch --all --prune
    +
    +
    +
  • +
  • rebase your development area to the master branch from the official repository (1), please read this to avoid loss of work

    +
    git rebase -i upstream/main
    +
    +
    +

    in this process you can also fix any commits that need touching up, be aware that deleting commits in the list will result also in the deletion of the corresponding changes (more info in the GitHub help and the Atlassian tutorial)

    +
  • +
  • push your local changes to your fork (2), see below how to create a local branch

    +
    git push origin [NAME_OF_LOCAL_BRANCH]
    +
    +
    +
  • +
+
+
+

Contributing code

+
    +
  • if you are fixing a bug, first create an issue in the github issue tracker.

  • +
  • develop your feature in your local copy (3) on a local branch of your choice, to create a branch do:

    +
    git branch -b [NAME_OF_LOCAL_BRANCH]
    +
    +
    +
  • +
  • refer to this tutorial to see how to commit changes

  • +
  • occasionally, get new code from the official repository (1) as explained above and merge it in this branch

  • +
  • test:

    +
      +
    • that the code compiles and all tests succeed (make && make test)

    • +
    • that your code runs (even better: [add an automatic test]

    • +
    • that it produces the expected results

    • +
    +
  • +
  • push your local branch to your fork (2) (see above)

  • +
  • create a pull request from your fork (2) to the offical repository’s (1) master branch (see github help-page)

    + +
  • +
+
+
+
+

Recommendations

+

Please always follow the recommendations below.

+
+

General recommendations

+
    +
  • if you’re working on a given topic, always create a branch for +it, e.g. pythia_interface. You may commit many times to this branch +in your local repository. When you have something solid create a +pull request to the official repository.

  • +
+
+
+

Commit comments

+
    +
  • feel free to commit often to your local repository, make a pull request once the topic you are working on is finished

    +
      +
    • if the feature you are working on is large, consider making a work in progress-pull request (see below)

    • +
    • git commits represent a snapshot of the software as a whole, and not only the difference to a previous commit (although that as well, in practice). It is recommended that each commit compiles and passes the tests. Take a look at the commit history of a key4hep repository and the histories of some individual files to find both good and bad examples.

    • +
    +
  • +
  • always provide a meaningful comment for each commit

    +
      +
    • if you are working on an issue, refer to that issue by adding “refs. #[issue id]”, see also +GitHub help

    • +
    +
  • +
  • commit comments should look like the one below, so that they show up +correctly in git printouts.

    +
    first version of a pythia interface # this line should be a short 1 liner
    +
    +Here, you may write a few more lines if needed
    +
    +
    +
  • +
+
+
+

Cleaning history

+
    +
  • before opening a pull request it may be a good idea to check that your history makes sense (commit messages explain what you did, no unnecessary commits, etc.), check with:

    +
    git log
    +
    +
    +
  • +
  • if you see commits that you’d like to change, there are several ways of doing that, the most commonly used is git rebase:

    +
      +
    • with the interactive version you can rebase your development branch to the official master and fix the history at the same time

    • +
    +
    git fetch upstream # get changes from the official repo
    +git rebase -i upstream/main # do the actual rebase
    +
    +
    +
      +
    • git will guide you through the steps, where you can delete entire commits (and the corresponding changes), merge commits and change commit messages

    • +
    • more information can be found in this tutorial

    • +
    +
  • +
+
+
+

Pull requests

+
    +
  • Give a meaningful title that appropriately describes what you did (e.g. Add new calorimeter clustering)

    +
      +
    • Pull requests of work in progress (to make people aware that you are working on a feature) create a PR starting with “[WIP]”

    • +
    +
  • +
  • In the description, give a short bullet-point list of what was done

  • +
  • If your pull request fixes issues tracked in the issue tracker:

    +
      +
    • Make sure you added a test that shows they are actually fixed

    • +
    • In the description mention that you fixed it by referring to the issue: “fixes #” (this will automatically close the issue, see also GitHub help)

    • +
    +
  • +
+
+
+
+

Trouble-shooting

+
+

When I try to push to the repository, I get an authentication error

+

Check with git remote -v which remote repositories you have added to your local copy. You should see something like:

+
upstream git@github.com:key4hep/k4SimDelphes.git (fetch)
+upstream git@github.com:key4hep/k4SimDelphes.git (push)
+origin	git@github.com:[your git user name]/k4SimDelphes.git (fetch)
+origin	git@github.com:[your git user name]/k4SimDelphes.git (push)
+
+
+

If you see something similar but all the addresses start with https, see below.

+

If you only see origin git@github.com:key4hep/k4SimDelphes.git, you need to add your own repository, push to that one and do a pull request, as described above. To add your own repository do:

+
git remote rename origin hep-fcc
+git remote add myfccsw git@github.com:[your git user name]/FCCSW.git
+
+
+
+
+

I have cloned with https and now I can’t push my changes, what do I do?

+

You only need to change the URL of your remote pointing to your repository to one that uses SSH instead:

+
git remote set-url [the remote name] git@github.com:[your git user name]/k4SimDelphes.git
+
+
+

Now you can push to that remote with:

+
git push [the remote name] [the branch you want to push]
+
+
+
+
+
+
+

Need help?

+

In case you have any questions on this guide, or need help to sort out +an issue with a repository, feel free to drop a mail to +key4hep-sw at CERN, and we’ll be happy to help you. +Alternatively create an issue in the bug tracker +smile.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/developing-key4hep-software/README.html b/developing-key4hep-software/README.html new file mode 100644 index 0000000..07da873 --- /dev/null +++ b/developing-key4hep-software/README.html @@ -0,0 +1,220 @@ + + + + + + + Developing Key4hep — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Developing Key4hep

+

Sooner rather than later you will find it necessary write code for Key4hep. These pages cover some software development topics to remove any friction.

+ +

CMakeBuild.md

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/developing-key4hep-software/SinglePackage.html b/developing-key4hep-software/SinglePackage.html new file mode 100644 index 0000000..804cc71 --- /dev/null +++ b/developing-key4hep-software/SinglePackage.html @@ -0,0 +1,159 @@ + + + + + + + Developing a single package — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Developing a single package

+

For quick changes of, for example, a single package, it’s possible to compile +the package using cmake (after having sourced the release or nightlies) and then +export some environment variables manually so that our local version will be +picked up instead of the one in cvmfs:

+
export PATH=/path/to/install/bin:$PATH
+export LD_LIBRARY_PATH=/path/to/install/lib:/path/to/install/lib64:$LD_LIBRARY_PATH
+export ROOT_INCLUDE_PATH=/path/to/install/include:$ROOT_INCLUDE_PATH
+export PYTHONPATH=/path/to/install/python:$PYTHONPATH
+
+
+

where the path to the installation is the one we gave cmake with +-DCMAKE_INSTALL_PREFIX when configuring. It’s possible more environment +variables need to be set depending on which package we are installing but the +previous ones are the main ones for many of the packages of the key4hep stack.

+

While this approach works and any number of packages can be built this way, it +is cumbersome to do so for many packages, as one has to repeat the cycle of +configuring, building and installing and then exporting the environment +variables as many times as packages are installed. It is possible to miss +packages and then the cvmfs version will be used instead of the local one +without notice and it’s also cumbersome to reproduce the environment at a later +time.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/developing-key4hep-software/SpackForDevelopers.html b/developing-key4hep-software/SpackForDevelopers.html new file mode 100644 index 0000000..d0a4469 --- /dev/null +++ b/developing-key4hep-software/SpackForDevelopers.html @@ -0,0 +1,442 @@ + + + + + + + Building Key4hep using Spack: For Developers — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Building Key4hep using Spack: For Developers

+

Using spack to develop software is somewhat pushing its intended usage to its +limits. However, it is not impossible and this is an area of spack that is +currently under active development. Unfortunately, this also means that the +spack documentation might not be fully up-to-date on these topics. Hence, this +page tries to collect some of the experiences the Key4hep developers have made.

+
+

Tip

+

To obtain and setup spack take a look at Setting up Spack.

+
+
+

Spack set up

+

For a standalone spack installation where we are happy to install all the +dependencies the link above will suffice. However, it is possible to use the +key4hep stack from cvmfs that has all the dependencies installed and only +install the packages that we want to work on. For that, it is important to +reproduce the environment that was used for building whatever release we are +going to use. Otherwise spack will see that we have different versions of +packages and will try to compile and install more than what we need. As +explained here, there are three files that are provided with each release or +nightly, that we need to use. Let’s say we want to use the nigthly for +2023-07-18. Then the first thing we do is source the nightly:

+
source /cvmfs/sw-nightlies.hsf.org/key4hep/releases/2023-07-18/x86_64-almalinux9-gcc11.3.1-opt/key4hep-stack/2023-07-18-kzukii/setup.sh
+
+
+

And then we clone spack and key4hep-spack, set up the environment and the +upstream installation, and the latest build from scratch (that we have to find +manually for now using, for example, find -iname .scratch), in this case it +happens to be 2023-06-24):

+
rel=/cvmfs/sw-nightlies.hsf.org/key4hep/releases/2023-07-18/x86_64-almalinux9-gcc11.3.1-opt
+latest_scratch=/cvmfs/sw-nightlies.hsf.org/key4hep/releases/2023-06-24/x86_64-almalinux9-gcc11.3.1-opt
+git clone https://github.com/key4hep/key4hep-spack --depth 1
+git clone https://github.com/spack/spack
+cd key4hep-spack
+git checkout $(cat $rel/.key4hep-spack-commit)
+cd ..
+cd spack
+git checkout $(cat $rel/.spack-commit)
+source $rel/.cherry-pick
+cd ..
+source spack/share/spack/setup-env.sh
+spack env activate key4hep-spack/environments/key4hep-nightly
+spack config add "upstreams:nightly:install_tree: $rel"
+spack config add "upstreams:nightly-scratch:install_tree: $latest_scratch"
+
+
+

And now we should have exactly the same version of spack and key4hep-spack that +was used to make the build, so the number of dependencies that spack tries to +install should be the minimum: it should find all the dependencies (in practice +this may not be the case but it should find most of them).

+
+
+

Developing a single package

+

When only developing on a single package it is possible to use the dev-build command of spack. +A brief tutorial can be found in the spack documentation. +There is also a dedicated channel on slack spackpm.slack.com (to get an invitation, visit slack.spack.io) where questions regarding the development workflow can be discussed. +It allows to build a given package directly from local sources in the same way as spack does it, and even makes this package available to other packages in the same way it does packages that have been installed by spack directly. +Here we will use LCIO as an example since it can be installed without (or with only one) dependency.

+

As a first step let’s have a look at what installing lcio with spack would entail. +Note that we explicitly disable the ROOT dictionaries in order to limit the number of dependencies

+
spack spec -Il lcio ~rootdict
+
+
+
Input spec
+--------------------------------
+ -   lcio~rootdict
+
+Concretized
+--------------------------------
+
+ -   vdwx2aq  lcio@2.16%gcc@9.3.0~examples~ipo~jar~rootdict build_type=RelWithDebInfo cxxstd=17 arch=linux-ubuntu20.04-skylake
+[+]  utzbuq7      ^cmake@3.16.3%gcc@9.3.0~doc+ncurses+openssl+ownlibs~qt patches=1c540040c7e203dd8e27aa20345ecb07fe06570d56410a24a266ae570b1c4c39,bf695e3febb222da2ed94b3beea600650e4318975da90e4a71d6f31a6d5d8c3d arch=linux-ubuntu20.04-skylake
+[+]  pljbs5a      ^sio@0.0.4%gcc@9.3.0+builtin_zlib~ipo build_type=RelWithDebInfo cxxstd=17 arch=linux-ubuntu20.04-skylake
+
+
+
+

In this configuration lcio has only two dependencies, sio and cmake, which +are both already installed in this case. If these dependencies are not yet +installed, spack will automatically install them for you when using the +dev-build command.

+
+

Installing a local version with dev-build

+

In order to install a local version of LCIO with spack, first we have to clone it into a local directory

+
git clone https://github.com/iLCSoft/LCIO
+
+
+

Now we can install this local version via

+
cd LCIO
+spack dev-build lcio@master ~rootdict
+
+
+

This should install lcio and all dependencies that are not yet fulfilled, giving you the full output of all the build stages ending on something like the following

+
...
+==> lcio: Successfully installed lcio-master-7dovpqn3kscbg672ham5wcqro7lg45gh
+  Fetch: 0.00s.  Build: 1.62s.  Total: 1.62s.
+[+] /home/tmadlener/work/spack/opt/spack/linux-ubuntu20.04-skylake/gcc-9.3.0/lcio-master-7dovpqn3kscbg672ham5wcqro7lg45gh
+
+
+

Note, that it is necessary to specify a single concrete version here for lcio. We use @master. +This version has to be one that is already available for the package (use spack info to find out which ones are available) and cannot be an arbitrary version. +It also does not necessarily have to correspond to the actual version of the source code you are currently installing. +However, it is of course encouraged to use a meaningful version specifier, since this package should also be useable as desired by dependent packages.

+
+
+

Using the local version as dependency

+

Now that the local version has been installed, it would of course be nice to be able to use it in downstream packages as well. +As far as spack is concerned, a package that has been built from local sources is not really different from one that has been built from automatically downloaded sources. +The main difference is that the fact that it has been built from local sources manifests in the spec

+
spack find -lv lcio
+
+
+

will yield something like

+
==> 1 installed package
+-- linux-ubuntu20.04-skylake / gcc@9.3.0 ------------------------
+7dovpqn lcio@master~examples~ipo~jar~rootdict build_type=RelWithDebInfo cxxstd=17 dev_path=/home/tmadlener/work/ILCSoft/LCIO
+
+
+

As you can see the local path from which this version was installed has become part of the spec for the installed package (the dev_path=... part of the spec above). +Hence, also the hash is affected by the fact that it has been built from a local source.

+

To use this specific version as a dependency the usual spack syntax can be used, e.g.

+
spack install marlin ^lcio/7dovpqn
+
+
+

will install marlin but use the version of lcio that we have just built locally.

+
+
+

More advanced usage

+

Note: If you have installed lcio following the description above you might have to uninstall it again first to follow these instructions, because spack will not overwrite an already installed package.

+

The above instructions only dealt with installing a package from a local source, but not how to easily get a development environment allowing for a quick edit, compile cycle. +This can be achieved by using the --drop-in and the --before/--until arguments of the dev-build command:

+
spack dev-build --drop-in bash --until cmake lcio@master ~rootdict
+
+
+

This command will first install all necessary dependencies, then run the install process for lcio until after the cmake stage and then drop you into a new bash shell with the proper build environment setup. +It will also setup a build folder, which follows the naming scheme spack-build-${hash}, in this case: spack-build-7dovpqn. +To compile lcio simply go into this directory and run make in there

+
cd spack-build-7dovpqn
+make -j4
+
+
+

You are now in an environment where you can easily edit the local source code and re-compile afterwards.

+

Once all the development is done, it is still necessary to install everything to the appropriate location. +This installation has to be registered in the spack database as well. Hence, simply calling make install in the build directory will not do the trick. +Another call to dev-build is necessary.

+
cd .. # go back to the source directory where you started
+spack dev-build lcio@master ~rootdict
+
+
+

This will run the whole chain again, but it will not overwrite the build directory. +Hence, it will not recompile everything again, but simply install all the build artifacts to the appropriate location. +spack find -lv lcio can be used to check if the installation was successful.

+

NOTE: You are probably still in the build environment at this stage. To return back to you original shell simply type exit.

+
+
+
+

Developing multiple packages or dependencies of other packages

+

Developing on many packages simultaneously using the dev-build command can become cumbersome and doesn’t really scale.

+
+

Using an environment to setup all dependencies

+

One way to develop on multiple packages simultaneously can be to setup an environment that contains the dependencies of all packages.

+

As an example the following definition of an environment has been used to develop on +podio, EDM4HEP and some other packages.

+
spack:
+  specs:
+    - python
+    - root@6.20.04 +davix+gsl+math~memstat+minuit+mlp~mysql+opengl~postgres~pythia6+pythia8+python~qt4+r+root7+rootfit+rpath~shadow+sqlite+ssl~table+tbb+threads+tmva+unuran+vc+vdt+vmc+x+xml+xrootd build_type=RelWithDebInfo cxxstd=17 patches=22af3471f3fd87c0fe8917bf9c811c6d806de6c8b9867d30a1e3d383a1b929d7
+    - dd4hep +geant4
+    - geant4
+    - heppdt
+    - hepmc@2.06.10
+    - tricktrack
+    - py-pyyaml
+    - py-jinja2
+    - cmake
+    - pythia8
+    - evtgen
+  concretization: together
+  view: true
+  packages:
+    all:
+      compiler: [gcc@9.3.0]
+      variants: cxxstd=17
+
+
+

Assuming this is the content of edm4hep_devel.yaml an environment can be created, activated, concretized and installed with the following commands:

+
spack env create edm4hep-devel edm4hep_devel.yaml
+spack env activate -p edm4hep-devel
+spack concretize
+spack install
+
+
+

After an environment has been installed, it can easily be activated via

+
spack env activate -p edm4hep-devel
+
+
+

which immediately drops you in an environment with all the packages stated in the environment file above available and properly set up. +Developing packages that depend on these should then be straight forward, especially for properly setup CMake based projects that can automatically find and configure their dependencies.

+

The disadvantage of this approach is that the packages you want to develop on have to be on the top of the stack and if they depend on each other, you still have to properly handle these dependencies on your own.

+
+
+

Environments and a development workflow

+

Recently spack gained the ability to setup environments and specify multiple packages that you would like to develop on (See spack/spack#256). +It is not yet really documented and it is not yet fully optimized, but it allows for a decent development experience if your package is not too deep down in the stack. +It is not impossible to develop on packages deep down the software stack, but this can imply frequently recompiling large parts of the software stack, since spack does not yet handle this in the best way, but instead builds all packages that you are not developing on from scratch. Hence, even if a simple relinking would have done the trick, spack will still build a lot of packages again. +Nevertheless, the feature is in a usable state and this section briefly describes how to use it. +Especially if you mainly develop on one package but sometimes want to check whether the rest of the stack, that depends on this package still compiles with the latest version, this can be a very useful workflow.

+

As an example we will be using the k4simdelphes package that depends on edm4hep, which in turn depens again on podio. +Suppose we want to change podio and edm4hep and see if k4simdelphes still compiles and works. +We would then use an environment definition file similar to the usual environments. For this example it has the following content

+
spack:
+  spec: 
+    - k4simdelphes
+  concretization: together
+  view: false
+  packages:
+     all:
+       compiler: [gcc@9.3.0]
+       variants: cxxstd=17
+  develop:
+    podio:
+      spec: podio@master +sio
+      path: ../../../../../podio
+    edm4hep:
+      spec: edm4hep@master
+      path: ../../../../../EDM4hep
+
+
+

The first part is the same as previously, but a new develop section containing information about the packages that should be developed on has been added. +For each package there is a spec and a path field. The spec field tells spack which spec to build, while the path field tells spack where the source files are located. +The path is relative to the $(prefix)/var/spack/environments/${environment-name} directory or an absolute path.

+

Assuming that you are currently in the directory that contains local spack installation, the following steps are necessary to create the development environment

+
git clone https://github.com/AIDASoft/podio
+git clone https://github.com/key4hep/EDM4hep
+spack env create my-development-env development_env_packages.yaml
+
+
+

where development_env_packages.yaml is the yaml file with the contents just described above.

+

It is now possible to activate this environment via

+
spack env activate -p my-development-env
+
+
+

To install all the packages, including the local versions of podio and edm4hep it is now enough to simply do spack installin the activated environment. +This will build your local copies of podio and edm4hep and use these versions as dependencies for the k4simdelphes package. +Changes can also be made to either of the two packages. +To compile only one package without installing it yet, it is easiest to simply go to the directory where the sources are. +There should now be a few spack related files and a spack build folder among the other source files

+
[...]
+spack-configure-args.txt
+spack-build-env.txt
+spack-build-out.txt
+spack-build-${hash}
+
+
+

Here ${hash} is the same that you get from spack find -l package. +After you have done all the necessary changes you can simply change into this build directory and run make to compile the package again. +Once all your development is done and you want to install the package spack install will run the whole build chain again. +This means that all the (local) development packages in your environment will only be recompiled as far as necessary, while all other packages that depend on the development packages will be re-built from scratch.

+

Once you are done developing, this environment can be used like any other environment simply by running spack env activate my-development-env to activate it.

+
+

Adding another package to develop

+

If you now realize that your changes to podio or edm4hep broke k4simdelphes and you need to also implement some changes there, you do not have to define a new environment. +Instead it is possible to add k4simdelphes to the develop section via spack develop (assuming you are still in the activated environment and in the same directory where also the podio and edm4hep sources live)

+
git clone https://github.com/key4hep/k4SimDelphes
+spack develop --no-clone --path ../../../../../k4SimDelphes k4simdelphes@main
+
+
+

Here, the --path is again either relative to the environment directory inside spack. It could also be an absolute path. +You now have to concretize the environment again before you can install the packages.

+
spack concretize -f
+spack install
+
+
+

Now you can work on k4simdelphes in the same way as you can for podio or edm4hep. +You can also check that the environment now indeed uses your local version of k4simdelphes via

+
spack find -lv k4simdelphes
+
+
+

which should now yield something along the lines of

+
==> In environment my-development-env
+==> Root specs
+------- k4simdelphes@main 
+
+==> 1 installed package
+-- linux-ubuntu20.04-broadwell / gcc@9.3.0 ----------------------
+m5khm2w k4simdelphes@main~ipo build_type=RelWithDebInfo dev_path=/home/tmadlener/work/spack/var/spack/environments/test-devel-env/../../../../../k4SimDelphes
+
+
+

where the path to the local source files has now again become part of the spec as can be seen by the dev_path=... part of the spec.

+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/developing-key4hep-software/WritingAlgorithms.html b/developing-key4hep-software/WritingAlgorithms.html new file mode 100644 index 0000000..0504013 --- /dev/null +++ b/developing-key4hep-software/WritingAlgorithms.html @@ -0,0 +1,426 @@ + + + + + + + Writing Gaudi Algorithms — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Writing Gaudi Algorithms

+
+

Gaudi

+

Gaudi is an event-processing framework. Algorithms can be defined by users and +Gaudi will take care of running them for each event. In addition, Gaudi has a +set of services and tools like logging and support for running in a +multithreaded environment.

+

The relationship between Gaudi with key4hep happens through +k4FWCore. k4FWCore has tools and +utilities needed to be able to use (almost) seamlessly EDM4hep collections in +Gaudi algorithms. We recommend checking out the +tests in this +repository since they contain examples of algorithms (in particular of +algorithms using Gaudi::Functional).

+
+
+
+

Gaudi::Functional

+

Using Gaudi::Functional is the recommended way of creating algorithms. The +design is simple and at the same time enforces several constraints at +compile-time, allowing for a quicker development cycle. In particular, we will +see that our algorithms won’t have an internal state and we obtain the benefit +of being able to run in a multithreaded environment (almost) trivially[1].

+
+

Setup

+

We will need Gaudi, k4FWCore and all their dependencies. Installing these by +ourselves is not easy but there are software stacks on cvmfs, see the +/setup-and-getting-started/README.md to set up the key4hep stack.

+

The easiest way of having a working repository is to copy the template +repository that we provide in key4hep:

+
git clone https://github.com/key4hep/k4-project-template
+
+
+

or ideally with ssh

+
git clone git@github.com:key4hep/k4-project-template
+
+
+

This template repository already has the cmake code that will make our +algorithms know where Gaudi and k4FWCore and to properly link to them. In +addition there are a few examples that combined with the tests in k4FWCore +provide an overview of what’s possible to do. The k4-project-template +repository contains a CMake configuration (as described in more detail in the +previous tutorial) so it can be built with:

+
cd k4-project-template
+mkdir build install
+cd build
+cmake .. -DCMAKE_INSTALL_PREFIX=../install
+make -j 4 install
+
+
+

To run the algorithms contained in this repository you can use k4run, like:

+
k4run ../K4TestFWCore/options/createExampleEventData.py 
+
+
+
+
+

Walkthrough of Functional Algorithms

+

Functional algorithms in Gaudi are relatively straightforward to write. For each +algorithm we want, we have to create a class that will inherit from one of the +Gaudi::Functional classes. The most important function member will be +operator() which is what will run over our events (or over none in case we are +generating). There are several base classes in Gaudi (see a more complete list +in https://lhcb.github.io/DevelopKit/03a-gaudi/):

+
    +
  • Consumer, one or more inputs, no outputs

  • +
  • Producer, one or more outputs, no inputs

  • +
  • Transformer (and MultiTransformer), one or more inputs, one or more outputs

  • +
+

The structure of our class (more precisely structs) will then be, in the general +case of the transformer:

+
#include "GaudiAlg/Transformer.h"
+// Define BaseClass_t
+#include "k4FWCore/BaseClass.h"
+
+struct ExampleTransformer final
+    : Gaudi::Functional::Transformer<colltype_out(const colltype_in&), BaseClass_t> {
+
+  ExampleTransformer(const std::string& name, ISvcLocator* svcLoc);
+  colltype_out operator()(const colltype_in& input) const override;
+};
+
+
+

Some key points:

+
    +
  • The magic to make our algorithm work with EDM4hep collections happens by +including BaseClass.h and passing BaseClass_t it as one of the template +arguments to the Gaudi class we are inheriting from.

  • +
  • operator() is const, which means that it can’t modify class members. This is +intended and helps with multithreading by not having an internal state.

  • +
+

Let’s start with the first template argument. It’s the signature of a function +that returns one or more outputs and takes as input one or more inputs. +One possible example would be to have these two lines before the class definition:

+
using colltype_in  = edm4hep::MCParticleCollection;
+using colltype_out = edm4hep::MCParticleCollection;
+
+
+

and then we have a transformer that will take one MCParticleCollection as +input and return another one. If we have multiple inputs we keep adding +arguments to the function arguments and if we don’t have any we can leave that +empty. For the output this is slightly more complicated because if there are +more than one output we have to return an std::tuple<OutputClass1, OutputClass2>; if there aren’t any outputs we can simply return void.

+

Then we reach the constructor. We’ll always initialize from the constructor of the +class we’re inheriting (in this example a Transformer) and then we’ll +initialize a set of KeyValues. These KeyValues will be how we define the +names of our inputs and outputs so they can be found by other algorithms, read +from a file or saved to a file.

+
  ExampleTransformer(const std::string& name, ISvcLocator* svcLoc)
+      : Transformer(name, svcLoc,
+                    KeyValue("InputCollection", "MCParticles"),
+                    KeyValue("OutputCollection", "NewMCParticles")) {
+                    // possibly do something
+                    }
+
+
+

Here we are defining how we will name our input collection in the steering value +(InputCollection) and giving it a default value. We’re doing the same with the +output collection. The order is important here: first inputs and then outputs +and they are ordered. When we have more inputs we just add another line, like +the one above for the input collection. For outputs, since they are bundled +together in a std::tuple when there are several, we have to enclose the list +of KeyValue with brackets, like

+
  ExampleMultiTransformer(const std::string& name, ISvcLocator* svcLoc)
+      : MultiTransformer(name, svcLoc,
+                    KeyValue("InputCollection", "MCParticles"),
+                    {
+                    KeyValue("OutputCollection1", "NewMCParticles"),
+                    KeyValue("OutputCollection2", "SimTrackerHits"),
+                    KeyValue("OutputCollection3", "UsefulCollection"),
+                    }
+                    ) {
+                    // possibly do something
+                    }
+
+
+

Then in the operator() we can do whatever we want to do with our collections

+
  colltype_out operator()(const colltype_in& input) const override {
+    auto coll_out = edm4hep::MCParticleCollection();
+    for (const auto& particle : input) {
+      auto new_particle = edm4hep::MutableMCParticle();
+      new_particle.setPDG(particle.getPDG() + 10);
+      new_particle.setGeneratorStatus(particle.getGeneratorStatus() + 10);
+      new_particle.setSimulatorStatus(particle.getSimulatorStatus() + 10);
+      new_particle.setCharge(particle.getCharge() + 10);
+      new_particle.setTime(particle.getTime() + 10);
+      new_particle.setMass(particle.getMass() + 10);
+      coll_out->push_back(new_particle);
+    }
+    return coll_out;
+
+
+

When we return several collections we can bundle them in an std::tuple like this:

+
    return std::make_tuple(std::move(collection1), std::move(collection2));
+
+
+

The complete example for reference can be found in the tests of k4FWCore: +https://github.com/key4hep/k4FWCore/blob/main/test/k4FWCoreTest/src/components/ExampleFunctionalTransformer.cpp

+
+
+

The steering file

+

The steering file is the file where we define which algorithms will run, what +parameters they will use and how they will do it; what level of logging, if +using multithreading, etc.

+

We start with some imports

+
from Gaudi.Configuration import INFO
+from Configurables import ExampleFunctionalTransformer
+from Configurables import ApplicationMgr
+from Configurables import k4DataSvc
+from Configurables import PodioOutput
+from Configurables import PodioInput
+
+
+

it’s also possible to import everything from Configurables but it’s better not +to so that if we are using IDE or an editor with some kind of analysis it can +tell us if we are using an undefined variable, for example.

+

Then, the input:

+
podioevent = k4DataSvc("EventDataSvc")
+podioevent.input = "output_k4test_exampledata_producer.root"
+
+inp = PodioInput()
+inp.collections = [
+    "MCParticles",
+]
+
+
+

We select the name of the input file and which collections we’ll make available +for the rest of the algorithms.

+

For the output:

+
out = PodioOutput("out")
+out.filename = "output_k4test_exampledata_transformer.root"
+# The collections that we don't drop will also be present in the output file
+out.outputCommands = ["drop MCParticles"]
+
+
+

we can select which collections we keep in the output file. By default the +collections in the output file will be the same as in the input file. Check the +relevant +documentation +to learn more about PodioInput and PodioOutput.

+

Our algorithm will look like this:

+
transformer = ExampleFunctionalTransformer("ExampleFunctionalTransformer",
+                                           InputCollection="MCParticles",
+                                           OutputCollection="NewMCParticles")
+
+
+

If we have defined Gaudi::Propertys for our algorithm it is also possible to +change them by doing transformer.property = value; however with the names of +the collections, if they are provided, they are set when creating the python +object with our algorithm.

+

Finally we define what to run:

+
ApplicationMgr(TopAlg=[inp, transformer, out],
+               EvtSel="NONE",
+               EvtMax=10,
+               ExtSvc=[k4DataSvc("EventDataSvc")],
+               OutputLevel=INFO,
+               )
+
+
+

We pass a list of the algorithms in TopAlg. PodioInput will be the first one +and PodioOutput will be the last one when used. In EvtMax we set what is the +maximum number of event that we are processing. Use -1 not to limit it. That +means if we are processing a file, then read all the events in the file. We pass +extra services to ExtSvc and set an OutputLevel that could be DEBUG, +WARNING or INFO most of the time.

+
+
+

Initialize and finalize

+

There are some occasions where we may want to run some code between the +constructor and the operator(); that is the place for initialize(). There is +also a way of doing something similar after processing with finalize(). For that, we +can add to our classes those functions (we can also add only one of these):

+
  StatusCode initialize() override;
+  StatusCode finalize() override;
+
+
+

and then we can implement them.

+

Make sure to remember to return the corresponding status code, otherwise +Gaudi will crash. For example:

+
StatusCode MyAlgorithm::initialize() {
+  // do something
+  return StatusCode::SUCCESS;
+}
+
+
+
+
+

Debugging: How to use GDB

+

The GNU Project Debugger is supported by +Gaudi and can be invoked by passing additional --gdb parameter to the k4run. +For example:

+
k4run ../K4TestFWCore/options/createExampleEventData.py --gdb
+
+
+

This will start the GDB and attaches it to the Gaudi steering. After initial +loading, user can start running of the steering by typing continue into the +GDB console. To interrupt running of the Gaudi steering use CTRL+C.

+

More details how to run GDB with Gaudi can be found in +LHCb Code Analysis Tools (requires a CERN account to view).

+
+
+

Avoiding const in operator()

+

There is a way of working around operator() being const and that is by adding +the keyword mutable to our data member. This will allow us to change our data +member inside operator() and will cause code that wasn’t compiling because of +this to compile. Of course, this is not a good idea because unless the member of +our class is thread-safe, that means that our algorithm is no longer thread-safe +and running with multiple threads can cause different results. Even worse than +that, it’s very possible that there are not any errors or crashes but the +results are simply wrong from having several threads changing a member at the +same time, for example.

+
+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/genindex.html b/genindex.html new file mode 100644 index 0000000..e5b4f28 --- /dev/null +++ b/genindex.html @@ -0,0 +1,126 @@ + + + + + + Index — Key4hep documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ + +

Index

+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/how-tos/README.html b/how-tos/README.html new file mode 100644 index 0000000..38ba430 --- /dev/null +++ b/how-tos/README.html @@ -0,0 +1,164 @@ + + + + + + + Key4hep How-Tos and Instructions — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Key4hep How-Tos and Instructions

+

This page contains a few brief How-Tos and Instructions on how to achieve +certain things within the Key4hep software stack. They are mainly aimed at +Key4hep users and are mostly designed to be reference material, rather than +tutorials.

+ + +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/how-tos/k4edm4hep2lcioconv/doc/LCIO2EDM4hep.html b/how-tos/k4edm4hep2lcioconv/doc/LCIO2EDM4hep.html new file mode 100644 index 0000000..011f53a --- /dev/null +++ b/how-tos/k4edm4hep2lcioconv/doc/LCIO2EDM4hep.html @@ -0,0 +1,318 @@ + + + + + + + Standalone conversion from LCIO to EDM4hep — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Standalone conversion from LCIO to EDM4hep

+

The lcio2edm4hep executable reads LCIO (.slcio) files and converts its +contents into EDM4hep. Each LCEvent of the input file will be put into a +podio::Frame in the output file (under the events category). The most basic +usage is simply

+
lcio2edm4hep <input.slcio> <output.edm4hep.root>
+
+
+
+

Patching missing collections on the fly

+

A major difference between LCIO and EDM4hep is that in LCIO an LCEvent can +effectively have arbitrary contents, whereas in EDM4hep the assumption is that +each event consists of the same collections (even if some of them are empty). +Hence, it is necessary to either ensure that all events in the LCIO file have +the same contents or or to give lcio2edm4hep some additional information such +that it can patch in potentially missing collections on the fly. This additional +information comes in the form of a third argument to lcio2edm4hep and is +effectively a list of collection names and their types that comprise the +superset of all collections appearing in at least one event in the input LCIO +file. The format looks like this

+
name[:output-name]  type-name
+
+
+

Each collection is a single line containing the name first (including an +optional output name see below) and than its +type. The simplest form looks like this:

+
SETSpacePoints             TrackerHit
+RecoMCTruthLink            LCRelation[ReconstructedParticle,MCParticle]
+
+
+

The easiest way to obtain such a file is to use the check_missing_cols +executable that comes with LCIO using the --minimal flag. The output of this +can be directly consumed by lcio2edm4hep

+
+

Example:

+
    +
  1. Get the patch file

  2. +
+
check_missing_cols --minimal \
+  /pnfs/desy.de/ilc/prod/ilc/mc-2020/ild/rec/250-SetA/higgs/ILD_l5_o2_v02/v02-02-01/00015671/000/rv02-02-01.sv02-02-01.mILD_l5_o2_v02.E250-SetA.I402005.Pe3e3h.eL.pR.n000_002.d_rec_00015671_493.slcio \
+  > patch.txt
+
+
+
    +
  1. Pass it to lcio2edm4hep

  2. +
+
lcio2edm4hep \
+  /pnfs/desy.de/ilc/prod/ilc/mc-2020/ild/rec/250-SetA/higgs/ILD_l5_o2_v02/v02-02-01/00015671/000/rv02-02-01.sv02-02-01.mILD_l5_o2_v02.E250-SetA.I402005.Pe3e3h.eL.pR.n000_002.d_rec_00015671_493.slcio \
+  Output.root \
+  patch.txt
+
+
+
+
+

Converting LCRelation collections

+

For collections of LCRelation type it is necessary to define the FromType and +ToType as well, as otherwise the converter will not be able to create the +correct edm4hep file. The check_missing_cols executable will try to determine +these types from the collection parameters and will warn if it cannot do it for +certain collections. In this case it is the users responsibility to provide +the missing types as otherwise the conversion will simply skip these +collections, or potentially even crash.

+
+
+
+

Converting only a subset of collections

+

Using the same mechanism as for patching collections it is also possible to only +convert a subset of all available collections. lcio2edm4hep uses the contents +of the colltypefile to determine the contents of the output. If that contains +only a subset of all collections, only that subset will be converted. Missing +collections will still be patched in, in this case.

+
+
+

Renaming collections on the fly

+

The optional [:output-name] part of each collection can be used to remap the +names of the collections in the input LCIO file to a different name in the +output EDM4hep file, e.g.

+
MCParticle:MCParticles      MCParticle
+
+
+

will read the MCParticle collection from the input file but store it as +MCParticles in the output file.

+
+
+
+

Library usage of the conversion functions

+

The conversion functions are designed to also be usable as a library. The overall design is to make the conversion a two step process. Step one is converting the data and step two being the resolving of the relations and filling of subset collection.

+
+

Converting collection (data)

+

The main entry point is convertCollection which will automatically dispatch to +the correct conversion function depending on the type information that is stored +in the input LCCollection. It is also possible to access the individual +conversion functions for each type. All of the conversion functions take a map +of LCIO to EDM4hep objects of their specific type that will be filled during the +conversion. for convenience all necessary maps are bundled in the +LcioEdmTypeMapping struct.

+
+
+

Handling relations

+

Once all necessary collections have been converted, it is necessary to resolve +the relations between the objects. This is done using the resolveRelations +function. This will again dispatch to the correct relation resolving function +for the corresponding types, which can obviously also be invoked directly.

+
+
+

Handling of subset collections

+

Subset collections are handled similar to relations using the function +fillSubset. Internally this simply forwards to handleSubsetColl which +handles all the type details and can obviously also be used directly.

+
+
+

Handling of LCRelations

+

LCRelation only exist in LCIO and their conversion is limited to what is +available in EDM4hep. They use the "FromType" and "ToType" collection +parameters to get the necessary type information.

+

The AssociationCollections in EDM4hep are then created using createAssociations.

+
+
+

Converting entire events

+

Converting an entire event can be done calling the convertEvent. This can also +be used as an example to guide the implementation of custom conversions using +the available functionality.

+
+
+

Converting Event parameters

+

This can be done by calling convertObjectParameters that will put all the event parameters into the passed podio::Frame.

+
+
+

Subtle differences between LCIO and EDM4hep

+

There are a few small differences between LCIO and EDM4hep that shine through in the conversion, these are:

+
    +
  • CaloHitContributions are part of the SimCalorimeterHits in LCIO while being their own data type in EDM4hep. They are created by createCaloHitContributions.

  • +
  • The event information like an event number is part of the LCEvent in LCIO. In EDM4hep there is a separate EventHeader Collection. It can be created using EventHeaderCollection which is stored under the name "EventHeader".

  • +
  • Particle IDs are converted during the conversion of the the reconstructed Particle collection.

  • +
+
+
+

Example for a ReconstructedParticle Collection

+
#include "k4EDM4hep2LcioConv/k4Lcio2EDM4hepConv.h"
+
+// the struct defined in the header file is used for the maps linking Lcio particles
+// to their EDM counterparts.
+
+auto typeMapping = LcioEdmTypeMapping{};
+
+// We assume that this is a collection of ReconstructedParticles!
+LCEVENT::LCCollection* lcCollection;
+
+// Convert the data
+auto edmCollections = convertReconstructedParticle("name",
+                                                   lcCollection,
+                                                   typeMapping.recoParticles,
+                                                   typeMapping.particleIDs);
+
+// Resolve relations (only converted objects will be available)
+// This has to be called at the very end, after all collection data has been
+// converted
+resolveRelations(typeMapping);
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/how-tos/k4fwcore/doc/PodioInputOutput.html b/how-tos/k4fwcore/doc/PodioInputOutput.html new file mode 100644 index 0000000..dd21a61 --- /dev/null +++ b/how-tos/k4fwcore/doc/PodioInputOutput.html @@ -0,0 +1,263 @@ + + + + + + + Reading and writing EDM4hep files in Gaudi — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ + +
+

Reading and writing EDM4hep files in Gaudi

+

The facilities to read and write EDM4hep (or in general event data models based +on podio) are provided by k4FWCore. +This page will describe their usage, but not go into too much details of their +internals. This page also assumes a certain familiarity with Gaudi, i.e. most of +the snippets just show a minimal configuration part, and not a complete runnable +example.

+
+

The k4DataSvc

+

Whenever you want to work with EDM4hep in the Gaudi based framework of Key4hep, +you will need to use the k4DataSvc as EventDataSvc. You can instantiate and +configure this service like the following

+
from Gaudi.Configuration import *
+from Configurables import k4DataSvc
+
+evtSvc = k4DataSvc("EventDataSvc")
+
+
+

It is important that the name is EventDataSvc in this case, as otherwise +this is an assumption from Gaudi. Once you have the k4DataSvc instantiated, +you still have to make the ApplicationMgr aware of it, by making sure that the +evtSvc is in the list of the external services (ExtSvc):

+
from Configurables import ApplicationMgr
+ApplicationMgr(
+    # other args
+    ExtSvc = [evtSvc]
+)
+
+
+
+
+

Reading events

+

To read events you will need to use the PodioInput algorithm in addition to +the k4DataSvc. Currently, you will need to pass the input +file to the k4DataSvc via the input option but pass the collections that you +want to read to the PodioInput. We are working on making this (discussion +happens in this issue). The +parts of your options file related to reading EDM4hep files will look something +like this

+
from Configurables import PodioInput, k4DataSvc
+
+evtSvc = k4DataSvc("EventDataSvc")
+evtSvc.input = "/path/to/your/input-file.root"
+
+podioInput = PodioInput()
+
+
+

It is possible to change the input file from the command line via

+
k4run <your-options-file> --EventDataSvc.input=<input-file>
+
+
+

By default the PodioInput will read all collections that are available from +the input file. It is possible to limit the collections that should become +available via the collections option

+
podioInput.collections = [
+  # List of collection names that should be made available
+]
+
+
+
+
+

Writing events

+

To write events you will need to use the PodioOutput algorithm in addition to +the k4DataSvc:

+
from Configurables import PodioOutput
+
+podioOutput = PodioOutput("PodioOutput", filename="my_output.root")
+
+
+

By default this will write the complete event contents to the output file.

+
+

Writing only a subset of collections

+

Sometimes it is desirable to limit the collections to a subset of all available +collections from the EventStore. The PodioOutput allows to do this via the +outputCommands option that takes a list of keep or drop commands. Each +command must consist of the keep/drop command and a target. The target is a +collection name that may include the ? or * wildcard patterns. This might +look like the following

+
podioOutput.outputCommands = ["keep *"]
+
+
+

which will keep everything (the default), while

+
podioOutput.outputCommands = ["drop *"]
+
+
+

will simply drop all collections and effectively write an empty file (apart from +some metadata). A common pattern is to "drop *" and then selectively adding +keep collections to keep, e.g. to only keep the highest level MC and reco +information:

+
podioOutput.outputCommands = [
+    "drop *",
+    "keep MCParticlesSkimmed",
+    "keep PandoraPFOs",
+    "keep RecoMCTruthLink",
+]
+
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/how-tos/k4fwcore/doc/k4run-args.html b/how-tos/k4fwcore/doc/k4run-args.html new file mode 100644 index 0000000..810f07a --- /dev/null +++ b/how-tos/k4fwcore/doc/k4run-args.html @@ -0,0 +1,169 @@ + + + + + + + Adding custom arguments to k4run — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ + +
+

Adding custom arguments to k4run

+

It is possible to extend k4run with custom arguments from a steering file using k4FWCore.parseArgs.

+

Example:

+
from k4FWCore.parseArgs import parser
+parser.add_argument("--trackingOnly", action="store_true", help="Run only track reconstruction", default=False)
+my_opts = parser.parse_known_args()[0]
+
+# later
+if my_opts.trackingOnly:
+    # only run track reconstruction
+
+
+

Behind the scenes parser is just a normal instance of pythons argparse.ArgumentParser, please refer to its documentation for usage details. The only important thing to keep in mind is to always use parse_known_args() instead of parse_args() so that the normal k4run arguments keep working.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/how-tos/k4marlinwrapper/doc/MarlinWrapperIntroduction.html b/how-tos/k4marlinwrapper/doc/MarlinWrapperIntroduction.html new file mode 100644 index 0000000..5e02fe2 --- /dev/null +++ b/how-tos/k4marlinwrapper/doc/MarlinWrapperIntroduction.html @@ -0,0 +1,361 @@ + + + + + + + Wrapping Marlin processors in Gaudi — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ + +
+

Wrapping Marlin processors in Gaudi

+

This page describes how to run existing Marlin processors within the Gaudi +framework. Marlin and Gaudi are two event processing frameworks available in +the Key4hep software stack. The former was originally developed by the linear +collider communities in iLCSoft, while the latter originally comes from LHCb. It +is also the event processing framework for future developments within Key4hep. +To enable using the existing functionality that has been developed for the +linear collider studies and also to allow for a gradual migration the +MarlinProcessorWrapper has been developed. It allows to run Marlin processors +within the Gaudi framework and it’s usage is described +below

+

One of the major differences between Marlin processors and (Key4hep) Gaudi +algorithms is the event data model (EDM) that they use. While Marlin uses LCIO, +Gaudi in Key4hep uses EDM4hep. Since EDM4hep is +based on LCIO the differences are limited and it is possible to convert between +the two EDMs as necessary. We will also show how to do this +below.

+

The following descriptions assume that you are somewhat familiar with how to +configure and run Gaudi via k4run, i.e. most of the snippets will just show +the bare minimum of configuration, but will usually not work without +modifications (e.g. in most cases the ApplicationMgr as well as putting all +the configured algorithms into the list of algorithms to run is missing +entirely).

+
+

The MarlinProcessorWrapper Gaudi algorithm

+

The MarlinProcessorWrapper is a standard Gaudi algorithm and can be used just +like all others, i.e. in a Gaudi options file we simply have to import it via

+
from Gaudi.Configuration import *
+from Configurables import MarlinProcessorWrapper
+
+
+

It can then be configured just like any other algorithm by instantiating it and +passing the necessary parameters to it. Each Marlin processor that you want to +wrap needs its own instance. The main configuration parameters for the +MarlinProcessorWrapper are

+
    +
  • ProcessorType - a string with the Marlin processor type. The type is +usually the class name of the Marlin processor, and corresponds to the type +attribute in a Marlin XML configuration for a processor.

  • +
  • Parameters - a dictionary of string keys and list of string values. Each +parameter of the Marlin processor needs its own entry in this dictionary and +all parameter values have to be strings as the parsing is done internally.

  • +
+

As a very brief example; The following snippet of a Marlin XML steering file

+
  <processor name="StatMonitorAlg" type="StatusMonitor">
+    <parameter name="HowOften" type="int">1</parameter>
+  </processor>
+
+
+

could be converted to the following snippet of a Gaudi options file

+
StatMonitorAlg = MarlinProcessorWrapper("StatMonitorAlg")
+StatMonitorAlg.ProcessorType = "StatusMonitor"
+StatMonitorAlg.Parameters = {"HowOften": ["1"]}
+
+
+

Note that wrapped Marlin processors still expect their inputs in LCIO +format! You can either read in the data in that format directly, or use +converters to convert from EDM4hep to LCIO first.

+
+
+

Reading and writing LCIO events with Gaudi

+

In order to read in event data in LCIO format into the Gaudi world it is +necessary to use the LcioEvent Gaudi algorithm. It is configured in the same +way as normal Gaudi algorithms, i.e. in a minimal standalone form

+
from Gaudi.Configurables import *
+from Configurables import LcioEvent
+
+read = LcioEvent()
+read.Files = ["inputfile1.slcio", "inputfile2.slcio"]
+
+
+

For writing LCIO events from Gaudi, simply use a MarlinProcessorWrapper to +wrap a LCIOOutputProcessor, e.g.

+
from Configurables import MarlinProcessorWrapper
+
+Output_DST = MarlinProcessorWrapper("Output_DST")
+Output_DST.ProcessorType = "LCIOOutputProcessor"
+Output_DST.Parameters = {
+                         "DropCollectionNames": [],
+                         "DropCollectionTypes": ["MCParticle", "LCRelation", "SimCalorimeterHit"],
+                         }
+
+
+
+
+

Automatic conversion of Marlin XML steering files

+

We provide the convertMarlinSteeringToGaudi.py converter script to +automatically convert Marlin steering files in XML format to Gaudi options +python files. Usage is as simple as

+
convertMarlinSteeringToGaudi.py <input-steering.xml> <output-gaudi-options.py>
+
+
+
+

Limitations

+

This converter script handles almost everything, but there are a few +short-comings which it cannot yet handle:

+
    +
  • Marlin XML steering files can have include statements, e.g. <include ref="Tracking/TrackingDigi.xml"/>. These cannot be resolved by the converter +script, and it will issue a warning. The easiest way to fix this is to simply +run Marlin -n to resolve all these statements and then run the converter +script again on the output file which will be named +<inputfile-base>Parsed.xml.

  • +
  • Marlin has a mechanism to resolve constants that are defined in the +constants section and used like ${someFancyConstant} in the following. The +converter script and the converted Gaudi options file handle these in general. +However, it might be necessary to change the values of the constants inside +the CONSTANTS dictionary that can be found at the beginning of the created +options file. Alternatively one can use Marlin -n with e.g. +--constant.someFancyConstant=<value> to set the values in the Marlin +steering file first and again parse the converted output.

  • +
  • Marlin supports conditional execution of processors via the condition tag. +These conditions can be configured via constant values from the constants +section in the steering file, but in principle these can also be runtime +values that are set, e.g. by a previously run processor. At the moment dynamic +conditions (where the value might change on an event by event basis) are not +supported by Gaudi. Additionally static conditions are only partially handled +by the converter script. While it converts the necessary configuration, it +will by default not put the converted algorithm into the algList list of +algorithms to run and you might have to comment / uncomment the algorithms you +actually want to run.

  • +
  • If the value of the LCIOInputFiles is empty in the input XML file, the +converter script will put a value of "None" into the read.Files parameter. +You will have to change this either in the steering file or them in via +--LcioEvent.Files.

  • +
  • Marlin is in some cases able to replace constants with the values stored in +environment variables of the same name. In Gaudi these have to be retrieved +from the environment explicitly via os.environ.

  • +
+
+
+
+

Using the EDM converters

+

The converters between EDM4hep and LCIO are implemented as so called +GaudiTools. They can be attached to any MarlinProcessorWrapper algorithm +that is configured in the Gaudi options file. The tools are called +Lcio2EDM4hepTool and EDM4hep2LcioTool respectively. Each wrapped processor +can be equipped with both tools, so that it is possible to e.g. convert input +from EDM4hep to LCIO and output from LCIO to EDM4hep again:

+

+

The (very) basic usage of the converter tools looks like the following

+
    +
  • Instantiate the necessary tools (and configure them as desired)

  • +
  • Attach the tools to a wrapped marlin processor via the Lcio2EDM4hepTool +and/or EDM4hep2LcioTool options

  • +
+
from Configurables import EDM4hep2LcioTool, Lcio2EDM4hepTool
+
+edm4hep2LcioConv = EDM4hep2LcioTool("EDM4hep2Lcio")
+lcio2edm4hepConv = Lcio2EDM4hepTool("Lcio2EDM4hep")
+
+wrappedProcAlg = MarlinProcessorWrapper("ProcessorToWrap")
+wrappedProcAlg.Lcio2EDM4hepTool = lcio2edm4hepConv
+wrappedProcAlg.EDM4hep2LcioTool = edm4hep2LcioConv
+
+
+

An arbitrary number of converter tools can be instantiated and attached to Gaudi +algorithms (taking into account that each algorithm can at most have one +converter for each direction attached). If you have multiple tools make sure to +give them meaningful names in order to avoid any confusion.

+
+

Configuration options

+

By default each converter tool will try to convert the complete event content +that is currently available in the transient event store for the corresponding +source format. It will skip the conversion of a collection if the same +collection already exists in the other format. This check is done by collection +name. However, it is possible to control the conversion process with a +slightly higher granularity with two options that can be configured

+
    +
  • collNameMapping - this is a dictionary of collection names, where a source +collection name is mapped to a target collection name during the conversion. +This makes it possible to rename collections on the fly. In combination with +the convertAll option this also allows to select the collections that should +be converted. In that case if you want to keep the original collection name +you can simply repeat it.

  • +
  • convertAll - set this to False if you do not want to convert all +collections, but rather would like to select a subset to convert.

  • +
+

As an example, if you only want to convert the MCParticles collection, you +would configure the tool like this

+
edm4hep2LcioConv = EDM4hep2LcioTool("EDM4hep2Lcio")
+edm4hep2LcioConv.convertAll = False
+edm4hep2LcioConv.collNameMapping = {"MCParticles": "MCParticles"}
+
+
+

On the other hand if you want to convert all collections, but rename the +MCParticle (LCIO) input collection to the MCParticles (EDM4hep) output +collection in the process, you would configure the tool like so

+
lcio2edm4hepConv = Lcio2EDM4hepTool("Lcio2EDM4hep")
+lcio2edm4hepConv.collNameMapping = {"MCParticle": "MCParticles"}
+
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/how-tos/key4hep-tutorials/edm4hep_analysis/edm4hep_api_intro.html b/how-tos/key4hep-tutorials/edm4hep_analysis/edm4hep_api_intro.html new file mode 100644 index 0000000..60a5a5e --- /dev/null +++ b/how-tos/key4hep-tutorials/edm4hep_analysis/edm4hep_api_intro.html @@ -0,0 +1,700 @@ + + + + + + + EDM4hep - The common event data model — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

EDM4hep - The common event data model

+

EDM4hep is the common and shared Event Data Model (EDM) of the Key4hep project. +Here we will give a brief introduction to EDM4hep as well as some of the +technicalities behind it. We will also guide you towards documentation and try +to give you the knowledge to make sense of it.

+
+

Important resources

+ +
+
+

Doxygen API documentation

+

We start with having a look at the EDM4hep doxygen API reference +page:

+
+

The overview diagram

+

+

You see a diagrammatic overview of EDM4hep with all the available data types, +broadly organized into different categories. The arrows depict two ways data +types can be related / associated with each other

+ +
+

Relations

+

These are relations defined within the data types, and which are directly +accessible from the data types. They come in two flavors, depending on the +multiplicity of the relation

+
    +
  • OneToOneRelations

  • +
  • OneToManyRelations

  • +
+

Data types can relate to other instances of the same type (e.g. MCParticles +usually form a hierarchy of mothers/daughters). Relations are directed, i.e. it +is possible to go from one object to a related object, but vice versa this does +usually not hold. For example, a ReconstructedParticle can point to multiple +Tracks or Clusters, but those do not point to a ReconstructedParticle.

+
+
+

Associations

+

These are relations that are in a sense “external” to the data model definition. +They are currently mainly used to connect MC and RECO information, as a direct +link via a relation is not desirable as it would mix the two worlds. In contrast +to relations, associations are not directed, i.e. it is possible to access both +involved objects from the association.

+
+
+
+

The table of available types

+

Just below the diagram is an overview table of all the types that are defined in +EDM4hep. Here they are organized into

+
    +
  • Components - very simple types, that are used throughout the

  • +
  • Datatypes - The data types that are defined in EDM4hep

  • +
  • Association - The available associations between different data types

  • +
+

+

Clicking on any of these links will take you to the +edm4hep.yaml +definition file of EDM4hep, jumping directly to the definition of the respective +datatype or component. For more information on this file check out the section +about podio. In +principle it is possible to have very educated guesses on how the interface of +the classes will look like from this.

+
+ +
+

Some utility functionality

+

EDM4hep also brings a bit of utility functionality. You can find it in the +edm4hep::utils +namespace (click on +Namespaces -> Namespace List, then expand the edm4hep namespace and then +click on utils to arrive at this link).

+
+
+
+
+

podio - The technical infrastructure on which things run

+

podio is an EDM toolkit that is used by and developed further in the Key4hep +context. The main purpose is to have an efficiently implemented, thread safe EDM +starting from a high level description. For more (gory) details have a look at +the github repository.

+

Here we will describe the code generation, and its implications for EDM4hep. A +bit further down we will describe how to read and +write podio (root) files and the podio-dump tool to inspect +files without having to open them.

+
+

podio code generation

+

The podio code generator is a python script that reads in the EDM definition in +yaml format, does a few basic validation checks on the definition, and then +generates all the necessary code via the Jinja2 template engine.

+

+

The generated code should (among other things)

+
    +
  • be efficient,

  • +
  • offer an easy to use interface,

  • +
  • offer performant I/O.

  • +
+

Having automated code generation has a few advantages:

+
    +
  • Freeing the user from the repetitive task of implementing all the types +themselves

  • +
  • Freeing the user from having to deal with all the details of how to do things +efficiently

  • +
  • Making it very easy to roll out improved implementations (or bug fixes) via +simply regenerating the code

  • +
+
+

The three layers of podio

+

To achieve the goals stated above podio favors composition over inheritance and +uses plain-old-data (POD) types wherever possible. To achieve this podio +employs a layered design, which makes it possible to have an efficient memory +layout and performant I/O implementation, while still offering an easy to use +interface

+

+
    +
  • The User Layer is the top most layer and it offers the full +functionality and is the only layer with which users interact directly. +It consists mainly of the collections and lightweight handle classes, i.e.

    +
      +
    • XYZCollection

    • +
    • XYZ

    • +
    • MutableXYZ

    • +
    +
  • +
  • The Object Layer consists of the XYZObj classes, that take care of all +resource management and which also enable the relations between different +objects.

  • +
  • The POD Layer at the very bottom is where all the actual data lives in +simple XYZData POD structs. These are the things that are actually stored +in, e.g. root files that are written by podio.

  • +
+
+
+

Basics of generated code - value semantics

+

The generated c++ code offers so called value semantics. The exact details of +what this actually means are not very important, the main point is that you +can treat all objects as values and you don’t have to worry about inefficient +copies or managing resources:

+
auto recos = edm4hep::ReconstructedParticleCollection();
+
+// ... fill, e.g. via
+auto p = recos.create();
+// or via
+auto p2 = edm4hep::ReconstructedParticle();
+recos.push_back(p2); 
+
+// Loop over a collection
+for (auto reco : recos) {
+  auto vtx = reco.getStartVertex();
+  // do something with the vertex
+  
+  // loop over related tracks
+  for (auto track : reco.getTracks()) {
+    // do something with this track
+  }
+}
+
+
+

This looks very similar to the equivalent python code (if you squint a bit, and ignore the autos, ; and {} ;) )

+
recos = edm4hep.ReconstructedParticleCollection()
+
+# ... fill, e.g. via
+p = recos.create()
+# or via
+p2 = edm4hep.ReconstructedParticle()
+recos.push_back(p2)
+
+# Loop over a collection
+for reco in recos:
+  vtx = reco.getStartVertex()
+  # do something with the vertex
+  
+  # loop over related tracks
+  for track in reco.getTracks():
+    # do something with the tracks
+
+
+

The python interface is functionally equivalent to the one c++ interface, since +that is implemented via PyROOT. There are some additions that make the python +interface more pythonic, e.g. len(recos) is equivalent to recos.size(). +Nevertheless, the doxygen reference is valid for both interfaces.

+
+
+

Guessing the interface from the yaml definition

+

Since all code is generated, it is usually pretty straight forward to guess how +the interface will look like just from looking at the definition in the yaml +file. For EDM4hep the general rule is to get a Member variable, a +OneToOneRelation, a OneToManyRelation or a VectorMember is to simply +stick a get in front of the name in the yaml file and to capitalize the first +letter., e.g.

+
Members:
+  - edm4hep::Vector3f momentum // the momentum in [GeV]
+
+
+

will turn into something like

+
const edm4hep::Vector3f& getMomentum() const;
+
+
+

Similar, but in slightly more nuanced rules apply for the methods that are +generated for setting a value. For Member variables and OneToOneRelations +the general rule is to stick a set in front of the name in the yaml file and +to capitalize the first letter, e.g. (continuing from above)

+
void setMomentum(edm4hep::Vector3f value);
+
+
+

For the OneToManyRelations and VectorMembers the rule is to stick a +addTo in front of the name in the yaml file and to capitalize the first +letter, e.g.

+
OneToManyRelation:
+  - MCParticle daughters // the daughters of this particle
+
+
+

will be generated to

+
void addToDaughters(MCParticle daughter);
+
+
+
+
+

Why is there a XYZ and a MutableXYX?

+

The underlying technical reasons are rather complex, dive quite deepish into c++ +nuances, and definitely far beyond the scope of this tutorial. In short: We need +two different handle classes in order to control whether users are allowed to +modify things or not. As one of the main goals of podio generated EDMs is to be +thread safe the default generated class for each data type allows only for +immutable read access, i.e. it provides only the get methods. Only the +Mutable classes actually have the set methods, and can hence be used to +actually modify objects. The most important implication of this is the +following: Everything that you read from file, or that you get from the Gaudi +TES (in gaudi, or that +you get from a Frame) is immutable. I.e. there +is no way for you to change or update the values that you read. The only way to +“update” values (or collections) is to actually copy the contents and then store +the updated values back. Independent copies of objects can be obtained with the +clone method.

+
+
+

Writing function interfaces

+

The Mutable objects implicitly convert to an instance of a default class. +Hence, always use the default classes when specifying function interfaces +(obviously this only works if you only need read access in the function. There +is no implicit conversion from the default, immutable objects to the Mutable +objects!

+

As an example

+
void printE(edm4hep::MCParticle particle) {
+  std::cout << particle.getEnergy() << '\n';
+}
+
+void printEMutable(edm4hep::MutableMCParticle particle) {
+  std::cout << particle.getEnergy() << '\n';
+}
+
+int main() {
+  auto mutP = edm4hep::MutableMCParticle();
+  p.setEnergy(3.14);
+  
+  printE(mutP);  // Works due to implicit conversion
+  printEMutable(mutP);  // Obviously also works
+  
+  // Now we create an immutable object
+  auto P = edm4hep::MCParticle();
+  
+  printE(P);  // Obviously works
+  printEMutable(P);  // BREAKS: No conversion from default to Mutable
+
+  return 0;
+}
+
+
+
+
+

Subset collections

+

Similar to LCIO, podio generated EDMs offer a subset collection functionality. +This allows to create collections of objects, that are actually part of another +collection, e.g. to simply collect all the muons that are present in a larger +collection of reconstructed particles:

+

+

To create a subset collection, simply do

+
auto muons = edm4hep::ReconstructedParticleCollection();
+muons.setSubsetCollection();
+
+// You can now add objects that are part 
+// of another collection to this one via push_back
+muons.push_back(recos[0]);
+
+
+

Reading a subset collection works exactly the same as reading a normal +collection. This is handled in a transparent way, such that you usually don’t +even realize that you are operating on a subset collection.

+
+
+
+

The podio::Frame container

+

The podio::Frame is a generalized event. It is a container that aggregates +all relevant data (and some meta data). It also defines an implicit interval of +validity (but that is less relevant for this tutorial). It provides a thread +safe interface for data access

+
    +
  • Immutable read access only for collections that are stored inside the a +Frame

  • +
  • All data that is inside a Frame is owned by it, and this is also reflected +in its interface.

  • +
+

+

Here we will just briefly introduce the main functionality, for more details see +the documentation in +podio.

+
+

Getting collections from a Frame

+

Assuming that event is a podio::Frame in the following code examples, +getting a collection can be done via (c++)

+
auto& mcParticles = event.get<edm4hep::MCParticleCollection>("MCParticles"); 
+
+
+

or (python)

+
mcParticles = event.get("MCParticles")
+
+
+

This retrieves the collection that is stored under the name MCParticles with +type edm4hep::MCParticleCollection. If no such collection exists, it will +simply return an empty collection of the desired type. As you can see, the type +is automatically inferred in python. Note that get returns a const&, so it +is required to actually put the & behind auto in c++, otherwise there will +be a compilation error complaining about a copy-constructor being marked +delete.

+
+
+

Putting a collection into a Frame

+

When putting a collection into a Frame you give up ownership of this +collection. To signal this to the users, it is necessary to move the +collection into a Frame. Again assuming event is a podio::Frame in the +following examples, this looks like this

+
auto recos = edm4hep::ReconstructedParticleCollection();
+event.put(std::move(recos), "ReconstructedParticles");
+
+
+

Note the requirement to explicitly use std::move in this case. At this point +recos is moved into the event, and you are left with an object in a +valid but unspecified state that you +should under normal circumstances no longer use after this point. (Technically +we do enough that you still can use this, but don’t expect the results to match +your expectations).

+
+
+
+

Reading EDM4hep files

+

EDM4hep files are read with tools provided by podio. As podio supports multiple +different backends there are several, low level readers that support all the +necessary functionality. You can obviously use these readers directly, but we +recommend to use the Reader class and the makeReader function that will +dispatch to the correct low level reader automatically.

+
#include <podio/Reader.h>
+
+#include <edm4hep/MCParticleCollection.h>
+
+int main() {
+  auto reader = podio::makeReader("some_file_containing_edm4hep.data.root");
+
+  // Loop over all events
+  for (size_t i = 0; i < reader.getEvents(); ++i) {
+    auto event = reader.readNextEvent());
+    auto& mcParticles = event.get<edm4hep::MCParticleCollection>("MCParticles");
+
+    // do more stuff with this event
+  }
+
+  return 0;
+}
+
+
+
+

The available low level readers

+
    +
  • ROOTReader - The default reader for TTree based files

  • +
  • ROOTLegacyReader - The reader for an old podio format based on TTrees

  • +
  • RNTupleReader - A reader for RNTuple based files

  • +
  • SIOReader - The reader for reading files using the SIO backend

  • +
  • SIOLegacyReader - The reader for the SIO backend with an old podio format

  • +
+

The Legacy readers are stated here mainly for completeness, in case you need +to read a rather old file that still used the EventStore which has been +removed from podio some time ago. See +here for more information on how to +figure out whether the file you are interested in is a legacy file or not. +As podio is a rather low level tool, also the interface of these readers feel +somewhat low level. This is mostly visible in the fact, that you have to provide +a category (name) when getting the number of entries, or when reading the next +entry. This is because in principle podio can handle multiple different +categories of Frames in one file. For the purpose of this tutorial and also +for the majority of use cases, simply use "events" as category name. Readers +in podio do not return a podio::Frame directly, rather they just return some +frame data from which a podio::Frame can be constructed. Putting all of +these things together, a simple event loop looks like this in c++:

+
#include "podio/ROOTReader.h"
+#include "podio/Frame.h"
+
+#include "edm4hep/MCParticleCollection.h"
+
+int main() {
+  auto reader = podio::ROOTReader();
+  reader.openFile("some_file_containing_edm4hep_data.root");
+  
+  // Loop over all events
+  for (size_t i = 0; i < reader.getEntries("events"); ++i) {
+    auto event = podio::Frame(reader.readNextEntry("events"));
+    auto& mcParticles = event.get<edm4hep::MCParticleCollection>("MCParticles");
+    
+    // do more stuff with this event
+  }
+
+  return 0;
+}
+
+
+

The equivalent python code looks like this

+
from podio import root_io
+
+reader = root_io.Reader("some_file_containing_edm4hep_data.root")
+# if you want to read legacy files use root_io.LegacyReader
+
+for event in reader.get("events"):
+  mcParticles = event.get("MCParticles")
+  # do more stuff with this event
+
+
+
+
+
+

ROOT file layout of podio generated EDMs

+

podio generated EDMs, i.e. also EDM4hep, use ROOT as their default I/O backend. +Since everything is based on PODs, the produced root files are pretty straight +forward to read and interpret (with some caveats). They are already almost flat +ntuples.

+

+

+
+

How do I figure out if a file is legacy?

+
    +
  1. Use podio-dump and it will tell you

  2. +
+
$podio-dump /home/workarea/data/rv02-02.sv02-02.mILD_l5_o1_v02.E250-SetA.I402003.Pe2e2h.eL.pR.n000.d_dstm_15089_0_edm4hep.root
+input file: /home/workarea/data/rv02-02.sv02-02.mILD_l5_o1_v02.E250-SetA.I402003.Pe2e2h.eL.pR.n000.d_dstm_15089_0_edm4hep.root
+
+Frame categories in this file (this is a legacy file!):
+[...]
+
+
+
    +
  1. Peek inside the root file and look at the contents

  2. +
+

+
+
+
+

podio-dump

+

The podio-dump utility allows to inspect EDM4hep files from the command line. +The synopsis looks like this

+
$podio-dump --help
+usage: podio-dump [-h] [-c CATEGORY] [-e ENTRIES] [-d] [--dump-edm DUMP_EDM] [--version] inputfile
+
+Dump contents of a podio file to stdout
+
+positional arguments:
+  inputfile             Name of the file to dump content from
+
+options:
+  -h, --help            show this help message and exit
+  -c CATEGORY, --category CATEGORY
+                        Which Frame category to dump
+  -e ENTRIES, --entries ENTRIES
+                        Which entries to print. A single number, comma separated list of numbers or "first:last" for an inclusive range of entries. Defaults to the first entry.
+  -d, --detailed        Dump the full contents not just the collection info
+  --dump-edm DUMP_EDM   Dump the specified EDM definition from the file in yaml format
+  --version             show program's version number and exit
+
+
+

By default it prints how many events are present in the file and also a summary +of the contents of the first event. This overview consists of the names, data +types and number of elements of the collections that are stored in this event. +Using the --detailed flag, podio-dump will print the complete contents of +all collections in ASCII format. This can be quite a bit of information. Using +the --entries flag it is possible to choose which events to look at. The +--categories flag is an advanced feature and not necessary for this tutorial.

+

podio-dump will also tell you whether the file that is passed to it is a +legacy file in which case you will need the ROOTLegacyReader or the +SIOLegacyReader to read it.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..36bf52b --- /dev/null +++ b/index.html @@ -0,0 +1,292 @@ + + + + + + + Key4hep — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Key4hep

+
+

Contents:

+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 0000000..490cb19 Binary files /dev/null and b/objects.inv differ diff --git a/search.html b/search.html new file mode 100644 index 0000000..393f8b3 --- /dev/null +++ b/search.html @@ -0,0 +1,140 @@ + + + + + + Search — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + + + +
+ +
+ +
+
+ +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 0000000..956410a --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": [".github/scripts/yamlheader", "CONDUCT", "CONTRIBUTING", "LICENSE", "call-for-logos/README", "developing-key4hep-software/CMakeBuild", "developing-key4hep-software/Key4hepCMakeGuide", "developing-key4hep-software/Key4hepSoftwareGit", "developing-key4hep-software/README", "developing-key4hep-software/SinglePackage", "developing-key4hep-software/SpackForDevelopers", "developing-key4hep-software/WritingAlgorithms", "how-tos/README", "how-tos/k4edm4hep2lcioconv/doc/LCIO2EDM4hep", "how-tos/k4fwcore/doc/PodioInputOutput", "how-tos/k4fwcore/doc/k4run-args", "how-tos/k4marlinwrapper/doc/MarlinWrapperIntroduction", "how-tos/key4hep-tutorials/edm4hep_analysis/edm4hep_api_intro", "index", "setup-and-getting-started/README", "spack-build-instructions-for-librarians/README", "spack-build-instructions-for-librarians/spack-advanced", "spack-build-instructions-for-librarians/spack-buildcache", "spack-build-instructions-for-librarians/spack-nightlies", "spack-build-instructions-for-librarians/spack-setup", "talks-and-presentations/README", "tutorials/README", "tutorials/k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/CEDViaWrapper", "tutorials/k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/Readme", "tutorials/k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/howtoMultithread", "tutorials/k4simdelphes/doc/starterkit/k4SimDelphes/Readme", "tutorials/key4hep-tutorials/gaudi_ild_reco/README"], "filenames": [".github/scripts/yamlheader.md", "CONDUCT.md", "CONTRIBUTING.md", "LICENSE.md", "call-for-logos/README.md", "developing-key4hep-software/CMakeBuild.md", "developing-key4hep-software/Key4hepCMakeGuide.md", "developing-key4hep-software/Key4hepSoftwareGit.md", "developing-key4hep-software/README.md", "developing-key4hep-software/SinglePackage.md", "developing-key4hep-software/SpackForDevelopers.md", "developing-key4hep-software/WritingAlgorithms.md", "how-tos/README.md", "how-tos/k4edm4hep2lcioconv/doc/LCIO2EDM4hep.md", "how-tos/k4fwcore/doc/PodioInputOutput.md", "how-tos/k4fwcore/doc/k4run-args.md", "how-tos/k4marlinwrapper/doc/MarlinWrapperIntroduction.md", "how-tos/key4hep-tutorials/edm4hep_analysis/edm4hep_api_intro.md", "index.md", "setup-and-getting-started/README.md", "spack-build-instructions-for-librarians/README.md", "spack-build-instructions-for-librarians/spack-advanced.md", "spack-build-instructions-for-librarians/spack-buildcache.md", "spack-build-instructions-for-librarians/spack-nightlies.md", "spack-build-instructions-for-librarians/spack-setup.md", "talks-and-presentations/README.md", "tutorials/README.md", "tutorials/k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/CEDViaWrapper.md", "tutorials/k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/Readme.md", "tutorials/k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/howtoMultithread.md", "tutorials/k4simdelphes/doc/starterkit/k4SimDelphes/Readme.md", "tutorials/key4hep-tutorials/gaudi_ild_reco/README.md"], "titles": ["<no title>", "Contributor Code of Conduct", "Contributing", "Software", "Call for logos", "Building Key4hep using CMake: For Developers", "CMake guide for Key4hep software", "Github workflow and contribution guide", "Developing Key4hep", "Developing a single package", "Building Key4hep using Spack: For Developers", "Writing Gaudi Algorithms", "Key4hep How-Tos and Instructions", "Standalone conversion from LCIO to EDM4hep", "Reading and writing EDM4hep files in Gaudi", "Adding custom arguments to k4run", "Wrapping Marlin processors in Gaudi", "EDM4hep - The common event data model", "Key4hep", "Getting started with Key4hep software", "Building Key4hep: For Librarians", "Spack Usage and Further Technical Topics", "Spack Buildcaches", "Nightly Builds with Spack", "Setting up Spack", "Talks and Presentations", "Key4hep Tutorials", "Running an Event Display with EDM4hep or LCIO input", "Using the Key4hep-Stack for CLIC Simulation and Reconstruction", "How to run multithreading with k4MarlinWrapper (Gaudi)", "Running Delphes fast simulation with EDM4hep output", "Running ILD simulation and reconstruction"], "terms": {"As": [1, 10, 16, 17], "maintain": 1, "thi": [1, 2, 5, 6, 7, 9, 10, 11, 12, 13, 14, 16, 17, 20, 21, 22, 24, 26, 27, 28, 29, 30, 31], "project": [1, 2, 10, 11, 17, 22], "we": [1, 2, 5, 7, 9, 10, 11, 13, 14, 16, 17, 19, 21, 25, 26, 27, 28, 30, 31], "pledg": 1, "respect": [1, 16, 17, 31], "all": [1, 2, 5, 6, 7, 8, 11, 13, 14, 16, 21, 22, 26, 27, 28, 29, 30, 31], "peopl": [1, 6, 7], "who": 1, "contribut": [1, 8, 18, 25], "through": [1, 7, 11, 13, 26], "report": [1, 2], "issu": [1, 2, 7, 14, 16, 21, 26, 31], "post": [1, 17], "featur": [1, 7, 10, 17, 19, 31], "request": [1, 2, 6, 8], "updat": [1, 6, 17, 25, 28], "document": [1, 10, 11, 15, 18, 20, 22], "submit": [1, 2], "pull": [1, 2, 8, 31], "patch": [1, 10, 18, 21], "other": [1, 3, 6, 8, 11, 14, 16, 17, 18, 21, 22, 24, 26, 28, 31], "activ": [1, 10, 24], "ar": [1, 2, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 16, 19, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31], "commit": [1, 8, 10, 22, 23], "make": [1, 2, 5, 6, 7, 10, 11, 13, 14, 16, 17, 19, 24, 27, 29, 31], "particip": 1, "harass": 1, "free": [1, 2, 6, 7, 17], "experi": [1, 8, 10, 18, 25], "everyon": 1, "regardless": [1, 21], "level": [1, 6, 11, 14, 29, 31], "gender": 1, "ident": 1, "express": [1, 6], "sexual": 1, "orient": 1, "disabl": [1, 10], "person": 1, "appear": [1, 5, 13], "bodi": 1, "size": [1, 17], "race": 1, "ethnic": 1, "ag": 1, "religion": 1, "exampl": [1, 3, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 21, 24, 26, 27, 28, 30, 31], "unaccept": 1, "behaviour": 1, "includ": [1, 5, 6, 9, 10, 11, 13, 14, 16, 17, 21, 23, 28, 31], "us": [1, 2, 7, 8, 9, 13, 14, 15, 17, 18, 20, 22, 23, 26, 29, 30], "languag": 1, "imageri": 1, "derogatori": 1, "comment": [1, 2, 8, 16, 28, 31], "attack": 1, "troll": 1, "public": 1, "privat": 1, "insult": 1, "unprofession": 1, "have": [1, 2, 6, 8, 9, 10, 11, 13, 14, 16, 17, 19, 21, 26, 27, 28, 29, 30, 31], "right": [1, 5, 21, 24], "respons": [1, 13], "remov": [1, 6, 8, 11, 17, 28], "edit": [1, 5, 10, 31], "reject": 1, "wiki": 1, "align": 1, "do": [1, 5, 6, 8, 9, 10, 11, 13, 14, 16, 21, 27, 28, 29, 30, 31], "follow": [1, 5, 6, 7, 10, 14, 16, 17, 20, 21, 22, 24, 26, 27, 28, 29, 30, 31], "mai": [1, 2, 5, 6, 7, 10, 11, 14, 28, 29], "from": [1, 2, 5, 6, 7, 10, 11, 12, 14, 15, 16, 18, 19, 21, 22, 24, 26, 27, 28, 29, 30], "team": [1, 2, 6], "instanc": [1, 15, 16, 17, 18, 20], "abus": 1, "otherwis": [1, 3, 10, 11, 13, 14, 17, 21], "open": [1, 2, 7, 17, 26], "an": [1, 2, 5, 6, 8, 11, 13, 14, 16, 17, 18, 21, 22, 23, 24, 26, 28, 29, 30, 31], "contact": [1, 6], "one": [1, 5, 7, 9, 10, 11, 13, 16, 17, 21, 24, 27, 28, 30, 31], "more": [1, 2, 6, 7, 8, 9, 11, 17, 20, 21, 22, 27, 31], "i": [1, 2, 5, 8, 9, 10, 11, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31], "adapt": [1, 26, 28, 29], "coven": 1, "version": [1, 5, 7, 8, 9, 11, 17, 19, 21, 22, 23, 24], "1": [1, 4, 6, 7, 10, 11, 16, 21, 24, 28, 29, 31], "0": [1, 3, 10, 15, 17, 21, 24], "avail": [1, 3, 6, 10, 11, 13, 14, 16, 19, 21, 24, 26, 29, 30, 31], "http": [1, 6, 8, 10, 11, 21, 22, 24, 25, 27, 28, 30, 31], "org": [1, 5, 6, 10, 19, 20, 21, 23, 24, 25, 27, 28, 30, 31], "key4hep": [2, 7, 9, 11, 14, 16, 17, 21, 22, 23, 25, 27, 31], "sourc": [2, 5, 6, 7, 9, 10, 16, 19, 20, 23, 24, 27, 28, 30, 31], "welcom": 2, "kind": [2, 11], "new": [2, 5, 6, 7, 10, 19, 24, 26, 28, 31], "lesson": 2, "fix": [2, 6, 7, 16, 17], "exist": [2, 13, 16, 17, 22, 24, 30, 31], "materi": [2, 12], "bug": [2, 7, 17], "review": 2, "propos": 2, "chang": [2, 8, 9, 10, 11, 14, 16, 17, 18, 19, 21, 23, 24, 27, 28, 31], "By": [2, 11, 14, 16, 17, 24], "you": [2, 5, 6, 7, 8, 10, 11, 14, 16, 17, 21, 26, 27, 28, 29, 30, 31], "agre": 2, "redistribut": 2, "your": [2, 8, 10, 14, 17, 18, 27, 28, 29, 30, 31], "work": [2, 5, 6, 7, 9, 10, 11, 14, 15, 16, 17, 21, 25, 26, 27, 31], "under": [2, 3, 5, 10, 13, 17, 21, 22, 24, 29], "licens": 2, "also": [2, 6, 7, 9, 10, 11, 13, 14, 16, 17, 19, 21, 22, 23, 24, 26, 27, 28, 30, 31], "abid": 2, "our": [2, 9, 11], "contributor": [2, 18, 21], "code": [2, 6, 8, 10, 11, 18, 23], "conduct": [2, 18], "fork": [2, 7, 24], "model": [2, 12, 14, 16, 18, 27, 31], "manag": [2, 17, 20, 29], "inform": [2, 5, 7, 10, 13, 14, 17, 19, 21, 22, 26], "about": [2, 10, 11, 17, 21], "repositori": [2, 5, 8, 11, 17, 23, 24, 26, 27, 28], "should": [2, 5, 6, 7, 10, 14, 16, 17, 24, 27, 28, 30, 31], "branch": [2, 7, 23], "against": [2, 22], "main": [2, 5, 6, 7, 9, 10, 11, 13, 16, 17, 23, 27, 29, 31], "some": [2, 5, 6, 7, 8, 9, 10, 11, 13, 14, 16, 19, 20, 21, 22, 23, 24, 27, 28, 29, 30, 31], "still": [2, 10, 13, 14, 16, 17, 21, 24, 31], "master": [2, 5, 7, 10, 22, 24], "futur": [2, 11, 16, 25], "If": [2, 5, 7, 10, 11, 13, 16, 17, 26, 27, 29, 31], "re": [2, 7, 10, 11, 21, 22, 24], "look": [2, 6, 7, 10, 11, 13, 14, 16, 17, 27, 31], "thing": [2, 5, 10, 12, 15, 18, 21, 31], "feel": [2, 6, 7, 17, 26], "touch": [2, 7], "dash": 2, "sw": [2, 5, 6, 7, 10, 19, 20, 21, 23, 24, 27, 28, 30, 31], "cern": [2, 7, 11, 17, 21, 22, 24, 25], "dot": 2, "ch": [2, 17, 21, 22, 24, 25], "can": [2, 5, 6, 8, 9, 10, 11, 13, 14, 16, 17, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], "list": [2, 6, 7, 11, 13, 14, 16, 17, 24, 25, 26, 27, 28, 29, 31], "equal": 2, "except": 3, "where": [3, 5, 7, 9, 10, 11, 16, 17, 24, 25, 28, 31], "note": [3, 6, 7, 10, 16, 17, 21, 24, 28, 31], "program": [3, 17, 20, 25, 27], "provid": [3, 6, 7, 10, 11, 13, 14, 16, 17, 21, 24, 27, 30, 31], "carpentri": 3, "made": [3, 6, 10, 14, 21], "osi": 3, "approv": 3, "apach": 3, "2": [3, 4, 5, 7, 10, 21, 24], "3": [4, 7, 10, 17, 21, 25, 28, 29, 31], "4": [4, 10, 11, 21, 29], "5": [4, 21, 25], "6": [4, 10, 21], "7": [4, 21], "A": [5, 10, 13, 14, 17, 20, 21, 22, 25, 29], "common": [5, 12, 14, 18, 24, 25], "problem": [5, 21], "when": [5, 6, 8, 9, 10, 11, 17, 21, 27, 28, 30], "need": [5, 6, 8, 9, 10, 11, 14, 16, 18, 20, 21, 22, 24, 27, 28, 29, 30, 31], "multipl": [5, 8, 11, 16, 17, 18, 29], "top": [5, 6, 10, 17, 31], "stack": [5, 9, 10, 11, 12, 16, 18, 20, 21, 22, 23, 24, 25, 26, 30], "sever": [5, 7, 11, 17, 21, 26, 31], "One": [5, 10, 11, 16], "wai": [5, 7, 9, 10, 11, 13, 16, 17, 21, 24, 26, 28, 29, 30, 31], "spack": [5, 6, 8, 18, 20, 25, 28, 30], "experiment": 5, "first": [5, 6, 8, 10, 11, 13, 16, 17, 18, 27, 28, 29, 31], "releas": [5, 9, 10, 18, 19, 20, 22, 23, 27, 28, 30], "nightli": [5, 9, 10, 19, 27], "usual": [5, 6, 10, 16, 17, 21], "Then": [5, 10, 11, 28], "run": [5, 7, 8, 10, 11, 12, 15, 16, 18, 23, 24, 26, 28], "command": [5, 6, 7, 10, 14, 17, 21, 22, 24, 27, 28, 31], "cvmf": [5, 6, 9, 10, 11, 18, 20, 24, 27, 28, 30, 31], "hsf": [5, 6, 10, 19, 20, 21, 23, 24, 25, 27, 28, 30, 31], "setup": [5, 6, 8, 18, 19, 20, 21, 23, 24, 26, 27, 28, 29], "py": [5, 6, 10, 11, 16, 26, 27, 28], "pkg1": 5, "pkg2": 5, "clone": [5, 6, 8, 10, 11, 17, 24, 27, 28, 31], "empti": [5, 11, 13, 14, 16, 17], "On": [5, 16], "check": [5, 6, 7, 10, 11, 16, 17, 29, 31], "folder": [5, 6, 10, 28, 31], "symbol": 5, "link": [5, 6, 10, 11, 13, 17, 24], "current": [5, 7, 10, 14, 16, 17, 19, 21, 24], "directori": [5, 6, 10, 21, 22, 24, 27, 31], "contain": [5, 6, 10, 11, 12, 13, 18, 21, 26, 27, 28, 30, 31], "cmakelist": [5, 6], "txt": [5, 6, 10, 13], "want": [5, 6, 7, 10, 11, 14, 16, 17, 25, 27, 29, 31], "local": [5, 8, 9, 21, 24], "don": [5, 7, 11, 17, 19, 31], "t": [5, 8, 10, 11, 17, 19, 21, 31], "after": [5, 9, 10, 11, 13, 17, 19, 29, 31], "file": [5, 6, 7, 8, 10, 12, 13, 15, 18, 21, 22, 24, 26, 28, 29, 30], "manual": [5, 9, 10], "recogn": 5, "organ": [5, 17], "than": [5, 8, 10, 11, 12, 13, 19, 27], "predefin": 5, "ones": [5, 9, 10, 17, 21, 24, 28, 30], "The": [5, 6, 7, 8, 10, 12, 13, 15, 18, 19, 20, 21, 22, 23, 24, 25, 27, 28, 29, 30, 31], "ll": [5, 7, 11], "most": [5, 6, 7, 10, 11, 13, 14, 16, 17, 19, 27], "like": [5, 6, 7, 10, 11, 13, 14, 16, 17, 21, 26, 27, 31], "line": [5, 6, 7, 10, 11, 13, 14, 17, 21, 28, 31], "set": [5, 8, 9, 11, 16, 17, 18, 20, 23, 26, 29], "pkg": 5, "edm4hep": [5, 10, 11, 12, 16, 18, 24, 26, 29], "k4fwcore": [5, 11, 14, 15], "built": [5, 9, 10, 11, 22], "order": [5, 6, 10, 11, 16, 17, 21, 22, 23, 24, 27, 30, 31], "individu": [5, 7, 13, 21, 23], "fetchcontent_declar": 5, "entri": [5, 13, 16, 17, 31], "each": [5, 7, 10, 11, 13, 14, 16, 17, 29], "happi": [5, 7, 10, 26], "": [5, 7, 9, 10, 11, 13, 16, 17, 18, 21, 28, 29, 30, 31], "import": [5, 6, 10, 11, 14, 15, 16, 18, 19, 21, 27, 28, 29, 31], "environ": [5, 8, 9, 11, 16, 18, 19, 20, 26, 28, 29, 31], "variabl": [5, 6, 9, 11, 16, 17, 31], "mkdir": [5, 6, 11, 31], "instal": [5, 7, 8, 9, 11, 18, 20, 22, 23, 27, 28, 30], "cd": [5, 6, 7, 10, 11, 28, 31], "export": [5, 6, 9], "path": [5, 6, 9, 10, 14, 21, 24, 28], "pwd": [5, 6, 24], "bin": [5, 6, 9], "ld_library_path": [5, 6, 9], "lib": [5, 6, 9, 21], "lib64": [5, 6, 9], "root_include_path": [5, 6, 9], "pythonpath": [5, 6, 9], "python": [5, 6, 9, 10, 11, 15, 16, 17, 21, 28], "cmake_prefix_path": [5, 6], "dcmake_install_prefix": [5, 6, 9, 11], "j": [5, 6, 11], "n": [5, 16, 17, 28, 29, 31], "same": [5, 7, 10, 11, 13, 16, 17, 21, 22, 24, 30, 31], "time": [5, 8, 9, 11, 17, 18, 19, 26], "so": [5, 6, 7, 9, 10, 11, 15, 16, 19, 20, 21, 22, 24, 25, 27, 31], "take": [5, 7, 10, 11, 13, 14, 16, 17, 21, 22, 27, 29, 31], "creat": [5, 6, 7, 10, 11, 13, 16, 17, 18, 20, 21, 22, 24, 26, 28, 29, 30], "allow": [5, 7, 10, 11, 14, 16, 17, 21, 31], "u": [5, 11, 22, 26], "ctest": [5, 8, 18, 29], "case": [5, 6, 7, 10, 11, 13, 14, 16, 17, 21, 27, 28, 30, 31], "done": [5, 6, 7, 10, 13, 16, 17, 21, 26, 27, 31], "Not": [5, 29], "everyth": [5, 10, 11, 14, 16, 17, 27], "ha": [5, 6, 9, 10, 11, 13, 16, 17, 21, 24, 27, 31], "won": [5, 11], "mani": [5, 7, 9, 10, 21, 29], "recent": [5, 10], "enabl": [5, 16, 17, 28], "older": [5, 19], "probabl": [5, 10, 27], "togeth": [5, 10, 11, 17, 24], "successfulli": [5, 10], "ani": [5, 6, 7, 8, 9, 10, 11, 16, 17, 19, 21, 26, 27, 31], "combin": [5, 11, 16, 29], "them": [5, 6, 10, 11, 13, 16, 21, 24, 26, 27], "podio": [5, 10, 12, 13, 14, 18, 31], "lcio": [5, 10, 12, 17, 18, 21, 26, 29, 31], "ilcutil": 5, "lccd": 5, "gear": 5, "marlin": [5, 10, 12, 18, 26, 27, 29, 31], "k4edm4hep2lcioconv": [5, 13], "k4marlinwrapp": [5, 18, 26, 27, 31], "two": [5, 10, 11, 13, 16, 17, 19, 28, 29], "option": [5, 6, 11, 13, 14, 17, 21, 24, 26, 27, 29], "correspond": [5, 7, 10, 11, 13, 16, 31], "git_tag": 5, "whatev": [5, 10, 11, 31], "checkout": [5, 10], "go": [5, 10, 11, 14, 17, 25, 27, 30], "which": [5, 6, 7, 9, 10, 11, 12, 13, 14, 16, 18, 23, 24, 26, 27, 28, 29, 30, 31], "found": [5, 6, 7, 10, 11, 16, 25, 27, 28], "_dep": 5, "src": [5, 6, 11], "tool": [6, 7, 11, 16, 17, 20, 22, 23, 25, 31], "becom": [6, 10, 14], "de": [6, 13], "facto": 6, "standard": [6, 16, 30, 31], "outsid": 6, "hep": [6, 7, 21, 25, 30], "In": [6, 7, 10, 11, 13, 16, 17, 19, 20, 21, 22, 23, 24, 27, 28, 29, 30, 31], "ilc": [6, 13, 18], "clic": [6, 18, 26, 27, 29], "commun": [6, 16], "lhcb": [6, 11, 16], "collabor": [6, 25], "For": [6, 7, 8, 9, 11, 13, 16, 17, 18, 21, 22, 23, 24, 30, 31], "cm": 6, "equival": [6, 17], "scram": 6, "step": [6, 7, 10, 13, 24, 27, 28, 31], "ad": [6, 7, 8, 11, 12, 14, 18, 22, 24, 31], "depend": [6, 8, 9, 11, 13, 17, 18, 20, 24, 27, 28, 31], "bash": [6, 10, 21], "unsur": 6, "best": [6, 10, 21, 27], "default": [6, 11, 14, 15, 16, 17, 21, 24, 27, 29, 30, 31], "init": [6, 29], "script": [6, 16, 17, 19, 20, 21, 23, 24, 31], "centos7": [6, 19, 20, 23, 24], "sh": [6, 10, 19, 20, 23, 24, 27, 28, 30, 31], "mix": [6, 17], "anoth": [6, 8, 11, 17, 21, 28], "intend": [6, 10, 11, 17, 19, 22], "mail": [6, 7], "channel": [6, 10], "develop": [6, 11, 16, 17, 18, 19, 21, 23, 24, 25, 31], "fine": 6, "grain": 6, "control": [6, 16, 17], "over": [6, 11, 17, 21, 22, 27, 29], "rerun": 6, "dcmake_build_typ": 6, "debug": [6, 8, 18, 21, 24, 29], "ccmake": 6, "compil": [6, 7, 9, 10, 11, 17, 20, 22, 29], "cpu": 6, "getconf": 6, "_nprocessors_onln": 6, "content": [6, 10, 13, 14, 16, 17, 30], "just": [6, 10, 11, 14, 15, 16, 17, 20, 21, 24, 31], "few": [6, 7, 10, 11, 12, 13, 16, 17, 19, 21, 24, 27, 28, 31], "assum": [6, 10, 13, 14, 16, 17, 24, 27, 28, 30, 31], "installarea": 6, "execut": [6, 13, 16, 18, 26, 27], "librari": [6, 12, 18, 21], "plugin": 6, "system": [6, 24], "gaudi": [6, 8, 12, 17, 18, 26, 27], "dd4hep": [6, 10, 26, 27], "root": [6, 10, 11, 13, 14, 18, 21, 27, 28, 30, 31], "dictionari": [6, 10, 16], "packagenam": 6, "share": [6, 10, 17, 21, 24], "distribut": [6, 19, 21, 27], "data": [6, 11, 12, 14, 16, 18, 29, 31], "special": 6, "name": [6, 7, 10, 11, 13, 14, 16, 17, 27, 28, 30, 31], "cap": 6, "e": [6, 7, 10, 13, 14, 16, 17, 21, 27, 30, 31], "g": [6, 7, 10, 13, 14, 16, 17, 21, 27, 30], "k4simdelph": [6, 7, 10, 30], "colin": 6, "simpl": [6, 10, 11, 16, 17, 27], "thei": [6, 7, 10, 11, 12, 13, 16, 17, 19, 22, 24, 26, 30], "help": [6, 8, 11, 15, 17, 18, 21, 30], "understand": [6, 17], "basic": [6, 13, 16, 24, 27], "get": [6, 8, 10, 11, 13, 18, 27, 28, 30, 31], "git": [6, 8, 10, 11, 18, 21, 24, 27, 28, 31], "github": [6, 8, 10, 11, 17, 18, 21, 24, 27, 28, 31], "com": [6, 7, 10, 11, 17, 21, 24, 27, 28, 30, 31], "cbernet": 6, "instruct": [6, 7, 10, 18, 19, 24, 30, 31], "readm": [6, 11], "md": [6, 8, 11], "awar": [6, 7, 14], "wildcard": [6, 14], "add": [6, 7, 10, 11, 17, 21, 22, 24, 26, 27, 28, 31], "implement": [6, 10, 11, 13, 16, 17], "subfold": 6, "cpp": [6, 11], "explicitli": [6, 10, 16, 17, 28, 31], "To": [6, 7, 10, 11, 14, 16, 17, 21, 27, 28, 29, 30, 31], "fastest": 6, "properti": [6, 11, 29], "algorithm": [6, 8, 14, 18, 28, 29, 31], "onli": [6, 7, 10, 11, 15, 16, 17, 18, 21, 22, 24, 27, 29, 31], "particular": [6, 11, 30, 31], "framework": [6, 11, 14, 16, 18, 26, 31], "compon": [6, 11, 17, 29], "consist": [6, 13, 14, 17, 21], "header": [6, 13], "dynam": [6, 16], "xml": [6, 10, 18, 27, 28, 31], "describ": [6, 7, 10, 11, 14, 16, 17, 30], "offer": [6, 17, 30], "possibl": [6, 9, 10, 11, 13, 14, 15, 16, 17, 21, 22, 27, 30, 31], "via": [6, 7, 10, 14, 16, 17, 21, 27, 28, 30, 31], "xenv": 6, "simpli": [6, 10, 11, 13, 14, 16, 17, 24, 27, 31], "prefix": [6, 10, 21], "fccsw": [6, 7], "directli": [6, 10, 13, 16, 17, 27, 31], "key4run": 6, "pythia": [6, 7, 30], "sometim": [6, 10, 14, 24], "conveni": [6, 13, 31], "binari": [6, 22], "without": [6, 9, 10, 16, 17, 19, 21, 22], "differ": [6, 7, 10, 11, 16, 17, 18, 21, 22, 27, 30, 31], "bit": [6, 17, 31], "mostli": [6, 12, 17, 24], "pre": [6, 24], "fccrun": 6, "pick": [6, 9, 10, 21], "integr": [6, 7, 30], "test": [6, 7, 10, 11, 19, 23, 27, 28, 29], "add_test": 6, "see": [6, 7, 10, 11, 13, 17, 21, 24, 27, 30, 31], "fcc": [6, 7, 18, 25, 30], "k4gen": 6, "blob": [6, 11, 24], "forward": [6, 10, 13, 17, 31], "argument": [6, 10, 11, 12, 13, 17, 18, 21, 27, 28, 30, 31], "trace": 6, "cmakeflag": 6, "callout": [6, 7, 22], "flag": [6, 13, 17, 21, 31], "instead": [6, 7, 9, 10, 15, 21, 28], "verbos": [6, 21, 29], "endcallout": [6, 7, 22], "page": [7, 8, 10, 12, 14, 16, 20, 21, 26], "user": [7, 11, 12, 13, 17, 18, 20, 21], "start": [7, 8, 10, 11, 17, 18, 27, 28, 30, 31], "softwar": [7, 8, 10, 11, 12, 16, 18, 20, 21, 22, 24, 25, 26, 30, 31], "access": [7, 13, 17, 22, 28, 30], "introduct": [7, 17, 27, 31], "tutori": [7, 10, 11, 12, 17, 18, 31], "atlassian": 7, "interact": [7, 17], "book": 7, "pleas": [7, 15, 26], "refer": [7, 11, 12, 15, 22, 28], "especi": [7, 10, 17], "easier": [7, 17], "replac": [7, 16, 28, 31], "abl": [7, 10, 11, 13, 16, 31], "lxplu": [7, 20], "later": [7, 8, 9, 15, 28], "section": [7, 10, 16, 17], "It": [7, 9, 10, 11, 13, 14, 15, 16, 17, 21, 22, 23, 24, 27, 30, 31], "shell": [7, 10], "tab": 7, "complet": [7, 11, 14, 16, 17, 23, 27, 30, 31], "show": [7, 14, 16, 17, 21, 27, 31], "prompt": 7, "pend": 7, "etc": [7, 11, 24, 27], "least": [7, 13, 30], "offici": 7, "mean": [7, 10, 11, 17, 27], "area": [7, 10, 21, 24], "af": 7, "remot": 7, "your_github_us": 7, "copi": [7, 10, 11, 17, 21, 22, 24, 31], "upstream": [7, 10, 20, 21, 23], "repo": [7, 21, 24], "addit": [7, 11, 13, 14, 17, 19, 20, 28], "fetch": [7, 10], "prune": 7, "rebas": 7, "read": [7, 11, 12, 13, 18, 21, 22, 24, 28, 29, 30, 31], "avoid": [7, 8, 16, 18, 21], "loss": 7, "process": [7, 10, 11, 13, 16, 21, 28, 30], "delet": [7, 17, 19, 21], "result": [7, 11, 17, 21, 31], "info": [7, 10, 11, 17, 28, 31], "below": [7, 13, 16, 17, 24, 25, 30, 31], "how": [7, 8, 10, 16, 18, 19, 21, 26, 28, 30, 31], "origin": [7, 10, 16, 17, 28, 31], "name_of_local_branch": 7, "tracker": 7, "choic": [7, 21], "b": 7, "occasion": 7, "explain": [7, 10, 28], "abov": [7, 10, 11, 17, 21, 27, 30], "merg": 7, "succe": 7, "even": [7, 10, 11, 13, 17, 20, 22], "better": [7, 11], "automat": [7, 10, 13, 17, 18, 21, 22, 23, 24, 31], "produc": [7, 11, 17, 28, 30, 31], "expect": [7, 16, 17], "offic": 7, "alwai": [7, 11, 15, 17, 19, 21, 24], "given": [7, 10, 21, 29], "topic": [7, 8, 10], "pythia_interfac": 7, "someth": [7, 10, 11, 14, 17, 26, 31], "solid": 7, "often": [7, 24], "onc": [7, 10, 13, 14], "finish": 7, "larg": [7, 10, 20], "consid": [7, 21, 31], "progress": [7, 21], "repres": 7, "snapshot": 7, "whole": [7, 10, 20], "previou": [7, 9, 11], "although": [7, 11, 21, 24], "well": [7, 10, 13, 16, 17, 22, 26, 28, 30, 31], "practic": [7, 10, 24, 31], "pass": [7, 11, 13, 14, 16, 17, 21, 28, 29, 30, 31], "find": [7, 8, 10, 11, 17, 21, 24, 26], "both": [7, 10, 16, 17, 23, 28, 31], "good": [7, 11, 24], "bad": [7, 21], "meaning": [7, 10, 16, 31], "ref": [7, 16], "id": [7, 11, 13], "correctli": 7, "printout": 7, "interfac": [7, 21, 31], "short": [7, 16, 17], "liner": 7, "here": [7, 10, 11, 17, 25, 26, 27, 30, 31], "write": [7, 8, 12, 18, 22, 29, 31], "befor": [7, 10, 11, 31], "idea": [7, 11], "sens": [7, 17], "messag": [7, 17], "did": 7, "unnecessari": 7, "log": [7, 11], "d": [7, 17, 20, 25], "commonli": [7, 27], "actual": [7, 10, 16, 17, 21, 31], "entir": [7, 16, 18], "give": [7, 10, 11, 13, 16, 17, 24, 31], "titl": 7, "appropri": [7, 10], "calorimet": 7, "cluster": [7, 17], "pr": [7, 13, 17], "wip": 7, "descript": [7, 10, 16, 17, 27, 31], "bullet": 7, "point": [7, 11, 13, 17, 19, 22, 28], "wa": [7, 10, 11, 16, 22], "track": [7, 15, 16, 17, 27], "sure": [7, 11, 14, 16, 27, 31], "mention": 7, "close": 7, "v": [7, 21], "similar": [7, 10, 11, 13, 17, 21, 30, 31], "address": 7, "own": [7, 10, 13, 16, 17, 29], "renam": [7, 16, 18], "myfccsw": 7, "url": 7, "question": [7, 10], "sort": 7, "out": [7, 10, 11, 21, 24, 31], "drop": [7, 10, 11, 14, 31], "altern": [7, 16, 21, 24, 30], "sooner": 8, "rather": [8, 12, 16, 17, 21], "necessari": [8, 10, 13, 16, 17, 21, 28, 30, 31], "These": [8, 11, 16, 17, 24, 28, 29, 31], "cover": [8, 30], "friction": 8, "workflow": [8, 18, 20, 31], "guid": [8, 13, 17, 18], "overview": [8, 11, 18], "gener": [8, 11, 14, 16, 18, 21, 30, 31], "up": [8, 9, 11, 17, 18, 20, 22, 23, 26, 31], "ssh": [8, 11, 18, 21], "kei": [8, 11, 16, 18], "improv": [8, 17, 18], "keep": [8, 11, 14, 15, 16, 31], "date": [8, 10, 21, 22], "recommend": [8, 11, 17, 18, 24, 31], "clean": [8, 31], "histori": 8, "troubl": [8, 18], "shoot": [8, 18, 27], "try": [8, 10, 13, 16, 17, 26], "push": [8, 10], "authent": 8, "error": [8, 11, 17, 21], "now": [8, 10, 17, 21, 24, 27, 31], "my": [8, 10], "what": [8, 10, 11, 13, 17, 21, 24, 29], "cmake": [8, 9, 10, 11, 18, 21], "quick": [8, 9, 10, 18], "build": [8, 9, 11, 18, 19, 21, 22, 24, 27, 29, 30], "packag": [8, 18, 19, 20, 22, 23, 25, 30], "configur": [8, 9, 10, 11, 14, 18, 20, 21, 23, 27, 28, 29, 30, 31], "runtim": [8, 16], "custom": [8, 12, 13, 18, 24], "singl": [8, 13, 17, 18], "dev": 8, "advanc": [8, 17, 21], "usag": [8, 12, 14, 15, 16, 17, 18, 26], "function": [8, 12, 16, 18, 30], "walkthrough": [8, 18], "steer": [8, 15, 18, 28, 30, 31], "initi": [8, 18], "final": [8, 18, 31], "gdb": [8, 18], "const": [8, 17, 18], "oper": [8, 17, 18], "cmakebuild": 8, "gave": 9, "while": [9, 10, 13, 14, 16, 17, 24, 31], "approach": [9, 10], "number": [9, 10, 11, 13, 16, 17, 20, 21, 28, 29, 31], "cumbersom": [9, 10], "repeat": [9, 16], "cycl": [9, 10, 11], "miss": [9, 16, 18, 26], "notic": 9, "reproduc": [9, 10, 19, 31], "somewhat": [10, 16, 17], "its": [10, 13, 15, 16, 17, 21, 24, 29], "limit": [10, 11, 13, 14], "howev": [10, 11, 16, 19, 24, 27, 30, 31], "imposs": 10, "unfortun": [10, 21], "might": [10, 14, 16, 21, 22, 27, 31], "fulli": [10, 27], "henc": [10, 13, 17, 31], "tri": [10, 21], "collect": [10, 11, 16, 18, 21, 27, 28, 31], "obtain": [10, 11, 13, 17, 28], "standalon": [10, 12, 16, 18, 26], "suffic": 10, "three": 10, "let": [10, 11, 21, 26], "sai": 10, "nigthli": 10, "2023": [10, 25], "07": 10, "18": [10, 21], "x86_64": [10, 21, 24], "almalinux9": [10, 19], "gcc11": 10, "opt": 10, "kzukii": 10, "And": 10, "latest": [10, 19, 23, 24], "scratch": [10, 22], "inam": 10, "happen": [10, 11, 14, 19], "06": [10, 21], "24": [10, 25], "rel": [10, 11, 24], "latest_scratch": 10, "depth": 10, "cat": [10, 24], "cherri": 10, "env": [10, 24], "config": [10, 24, 28, 29, 30, 31], "install_tre": [10, 24], "exactli": [10, 17], "minimum": [10, 16], "brief": [10, 12, 16, 17], "There": [10, 11, 13, 17, 29], "dedic": 10, "slack": 10, "spackpm": 10, "invit": 10, "visit": 10, "io": [10, 11], "regard": 10, "discuss": [10, 14], "doe": [10, 17, 21], "been": [10, 13, 16, 17, 27, 31], "sinc": [10, 11, 16, 17, 21, 22, 24, 31], "would": [10, 11, 16, 17, 21, 26, 28, 31], "entail": 10, "spec": [10, 21, 24], "il": 10, "rootdict": 10, "input": [10, 11, 13, 14, 16, 17, 18, 21, 26, 29, 30, 31], "concret": [10, 21, 24], "vdwx2aq": 10, "16": [10, 21], "gcc": [10, 24], "9": [10, 19, 21], "ipo": [10, 21], "jar": 10, "build_typ": [10, 21], "relwithdebinfo": [10, 21], "cxxstd": [10, 21], "17": [10, 21, 24, 25], "arch": [10, 21], "linux": [10, 21], "ubuntu20": [10, 21], "04": [10, 19, 21], "skylak": 10, "utzbuq7": 10, "doc": [10, 21, 26], "ncurs": [10, 21], "openssl": [10, 21], "ownlib": [10, 21], "qt": [10, 21], "1c540040c7e203dd8e27aa20345ecb07fe06570d56410a24a266ae570b1c4c39": 10, "bf695e3febb222da2ed94b3beea600650e4318975da90e4a71d6f31a6d5d8c3d": 10, "pljbs5a": 10, "sio": [10, 17], "builtin_zlib": 10, "alreadi": [10, 11, 16, 17, 21, 22, 24, 27], "yet": [10, 16, 21, 31], "ilcsoft": [10, 16, 27, 28, 31], "fulfil": 10, "full": [10, 17, 31], "output": [10, 11, 13, 14, 16, 18, 26, 28, 29, 31], "stage": 10, "end": [10, 13, 28, 31], "7dovpqn3kscbg672ham5wcqro7lg45gh": 10, "00": 10, "62": 10, "total": [10, 29], "home": [10, 17, 21], "tmadlen": 10, "specifi": [10, 17, 31], "cannot": [10, 13, 16, 21, 24], "arbitrari": [10, 13, 16], "necessarili": 10, "cours": [10, 11, 31], "encourag": 10, "useabl": 10, "desir": [10, 14, 16, 17], "nice": 10, "downstream": 10, "far": [10, 17], "concern": 10, "realli": 10, "download": [10, 18, 20, 30], "fact": [10, 17], "manifest": 10, "lv": 10, "yield": 10, "7dovpqn": 10, "dev_path": 10, "part": [10, 13, 14, 17, 20, 27, 28, 30, 31], "hash": [10, 23], "affect": 10, "specif": [10, 13, 21], "syntax": 10, "uninstal": 10, "again": [10, 13, 16, 17, 31], "becaus": [10, 11, 17], "overwrit": 10, "dealt": 10, "easili": [10, 24], "achiev": [10, 12, 17, 29, 30, 31], "until": 10, "proper": [10, 27], "scheme": 10, "j4": 10, "afterward": 10, "locat": [10, 28, 29], "regist": [10, 21], "databas": 10, "call": [10, 13, 16, 17, 18, 22], "trick": 10, "back": [10, 17], "chain": [10, 31], "recompil": 10, "artifact": 10, "success": [10, 11, 29], "return": [10, 11, 17], "type": [10, 11, 13, 16, 29], "exit": [10, 17], "simultan": 10, "doesn": 10, "scale": [10, 20], "definit": [10, 11], "20": [10, 25, 31], "davix": 10, "gsl": 10, "math": 10, "memstat": 10, "minuit": 10, "mlp": 10, "mysql": 10, "opengl": 10, "postgr": 10, "pythia6": 10, "pythia8": [10, 21, 30], "qt4": 10, "r": [10, 20, 25, 29], "root7": 10, "rootfit": 10, "rpath": 10, "shadow": 10, "sqlite": 10, "ssl": 10, "tabl": 10, "tbb": [10, 29], "thread": [10, 11, 17, 21, 29], "tmva": 10, "unuran": 10, "vc": 10, "vdt": 10, "vmc": 10, "x": [10, 30], "xrootd": 10, "22af3471f3fd87c0fe8917bf9c811c6d806de6c8b9867d30a1e3d383a1b929d7": 10, "geant4": [10, 21], "heppdt": 10, "hepmc": [10, 21], "10": [10, 11, 21, 25, 27, 28, 29], "tricktrack": 10, "pyyaml": 10, "jinja2": [10, 17], "evtgen": [10, 21], "view": [10, 11, 21, 24], "true": [10, 29], "variant": 10, "edm4hep_devel": 10, "yaml": [10, 18, 20, 21], "devel": 10, "p": [10, 17, 24], "immedi": 10, "state": [10, 11, 17, 21, 31], "properli": [10, 11], "straight": [10, 17, 31], "base": [10, 11, 14, 16, 17, 31], "disadvantag": 10, "handl": [10, 16, 17, 18, 21, 31], "gain": 10, "abil": 10, "256": 10, "optim": [10, 21, 29], "decent": 10, "too": [10, 14], "deep": 10, "down": [10, 17], "impli": 10, "frequent": 10, "relink": 10, "lot": [10, 27], "nevertheless": [10, 17], "usabl": [10, 13, 29], "briefli": [10, 17], "mainli": [10, 12, 17], "whether": [10, 17, 24], "rest": [10, 11, 31], "veri": [10, 11, 13, 16, 17, 23, 24, 26, 31], "turn": [10, 17], "depen": 10, "suppos": 10, "fals": [10, 15, 16, 28], "previous": [10, 16, 31], "field": 10, "tell": [10, 11, 17], "var": 10, "absolut": 10, "aidasoft": [10, 17], "development_env_packag": 10, "enough": [10, 17, 21], "either": [10, 13, 16, 21, 28, 31], "easiest": [10, 11, 13, 16, 30, 31], "relat": [10, 14, 18], "among": [10, 17], "arg": [10, 14], "l": [10, 31], "realiz": [10, 17, 24], "broke": 10, "defin": [10, 11, 13, 16, 17, 28], "live": [10, 17], "insid": [10, 11, 16, 17], "could": [10, 11, 16, 31], "f": [10, 22, 24], "inde": 10, "along": [10, 31], "broadwel": [10, 21], "m5khm2w": 10, "seen": 10, "event": [11, 12, 18, 25, 26, 28, 30, 31], "care": [11, 17], "servic": [11, 14, 29], "support": [11, 16, 17, 18, 19, 21, 22, 26, 31], "multithread": [11, 18, 26], "relationship": 11, "between": [11, 16, 17, 18, 29, 31], "util": [11, 30], "almost": [11, 16, 17, 31], "seamlessli": 11, "design": [11, 12, 13, 17, 26], "enforc": [11, 21], "constraint": 11, "quicker": 11, "intern": [11, 13, 14, 16, 17, 25], "benefit": 11, "being": [11, 13, 17, 21, 31], "trivial": 11, "ourselv": 11, "easi": [11, 17, 24], "templat": [11, 17], "k4": 11, "ideal": [11, 22], "know": [11, 26], "detail": [11, 13, 14, 15, 17, 18, 26, 31], "k4run": [11, 12, 14, 16, 18, 26, 27, 28], "k4testfwcor": 11, "createexampleeventdata": 11, "straightforward": 11, "class": [11, 16], "inherit": [11, 17], "member": [11, 17, 29], "none": [11, 16, 21, 28, 29], "developkit": 11, "03a": 11, "consum": [11, 13], "transform": 11, "multitransform": 11, "structur": [11, 21], "precis": 11, "struct": [11, 13, 17], "gaudialg": 11, "h": [11, 13, 17, 30], "baseclass_t": 11, "baseclass": 11, "exampletransform": 11, "colltype_out": 11, "colltype_in": 11, "std": [11, 17], "string": [11, 16, 21], "isvcloc": 11, "svcloc": 11, "overrid": [11, 21], "magic": 11, "modifi": [11, 17, 24, 28], "signatur": 11, "mcparticlecollect": [11, 17], "leav": 11, "slightli": [11, 16, 17], "complic": 11, "tupl": 11, "outputclass1": 11, "outputclass2": 11, "aren": 11, "void": [11, 17], "reach": 11, "constructor": [11, 17], "keyvalu": 11, "save": 11, "inputcollect": 11, "mcparticl": [11, 13, 16, 17, 31], "outputcollect": 11, "newmcparticl": 11, "possibli": 11, "valu": [11, 16, 21, 29, 31], "bundl": [11, 13, 24], "enclos": 11, "bracket": 11, "examplemultitransform": 11, "outputcollection1": 11, "outputcollection2": 11, "simtrackerhit": 11, "outputcollection3": 11, "usefulcollect": 11, "auto": [11, 13, 17], "coll_out": 11, "particl": [11, 13, 17, 25, 27], "new_particl": 11, "mutablemcparticl": [11, 17], "setpdg": 11, "getpdg": 11, "setgeneratorstatu": 11, "getgeneratorstatu": 11, "setsimulatorstatu": 11, "getsimulatorstatu": 11, "setcharg": 11, "getcharg": 11, "settim": 11, "gettim": 11, "setmass": 11, "getmass": 11, "push_back": [11, 17], "make_tupl": 11, "move": [11, 17, 22, 29], "collection1": 11, "collection2": 11, "k4fwcoretest": 11, "examplefunctionaltransform": 11, "paramet": [11, 16, 18, 27, 28], "applicationmgr": [11, 14, 16, 28, 29, 31], "k4datasvc": [11, 18, 28, 29, 31], "podiooutput": [11, 14, 29, 31], "podioinput": [11, 14, 28, 29, 31], "editor": 11, "analysi": [11, 31], "undefin": 11, "podioev": 11, "eventdatasvc": [11, 14, 28, 29, 31], "output_k4test_exampledata_produc": 11, "inp": 11, "select": [11, 14, 16, 24], "filenam": [11, 14, 31], "output_k4test_exampledata_transform": 11, "present": [11, 17, 18, 26, 27], "outputcommand": [11, 14, 31], "relev": [11, 17, 21], "learn": [11, 31], "object": [11, 13, 17], "topalg": [11, 28, 29], "evtsel": [11, 28, 29], "evtmax": [11, 28, 29], "extsvc": [11, 14, 28, 29], "outputlevel": [11, 28, 29, 31], "last": [11, 17, 31], "maximum": 11, "That": 11, "extra": 11, "warn": [11, 13, 16, 19, 28, 29], "occas": 11, "place": 11, "those": [11, 17], "statuscod": 11, "rememb": [11, 31], "statu": [11, 25], "crash": [11, 13], "myalgorithm": 11, "gnu": 11, "debugg": 11, "invok": [11, 13, 21], "attach": [11, 16, 25, 31], "load": [11, 21, 24], "continu": [11, 17], "consol": 11, "interrupt": 11, "ctrl": 11, "c": [11, 17, 27], "requir": [11, 17, 28], "account": [11, 16], "around": 11, "keyword": 11, "mutabl": [11, 17], "caus": 11, "wasn": 11, "Of": 11, "unless": [11, 28], "safe": [11, 17, 21, 29], "longer": [11, 17, 22], "wors": 11, "wrong": 11, "written": [11, 17], "substitut": 11, "certain": [12, 13, 14], "within": [12, 16, 17, 29, 30, 31], "aim": [12, 31], "technic": [12, 18], "infrastructur": [12, 18], "wrap": [12, 18, 27, 28, 29, 31], "processor": [12, 18, 27, 28, 29, 31], "convers": [12, 17, 18, 27, 28, 31], "lcio2edm4hep": [13, 16], "slcio": [13, 16, 28, 31], "lcevent": 13, "put": [13, 16, 21, 22, 24], "frame": [13, 18], "categori": [13, 17], "major": [13, 16, 17, 30], "effect": [13, 14], "wherea": 13, "assumpt": [13, 14], "ensur": [13, 21], "potenti": [13, 31], "come": [13, 16, 17], "form": [13, 16, 17], "third": 13, "compris": [13, 20], "superset": 13, "format": [13, 16, 17, 28, 30, 31], "simplest": [13, 21], "setspacepoint": 13, "trackerhit": 13, "recomctruthlink": [13, 14, 31], "check_missing_col": 13, "minim": [13, 14, 16], "pnf": 13, "desi": 13, "prod": 13, "mc": [13, 14, 17], "2020": [13, 25], "ild": [13, 18, 26, 27], "rec": [13, 31], "250": 13, "seta": [13, 17], "higg": 13, "ild_l5_o2_v02": 13, "v02": 13, "02": [13, 17], "01": 13, "00015671": 13, "000": 13, "rv02": [13, 17], "sv02": [13, 17], "mild_l5_o2_v02": 13, "e250": [13, 17], "i402005": 13, "pe3e3h": 13, "el": [13, 17], "n000_002": 13, "d_rec_00015671_493": 13, "fromtyp": 13, "totyp": 13, "correct": [13, 17, 23], "determin": [13, 29], "skip": [13, 16], "mechan": [13, 16, 21], "colltypefil": 13, "remap": 13, "store": [13, 16, 17], "overal": 13, "resolv": [13, 16, 31], "fill": [13, 17], "convertcollect": 13, "dispatch": [13, 17], "lccollect": 13, "map": [13, 16], "dure": [13, 16, 21, 28], "lcioedmtypemap": 13, "resolverel": 13, "obvious": [13, 17], "fillsubset": 13, "handlesubsetcol": 13, "associationcollect": 13, "createassoci": 13, "convertev": 13, "convertobjectparamet": 13, "small": 13, "shine": 13, "calohitcontribut": [13, 17], "simcalorimeterhit": [13, 16], "createcalohitcontribut": 13, "separ": [13, 17, 22], "eventhead": [13, 31], "eventheadercollect": 13, "reconstruct": [13, 15, 17, 18, 26, 29], "k4lcio2edm4hepconv": 13, "edm": [13, 18, 28, 29], "counterpart": 13, "typemap": 13, "edmcollect": 13, "convertreconstructedparticl": 13, "recoparticl": 13, "particleid": 13, "facil": 14, "much": 14, "familiar": [14, 16], "snippet": [14, 16], "runnabl": 14, "whenev": 14, "instanti": [14, 16, 31], "evtsvc": [14, 28, 31], "extern": [14, 17, 20, 21], "my_output": 14, "eventstor": [14, 17, 29], "must": [14, 22, 29], "target": [14, 16, 22], "pattern": 14, "apart": 14, "metadata": 14, "highest": 14, "reco": [14, 17], "mcparticlesskim": [14, 31], "pandorapfo": [14, 31], "extend": 15, "parsearg": 15, "parser": 15, "add_argu": 15, "trackingonli": 15, "action": 15, "store_tru": 15, "my_opt": 15, "parse_known_arg": 15, "behind": [15, 17], "scene": 15, "normal": [15, 16, 17], "argpars": 15, "argumentpars": 15, "mind": 15, "parse_arg": 15, "former": 16, "linear": 16, "collid": [16, 18, 25], "latter": [16, 17, 28], "studi": [16, 25], "gradual": 16, "migrat": 16, "bare": 16, "modif": 16, "processortyp": [16, 27], "attribut": [16, 27], "pars": [16, 21], "statmonitoralg": 16, "statusmonitor": 16, "howoften": 16, "int": [16, 17], "world": [16, 17], "lcioevent": [16, 29, 31], "inputfile1": 16, "inputfile2": 16, "lciooutputprocessor": [16, 29], "output_dst": 16, "dropcollectionnam": 16, "dropcollectiontyp": 16, "lcrelat": [16, 18], "convertmarlinsteeringtogaudi": [16, 28, 31], "statement": [16, 31], "trackingdigi": 16, "inputfil": [16, 17, 27, 28, 31], "constant": [16, 31], "somefancyconst": 16, "begin": 16, "condit": 16, "tag": 16, "principl": [16, 17], "At": [16, 17, 28], "moment": [16, 19], "basi": 16, "addition": [16, 21], "static": [16, 21], "partial": 16, "alglist": [16, 28, 29, 31], "uncom": [16, 28], "lcioinputfil": [16, 28], "retriev": [16, 17], "o": [16, 17, 21, 28, 31], "gauditool": 16, "lcio2edm4heptool": [16, 29, 31], "edm4hep2lciotool": [16, 29, 31], "equip": 16, "edm4hep2lcioconv": [16, 31], "edm4hep2lcio": 16, "lcio2edm4hepconv": [16, 31], "wrappedprocalg": 16, "processortowrap": 16, "direct": [16, 17], "confus": 16, "transient": 16, "higher": 16, "granular": 16, "collnamemap": [16, 31], "fly": [16, 18, 27, 31], "convertal": 16, "subset": [16, 18], "hand": [16, 26], "toward": [17, 25], "knowledg": 17, "web": [17, 22], "diagrammat": 17, "broadli": 17, "arrow": 17, "depict": 17, "black": 17, "purpl": 17, "ish": 17, "flavor": 17, "onetoonerel": 17, "onetomanyrel": 17, "hierarchi": 17, "mother": 17, "daughter": 17, "vice": [17, 31], "versa": [17, 31], "hold": 17, "reconstructedparticl": [17, 18], "connect": [17, 27], "contrast": [17, 23], "involv": 17, "throughout": 17, "datatyp": 17, "click": 17, "jump": [17, 27], "educ": 17, "index": 17, "expand": 17, "namespac": [17, 21], "calohitcontributioncollect": 17, "calohitcontributioncollectiondata": 17, "calohitcontributioncollectioniter": 17, "calohitcontributiondata": 17, "calohitcontributionmutablecollectioniter": 17, "calohitcontributionobj": 17, "calohitcontributionsioblock": 17, "mutablecalohitcontribut": 17, "mark": 17, "bold": 17, "truli": 17, "visibl": 17, "helper": 17, "ever": 17, "style": 17, "herb": 17, "sutter": 17, "blog": 17, "digest": 17, "summari": 17, "purpos": [17, 27], "slight": 17, "detour": 17, "bring": 17, "arriv": 17, "toolkit": 17, "further": [17, 24, 31], "context": 17, "effici": [17, 20, 23], "high": [17, 25], "gori": 17, "implic": 17, "inspect": 17, "valid": 17, "engin": 17, "perform": [17, 28], "autom": 17, "advantag": 17, "repetit": 17, "task": 17, "themselv": 17, "deal": 17, "roll": [17, 22], "regener": 17, "goal": 17, "favor": 17, "composit": 17, "plain": 17, "old": 17, "pod": 17, "wherev": 17, "emploi": 17, "memori": [17, 31], "lightweight": 17, "xyzcollect": 17, "mutablexyz": 17, "xyzobj": 17, "bottom": [17, 28], "xyzdata": 17, "exact": [17, 21], "treat": [17, 21, 22], "worri": 17, "ineffici": 17, "reconstructedparticlecollect": 17, "p2": 17, "loop": [17, 29], "vtx": 17, "getstartvertex": 17, "vertex": 17, "gettrack": 17, "squint": 17, "ignor": 17, "pyroot": 17, "len": 17, "pretti": 17, "rule": 17, "vectormemb": 17, "stick": 17, "front": 17, "capit": 17, "letter": 17, "vector3f": 17, "momentum": [17, 21], "gev": [17, 21, 27], "getmomentum": 17, "nuanc": 17, "appli": 17, "method": [17, 29], "setmomentum": 17, "addto": 17, "addtodaught": 17, "underli": 17, "reason": 17, "complex": 17, "dive": 17, "quit": 17, "deepish": 17, "beyond": 17, "scope": [17, 24], "immut": 17, "te": 17, "independ": 17, "implicitli": 17, "convert": [17, 18, 28, 29, 30, 31], "implicit": 17, "print": [17, 30], "cout": 17, "getenergi": 17, "printemut": 17, "mutp": 17, "setenergi": 17, "14": [17, 21], "due": [17, 22], "break": [17, 19], "No": 17, "muon": [17, 18, 30], "larger": 17, "setsubsetcollect": 17, "transpar": 17, "aggreg": 17, "meta": 17, "interv": 17, "less": 17, "reflect": 17, "introduc": [17, 19], "infer": 17, "complain": 17, "ownership": 17, "signal": 17, "left": [17, 28], "unspecifi": 17, "circumst": 17, "match": 17, "backend": 17, "makeread": 17, "some_file_containing_edm4hep": 17, "size_t": 17, "getev": 17, "readnextev": 17, "stuff": 17, "rootread": 17, "ttree": 17, "rootlegacyread": 17, "rntupleread": 17, "rntupl": 17, "sioread": 17, "siolegacyread": 17, "ago": 17, "interest": [17, 21, 31], "next": [17, 31], "construct": 17, "openfil": 17, "some_file_containing_edm4hep_data": 17, "getentri": 17, "readnextentri": 17, "root_io": 17, "legacyread": 17, "interpret": 17, "caveat": 17, "flat": 17, "ntupl": 17, "workarea": 17, "mild_l5_o1_v02": 17, "i402003": 17, "pe2e2h": 17, "n000": 17, "d_dstm_15089_0_edm4hep": 17, "peek": 17, "synopsi": 17, "dump_edm": 17, "stdout": 17, "posit": 17, "comma": 17, "inclus": 17, "rang": 17, "element": 17, "ascii": 17, "choos": [17, 24, 31], "central": [18, 21, 22, 24], "Tos": 18, "resourc": [18, 30], "doxygen": 18, "api": 18, "layout": 18, "dump": [18, 21], "marlinprocessorwrapp": [18, 27, 28, 29, 31], "subtl": 18, "simul": [18, 26, 27], "displai": [18, 19, 26], "troubleshoot": [18, 26], "detector": [18, 25, 26, 28, 30, 31], "delph": [18, 26], "fast": [18, 26], "prerequisit": [18, 26], "librarian": 18, "talk": 18, "logo": 18, "cepc": 18, "everi": [19, 23], "month": 19, "demand": 19, "ubuntu22": 19, "el9": 19, "rockylinux9": 19, "almalinux": 19, "ubuntu": 19, "22": 19, "unannounc": 19, "anyth": [19, 27, 30, 31], "els": [19, 31], "fairli": [20, 23], "scientif": 20, "regularli": 20, "deploi": [20, 21, 23], "recip": 20, "known": 21, "workaround": [21, 31], "invoc": 21, "degre": 21, "decis": 21, "estim": 21, "long": 21, "proxi": 21, "solv": 21, "spit": 21, "solut": 21, "were": [21, 22, 31], "12": 21, "criteria": 21, "prioriti": 21, "criterion": 21, "tobuild": 21, "reus": 21, "weight": 21, "deprec": 21, "non": [21, 29], "prefer": 21, "8": 21, "11": [21, 24, 25], "mismatch": 21, "13": 21, "156": 21, "15": 21, "165": 21, "44": 21, "whizard": [21, 31], "fastjet": 21, "latex": 21, "lhapdf": 21, "openloop": 21, "openmp": 21, "hepmc3": 21, "rootio": 21, "1c54004": 21, "bf695e3": 21, "libtirpc": 21, "krb5": 21, "19": 21, "bison": 21, "diffutil": 21, "libiconv": 21, "m4": 21, "sigsegv": 21, "3877ab5": 21, "fc9b616": 21, "perl": 21, "30": 21, "cpanm": 21, "gettext": 21, "21": [21, 25], "bzip2": 21, "curs": 21, "libunistr": 21, "libxml2": 21, "tar": 21, "xz": 21, "pic": 21, "pkgconf": 21, "zlib": 21, "0d38234": 21, "symlink": 21, "termlib": 21, "abi": 21, "zip": 21, "pigz": 21, "1f": 21, "cert": 21, "mozilla": 21, "ocaml": 21, "forc": 21, "306": 21, "hdf5": 21, "madgraph5amc": 21, "mpich": 21, "openmpi": 21, "rivet": 21, "length": 21, "mm": 21, "rsync": 21, "alradi": 21, "hard": 21, "preced": 21, "detect": [21, 31], "perfectli": 21, "varieti": 21, "machin": [21, 22, 24, 29, 31], "bundlepackag": 21, "investig": [21, 22], "filesystem": 21, "usr": 21, "simplifi": 21, "thu": [21, 22], "platform": [21, 22, 24], "gracefulli": 21, "ongo": 21, "discourag": 21, "strenght": 21, "smoothli": 21, "publish": 21, "axv": 21, "inplac": 21, "compress": 21, "stricthostkeycheck": 21, "gssapiauthent": 21, "ye": 21, "gssapitrustdn": 21, "spackag": [21, 22, 23], "omit": 21, "preserv": 21, "expos": [21, 29], "gitlab": 21, "sft": [21, 24], "cc": 21, "cling": 21, "17488": 21, "difficulti": 22, "reloc": 22, "eo": 22, "space": [22, 28], "k": 22, "www": 22, "spack_build": 22, "mirror": 22, "lcg": [22, 24], "branchnam": 22, "indic": [22, 28, 29], "contrib": [22, 24], "subdirectori": 22, "permiss": 22, "subscrib": 22, "egroup": 22, "cernbox": 22, "writer": 22, "m": 22, "hour": 22, "search": [22, 24], "serv": 22, "quickli": 23, "stabl": 23, "typic": 23, "head": 23, "rebuild": 23, "dai": 23, "infrequ": 23, "setup_clingo_centos7": 24, "client": 24, "oss": 24, "bootstrap": 24, "clingo": 24, "suitabl": 24, "kept": 24, "therefor": 24, "variat": 24, "clang": 24, "compat": [24, 31], "essenti": [24, 30], "ci_setup_spack": 24, "global": [24, 28], "itself": 24, "hint": 24, "nudg": 24, "With": [24, 31], "obsolet": 24, "ship": [24, 30], "box": 24, "cp": [24, 28], "eot": 24, "spackages6": 24, "site": 24, "zotero": 25, "group": 25, "item": 25, "carcel": 25, "juan": 25, "miguel": 25, "juli": 25, "indico": 25, "1301872": 25, "5474076": 25, "2682457": 25, "4653446": 25, "carceller_key4hep_spack_2023": 25, "pdf": 25, "ep": 25, "meet": 25, "june": 25, "1253565": 25, "5265910": 25, "2591081": 25, "4628747": 25, "carceller_key4hep_20230621": 25, "volkl": 25, "valentin": 25, "ia": 25, "energi": [25, 27], "physic": [25, 30], "2021": 25, "januari": 25, "971970": 25, "timet": 25, "153": 25, "madlen": 25, "thoma": 25, "turnkei": 25, "xxvii": 25, "cracow": 25, "epiphani": 25, "confer": 25, "934666": 25, "4154229": 25, "2168411": 25, "3660367": 25, "key4hep_epiphany2021_cracow": 25, "helsen": 25, "clement": 25, "4154228": 25, "gani": 25, "gerardo": 25, "ust": 25, "hk": 25, "shared_doc": 25, "202001hep": 25, "workshop": 25, "exp": 25, "20200117_1038_am_gerri_gani": 25, "sailer": 25, "andr\u00e9": 25, "joint": 25, "charm": 25, "tau": 25, "factori": 25, "septemb": 25, "2019": 25, "rich2018": 25, "180": 25, "151": 25, "247": 25, "190924_sailer_softwar": 25, "comput": 25, "nuclear": 25, "773049": 25, "3474763": 25, "1938664": 25, "3213633": 25, "191105_sailer_key4hep": 25, "mato": 25, "pere": 25, "clicdp": 25, "august": 25, "28": 25, "792656": 25, "3536473": 25, "1898480": 25, "3132881": 25, "key4hep_clicdp_meet": 25, "session": 26, "incomplet": 26, "accept": 26, "suggest": [26, 31], "geometri": [26, 27], "ildreconstruct": 26, "ildconfig": 26, "inter": 26, "parallel": 26, "ced": 27, "cedview": 27, "concept": [27, 31], "self": 27, "clicperform": [27, 28], "ddsim": [27, 28, 31], "gun": 27, "photon": 27, "illustr": 27, "creation": 27, "minut": [27, 31], "steeringfil": [27, 28, 31], "clicconfig": [27, 28], "clic_steer": [27, 28], "compactfil": [27, 28, 31], "k4geo": [27, 28], "compact": [27, 28, 31], "clic_o3_v14": [27, 28], "enablegun": 27, "uniform": 27, "gamma": 27, "outputfil": [27, 28, 31], "gamma_10gev_edm4hep": 27, "numberofev": [27, 28], "ddcedview": 27, "wrapper": 27, "event_displai": 27, "glced": 27, "server": 27, "visualis": 27, "clic_o3_v06_c": 27, "mycedview": 27, "explanatori": 27, "cld": 27, "deriv": 27, "compar": 27, "hit": 27, "drawinlay": 27, "_edm4hep": 28, "ttbar_edm4hep": 28, "yyxyev_000": 28, "stdhep": [28, 30], "ttbar": 28, "clicreconstruct": [28, 29], "initdd4hep": 28, "dd4hepxmlfil": 28, "maxrecordnumb": 28, "overlayfals": 28, "trackingconform": 28, "sed": [28, 31], "append": [28, 29, 31], "myconformaltrack": 28, "clonesandsplittracksfind": 28, "renamecollect": 28, "lcgeo": 28, "wont": 28, "clicrec_e4h_input": 28, "marlindd4hep": 28, "initializedd4hep": 28, "k4simgeant4": 28, "geosvc": 28, "trackingcellidencodingsvc": 28, "svclist": 28, "join": 28, "test_dir": 28, "geoservic": 28, "clic_o3_v15": 28, "enablegeant4geo": 28, "cellidsvc": 28, "encodingstringparameternam": 28, "globaltrackerreadoutid": 28, "geosvcnam": 28, "lcioeventoutput": 29, "whiteboard": 29, "isfirstev": 29, "processev": 29, "multi": 29, "intel": 29, "hood": 29, "intra": 29, "hivewhiteboard": 29, "hiveslimeventloopmgr": 29, "avalancheschedulersvc": 29, "sequenc": 29, "hardwar": 29, "eventslot": 29, "schedul": 29, "flight": 29, "decid": [29, 31], "evtslot": 29, "slimeventloopmgr": 29, "schedulernam": 29, "threadpools": 29, "seq": 29, "eventloop": 29, "messagesvctyp": 29, "inertmessagesvc": 29, "cardin": 29, "gaudisequenc": 29, "sequenti": 29, "applic": 29, "alg1": 29, "alg2": 29, "alg3": 29, "alg4": 29, "algo": 29, "createviewseq": 29, "mode": 29, "clicrec_lcio_mt": 29, "fccee": 30, "zh": 30, "mu": 30, "z": 30, "decai": 30, "pair": 30, "opposit": 30, "charg": 30, "card": 30, "wget": [30, 31], "raw": [30, 31], "githubusercont": [30, 31], "spring2021": 30, "p8_nobes_ee_zh_ecm240": 30, "cmd": 30, "delphespythia8_edm4hep": 30, "delphespythia8": 30, "contrari": 30, "delphes_dir": 30, "delphes_card_idea": 30, "tcl": 30, "edm4hep_output_config": 30, "delphes_events_edm4hep": 30, "parameter": 30, "delphesstdhep_edm4hep": 30, "delphesroot_edm4hep": 30, "delpheshepmc": 30, "config_fil": 30, "output_config_fil": 30, "output_fil": 30, "input_fil": [30, 31], "todo": 30, "exercis": 31, "sim": 31, "conceptu": 31, "haven": 31, "remaind": 31, "key4hep_tut_ild_reco": 31, "minor": 31, "though": 31, "standardconfig": 31, "product": 31, "gaudi_ild_reco": 31, "zh_mumu": 31, "k4geo_dir": 31, "ild_l5_v02": 31, "ddsim_steer": 31, "zh_mumu_sim": 31, "meantim": 31, "detectormodel": 31, "ild_l5_o1_v02": 31, "outputfilebas": 31, "zh_mumu_rec": 31, "zh_mumu_aida": 31, "histogram": 31, "aida": 31, "zh_mumu_pfoanalysi": 31, "pandora": 31, "pfo": 31, "lciooutput": 31, "off": 31, "emd4hep": 31, "analys": 31, "exhibit": 31, "strongli": 31, "bulk": 31, "marlinstdreco": 31, "adjust": 31, "marlinstdrecopars": 31, "lcgeo_dir": 31, "dict": 31, "forget": 31, "exclud": 31, "bgoverlayww": 31, "bgoverlaybb": 31, "bgoverlaybw": 31, "bgoverlaywb": 31, "pairbgoverlai": 31, "popul": 31, "somewher": 31, "second": 31, "roughli": 31, "standardreco_": 31, "dst": 31, "pfoanalysi": 31, "outputbasenam": 31, "resp": 31, "sake": 31, "myaidaprocessor": 31, "mypfoanalysi": 31, "parseconst": 31, "reader": 31, "unchang": 31, "beamcalcollect": 31, "beamcalcollectioncontribut": 31, "ecalbarrelschitseven": 31, "ecalbarrelschitsevencontribut": 31, "ecalbarrelschitsodd": 31, "ecalbarrelschitsoddcontribut": 31, "ecalbarrelsihitseven": 31, "ecalbarrelsihitsevencontribut": 31, "ecalbarrelsihitsodd": 31, "ecalbarrelsihitsoddcontribut": 31, "ecalendcapringcollect": 31, "ecalendcapringcollectioncontribut": 31, "ecalendcapschitseven": 31, "ecalendcapschitsevencontribut": 31, "ecalendcapschitsodd": 31, "ecalendcapschitsoddcontribut": 31, "ecalendcapsihitseven": 31, "ecalendcapsihitsevencontribut": 31, "ecalendcapsihitsodd": 31, "ecalendcapsihitsoddcontribut": 31, "ftdcollect": 31, "hcalbarrelregcollect": 31, "hcalbarrelregcollectioncontribut": 31, "hcalbarrelrpchit": 31, "hcalbarrelrpchitscontribut": 31, "hcalecringrpchit": 31, "hcalecringrpchitscontribut": 31, "hcalendcapringcollect": 31, "hcalendcapringcollectioncontribut": 31, "hcalendcaprpchit": 31, "hcalendcaprpchitscontribut": 31, "hcalendcapscollect": 31, "hcalendcapscollectioncontribut": 31, "lhcalcollect": 31, "lhcalcollectioncontribut": 31, "lumicalcollect": 31, "lumicalcollectioncontribut": 31, "setcollect": 31, "sitcollect": 31, "tpccollect": 31, "tpclowptcollect": 31, "tpcspacepointcollect": 31, "vxdcollect": 31, "yokebarrelcollect": 31, "yokebarrelcollectioncontribut": 31, "yokeendcapscollect": 31, "yokeendcapscollectioncontribut": 31, "edm4hepoutput": 31, "zh_mumu_reco": 31, "num": 31, "glori": 31, "tweak": 31, "tier": 31}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"contributor": 1, "code": [1, 7, 17], "conduct": 1, "contribut": [2, 7], "get": [2, 7, 17, 19], "start": [2, 6, 19], "softwar": [3, 6, 19], "call": 4, "logo": 4, "build": [5, 6, 10, 20, 23], "key4hep": [5, 6, 8, 10, 12, 18, 19, 20, 24, 26, 28, 30], "us": [5, 6, 10, 11, 16, 19, 21, 24, 27, 28, 31], "cmake": [5, 6], "For": [5, 10, 20], "develop": [5, 7, 8, 9, 10], "possibl": 5, "issu": 5, "packag": [5, 6, 9, 10, 21, 24], "have": [5, 7], "been": 5, "test": 5, "chang": [5, 6, 7], "differ": [5, 13], "commit": [5, 7], "branch": 5, "guid": [6, 7], "overview": [6, 7, 17], "quick": 6, "set": [6, 7, 10, 19, 21, 24, 27], "up": [6, 7, 10, 19, 21, 24, 27], "environ": [6, 10, 21, 24, 27], "run": [6, 17, 27, 29, 30, 31], "your": [6, 7], "local": [6, 7, 10], "instal": [6, 10, 19, 21, 24], "exampl": [6, 13, 29], "configur": [6, 16, 24], "runtim": [6, 21], "ctest": 6, "custom": [6, 15], "how": [6, 11, 12, 17, 29], "i": [6, 7, 17], "github": 7, "workflow": [7, 10, 21], "first": 7, "time": 7, "setup": [7, 10, 11, 30, 31], "git": 7, "gener": [7, 17], "ssh": 7, "kei": 7, "improv": 7, "experi": 7, "keep": 7, "repositori": [7, 21], "date": 7, "recommend": 7, "comment": 7, "clean": 7, "histori": 7, "pull": 7, "request": 7, "troubl": 7, "shoot": 7, "when": 7, "try": 7, "push": 7, "an": [7, 10, 27], "authent": 7, "error": 7, "clone": 7, "http": 7, "now": 7, "can": 7, "t": 7, "my": 7, "what": 7, "do": [7, 17], "need": [7, 17], "help": 7, "content": [8, 12, 18, 20], "singl": [9, 10], "spack": [10, 21, 22, 23, 24], "version": 10, "dev": 10, "depend": [10, 21], "more": 10, "advanc": 10, "usag": [10, 13, 21, 23, 30], "multipl": 10, "other": [10, 27, 30], "all": [10, 17], "ad": [10, 15], "anoth": 10, "write": [11, 14, 16, 17], "gaudi": [11, 14, 16, 28, 29, 31], "algorithm": [11, 16], "function": [11, 13, 17], "walkthrough": 11, "The": [11, 14, 16, 17], "steer": [11, 16], "file": [11, 14, 16, 17, 27, 31], "initi": 11, "final": 11, "debug": 11, "gdb": 11, "avoid": 11, "const": 11, "oper": 11, "Tos": 12, "instruct": 12, "standalon": [13, 30], "convers": [13, 16], "from": [13, 17, 31], "lcio": [13, 16, 27, 28], "edm4hep": [13, 14, 17, 27, 28, 30, 31], "patch": 13, "miss": 13, "collect": [13, 14, 17], "fly": 13, "convert": [13, 16], "lcrelat": 13, "onli": [13, 14], "subset": [13, 14, 17], "renam": 13, "librari": 13, "data": [13, 17, 21], "handl": 13, "relat": [13, 17], "entir": 13, "event": [13, 14, 16, 17, 27, 29], "paramet": 13, "subtl": 13, "between": 13, "reconstructedparticl": 13, "read": [14, 16, 17], "k4datasvc": 14, "argument": 15, "k4run": [15, 31], "wrap": 16, "marlin": [16, 28], "processor": 16, "marlinprocessorwrapp": 16, "automat": 16, "xml": 16, "limit": 16, "edm": [16, 17], "option": [16, 31], "common": 17, "model": 17, "import": 17, "resourc": 17, "doxygen": 17, "api": 17, "document": 17, "diagram": 17, "associ": 17, "tabl": 17, "avail": 17, "type": 17, "navig": 17, "refer": 17, "page": 17, "why": 17, "ar": 17, "so": 17, "mani": 17, "class": 17, "them": 17, "some": 17, "util": 17, "podio": 17, "technic": [17, 21, 23], "infrastructur": 17, "which": [17, 21], "thing": 17, "three": 17, "layer": 17, "basic": 17, "valu": 17, "semant": 17, "guess": 17, "interfac": 17, "yaml": [17, 24], "definit": 17, "xyz": 17, "mutablexyx": 17, "frame": 17, "contain": 17, "put": 17, "low": 17, "level": 17, "reader": 17, "root": 17, "layout": 17, "figur": 17, "out": 17, "legaci": 17, "dump": 17, "extern": 18, "link": 18, "stack": [19, 28], "central": 19, "cvmf": [19, 21, 23], "librarian": 20, "further": 21, "topic": 21, "check": 21, "newli": 21, "requir": 21, "certain": 21, "variant": 21, "global": 21, "system": 21, "target": 21, "architectur": 21, "bundl": 21, "compil": [21, 24], "duplic": 21, "recip": [21, 24], "downstream": 21, "wrapper": 21, "lcg": 21, "releas": [21, 24], "gcc": 21, "buildcach": 22, "nightli": 23, "inform": [23, 28], "download": 24, "instanc": 24, "user": 24, "upstream": 24, "addit": 24, "talk": 25, "present": 25, "tutori": 26, "exercis": 26, "displai": 27, "input": [27, 28], "creat": [27, 31], "detail": 27, "troubleshoot": 27, "detector": 27, "clic": 28, "simul": [28, 30, 31], "reconstruct": [28, 31], "through": 28, "k4marlinwrapp": [28, 29], "dd4hep": 28, "geometri": 28, "multithread": 29, "support": 29, "inter": 29, "parallel": 29, "delph": 30, "fast": 30, "output": 30, "prerequisit": 30, "execut": 30, "framework": 30, "ild": 31, "ildreconstruct": 31, "py": 31, "ildconfig": 31, "adapt": 31}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 60}, "alltitles": {"Contributor Code of Conduct": [[1, "contributor-code-of-conduct"]], "Contributing": [[2, "contributing"]], "Getting Started": [[2, "getting-started"]], "Software": [[3, "software"]], "Call for logos": [[4, "call-for-logos"]], "Building Key4hep using CMake: For Developers": [[5, "building-key4hep-using-cmake-for-developers"]], "Possible issues": [[5, "possible-issues"]], "Packages that have been tested": [[5, "packages-that-have-been-tested"]], "Changing to a different commit or branch": [[5, "changing-to-a-different-commit-or-branch"]], "CMake guide for Key4hep software": [[6, "cmake-guide-for-key4hep-software"]], "Overview": [[6, "overview"], [7, "overview"]], "Quick start into building Key4hep Software": [[6, "quick-start-into-building-key4hep-software"]], "Set up the environment": [[6, "set-up-the-environment"]], "Running CMake": [[6, "running-cmake"]], "Using your local installation": [[6, "using-your-local-installation"]], "CMake example packages": [[6, "cmake-example-packages"]], "Changing the CMake Configuration": [[6, "changing-the-cmake-configuration"]], "Runtime Environment": [[6, "runtime-environment"]], "CTest in Key4hep": [[6, "ctest-in-key4hep"]], "Customizing how CMake is run": [[6, "customizing-how-cmake-is-run"]], "Github workflow and contribution guide": [[7, "github-workflow-and-contribution-guide"]], "First time setup of git": [[7, "first-time-setup-of-git"]], "Generate and set up ssh keys for github": [[7, "generate-and-set-up-ssh-keys-for-github"]], "Improving your git experience": [[7, "improving-your-git-experience"]], "Development workflow": [[7, "development-workflow"]], "Keeping your local repository up to date": [[7, "keeping-your-local-repository-up-to-date"]], "Contributing code": [[7, "contributing-code"]], "Recommendations": [[7, "recommendations"]], "General recommendations": [[7, "general-recommendations"]], "Commit comments": [[7, "commit-comments"]], "Cleaning history": [[7, "cleaning-history"]], "Pull requests": [[7, "pull-requests"]], "Trouble-shooting": [[7, "trouble-shooting"]], "When I try to push to the repository, I get an authentication error": [[7, "when-i-try-to-push-to-the-repository-i-get-an-authentication-error"]], "I have cloned with https and now I can\u2019t push my changes, what do I do?": [[7, "i-have-cloned-with-https-and-now-i-can-t-push-my-changes-what-do-i-do"]], "Need help?": [[7, "need-help"]], "Developing Key4hep": [[8, "developing-key4hep"]], "Contents:": [[8, null], [18, null], [20, null]], "Developing a single package": [[9, "developing-a-single-package"], [10, "developing-a-single-package"]], "Building Key4hep using Spack: For Developers": [[10, "building-key4hep-using-spack-for-developers"]], "Spack set up": [[10, "spack-set-up"]], "Installing a local version with dev-build": [[10, "installing-a-local-version-with-dev-build"]], "Using the local version as dependency": [[10, "using-the-local-version-as-dependency"]], "More advanced usage": [[10, "more-advanced-usage"]], "Developing multiple packages or dependencies of other packages": [[10, "developing-multiple-packages-or-dependencies-of-other-packages"]], "Using an environment to setup all dependencies": [[10, "using-an-environment-to-setup-all-dependencies"]], "Environments and a development workflow": [[10, "environments-and-a-development-workflow"]], "Adding another package to develop": [[10, "adding-another-package-to-develop"]], "Writing Gaudi Algorithms": [[11, "writing-gaudi-algorithms"]], "Gaudi": [[11, "gaudi"]], "Gaudi::Functional": [[11, "gaudi-functional"]], "Setup": [[11, "setup"], [31, "setup"]], "Walkthrough of Functional Algorithms": [[11, "walkthrough-of-functional-algorithms"]], "The steering file": [[11, "the-steering-file"]], "Initialize and finalize": [[11, "initialize-and-finalize"]], "Debugging: How to use GDB": [[11, "debugging-how-to-use-gdb"]], "Avoiding const in operator()": [[11, "avoiding-const-in-operator"]], "Key4hep How-Tos and Instructions": [[12, "key4hep-how-tos-and-instructions"]], "Contents": [[12, null]], "Standalone conversion from LCIO to EDM4hep": [[13, "standalone-conversion-from-lcio-to-edm4hep"]], "Patching missing collections on the fly": [[13, "patching-missing-collections-on-the-fly"]], "Example:": [[13, "example"]], "Converting LCRelation collections": [[13, "converting-lcrelation-collections"]], "Converting only a subset of collections": [[13, "converting-only-a-subset-of-collections"]], "Renaming collections on the fly": [[13, "renaming-collections-on-the-fly"]], "Library usage of the conversion functions": [[13, "library-usage-of-the-conversion-functions"]], "Converting collection (data)": [[13, "converting-collection-data"]], "Handling relations": [[13, "handling-relations"]], "Handling of subset collections": [[13, "handling-of-subset-collections"]], "Handling of LCRelations": [[13, "handling-of-lcrelations"]], "Converting entire events": [[13, "converting-entire-events"]], "Converting Event parameters": [[13, "converting-event-parameters"]], "Subtle differences between LCIO and EDM4hep": [[13, "subtle-differences-between-lcio-and-edm4hep"]], "Example for a ReconstructedParticle Collection": [[13, "example-for-a-reconstructedparticle-collection"]], "Reading and writing EDM4hep files in Gaudi": [[14, "reading-and-writing-edm4hep-files-in-gaudi"]], "The k4DataSvc": [[14, "the-k4datasvc"]], "Reading events": [[14, "reading-events"]], "Writing events": [[14, "writing-events"]], "Writing only a subset of collections": [[14, "writing-only-a-subset-of-collections"]], "Adding custom arguments to k4run": [[15, "adding-custom-arguments-to-k4run"]], "Wrapping Marlin processors in Gaudi": [[16, "wrapping-marlin-processors-in-gaudi"]], "The MarlinProcessorWrapper Gaudi algorithm": [[16, "the-marlinprocessorwrapper-gaudi-algorithm"]], "Reading and writing LCIO events with Gaudi": [[16, "reading-and-writing-lcio-events-with-gaudi"]], "Automatic conversion of Marlin XML steering files": [[16, "automatic-conversion-of-marlin-xml-steering-files"]], "Limitations": [[16, "limitations"]], "Using the EDM converters": [[16, "using-the-edm-converters"]], "Configuration options": [[16, "configuration-options"]], "EDM4hep - The common event data model": [[17, "edm4hep-the-common-event-data-model"]], "Important resources": [[17, "important-resources"]], "Doxygen API documentation": [[17, "doxygen-api-documentation"]], "The overview diagram": [[17, "the-overview-diagram"]], "Relations": [[17, "relations"]], "Associations": [[17, "associations"]], "The table of available types": [[17, "the-table-of-available-types"]], "Navigating the doxygen reference page": [[17, "navigating-the-doxygen-reference-page"]], "Why are there so many classes and do I need all of them?": [[17, "why-are-there-so-many-classes-and-do-i-need-all-of-them"]], "Some utility functionality": [[17, "some-utility-functionality"]], "podio - The technical infrastructure on which things run": [[17, "podio-the-technical-infrastructure-on-which-things-run"]], "podio code generation": [[17, "podio-code-generation"]], "The three layers of podio": [[17, "the-three-layers-of-podio"]], "Basics of generated code - value semantics": [[17, "basics-of-generated-code-value-semantics"]], "Guessing the interface from the yaml definition": [[17, "guessing-the-interface-from-the-yaml-definition"]], "Why is there a XYZ and a MutableXYX?": [[17, "why-is-there-a-xyz-and-a-mutablexyx"]], "Writing function interfaces": [[17, "writing-function-interfaces"]], "Subset collections": [[17, "subset-collections"]], "The podio::Frame container": [[17, "the-podio-frame-container"]], "Getting collections from a Frame": [[17, "getting-collections-from-a-frame"]], "Putting a collection into a Frame": [[17, "putting-a-collection-into-a-frame"]], "Reading EDM4hep files": [[17, "reading-edm4hep-files"]], "The available low level readers": [[17, "the-available-low-level-readers"]], "ROOT file layout of podio generated EDMs": [[17, "root-file-layout-of-podio-generated-edms"]], "How do I figure out if a file is legacy?": [[17, "how-do-i-figure-out-if-a-file-is-legacy"]], "podio-dump": [[17, "podio-dump"]], "Key4hep": [[18, "key4hep"]], "External links:": [[18, null]], "Getting started with Key4hep software": [[19, "getting-started-with-key4hep-software"]], "Setting up the Key4hep Software Stack": [[19, "setting-up-the-key4hep-software-stack"]], "Using a central installation on cvmfs": [[19, "using-a-central-installation-on-cvmfs"]], "Building Key4hep: For Librarians": [[20, "building-key4hep-for-librarians"]], "Spack Usage and Further Technical Topics": [[21, "spack-usage-and-further-technical-topics"]], "Checking which packages will be newly installed": [[21, "checking-which-packages-will-be-newly-installed"]], "Requiring certain variants globally": [[21, "requiring-certain-variants-globally"]], "System Dependencies": [[21, "system-dependencies"]], "Target Architectures": [[21, "target-architectures"]], "Bundle Packages and Environments": [[21, "bundle-packages-and-environments"]], "Setting Up Runtime Environments": [[21, "setting-up-runtime-environments"]], "Compiler Dependencies and Data Packages": [[21, "compiler-dependencies-and-data-packages"]], "Duplicating Recipes in Downstream Repositories": [[21, "duplicating-recipes-in-downstream-repositories"]], "CVMFS Installation Workflow": [[21, "cvmfs-installation-workflow"]], "Compiler Wrappers": [[21, "compiler-wrappers"]], "Spack-Installed LCG releases": [[21, "spack-installed-lcg-releases"]], "Using Spack-installed GCC": [[21, "using-spack-installed-gcc"]], "Spack Buildcaches": [[22, "spack-buildcaches"]], "Nightly Builds with Spack": [[23, "nightly-builds-with-spack"]], "Usage of the nightly builds on CVMFS": [[23, "usage-of-the-nightly-builds-on-cvmfs"]], "Technical Information": [[23, "technical-information"]], "Setting up Spack": [[24, "setting-up-spack"]], "Downloading a spack instance": [[24, "downloading-a-spack-instance"]], "Using Spack Environments": [[24, "using-spack-environments"]], "Using the key4hep-release-user environment": [[24, "using-the-key4hep-release-user-environment"]], "Configuring Spack": [[24, "configuring-spack"]], "Installing Spack": [[24, "installing-spack"]], "Installing the key4hep package recipes": [[24, "installing-the-key4hep-package-recipes"]], "Configuring packages.yaml": [[24, "configuring-packages-yaml"]], "Configuring upstreams.yaml": [[24, "configuring-upstreams-yaml"]], "Setting up additional compilers": [[24, "setting-up-additional-compilers"]], "Talks and Presentations": [[25, "talks-and-presentations"]], "Key4hep Tutorials": [[26, "key4hep-tutorials"]], "Exercises": [[26, null]], "Running an Event Display with EDM4hep or LCIO input": [[27, "running-an-event-display-with-edm4hep-or-lcio-input"]], "Setting up an environment": [[27, "setting-up-an-environment"]], "Creating an input file": [[27, "creating-an-input-file"]], "Running the event display": [[27, "running-the-event-display"]], "Details": [[27, "details"]], "Troubleshooting / Using other detectors": [[27, "troubleshooting-using-other-detectors"]], "Using the Key4hep-Stack for CLIC Simulation and Reconstruction": [[28, "using-the-key4hep-stack-for-clic-simulation-and-reconstruction"]], "Simulation": [[28, "simulation"]], "Reconstruction": [[28, "reconstruction"], [31, "reconstruction"]], "Reconstruction with Marlin": [[28, "reconstruction-with-marlin"]], "Reconstruction with Gaudi through k4MarlinWrapper": [[28, "reconstruction-with-gaudi-through-k4marlinwrapper"]], "Reconstruction with LCIO input": [[28, "reconstruction-with-lcio-input"]], "Reconstruction with EDM4hep input": [[28, "reconstruction-with-edm4hep-input"]], "DD4hep Geometry Information": [[28, "dd4hep-geometry-information"]], "How to run multithreading with k4MarlinWrapper (Gaudi)": [[29, "how-to-run-multithreading-with-k4marlinwrapper-gaudi"]], "Running Gaudi with multithreading support": [[29, "running-gaudi-with-multithreading-support"]], "How to run with inter-event parallelism": [[29, "how-to-run-with-inter-event-parallelism"]], "Running example": [[29, "running-example"]], "Running Delphes fast simulation with EDM4hep output": [[30, "running-delphes-fast-simulation-with-edm4hep-output"]], "Setup and prerequisites": [[30, "setup-and-prerequisites"]], "Standalone executables": [[30, "standalone-executables"]], "Other standalone executables": [[30, "other-standalone-executables"]], "Usage in the Key4hep framework": [[30, "usage-in-the-key4hep-framework"]], "Running ILD simulation and reconstruction": [[31, "running-ild-simulation-and-reconstruction"]], "Running the simulation": [[31, "running-the-simulation"]], "Using ILDReconstruction.py from ILDConfig": [[31, "using-ildreconstruction-py-from-ildconfig"]], "Creating a Gaudi options file": [[31, "creating-a-gaudi-options-file"]], "Adapting the options file for EDM4hep": [[31, "adapting-the-options-file-for-edm4hep"]], "Running the reconstruction with k4run": [[31, "running-the-reconstruction-with-k4run"]]}, "indexentries": {}}) \ No newline at end of file diff --git a/setup-and-getting-started/README.html b/setup-and-getting-started/README.html new file mode 100644 index 0000000..db6e207 --- /dev/null +++ b/setup-and-getting-started/README.html @@ -0,0 +1,160 @@ + + + + + + + Getting started with Key4hep software — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Getting started with Key4hep software

+
+

Setting up the Key4hep Software Stack

+
+

Using a central installation on cvmfs

+

Two builds with the key4hep stack are distributed on cvmfs. The releases happen +every few months on demand (for example, if there is a new important feature or +a breaking change) and at the moment Ubuntu22.04 and AlmaLinux9 (EL9, +RockyLinux9) are supported. We also have older releases for CentOS7 but are not +making any new builds for that.

+
source /cvmfs/sw.hsf.org/key4hep/setup.sh
+
+
+

In addition, nightly builds for AlmaLinux 9 and Ubuntu 22.04 with the latest +version of most of the packages are available:

+
source /cvmfs/sw-nightlies.hsf.org/key4hep/setup.sh
+
+
+

The setup.sh script always points to the latest build and it will change +without warning. However, after sourcing the script some information will be +displayed with instructions on how to reproduce the current environment. +Nightly builds are intended for development and testing and they will be +deleted after some time from /cvmfs. They will also introduce new features +unannounced, so don’t use these for anything else than development!

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/spack-build-instructions-for-librarians/README.html b/spack-build-instructions-for-librarians/README.html new file mode 100644 index 0000000..a8638ff --- /dev/null +++ b/spack-build-instructions-for-librarians/README.html @@ -0,0 +1,159 @@ + + + + + + + Building Key4hep: For Librarians — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Building Key4hep: For Librarians

+

Key4hep comprises a fairly large number of software and depends on even more externals, so some tooling is needed to efficiently build the whole software stack. The spack package manager can be used to build scientific software at scale, and is part of the Key4hep software R&D program.

+

A spack install of Key4hep is regularly deployed to /cvmfs/sw.hsf.org/, and can be used on lxplus/centos7 just by sourcing the following setup script:

+
source /cvmfs/sw.hsf.org/key4hep/setup.sh
+
+
+

In this page, the workflow to create this installation is documented.

+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/spack-build-instructions-for-librarians/spack-advanced.html b/spack-build-instructions-for-librarians/spack-advanced.html new file mode 100644 index 0000000..c26bd71 --- /dev/null +++ b/spack-build-instructions-for-librarians/spack-advanced.html @@ -0,0 +1,264 @@ + + + + + + + Spack Usage and Further Technical Topics — Key4hep documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Spack Usage and Further Technical Topics

+

This page collects a few known workarounds for issues and areas of development in spack. +Check also the issues in key4hep-spack for up-to-date information. +Additionally, we also provide a few more advanced invocations of spack commands that allow a certain degree of debugging of the decisions spack has made when installing a given package and its dependencies.

+
+

Checking which packages will be newly installed

+

When installing a package it might be interesting to estimate how long it will take to do so. +An important proxy for this is how many and which dependencies spack will install in order to build a package. +This can be done with the spack solve command, which invokes the concretizer and then spits out the solution that would be installed if the same arguments were passed to spack install, e.g.

+
spack solve -I
+
+
+
==> Best of 12 considered solutions.
+==> Optimization Criteria:
+  Priority  Criterion                                            Installed  ToBuild
+  1         number of input specs not concretized                        -        0
+  2         number of packages to build (vs. reuse)                      -        4
+  3         requirement weight                                           0        0
+  4         deprecated versions used                                     1        0
+  5         version weight                                               0        0
+  6         number of non-default variants (roots)                       0        0
+  7         preferred providers for roots                                0        0
+  8         default values of variants not being used (roots)            0        0
+  9         number of non-default variants (non-roots)                   3        0
+  10        preferred providers (non-roots)                              0        0
+  11        compiler mismatches                                          0        0
+  12        OS mismatches                                                0        0
+  13        non-preferred OS's                                           0        0
+  14        version badness                                            156        0
+  15        default values of variants not being used (non-roots)        1        0
+  16        non-preferred compilers                                      0        0
+  17        target mismatches                                            0        0
+  18        non-preferred targets                                      165       44
+
+ -   whizard@3.0.3%gcc@10.3.0~fastjet~latex~lcio~lhapdf~openloops~openmp+pythia8 hepmc=3 arch=linux-ubuntu20.04-x86_64
+[+]      ^hepmc3@3.2.4%gcc@10.3.0~interfaces~ipo~python~rootio build_type=RelWithDebInfo arch=linux-ubuntu20.04-x86_64
+[+]          ^cmake@3.16.3%gcc@10.3.0~doc+ncurses+ownlibs~qt build_type=RelWithDebInfo patches=1c54004,bf695e3 arch=linux-ubuntu20.04-x86_64
+ -       ^libtirpc@1.2.6%gcc@10.3.0 arch=linux-ubuntu20.04-x86_64
+ -           ^krb5@1.19.3%gcc@10.3.0+shared arch=linux-ubuntu20.04-x86_64
+[+]              ^bison@3.8.2%gcc@10.3.0 arch=linux-ubuntu20.04-x86_64
+[+]                  ^diffutils@3.8%gcc@10.3.0 arch=linux-ubuntu20.04-x86_64
+[+]                      ^libiconv@1.16%gcc@10.3.0 libs=shared,static arch=linux-ubuntu20.04-x86_64
+[+]                  ^m4@1.4.18%gcc@10.3.0+sigsegv patches=3877ab5,fc9b616 arch=linux-ubuntu20.04-x86_64
+[+]                  ^perl@5.30.0%gcc@10.3.0~cpanm+shared+threads arch=linux-ubuntu20.04-x86_64
+[+]              ^gettext@0.21%gcc@10.3.0+bzip2+curses+git~libunistring+libxml2+tar+xz arch=linux-ubuntu20.04-x86_64
+[+]                  ^bzip2@1.0.8%gcc@10.3.0~debug~pic+shared arch=linux-ubuntu20.04-x86_64
+[+]                  ^libxml2@2.9.13%gcc@10.3.0~python arch=linux-ubuntu20.04-x86_64
+[+]                      ^pkgconf@1.8.0%gcc@10.3.0 arch=linux-ubuntu20.04-x86_64
+[+]                      ^xz@5.2.5%gcc@10.3.0~pic libs=shared,static arch=linux-ubuntu20.04-x86_64
+[+]                      ^zlib@1.2.12%gcc@10.3.0+optimize+pic+shared patches=0d38234 arch=linux-ubuntu20.04-x86_64
+[+]                  ^ncurses@6.2%gcc@10.3.0~symlinks+termlib abi=none arch=linux-ubuntu20.04-x86_64
+[+]                  ^tar@1.30%gcc@10.3.0 zip=pigz arch=linux-ubuntu20.04-x86_64
+[+]              ^openssl@1.1.1f%gcc@10.3.0~docs~shared certs=mozilla arch=linux-ubuntu20.04-x86_64
+ -       ^ocaml@4.13.1%gcc@10.3.0+force-safe-string arch=linux-ubuntu20.04-x86_64
+[+]      ^pythia8@8.306%gcc@10.3.0~evtgen~fastjet~hdf5+hepmc+hepmc3~lhapdf~madgraph5amc~mpich~openmpi~python~rivet~root+shared arch=linux-ubuntu20.04-x86_64
+[+]          ^hepmc@2.06.11%gcc@10.3.0~ipo build_type=RelWithDebInfo length=MM momentum=GEV arch=linux-ubuntu20.04-x86_64
+[+]          ^rsync@3.1.3%gcc@10.3.0 arch=linux-ubuntu20.04-x86_64
+
+
+

The -I flag shows which packages are alrady installed. +spack solve also shows some information about all the things that were considered during concretization. It can also be used to dump more information on the concretization process. +Unfortunately, this information is rather hard to parse, and still a work in progress from the spack developers.

+
+
+

Requiring certain variants globally

+

spack can be configured using some configuration +files. Specifically +using packages.yaml which is read from the user directory, i.e. ~/.spack (or +/.spack/linux) can be used to enforce the value of certain default variants +globally. To solve the above problem it is enough to put the following into +packages.yaml:

+
packages:
+  all:
+  variants: cxxstd=17
+
+
+

It is still possible to override this for certain packages either by +individually configuring them in packages.yaml or via the command line which +take precedence over all configuration files.

+

In the Key4hep software stack build recipes for releases, we use the same mechanism, as this configuration is also available from spack environments.

+
+
+

System Dependencies

+

Some spack packages have external find support. For these packages it is possible to let spack detect the variants and versions for system (or otherwise) installed packages. +For such cases use the spack external find command. It has to be noted that detecting external packages and using them does not always work perfectly.

+
+
+

Target Architectures

+

Since HEP software is usually deployed on a variety of machines via cvmfs, installations need to pick a target architecture. broadwell is for now the default choice, and can be set with:

+
packages:
+  all:
+    target: [broadwell]
+
+
+

in $HOME/.spack/linux/packages.yaml

+
+
+

Bundle Packages and Environments

+

Right now, key4hep is installed via a BundlePackage, that depends on all other relevant packages. +An alternative would be to use spack environments. This alternative is still under investigation.

+
+
+

Setting Up Runtime Environments

+

The simplest way to set the environment to use spack installed packages is to use the spack load command. +In order for users not to have to set up spack when it is not needed, the key4hep-stack bundle package includes a script that will automatically generate a bash setup script and install it into its prefix.

+

Spack can also create “filesystem views” of several packages, resulting in a directory structure similar what you would find in /usr/local. +This simplifies library and include paths, but the setup generation for views still has to be developed.

+
+
+

Compiler Dependencies and Data Packages

+

Some HEP packages (like geant4-data) consist only of data files, and can thus be used on any platform. +Spack cannot yet handle this gracefully, but an ongoing development tries to treat compilers as dependencies, which would help with re-using data packages.

+
+
+

Duplicating Recipes in Downstream Repositories

+

Although it is possible to “patch” spack build recipes by overriding them in another repository (key4hep-spack, for example), this is discouraged. +The central repo is one of the strenghts of spack, with many contributors ensuring that packages build smoothly. +Also, packages are installed in different namespaces, so it is not possible to deprecate changed recipes and use the upstream ones without re-installing the packages.

+
+
+

CVMFS Installation Workflow

+

The distribution on cvmfs is an exact copy of the spack installation on the build machine, just copied with this rsync command on the publisher:

+
rsync -axv --inplace --delete    --verbose -e "ssh -T  -o Compression=no -o StrictHostKeyChecking=no -o GSSAPIAuthentication=yes -o GSSAPITrustDNS=yes" user@build-machine:/cvmfs/sw.hsf.org/spackages/ /cvmfs/sw.hsf.org/spackages/
+
+
+

The --delete option can be omitted in order to preserve already installed packages, regardless of the state of the build machine.

+
+
+

Compiler Wrappers

+

Spack uses compiler wrappers instead of exposing the actual compilers during the build. +For packages like whizard, which register the compiler path to use during runtime, this will not work, as the wrappers are not available at runtime. +For these packages, the current workaround is to force spack to use the actual compilers during build (see the build recipe of whizard).

+
+
+

Spack-Installed LCG releases

+

A spack installation that contains all packages in the LCG releases is work in progress, see https://gitlab.cern.ch/sft/sft-spack-repo.

+
+
+

Using Spack-installed GCC

+

When installing gcc with spack, it is necessary to add a cc symlink to $PATH, in order to avoid errors with cling, see https://github.com/spack/spack/issues/17488.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/spack-build-instructions-for-librarians/spack-buildcache.html b/spack-build-instructions-for-librarians/spack-buildcache.html new file mode 100644 index 0000000..47520f0 --- /dev/null +++ b/spack-build-instructions-for-librarians/spack-buildcache.html @@ -0,0 +1,155 @@ + + + + + + + Spack Buildcaches — Key4hep documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Spack Buildcaches

+

{% callout “Spack documentation” %}

+

Buildcaches were investigated, but are no longer supported for Key4hep software, due to the difficulty of relocating some packages.

+

For more information refer to the spack documentation.

+

{% endcallout %}

+

It is possible to relocate and re-use binaries with the so-called buildcache. +Some central buildcaches are on the key4hep eos space under:

+
/eos/project/k/key4hep/www/key4hep/spack_build/mirror/spackages
+
+
+

spackages is intended as the central buildcache for key4hep packages built from scratch, +but there exist other buildcaches for packages built against the LCG releases, and rolling builds that are using the branchname master or other moving targets. +All packages versioned package@master are treated by spack as the same version, even if master points to different commits, thus they must be installed to separate directories, ideally indicating the date. +A buildcache called contrib is intended for build tools such as compilers. +Spack automatically creates subdirectory for different platforms and compiler versions.

+

For write permissions to this space, subscribe to the egroup cernbox-project-key4hep-writers.

+

The following command can be used to put packages into the buildcache:

+
# key4hep-stack was already installed with 'spack install key4hep-stack'
+spack mirror add key4hep /eos/project/k/key4hep/www/key4hep/spack_build/mirror/spackages
+spack buildcache create -m key4hep -u -a -f key4hep-stack
+
+
+

Since the packages need to be relocated as well as copied, this might take up to an hour.

+

In order to install packages from the buildcache, use:

+
spack buildcache install -u -a key4hep-stack
+
+
+

Spack will then search all added mirrors for key4hep-stack. +For read-only access on machines without eos, these files are served also over http:

+
spack mirror add key4hep-web http://key4hep.web.cern.ch/key4hep/spack_build/mirror/spackages/
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/spack-build-instructions-for-librarians/spack-nightlies.html b/spack-build-instructions-for-librarians/spack-nightlies.html new file mode 100644 index 0000000..1ce4eeb --- /dev/null +++ b/spack-build-instructions-for-librarians/spack-nightlies.html @@ -0,0 +1,139 @@ + + + + + + + Nightly Builds with Spack — Key4hep documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Nightly Builds with Spack

+
+

Usage of the nightly builds on CVMFS

+

For Centos7, the latest nightly build can be set up by running:

+
source /cvmfs/sw-nightlies.hsf.org/key4hep/setup.sh
+
+
+

Spack can also be configured to use /cvmfs/sw-nightlies.hsf.org/spackages as an upstream installation.

+
+
+

Technical Information

+

Nightly builds can be a very useful tool, both to test code correctness and to quickly and automatically deploy the latest developments. +In contrast to the release builds, which use the latest stable version of the individual packages, nightly builds typically use the HEAD of the main development branch.

+

It is not very efficient to completely rebuild the stack every day, as some packages change fairly infrequently. +The key4hep-spack repository includes some scripts in order to use commit hashes as versions.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/spack-build-instructions-for-librarians/spack-setup.html b/spack-build-instructions-for-librarians/spack-setup.html new file mode 100644 index 0000000..80fee0e --- /dev/null +++ b/spack-build-instructions-for-librarians/spack-setup.html @@ -0,0 +1,237 @@ + + + + + + + Setting up Spack — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Setting up Spack

+
+

Downloading a spack instance

+

Spack is easy to set up: simply clone the key4hep fork, and use one of the provided spack “environments”, that is spack configuration that is created automatically from the current key4hep/key4hep-spack repository.

+
git clone https://github.com/spack/spack
+git clone https://github.com/key4hep/key4hep-spack
+source spack/share/spack/setup-env.sh
+source key4hep-spack/environments/key4hep-release-user/setup_clingo_centos7.sh # NOTE: only needed on centos7
+spack env activate key4hep-spack/environments/key4hep-release-user # or other environment, see below
+
+
+

These instructions assume that a Centos7 machine with a running CVMFS client is used (for other OSs see below). Since Spack cannot bootstrap with the system compiler on Centos7, a setup script for Clingo ( a spack dependency ) is provided.

+
+
+

Using Spack Environments

+

The spack environments available in key4hep-spack/environments bundle the spack configuration, setting up a suitable compiler from cvmfs, the key4hep package recipes, whether to create a view, etc. It is recommended to always use spack in an environment. New environments can be easily created by copying and modifying existing ones, but some use relative links to common configuration files in key4hep-spack/environments/key4hep-common, so they should be kept in the key4hep/environments directory.

+

The basic environment is key4hep-release, which is used for the central installations and therefore uses /cvmfs as install area. key4hep-debug is a variation for debug builds. The default compiler is gcc, but an environment that uses clang is provided under key4hep-release-clang. +For local builds that use cvmfs read-only, key4hep-release-user can be used.

+
+
+

Using the key4hep-release-user environment

+

The key4hep user environment has the key4hep-stack bundle package in its spec list. By concretizing it, spack selects the latest compatible versions, re-using installations from cvmfs

+
spack concretize -f
+spack find # lists the available concretized packages
+
+
+

The environment can be installed as is, although this will just install the bundle packages. However, this will create a setup script that can be used to load the software.

+
spack install
+
+
+

Custom builds can now be realized, by adding specs to the environment and concretizing together. For example, to build the stack with a local version of EDM4hep:

+
spack add edm4hep@master
+git clone https://github.com/key4hep/edm4hep
+# make some local changes to edm4hep
+spack develop -p $PWD/edm4hep edm4hep@master
+spack concretize -f
+spack install
+
+
+
+
+
+

Configuring Spack

+

Alternatively, and for other platforms, spack can be configured in a few steps. These steps are essentially what is used to create the pre-configured spack instance in this script: https://github.com/key4hep/key4hep-spack/blob/master/scripts/ci_setup_spack.sh

+

While this still puts the configuration files in the global scope of spack, it is recommended to use them in an environment, as provided by key4hep-spack.

+
+

Installing Spack

+

Spack itself is very easy to install - simply clone the repository with git.

+
git clone https://github.com/spack/spack.git
+source spack/share/spack/setup-env.sh
+
+
+
+
+

Installing the key4hep package recipes

+

The spack repository for key4hep packages is installed the same way:

+
git clone https://github.com/key4hep/key4hep-spack.git
+spack repo add key4hep-spack
+
+
+
+
+
+

Configuring packages.yaml

+

In order to choose the right package versions and build options, spack sometimes needs a few hints and nudges. With the new concretizer (default as of spack version 0.17) this should be mostly obsolete. +key4hep-spack ships a spack config file that should give a good build customization out of the box, but can also be customized further. It just needs to be copied to the configuration where spack searches for configurations:

+
cp key4hep-spack/environments/key4hep-common/packages.yaml spack/etc/spack/
+
+
+
+

Configuring upstreams.yaml

+

The cvmfs installation can be used as an “upstream installation”, by adding the following configuration:

+
cat <<EOT >> spack/etc/spack/upstreams.yaml
+upstreams:
+  spack-instance-1:
+      install_tree: /cvmfs/sw.hsf.org/spackages6/
+EOT
+
+
+
+
+

Setting up additional compilers

+

Often it is practical to use a compiler already installed upstream. Spack provides the spack compiler find command for this, but the compiler needs to be loaded into the PATH:

+
# loading the compiler from upstream
+source /cvmfs/sft.cern.ch/lcg/contrib/gcc/11.2.0/x86_64-centos7/setup.sh
+spack compiler find --scope site
+
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/talks-and-presentations/README.html b/talks-and-presentations/README.html new file mode 100644 index 0000000..7c8225b --- /dev/null +++ b/talks-and-presentations/README.html @@ -0,0 +1,163 @@ + + + + + + + Talks and Presentations — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Talks and Presentations

+

A Zotero group with the items listed below can be found here.

+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/tutorials/README.html b/tutorials/README.html new file mode 100644 index 0000000..8c570b9 --- /dev/null +++ b/tutorials/README.html @@ -0,0 +1,203 @@ + + + + + + + Key4hep Tutorials — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Key4hep Tutorials

+

This page contains several tutorials for working in a Key4hep software stack. We +try to design and set them up in a way that they can be done at any time but we +present them at hands-on tutorial sessions as well. This is an incomplete list +of all available tutorials, which you can find in the +key4hep-tutorials repository.

+

If you are following these tutorials and run into an issue please let us know +by opening an issue +on the key4hep-doc repository. If +you have the feeling that something is missing, we are also very happy to accept +new tutorial suggestions. If you have a tutorial that you would like to add +here.

+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/tutorials/k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/CEDViaWrapper.html b/tutorials/k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/CEDViaWrapper.html new file mode 100644 index 0000000..7e2fbfa --- /dev/null +++ b/tutorials/k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/CEDViaWrapper.html @@ -0,0 +1,221 @@ + + + + + + + Running an Event Display with EDM4hep or LCIO input — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ + +
+

Running an Event Display with EDM4hep or LCIO input

+

It is possible to run the C Event Display (CED) via a wrapped CEDViewer Marlin Processor. This makes it possible to run the Event Display with EDM4hep input files using an on the fly conversion to LCIO for CED. This introduction shows the basic concepts and also provides a options file that should work for most use cases. This example will be using the CLIC detector but should also work for other DD4hep detector models. The example is fully self contained, if you already have everything set up you can jump directly to running the event display.

+
+

Setting up an environment

+

The following steps have been tested with the Key4hep nightly builds release which can be setup using

+
source /cvmfs/sw-nightlies.hsf.org/key4hep/setup.sh
+
+
+

To get the CLIC detector description we clone the CLICPerformance repository

+
git clone https://github.com/iLCSoft/CLICPerformance
+
+
+

All the following steps assume that the environment is setup like above and that the detector description is in the CLICPerformance directory. All commands start from the directory from which git clone has been executed.

+
+
+

Creating an input file

+

To create an input file for the event display we run a simple detector simulation using ddsim and a particle gun that shoots photons. The input file that we create here for illustration purposes has only 10 events, which also means that the creation should only take a few minutes. The steps to create this file are the following

+
ddsim --steeringFile CLICPerformance/clicConfig/clic_steer.py \
+      --compactFile $K4GEO/CLIC/compact/CLIC_o3_v14/CLIC_o3_v14.xml \
+      --enableGun \
+      --gun.distribution uniform \
+      --gun.particle gamma \
+      --gun.energy 10*GeV \
+      --outputFile gamma_10GeV_edm4hep.root \
+      --numberOfEvents 10
+
+
+

You should now have a gamma_10GeV_edm4hep.root file containing 10 events.

+
+
+

Running the event display

+

In order to run the event display via the DDCEDViewer we use the Marlin wrapper. Here we simply present the most important steps, but do not go over all details of the DDCEDViewer configuration, for that it is probably best to directly look at the CEDViewer repository directly. The complete Gaudi configuration can be found in k4MarlinWrapper/examples/event_display.py which is also installed at $K4MARLINWRAPPER/examples/event_display.py

+

In order to run the event display we first have to start the glced server program to which the wrapped CEDViewer processor will then connect. Starting the server and running the wrapped processor can be done via

+
glced &
+
+k4run $K4MARLINWRAPPER/examples/event_display.py --inputFiles=gamma_10GeV_edm4hep.root
+
+
+

If you want to run the event display for a different geometry you can do so with the --compactFile argument. However, depending on your detector model you might also need to change some of the DDCEDViewer parameters. The default compact file is "CLICPerformance/Visualisation/CLIC_o3_v06_CED/CLIC_o3_v06_CED.xml".

+
+
+

Details

+

The main work is done by the DDCEDViewer, which we use via the MarlinProcessorWrapper. It is the following part of example event_display.py.

+
from Configurables import MarlinProcessorWrapper
+
+MyCEDViewer = MarlinProcessorWrapper("MyCEDViewer")
+MyCEDViewer.ProcessorType = "DDCEDViewer"
+MyCEDViewer.Parameters = {
+                          # ... lots of CEDViewer configuration ...
+                          }
+
+
+

Some of the more commonly used parameters have self explanatory names.

+
+
+

Troubleshooting / Using other detectors

+

When running this for a detector different than CLD, CLIC or ILD (or a derivative of one of them) you might not see anything in the event display.

+

If you are not seeing the detector make sure that it has the proper visualisation attributes, e.g. by comparing it to the compact file used above. +If you are not seeing any hits, tracks etc. from your event, make sure to add their collection names to the DrawInLayer list in the DDCEDViewer parameters.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/tutorials/k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/Readme.html b/tutorials/k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/Readme.html new file mode 100644 index 0000000..b89ede0 --- /dev/null +++ b/tutorials/k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/Readme.html @@ -0,0 +1,344 @@ + + + + + + + Using the Key4hep-Stack for CLIC Simulation and Reconstruction — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ + +
+

Using the Key4hep-Stack for CLIC Simulation and Reconstruction

+

This assumes that you have access to an installation of the Key4hep-stack, either via CVMFS or spack install. +To setup the installation on cvmfs, do:

+
source /cvmfs/sw.hsf.org/key4hep/setup.sh
+
+
+

These commands will explain how one can run the CLIC detector simulation and reconstruction using the Key4hep-Stack. +First we will obtain all the necessary steering and input files for CLIC, simulate a few events and run the +reconstruction both with Marlin and k4run. These steps can be adapted to simulate or run other Marlin +processors as well.

+

The CLICPerformance repository contains the steering and input files.

+
git clone https://github.com/iLCSoft/CLICPerformance
+
+
+
+

Simulation

+

Simulating a few events with ddsim can produce output in EDM4hep or LCIO format.

+
    +
  • To produce events in EDM4hep format one can run indicating --outputFile <name>_edm4hep.root to produce the +output in such format:

  • +
+
cd CLICPerformance/clicConfig
+
+ddsim --compactFile $K4GEO/CLIC/compact/CLIC_o3_v14/CLIC_o3_v14.xml \
+      --outputFile ttbar_edm4hep.root \
+      --steeringFile clic_steer.py \
+      --inputFiles ../Tests/yyxyev_000.stdhep \
+      --numberOfEvents 3
+
+
+
    +
  • To produce events in LCIO format one can run indicating --outputFile <name>.slcio to produce the output file +in such format:

  • +
+
cd CLICPerformance/clicConfig
+
+ddsim --compactFile $K4GEO/CLIC/compact/CLIC_o3_v14/CLIC_o3_v14.xml \
+      --outputFile ttbar.slcio \
+      --steeringFile clic_steer.py \
+      --inputFiles ../Tests/yyxyev_000.stdhep \
+      --numberOfEvents 3
+
+
+
+
+

Reconstruction

+
+

Reconstruction with Marlin

+

To run the reconstruction with Marlin:

+
cd CLICPerformance/clicConfig
+
+Marlin clicReconstruction.xml \
+       --InitDD4hep.DD4hepXMLFile=$K4GEO/CLIC/compact/CLIC_o3_v14/CLIC_o3_v14.xml \
+       --global.LCIOInputFiles=ttbar.slcio \
+       --global.MaxRecordNumber=3
+
+
+
+
+

Reconstruction with Gaudi through k4MarlinWrapper

+

We can convert the xml steering file to a Gaudi steering file (python):

+
cd CLICPerformance/clicConfig
+
+convertMarlinSteeringToGaudi.py clicReconstruction.xml clicReconstruction.py
+
+
+

Reconstruction can be performed with LCIO or EDM4hep input, depending on the output format of the events produced +during Simulation.

+
+

Reconstruction with LCIO input

+
    +
  • When using LCIO format for the input events to be used in reconstruction:

    +
      +
    • Modify the clicReconstruction.py file to point to the ttbar.slcio input file, and change the +DD4hepXMLFile parameter for the InitDD4hep algorithm. In addition the two processors with the comment # Config.OverlayFalse and # Config.TrackingConformal should be enabled by uncommenting their line in the algList +at the end of the file.

    • +
    +
  • +
+
cd CLICPerformance/clicConfig
+
+sed -i '1s/^/import os\n/' clicReconstruction.py
+sed -i 's;read.Files = \[".*"\];read.Files = \["ttbar.slcio"\];' clicReconstruction.py
+sed -i 's;EvtMax   = 10,;EvtMax   = 3,;' clicReconstruction.py
+sed -i 's;"MaxRecordNumber": ["10"],;"MaxRecordNumber": ["3"],;' clicReconstruction.py
+sed -i 's;# algList.append(OverlayFalse);algList.append(OverlayFalse);' clicReconstruction.py
+sed -i 's;# algList.append(MyConformalTracking);algList.append(MyConformalTracking);' clicReconstruction.py
+sed -i 's;# algList.append(ClonesAndSplitTracksFinder);algList.append(ClonesAndSplitTracksFinder);' clicReconstruction.py
+sed -i 's;# algList.append(RenameCollection);algList.append(RenameCollection);' clicReconstruction.py
+sed -i 's;"DD4hepXMLFile": \[".*"\],; "DD4hepXMLFile": \[os.environ["LCGEO"]+"/CLIC/compact/CLIC_o3_v14/CLIC_o3_v14.xml"\],;' clicReconstruction.py
+
+
+

Then the reconstruction using the k4MarlinWrapper can be run with

+
cd CLICPerformance/clicConfig
+
+k4run clicReconstruction.py
+
+
+
+
+

Reconstruction with EDM4hep input

+
    +
  • When using EDM4hep format for the input events to be used in reconstruction, refer to the EDM converters +included with k4MarlinWrapper. Note that:

    +
      +
    • MarlinProcessorWrappers need input in LCIO format: EDM4hep collections need to be converted to LCIO

    • +
    • The output collections of MarlinProcessorWrappers may be used later by other algorithms:

      +
        +
      • Output collections of MarlinProcessorWrappers will be in LCIO format unless these are explicitly converted

      • +
      • Some MarlinProcessorWrappers may modify collections instead of producing new ones: the original EDM4hep collection wont be updated in this case and would need conversion from LCIO to EDM4hep.

      • +
      +
    • +
    +
  • +
  • To run clicReconstruction with EDM4hep format, use the steering file found in the examples folder of k4MarlinWrapper: +k4MarlinWrapper/examples/clicRec_e4h_input.py (this also gets installed to $K4MARLINWRAPPER/examples in Key4hep releases)

    +
      +
    • Change the line where evtsvc.input is defined to point to the location of your input file.

    • +
    • At the bottom of the file, in the ApplicationMgr parameters, change EvtMax   = 3, to the number of events to run.

    • +
    +
  • +
+

This can be run in the following way.

+
cd CLICPerformance/clicConfig
+
+cp $K4MARLINWRAPPER/examples/clicRec_e4h_input.py .
+
+k4run clicRec_e4h_input.py --EventDataSvc.input ttbar_edm4hep.root
+
+
+
+
+
+

DD4hep Geometry Information

+

The MarlinDD4hep::InitializeDD4hep processor can be replaced by the k4SimGeant4::GeoSvc and the +TrackingCellIDEncodingSvc the latter of which is part of the k4MarlinWrapper repository. +This requires removing the wrapped InitDD4hep processor from the algList and the two new processed be appended to the ExtSvc argument in the ApplicationMgr.

+

We will create another list, svcList for this. +In the space following

+
import os
+from Configurables import k4DataSvc, PodioInput
+evtsvc = k4DataSvc('EventDataSvc')
+evtsvc.input = os.path.join('$TEST_DIR/inputFiles/', os.environ.get("INPUTFILE", "ttbar_edm4hep.root"))
+
+
+

we can start the svcList list and add the GeoSvc and TrackingCellIDEncodingSvc with;

+
svcList = []
+svcList.append(evtsvc)
+
+
+import os
+from Gaudi.Configuration import INFO
+from Configurables import GeoSvc, TrackingCellIDEncodingSvc
+
+geoservice = GeoSvc("GeoSvc")
+geoservice.detectors = [os.environ["K4GEO"]+"/CLIC/compact/CLIC_o3_v15/CLIC_o3_v15.xml"]
+geoservice.OutputLevel = INFO
+geoservice.EnableGeant4Geo = False
+svcList.append(geoservice)
+
+
+cellIDSvc = TrackingCellIDEncodingSvc("CellIDSvc")
+cellIDSvc.EncodingStringParameterName = "GlobalTrackerReadoutID"
+cellIDSvc.GeoSvcName = geoservice.name()
+cellIDSvc.OutputLevel = INFO
+svcList.append(cellIDSvc)
+
+
+

Then all that is left is to pass that to the ExtSvc argument. +At the bottom of the file:

+
ApplicationMgr( TopAlg = algList,
+                EvtSel = 'NONE',
+                EvtMax   = 3,
+-               ExtSvc = [evtsvc],
++               ExtSvc = svcList,
+                OutputLevel=WARNING
+              )
+
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/tutorials/k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/howtoMultithread.html b/tutorials/k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/howtoMultithread.html new file mode 100644 index 0000000..f15cde5 --- /dev/null +++ b/tutorials/k4marlinwrapper/doc/starterkit/k4MarlinWrapperCLIC/howtoMultithread.html @@ -0,0 +1,290 @@ + + + + + + + How to run multithreading with k4MarlinWrapper (Gaudi) — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ + +
+

How to run multithreading with k4MarlinWrapper (Gaudi)

+

Supported

+
    +
  • Reading LCIO events with LcioEvent()

  • +
  • Writing LCIO events with LcioEventOutput()

  • +
  • Running MarlinProcessorWrappers with no converters

  • +
  • Using whiteboard as ExtSvc (no k4DataSvc or EventDataSvc)

  • +
+

Not supported

+
    +
  • Using EDM converters EDM4hep2LcioTool and Lcio2EDM4hepTool()

  • +
  • Reading EDM4hep events with PodioInput()

  • +
  • Writing EDM4hep events with PodioOutput()

  • +
  • Writing EDM4hep events with MarlinProcessorWrapper of type LCIOOutputProcessor

  • +
  • Running non-thread algorithms/processors in parallel

  • +
  • Running wrapped Marlin processors that make use of the isFirstEvent method in their processEvent method to do some setup only in the first event. There is no way to make this thread safe. If you want your processor to be usable on in a multi threaded environment, you have to move this setup to init.

  • +
+
+

Running Gaudi with multithreading support

+

Gaudi uses Intel TBB under the hood for multithreading.

+

Gaudi exposes two main levels of parallelism:

+
    +
  • Inter-event parallelism: running multiple events in parallel

  • +
  • Intra-event parallelism: running multiple algorithms in parallel, within an event

  • +
+

The two levels of parallelism can be combined: events can run in parallel, and algorithms within the events can run in parallel.

+
+

How to run with inter-event parallelism

+

The following components are used to achieve parallelism:

+
from Configurables import (HiveWhiteBoard, HiveSlimEventLoopMgr, AvalancheSchedulerSvc)
+
+
+

These 3 components need to be configured to adapt the level of parallelism to the sequence, algorithms and hardware to be used.

+
    +
  • Event Data Service: HiveWhiteBoard

    +
      +
    • EventSlots: Number of events that may run in parallel, each with its own EventStore

    • +
    • This is the Event Data Service, which needs the number of EventSlots

    • +
    +
  • +
  • Event Loop Manager: HiveSlimEventLoopMgr

    +
      +
    • Event Loop Manager with parallelism support

    • +
    +
  • +
  • Thread Scheduling config: AvalancheSchedulerSvc

    +
      +
    • Scheduler to indicate the number of threads to use

    • +
    • In needs the total number of threads to use: this determines how many events and algorithms can be in flight (run in parallel)

    • +
    • Default value is -1 which indicate TBB to take over the machine with what it decides to be the optimal configuration

    • +
    +
  • +
+

All these components can be set as follows in the options file:

+
evtslots = 4
+threads = 4
+
+whiteboard = HiveWhiteBoard("EventDataSvc", EventSlots=evtslots)
+slimeventloopmgr = HiveSlimEventLoopMgr(SchedulerName="AvalancheSchedulerSvc", OutputLevel=DEBUG)
+scheduler = AvalancheSchedulerSvc(ThreadPoolSize=threads, OutputLevel=WARNING)
+
+from Configurables import ApplicationMgr
+ApplicationMgr( TopAlg = [seq],
+                EvtSel = 'NONE',
+                EvtMax = 10,
+                ExtSvc = [whiteboard],
+                EventLoop=slimeventloopmgr,
+                MessageSvcType="InertMessageSvc"
+              )
+
+
+

To only run events in parallel, with no parallelism between the algorithms within each event, the cardinality of the algorithms must be set:

+
    +
  • Given a list of algorithms, set the cardinality of all to be 1

  • +
  • Create a GaudiSequencer with all the algorithms as Members

  • +
  • Set the GaudiSequencer sequential property to true

  • +
  • Pass the created GaudiSequencer to the Application Manager in the TopAlg: TopAlg = [seq]

  • +
+
from Configurables import MarlinProcessorWrapper
+from Configurables import (GaudiSequencer)
+
+cardinality = 1
+
+alg1 = MarlinProcessorWrapper("alg1")
+alg2 = MarlinProcessorWrapper("alg2")
+alg3 = MarlinProcessorWrapper("alg3")
+alg4 = MarlinProcessorWrapper("alg4")
+
+algList = []
+
+algList.append(alg1)
+algList.append(alg2)
+algList.append(alg3)
+algList.append(alg4)
+
+for algo in algList:
+    algo.Cardinality = cardinality
+    algo.OutputLevel = DEBUG
+
+seq = GaudiSequencer(
+    "createViewSeq",
+    Members=algList,
+    Sequential=True,
+    OutputLevel=VERBOSE)
+
+from Configurables import ApplicationMgr
+ApplicationMgr( TopAlg = [seq],
+                EvtSel = 'NONE',
+                EvtMax = 10,
+                ExtSvc = [whiteboard],
+                EventLoop=slimeventloopmgr,
+                MessageSvcType="InertMessageSvc"
+              )
+
+
+
+
+
+

Running example

+

A multi-threaded CLIC Reconstruction can be run in multi-threaded mode, for LCIO input and output. +After successful compilation, from the build location:

+
# Check available tests
+ctest -N
+
+# Run multi-threaded clicReconstruction test
+ctest -R clicRec_lcio_mt
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/tutorials/k4simdelphes/doc/starterkit/k4SimDelphes/Readme.html b/tutorials/k4simdelphes/doc/starterkit/k4SimDelphes/Readme.html new file mode 100644 index 0000000..ccb0cdc --- /dev/null +++ b/tutorials/k4simdelphes/doc/starterkit/k4SimDelphes/Readme.html @@ -0,0 +1,207 @@ + + + + + + + Running Delphes fast simulation with EDM4hep output — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Running Delphes fast simulation with EDM4hep output

+

The k4SimDelphes package provides utilities to convert output from the Delphes fast simulation framework into the EDM4hep format. It offers standalone executables, similar to the ones Delphes offers, as well as integration into the Key4hep framework. Here we will provide examples of how to run the standalone executables as well as the usage in the Key4hep framework.

+
+

Setup and prerequisites

+

The following examples assume that you have access to an existing installation of the Key4hep software stack. The easiest way to achieve this to use an existing installation on cvmfs

+
source /cvmfs/sw.hsf.org/key4hep/setup.sh
+
+
+

Alternatively it is possible to build the complete stack via spack, see the instructions for how to do this.

+

In order to run the examples below it is necessary to get some inputs that are used for the generation of the physics events. In the following we will be using pythia generator files that are also used by the FCCee. In particular we will be generating the following process

+

e+e- -> ZH -> mu+mu- X (i.e. the Z decays into a pair of oppositely charged muons and the H to anything)

+

To start we download the pythia cards for this process

+
wget https://raw.githubusercontent.com/HEP-FCC/FCC-config/spring2021/FCCee/Generator/Pythia8/p8_noBES_ee_ZH_ecm240.cmd
+
+
+

All the other resources are available from within a Key4hep release.

+
+
+

Standalone executables

+

For this example we will be using the DelphesPythia8_EDM4HEP standalone executable, which is essentially the same as the DelphesPythia8 executable that is provided by Delphes. Contrary to the Delphes executable the one provided by k4SimDelphes will produce output in the EDM4hep format.

+

To run the generation and fast detector simulation in one go run

+
DelphesPythia8_EDM4HEP ${DELPHES_DIR}/cards/delphes_card_IDEA.tcl \
+                       ${K4SIMDELPHES}/edm4hep_output_config.tcl \
+                       p8_noBES_ee_ZH_ecm240.cmd \
+                       delphes_events_edm4hep.root
+
+
+

The arguments in this case are (in the order they are passed)

+
    +
  • The delphes card that describes the (parameterized) detector. In this case we use one that is shipped with the Delphes installation

  • +
  • The output configuration for the Delphes to EDM4hep converter. Here we use the defaults that are provided by k4SimDelphes, which should cover the majority of use cases. It is however possible to configure these to your needs if necessary.

  • +
  • The pythia card that describes the physics process as described above

  • +
  • The name of the output file that will be created and that will contain the generated and simulated events in EDM4hep format

  • +
+
+

Other standalone executables

+

k4SimDelphes provides other standalone executables that can read different inputs. They offer the same functionality as the ones available from Delphes:

+
    +
  • DelphesSTDHEP_EDM4HEP - for reading STDHEP inputs

  • +
  • DelphesROOT_EDM4HEP - for reading ROOT files in the Delphes format

  • +
  • DelphesPythia8_EDM4HEP - for running Pythia8 as part of the simulation

  • +
+

For all executables it is possible to at least get the order of the input arguments via --help or -h, e.g.

+
DelphesSTDHEP_EDM4HEP --help
+
+
+

will print

+
Usage: DelphesHepMC config_file output_config_file output_file [input_file(s)]
+config_file - configuration file in Tcl format,
+output_config_file - configuration file steering the content of the edm4hep output in Tcl format,
+output_file - output file in ROOT format,
+input_file(s) - input file(s) in STDHEP format,
+with no input_file, or when input_file is -, read standard input.
+
+
+
+
+
+

Usage in the Key4hep framework

+
    +
  • [ ] TODO

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/tutorials/key4hep-tutorials/gaudi_ild_reco/README.html b/tutorials/key4hep-tutorials/gaudi_ild_reco/README.html new file mode 100644 index 0000000..601a814 --- /dev/null +++ b/tutorials/key4hep-tutorials/gaudi_ild_reco/README.html @@ -0,0 +1,530 @@ + + + + + + + Running ILD simulation and reconstruction — Key4hep documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Running ILD simulation and reconstruction

+

This exercise aims at showing you how to run full simulation as well as +reconstruction using ddsim and the Gaudi based Key4hep framework respectively. +You will

+
    +
  • Run ddsim to produce SIM level input files for the reconstruction in EDM4hep +format

  • +
  • Learn how to use the tools provided by +k4MarlinWrapper that allows to +run workflows that were originally developed for the Marlin in the Gaudi +based framework of Key4hep. This includes

    +
      +
    • Converting a Marlin steering file to a Gaudi options file,

    • +
    • Adapting the options file to be able to read and write EDM4hep output

    • +
    • Running this Gaudi options file via k4run

    • +
    +
  • +
+

In this particular case we are using the ILD configuration to do this but the +conceptual steps are very similar for other detector concepts that used Marlin +originally.

+
+

Setup

+

If you haven’t done it yet, source a Key4hep software environment via

+
source /cvmfs/sw.hsf.org/key4hep/setup.sh
+
+
+

For the remainder of the tutorial we will assume that you are working within the +key4hep_tut_ild_reco directory, i.e.

+
mkdir key4hep_tut_ild_reco
+cd key4hep_tut_ild_reco 
+
+
+

However, this is a minor detail and you can choose whatever directory you want. +We do suggest a clean directory though.

+

Next we will be using the standard simulation and reconstruction +configuration for ILD which we can get via

+
git clone https://github.com/iLCSoft/ILDConfig
+
+
+

For the rest of this tutorial we will be working in the +ILDConfig/StandardConfig/production folder

+
cd ILDConfig/StandardConfig/production
+
+
+
+
+

Running the simulation

+

We will use the output file of the whizard +tutorial +as generator level input. In case you have not done that exercise you can get +one via

+
wget https://raw.githubusercontent.com/key4hep/key4hep-tutorials/main/gaudi_ild_reco/input_files/zh_mumu.slcio
+
+
+

Simulating a few events with ddsim is straight forward. ddsim can produce +EDM4hep and LCIO format output files, and it decides which format to used based +on the name of the output file:

+
    +
  • Names ending on .slcio will result in LCIO output files

  • +
  • Names ending in edm4hep.root will result in in EDM4hep output files

  • +
+

In the course of this exercise we will only need the EDM4hep format, we simply +provide both options for convenience here.

+
+ +
+

To run the simulation with EDM4hep output you can use the following command

+
ddsim --compactFile $k4geo_DIR/ILD/compact/ILD_l5_v02/ILD_l5_v02.xml \
+      --steeringFile ddsim_steer.py \
+      --inputFiles zh_mumu.slcio \
+      --outputFile zh_mumu_SIM.edm4hep.root
+
+
+
+ +
+

To run the simulation with LCIO output you can use the following command

+
ddsim --compactFile $k4geo_DIR/ILD/compact/ILD_l5_v02/ILD_l5_v02.xml \
+      --steeringFile ddsim_steer.py \
+      --inputFiles zh_mumu.slcio \
+      --outputFile zh_mumu_SIM.slcio
+
+
+
+
+

Depending on the machine where you are running this, this will take up to a few +minutes to complete. You can start this and read on in the meantime.

+
+
+

Reconstruction

+

To run the reconstruction we will use the Gaudi based Key4hep framework. Note +that we can run the reconstruction just the same as within iLCSoft via Marlin. +However, we will not show that in this tutorial.

+
+

Using ILDReconstruction.py from ILDConfig

+

In order to run the standard reconstruction simply run the following command

+
k4run ILDReconstruction.py \
+      --detectorModel=ILD_l5_o1_v02 \
+      --inputFiles=zh_mumu_SIM.edm4hep.root \
+      --outputFileBase=zh_mumu
+
+
+

The ILDReconstruction.py configuration can handle several different ILD +detector configurations, so we have to choose one via the --detectorModel +argument. Make sure that this is compatible to the one that has been used for +simulation.

+

This will produce several new output files

+
    +
  • zh_mumu_REC.edm4hep.root - The output of the reconstruction in EDM4hep +format

  • +
  • zh_mumu_AIDA.root - The histograms that were produce by wrapped processors +using the AIDA interface

  • +
  • zh_mumu_PfoAnalysis.root - The output file of the Pandora PFO analysis +processor

  • +
+

ILDReconstruction.py also supports reading LCIO inputs and will detect this +automatically from the input file name. It also supports producing LCIO output +files via the --lcioOutput flag, which can either be off (default), on or +only (for not producing any EMD4hep output).

+

Check the introduction to EDM4hep / +podio +for more details on how to read and analyse this file.

+
+
+

Creating a Gaudi options file

+
+

Warning

+

These instructions show you how to convert an existing Marlin steering file to a +Gaudi options file using the full ILD reconstruction as an example since it +exhibits a few of the potential issues that you might run into along the way. +However, we strongly recommend using the existing reconstruction configuration +that is available from +ILDConfig +for actually running the reconstruction. It has more features and also +supports running with different detector models, something that the following +steps will not achieve!.

+
+

The bulk of the work for creating such an options file from an existing Marlin +steering file in XML format can be done with the +convertMarlinSteeringToGaudi.py converter script. We will start by converting +the MarlinStdReco.xml steering file and then do some minor adjustments to the +converted options file. The main thing to consider for the ILD configuration is +that MarlinStdReco.xml makes use of several include statements to pull in more +configuration. Hence, we first have to create a Marlin steering file with these +includes resolved. We also have to provide a DetectorModel constant here, +since some of the includes depend on this.

+
Marlin -n MarlinStdReco.xml --constant.DetectorModel=ILD_l5_o1_v02
+
+
+

You should now have a MarlinStdRecoParsed.xml file. This is the one that we +will convert using the converter script via

+
convertMarlinSteeringToGaudi.py MarlinStdRecoParsed.xml MarlinStdReco.py
+
+
+

Since some parts of the Marlin steering file conversion can not be handled +automatically we have to make a few adjustments to MarlinStdReco.py. We +recommend to simply edit the file directly, but you can also use the sed +commands below to do these adjustments. The adjustments are:

+
    +
  • Give the lcgeo_DIR constant (first entry in the CONSTANTS dict) a +meaningful value. The easiest way to do this is to simply get the value of the +corresponding environment variable via os.environ["lcgeo_DIR"] (don’t forget +to import os at the top)

  • +
  • Exclude the BgOverlayWW, BgOverlayBB, BgOverlayBW, BgOverlayWB and PairBgOverlay +algorithms from being run, by simply commenting out the lines where these are +appended to the algList (this list is populated at almost the end of the +file).

  • +
+
+ +sed commands for adjustments
+
+
+
+
+
sed -i '1s/^/import os\n/' MarlinStdReco.py
+sed -i 's/\( *.lcgeo_DIR.:\).*/\1 os.environ["lcgeo_DIR"],'/ MarlinStdReco.py
+sed -i 's/algList.append(BgOverlayWW)/# algList.append(BgOverlayWW)/' MarlinStdReco.py
+sed -i 's/algList.append(BgOverlayWB)/# algList.append(BgOverlayWB)/' MarlinStdReco.py
+sed -i 's/algList.append(BgOverlayBW)/# algList.append(BgOverlayBW)/' MarlinStdReco.py
+sed -i 's/algList.append(BgOverlayBB)/# algList.append(BgOverlayBB)/' MarlinStdReco.py
+sed -i 's/algList.append(PairBgOverlay)/# algList.append(PairBgOverlay)/' MarlinStdReco.py
+
+
+
+

With the state the options file is in now, you would be able to run it with LCIO +input.

+
+ +Running the reconstruction with LCIO
+
+
+
+
+

To run the reconstruction with LCIO inputs and outputs we now simply need to +pass in the input file that we have created at the simulation step

+
k4run MarlinStdReco.py --LcioEvent.Files=zh_mumu_SIM.slcio
+
+
+

This should take somewhere between 20 seconds up to roughly a minute to run. If +you haven’t changed anything else you should now have a few output files:

+
ls StandardReco_*.*
+
+
+

should now show a REC and DST file, as well as a PfoAnalysis and an AIDA +file. You can change the names of these files by adjusting the OutputBaseName, +resp. The corresponding filename constants values in CONSTANTS.

+
+
+
+

Adapting the options file for EDM4hep

+

It is necessary to adapt the Gaudi options file a bit further:

+
    +
  • Replace the LcioEvent algorithm with the PodioInput algorithm

    +
      +
    • Make sure to replace the Files option with the collections option and to +populate this option with the list of collections you want to read (see +below)

    • +
    +
  • +
  • Replace the EventDataSvc with the k4DataSvc (remember to instantiate it +with "EventDataSvc" as name)

  • +
  • Add a PodioOutput algorithm to write EDM4hep output (don’t forget to add it +to the algList at the very end)

    +
      +
    • (For the sake of this exercise) configure this to only write the +MCParticlesSkimmed, PandoraPFOs and the RecoMCTruthLink collections

    • +
    +
  • +
  • Attach the necessary in-memory on-the-fly converters between EDM4hep and LCIO +(and vice versa)

    +
      +
    • For the conversion of the EDM4hep inputs to LCIO instantiate a +EDM4hep2LcioTool and attach it to the first wrapped processor that is run +(MyAIDAProcessor). See detailed description below.

    • +
    • For the conversion of the LCIO outputs to EDM4hep instantiate a +Lcio2EDM4hepTool and attach it to the last wrapped processor that is run +before the PodioOutput algorithm that you just added (MyPfoAnalysis). +Also see below.

    • +
    +
  • +
+

For all of these steps make sure that you import all the necessary tools and +algorithms from Configurables!

+

The top of your file should now look something like this

+
from Configurables import (
+    PodioInput, PodioOutput, k4DataSvc, MarlinProcessorWrapper,
+    EDM4hep2LcioTool, Lcio2EDM4hepTool
+    )
+from k4MarlinWrapper.parseConstants import *
+algList = []
+evtsvc = k4DataSvc("EventDataSvc")
+
+
+

while the configuration for the input reader and the EDM4hep2LcioTool should +look like this

+
read = PodioInput()
+read.OutputLevel = INFO
+read.collections = [
+    # ... list of collection names
+]
+algList.append(read)
+
+edm4hep2LcioConv = EDM4hep2LcioTool()
+edm4hep2LcioConv.collNameMapping = {
+    "MCParticles": "MCParticle"
+}
+
+# ... Unchanged config of MyAIDAProcessor
+
+MyAIDAProcessor.EDM4hep2LcioTool = edm4hep2LcioConv
+
+
+
+ +list of collection names
+
+
+
+
+

The list of collections that is populated by standard configuration of ILD for +simulation looks like this. You can simply copy this into the options file

+
read.collections = [
+     "BeamCalCollection",
+     "BeamCalCollectionContributions",
+     "ECalBarrelScHitsEven",
+     "ECalBarrelScHitsEvenContributions",
+     "ECalBarrelScHitsOdd",
+     "ECalBarrelScHitsOddContributions",
+     "ECalBarrelSiHitsEven",
+     "ECalBarrelSiHitsEvenContributions",
+     "ECalBarrelSiHitsOdd",
+     "ECalBarrelSiHitsOddContributions",
+     "EcalEndcapRingCollection",
+     "EcalEndcapRingCollectionContributions",
+     "ECalEndcapScHitsEven",
+     "ECalEndcapScHitsEvenContributions",
+     "ECalEndcapScHitsOdd",
+     "ECalEndcapScHitsOddContributions",
+     "ECalEndcapSiHitsEven",
+     "ECalEndcapSiHitsEvenContributions",
+     "ECalEndcapSiHitsOdd",
+     "ECalEndcapSiHitsOddContributions",
+     "EventHeader",
+     "FTDCollection",
+     "HcalBarrelRegCollection",
+     "HcalBarrelRegCollectionContributions",
+     "HCalBarrelRPCHits",
+     "HCalBarrelRPCHitsContributions",
+     "HCalECRingRPCHits",
+     "HCalECRingRPCHitsContributions",
+     "HcalEndcapRingCollection",
+     "HcalEndcapRingCollectionContributions",
+     "HCalEndcapRPCHits",
+     "HCalEndcapRPCHitsContributions",
+     "HcalEndcapsCollection",
+     "HcalEndcapsCollectionContributions",
+     "LHCalCollection",
+     "LHCalCollectionContributions",
+     "LumiCalCollection",
+     "LumiCalCollectionContributions",
+     "MCParticles",
+     "SETCollection",
+     "SITCollection",
+     "TPCCollection",
+     "TPCLowPtCollection",
+     "TPCSpacePointCollection",
+     "VXDCollection",
+     "YokeBarrelCollection",
+     "YokeBarrelCollectionContributions",
+     "YokeEndcapsCollection",
+     "YokeEndcapsCollectionContributions",
+]
+
+
+
+

Finally, the PodioOutput algorithm and the Lcio2EDM4hepTool can be +configuration should look something like this

+
# ... MyPfoAnalysis configuration unchanged
+
+lcio2edm4hepConv = Lcio2EDM4hepTool()
+lcio2edm4hepConv.collNameMapping = {
+    "MCParticle": "MCParticles"
+}
+MyPfoAnalysis.Lcio2EDM4hepTool = lcio2edm4hepConv
+
+edm4hepOutput = PodioOutput()
+edm4hepOutput.filename = "zh_mumu_reco.edm4hep.root"
+edm4hepOutput.outputCommands = [
+    "drop *",
+    "keep MCParticlesSkimmed",
+    "keep PandoraPFOs",
+    "keep RecoMCTruthLink",
+]
+
+# ... the complete algList
+algList.append(edm4hepOutput)
+
+# ... ApplicationMgr config
+
+
+
+
+

Running the reconstruction with k4run

+

After all these adaptions it is now possible to run the full reconstruction +chain on the previously simulated input with k4run

+
k4run MarlinStdReco.py --num-events=3 --EventDataSvc.input=zh_mumu_SIM.edm4hep.root
+
+
+

Here we are again using the command line to specify the input file, we could +have just as well used the input option of the evtsvc in the options file. +Note also that we explicitly pass in the number of events, this is a workaround +for this issue.

+

You should now have a zh_mumu_reco.edm4hep.root file that contains the +complete events in all their glory. For a more practical output you can tweak +the edm4hepOutput.outputCommands option in order to keep only “interesting” +collections. Also note that the REC and DST LCIO output files are still +produced. Can you reproduce these data tiers for EDM4hep?

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file