diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 00000000..adf4fb9a --- /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: 5a8a84bd6f586082e026f00c7c5b76ef +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/_sources/api/algorithms.rst.txt b/_sources/api/algorithms.rst.txt new file mode 100644 index 00000000..a79cec3f --- /dev/null +++ b/_sources/api/algorithms.rst.txt @@ -0,0 +1,6 @@ +fedeca.algorithms +========================= + +.. currentmodule:: fedeca.algorithms + +.. autoclass:: fedeca.algorithms.TorchWebDiscoAlgo diff --git a/_sources/api/competitors.rst.txt b/_sources/api/competitors.rst.txt new file mode 100644 index 00000000..bd08e3eb --- /dev/null +++ b/_sources/api/competitors.rst.txt @@ -0,0 +1,8 @@ +fedeca.competitors +========================= + +.. autoclass:: fedeca.PooledIPTW + +.. autoclass:: fedeca.MatchingAjudsted + +.. autoclass:: fedeca.NaiveComparison diff --git a/_sources/api/iptw.rst.txt b/_sources/api/iptw.rst.txt new file mode 100644 index 00000000..16d97f2c --- /dev/null +++ b/_sources/api/iptw.rst.txt @@ -0,0 +1,4 @@ +fedeca.fedeca_core +========================= + +.. autoclass:: fedeca.FedECA diff --git a/_sources/api/metrics.rst.txt b/_sources/api/metrics.rst.txt new file mode 100644 index 00000000..89ebf5f6 --- /dev/null +++ b/_sources/api/metrics.rst.txt @@ -0,0 +1,4 @@ +fedeca.metrics +========================= + +.. automodule:: fedeca.metrics.metrics diff --git a/_sources/api/scripts.rst.txt b/_sources/api/scripts.rst.txt new file mode 100644 index 00000000..7bb4b48e --- /dev/null +++ b/_sources/api/scripts.rst.txt @@ -0,0 +1,4 @@ +fedeca.scripts +========================= + +.. autoclass:: fedeca.scripts.substra_assets.csv_opener.CSVOpener diff --git a/_sources/api/strategies.rst.txt b/_sources/api/strategies.rst.txt new file mode 100644 index 00000000..83d508db --- /dev/null +++ b/_sources/api/strategies.rst.txt @@ -0,0 +1,12 @@ +fedeca.strategies +========================= + +.. currentmodule:: fedeca.strategies.webdisco + +.. autoclass:: fedeca.strategies.WebDisco + +.. automodule:: fedeca.strategies.bootstraper + +.. automodule:: fedeca.strategies.webdisco_utils + + diff --git a/_sources/api/utils.rst.txt b/_sources/api/utils.rst.txt new file mode 100644 index 00000000..965c68bf --- /dev/null +++ b/_sources/api/utils.rst.txt @@ -0,0 +1,14 @@ +fedeca.utils +========================= + +.. automodule:: fedeca.utils.data_utils + +.. automodule:: fedeca.utils.experiments_utils + +.. automodule:: fedeca.utils.moments_utils + +.. automodule:: fedeca.utils.substrafl_utils + +.. automodule:: fedeca.utils.tensor_utils + +.. automodule:: fedeca.utils.typing diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt new file mode 100644 index 00000000..c4842e34 --- /dev/null +++ b/_sources/index.rst.txt @@ -0,0 +1,67 @@ +FedECA documentation +====================== + +This package allows to perform both simulations and deployments of federated +external control arms (FedECA) analyses. + +Before using this code make sure to: + +#. read and accept the terms of the license license.md that can be found at the root of the repository. +#. read `substra's privacy strategy `_ +#. read our `companion article `_ +#. `activate secure rng in Opacus `_ if you plan on using differential privacy. + + + +Citing this work +---------------- + +:: + + @ARTICLE{terrail2023fedeca, + author = {{Ogier du Terrail}, Jean and {Klopfenstein}, Quentin and {Li}, Honghao and {Mayer}, Imke and {Loiseau}, Nicolas and {Hallal}, Mohammad and {Debouver}, Michael and {Camalon}, Thibault and {Fouqueray}, Thibault and {Arellano Castro}, Jorge and {Yanes}, Zahia and {Dahan}, Laetitia and {Ta{\"\i}eb}, Julien and {Laurent-Puig}, Pierre and {Bachet}, Jean-Baptiste and {Zhao}, Shulin and {Nicolle}, Remy and {Cros}, J{\'e}rome and {Gonzalez}, Daniel and {Carreras-Torres}, Robert and {Garcia Velasco}, Adelaida and {Abdilleh}, Kawther and {Doss}, Sudheer and {Balazard}, F{\'e}lix and {Andreux}, Mathieu}, + title = "{FedECA: A Federated External Control Arm Method for Causal Inference with Time-To-Event Data in Distributed Settings}", + journal = {arXiv e-prints}, + keywords = {Statistics - Methodology, Computer Science - Distributed, Parallel, and Cluster Computing, Computer Science - Machine Learning}, + year = 2023, + month = nov, + eid = {arXiv:2311.16984}, + pages = {arXiv:2311.16984}, + doi = {10.48550/arXiv.2311.16984}, + archivePrefix = {arXiv}, + eprint = {2311.16984}, + primaryClass = {stat.ME}, + adsurl = {https://ui.adsabs.harvard.edu/abs/2023arXiv231116984O}, + adsnote = {Provided by the SAO/NASA Astrophysics Data System} + } + + +License +------- + +FedECA is released under a custom license that can be found under license.md at the root of the repository. + +.. toctree:: + :maxdepth: 0 + :caption: Installation + + installation + +.. toctree:: + :maxdepth: 0 + :caption: Getting Started Instructions + + quickstart + +.. toctree:: + :hidden: + :maxdepth: 4 + :caption: API + + api/fedeca + api/competitors + api/algorithms + api/metrics + api/scripts + api/strategies + api/utils diff --git a/_sources/installation.rst.txt b/_sources/installation.rst.txt new file mode 100644 index 00000000..a3281c00 --- /dev/null +++ b/_sources/installation.rst.txt @@ -0,0 +1,22 @@ + +Installation +============ + +To install the package, create an env with python ``3.9`` with conda + +.. code-block:: bash + + conda create -n fedeca python=3.9 + conda activate fedeca + +Within the environment, install the package by running: + +.. code-block:: + + git clone https://github.com/owkin/fedeca.git + pip install -e ".[all_extra]" + +If you plan developing, you should also install the pre-commit hooks + +```bash +pre-commit install diff --git a/_sources/quickstart.rst.txt b/_sources/quickstart.rst.txt new file mode 100644 index 00000000..f92fa739 --- /dev/null +++ b/_sources/quickstart.rst.txt @@ -0,0 +1,178 @@ + +Quickstart +---------- + +FedECA tries to mimic scikit-learn API as much as possible with the constraints +of distributed learning. +The first step in data science is always the data. +We need to first use or generate some survival data in pandas.dataframe format. +Note that fedeca should work on any data format, provided that the +return type of the substra opener is indeed a pandas.dataframe but let's keep +it simple in this quickstart. + +Here we will use fedeca utils which will generate some synthetic survival data +following CoxPH assumptions: + +.. code-block:: python + + import pandas as pd + from fedeca.utils.survival_utils import CoxData + # Let's generate 1000 data samples with 10 covariates + data = CoxData(seed=42, n_samples=1000, ndim=10) + df = data.generate_dataframe() + + # We remove the true propensity score + df = df.drop(columns=["propensity_scores"], axis=1) + +Let's inspect the data that we have here. + +.. code-block:: python + + print(df.info()) + # + # RangeIndex: 1000 entries, 0 to 999 + # Data columns (total 13 columns): + # # Column Non-Null Count Dtype + # --- ------ -------------- ----- + # 0 X_0 1000 non-null float64 + # 1 X_1 1000 non-null float64 + # 2 X_2 1000 non-null float64 + # 3 X_3 1000 non-null float64 + # 4 X_4 1000 non-null float64 + # 5 X_5 1000 non-null float64 + # 6 X_6 1000 non-null float64 + # 7 X_7 1000 non-null float64 + # 8 X_8 1000 non-null float64 + # 9 X_9 1000 non-null float64 + # 10 time 1000 non-null float64 + # 11 event 1000 non-null uint8 + # 12 treatment 1000 non-null uint8 + # dtypes: float64(11), uint8(2) + # memory usage: 88.0 KB + print(df.head()) + # X_0 X_1 X_2 X_3 X_4 X_5 X_6 X_7 X_8 X_9 time event treatment + # 0 -0.918373 -0.814340 -0.148994 0.482720 -1.130384 -1.254769 -0.462002 1.451622 1.199705 0.133197 2.573516 1 1 + # 1 0.360051 -0.863619 0.198673 0.330630 -0.189184 -0.802424 -1.694990 -0.989009 -0.421245 -0.112665 0.519108 1 1 + # 2 0.442502 0.024682 0.069500 -0.398015 -0.521236 -0.824907 0.373018 1.016843 0.765661 0.858817 0.652803 1 1 + # 3 -0.783965 -1.116391 -1.482413 -2.039827 -1.639304 -0.500380 -0.298467 -1.801688 -0.743004 -0.724039 0.074925 1 1 + # 4 -0.199620 -0.652347 -0.018776 0.004630 -0.122242 -0.413490 -0.450718 -0.761894 -1.323135 -0.234899 0.006951 1 1 + print(df["treatment"].unique()) + # array([1, 0], dtype=uint8) + df["treatment"].sum() + # 500 + +So we have survival data with covariates and a binary treatment variable. +Let's inspect it using proper survival plots using the great survival analysis +package `lifelines `_ that was a +source of inspiration for fedeca: + +.. code-block:: python + + from lifelines import KaplanMeierFitter as KMF + import matplotlib.pyplot as plt + treatments = [0, 1] + kms = [KMF().fit(durations=df.loc[df["treatment"] == t]["time"], event_observed=df.loc[df["treatment"] == t]["event"]) for t in treatments] + + axs = [km.plot(label="treated" if t == 1 else "untreated") for km, t in zip(kms, treatments)] + axs[-1].set_ylabel("Survival Probability") + plt.xlim(0, 1500) + plt.savefig("treated_vs_untreated.pdf", bbox_inches="tight") + +Open ``treated_vs_untreated.pdf`` in your favorite pdf viewer and see for yourself. + +Pooled IPTW analysis +-------------------- + +The treatment seems to improve survival but it's hard to say for sure as it might +simply be due to chance or sampling bias. +Let's perform an IPTW analysis to be sure: + +.. code-block:: python + + from fedeca.competitors import PooledIPTW + pooled_iptw = PooledIPTW(treated_col="treatment", event_col="event", duration_col="time") + # Targets is the propensity weights + pooled_iptw.fit(data=df, targets=None) + print(pooled_iptw.results_) + # coef exp(coef) se(coef) coef lower 95% coef upper 95% exp(coef) lower 95% exp(coef) upper 95% cmp to z p -log2(p) + # covariate + # treatment 0.041727 1.04261 0.070581 -0.096609 0.180064 0.907911 1.197294 0.0 0.591196 0.554389 0.85103 + +When looking at the ``p-value=0.554389 > 0.05``\ , thus judging by what we observe we +cannot say for sure that there is a treatment effect. We say the ATE is non significant. + +Distributed Analysis +-------------------- + +However in practice data is private and held by different institutions. Therefore +in practice each client holds a subset of the rows of our dataframe. +We will simulate this using a realistic scenario where a "pharma" node is developing +a new drug and thus holds all treated and the rest of the data is split across +3 other institutions where patients were treated with the old drug. +We will use the split utils of FedECA. + +.. code-block:: python + + from fedeca.utils.data_utils import split_dataframe_across_clients + + clients, train_data_nodes, _, _, _ = split_dataframe_across_clients( + df, + n_clients=4, + split_method= "split_control_over_centers", + split_method_kwargs={"treatment_info": "treatment"}, + data_path="./data", + backend_type="simu", + ) + +Note that you can replace split_method by any callable with the signature +``pd.DataFrame -> list[int]`` where the list of ints is the split of the indices +of the df across the different institutions. +To convince you that the split was effective you can inspect the folder "./data". +You will find different subfolders ``center0`` to ``center3`` each with different +parts of the data. +To unpack a bit what is going on in more depth, we have created a dict of client +'clients', +which is a dict with 4 keys containing substra API handles towards the different +institutions and their data. +``train_data_nodes`` is a list of handles towards the datasets of the different institutions +that were registered through the substra interface using the data in the different +folders. +You might have noticed that we did not talk about the ``backend_type`` argument. +This argument is used to choose on which network will experiments be run. +"simu" means in-RAM. If you finish this tutorial do try other values such as: +"docker" or "subprocess" but expect a significant slow-down as experiments +get closer and closer to a real distributed system. + +Now let's try to see if we can reproduce the pooled anaysis in this much more +complicated distributed setting: + +.. code-block:: python + + from fedeca import FedECA + # We use the first client as the node, which launches order + ds_client = clients[list(clients.keys())[0]] + fed_iptw = FedECA(ndim=10, ds_client=ds_client, train_data_nodes=train_data_nodes, treated_col="treatment", duration_col="time", event_col="event", variance_method="robust") + fed_iptw.run() + # Final partial log-likelihood: + # [-11499.19619422] + # coef se(coef) coef lower 95% coef upper 95% z p exp(coef) exp(coef) lower 95% exp(coef) upper 95% + # 0 0.041718 0.070581 -0.096618 0.180054 0.591062 0.554479 1.0426 0.907902 1.197282 + +In fact what we did above is both quite verbose. For simulation purposes we +advise to use directly the scikit-learn inspired syntax: + +.. code-block:: python + + from fedeca import FedECA + + fed_iptw = FedECA(ndim=10, treated_col="treatment", event_col="event", duration_col="time") + fed_iptw.fit(df, n_clients=4, split_method="split_control_over_centers", split_method_kwargs={"treatment_info": "treatment"}, data_path="./data", variance_method="robust", backend_type="simu") + # coef se(coef) coef lower 95% coef upper 95% z p exp(coef) exp(coef) lower 95% exp(coef) upper 95% + # 0 0.041718 0.070581 -0.096618 0.180054 0.591062 0.554479 1.0426 0.907902 1.197282 + +We find a similar p-value ! The distributed analysis is working as expected. +We recommend to users that made it to here as a next step to use their own data +and write custom split functions and to test this pipeline under various +heterogeneity settings. +Another interesting avenue is to try adding differential privacy to the training +of the propensity model but that is outside the scope of this quickstart. diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 00000000..7577acb1 --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,903 @@ +/* + * 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; +} + +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; +} + +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; +} + +/* -- 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/css/badge_only.css b/_static/css/badge_only.css new file mode 100644 index 00000000..323730ae --- /dev/null +++ b/_static/css/badge_only.css @@ -0,0 +1 @@ +.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-weight:normal;font-style:normal;src:url("../fonts/fontawesome-webfont.eot");src:url("../fonts/fontawesome-webfont.eot?#iefix") format("embedded-opentype"),url("../fonts/fontawesome-webfont.woff") format("woff"),url("../fonts/fontawesome-webfont.ttf") format("truetype"),url("../fonts/fontawesome-webfont.svg#FontAwesome") format("svg")}.fa:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa{display:inline-block;text-decoration:inherit}li .fa{display:inline-block}li .fa-large:before,li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before,ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before{content:""}.icon-book:before{content:""}.fa-caret-down:before{content:""}.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.icon-caret-up:before{content:""}.fa-caret-left:before{content:""}.icon-caret-left:before{content:""}.fa-caret-right:before{content:""}.icon-caret-right:before{content:""}.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:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book{float:left}.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%}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #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}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book{float:left}.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}} diff --git a/_static/css/theme.css b/_static/css/theme.css new file mode 100644 index 00000000..b19dbfe5 --- /dev/null +++ b/_static/css/theme.css @@ -0,0 +1,6 @@ +/* sphinx_rtd_theme version 0.4.2 | MIT license */ +/* Built 20181005 13:10 */ +*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}[hidden]{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:hover,a:active{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;color:#000;text-decoration:none}mark{background:#ff0;color:#000;font-style:italic;font-weight:bold}pre,code,.rst-content tt,.rst-content code,kbd,samp{font-family:monospace,serif;_font-family:"courier new",monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:before,q:after{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}ul,ol,dl{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{margin:0}form{margin:0}fieldset{border:0;margin:0;padding:0}label{cursor:pointer}legend{border:0;*margin-left:-7px;padding:0;white-space:normal}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="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;*width:13px;*height:13px}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top;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{html,body,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^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:.5cm}p,h2,.rst-content .toctree-wrapper p.caption,h3{orphans:3;widows:3}h2,.rst-content .toctree-wrapper p.caption,h3{page-break-after:avoid}}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title: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 dl dt .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo,.rst-content .admonition,.btn,input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"],select,textarea,.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a,.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a,.wy-nav-top a{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{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?v=4.7.0");src:url("../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0") format("embedded-opentype"),url("../fonts/fontawesome-webfont.woff2?v=4.7.0") format("woff2"),url("../fonts/fontawesome-webfont.woff?v=4.7.0") format("woff"),url("../fonts/fontawesome-webfont.ttf?v=4.7.0") format("truetype"),url("../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular") format("svg");font-weight:normal;font-style:normal}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.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 dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon{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.3333333333em;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.2857142857em;text-align:center}.fa-ul{padding-left:0;margin-left:2.1428571429em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.1428571429em;width:2.1428571429em;top:.1428571429em;text-align:center}.fa-li.fa-lg{left:-1.8571428571em}.fa-border{padding:.2em .25em .15em;border:solid 0.08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.wy-menu-vertical li span.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a span.fa-pull-left.toctree-expand,.wy-menu-vertical li.current>a span.fa-pull-left.toctree-expand,.rst-content .fa-pull-left.admonition-title,.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 dl dt .fa-pull-left.headerlink,.rst-content p.caption .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.rst-content code.download span.fa-pull-left:first-child,.fa-pull-left.icon{margin-right:.3em}.fa.fa-pull-right,.wy-menu-vertical li span.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a span.fa-pull-right.toctree-expand,.wy-menu-vertical li.current>a span.fa-pull-right.toctree-expand,.rst-content .fa-pull-right.admonition-title,.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 dl dt .fa-pull-right.headerlink,.rst-content p.caption .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.rst-content code.download span.fa-pull-right:first-child,.fa-pull-right.icon{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.wy-menu-vertical li span.pull-left.toctree-expand,.wy-menu-vertical li.on a span.pull-left.toctree-expand,.wy-menu-vertical li.current>a span.pull-left.toctree-expand,.rst-content .pull-left.admonition-title,.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 dl dt .pull-left.headerlink,.rst-content p.caption .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.rst-content code.download span.pull-left:first-child,.pull-left.icon{margin-right:.3em}.fa.pull-right,.wy-menu-vertical li span.pull-right.toctree-expand,.wy-menu-vertical li.on a span.pull-right.toctree-expand,.wy-menu-vertical li.current>a span.pull-right.toctree-expand,.rst-content .pull-right.admonition-title,.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 dl dt .pull-right.headerlink,.rst-content p.caption .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.rst-content code.download span.pull-right:first-child,.pull-right.icon{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-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:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{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-remove:before,.fa-close: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-gear:before,.fa-cog: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 tt.download span:first-child:before,.rst-content code.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-rotate-right:before,.fa-repeat: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-photo:before,.fa-image: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,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.rst-content .admonition-title: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-warning:before,.fa-exclamation-triangle: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-gears:before,.fa-cogs: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-save:before,.fa-floppy-o:before{content:""}.fa-square:before{content:""}.fa-navicon:before,.fa-reorder:before,.fa-bars: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,.wy-dropdown .caret:before,.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-unsorted:before,.fa-sort:before{content:""}.fa-sort-down:before,.fa-sort-desc:before{content:""}.fa-sort-up:before,.fa-sort-asc:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-legal:before,.fa-gavel:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-flash:before,.fa-bolt:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-paste:before,.fa-clipboard: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-unlink:before,.fa-chain-broken: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.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.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-toggle-down:before,.fa-caret-square-o-down:before{content:""}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:""}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:""}.fa-euro:before,.fa-eur:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-rupee:before,.fa-inr:before{content:""}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:""}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:""}.fa-won:before,.fa-krw: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-toggle-left:before,.fa-caret-square-o-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-turkish-lira:before,.fa-try:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li span.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-institution:before,.fa-bank:before,.fa-university:before{content:""}.fa-mortar-board:before,.fa-graduation-cap: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-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:""}.fa-file-zip-o:before,.fa-file-archive-o:before{content:""}.fa-file-sound-o:before,.fa-file-audio-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-saver:before,.fa-support:before,.fa-life-ring:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:""}.fa-ge:before,.fa-empire:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-send:before,.fa-paper-plane:before{content:""}.fa-send-o:before,.fa-paper-plane-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-soccer-ball-o:before,.fa-futbol-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-shekel:before,.fa-sheqel:before,.fa-ils: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-hotel:before,.fa-bed:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-yc:before,.fa-y-combinator:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery:before,.fa-battery-full: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-stop-o:before,.fa-hand-paper-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-tv:before,.fa-television: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-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:""}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-signing:before,.fa-sign-language: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-vcard:before,.fa-address-card:before{content:""}.fa-vcard-o:before,.fa-address-card-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:before,.fa-thermometer-full: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-bathtub:before,.fa-s15:before,.fa-bath: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,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.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 dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context{font-family:inherit}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title: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 dl dt .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before{font-family:"FontAwesome";display:inline-block;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa,a .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,a .rst-content .admonition-title,.rst-content a .admonition-title,a .rst-content h1 .headerlink,.rst-content h1 a .headerlink,a .rst-content h2 .headerlink,.rst-content h2 a .headerlink,a .rst-content h3 .headerlink,.rst-content h3 a .headerlink,a .rst-content h4 .headerlink,.rst-content h4 a .headerlink,a .rst-content h5 .headerlink,.rst-content h5 a .headerlink,a .rst-content h6 .headerlink,.rst-content h6 a .headerlink,a .rst-content dl dt .headerlink,.rst-content dl dt a .headerlink,a .rst-content p.caption .headerlink,.rst-content p.caption a .headerlink,a .rst-content table>caption .headerlink,.rst-content table>caption a .headerlink,a .rst-content tt.download span:first-child,.rst-content tt.download a span:first-child,a .rst-content code.download span:first-child,.rst-content code.download a span:first-child,a .icon{display:inline-block;text-decoration:inherit}.btn .fa,.btn .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .btn span.toctree-expand,.btn .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .btn span.toctree-expand,.btn .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .btn span.toctree-expand,.btn .rst-content .admonition-title,.rst-content .btn .admonition-title,.btn .rst-content h1 .headerlink,.rst-content h1 .btn .headerlink,.btn .rst-content h2 .headerlink,.rst-content h2 .btn .headerlink,.btn .rst-content h3 .headerlink,.rst-content h3 .btn .headerlink,.btn .rst-content h4 .headerlink,.rst-content h4 .btn .headerlink,.btn .rst-content h5 .headerlink,.rst-content h5 .btn .headerlink,.btn .rst-content h6 .headerlink,.rst-content h6 .btn .headerlink,.btn .rst-content dl dt .headerlink,.rst-content dl dt .btn .headerlink,.btn .rst-content p.caption .headerlink,.rst-content p.caption .btn .headerlink,.btn .rst-content table>caption .headerlink,.rst-content table>caption .btn .headerlink,.btn .rst-content tt.download span:first-child,.rst-content tt.download .btn span:first-child,.btn .rst-content code.download span:first-child,.rst-content code.download .btn span:first-child,.btn .icon,.nav .fa,.nav .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .nav span.toctree-expand,.nav .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .nav span.toctree-expand,.nav .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .nav span.toctree-expand,.nav .rst-content .admonition-title,.rst-content .nav .admonition-title,.nav .rst-content h1 .headerlink,.rst-content h1 .nav .headerlink,.nav .rst-content h2 .headerlink,.rst-content h2 .nav .headerlink,.nav .rst-content h3 .headerlink,.rst-content h3 .nav .headerlink,.nav .rst-content h4 .headerlink,.rst-content h4 .nav .headerlink,.nav .rst-content h5 .headerlink,.rst-content h5 .nav .headerlink,.nav .rst-content h6 .headerlink,.rst-content h6 .nav .headerlink,.nav .rst-content dl dt .headerlink,.rst-content dl dt .nav .headerlink,.nav .rst-content p.caption .headerlink,.rst-content p.caption .nav .headerlink,.nav .rst-content table>caption .headerlink,.rst-content table>caption .nav .headerlink,.nav .rst-content tt.download span:first-child,.rst-content tt.download .nav span:first-child,.nav .rst-content code.download span:first-child,.rst-content code.download .nav span:first-child,.nav .icon{display:inline}.btn .fa.fa-large,.btn .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .btn span.fa-large.toctree-expand,.btn .rst-content .fa-large.admonition-title,.rst-content .btn .fa-large.admonition-title,.btn .rst-content h1 .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.btn .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .btn .fa-large.headerlink,.btn .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .btn .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .btn span.fa-large:first-child,.btn .rst-content code.download span.fa-large:first-child,.rst-content code.download .btn span.fa-large:first-child,.btn .fa-large.icon,.nav .fa.fa-large,.nav .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .nav span.fa-large.toctree-expand,.nav .rst-content .fa-large.admonition-title,.rst-content .nav .fa-large.admonition-title,.nav .rst-content h1 .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.nav .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.nav .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .nav .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.nav .rst-content code.download span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.nav .fa-large.icon{line-height:.9em}.btn .fa.fa-spin,.btn .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .btn span.fa-spin.toctree-expand,.btn .rst-content .fa-spin.admonition-title,.rst-content .btn .fa-spin.admonition-title,.btn .rst-content h1 .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.btn .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .btn .fa-spin.headerlink,.btn .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .btn .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .btn span.fa-spin:first-child,.btn .rst-content code.download span.fa-spin:first-child,.rst-content code.download .btn span.fa-spin:first-child,.btn .fa-spin.icon,.nav .fa.fa-spin,.nav .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .nav span.fa-spin.toctree-expand,.nav .rst-content .fa-spin.admonition-title,.rst-content .nav .fa-spin.admonition-title,.nav .rst-content h1 .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.nav .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.nav .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .nav .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.nav .rst-content code.download span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.nav .fa-spin.icon{display:inline-block}.btn.fa:before,.wy-menu-vertical li span.btn.toctree-expand:before,.rst-content .btn.admonition-title: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 dl dt .btn.headerlink:before,.rst-content p.caption .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.rst-content code.download span.btn:first-child:before,.btn.icon:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.wy-menu-vertical li span.btn.toctree-expand:hover:before,.rst-content .btn.admonition-title: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 dl dt .btn.headerlink:hover:before,.rst-content p.caption .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.rst-content code.download span.btn:first-child:hover:before,.btn.icon:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li .btn-mini span.toctree-expand:before,.btn-mini .rst-content .admonition-title:before,.rst-content .btn-mini .admonition-title:before,.btn-mini .rst-content h1 .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.btn-mini .rst-content dl dt .headerlink:before,.rst-content dl dt .btn-mini .headerlink:before,.btn-mini .rst-content p.caption .headerlink:before,.rst-content p.caption .btn-mini .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.rst-content tt.download .btn-mini span:first-child:before,.btn-mini .rst-content code.download span:first-child:before,.rst-content code.download .btn-mini span:first-child:before,.btn-mini .icon:before{font-size:14px;vertical-align:-15%}.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo,.rst-content .admonition{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.wy-alert-title,.rst-content .admonition-title{color:#fff;font-weight:bold;display:block;color:#fff;background:#6ab0de;margin:-12px;padding:6px 12px;margin-bottom:12px}.wy-alert.wy-alert-danger,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.admonition{background:#fdf3f2}.wy-alert.wy-alert-danger .wy-alert-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .danger .wy-alert-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .danger .admonition-title,.rst-content .error .admonition-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition .admonition-title{background:#f29f97}.wy-alert.wy-alert-warning,.rst-content .wy-alert-warning.note,.rst-content .attention,.rst-content .caution,.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.tip,.rst-content .warning,.rst-content .wy-alert-warning.seealso,.rst-content .admonition-todo,.rst-content .wy-alert-warning.admonition{background:#ffedcc}.wy-alert.wy-alert-warning .wy-alert-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .attention .wy-alert-title,.rst-content .caution .wy-alert-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .attention .admonition-title,.rst-content .caution .admonition-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .warning .admonition-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .admonition-todo .admonition-title,.rst-content .wy-alert-warning.admonition .admonition-title{background:#f0b37e}.wy-alert.wy-alert-info,.rst-content .note,.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,.rst-content .seealso,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.admonition{background:#e7f2fa}.wy-alert.wy-alert-info .wy-alert-title,.rst-content .note .wy-alert-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.rst-content .note .admonition-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .seealso .admonition-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition .admonition-title{background:#6ab0de}.wy-alert.wy-alert-success,.rst-content .wy-alert-success.note,.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 .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.warning,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.admonition{background:#dbfaf4}.wy-alert.wy-alert-success .wy-alert-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .hint .wy-alert-title,.rst-content .important .wy-alert-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .hint .admonition-title,.rst-content .important .admonition-title,.rst-content .tip .admonition-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition .admonition-title{background:#1abc9c}.wy-alert.wy-alert-neutral,.rst-content .wy-alert-neutral.note,.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.tip,.rst-content .wy-alert-neutral.warning,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.admonition{background:#f3f6f6}.wy-alert.wy-alert-neutral .wy-alert-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition .admonition-title{color:#404040;background:#e1e4e5}.wy-alert.wy-alert-neutral a,.rst-content .wy-alert-neutral.note 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.tip a,.rst-content .wy-alert-neutral.warning a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a{color:#2980B9}.wy-alert p:last-child,.rst-content .note 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 .tip p:last-child,.rst-content .warning p:last-child,.rst-content .seealso p:last-child,.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0px;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,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 12px;color:#fff;border:1px solid rgba(0,0,0,0.1);background-color:#27AE60;text-decoration:none;font-weight:normal;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:0px 1px 2px -1px rgba(255,255,255,0.5) inset,0px -2px 0px 0px rgba(0,0,0,0.1) inset;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:0px -1px 0px 0px rgba(0,0,0,0.05) inset,0px 2px 0px 0px rgba(0,0,0,0.1) inset;padding:8px 12px 6px 12px}.btn:visited{color:#fff}.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-disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn-disabled:hover,.btn-disabled:focus,.btn-disabled:active{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:hover{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:active{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:before,.wy-btn-group:after{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:solid 1px #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,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:solid 1px #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 input,.wy-form-aligned textarea,.wy-form-aligned select,.wy-form-aligned .wy-help-inline,.wy-form-aligned label{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{border:0;margin:0;padding:0}legend{display:block;width:100%;border:0;padding:0;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label{display:block;margin:0 0 .3125em 0;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;*zoom:1;max-width:68em;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group:before,.wy-control-group:after{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 select,.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full input[type="text"],.wy-control-group .wy-form-full input[type="password"],.wy-control-group .wy-form-full input[type="email"],.wy-control-group .wy-form-full input[type="url"],.wy-control-group .wy-form-full input[type="date"],.wy-control-group .wy-form-full input[type="month"],.wy-control-group .wy-form-full input[type="time"],.wy-control-group .wy-form-full input[type="datetime"],.wy-control-group .wy-form-full input[type="datetime-local"],.wy-control-group .wy-form-full input[type="week"],.wy-control-group .wy-form-full input[type="number"],.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="color"],.wy-control-group .wy-form-halves input[type="text"],.wy-control-group .wy-form-halves input[type="password"],.wy-control-group .wy-form-halves input[type="email"],.wy-control-group .wy-form-halves input[type="url"],.wy-control-group .wy-form-halves input[type="date"],.wy-control-group .wy-form-halves input[type="month"],.wy-control-group .wy-form-halves input[type="time"],.wy-control-group .wy-form-halves input[type="datetime"],.wy-control-group .wy-form-halves input[type="datetime-local"],.wy-control-group .wy-form-halves input[type="week"],.wy-control-group .wy-form-halves input[type="number"],.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="color"],.wy-control-group .wy-form-thirds input[type="text"],.wy-control-group .wy-form-thirds input[type="password"],.wy-control-group .wy-form-thirds input[type="email"],.wy-control-group .wy-form-thirds input[type="url"],.wy-control-group .wy-form-thirds input[type="date"],.wy-control-group .wy-form-thirds input[type="month"],.wy-control-group .wy-form-thirds input[type="time"],.wy-control-group .wy-form-thirds input[type="datetime"],.wy-control-group .wy-form-thirds input[type="datetime-local"],.wy-control-group .wy-form-thirds input[type="week"],.wy-control-group .wy-form-thirds input[type="number"],.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="color"]{width:100%}.wy-control-group .wy-form-full{float:left;display:block;margin-right:2.3576515979%;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.3576515979%;width:48.821174201%}.wy-control-group .wy-form-halves:last-child{margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n+1){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.3576515979%;width:31.7615656014%}.wy-control-group .wy-form-thirds:last-child{margin-right:0}.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{margin:6px 0 0 0;font-size:90%}.wy-control-no-input{display:inline-block;margin:6px 0 0 0;font-size:90%}.wy-control-group.fluid-input input[type="text"],.wy-control-group.fluid-input input[type="password"],.wy-control-group.fluid-input input[type="email"],.wy-control-group.fluid-input input[type="url"],.wy-control-group.fluid-input input[type="date"],.wy-control-group.fluid-input input[type="month"],.wy-control-group.fluid-input input[type="time"],.wy-control-group.fluid-input input[type="datetime"],.wy-control-group.fluid-input input[type="datetime-local"],.wy-control-group.fluid-input input[type="week"],.wy-control-group.fluid-input input[type="number"],.wy-control-group.fluid-input input[type="search"],.wy-control-group.fluid-input input[type="tel"],.wy-control-group.fluid-input input[type="color"]{width:100%}.wy-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;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="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"]{-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"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0;margin-right:.3125em;*height:13px;*width:13px}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="text"]:focus,input[type="password"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus{outline:0;outline:thin dotted \9;border-color:#333}input.no-focus:focus{border-color:#ccc !important}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:1px auto #129FEA}input[type="text"][disabled],input[type="password"][disabled],input[type="email"][disabled],input[type="url"][disabled],input[type="date"][disabled],input[type="month"][disabled],input[type="time"][disabled],input[type="datetime"][disabled],input[type="datetime-local"][disabled],input[type="week"][disabled],input[type="number"][disabled],input[type="search"][disabled],input[type="tel"][disabled],input[type="color"][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#E74C3C;border:1px solid #E74C3C}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#E74C3C}input[type="file"]:focus:invalid:focus,input[type="radio"]:focus:invalid:focus,input[type="checkbox"]: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}select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type="radio"][disabled],input[type="checkbox"][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:solid 1px #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{position:absolute;content:"";display:block;left:0;top:0;width:36px;height:12px;border-radius:4px;background:#ccc;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{position:absolute;content:"";display:block;width:18px;height:18px;border-radius:4px;background:#999;left:-3px;top:-3px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.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="text"],.wy-control-group.wy-control-group-error input[type="password"],.wy-control-group.wy-control-group-error input[type="email"],.wy-control-group.wy-control-group-error input[type="url"],.wy-control-group.wy-control-group-error input[type="date"],.wy-control-group.wy-control-group-error input[type="month"],.wy-control-group.wy-control-group-error input[type="time"],.wy-control-group.wy-control-group-error input[type="datetime"],.wy-control-group.wy-control-group-error input[type="datetime-local"],.wy-control-group.wy-control-group-error input[type="week"],.wy-control-group.wy-control-group-error input[type="number"],.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="color"]{border:solid 1px #E74C3C}.wy-control-group.wy-control-group-error textarea{border:solid 1px #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="text"],.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:.3em;display:block}.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{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 0}.wy-form .wy-help-inline,.wy-form-message-inline,.wy-form-message{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%}.wy-table,.rst-content table.docutils,.rst-content table.field-list{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.wy-table caption,.rst-content table.docutils caption,.rst-content table.field-list caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td,.wy-table th,.rst-content table.docutils th,.rst-content table.field-list th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.wy-table td:first-child,.rst-content table.docutils td:first-child,.rst-content table.field-list td:first-child,.wy-table th:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list th:first-child{border-left-width:0}.wy-table thead,.rst-content table.docutils thead,.rst-content table.field-list thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.wy-table thead th,.rst-content table.docutils thead th,.rst-content table.field-list thead th{font-weight:bold;border-bottom:solid 2px #e1e4e5}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td{background-color:transparent;vertical-align:middle}.wy-table td p,.rst-content table.docutils td p,.rst-content table.field-list td p{line-height:18px}.wy-table td p:last-child,.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child{margin-bottom:0}.wy-table .wy-table-cell-min,.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min{width:1%;padding-right:0}.wy-table .wy-table-cell-min input[type=checkbox],.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],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:gray;font-size:90%}.wy-table-tertiary{color:gray;font-size:80%}.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td,.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td{background-color:#f3f6f6}.wy-table-backed{background-color:#f3f6f6}.wy-table-bordered-all,.rst-content table.docutils{border:1px solid #e1e4e5}.wy-table-bordered-all td,.rst-content table.docutils td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.wy-table-bordered-all tbody>tr:last-child td,.rst-content table.docutils 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 tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px 0;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%;overflow-x:hidden}body{font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;font-weight:normal;color:#404040;min-height:100%;overflow-x:hidden;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}h1,h2,.rst-content .toctree-wrapper p.caption,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;margin:0;font-size:16px;margin-bottom:24px}h1{font-size:175%}h2,.rst-content .toctree-wrapper p.caption{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}code,.rst-content tt,.rst-content code{white-space:nowrap;max-width:100%;background:#fff;border:solid 1px #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}code.code-large,.rst-content tt.code-large{font-size:90%}.wy-plain-list-disc,.rst-content .section ul,.rst-content .toctree-wrapper ul,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.wy-plain-list-disc li,.rst-content .section ul li,.rst-content .toctree-wrapper ul li,article ul li{list-style:disc;margin-left:24px}.wy-plain-list-disc li p:last-child,.rst-content .section ul li p:last-child,.rst-content .toctree-wrapper ul li p:last-child,article ul li p:last-child{margin-bottom:0}.wy-plain-list-disc li ul,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li ul,article ul li ul{margin-bottom:0}.wy-plain-list-disc li li,.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,article ul li li{list-style:circle}.wy-plain-list-disc li li li,.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,article ul li li li{list-style:square}.wy-plain-list-disc li ol li,.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,article ul li ol li{list-style:decimal}.wy-plain-list-decimal,.rst-content .section ol,.rst-content ol.arabic,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.wy-plain-list-decimal li,.rst-content .section ol li,.rst-content ol.arabic li,article ol li{list-style:decimal;margin-left:24px}.wy-plain-list-decimal li p:last-child,.rst-content .section ol li p:last-child,.rst-content ol.arabic li p:last-child,article ol li p:last-child{margin-bottom:0}.wy-plain-list-decimal li ul,.rst-content .section ol li ul,.rst-content ol.arabic li ul,article ol li ul{margin-bottom:0}.wy-plain-list-decimal li ul li,.rst-content .section ol li ul li,.rst-content ol.arabic li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:before,.wy-breadcrumbs:after{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs li{display:inline-block}.wy-breadcrumbs li.wy-breadcrumbs-aside{float:right}.wy-breadcrumbs li a{display:inline-block;padding:5px}.wy-breadcrumbs li a:first-child{padding-left:0}.wy-breadcrumbs li code,.wy-breadcrumbs li .rst-content tt,.rst-content .wy-breadcrumbs li tt{padding:5px;border:none;background:none}.wy-breadcrumbs li code.literal,.wy-breadcrumbs li .rst-content tt.literal,.rst-content .wy-breadcrumbs li tt.literal{color:#404040}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width: 480px){.wy-breadcrumbs-extra{display:none}.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:before,.wy-menu-horiz:after{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz ul,.wy-menu-horiz li{display:inline-block}.wy-menu-horiz li:hover{background:rgba(255,255,255,0.1)}.wy-menu-horiz li.divide-left{border-left:solid 1px #404040}.wy-menu-horiz li.divide-right{border-right:solid 1px #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{height:32px;display:inline-block;line-height:32px;padding:0 1.618em;margin-bottom:0;display:block;font-weight:bold;text-transform:uppercase;font-size:80%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:solid 1px #404040}.wy-menu-vertical li.divide-bottom{border-bottom:solid 1px #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:gray;border-right:solid 1px #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.wy-menu-vertical li code,.wy-menu-vertical li .rst-content tt,.rst-content .wy-menu-vertical li tt{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li span.toctree-expand{display:block;float:left;margin-left:-1.2em;font-size:.8em;line-height:1.6em;color:#4d4d4d}.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a{color:#404040;padding:.4045em 1.618em;font-weight:bold;position:relative;background:#fcfcfc;border:none;padding-left:1.618em -4px}.wy-menu-vertical li.on a:hover,.wy-menu-vertical li.current>a:hover{background:#fcfcfc}.wy-menu-vertical li.on a:hover span.toctree-expand,.wy-menu-vertical li.current>a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand{display:block;font-size:.8em;line-height:1.6em;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:solid 1px #c9c9c9;border-top:solid 1px #c9c9c9}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a{color:#404040}.wy-menu-vertical li.toctree-l1.current li.toctree-l2>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>ul{display:none}.wy-menu-vertical li.toctree-l1.current li.toctree-l2.current>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3.current>ul{display:block}.wy-menu-vertical li.toctree-l2.current>a{background:#c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{display:block;background:#c9c9c9;padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l2 span.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3{font-size:.9em}.wy-menu-vertical li.toctree-l3.current>a{background:#bdbdbd;padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{display:block;background:#bdbdbd;padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l3 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l3 span.toctree-expand{color:#969696}.wy-menu-vertical li.toctree-l4{font-size:.9em}.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:normal}.wy-menu-vertical a{display:inline-block;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 span.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980B9;cursor:pointer;color:#fff}.wy-menu-vertical a:active span.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;padding:.809em;display:block;color:#fcfcfc;margin-bottom:.809em}.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 auto;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a{color:#fcfcfc;font-size:100%;font-weight:bold;display:inline-block;padding:4px 6px;margin-bottom:.809em}.wy-side-nav-search>a:hover,.wy-side-nav-search .wy-dropdown>a:hover{background:rgba(255,255,255,0.1)}.wy-side-nav-search>a img.logo,.wy-side-nav-search .wy-dropdown>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search>a.icon img.logo,.wy-side-nav-search .wy-dropdown>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:normal;color:rgba(255,255,255,0.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:before,.wy-nav-top:after{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:bold}.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,0.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:gray}footer p{margin-bottom:12px}footer span.commit code,footer span.commit .rst-content tt,.rst-content footer span.commit tt{padding:0px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;font-size:1em;background:none;border:none;color:gray}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:before,.rst-footer-buttons:after{width:100%}.rst-footer-buttons:before,.rst-footer-buttons:after{display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:before,.rst-breadcrumbs-buttons:after{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:solid 1px #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:solid 1px #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:gray;font-size:90%}@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-side-scroll{width:auto}.wy-side-nav-search{width:auto}.wy-menu.wy-menu-vertical{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,0.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,footer,.wy-nav-side{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:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version span.toctree-expand,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content p.caption .headerlink,.rst-content p.caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .icon{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.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%}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #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}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none}.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.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 img{max-width:100%;height:auto}.rst-content div.figure{margin-bottom:24px}.rst-content div.figure p.caption{font-style:italic}.rst-content div.figure p:last-child.caption{margin-bottom:0px}.rst-content div.figure.align-center{text-align:center}.rst-content .section>img,.rst-content .section>a>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"";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 12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;display:block;overflow:auto}.rst-content pre.literal-block,.rst-content div[class^='highlight']{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px 0}.rst-content pre.literal-block div[class^='highlight'],.rst-content div[class^='highlight'] div[class^='highlight']{padding:0px;border:none;margin:0}.rst-content div[class^='highlight'] td.code{width:100%}.rst-content .linenodiv pre{border-right:solid 1px #e6e9ea;margin:0;padding:12px 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 12px;display:block;overflow:auto}.rst-content div[class^='highlight'] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content pre.literal-block,.rst-content div[class^='highlight'] pre,.rst-content .linenodiv pre{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;font-size:12px;line-height:1.4}@media print{.rst-content .codeblock,.rst-content div[class^='highlight'],.rst-content div[class^='highlight'] pre{white-space:pre-wrap}}.rst-content .note .last,.rst-content .attention .last,.rst-content .caution .last,.rst-content .danger .last,.rst-content .error .last,.rst-content .hint .last,.rst-content .important .last,.rst-content .tip .last,.rst-content .warning .last,.rst-content .seealso .last,.rst-content .admonition-todo .last,.rst-content .admonition .last{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,0.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent !important;border-color:rgba(0,0,0,0.1) !important}.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{list-style:upper-alpha}.rst-content .section ol p,.rst-content .section ul p{margin-bottom:12px}.rst-content .section ol p:last-child,.rst-content .section ul p:last-child{margin-bottom:24px}.rst-content .line-block{margin-left:0px;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0px}.rst-content .topic-title{font-weight:bold;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0px 0px 24px 24px}.rst-content .align-left{float:left;margin:0px 24px 24px 0px}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content .toctree-wrapper p.caption .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink{visibility:hidden;font-size:14px}.rst-content h1 .headerlink:after,.rst-content h2 .headerlink:after,.rst-content .toctree-wrapper p.caption .headerlink:after,.rst-content h3 .headerlink:after,.rst-content h4 .headerlink:after,.rst-content h5 .headerlink:after,.rst-content h6 .headerlink:after,.rst-content dl dt .headerlink:after,.rst-content p.caption .headerlink:after,.rst-content table>caption .headerlink:after{content:"";font-family:FontAwesome}.rst-content h1:hover .headerlink:after,.rst-content h2:hover .headerlink:after,.rst-content .toctree-wrapper p.caption:hover .headerlink:after,.rst-content h3:hover .headerlink:after,.rst-content h4:hover .headerlink:after,.rst-content h5:hover .headerlink:after,.rst-content h6:hover .headerlink:after,.rst-content dl dt:hover .headerlink:after,.rst-content p.caption:hover .headerlink:after,.rst-content table>caption:hover .headerlink:after{visibility:visible}.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:solid 1px #e1e4e5}.rst-content .sidebar p,.rst-content .sidebar ul,.rst-content .sidebar dl{font-size:90%}.rst-content .sidebar .last{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif;font-weight:bold;background:#e1e4e5;padding:6px 12px;margin:-24px;margin-bottom:24px;font-size:100%}.rst-content .highlighted{background:#F1C40F;display:inline-block;font-weight:bold;padding:0 6px}.rst-content .footnote-reference,.rst-content .citation-reference{vertical-align:baseline;position:relative;top:-0.4em;line-height:0;font-size:90%}.rst-content table.docutils.citation,.rst-content table.docutils.footnote{background:none;border:none;color:gray}.rst-content table.docutils.citation td,.rst-content table.docutils.citation tr,.rst-content table.docutils.footnote td,.rst-content table.docutils.footnote tr{border:none;background-color:transparent !important;white-space:normal}.rst-content table.docutils.citation td.label,.rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}.rst-content table.docutils.citation tt,.rst-content table.docutils.citation code,.rst-content table.docutils.footnote tt,.rst-content table.docutils.footnote code{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}.rst-content table.docutils td .last,.rst-content table.docutils td .last :last-child{margin-bottom:0}.rst-content table.field-list{border:none}.rst-content table.field-list td{border:none}.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 tt,.rst-content tt,.rst-content code{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;padding:2px 5px}.rst-content tt big,.rst-content tt em,.rst-content tt big,.rst-content code big,.rst-content tt em,.rst-content code em{font-size:100% !important;line-height:normal}.rst-content tt.literal,.rst-content tt.literal,.rst-content code.literal{color:#E74C3C}.rst-content tt.xref,a .rst-content tt,.rst-content tt.xref,.rst-content code.xref,a .rst-content tt,a .rst-content code{font-weight:bold;color:#404040}.rst-content pre,.rst-content kbd,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace}.rst-content a tt,.rst-content a tt,.rst-content a code{color:#2980B9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:bold;margin-bottom:12px}.rst-content dl p,.rst-content dl table,.rst-content dl ul,.rst-content dl ol{margin-bottom:12px !important}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl:not(.docutils){margin-bottom:24px}.rst-content dl:not(.docutils) dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980B9;border-top:solid 3px #6ab0de;padding:6px;position:relative}.rst-content dl:not(.docutils) dt:before{color:#6ab0de}.rst-content dl:not(.docutils) dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dl dt{margin-bottom:6px;border:none;border-left:solid 3px #ccc;background:#f0f0f0;color:#555}.rst-content dl:not(.docutils) dl dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dt:first-child{margin-top:0}.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) code{font-weight:bold}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) code.descclassname{background-color:transparent;border:none;padding:0;font-size:100% !important}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname{font-weight:bold}.rst-content dl:not(.docutils) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:bold}.rst-content dl:not(.docutils) .property{display:inline-block;padding-right:8px}.rst-content .viewcode-link,.rst-content .viewcode-back{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:bold}.rst-content tt.download,.rst-content code.download{background:inherit;padding:inherit;font-weight:normal;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content tt.download span:first-child,.rst-content code.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{margin-right:4px}.rst-content .guilabel{border:1px solid #7fbbe3;background:#e7f2fa;font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.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/lato-regular.eot");src:url("../fonts/Lato/lato-regular.eot?#iefix") format("embedded-opentype"),url("../fonts/Lato/lato-regular.woff2") format("woff2"),url("../fonts/Lato/lato-regular.woff") format("woff"),url("../fonts/Lato/lato-regular.ttf") format("truetype");font-weight:400;font-style:normal}@font-face{font-family:"Lato";src:url("../fonts/Lato/lato-bold.eot");src:url("../fonts/Lato/lato-bold.eot?#iefix") format("embedded-opentype"),url("../fonts/Lato/lato-bold.woff2") format("woff2"),url("../fonts/Lato/lato-bold.woff") format("woff"),url("../fonts/Lato/lato-bold.ttf") format("truetype");font-weight:700;font-style:normal}@font-face{font-family:"Lato";src:url("../fonts/Lato/lato-bolditalic.eot");src:url("../fonts/Lato/lato-bolditalic.eot?#iefix") format("embedded-opentype"),url("../fonts/Lato/lato-bolditalic.woff2") format("woff2"),url("../fonts/Lato/lato-bolditalic.woff") format("woff"),url("../fonts/Lato/lato-bolditalic.ttf") format("truetype");font-weight:700;font-style:italic}@font-face{font-family:"Lato";src:url("../fonts/Lato/lato-italic.eot");src:url("../fonts/Lato/lato-italic.eot?#iefix") format("embedded-opentype"),url("../fonts/Lato/lato-italic.woff2") format("woff2"),url("../fonts/Lato/lato-italic.woff") format("woff"),url("../fonts/Lato/lato-italic.ttf") format("truetype");font-weight:400;font-style:italic}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:400;src:url("../fonts/RobotoSlab/roboto-slab.eot");src:url("../fonts/RobotoSlab/roboto-slab-v7-regular.eot?#iefix") format("embedded-opentype"),url("../fonts/RobotoSlab/roboto-slab-v7-regular.woff2") format("woff2"),url("../fonts/RobotoSlab/roboto-slab-v7-regular.woff") format("woff"),url("../fonts/RobotoSlab/roboto-slab-v7-regular.ttf") format("truetype")}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:700;src:url("../fonts/RobotoSlab/roboto-slab-v7-bold.eot");src:url("../fonts/RobotoSlab/roboto-slab-v7-bold.eot?#iefix") format("embedded-opentype"),url("../fonts/RobotoSlab/roboto-slab-v7-bold.woff2") format("woff2"),url("../fonts/RobotoSlab/roboto-slab-v7-bold.woff") format("woff"),url("../fonts/RobotoSlab/roboto-slab-v7-bold.ttf") format("truetype")} diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 00000000..d06a71d7 --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 00000000..48f5f06b --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,14 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: 'fa9652cb6090a9a41b7cae679e71f929a1e4dd42', + 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/favicon.ico b/_static/favicon.ico new file mode 100644 index 00000000..b20ed84b Binary files /dev/null and b/_static/favicon.ico differ diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/_static/file.png differ diff --git a/_static/fonts.css b/_static/fonts.css new file mode 100644 index 00000000..0f048c33 --- /dev/null +++ b/_static/fonts.css @@ -0,0 +1,35 @@ +@font-face { + font-family: "averta"; + src: url("./Averta/AvertaDemo-Regular.otf") format("truetype"); +} + +@font-face { + font-family: "averta"; + src: url("./Averta/AvertaDemo-Bold.otf") format("truetype"); + font-weight: bold; +} + +@font-face { + font-family: "averta"; + src: url("./Averta/AvertaDemo-ExtraBoldItalic.otf") format("truetype"); + font-weight: bolder; + font-style: italic; +} + +@font-face { + font-family: "futuralt"; + src: url("./Futura/FuturaLT.ttf") format("truetype"); +} + +@font-face { + font-family: "futuralt"; + src: url("./Futura/FuturaLT-Bold.ttf") format("truetype"); + font-weight: bold; +} + +@font-face { + font-family: "futuralt"; + src: url("./Futura/FuturaLT-Heavy.otf") format("truetype"); + font-weight: bolder; + font-style: italic; +} diff --git a/_static/fonts/Inconsolata-Bold.ttf b/_static/fonts/Inconsolata-Bold.ttf new file mode 100644 index 00000000..809c1f58 Binary files /dev/null and b/_static/fonts/Inconsolata-Bold.ttf differ diff --git a/_static/fonts/Inconsolata-Regular.ttf b/_static/fonts/Inconsolata-Regular.ttf new file mode 100644 index 00000000..fc981ce7 Binary files /dev/null and b/_static/fonts/Inconsolata-Regular.ttf differ diff --git a/_static/fonts/Inconsolata.ttf b/_static/fonts/Inconsolata.ttf new file mode 100644 index 00000000..4b8a36d2 Binary files /dev/null and b/_static/fonts/Inconsolata.ttf differ diff --git a/_static/fonts/Lato-Bold.ttf b/_static/fonts/Lato-Bold.ttf new file mode 100644 index 00000000..1d23c706 Binary files /dev/null and b/_static/fonts/Lato-Bold.ttf differ diff --git a/_static/fonts/Lato-Regular.ttf b/_static/fonts/Lato-Regular.ttf new file mode 100644 index 00000000..0f3d0f83 Binary files /dev/null and b/_static/fonts/Lato-Regular.ttf differ diff --git a/_static/fonts/Lato/lato-bold.eot b/_static/fonts/Lato/lato-bold.eot new file mode 100644 index 00000000..3361183a Binary files /dev/null and b/_static/fonts/Lato/lato-bold.eot differ diff --git a/_static/fonts/Lato/lato-bold.ttf b/_static/fonts/Lato/lato-bold.ttf new file mode 100644 index 00000000..29f691d5 Binary files /dev/null and b/_static/fonts/Lato/lato-bold.ttf differ diff --git a/_static/fonts/Lato/lato-bold.woff b/_static/fonts/Lato/lato-bold.woff new file mode 100644 index 00000000..c6dff51f Binary files /dev/null and b/_static/fonts/Lato/lato-bold.woff differ diff --git a/_static/fonts/Lato/lato-bold.woff2 b/_static/fonts/Lato/lato-bold.woff2 new file mode 100644 index 00000000..bb195043 Binary files /dev/null and b/_static/fonts/Lato/lato-bold.woff2 differ diff --git a/_static/fonts/Lato/lato-bolditalic.eot b/_static/fonts/Lato/lato-bolditalic.eot new file mode 100644 index 00000000..3d415493 Binary files /dev/null and b/_static/fonts/Lato/lato-bolditalic.eot differ diff --git a/_static/fonts/Lato/lato-bolditalic.ttf b/_static/fonts/Lato/lato-bolditalic.ttf new file mode 100644 index 00000000..f402040b Binary files /dev/null and b/_static/fonts/Lato/lato-bolditalic.ttf differ diff --git a/_static/fonts/Lato/lato-bolditalic.woff b/_static/fonts/Lato/lato-bolditalic.woff new file mode 100644 index 00000000..88ad05b9 Binary files /dev/null and b/_static/fonts/Lato/lato-bolditalic.woff differ diff --git a/_static/fonts/Lato/lato-bolditalic.woff2 b/_static/fonts/Lato/lato-bolditalic.woff2 new file mode 100644 index 00000000..c4e3d804 Binary files /dev/null and b/_static/fonts/Lato/lato-bolditalic.woff2 differ diff --git a/_static/fonts/Lato/lato-italic.eot b/_static/fonts/Lato/lato-italic.eot new file mode 100644 index 00000000..3f826421 Binary files /dev/null and b/_static/fonts/Lato/lato-italic.eot differ diff --git a/_static/fonts/Lato/lato-italic.ttf b/_static/fonts/Lato/lato-italic.ttf new file mode 100644 index 00000000..b4bfc9b2 Binary files /dev/null and b/_static/fonts/Lato/lato-italic.ttf differ diff --git a/_static/fonts/Lato/lato-italic.woff b/_static/fonts/Lato/lato-italic.woff new file mode 100644 index 00000000..76114bc0 Binary files /dev/null and b/_static/fonts/Lato/lato-italic.woff differ diff --git a/_static/fonts/Lato/lato-italic.woff2 b/_static/fonts/Lato/lato-italic.woff2 new file mode 100644 index 00000000..3404f37e Binary files /dev/null and b/_static/fonts/Lato/lato-italic.woff2 differ diff --git a/_static/fonts/Lato/lato-regular.eot b/_static/fonts/Lato/lato-regular.eot new file mode 100644 index 00000000..11e3f2a5 Binary files /dev/null and b/_static/fonts/Lato/lato-regular.eot differ diff --git a/_static/fonts/Lato/lato-regular.ttf b/_static/fonts/Lato/lato-regular.ttf new file mode 100644 index 00000000..74decd9e Binary files /dev/null and b/_static/fonts/Lato/lato-regular.ttf differ diff --git a/_static/fonts/Lato/lato-regular.woff b/_static/fonts/Lato/lato-regular.woff new file mode 100644 index 00000000..ae1307ff Binary files /dev/null and b/_static/fonts/Lato/lato-regular.woff differ diff --git a/_static/fonts/Lato/lato-regular.woff2 b/_static/fonts/Lato/lato-regular.woff2 new file mode 100644 index 00000000..3bf98433 Binary files /dev/null and b/_static/fonts/Lato/lato-regular.woff2 differ diff --git a/_static/fonts/RobotoSlab-Bold.ttf b/_static/fonts/RobotoSlab-Bold.ttf new file mode 100644 index 00000000..df5d1df2 Binary files /dev/null and b/_static/fonts/RobotoSlab-Bold.ttf differ diff --git a/_static/fonts/RobotoSlab-Regular.ttf b/_static/fonts/RobotoSlab-Regular.ttf new file mode 100644 index 00000000..eb52a790 Binary files /dev/null and b/_static/fonts/RobotoSlab-Regular.ttf differ diff --git a/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot b/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot new file mode 100644 index 00000000..79dc8efe Binary files /dev/null and b/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot differ diff --git a/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf b/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf new file mode 100644 index 00000000..df5d1df2 Binary files /dev/null and b/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf differ diff --git a/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff b/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff new file mode 100644 index 00000000..6cb60000 Binary files /dev/null and b/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff differ diff --git a/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 b/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 new file mode 100644 index 00000000..7059e231 Binary files /dev/null and b/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 differ diff --git a/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot b/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot new file mode 100644 index 00000000..2f7ca78a Binary files /dev/null and b/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot differ diff --git a/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf b/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf new file mode 100644 index 00000000..eb52a790 Binary files /dev/null and b/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf differ diff --git a/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff b/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff new file mode 100644 index 00000000..f815f63f Binary files /dev/null and b/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff differ diff --git a/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 b/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 new file mode 100644 index 00000000..f2c76e5b Binary files /dev/null and b/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 differ diff --git a/_static/fonts/fontawesome-webfont.eot b/_static/fonts/fontawesome-webfont.eot new file mode 100644 index 00000000..e9f60ca9 Binary files /dev/null and b/_static/fonts/fontawesome-webfont.eot differ diff --git a/_static/fonts/fontawesome-webfont.svg b/_static/fonts/fontawesome-webfont.svg new file mode 100644 index 00000000..855c845e --- /dev/null +++ b/_static/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/fonts/fontawesome-webfont.ttf b/_static/fonts/fontawesome-webfont.ttf new file mode 100644 index 00000000..35acda2f Binary files /dev/null and b/_static/fonts/fontawesome-webfont.ttf differ diff --git a/_static/fonts/fontawesome-webfont.woff b/_static/fonts/fontawesome-webfont.woff new file mode 100644 index 00000000..400014a4 Binary files /dev/null and b/_static/fonts/fontawesome-webfont.woff differ diff --git a/_static/fonts/fontawesome-webfont.woff2 b/_static/fonts/fontawesome-webfont.woff2 new file mode 100644 index 00000000..4d13fc60 Binary files /dev/null and b/_static/fonts/fontawesome-webfont.woff2 differ diff --git a/_static/js/modernizr.min.js b/_static/js/modernizr.min.js new file mode 100644 index 00000000..f65d4797 --- /dev/null +++ b/_static/js/modernizr.min.js @@ -0,0 +1,4 @@ +/* Modernizr 2.6.2 (Custom Build) | MIT & BSD + * Build: http://modernizr.com/download/#-fontface-backgroundsize-borderimage-borderradius-boxshadow-flexbox-hsla-multiplebgs-opacity-rgba-textshadow-cssanimations-csscolumns-generatedcontent-cssgradients-cssreflections-csstransforms-csstransforms3d-csstransitions-applicationcache-canvas-canvastext-draganddrop-hashchange-history-audio-video-indexeddb-input-inputtypes-localstorage-postmessage-sessionstorage-websockets-websqldatabase-webworkers-geolocation-inlinesvg-smil-svg-svgclippaths-touch-webgl-shiv-mq-cssclasses-addtest-prefixed-teststyles-testprop-testallprops-hasevent-prefixes-domprefixes-load + */ +;window.Modernizr=function(a,b,c){function D(a){j.cssText=a}function E(a,b){return D(n.join(a+";")+(b||""))}function F(a,b){return typeof a===b}function G(a,b){return!!~(""+a).indexOf(b)}function H(a,b){for(var d in a){var e=a[d];if(!G(e,"-")&&j[e]!==c)return b=="pfx"?e:!0}return!1}function I(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:F(f,"function")?f.bind(d||b):f}return!1}function J(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+p.join(d+" ")+d).split(" ");return F(b,"string")||F(b,"undefined")?H(e,b):(e=(a+" "+q.join(d+" ")+d).split(" "),I(e,b,c))}function K(){e.input=function(c){for(var d=0,e=c.length;d',a,""].join(""),l.id=h,(m?l:n).innerHTML+=f,n.appendChild(l),m||(n.style.background="",n.style.overflow="hidden",k=g.style.overflow,g.style.overflow="hidden",g.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),g.style.overflow=k),!!i},z=function(b){var c=a.matchMedia||a.msMatchMedia;if(c)return c(b).matches;var d;return y("@media "+b+" { #"+h+" { position: absolute; } }",function(b){d=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle)["position"]=="absolute"}),d},A=function(){function d(d,e){e=e||b.createElement(a[d]||"div"),d="on"+d;var f=d in e;return f||(e.setAttribute||(e=b.createElement("div")),e.setAttribute&&e.removeAttribute&&(e.setAttribute(d,""),f=F(e[d],"function"),F(e[d],"undefined")||(e[d]=c),e.removeAttribute(d))),e=null,f}var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return d}(),B={}.hasOwnProperty,C;!F(B,"undefined")&&!F(B.call,"undefined")?C=function(a,b){return B.call(a,b)}:C=function(a,b){return b in a&&F(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=w.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(w.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(w.call(arguments)))};return e}),s.flexbox=function(){return J("flexWrap")},s.canvas=function(){var a=b.createElement("canvas");return!!a.getContext&&!!a.getContext("2d")},s.canvastext=function(){return!!e.canvas&&!!F(b.createElement("canvas").getContext("2d").fillText,"function")},s.webgl=function(){return!!a.WebGLRenderingContext},s.touch=function(){var c;return"ontouchstart"in a||a.DocumentTouch&&b instanceof DocumentTouch?c=!0:y(["@media (",n.join("touch-enabled),("),h,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(a){c=a.offsetTop===9}),c},s.geolocation=function(){return"geolocation"in navigator},s.postmessage=function(){return!!a.postMessage},s.websqldatabase=function(){return!!a.openDatabase},s.indexedDB=function(){return!!J("indexedDB",a)},s.hashchange=function(){return A("hashchange",a)&&(b.documentMode===c||b.documentMode>7)},s.history=function(){return!!a.history&&!!history.pushState},s.draganddrop=function(){var a=b.createElement("div");return"draggable"in a||"ondragstart"in a&&"ondrop"in a},s.websockets=function(){return"WebSocket"in a||"MozWebSocket"in a},s.rgba=function(){return D("background-color:rgba(150,255,150,.5)"),G(j.backgroundColor,"rgba")},s.hsla=function(){return D("background-color:hsla(120,40%,100%,.5)"),G(j.backgroundColor,"rgba")||G(j.backgroundColor,"hsla")},s.multiplebgs=function(){return D("background:url(https://),url(https://),red url(https://)"),/(url\s*\(.*?){3}/.test(j.background)},s.backgroundsize=function(){return J("backgroundSize")},s.borderimage=function(){return J("borderImage")},s.borderradius=function(){return J("borderRadius")},s.boxshadow=function(){return J("boxShadow")},s.textshadow=function(){return b.createElement("div").style.textShadow===""},s.opacity=function(){return E("opacity:.55"),/^0.55$/.test(j.opacity)},s.cssanimations=function(){return J("animationName")},s.csscolumns=function(){return J("columnCount")},s.cssgradients=function(){var a="background-image:",b="gradient(linear,left top,right bottom,from(#9f9),to(white));",c="linear-gradient(left top,#9f9, white);";return D((a+"-webkit- ".split(" ").join(b+a)+n.join(c+a)).slice(0,-a.length)),G(j.backgroundImage,"gradient")},s.cssreflections=function(){return J("boxReflect")},s.csstransforms=function(){return!!J("transform")},s.csstransforms3d=function(){var a=!!J("perspective");return a&&"webkitPerspective"in g.style&&y("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}",function(b,c){a=b.offsetLeft===9&&b.offsetHeight===3}),a},s.csstransitions=function(){return J("transition")},s.fontface=function(){var a;return y('@font-face {font-family:"font";src:url("https://")}',function(c,d){var e=b.getElementById("smodernizr"),f=e.sheet||e.styleSheet,g=f?f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"":"";a=/src/i.test(g)&&g.indexOf(d.split(" ")[0])===0}),a},s.generatedcontent=function(){var a;return y(["#",h,"{font:0/0 a}#",h,':after{content:"',l,'";visibility:hidden;font:3px/1 a}'].join(""),function(b){a=b.offsetHeight>=3}),a},s.video=function(){var a=b.createElement("video"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),c.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,"")}catch(d){}return c},s.audio=function(){var a=b.createElement("audio"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),c.mp3=a.canPlayType("audio/mpeg;").replace(/^no$/,""),c.wav=a.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),c.m4a=(a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")).replace(/^no$/,"")}catch(d){}return c},s.localstorage=function(){try{return localStorage.setItem(h,h),localStorage.removeItem(h),!0}catch(a){return!1}},s.sessionstorage=function(){try{return sessionStorage.setItem(h,h),sessionStorage.removeItem(h),!0}catch(a){return!1}},s.webworkers=function(){return!!a.Worker},s.applicationcache=function(){return!!a.applicationCache},s.svg=function(){return!!b.createElementNS&&!!b.createElementNS(r.svg,"svg").createSVGRect},s.inlinesvg=function(){var a=b.createElement("div");return a.innerHTML="",(a.firstChild&&a.firstChild.namespaceURI)==r.svg},s.smil=function(){return!!b.createElementNS&&/SVGAnimate/.test(m.call(b.createElementNS(r.svg,"animate")))},s.svgclippaths=function(){return!!b.createElementNS&&/SVGClipPath/.test(m.call(b.createElementNS(r.svg,"clipPath")))};for(var L in s)C(s,L)&&(x=L.toLowerCase(),e[x]=s[L](),v.push((e[x]?"":"no-")+x));return e.input||K(),e.addTest=function(a,b){if(typeof a=="object")for(var d in a)C(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,typeof f!="undefined"&&f&&(g.className+=" "+(b?"":"no-")+a),e[a]=b}return e},D(""),i=k=null,function(a,b){function k(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 l(){var a=r.elements;return typeof a=="string"?a.split(" "):a}function m(a){var b=i[a[g]];return b||(b={},h++,a[g]=h,i[h]=b),b}function n(a,c,f){c||(c=b);if(j)return c.createElement(a);f||(f=m(c));var g;return f.cache[a]?g=f.cache[a].cloneNode():e.test(a)?g=(f.cache[a]=f.createElem(a)).cloneNode():g=f.createElem(a),g.canHaveChildren&&!d.test(a)?f.frag.appendChild(g):g}function o(a,c){a||(a=b);if(j)return a.createDocumentFragment();c=c||m(a);var d=c.frag.cloneNode(),e=0,f=l(),g=f.length;for(;e",f="hidden"in a,j=a.childNodes.length==1||function(){b.createElement("a");var a=b.createDocumentFragment();return typeof a.cloneNode=="undefined"||typeof a.createDocumentFragment=="undefined"||typeof a.createElement=="undefined"}()}catch(c){f=!0,j=!0}})();var r={elements:c.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:c.shivCSS!==!1,supportsUnknownElements:j,shivMethods:c.shivMethods!==!1,type:"default",shivDocument:q,createElement:n,createDocumentFragment:o};a.html5=r,q(b)}(this,b),e._version=d,e._prefixes=n,e._domPrefixes=q,e._cssomPrefixes=p,e.mq=z,e.hasEvent=A,e.testProp=function(a){return H([a])},e.testAllProps=J,e.testStyles=y,e.prefixed=function(a,b,c){return b?J(a,b,c):J(a,"pfx")},g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" js "+v.join(" "):""),e}(this,this.document),function(a,b,c){function d(a){return"[object Function]"==o.call(a)}function e(a){return"string"==typeof a}function f(){}function g(a){return!a||"loaded"==a||"complete"==a||"uninitialized"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){("c"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){"img"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),"object"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),"img"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i("c"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&"[object Opera]"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return"[object Array]"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f"),i("table.docutils.footnote").wrap("
"),i("table.docutils.citation").wrap("
"),i(".wy-menu-vertical ul").not(".simple").siblings("a").each(function(){var e=i(this);expand=i(''),expand.on("click",function(n){return t.toggleCurrent(e),n.stopPropagation(),!1}),e.prepend(expand)})},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),i=e.find('[href="'+n+'"]');if(0===i.length){var t=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(i=e.find('[href="#'+t.attr("id")+'"]')).length&&(i=e.find('[href="#"]'))}0this.docHeight||(this.navBar.scrollTop(i),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"),e.siblings().find("li.current").removeClass("current"),e.find("> ul li.current").removeClass("current"),e.toggleClass("current")}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:e.exports.ThemeNav,StickyNav:e.exports.ThemeNav}),function(){for(var r=0,n=["ms","moz","webkit","o"],e=0;e0 + 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 00000000..d96755fd Binary files /dev/null and b/_static/minus.png differ diff --git a/_static/owkin.css b/_static/owkin.css new file mode 100644 index 00000000..38041b21 --- /dev/null +++ b/_static/owkin.css @@ -0,0 +1,186 @@ +:root { + --color-blue: #3c73c4; + --color-dark-grey: #262c3c; + + --font-title: "futuralt", Trebuchet MS, arial, sans-serif; + + --font-size-xxl: 62px; + --font-size-xl: 4rem; + --font-size-large: 2.4rem; + --font-size-normal: 17px; + --font-size-small: 14px; +} + +html { + font-size: 62.5%; +} + +body { + font-family: "averta", "Helvetica Neue", helvetica, arial, sans-serif; + color: black; + text-align:justify; + font-size: var(--font-size-normal); +} + +a { + color: var(--color-blue); +} + +a:hover { + color: black; +} + +h1, h2, h3, +.rst-content .toctree-wrapper > p.caption { + font-family: var(--font-title); + font-weight: bolder; + color: var(--color-dark-grey); +} + +h1 { + font-size: var(--font-size-xxl); + line-height: 1.1; + text-align: left; + /*text-transform: uppercase;*/ +} + +h2, +.rst-content .toctree-wrapper > p.caption { + font-size: var(--font-size-xl); + line-height: 1.4; + margin: 6rem auto 3rem; +} + +h3 { + font-size: var(--font-size-large); + line-height: 1.4; + margin: 4.5rem auto 2.5rem; +} + +p, ul, ol { + font-size: var(--font-size-normal); + line-height: 1.4; + margin: 0 0 1.5em 0; +} + +.wy-nav-content { + max-width: 900px; +} + +@media screen and (min-width: 1100px) { + .wy-nav-content { + margin-left: 75px; + background-color: white; + } + + .rst-content div[class^=highlight] { + max-width: calc(100vw - 300px - 2 * 75px - 3.236em); + min-width: 100%; + width: fit-content; + overflow-x: hidden; + + } +} + +.wy-side-nav-search, +.wy-nav-content-wrap, +.wy-body-for-nav, +.wy-nav-side { + color: black; + background-color: white !important; +} + +.wy-side-nav-search { + padding: 2.8rem 0 0 0; + +} + + +.wy-breadcrumbs { + /*text-transform: uppercase;*/ + font-weight: bold; + font-size: var(--font-size-small); +} + +a, +a:visited { + color: var(--color-blue); +} + +a:hover, +a:visited:hover { + color: black; +} + +.btn-download { + display: flex; + max-width: 260px; + align-items: center; + text-transform: uppercase; + padding-bottom: 0.625rem; + border-bottom: 1px solid #f3f4f7; +} + +.btn-download:hover { + border-bottom: 1px solid; +} + +.btn-download-image { + height: 40px !important; + margin-right: 8px; +} + +.btn { + display: inline-block; + padding: 8px 20px; + border-radius: 30px; + border: 1px solid; + text-transform: uppercase; + font-size: var(--font-size-small); + text-decoration: none; + margin: 0 10px 12px 0; + line-height: 2; + text-align: center; + color: var(--color-blue); +} + +.btn:active { + padding: 8px 20px; +} + +.btn-neutral, +.btn-neutral:visited { + color: var(--color-blue) !important; + background-color: transparent !important; +} + +.btn-neutral:hover, +.btn-neutral:visited:hover { + color: black !important; + background-color: transparent !important; +} + +.rst-content .admonition-title, +.wy-alert-title { + font-size: var(--font-size-small); +} + +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(.glossary):not(.simple) > dt { + font-size: var(--font-size-small); +} + +html.writer-html5 .rst-content table.docutils td > p, +html.writer-html5 .rst-content table.docutils th > p { + font-size: var(--font-size-small); +} + +.wy-nav-top { + background-color: var(--color-dark-grey); +} + +.wy-nav-top a, +.wy-nav-top a:visited, +.wy-nav-top a:hover { + color: white; +} diff --git a/_static/plus.png b/_static/plus.png new file mode 100644 index 00000000..7107cec9 Binary files /dev/null and b/_static/plus.png differ diff --git a/_static/pygments.css b/_static/pygments.css new file mode 100644 index 00000000..84ab3030 --- /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 00000000..97d56a74 --- /dev/null +++ b/_static/searchtools.js @@ -0,0 +1,566 @@ +/* + * 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) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docUrlRoot = DOCUMENTATION_OPTIONS.URL_ROOT; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + + 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 = docUrlRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = docUrlRoot + 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 + ")"; + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms) + ); + }); + 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 +) => { + // 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); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms), + 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); + }, + + /** + * 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/sidebar.css b/_static/sidebar.css new file mode 100644 index 00000000..cb263504 --- /dev/null +++ b/_static/sidebar.css @@ -0,0 +1,92 @@ +.wy-side-nav-search > a { + font-family: var(--font-title); + font-weight: bolder; + color: var(--color-dark-grey); + display: flex; + flex-direction: column-reverse; + font-size: 2rem; + /*text-transform: uppercase;*/ + align-items: center; + padding: 0; + margin-bottom: 0.5em; +} + +.wy-side-nav-search .wy-dropdown>a img.logo, +.wy-side-nav-search>a img.logo { + width: 200px; + margin: 0 !important; +} + +.wy-side-nav-search > a:before { + display: none; +} + +.wy-side-nav-search>div.version { + font-family: var(--font-title); + color: black; + font-size: 1.4rem; + font-weight: bolder; +} + +.wy-side-nav-search input[type=text] { + padding: 8px 20px; + margin: 2.8rem 1rem 0 1rem; + border-radius: 30px; + border: 1px solid; + font-size: 17px; + text-decoration: none; + line-height: 2; + color: var(--color-blue); + width: calc(100% - 2rem); +} + +.wy-menu-vertical header, +.wy-menu-vertical p.caption { + font-size: 1.4rem; + margin-top: 2.8rem; + /*text-transform: uppercase;*/ + color: black; + opacity: 0.4; +} + +.wy-menu-vertical a, +.wy-menu-vertical li.current a { + color: black; + text-align: left; + border-right: none; +} +.wy-menu-vertical a:hover, +.wy-menu-vertical li.current a:hover { + background-color: transparent; +} +.wy-menu-vertical li.current, +.wy-menu-vertical li.toctree-l1.current > a, +.wy-menu-vertical li.toctree-l2.current > a, +.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a { + color: var(--color-blue); + background-color: transparent; + border-bottom: none; + border-top: none; +} + +.rst-versions { + background: var(--color-dark-grey); + color: white; + font-family: inherit; +} + +.rst-versions .rst-current-version { + background-color: var(--color-dark-grey); + color: white; + font-size: var(--font-size-small); +} + +.rst-versions .rst-other-versions { + background-color: var(--color-dark-grey); + color: white; + font-size: var(--font-size-small); +} + +.rst-versions .rst-other-versions dd a { + color: white; +} diff --git a/_static/sphinx_highlight.js b/_static/sphinx_highlight.js new file mode 100644 index 00000000..aae669d7 --- /dev/null +++ b/_static/sphinx_highlight.js @@ -0,0 +1,144 @@ +/* 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))); + parent.insertBefore( + span, + parent.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + + 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(SphinxHighlight.highlightSearchWords); +_ready(SphinxHighlight.initEscapeListener); diff --git a/api/algorithms.html b/api/algorithms.html new file mode 100644 index 00000000..8454a64a --- /dev/null +++ b/api/algorithms.html @@ -0,0 +1,416 @@ + + + + + + + + + + + + fedeca.algorithms — FedECA fa9652cb6090a9a41b7cae679e71f929a1e4dd42 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • fedeca.algorithms
  • + + +
  • + + + +
  • + +
+ + +
+
+
+
+ +
+

fedeca.algorithms

+
+
+class TorchWebDiscoAlgo(model, batch_size, *args, duration_col='T', event_col='E', treated_col=None, initial_step_size=0.95, learning_rate_strategy='lifelines', standardize_data=True, tol=1e-16, penalizer=0.0, l1_ratio=0.0, propensity_model=None, training_strategy='iptw', cox_fit_cols=None, propensity_fit_cols=None, store_hessian=False, with_batch_norm_parameters=False, use_gpu=True, robust=False, **kwargs)
+

Bases: TorchAlgo

+

WebDiscoAlgo class.

+
+
Parameters:
+
    +
  • model (Module) –

  • +
  • batch_size (int | None) –

  • +
  • duration_col (str) –

  • +
  • event_col (str) –

  • +
  • treated_col (str) –

  • +
  • initial_step_size (float) –

  • +
  • learning_rate_strategy (str) –

  • +
  • standardize_data (bool) –

  • +
  • tol (float) –

  • +
  • penalizer (float) –

  • +
  • l1_ratio (float) –

  • +
  • propensity_model (Module) –

  • +
  • training_strategy (str) –

  • +
  • cox_fit_cols (None | list) –

  • +
  • propensity_fit_cols (None | list) –

  • +
  • store_hessian (bool) –

  • +
  • with_batch_norm_parameters (bool) –

  • +
  • use_gpu (bool) –

  • +
  • robust (bool) –

  • +
+
+
+
+
+compute_X_y_and_propensity_weights(data_from_opener, shared_state)
+

Build appropriate X, y and weights from raw output of opener.

+

Uses the helper function build_X_y and the propensity model to build the +weights.

+
+
Parameters:
+
    +
  • data_from_opener (pd.DataFrame) – Raw output from opener

  • +
  • shared_state (dict, optional) – Outmodel containing global means and stds, by default {}

  • +
+
+
Returns:
+

X input to the Cox model, y target of Cox model, weights propensity weights

+
+
Return type:
+

tuple

+
+
+
+ +
+
+compute_local_phi_stats(data_from_opener, shared_state=None)
+

Compute local updates.

+
+
Parameters:
+
    +
  • data_from_opener (Any) – _description_

  • +
  • shared_state (Optional[WebDiscoAveragedStates], optional) – _description_. Defaults to None.

  • +
+
+
Returns:
+

_description_

+
+
Return type:
+

WebDiscoSharedState

+
+
+
+ +
+
+local_uncentered_moments(data_from_opener, shared_state=None)
+

Compute the local uncentered moments.

+

This method is transformed by the decorator to meet Substra API, +and is executed in the training nodes. See build_compute_plan.

+
+
Parameters:
+
    +
  • data_from_opener (pd.DataFrame) – Dataframe returned by the opener.

  • +
  • shared_state (None, optional) – Given by the aggregation node, here nothing, by default None.

  • +
+
+
Returns:
+

Local results to be shared via shared_state to the aggregation node.

+
+
Return type:
+

dict

+
+
+
+ +
+
+predict(data_from_opener, shared_state=None)
+

Predict function.

+

Execute the following operations:

+
+
    +
  • Create the test torch dataset.

  • +
  • Execute and return the results of the self._local_predict method

  • +
+
+
+
Parameters:
+
    +
  • data_from_opener (typing.Any) – Input data

  • +
  • shared_state (typing.Any) – Latest train task shared state (output of the train method)

  • +
+
+
Return type:
+

Any

+
+
+
+ +
+
+summary()
+

Summary of the class to be exposed in the experiment summary file.

+
+
Returns:
+

A json-serializable dict with the attributes the user wants to store

+
+
Return type:
+

dict

+
+
+
+ +
+
+train(data_from_opener, shared_state=None)
+

Local train function.

+
+
Parameters:
+
    +
  • data_from_opener (Any) – _description_

  • +
  • shared_state (Optional[WebDiscoAveragedStates], optional) – description_. Defaults to None.

  • +
+
+
Raises:
+

NotImplementedError – _description_

+
+
Returns:
+

_description_

+
+
Return type:
+

WebDiscoSharedState

+
+
+
+ +
+
+property strategies: List[StrategyName]
+

List of compatible strategies.

+
+
Returns:
+

List of compatible strategies.

+
+
Return type:
+

typing.List[StrategyName]

+
+
+
+ +
+ +
+ + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/competitors.html b/api/competitors.html new file mode 100644 index 00000000..ae8d81d2 --- /dev/null +++ b/api/competitors.html @@ -0,0 +1,438 @@ + + + + + + + + + + + + fedeca.competitors — FedECA fa9652cb6090a9a41b7cae679e71f929a1e4dd42 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • fedeca.competitors
  • + + +
  • + + + +
  • + +
+ + +
+
+
+
+ +
+

fedeca.competitors

+
+
+class PooledIPTW(treated_col='treated', event_col='E', duration_col='T', ps_col='propensity_scores', effect='ATE', variance_method='naive', n_bootstrap=200, seed=None, cox_fit_kwargs=None)
+

Bases: BaseSurvivalEstimator, BootstrapMixin

+

Class for the Pooled IPTW.

+
+
Parameters:
+
+
+
+
+
+fit(data, targets=None)
+

Estimate the treatment effect via Inverse Probability Treatment Weighting.

+

Option to estimate the variance of estimation by bootstrapping.

+
+
targets: pd.DataFrame, optional

pre-computed propensity scores. +It is possible to pass pre-computed propensity scores to the fit +function to use in the IPTW estimator instead of estimating the +scores using logistic regression.

+
+
+
+
Parameters:
+
+
+
+
+ +
+
+point_estimate(data)
+

Return a point estimate of the treatment effect.

+
+
Return type:
+

ndarray

+
+
Parameters:
+

data (DataFrame) –

+
+
+
+ +
+ +
+
+class MatchingAjudsted(treated_col='treated', event_col='E', duration_col='T', ps_col='propensity_scores', variance_method='naive', n_bootstrap=200, seed=None, cox_fit_kwargs=None)
+

Bases: BaseSurvivalEstimator, BootstrapMixin

+

Implement Matching-Adjusted Indirect Comparisons class.

+

We consider that we have access to individual patients data for one of the centers +and that for the other centers we only have access to aggregated data. This method +proposes a way to balance the distribution of the indivual patients data to match +the mean (and std) of a list of covariates available in both studies.

+
+
Parameters:
+
+
+
+
+
+bootstrap_sample(data, seed=None)
+

Resampling only the individual patient data (IPD) with replacement.

+

In the setting of an estimation using MAIC, the caller is suppposed to have +access only to the individual patient data, assumed here to be marked by non- +zero treatment allocations in the data. Therefore during the resampling, only +accessible data should be resampled.

+
+
Return type:
+

DataFrame

+
+
Parameters:
+
+
+
+
+ +
+
+fit(data, targets=None)
+

Estimate the treatment effect via Inverse Probability Treatment Weighting.

+

Option to estimate the variance of estimation by bootstrapping.

+
+
Return type:
+

None

+
+
Parameters:
+
+
+
+
+
targets: pd.DataFrame, optional

pre-computed propensity scores. +It is possible to pass pre-computed propensity scores to the fit +function to use in the IPTW estimator instead of estimating the +scores using logistic regression.

+
+
+
+ +
+
+point_estimate(data)
+

Return a point estimate of the treatment effect.

+
+
Return type:
+

ndarray

+
+
Parameters:
+

data (DataFrame) –

+
+
+
+ +
+ +
+
+class NaiveComparison(treated_col='treated', event_col='E', duration_col='T', ps_col='propensity_scores', variance_method='naive', n_bootstrap=200, seed=None, cox_fit_kwargs=None)
+

Bases: BaseSurvivalEstimator, BootstrapMixin

+

Naive comparison as if in a randomized setting.

+
+
Parameters:
+
+
+
+
+
+fit(data, targets=None)
+

Estimate the treatment effect via Inverse Probability Treatment Weighting.

+

Option to estimate the variance of estimation by bootstrapping.

+
+
Return type:
+

None

+
+
Parameters:
+
+
+
+
+
targets: pd.DataFrame, optional

pre-computed propensity scores. +It is possible to pass pre-computed propensity scores to the fit +function to use in the IPTW estimator instead of estimating the +scores using logistic regression.

+
+
+
+ +
+
+point_estimate(data)
+

Return a point estimate of the treatment effect.

+
+
Return type:
+

ndarray

+
+
Parameters:
+

data (DataFrame) –

+
+
+
+ +
+ +
+ + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iptw.html b/api/iptw.html new file mode 100644 index 00000000..976ccda9 --- /dev/null +++ b/api/iptw.html @@ -0,0 +1,413 @@ + + + + + + + + + + + + fedeca.fedeca_core — FedECA fa9652cb6090a9a41b7cae679e71f929a1e4dd42 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • fedeca.fedeca_core
  • + + +
  • + + + +
  • + +
+ + +
+
+
+
+ +
+

fedeca.fedeca_core

+
+
+class FedECA(ndim, ds_client=None, train_data_nodes=None, treated_col='treated', event_col='E', duration_col='T', ps_col='propensity_scores', propensity_fit_cols=None, cox_fit_cols=None, num_rounds_list=[10, 10], damping_factor_nr=0.8, l2_coeff_nr=0.0, standardize_data=True, penalizer=0.0, l1_ratio=1.0, initial_step_size=0.95, learning_rate_strategy='lifelines', dtype='float64', training_strategy='iptw', variance_method='naïve', n_bootstrap=200, bootstrap_seeds=None, bootstrap_function='global', clients_sizes=None, indices_in_global_dataset=None, client_identifier='client', clients_names=None, dp_target_epsilon=None, dp_target_delta=None, dp_max_grad_norm=None, dp_propensity_model_optimizer_class=<class 'torch.optim.sgd.SGD'>, dp_propensity_model_optimizer_kwargs=None, dp_propensity_model_training_params=None, seed=42, aggregation_node=None, experiment_folder='./iptw_experiment', clean_models=False, dependencies=None, timeout=3600, sleep_time=30, fedeca_path=None, evaluation_frequency=None, partner_client=None)
+

Bases: Experiment, BaseSurvivalEstimator, BootstrapMixin

+

FedECA class that performs Federated IPTW or AIPTW.

+
+
Parameters:
+
    +
  • ndim (int) –

  • +
  • train_data_nodes (list[substrafl.nodes.train_data_node.TrainDataNode] | None) –

  • +
  • treated_col (str) –

  • +
  • event_col (str) –

  • +
  • duration_col (str) –

  • +
  • propensity_fit_cols (None | list) –

  • +
  • cox_fit_cols (None | list) –

  • +
  • num_rounds_list (list[int]) –

  • +
  • damping_factor_nr (float) –

  • +
  • l2_coeff_nr (float) –

  • +
  • standardize_data (bool) –

  • +
  • penalizer (float) –

  • +
  • l1_ratio (float) –

  • +
  • initial_step_size (float) –

  • +
  • learning_rate_strategy (str) –

  • +
  • dtype (float) –

  • +
  • training_strategy (str) –

  • +
  • variance_method (str) –

  • +
  • n_bootstrap (int | None) –

  • +
  • bootstrap_seeds (list[int] | None) –

  • +
  • bootstrap_function (Callable | str) –

  • +
  • clients_sizes (list | None) –

  • +
  • indices_in_global_dataset (list | None) –

  • +
  • client_identifier (str) –

  • +
  • clients_names (list | None) –

  • +
  • dp_target_epsilon (float | None) –

  • +
  • dp_target_delta (float | None) –

  • +
  • dp_max_grad_norm (float | None) –

  • +
  • dp_propensity_model_optimizer_class (Optimizer) –

  • +
  • dp_propensity_model_optimizer_kwargs (dict | None) –

  • +
  • dp_propensity_model_training_params (dict | None) –

  • +
  • seed (int) –

  • +
  • aggregation_node (AggregationNode | None) –

  • +
  • experiment_folder (str) –

  • +
  • clean_models (bool) –

  • +
  • dependencies (list | None) –

  • +
  • timeout (int) –

  • +
  • sleep_time (int) –

  • +
  • fedeca_path (None | str) –

  • +
  • partner_client (None | Client) –

  • +
+
+
+
+
+check_cp_status(idx=0)
+

Check the status of the process.

+
+ +
+
+compute_propensity_scores(data)
+

Compute propensity scores and corresponding weights.

+
+
Parameters:
+

data (DataFrame) –

+
+
+
+ +
+
+compute_summary(alpha=0.05)
+

Compute summary for a given threshold.

+
+
Parameters:
+

alpha (float, (default=0.05)) – Confidence level for computing CIs

+
+
+
+ +
+
+fit(data, targets=None, n_clients=None, split_method=None, split_method_kwargs=None, data_path=None, variance_method=None, n_bootstrap=None, bootstrap_seeds=None, bootstrap_function=None, dp_target_epsilon=None, dp_target_delta=None, dp_max_grad_norm=None, dp_propensity_model_training_params=None, dp_propensity_model_optimizer_class=None, dp_propensity_model_optimizer_kwargs=None, backend_type='subprocess', urls=None, server_org_id=None, tokens=None)
+

Fit strategies on global data split across clients.

+

For test if provided we use test_data_nodes from int or the +train_data_nodes in the latter train=test.

+
+
Parameters:
+
    +
  • data (pd.DataFrame) – The global data to be split has to be a dataframe as we only support +one opener type.

  • +
  • targets (Optional[pd.DataFrame], optional) – A dataframe with propensity score or nothing.

  • +
  • nb_clients (Union[int, None], optional) – The number of clients used to split data across, by default None

  • +
  • split_method (Union[Callable, None], optional) – How to split data across the nb_clients, by default None

  • +
  • split_method_kwargs (Union[Callable, None], optional) – Argument of the function used to split data, by default None

  • +
  • data_path (Union[str, None]) – Where to store the data on disk when backend is not remote.

  • +
  • variance_method (:class:```{"naive", "robust", "bootstrap"}:class:```) –

    Method for estimating the variance, and therefore the p-value of the +estimated treatment effect. +* “naive”: Inverse of the Fisher information. +* “robust”: The robust sandwich estimator [1] computed in FL thanks

    +
    +

    to FedECA. Useful when samples are reweighted.

    +
    +
      +
    • ”bootstrap”: Bootstrap the given data by sampling each patient +with replacement, each time estimate the treatment effect, then +use all repeated estimations to compute the variance. The implementation +is efficient in substra and shouldn’t induce too much overhead.

    • +
    +

    Defauts to naïve. +[1] David A Binder. Fitting cox’s proportional hazards models from survey data. Biometrika, 79(1):139–147, 1992. # noqa: E501

    +

  • +
  • n_bootstraps (Union[int, None]) – Number of bootstrap to be performed. If None will use +len(bootstrap_seeds) instead. If bootstrap_seeds is given +seeds those seeds will be used for the generation +otherwise seeds are generated randomly.

  • +
  • bootstrap_seeds (Union[list[int], None]) – The list of seeds used for bootstrapping random states. +If None will generate n_bootstraps randomly, in the presence +of both allways use bootstrap_seeds.

  • +
  • bootstrap_function (Union[Callable, None]) – The bootstrap function to use for instance if it is necessary to mimic +a global sampling.

  • +
  • dp_target_epsilon (float) – The target epsilon for (epsilon, delta)-differential +private guarantee. Defaults to None.

  • +
  • dp_target_delta (float) – The target delta for (epsilon, delta)-differential +private guarantee. Defaults to None.

  • +
  • dp_max_grad_norm (float) – The maximum L2 norm of per-sample gradients; +used to enforce differential privacy. Defaults to None.

  • +
  • dp_propensity_model_optimizer_class (torch.optim.Optimizer) – The optimizer to use for the training of the propensity model. +Defauts to Adam.

  • +
  • dp_propensity_model_optimizer_class_kwargs (dict) – The params to give to optimizer class.

  • +
  • dp_propensity_model_training_params (dict) – A dict with keys batch_size and num_updates for the DP-SGD training. +Defaults to None.

  • +
  • backend_type (str) – The backend to use for substra. Can be either: +[“subprocess”, “docker”, “remote”]. Defaults to “subprocess”.

  • +
  • urls (Union[list[str], None]) – Urls corresponding to clients API if using remote backend_type. +Defaults to None.

  • +
  • server_org_id (Union[str, None]) – Url corresponding to server API if using remote backend_type. +Defaults to None.

  • +
  • tokens (Union[list[str], None]) – Tokens necessary to authenticate each client API if backend_type +is remote. Defauts to None.

  • +
  • n_clients (int | None) –

  • +
  • n_bootstrap (int | None) –

  • +
  • dp_propensity_model_optimizer_kwargs (dict | None) –

  • +
+
+
+
+ +
+
+get_final_cox_model()
+

Retrieve final cox model.

+
+ +
+
+print_summary()
+

Print a summary of the FedECA estimation.

+
+ +
+
+reset_experiment()
+

Remove the propensity model just in case.

+
+ +
+
+run(targets=None)
+

Run the federated iptw algorithms.

+
+
Parameters:
+

targets (DataFrame | None) –

+
+
+
+ +
+
+set_propensity_model_strategy()
+

Set FedECA to use DP.

+

At the end it sets the parameter self.propensity_model_strateg

+
+ +
+
+clients_names
+

of clients for global bootstrap by passing num_clients

+
+ +
+ +
+ + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/metrics.html b/api/metrics.html new file mode 100644 index 00000000..d0cb26e3 --- /dev/null +++ b/api/metrics.html @@ -0,0 +1,263 @@ + + + + + + + + + + + + fedeca.metrics — FedECA fa9652cb6090a9a41b7cae679e71f929a1e4dd42 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • fedeca.metrics
  • + + +
  • + + + +
  • + +
+ + +
+
+
+
+ +
+

fedeca.metrics

+

Define metrics for ECA analysis.

+
+
+standardized_mean_diff(confounders, treated, weights=None, use_unweighted_variance=True)
+

Compute the Standardized Mean Differences (SMD).

+

Compute the Standardized Mean Differences between +treated and control patients.

+
+
Parameters:
+
+
+
Returns:
+

smd – standardized mean differences of the confounders.

+
+
Return type:
+

np.ndarray

+
+
+
+ +
+ + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/scripts.html b/api/scripts.html new file mode 100644 index 00000000..d5c75c34 --- /dev/null +++ b/api/scripts.html @@ -0,0 +1,281 @@ + + + + + + + + + + + + fedeca.scripts — FedECA fa9652cb6090a9a41b7cae679e71f929a1e4dd42 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • fedeca.scripts
  • + + +
  • + + + +
  • + +
+ + +
+
+
+
+ +
+

fedeca.scripts

+
+
+class CSVOpener
+

Bases: Opener

+

CSV opener class.

+
+
+fake_data(n_samples=None)
+

Generate simulated survival data.

+
+
Parameters:
+

n_samples (int or None, optional) – Number of samples, by default None.

+
+
Returns:
+

Fake survival data.

+
+
Return type:
+

pd.DataFrame

+
+
+
+ +
+
+get_data(folders)
+

Get data from CSV files.

+
+
Parameters:
+

folders (list) – List of folder paths.

+
+
Returns:
+

Loaded data from CSV files.

+
+
Return type:
+

pd.DataFrame

+
+
+
+ +
+ +
+ + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/strategies.html b/api/strategies.html new file mode 100644 index 00000000..1ef4e899 --- /dev/null +++ b/api/strategies.html @@ -0,0 +1,569 @@ + + + + + + + + + + + + fedeca.strategies — FedECA fa9652cb6090a9a41b7cae679e71f929a1e4dd42 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • fedeca.strategies
  • + + +
  • + + + +
  • + +
+ + +
+
+
+
+ +
+

fedeca.strategies

+
+
+class WebDisco(algo, metric_functions=None, standardize_data=True, tol=1e-16)
+

Bases: Strategy

+

WebDisco strategy class.

+

It can only be used with traditional Cox models on pandas.DataFrames. +This strategy is one of its kind because it can only be used with +Linear CoxPH models defined in fedeca.utils.survival_utils. Therefore all models are +initialized with zeroed weights (as in lifelines), tested and we cover all possible +use cases with the dtype and ndim arguments. This strategy splits the computations +of gradient and Hessian between workers to compute a centralized batch Newton- +Raphson update on Breslow’s partial log-likelihod (to handle tied events it uses +Breslow’s approximation unlike lifelines which uses Efron’s by default but Efron is +not separable). This strategy uses lifeline’s adaptive step-size to converge faster +starting from initial_ste_size and use lifelines safe way of inverting the hessian. +As lifelines standardizes the data by default we allow the user to do it optionally.

+
+

Reference

+ +
+
param statistics_computed:
+

If the statistics that we can find in each gradient, hessian are already +computed and given as attribute to the server or not.

+
+
type statistics_computed:
+

bool,

+
+
param initial_step_size:
+

The initial step size of the Newton-Raphson algorithm at the server side. +The following steps will use lifelines heuristics to adapt the step-size. +Defaults to 0.9.

+
+
type initial_step_size:
+

float, otional

+
+
type tol:
+

float

+
+
param tol:
+

Capping every division to avoid dividing by 0. Defaults to 1e-16.

+
+
type tol:
+

float, optional

+
+
type standardize_data:
+

bool

+
+
param standardize_data:
+

Whether or not to standardize the data before comuting updates. +Defaults to False.

+
+
type standardize_data:
+

bool,

+
+
param penalizer:
+

Add a regularizer in case of ill-conditioned hessians, which happen quite +often with large covariates. +Defaults to 0.

+
+
type penalizer:
+

float, optional

+
+
param l1_ratio:
+

When using a penalizer the ratio between L1 and L2 regularization as in +sklearn. +Defaults to 0.

+
+
type l1_ratio:
+

float, optional

+
+
+
+
+aggregate_moments(shared_states)
+

Compute the global centered moments given the local results.

+
+
Parameters:
+

shared_states (List) – List of results (local_m1, local_m2, n_samples) from training nodes.

+
+
Returns:
+

Global results to be shared with train nodes via shared_state.

+
+
Return type:
+

dict

+
+
+
+ +
+
+build_compute_plan(train_data_nodes, aggregation_node, evaluation_strategy, num_rounds, clean_models)
+

Build the computation graph of the strategy.

+

It removes initialization round, +which is useless in this case as all models start at 0.

+
+
Parameters:
+
    +
  • train_data_nodes (typing.List[TrainDataNode],) – list of the train organizations

  • +
  • aggregation_node (typing.Optional[AggregationNode],) – aggregation node, necessary for centralized strategy, unused otherwise

  • +
  • evaluation_strategy (Optional[EvaluationStrategy],) – When and how to compute performance.

  • +
  • num_rounds (int,) – The number of rounds to perform.

  • +
  • clean_models (bool (default=True),) – Clean the intermediary models on the Substra platform. +Set it to False if you want to download or re-use +intermediary models. This causes the disk space to +fill quickly so should be set to True unless needed. +Defaults to True.

  • +
+
+
+
+ +
+
+perform_evaluation(test_data_nodes, train_data_nodes, round_idx)
+

Evaluate model on the given test_data_nodes.

+
+
Parameters:
+
    +
  • test_data_nodes (List[TestDataNode]),) – test data nodes to intersect with train data nodes to evaluate the +model on.

  • +
  • train_data_nodes (List[TrainDataNode],) – train data nodes the model has been trained on.

  • +
  • round_idx (int,) – round index.

  • +
+
+
Raises:
+

NotImplementedError

+
+
+
+ +
+
+perform_round(train_data_nodes, aggregation_node, round_idx, clean_models, additional_orgs_permissions=None)
+

Perform one round of webdisco.

+
+
One round of the WebDisco strategy consists in:
    +
  • optionally compute global means and stds for all features if +standardize_data is True

  • +
  • compute global survival statistics that will be reused at each round

  • +
  • build building blocks of the gradient and hessian based on global risk +sets

  • +
  • perform a Newton-Raphson update on each train data nodes

  • +
+
+
+
+
Parameters:
+
    +
  • train_data_nodes (typing.List[TrainDataNode],) – List of the nodes on which to train

  • +
  • aggregation_node (AggregationNode) – node without data, used to perform operations on the +shared states of the models

  • +
  • round_idx (int,) – Round number, it starts at 0.

  • +
  • clean_models (bool,) – Clean the intermediary models of this round on the +Substra platform. Set it to False if you want to +download or re-use intermediary models. This causes the +disk space to fill quickly so should be set to True unless needed.

  • +
  • additional_orgs_permissions (typing.Optional[set],) – Additional permissions to give to the model outputs after training, +in order to test the model on an other organization.

  • +
+
+
+
+ +
+
+property name: StrategyName
+

The name of the strategy.

+
+
Returns:
+

StrategyName

+
+
Return type:
+

Name of the strategy

+
+
+
+ +
+
+
Parameters:
+
+
+
+
+ +

Bootstrap substra strategy in an efficient fashion.

+
+
+make_bootstrap_metric_function(metric_functions)
+

Take the metric_functions dict, and bootstrap each metric.

+
+
Parameters:
+

metric_functions (dict) – The metric functions to hook.

+
+
Return type:
+

dict

+
+
+
+ +
+
+make_bootstrap_strategy(strategy, n_bootstrap=None, bootstrap_seeds=None, bootstrap_function=None, client_specific_kwargs=None)
+

Bootstrap a substrafl strategy wo impacting the number of compute tasks.

+

In order to reduce the bottleneck of substra when bootstraping a strategy +we need to go over the strategy compute plan and modifies each local atomic +task to execute n_bootstrap times on bootstraped data. Each modified task +returns a list of n_bootstraps original outputs obtained on each bootstrap. +Each aggregation task is then modified to aggregate the n_bootstrap outputs +independently. +This code heavily uses some code patterns invented by Arthur Pignet.

+
+
Parameters:
+
    +
  • strategy (Strategy) – The strategy to bootstrap.

  • +
  • n_bootstrap (Union[int, None]) – Number of bootstrap to be performed. If None will use +len(bootstrap_seeds) instead. If bootstrap_seeds is given +seeds those seeds will be used for the generation +otherwise seeds are generated randomly.

  • +
  • bootstrap_seeds (Union[list[int], None]) – The list of seeds used for bootstrapping random states. +If None will generate n_bootstrap randomly, in the presence +of both allways use bootstrap_seeds.

  • +
  • bootstrap_function (Union[Callable, None]) – A function with signature f(data, seed) that returns a bootstrapped +version of the data. +If None, use the BootstrapMixin function. +Note that this can be used to provide splits/cross-validation capabilities +as well where seed would be the fold number in a flattened list of folds.

  • +
  • client_specific_kwargs (Union[None, list[dict]]) – A list of dictionaries containing the kwargs to be passed to the algos +if they are different for each bootstrap. It is useful to chain bootstrapped +compute plans for instance.

  • +
+
+
Returns:
+

The resulting efficiently bootstrapped strategy

+
+
Return type:
+

Strategy

+
+
+
+ +

Webdisco utils.

+
+
+compute_summary_function(final_params, variance_matrix, alpha=0.05)
+

Compute summary function.

+
+
Parameters:
+
    +
  • final_params (np.ndarray) – The estimated vallues of Cox model coefficients.

  • +
  • variance_matrix (np.ndarray) – Computed variance matrix whether using robust estimation or not.

  • +
  • alpha (float, optional) – The quantile level to test, by default 0.05

  • +
+
+
Returns:
+

Summary of IPTW analysis as in lifelines.

+
+
Return type:
+

pd.DataFrame

+
+
+
+ +
+
+get_final_cox_model_function(client, compute_plan_key, num_rounds, standardize_data, duration_col, event_col, simu_mode=False, robust=False)
+

Retrieve first converged Cox model and corresponding hessian.

+

In case of bootstrapping retrieves the first converged Cox models for each +seed.

+
+
Parameters:
+
    +
  • Client (Client) – The susbtrafl Client that registered the CP.

  • +
  • compute_plan_key (Union[str, Algo]) – The key of the CP.

  • +
  • num_rounds (int) – The number of rounds of the CP.

  • +
  • standardize_data (float, optional) – Whether or not the data was standadized, by default 0.05

  • +
  • duration_col (str) – The name of the duration column.

  • +
  • event_col (str) – The name of the event column.

  • +
  • simu_mode (bool) – Whether or not we are using simu mode. Note this could be inferred from +the Client.

  • +
  • robust (bool, optional) – Retreive global statistics for robust variance estimation.

  • +
  • client (Client) –

  • +
+
+
Returns:
+

Returns hessian, log-likelihood, Cox model’s weights, global moments

+
+
Return type:
+

tuple

+
+
+
+ +
+
+get_last_algo_from_round_count(num_rounds, standardize_data=True, simu_mode=False)
+

Get true number of rounds.

+
+
Parameters:
+
    +
  • num_rounds (list[int]) – _description_

  • +
  • standardize_data (bool, optional) – _description_, by default True

  • +
  • simu_mode (bool) – Whether or not we are in simu mode.

  • +
+
+
Returns:
+

_description_

+
+
Return type:
+

_type_

+
+
+
+ +
+ + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/utils.html b/api/utils.html new file mode 100644 index 00000000..b33caa3e --- /dev/null +++ b/api/utils.html @@ -0,0 +1,646 @@ + + + + + + + + + + + + fedeca.utils — FedECA fa9652cb6090a9a41b7cae679e71f929a1e4dd42 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • fedeca.utils
  • + + +
  • + + + +
  • + +
+ + +
+
+
+
+ +
+

fedeca.utils

+

Utility functions of data generation.

+
+
+generate_cox_data_and_substra_clients(n_clients=2, ndim=10, split_method_kwargs=None, backend_type='subprocess', data_path=None, urls=None, tokens=None, seed=42, n_per_client=200, add_treated=False, ncategorical=0)
+

Generate Cox data on disk for several clients.

+

Generate Cox data and register them with different +fake clients.

+
+
Parameters:
+
    +
  • n_clients (int, (optional)) – Number of clients. Defaults to 2.

  • +
  • ndim (int, (optional)) – Number of covariates. Defaults to 10.

  • +
  • Union[dict (split_method_kwargs =) – The argument to the split_method uniform.

  • +
  • None] – The argument to the split_method uniform.

  • +
  • backend_type (str, (optional)) – Type of backend. Defaults to “subprocess”.

  • +
  • data_path (str, (optional)) – Path to save the data. Defaults to None.

  • +
  • seed (int, (optional)) – Random seed. Defaults to 42.

  • +
  • n_per_client (int, (optional)) – Number of samples per client. Defaults to 200.

  • +
  • add_treated (bool, (optional)) – Whether or not to keep treated column.

  • +
  • ncategorical (int, (optional)) – Number of features to make categorical a posteriori (moving away from Cox +assumptions).

  • +
  • split_method_kwargs (dict | None) –

  • +
  • urls (None | list) –

  • +
  • tokens (None | list) –

  • +
+
+
+
+ +
+
+split_control_over_centers(df, n_clients, treatment_info='treatment_allocation', use_random=True, seed=42)
+

Split patients in the control group over the centers.

+
+
Parameters:
+
    +
  • df (pandas.DataFrame,) – Dataframe containing features of the patients.

  • +
  • n_clients (int,) – Number of clients.

  • +
  • treatment_info (str, (optional)) – Column name for the treatment allocation covariate. +Defaults to “treatment_allocation”.

  • +
  • use_random (bool) – Whether or not to shuffle the control group indices before splitting.

  • +
  • seed (int) – The seed of the shuffling.

  • +
+
+
+
+ +
+
+split_dataframe_across_clients(df, n_clients, split_method='uniform', split_method_kwargs=None, backend_type='subprocess', data_path=None, urls=[], tokens=[])
+

Split patients over the centers.

+
+
Parameters:
+
    +
  • df (pandas.DataFrame,) – Dataframe containing features of the patients.

  • +
  • n_clients (int,) – Number of clients.

  • +
  • split_method (Union[Callable, str]) – How to split the dataset across all clients, if callable should have the +signature: df, n_clients, kwargs -> list[list[int]] +if str should be an existing key, which will invoke the corresponding +callable. Possible values are uniform which splits the patients +uniformly across centers or split_control_over_centers where one +center has all the treated patients and the control is split over the +remaining ones.

  • +
  • split_method_kwargs (Union[dict, None]) – Optional kwargs for the split_method method.

  • +
  • backend_type (str, (optional)) – Backend type. Default is “subprocess”.

  • +
  • data_path (Union[str, None],) – Path on where to save the data on disk.

  • +
  • urls (List,) – List of urls.

  • +
  • tokens (List,) – List of tokens.

  • +
+
+
+
+ +
+
+uniform_split(df, n_clients, use_random=True, seed=42)
+

Split patients uniformly over n_clients.

+
+
Parameters:
+
    +
  • df (pandas.DataFrame,) – Dataframe containing features of the patients.

  • +
  • n_clients (int,) – Number of clients.

  • +
  • use_random (bool) – Whether or not to shuffle data before splitting. Defaults to True.

  • +
  • seed (int, (optional)) – Seeding for shuffling

  • +
+
+
+
+ +

A module containing utils to compute high-order moments using Newton’s formeanla.

+
+
+aggregation_mean(local_means, n_local_samples)
+

Aggregate local means.

+

Aggregate the local means into a global mean by using the local number of samples.

+
+
Parameters:
+
    +
  • local_means (List[Any]) – List of local means. Could be array, float, Series.

  • +
  • n_local_samples (List[int]) – List of number of samples used for each local mean.

  • +
+
+
Returns:
+

Aggregated mean. Same type of the local means

+
+
Return type:
+

Any

+
+
+
+ +
+
+compute_centered_moment(uncentered_moments)
+

Compute the centered moment of order k.

+

Given a list of the k first unnormalized moments, +compute the centered moment of order k. +For high values of the moments the results can +differ from scipy.special.moment. +We are interested in computing +.. math:

+
\hat{\mu}_k  = \frac{1}{\hat{\sigma}^k}
+    \mathbb E_Z \left[ (Z - \hat{\mu})^k\right]
+\hat{\mu}_k  = \frac{1}{\hat{\sigma}^k}
+    \mathbb E_Z \left[ \sum_{l=0}^k\binom{k}{l} Z^{k-l} (-1)^l\hat\mu^l)\right]
+\hat{\mu}_k  = \frac{1}{\hat{\sigma}^k}
+  \sum_{l=0}^k(-1)^l\binom{k}{l} \mathbb E_Z \left[ Z^{k-l}
+  \right]\mathbb E_Z \left[ Z \right]^l
+
+
+

thus we only need the list uncentered moments up to order k.

+
+
Parameters:
+

uncentered_moments (List[Any]) – List of the k first non-centered moment.

+
+
Returns:
+

The centered k-th moment.

+
+
Return type:
+

Any

+
+
+
+ +
+
+compute_global_moments(shared_states)
+

Aggregate local moments.

+
+
Parameters:
+

shared_states (list) – list of outputs from compute_uncentered_moment.

+
+
Returns:
+

The results of the aggregation with both centered and uncentered moments.

+
+
Return type:
+

dict

+
+
+
+ +
+
+compute_uncentered_moment(data, order, weights=None)
+

Compute the uncentered moment.

+
+
Parameters:
+
    +
  • data (pd.DataFrame, np.array) – dataframe.

  • +
  • order (int) – order of the moment.

  • +
  • weights (np.array) – weight for the aggregation.

  • +
+
+
Returns:
+

Moment of order k.

+
+
Return type:
+

pd.DataFrame, np.array

+
+
Raises:
+

NotImplementedError – Raised if the data type is not Dataframe nor np.ndarray.

+
+
+
+ +

Utils functions for Substra.

+
+
+class Experiment(strategies, num_rounds_list, ds_client=None, train_data_nodes=None, test_data_nodes=None, aggregation_node=None, evaluation_frequency=None, experiment_folder='./experiments', clean_models=False, fedeca_path=None, algo_dependencies=None, partner_client=None)
+

Bases: object

+

Experiment class.

+
+
Parameters:
+
    +
  • strategies (list) –

  • +
  • num_rounds_list (list[int]) –

  • +
  • ds_client (Client | None) –

  • +
  • train_data_nodes (list[substrafl.nodes.train_data_node.TrainDataNode] | None) –

  • +
  • test_data_nodes (list[substrafl.nodes.test_data_node.TestDataNode] | None) –

  • +
  • aggregation_node (AggregationNode | None) –

  • +
  • evaluation_frequency (int | None) –

  • +
  • experiment_folder (str) –

  • +
  • clean_models (bool) –

  • +
  • fedeca_path (str | None) –

  • +
  • algo_dependencies (list | None) –

  • +
  • partner_client (Client | None) –

  • +
+
+
+
+
+fit(data, nb_clients=None, split_method='uniform', split_method_kwargs=None, data_path=None, backend_type='subprocess', urls=None, tokens=None)
+

Fit strategies on global data split across clients.

+

For test if provided we use test_data_nodes from int or the +train_data_nodes in the latter train=test.

+
+
Parameters:
+
    +
  • data (pd.DataFrame) – The global data to be split has to be a dataframe as we only support +one opener type.

  • +
  • nb_clients (Union[int, None], optional) – The number of clients used to split data across, by default None

  • +
  • split_method (Union[Callable, None], optional) – How to split data across the nb_clients, by default None.

  • +
  • split_method_kwargs (Union[Callable, None], optional) – Argument of the function used to split data, by default None.

  • +
  • data_path (Union[str, None]) – Where to store the data on disk when backend is not remote.

  • +
  • backend_type (str) – The backend to use for substra. Can be either: +[“subprocess”, “docker”, “remote”]. Defaults to “subprocess”.

  • +
  • urls (Union[list[str], None]) – Urls corresponding to clients API if using remote backend_type. +Defaults to None.

  • +
  • tokens (Union[list[str], None]) – Tokens necessary to authenticate each client API if backend_type +is remote. Defauts to None.

  • +
+
+
+
+ +
+
+get_outmodel(task_name, strategy_idx=0, idx_task=0)
+

Get the output model.

+
+
Parameters:
+
    +
  • task_name (str) – Name of the task.

  • +
  • strategy_idx (int, optional) – Index of the strategy, by default 0.

  • +
  • idx_task (int, optional) – Index of the task, by default 0.

  • +
+
+
+
+ +
+
+reset_experiment()
+

Reset the state of the object.

+

So it can be fit with a new dataset.

+
+ +
+
+run(num_strategies_to_run=None)
+

Run the experiment.

+
+
Parameters:
+

num_strategies_to_run (int, optional) – Number of strategies to run, by default None.

+
+
+
+ +
+ +
+
+class SubstraflTorchDataset(data_from_opener, is_inference, target_columns=None, columns_to_drop=None, fit_cols=None, dtype='float64', return_torch_tensors=False)
+

Bases: Dataset

+

Substra torch dataset class.

+
+
Parameters:
+
    +
  • is_inference (bool) –

  • +
  • target_columns (list | None) –

  • +
  • columns_to_drop (list | None) –

  • +
  • fit_cols (list | None) –

  • +
+
+
+
+ +
+
+download_train_task_models_by_round(client, dest_folder, compute_plan_key, round_idx)
+

Download models associated with a specific round of a train task.

+
+ +
+
+get_outmodel_function(task_name, client, compute_plan_key=None, idx_task=0, tasks_dict={})
+

Retrieve an output model from a task or tasks_dict.

+
+ +
+
+get_simu_state_from_round(simu_memory, client_id, round_idx=None)
+

Get the simulation state from a specific round and client.

+
+
Parameters:
+
    +
  • simu_memory (SimuStatesMemory) – Simulation memory.

  • +
  • client_id (str) – Client ID.

  • +
  • round_idx (Optional[int], optional) – Round index, by default None.

  • +
+
+
+
+ +
+
+make_accuracy_function(treatment_col)
+

Build accuracy function.

+
+
Parameters:
+

treatment_col (str,) – Column name for the treatment allocation.

+
+
+
+ +
+
+make_c_index_function(duration_col, event_col)
+

Build C-index function.

+
+
Parameters:
+
    +
  • duration_col (str,) – Column name for the duration.

  • +
  • event_col (str,) – Column name for the event.

  • +
+
+
+
+ +
+
+make_substrafl_torch_dataset_class(target_cols, event_col, duration_col, fit_cols=None, dtype='float64', return_torch_tensors=False, client_identifier=None)
+

Create a custom SubstraflTorchDataset class for survival analysis.

+
+
Parameters:
+
    +
  • target_cols (list) – List of target columns.

  • +
  • event_col (str) – Name of the event column.

  • +
  • duration_col (str) – Name of the duration column.

  • +
  • fit_cols (Union[list, None], optional) – List of columns to fit on, by default None will use all +columns that can be cast to numeric except target_columns.

  • +
  • dtype (str, optional) – Data type, by default “float64”.

  • +
  • return_torch_tensors (bool, optional) – Returns torch.Tensor. Defaults to False.

  • +
  • client_identifier (Union[None, str], optional) – Name of the column that identifies the client and that is to be dropped. +By default assumes there is no client identifier.

  • +
+
+
Returns:
+

Custom SubstraflTorchDataset class.

+
+
Return type:
+

type

+
+
+
+ +

Functions for tensors comparison.

+
+
+compare_tensors_lists(tensor_list_a, tensor_list_b, rtol=1e-05, atol=1e-08)
+

Compare list of tensors up to a certain precision.

+

The criteria that is checked is the following: |x - y| <= |y| * rtol + atol. +So there are two terms to consider. The first one is relative (rtol) and the second +is absolute (atol). The default for atol is a bit low for float32 tensors. We keep +the defaults everywhereto be safe except in the tests computed gradients wrt theory +where we raise atol to 1e-6. It makes sens in this case because it matches the +expected precision for slightly different float32 ops that should theoretically +give the exact same result.

+
+
Parameters:
+
    +
  • tensor_list_a (list) – a list of tensors

  • +
  • tensor_list_b (list) – a list of tensors

  • +
  • atol (float, optional) – absolute difference tolerance for tensor-to-tensor comparison. Default to 1e-5.

  • +
  • rtol (float, optional) – relative difference tolerance for tensor-to-tensor comparison. Default to 1e-8.

  • +
+
+
+
+ +

Module defining type alias.

+
+ + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/genindex.html b/genindex.html new file mode 100644 index 00000000..ca093d20 --- /dev/null +++ b/genindex.html @@ -0,0 +1,571 @@ + + + + + + + + + + + Index — FedECA fa9652cb6090a9a41b7cae679e71f929a1e4dd42 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • Index
  • + + +
  • + + + +
  • + +
+ + +
+
+
+
+ + +

Index

+ +
+ A + | B + | C + | D + | E + | F + | G + | L + | M + | N + | P + | R + | S + | T + | U + | W + +
+

A

+ + + +
+ +

B

+ + + +
+ +

C

+ + + +
+ +

D

+ + +
+ +

E

+ + +
+ +

F

+ + + +
+ +

G

+ + + +
+ +

L

+ + +
+ +

M

+ + +
+ +

N

+ + + +
+ +

P

+ + + +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

T

+ + + +
+ +

U

+ + +
+ +

W

+ + +
+ + + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..2d07f1de --- /dev/null +++ b/index.html @@ -0,0 +1,280 @@ + + + + + + + + + + + + FedECA documentation — FedECA fa9652cb6090a9a41b7cae679e71f929a1e4dd42 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • FedECA documentation
  • + + +
  • + + + +
  • + +
+ + +
+
+
+
+ +
+

FedECA documentation

+

This package allows to perform both simulations and deployments of federated +external control arms (FedECA) analyses.

+

Before using this code make sure to:

+
    +
  1. read and accept the terms of the license license.md that can be found at the root of the repository.

  2. +
  3. read substra’s privacy strategy

  4. +
  5. read our companion article

  6. +
  7. activate secure rng in Opacus if you plan on using differential privacy.

  8. +
+
+

Citing this work

+
@ARTICLE{terrail2023fedeca,
+     author = {{Ogier du Terrail}, Jean and {Klopfenstein}, Quentin and {Li}, Honghao and {Mayer}, Imke and {Loiseau}, Nicolas and {Hallal}, Mohammad and {Debouver}, Michael and {Camalon}, Thibault and {Fouqueray}, Thibault and {Arellano Castro}, Jorge and {Yanes}, Zahia and {Dahan}, Laetitia and {Ta{\"\i}eb}, Julien and {Laurent-Puig}, Pierre and {Bachet}, Jean-Baptiste and {Zhao}, Shulin and {Nicolle}, Remy and {Cros}, J{\'e}rome and {Gonzalez}, Daniel and {Carreras-Torres}, Robert and {Garcia Velasco}, Adelaida and {Abdilleh}, Kawther and {Doss}, Sudheer and {Balazard}, F{\'e}lix and {Andreux}, Mathieu},
+     title = "{FedECA: A Federated External Control Arm Method for Causal Inference with Time-To-Event Data in Distributed Settings}",
+     journal = {arXiv e-prints},
+     keywords = {Statistics - Methodology, Computer Science - Distributed, Parallel, and Cluster Computing, Computer Science - Machine Learning},
+     year = 2023,
+     month = nov,
+     eid = {arXiv:2311.16984},
+     pages = {arXiv:2311.16984},
+     doi = {10.48550/arXiv.2311.16984},
+     archivePrefix = {arXiv},
+     eprint = {2311.16984},
+     primaryClass = {stat.ME},
+     adsurl = {https://ui.adsabs.harvard.edu/abs/2023arXiv231116984O},
+     adsnote = {Provided by the SAO/NASA Astrophysics Data System}
+}
+
+
+
+
+

License

+

FedECA is released under a custom license that can be found under license.md at the root of the repository.

+
+

Installation

+ +
+
+

Getting Started Instructions

+ +
+
+
+
+
+ + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/installation.html b/installation.html new file mode 100644 index 00000000..6a02723d --- /dev/null +++ b/installation.html @@ -0,0 +1,246 @@ + + + + + + + + + + + + Installation — FedECA fa9652cb6090a9a41b7cae679e71f929a1e4dd42 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • Installation
  • + + +
  • + + + +
  • + +
+ + +
+
+
+
+ +
+

Installation

+

To install the package, create an env with python 3.9 with conda

+
conda create -n fedeca python=3.9
+conda activate fedeca
+
+
+

Within the environment, install the package by running:

+
git clone https://github.com/owkin/fedeca.git
+pip install -e ".[all_extra]"
+
+
+

If you plan developing, you should also install the pre-commit hooks

+

```bash +pre-commit install

+
+ + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 00000000..79abdd4b Binary files /dev/null and b/objects.inv differ diff --git a/py-modindex.html b/py-modindex.html new file mode 100644 index 00000000..86336671 --- /dev/null +++ b/py-modindex.html @@ -0,0 +1,277 @@ + + + + + + + + + + + Python Module Index — FedECA fa9652cb6090a9a41b7cae679e71f929a1e4dd42 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • Python Module Index
  • + + +
  • + +
  • + +
+ + +
+
+
+
+ + +

Python Module Index

+ +
+ f +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+ f
+ fedeca +
    + fedeca.metrics.metrics +
    + fedeca.strategies.bootstraper +
    + fedeca.strategies.webdisco_utils +
    + fedeca.utils.data_utils +
    + fedeca.utils.moments_utils +
    + fedeca.utils.substrafl_utils +
    + fedeca.utils.tensor_utils +
    + fedeca.utils.typing +
+ + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/quickstart.html b/quickstart.html new file mode 100644 index 00000000..dff032cd --- /dev/null +++ b/quickstart.html @@ -0,0 +1,389 @@ + + + + + + + + + + + + Quickstart — FedECA fa9652cb6090a9a41b7cae679e71f929a1e4dd42 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • Quickstart
  • + + +
  • + + + +
  • + +
+ + +
+
+
+
+ +
+

Quickstart

+

FedECA tries to mimic scikit-learn API as much as possible with the constraints +of distributed learning. +The first step in data science is always the data. +We need to first use or generate some survival data in pandas.dataframe format. +Note that fedeca should work on any data format, provided that the +return type of the substra opener is indeed a pandas.dataframe but let’s keep +it simple in this quickstart.

+

Here we will use fedeca utils which will generate some synthetic survival data +following CoxPH assumptions:

+
import pandas as pd
+from fedeca.utils.survival_utils import CoxData
+# Let's generate 1000 data samples with 10 covariates
+data = CoxData(seed=42, n_samples=1000, ndim=10)
+df = data.generate_dataframe()
+
+# We remove the true propensity score
+df = df.drop(columns=["propensity_scores"], axis=1)
+
+
+

Let’s inspect the data that we have here.

+
print(df.info())
+# <class 'pandas.core.frame.DataFrame'>
+# RangeIndex: 1000 entries, 0 to 999
+# Data columns (total 13 columns):
+#  #   Column     Non-Null Count  Dtype
+# ---  ------     --------------  -----
+#  0   X_0        1000 non-null   float64
+#  1   X_1        1000 non-null   float64
+#  2   X_2        1000 non-null   float64
+#  3   X_3        1000 non-null   float64
+#  4   X_4        1000 non-null   float64
+#  5   X_5        1000 non-null   float64
+#  6   X_6        1000 non-null   float64
+#  7   X_7        1000 non-null   float64
+#  8   X_8        1000 non-null   float64
+#  9   X_9        1000 non-null   float64
+#  10  time       1000 non-null   float64
+#  11  event      1000 non-null   uint8
+#  12  treatment  1000 non-null   uint8
+# dtypes: float64(11), uint8(2)
+# memory usage: 88.0 KB
+print(df.head())
+#         X_0       X_1       X_2       X_3       X_4       X_5       X_6       X_7       X_8       X_9      time  event  treatment
+# 0 -0.918373 -0.814340 -0.148994  0.482720 -1.130384 -1.254769 -0.462002  1.451622  1.199705  0.133197  2.573516      1          1
+# 1  0.360051 -0.863619  0.198673  0.330630 -0.189184 -0.802424 -1.694990 -0.989009 -0.421245 -0.112665  0.519108      1          1
+# 2  0.442502  0.024682  0.069500 -0.398015 -0.521236 -0.824907  0.373018  1.016843  0.765661  0.858817  0.652803      1          1
+# 3 -0.783965 -1.116391 -1.482413 -2.039827 -1.639304 -0.500380 -0.298467 -1.801688 -0.743004 -0.724039  0.074925      1          1
+# 4 -0.199620 -0.652347 -0.018776  0.004630 -0.122242 -0.413490 -0.450718 -0.761894 -1.323135 -0.234899  0.006951      1          1
+print(df["treatment"].unique())
+# array([1, 0], dtype=uint8)
+df["treatment"].sum()
+# 500
+
+
+

So we have survival data with covariates and a binary treatment variable. +Let’s inspect it using proper survival plots using the great survival analysis +package lifelines that was a +source of inspiration for fedeca:

+
from lifelines import KaplanMeierFitter as KMF
+import matplotlib.pyplot as plt
+treatments = [0, 1]
+kms = [KMF().fit(durations=df.loc[df["treatment"] == t]["time"], event_observed=df.loc[df["treatment"] == t]["event"]) for t in treatments]
+
+axs = [km.plot(label="treated" if t == 1 else "untreated") for km, t in zip(kms, treatments)]
+axs[-1].set_ylabel("Survival Probability")
+plt.xlim(0, 1500)
+plt.savefig("treated_vs_untreated.pdf", bbox_inches="tight")
+
+
+

Open treated_vs_untreated.pdf in your favorite pdf viewer and see for yourself.

+
+
+

Pooled IPTW analysis

+

The treatment seems to improve survival but it’s hard to say for sure as it might +simply be due to chance or sampling bias. +Let’s perform an IPTW analysis to be sure:

+
from fedeca.competitors import PooledIPTW
+pooled_iptw = PooledIPTW(treated_col="treatment", event_col="event", duration_col="time")
+# Targets is the propensity weights
+pooled_iptw.fit(data=df, targets=None)
+print(pooled_iptw.results_)
+#                coef  exp(coef)  se(coef)  coef lower 95%  coef upper 95%  exp(coef) lower 95%  exp(coef) upper 95%  cmp to         z         p  -log2(p)
+# covariate
+# treatment  0.041727    1.04261  0.070581       -0.096609        0.180064             0.907911             1.197294     0.0  0.591196  0.554389   0.85103
+
+
+

When looking at the p-value=0.554389 > 0.05, thus judging by what we observe we +cannot say for sure that there is a treatment effect. We say the ATE is non significant.

+
+
+

Distributed Analysis

+

However in practice data is private and held by different institutions. Therefore +in practice each client holds a subset of the rows of our dataframe. +We will simulate this using a realistic scenario where a “pharma” node is developing +a new drug and thus holds all treated and the rest of the data is split across +3 other institutions where patients were treated with the old drug. +We will use the split utils of FedECA.

+
from fedeca.utils.data_utils import split_dataframe_across_clients
+
+clients, train_data_nodes, _, _, _ = split_dataframe_across_clients(
+    df,
+    n_clients=4,
+    split_method= "split_control_over_centers",
+    split_method_kwargs={"treatment_info": "treatment"},
+    data_path="./data",
+    backend_type="simu",
+)
+
+
+

Note that you can replace split_method by any callable with the signature +pd.DataFrame -> list[int] where the list of ints is the split of the indices +of the df across the different institutions. +To convince you that the split was effective you can inspect the folder “./data”. +You will find different subfolders center0 to center3 each with different +parts of the data. +To unpack a bit what is going on in more depth, we have created a dict of client +‘clients’, +which is a dict with 4 keys containing substra API handles towards the different +institutions and their data. +train_data_nodes is a list of handles towards the datasets of the different institutions +that were registered through the substra interface using the data in the different +folders. +You might have noticed that we did not talk about the backend_type argument. +This argument is used to choose on which network will experiments be run. +“simu” means in-RAM. If you finish this tutorial do try other values such as: +“docker” or “subprocess” but expect a significant slow-down as experiments +get closer and closer to a real distributed system.

+

Now let’s try to see if we can reproduce the pooled anaysis in this much more +complicated distributed setting:

+
from fedeca import FedECA
+# We use the first client as the node, which launches order
+ds_client = clients[list(clients.keys())[0]]
+fed_iptw = FedECA(ndim=10, ds_client=ds_client, train_data_nodes=train_data_nodes, treated_col="treatment", duration_col="time", event_col="event", variance_method="robust")
+fed_iptw.run()
+# Final partial log-likelihood:
+# [-11499.19619422]
+#        coef  se(coef)  coef lower 95%  coef upper 95%         z         p  exp(coef)  exp(coef) lower 95%  exp(coef) upper 95%
+# 0  0.041718  0.070581       -0.096618        0.180054  0.591062  0.554479     1.0426             0.907902             1.197282
+
+
+

In fact what we did above is both quite verbose. For simulation purposes we +advise to use directly the scikit-learn inspired syntax:

+
from fedeca import FedECA
+
+fed_iptw = FedECA(ndim=10, treated_col="treatment", event_col="event", duration_col="time")
+fed_iptw.fit(df, n_clients=4, split_method="split_control_over_centers", split_method_kwargs={"treatment_info": "treatment"}, data_path="./data", variance_method="robust", backend_type="simu")
+#        coef  se(coef)  coef lower 95%  coef upper 95%         z         p  exp(coef)  exp(coef) lower 95%  exp(coef) upper 95%
+# 0  0.041718  0.070581       -0.096618        0.180054  0.591062  0.554479     1.0426             0.907902             1.197282
+
+
+

We find a similar p-value ! The distributed analysis is working as expected. +We recommend to users that made it to here as a next step to use their own data +and write custom split functions and to test this pipeline under various +heterogeneity settings. +Another interesting avenue is to try adding differential privacy to the training +of the propensity model but that is outside the scope of this quickstart.

+
+ + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/search.html b/search.html new file mode 100644 index 00000000..486d066f --- /dev/null +++ b/search.html @@ -0,0 +1,238 @@ + + + + + + + + + + + Search — FedECA fa9652cb6090a9a41b7cae679e71f929a1e4dd42 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • Search
  • + + +
  • + + + +
  • + +
+ + +
+
+
+
+ + + + +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 00000000..33f911e8 --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": ["api/algorithms", "api/competitors", "api/iptw", "api/metrics", "api/scripts", "api/strategies", "api/utils", "index", "installation", "quickstart"], "filenames": ["api/algorithms.rst", "api/competitors.rst", "api/iptw.rst", "api/metrics.rst", "api/scripts.rst", "api/strategies.rst", "api/utils.rst", "index.rst", "installation.rst", "quickstart.rst"], "titles": ["fedeca.algorithms", "fedeca.competitors", "fedeca.fedeca_core", "fedeca.metrics", "fedeca.scripts", "fedeca.strategies", "fedeca.utils", "FedECA documentation", "Installation", "Quickstart"], "terms": {"class": [0, 1, 2, 4, 5, 6, 9], "torchwebdiscoalgo": 0, "model": [0, 2, 5, 6, 9], "batch_siz": [0, 2], "arg": 0, "duration_col": [0, 1, 2, 5, 6, 9], "t": [0, 1, 2, 9], "event_col": [0, 1, 2, 5, 6, 9], "e": [0, 1, 2, 7, 8], "treated_col": [0, 1, 2, 9], "none": [0, 1, 2, 3, 4, 5, 6, 9], "initial_step_s": [0, 2, 5], "0": [0, 2, 5, 6, 9], "95": [0, 2, 9], "learning_rate_strategi": [0, 2], "lifelin": [0, 2, 5, 9], "standardize_data": [0, 2, 5], "true": [0, 2, 3, 5, 6, 9], "tol": [0, 5], "1e": [0, 5, 6], "16": [0, 5], "penal": [0, 2, 5], "l1_ratio": [0, 2, 5], "propensity_model": 0, "training_strategi": [0, 2], "iptw": [0, 1, 2, 5, 7], "cox_fit_col": [0, 2], "propensity_fit_col": [0, 2], "store_hessian": 0, "fals": [0, 2, 3, 5, 6], "with_batch_norm_paramet": 0, "use_gpu": 0, "robust": [0, 1, 2, 5, 9], "kwarg": [0, 5, 6], "base": [0, 1, 2, 4, 5, 6], "torchalgo": 0, "webdiscoalgo": 0, "paramet": [0, 1, 2, 3, 4, 5, 6], "modul": [0, 6], "int": [0, 1, 2, 4, 5, 6, 9], "str": [0, 2, 5, 6], "float": [0, 2, 5, 6], "bool": [0, 2, 3, 5, 6], "list": [0, 1, 2, 4, 5, 6, 9], "compute_x_y_and_propensity_weight": 0, "data_from_open": [0, 6], "shared_st": [0, 5, 6], "build": [0, 5, 6], "appropri": 0, "x": [0, 6], "y": [0, 6], "weight": [0, 1, 2, 3, 5, 6, 9], "from": [0, 2, 4, 5, 6, 9], "raw": 0, "output": [0, 5, 6], "open": [0, 2, 4, 6, 9], "us": [0, 1, 2, 3, 5, 6, 7, 9], "helper": 0, "function": [0, 1, 2, 5, 6, 9], "build_x_i": 0, "propens": [0, 1, 2, 9], "pd": [0, 1, 2, 3, 4, 5, 6, 9], "datafram": [0, 1, 2, 3, 4, 5, 6, 9], "dict": [0, 2, 5, 6, 9], "option": [0, 1, 2, 4, 5, 6], "outmodel": 0, "contain": [0, 5, 6, 9], "global": [0, 2, 5, 6], "mean": [0, 1, 3, 5, 6, 9], "std": [0, 1, 5], "default": [0, 2, 4, 5, 6], "return": [0, 1, 3, 4, 5, 6, 9], "input": 0, "cox": [0, 2, 5, 6], "target": [0, 1, 2, 6, 9], "type": [0, 1, 2, 3, 4, 5, 6, 9], "tupl": [0, 5], "compute_local_phi_stat": 0, "comput": [0, 1, 2, 3, 5, 6, 7], "local": [0, 5, 6], "updat": [0, 5], "ani": [0, 6, 9], "_description_": [0, 5], "webdiscoaveragedst": 0, "webdiscosharedst": 0, "local_uncentered_mo": 0, "uncent": [0, 6], "moment": [0, 5, 6], "thi": [0, 1, 5, 6, 9], "method": [0, 1, 2, 6, 7], "i": [0, 1, 2, 3, 5, 6, 7, 9], "transform": 0, "decor": 0, "meet": 0, "substra": [0, 2, 5, 6, 7, 9], "api": [0, 2, 6, 9], "execut": [0, 5], "train": [0, 2, 5, 6, 9], "node": [0, 2, 5, 6, 9], "see": [0, 9], "build_compute_plan": [0, 5], "given": [0, 2, 5, 6], "aggreg": [0, 1, 3, 5, 6], "here": [0, 1, 9], "noth": [0, 2], "result": [0, 5, 6], "share": [0, 5], "via": [0, 1, 5], "predict": 0, "follow": [0, 3, 5, 6, 9], "oper": [0, 5], "creat": [0, 6, 8, 9], "test": [0, 2, 5, 6, 9], "torch": [0, 2, 6], "dataset": [0, 6, 9], "self": [0, 2], "_local_predict": 0, "data": [0, 1, 2, 4, 5, 6, 7, 9], "latest": 0, "task": [0, 5, 6], "state": [0, 2, 5, 6], "summari": [0, 2, 5], "expos": 0, "experi": [0, 2, 6, 9], "file": [0, 4], "A": [0, 2, 5, 6, 7], "json": 0, "serializ": 0, "attribut": [0, 5], "user": [0, 5, 9], "want": [0, 5], "store": [0, 2, 6], "description_": 0, "rais": [0, 5, 6], "notimplementederror": [0, 5, 6], "properti": [0, 5], "strategi": [0, 2, 6, 7], "strategynam": [0, 5], "compat": 0, "poolediptw": [1, 9], "treat": [1, 2, 3, 6, 9], "ps_col": [1, 2], "propensity_scor": [1, 2, 9], "effect": [1, 2, 9], "ATE": [1, 9], "variance_method": [1, 2, 9], "naiv": [1, 2], "n_bootstrap": [1, 2, 5], "200": [1, 2, 6], "seed": [1, 2, 5, 6, 9], "cox_fit_kwarg": 1, "basesurvivalestim": [1, 2], "bootstrapmixin": [1, 2, 5], "pool": [1, 7], "liter": 1, "bootstrap": [1, 2, 5], "sequenc": 1, "bitgener": 1, "seedsequ": 1, "gener": [1, 2, 4, 5, 6, 9], "fit": [1, 2, 6, 9], "estim": [1, 2, 5], "treatment": [1, 2, 6, 9], "invers": [1, 2], "probabl": [1, 9], "varianc": [1, 2, 3, 5], "pre": [1, 8], "score": [1, 2, 9], "It": [1, 5, 6], "possibl": [1, 5, 6, 9], "pass": [1, 2, 5], "instead": [1, 2, 5], "logist": 1, "regress": 1, "point_estim": 1, "point": 1, "ndarrai": [1, 3, 5, 6], "matchingajudst": 1, "implement": [1, 2], "match": [1, 6], "adjust": 1, "indirect": 1, "comparison": [1, 6], "we": [1, 2, 5, 6, 9], "consid": [1, 6], "have": [1, 6, 9], "access": 1, "individu": 1, "patient": [1, 2, 3, 6, 9], "one": [1, 2, 5, 6], "center": [1, 5, 6], "other": [1, 5, 9], "onli": [1, 2, 5, 6], "propos": 1, "wai": [1, 5], "balanc": 1, "distribut": [1, 7], "indivu": 1, "covari": [1, 5, 6, 9], "avail": 1, "both": [1, 2, 5, 6, 7, 9], "studi": 1, "bootstrap_sampl": 1, "resampl": 1, "ipd": 1, "replac": [1, 2, 9], "In": [1, 5, 9], "set": [1, 2, 5, 7, 9], "an": [1, 5, 6, 8, 9], "maic": 1, "caller": 1, "supppos": 1, "assum": [1, 6], "mark": 1, "non": [1, 6, 9], "zero": [1, 5], "alloc": [1, 6], "therefor": [1, 2, 5, 9], "dure": 1, "should": [1, 5, 6, 8, 9], "naivecomparison": 1, "random": [1, 2, 5, 6], "ndim": [2, 5, 6, 9], "ds_client": [2, 6, 9], "train_data_nod": [2, 5, 6, 9], "num_rounds_list": [2, 6], "10": [2, 6, 7, 9], "damping_factor_nr": 2, "8": [2, 6, 9], "l2_coeff_nr": 2, "1": [2, 6, 9], "dtype": [2, 5, 6, 9], "float64": [2, 6, 9], "na\u00efv": 2, "bootstrap_se": [2, 5], "bootstrap_funct": [2, 5], "clients_siz": 2, "indices_in_global_dataset": 2, "client_identifi": [2, 6], "client": [2, 5, 6, 9], "clients_nam": 2, "dp_target_epsilon": 2, "dp_target_delta": 2, "dp_max_grad_norm": 2, "dp_propensity_model_optimizer_class": 2, "optim": 2, "sgd": 2, "dp_propensity_model_optimizer_kwarg": 2, "dp_propensity_model_training_param": 2, "42": [2, 6, 9], "aggregation_nod": [2, 5, 6], "experiment_fold": [2, 6], "iptw_experi": 2, "clean_model": [2, 5, 6], "depend": 2, "timeout": 2, "3600": 2, "sleep_tim": 2, "30": 2, "fedeca_path": [2, 6], "evaluation_frequ": [2, 6], "partner_cli": [2, 6], "perform": [2, 5, 7, 9], "feder": [2, 7], "aiptw": 2, "substrafl": [2, 5, 6], "traindatanod": [2, 5, 6], "callabl": [2, 5, 6, 9], "aggregationnod": [2, 5, 6], "check_cp_statu": 2, "idx": 2, "check": [2, 6], "statu": 2, "process": 2, "compute_propensity_scor": 2, "correspond": [2, 5, 6], "compute_summari": 2, "alpha": [2, 5], "05": [2, 5, 6, 9], "threshold": 2, "confid": 2, "level": [2, 5], "ci": 2, "n_client": [2, 6, 9], "split_method": [2, 6, 9], "split_method_kwarg": [2, 6, 9], "data_path": [2, 6, 9], "backend_typ": [2, 6, 9], "subprocess": [2, 6, 9], "url": [2, 6], "server_org_id": 2, "token": [2, 6], "split": [2, 5, 6, 9], "across": [2, 6, 9], "For": [2, 6, 9], "provid": [2, 5, 6, 7, 9], "test_data_nod": [2, 5, 6], "latter": [2, 6], "The": [2, 5, 6, 9], "ha": [2, 5, 6], "support": [2, 6], "nb_client": [2, 6], "union": [2, 5, 6], "number": [2, 4, 5, 6], "how": [2, 5, 6], "argument": [2, 5, 6, 9], "where": [2, 5, 6, 9], "disk": [2, 5, 6], "when": [2, 5, 6, 9], "backend": [2, 6], "remot": [2, 6], "p": [2, 9], "valu": [2, 6, 9], "fisher": 2, "inform": [2, 3], "sandwich": 2, "fl": 2, "thank": 2, "sampl": [2, 4, 6, 9], "ar": [2, 5, 6], "reweight": 2, "each": [2, 5, 6, 9], "time": [2, 5, 7, 9], "all": [2, 5, 6, 9], "repeat": 2, "effici": [2, 5], "shouldn": 2, "induc": 2, "too": 2, "much": [2, 9], "overhead": 2, "defaut": [2, 6], "david": 2, "binder": 2, "": [2, 5, 6, 7, 9], "proport": 2, "hazard": 2, "survei": 2, "biometrika": 2, "79": 2, "139": 2, "147": 2, "1992": 2, "noqa": [2, 3], "e501": [2, 3], "If": [2, 3, 5, 8, 9], "len": [2, 5], "those": [2, 5], "otherwis": [2, 5], "randomli": [2, 5], "presenc": [2, 5], "allwai": [2, 5], "instanc": [2, 5], "necessari": [2, 5, 6], "mimic": [2, 9], "epsilon": 2, "delta": 2, "differenti": [2, 7, 9], "privat": [2, 9], "guarante": 2, "maximum": 2, "l2": [2, 5], "norm": 2, "per": [2, 6], "gradient": [2, 5, 6], "enforc": 2, "privaci": [2, 7, 9], "adam": 2, "dp_propensity_model_optimizer_class_kwarg": 2, "param": [2, 5], "give": [2, 3, 5, 6], "kei": [2, 5, 6, 9], "num_upd": 2, "dp": 2, "can": [2, 5, 6, 7, 9], "either": [2, 6], "docker": [2, 6, 9], "server": [2, 5], "authent": [2, 6], "get_final_cox_model": 2, "retriev": [2, 5, 6], "final": [2, 9], "print_summari": 2, "print": [2, 7, 9], "reset_experi": [2, 6], "remov": [2, 5, 9], "just": 2, "case": [2, 5, 6], "run": [2, 6, 8, 9], "algorithm": [2, 5], "set_propensity_model_strategi": 2, "At": 2, "end": 2, "propensity_model_strateg": 2, "num_client": 2, "defin": [3, 5, 6], "eca": 3, "analysi": [3, 5, 6, 7], "standardized_mean_diff": 3, "confound": 3, "use_unweighted_vari": 3, "standard": [3, 5], "differ": [3, 5, 6, 9], "smd": 3, "between": [3, 5], "control": [3, 6, 7], "arrai": [3, 6, 9], "np": [3, 5, 6], "mask": 3, "boolean": 3, "about": [3, 9], "without": [3, 5], "To": [3, 7, 8, 9], "http": [3, 5, 7, 8], "stat": [3, 7], "stackexchang": 3, "com": [3, 8], "question": 3, "618643": 3, "formula": 3, "cobalt": 3, "packag": [3, 7, 8, 9], "categor": [3, 6], "varia": 3, "recalibr": 3, "www": [3, 5], "ncbi": [3, 5], "nlm": [3, 5], "nih": [3, 5], "gov": [3, 5], "pmc": [3, 5], "articl": [3, 5, 7], "pmc4626409": 3, "csvopen": 4, "csv": 4, "fake_data": 4, "n_sampl": [4, 5, 9], "simul": [4, 6, 7, 9], "surviv": [4, 5, 6, 9], "fake": [4, 6], "get_data": 4, "folder": [4, 9], "get": [4, 5, 6, 9], "path": [4, 6], "load": 4, "webdisco": 5, "algo": 5, "metric_funct": 5, "tradit": 5, "panda": [5, 6, 9], "its": 5, "kind": 5, "becaus": [5, 6], "linear": 5, "coxph": [5, 9], "util": [5, 9], "survival_util": [5, 9], "initi": 5, "cover": 5, "hessian": 5, "worker": 5, "central": 5, "batch": 5, "newton": [5, 6], "raphson": 5, "breslow": 5, "partial": [5, 9], "log": [5, 9], "likelihod": 5, "handl": [5, 9], "ti": 5, "event": [5, 6, 7, 9], "approxim": 5, "unlik": 5, "which": [5, 6, 9], "efron": 5, "separ": 5, "adapt": 5, "step": [5, 9], "size": 5, "converg": 5, "faster": 5, "start": 5, "initial_ste_s": 5, "safe": [5, 6], "invert": 5, "As": 5, "allow": [5, 7], "do": [5, 9], "pmc5009917": 5, "statistics_comput": 5, "statist": [5, 7], "find": [5, 9], "alreadi": 5, "side": 5, "heurist": 5, "9": [5, 8, 9], "otion": 5, "cap": 5, "everi": 5, "divis": 5, "avoid": 5, "divid": 5, "whether": [5, 6], "befor": [5, 6, 7], "comut": 5, "add": 5, "regular": 5, "ill": 5, "condit": 5, "happen": 5, "quit": [5, 9], "often": 5, "larg": 5, "ratio": 5, "l1": 5, "sklearn": 5, "aggregate_mo": 5, "local_m1": 5, "local_m2": 5, "evaluation_strategi": 5, "num_round": 5, "graph": 5, "round": [5, 6], "useless": 5, "organ": 5, "unus": 5, "evaluationstrategi": 5, "clean": 5, "intermediari": 5, "platform": 5, "you": [5, 7, 8, 9], "download": [5, 6], "re": 5, "caus": 5, "space": 5, "fill": 5, "quickli": 5, "so": [5, 6, 9], "unless": 5, "need": [5, 6, 9], "perform_evalu": 5, "round_idx": [5, 6], "evalu": 5, "testdatanod": [5, 6], "intersect": 5, "been": 5, "index": [5, 6], "perform_round": 5, "additional_orgs_permiss": 5, "One": 5, "consist": 5, "featur": [5, 6], "reus": 5, "block": 5, "risk": 5, "addit": 5, "permiss": 5, "after": 5, "order": [5, 6, 9], "name": [5, 6], "fashion": 5, "make_bootstrap_metric_funct": 5, "take": 5, "metric": 5, "hook": [5, 8], "make_bootstrap_strategi": 5, "client_specific_kwarg": 5, "wo": 5, "impact": 5, "reduc": 5, "bottleneck": 5, "go": [5, 9], "over": [5, 6], "plan": [5, 7, 8], "modifi": 5, "atom": 5, "origin": 5, "obtain": 5, "independ": 5, "code": [5, 7], "heavili": 5, "some": [5, 9], "pattern": 5, "invent": 5, "arthur": 5, "pignet": 5, "signatur": [5, 6, 9], "f": [5, 7], "version": 5, "note": [5, 9], "cross": 5, "valid": 5, "capabl": 5, "well": 5, "would": 5, "fold": 5, "flatten": 5, "dictionari": 5, "thei": 5, "chain": 5, "compute_summary_funct": 5, "final_param": 5, "variance_matrix": 5, "vallu": 5, "coeffici": 5, "matrix": 5, "quantil": 5, "get_final_cox_model_funct": 5, "compute_plan_kei": [5, 6], "simu_mod": 5, "first": [5, 6, 9], "susbtrafl": 5, "regist": [5, 6, 9], "cp": 5, "wa": [5, 9], "standad": 5, "durat": [5, 6, 9], "column": [5, 6, 9], "simu": [5, 9], "mode": 5, "could": [5, 6], "infer": [5, 7], "retreiv": 5, "likelihood": [5, 9], "get_last_algo_from_round_count": 5, "_type_": 5, "generate_cox_data_and_substra_cli": 6, "2": [6, 9], "n_per_client": 6, "add_treat": 6, "ncategor": 6, "sever": 6, "them": 6, "uniform": 6, "save": 6, "keep": [6, 9], "make": [6, 7], "posteriori": 6, "move": 6, "awai": 6, "assumpt": [6, 9], "split_control_over_cent": [6, 9], "df": [6, 9], "treatment_info": [6, 9], "treatment_alloc": 6, "use_random": 6, "group": 6, "shuffl": 6, "indic": [6, 9], "split_dataframe_across_cli": [6, 9], "exist": 6, "invok": 6, "uniformli": 6, "remain": 6, "ones": 6, "uniform_split": 6, "high": 6, "formeanla": 6, "aggregation_mean": 6, "local_mean": 6, "n_local_sampl": 6, "seri": 6, "same": 6, "compute_centered_mo": 6, "uncentered_mo": 6, "k": 6, "unnorm": 6, "scipi": 6, "special": 6, "interest": [6, 9], "math": 6, "hat": 6, "mu": 6, "_k": 6, "frac": 6, "sigma": 6, "mathbb": 6, "e_z": 6, "left": 6, "z": [6, 9], "right": 6, "sum_": 6, "l": 6, "binom": 6, "thu": [6, 9], "up": 6, "th": 6, "compute_global_mo": 6, "compute_uncentered_mo": 6, "nor": 6, "algo_depend": 6, "object": 6, "get_outmodel": 6, "task_nam": 6, "strategy_idx": 6, "idx_task": 6, "reset": 6, "new": [6, 9], "num_strategies_to_run": 6, "substrafltorchdataset": 6, "is_infer": 6, "target_column": 6, "columns_to_drop": 6, "fit_col": 6, "return_torch_tensor": 6, "download_train_task_models_by_round": 6, "dest_fold": 6, "associ": 6, "specif": 6, "get_outmodel_funct": 6, "tasks_dict": 6, "get_simu_state_from_round": 6, "simu_memori": 6, "client_id": 6, "simustatesmemori": 6, "memori": [6, 9], "id": 6, "make_accuracy_funct": 6, "treatment_col": 6, "accuraci": 6, "make_c_index_funct": 6, "c": 6, "make_substrafl_torch_dataset_class": 6, "target_col": 6, "custom": [6, 7, 9], "cast": 6, "numer": 6, "except": 6, "tensor": 6, "identifi": 6, "drop": [6, 9], "By": 6, "compare_tensors_list": 6, "tensor_list_a": 6, "tensor_list_b": 6, "rtol": 6, "atol": 6, "08": 6, "compar": 6, "certain": 6, "precis": 6, "criteria": 6, "two": 6, "term": [6, 7], "rel": 6, "second": 6, "absolut": 6, "bit": [6, 9], "low": 6, "float32": 6, "everywhereto": 6, "wrt": 6, "theori": 6, "6": [6, 9], "sen": 6, "expect": [6, 9], "slightli": 6, "op": 6, "theoret": 6, "exact": 6, "toler": 6, "5": [6, 9], "alia": 6, "deploy": 7, "extern": 7, "arm": 7, "analys": 7, "sure": [7, 9], "read": 7, "accept": 7, "md": 7, "found": 7, "root": 7, "repositori": 7, "our": [7, 9], "companion": 7, "activ": [7, 8], "secur": 7, "rng": 7, "opacu": 7, "terrail2023fedeca": 7, "author": 7, "ogier": 7, "du": 7, "terrail": 7, "jean": 7, "klopfenstein": 7, "quentin": 7, "li": 7, "honghao": 7, "mayer": 7, "imk": 7, "loiseau": 7, "nicola": 7, "hallal": 7, "mohammad": 7, "debouv": 7, "michael": 7, "camalon": 7, "thibault": 7, "fouquerai": 7, "arellano": 7, "castro": 7, "jorg": 7, "yane": 7, "zahia": 7, "dahan": 7, "laetitia": 7, "ta": 7, "eb": 7, "julien": 7, "laurent": 7, "puig": 7, "pierr": 7, "bachet": 7, "baptist": 7, "zhao": 7, "shulin": 7, "nicol": 7, "remi": 7, "cro": 7, "j": 7, "rome": 7, "gonzalez": 7, "daniel": 7, "carrera": 7, "torr": 7, "robert": 7, "garcia": 7, "velasco": 7, "adelaida": 7, "abdilleh": 7, "kawther": 7, "doss": 7, "sudheer": 7, "balazard": 7, "lix": 7, "andreux": 7, "mathieu": 7, "titl": 7, "causal": 7, "journal": 7, "arxiv": 7, "keyword": 7, "methodologi": 7, "scienc": [7, 9], "parallel": 7, "cluster": 7, "machin": 7, "learn": [7, 9], "year": 7, "2023": 7, "month": 7, "nov": 7, "eid": 7, "2311": 7, "16984": 7, "page": 7, "doi": 7, "48550": 7, "archiveprefix": 7, "eprint": 7, "primaryclass": 7, "me": 7, "adsurl": 7, "ui": 7, "adsab": 7, "harvard": 7, "edu": 7, "ab": 7, "2023arxiv231116984o": 7, "adsnot": 7, "sao": 7, "nasa": 7, "astrophys": 7, "system": [7, 9], "releas": 7, "under": [7, 9], "quickstart": 7, "env": 8, "python": 8, "3": [8, 9], "conda": 8, "n": 8, "fedeca": [8, 9], "within": 8, "environ": 8, "git": 8, "clone": 8, "github": 8, "owkin": 8, "pip": 8, "all_extra": 8, "develop": [8, 9], "also": 8, "commit": 8, "bash": 8, "tri": 9, "scikit": 9, "constraint": 9, "alwai": 9, "format": 9, "work": 9, "inde": 9, "let": 9, "simpl": 9, "synthet": 9, "import": 9, "coxdata": 9, "1000": 9, "generate_datafram": 9, "axi": 9, "inspect": 9, "info": 9, "core": 9, "frame": 9, "rangeindex": 9, "entri": 9, "999": 9, "total": 9, "13": 9, "null": 9, "count": 9, "x_0": 9, "x_1": 9, "x_2": 9, "x_3": 9, "4": 9, "x_4": 9, "x_5": 9, "x_6": 9, "7": 9, "x_7": 9, "x_8": 9, "x_9": 9, "11": 9, "uint8": 9, "12": 9, "usag": 9, "88": 9, "kb": 9, "head": 9, "918373": 9, "814340": 9, "148994": 9, "482720": 9, "130384": 9, "254769": 9, "462002": 9, "451622": 9, "199705": 9, "133197": 9, "573516": 9, "360051": 9, "863619": 9, "198673": 9, "330630": 9, "189184": 9, "802424": 9, "694990": 9, "989009": 9, "421245": 9, "112665": 9, "519108": 9, "442502": 9, "024682": 9, "069500": 9, "398015": 9, "521236": 9, "824907": 9, "373018": 9, "016843": 9, "765661": 9, "858817": 9, "652803": 9, "783965": 9, "116391": 9, "482413": 9, "039827": 9, "639304": 9, "500380": 9, "298467": 9, "801688": 9, "743004": 9, "724039": 9, "074925": 9, "199620": 9, "652347": 9, "018776": 9, "004630": 9, "122242": 9, "413490": 9, "450718": 9, "761894": 9, "323135": 9, "234899": 9, "006951": 9, "uniqu": 9, "sum": 9, "500": 9, "binari": 9, "variabl": 9, "proper": 9, "plot": 9, "great": 9, "sourc": 9, "inspir": 9, "kaplanmeierfitt": 9, "kmf": 9, "matplotlib": 9, "pyplot": 9, "plt": 9, "km": 9, "loc": 9, "event_observ": 9, "ax": 9, "label": 9, "els": 9, "untreat": 9, "zip": 9, "set_ylabel": 9, "xlim": 9, "1500": 9, "savefig": 9, "treated_vs_untr": 9, "pdf": 9, "bbox_inch": 9, "tight": 9, "your": 9, "favorit": 9, "viewer": 9, "yourself": 9, "seem": 9, "improv": 9, "hard": 9, "sai": 9, "might": 9, "simpli": 9, "due": 9, "chanc": 9, "bia": 9, "competitor": 9, "pooled_iptw": 9, "results_": 9, "coef": 9, "exp": 9, "se": 9, "lower": 9, "upper": 9, "cmp": 9, "log2": 9, "041727": 9, "04261": 9, "070581": 9, "096609": 9, "180064": 9, "907911": 9, "197294": 9, "591196": 9, "554389": 9, "85103": 9, "look": 9, "judg": 9, "what": 9, "observ": 9, "cannot": 9, "signific": 9, "howev": 9, "practic": 9, "held": 9, "institut": 9, "hold": 9, "subset": 9, "row": 9, "realist": 9, "scenario": 9, "pharma": 9, "drug": 9, "rest": 9, "were": 9, "old": 9, "data_util": 9, "_": 9, "convinc": 9, "subfold": 9, "center0": 9, "center3": 9, "part": 9, "unpack": 9, "more": 9, "depth": 9, "toward": 9, "through": 9, "interfac": 9, "notic": 9, "did": 9, "talk": 9, "choos": 9, "network": 9, "ram": 9, "finish": 9, "tutori": 9, "try": 9, "slow": 9, "down": 9, "closer": 9, "real": 9, "now": 9, "reproduc": 9, "anaysi": 9, "complic": 9, "launch": 9, "fed_iptw": 9, "11499": 9, "19619422": 9, "041718": 9, "096618": 9, "180054": 9, "591062": 9, "554479": 9, "0426": 9, "907902": 9, "197282": 9, "fact": 9, "abov": 9, "verbos": 9, "purpos": 9, "advis": 9, "directli": 9, "syntax": 9, "similar": 9, "recommend": 9, "made": 9, "next": 9, "own": 9, "write": 9, "pipelin": 9, "variou": 9, "heterogen": 9, "anoth": 9, "avenu": 9, "ad": 9, "outsid": 9, "scope": 9}, "objects": {"fedeca": [[2, 0, 1, "", "FedECA"], [1, 0, 1, "", "MatchingAjudsted"], [1, 0, 1, "", "NaiveComparison"], [1, 0, 1, "", "PooledIPTW"]], "fedeca.FedECA": [[2, 1, 1, "", "check_cp_status"], [2, 2, 1, "", "clients_names"], [2, 1, 1, "", "compute_propensity_scores"], [2, 1, 1, "", "compute_summary"], [2, 1, 1, "", "fit"], [2, 1, 1, "", "get_final_cox_model"], [2, 1, 1, "", "print_summary"], [2, 1, 1, "", "reset_experiment"], [2, 1, 1, "", "run"], [2, 1, 1, "", "set_propensity_model_strategy"]], "fedeca.MatchingAjudsted": [[1, 1, 1, "", "bootstrap_sample"], [1, 1, 1, "", "fit"], [1, 1, 1, "", "point_estimate"]], "fedeca.NaiveComparison": [[1, 1, 1, "", "fit"], [1, 1, 1, "", "point_estimate"]], "fedeca.PooledIPTW": [[1, 1, 1, "", "fit"], [1, 1, 1, "", "point_estimate"]], "fedeca.algorithms": [[0, 0, 1, "", "TorchWebDiscoAlgo"]], "fedeca.algorithms.TorchWebDiscoAlgo": [[0, 1, 1, "", "compute_X_y_and_propensity_weights"], [0, 1, 1, "", "compute_local_phi_stats"], [0, 1, 1, "", "local_uncentered_moments"], [0, 1, 1, "", "predict"], [0, 3, 1, "", "strategies"], [0, 1, 1, "", "summary"], [0, 1, 1, "", "train"]], "fedeca.metrics": [[3, 4, 0, "-", "metrics"]], "fedeca.metrics.metrics": [[3, 5, 1, "", "standardized_mean_diff"]], "fedeca.scripts.substra_assets.csv_opener": [[4, 0, 1, "", "CSVOpener"]], "fedeca.scripts.substra_assets.csv_opener.CSVOpener": [[4, 1, 1, "", "fake_data"], [4, 1, 1, "", "get_data"]], "fedeca.strategies": [[5, 0, 1, "", "WebDisco"], [5, 4, 0, "-", "bootstraper"], [5, 4, 0, "-", "webdisco_utils"]], "fedeca.strategies.WebDisco": [[5, 1, 1, "", "aggregate_moments"], [5, 1, 1, "", "build_compute_plan"], [5, 3, 1, "", "name"], [5, 1, 1, "", "perform_evaluation"], [5, 1, 1, "", "perform_round"]], "fedeca.strategies.bootstraper": [[5, 5, 1, "", "make_bootstrap_metric_function"], [5, 5, 1, "", "make_bootstrap_strategy"]], "fedeca.strategies.webdisco_utils": [[5, 5, 1, "", "compute_summary_function"], [5, 5, 1, "", "get_final_cox_model_function"], [5, 5, 1, "", "get_last_algo_from_round_count"]], "fedeca.utils": [[6, 4, 0, "-", "data_utils"], [6, 4, 0, "-", "moments_utils"], [6, 4, 0, "-", "substrafl_utils"], [6, 4, 0, "-", "tensor_utils"], [6, 4, 0, "-", "typing"]], "fedeca.utils.data_utils": [[6, 5, 1, "", "generate_cox_data_and_substra_clients"], [6, 5, 1, "", "split_control_over_centers"], [6, 5, 1, "", "split_dataframe_across_clients"], [6, 5, 1, "", "uniform_split"]], "fedeca.utils.moments_utils": [[6, 5, 1, "", "aggregation_mean"], [6, 5, 1, "", "compute_centered_moment"], [6, 5, 1, "", "compute_global_moments"], [6, 5, 1, "", "compute_uncentered_moment"]], "fedeca.utils.substrafl_utils": [[6, 0, 1, "", "Experiment"], [6, 0, 1, "", "SubstraflTorchDataset"], [6, 5, 1, "", "download_train_task_models_by_round"], [6, 5, 1, "", "get_outmodel_function"], [6, 5, 1, "", "get_simu_state_from_round"], [6, 5, 1, "", "make_accuracy_function"], [6, 5, 1, "", "make_c_index_function"], [6, 5, 1, "", "make_substrafl_torch_dataset_class"]], "fedeca.utils.substrafl_utils.Experiment": [[6, 1, 1, "", "fit"], [6, 1, 1, "", "get_outmodel"], [6, 1, 1, "", "reset_experiment"], [6, 1, 1, "", "run"]], "fedeca.utils.tensor_utils": [[6, 5, 1, "", "compare_tensors_lists"]]}, "objtypes": {"0": "py:class", "1": "py:method", "2": "py:attribute", "3": "py:property", "4": "py:module", "5": "py:function"}, "objnames": {"0": ["py", "class", "Python class"], "1": ["py", "method", "Python method"], "2": ["py", "attribute", "Python attribute"], "3": ["py", "property", "Python property"], "4": ["py", "module", "Python module"], "5": ["py", "function", "Python function"]}, "titleterms": {"fedeca": [0, 1, 2, 3, 4, 5, 6, 7], "algorithm": 0, "competitor": 1, "fedeca_cor": 2, "metric": 3, "script": 4, "strategi": 5, "refer": 5, "util": 6, "document": 7, "cite": 7, "thi": 7, "work": 7, "licens": 7, "instal": [7, 8], "get": 7, "start": 7, "instruct": 7, "quickstart": 9, "pool": 9, "iptw": 9, "analysi": 9, "distribut": 9}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 8, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.intersphinx": 1, "sphinxcontrib.bibtex": 9, "sphinx": 57}, "alltitles": {"fedeca.algorithms": [[0, "fedeca-algorithms"]], "fedeca.competitors": [[1, "fedeca-competitors"]], "fedeca.fedeca_core": [[2, "fedeca-fedeca-core"]], "fedeca.metrics": [[3, "module-fedeca.metrics.metrics"]], "fedeca.scripts": [[4, "fedeca-scripts"]], "fedeca.strategies": [[5, "fedeca-strategies"]], "Reference": [[5, "reference"]], "fedeca.utils": [[6, "module-fedeca.utils.data_utils"]], "FedECA documentation": [[7, "fedeca-documentation"]], "Citing this work": [[7, "citing-this-work"]], "License": [[7, "license"]], "Installation": [[7, null], [8, "installation"]], "Getting Started Instructions": [[7, null]], "Quickstart": [[9, "quickstart"]], "Pooled IPTW analysis": [[9, "pooled-iptw-analysis"]], "Distributed Analysis": [[9, "distributed-analysis"]]}, "indexentries": {"torchwebdiscoalgo (class in fedeca.algorithms)": [[0, "fedeca.algorithms.TorchWebDiscoAlgo"]], "compute_x_y_and_propensity_weights() (torchwebdiscoalgo method)": [[0, "fedeca.algorithms.TorchWebDiscoAlgo.compute_X_y_and_propensity_weights"]], "compute_local_phi_stats() (torchwebdiscoalgo method)": [[0, "fedeca.algorithms.TorchWebDiscoAlgo.compute_local_phi_stats"]], "local_uncentered_moments() (torchwebdiscoalgo method)": [[0, "fedeca.algorithms.TorchWebDiscoAlgo.local_uncentered_moments"]], "predict() (torchwebdiscoalgo method)": [[0, "fedeca.algorithms.TorchWebDiscoAlgo.predict"]], "strategies (torchwebdiscoalgo property)": [[0, "fedeca.algorithms.TorchWebDiscoAlgo.strategies"]], "summary() (torchwebdiscoalgo method)": [[0, "fedeca.algorithms.TorchWebDiscoAlgo.summary"]], "train() (torchwebdiscoalgo method)": [[0, "fedeca.algorithms.TorchWebDiscoAlgo.train"]], "matchingajudsted (class in fedeca)": [[1, "fedeca.MatchingAjudsted"]], "naivecomparison (class in fedeca)": [[1, "fedeca.NaiveComparison"]], "poolediptw (class in fedeca)": [[1, "fedeca.PooledIPTW"]], "bootstrap_sample() (matchingajudsted method)": [[1, "fedeca.MatchingAjudsted.bootstrap_sample"]], "fit() (matchingajudsted method)": [[1, "fedeca.MatchingAjudsted.fit"]], "fit() (naivecomparison method)": [[1, "fedeca.NaiveComparison.fit"]], "fit() (poolediptw method)": [[1, "fedeca.PooledIPTW.fit"]], "point_estimate() (matchingajudsted method)": [[1, "fedeca.MatchingAjudsted.point_estimate"]], "point_estimate() (naivecomparison method)": [[1, "fedeca.NaiveComparison.point_estimate"]], "point_estimate() (poolediptw method)": [[1, "fedeca.PooledIPTW.point_estimate"]], "fedeca (class in fedeca)": [[2, "fedeca.FedECA"]], "check_cp_status() (fedeca method)": [[2, "fedeca.FedECA.check_cp_status"]], "clients_names (fedeca attribute)": [[2, "fedeca.FedECA.clients_names"]], "compute_propensity_scores() (fedeca method)": [[2, "fedeca.FedECA.compute_propensity_scores"]], "compute_summary() (fedeca method)": [[2, "fedeca.FedECA.compute_summary"]], "fit() (fedeca method)": [[2, "fedeca.FedECA.fit"]], "get_final_cox_model() (fedeca method)": [[2, "fedeca.FedECA.get_final_cox_model"]], "print_summary() (fedeca method)": [[2, "fedeca.FedECA.print_summary"]], "reset_experiment() (fedeca method)": [[2, "fedeca.FedECA.reset_experiment"]], "run() (fedeca method)": [[2, "fedeca.FedECA.run"]], "set_propensity_model_strategy() (fedeca method)": [[2, "fedeca.FedECA.set_propensity_model_strategy"]], "fedeca.metrics.metrics": [[3, "module-fedeca.metrics.metrics"]], "module": [[3, "module-fedeca.metrics.metrics"], [5, "module-fedeca.strategies.bootstraper"], [5, "module-fedeca.strategies.webdisco_utils"], [6, "module-fedeca.utils.data_utils"], [6, "module-fedeca.utils.moments_utils"], [6, "module-fedeca.utils.substrafl_utils"], [6, "module-fedeca.utils.tensor_utils"], [6, "module-fedeca.utils.typing"]], "standardized_mean_diff() (in module fedeca.metrics.metrics)": [[3, "fedeca.metrics.metrics.standardized_mean_diff"]], "csvopener (class in fedeca.scripts.substra_assets.csv_opener)": [[4, "fedeca.scripts.substra_assets.csv_opener.CSVOpener"]], "fake_data() (csvopener method)": [[4, "fedeca.scripts.substra_assets.csv_opener.CSVOpener.fake_data"]], "get_data() (csvopener method)": [[4, "fedeca.scripts.substra_assets.csv_opener.CSVOpener.get_data"]], "webdisco (class in fedeca.strategies)": [[5, "fedeca.strategies.WebDisco"]], "aggregate_moments() (webdisco method)": [[5, "fedeca.strategies.WebDisco.aggregate_moments"]], "build_compute_plan() (webdisco method)": [[5, "fedeca.strategies.WebDisco.build_compute_plan"]], "compute_summary_function() (in module fedeca.strategies.webdisco_utils)": [[5, "fedeca.strategies.webdisco_utils.compute_summary_function"]], "fedeca.strategies.bootstraper": [[5, "module-fedeca.strategies.bootstraper"]], "fedeca.strategies.webdisco_utils": [[5, "module-fedeca.strategies.webdisco_utils"]], "get_final_cox_model_function() (in module fedeca.strategies.webdisco_utils)": [[5, "fedeca.strategies.webdisco_utils.get_final_cox_model_function"]], "get_last_algo_from_round_count() (in module fedeca.strategies.webdisco_utils)": [[5, "fedeca.strategies.webdisco_utils.get_last_algo_from_round_count"]], "make_bootstrap_metric_function() (in module fedeca.strategies.bootstraper)": [[5, "fedeca.strategies.bootstraper.make_bootstrap_metric_function"]], "make_bootstrap_strategy() (in module fedeca.strategies.bootstraper)": [[5, "fedeca.strategies.bootstraper.make_bootstrap_strategy"]], "name (webdisco property)": [[5, "fedeca.strategies.WebDisco.name"]], "perform_evaluation() (webdisco method)": [[5, "fedeca.strategies.WebDisco.perform_evaluation"]], "perform_round() (webdisco method)": [[5, "fedeca.strategies.WebDisco.perform_round"]], "experiment (class in fedeca.utils.substrafl_utils)": [[6, "fedeca.utils.substrafl_utils.Experiment"]], "substrafltorchdataset (class in fedeca.utils.substrafl_utils)": [[6, "fedeca.utils.substrafl_utils.SubstraflTorchDataset"]], "aggregation_mean() (in module fedeca.utils.moments_utils)": [[6, "fedeca.utils.moments_utils.aggregation_mean"]], "compare_tensors_lists() (in module fedeca.utils.tensor_utils)": [[6, "fedeca.utils.tensor_utils.compare_tensors_lists"]], "compute_centered_moment() (in module fedeca.utils.moments_utils)": [[6, "fedeca.utils.moments_utils.compute_centered_moment"]], "compute_global_moments() (in module fedeca.utils.moments_utils)": [[6, "fedeca.utils.moments_utils.compute_global_moments"]], "compute_uncentered_moment() (in module fedeca.utils.moments_utils)": [[6, "fedeca.utils.moments_utils.compute_uncentered_moment"]], "download_train_task_models_by_round() (in module fedeca.utils.substrafl_utils)": [[6, "fedeca.utils.substrafl_utils.download_train_task_models_by_round"]], "fedeca.utils.data_utils": [[6, "module-fedeca.utils.data_utils"]], "fedeca.utils.moments_utils": [[6, "module-fedeca.utils.moments_utils"]], "fedeca.utils.substrafl_utils": [[6, "module-fedeca.utils.substrafl_utils"]], "fedeca.utils.tensor_utils": [[6, "module-fedeca.utils.tensor_utils"]], "fedeca.utils.typing": [[6, "module-fedeca.utils.typing"]], "fit() (experiment method)": [[6, "fedeca.utils.substrafl_utils.Experiment.fit"]], "generate_cox_data_and_substra_clients() (in module fedeca.utils.data_utils)": [[6, "fedeca.utils.data_utils.generate_cox_data_and_substra_clients"]], "get_outmodel() (experiment method)": [[6, "fedeca.utils.substrafl_utils.Experiment.get_outmodel"]], "get_outmodel_function() (in module fedeca.utils.substrafl_utils)": [[6, "fedeca.utils.substrafl_utils.get_outmodel_function"]], "get_simu_state_from_round() (in module fedeca.utils.substrafl_utils)": [[6, "fedeca.utils.substrafl_utils.get_simu_state_from_round"]], "make_accuracy_function() (in module fedeca.utils.substrafl_utils)": [[6, "fedeca.utils.substrafl_utils.make_accuracy_function"]], "make_c_index_function() (in module fedeca.utils.substrafl_utils)": [[6, "fedeca.utils.substrafl_utils.make_c_index_function"]], "make_substrafl_torch_dataset_class() (in module fedeca.utils.substrafl_utils)": [[6, "fedeca.utils.substrafl_utils.make_substrafl_torch_dataset_class"]], "reset_experiment() (experiment method)": [[6, "fedeca.utils.substrafl_utils.Experiment.reset_experiment"]], "run() (experiment method)": [[6, "fedeca.utils.substrafl_utils.Experiment.run"]], "split_control_over_centers() (in module fedeca.utils.data_utils)": [[6, "fedeca.utils.data_utils.split_control_over_centers"]], "split_dataframe_across_clients() (in module fedeca.utils.data_utils)": [[6, "fedeca.utils.data_utils.split_dataframe_across_clients"]], "uniform_split() (in module fedeca.utils.data_utils)": [[6, "fedeca.utils.data_utils.uniform_split"]]}}) \ No newline at end of file